From 65d83871e2a784c12e9edc3f1115991161b6138f Mon Sep 17 00:00:00 2001 From: Yunda Date: Tue, 23 Jul 2013 14:32:37 +0200 Subject: [PATCH 01/72] 8011888: sa.js: TypeError: [object JSAdapter] has no such function "__has__" Reviewed-by: sla, sundar, kmo --- .../sun/jvm/hotspot/utilities/soql/sa.js | 90 +++++++++++++------ 1 file changed, 62 insertions(+), 28 deletions(-) diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/soql/sa.js b/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/soql/sa.js index ec22e35e633..4253740369b 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/soql/sa.js +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/soql/sa.js @@ -35,8 +35,9 @@ sapkg.c1 = sapkg.hotspot.c1; sapkg.code = sapkg.hotspot.code; sapkg.compiler = sapkg.hotspot.compiler; -// 'debugger' is a JavaScript keyword :-( -// sapkg.debugger = sapkg.hotspot.debugger; +// 'debugger' is a JavaScript keyword, but ES5 relaxes the +// restriction of using keywords as property name +sapkg.debugger = sapkg.hotspot.debugger; sapkg.interpreter = sapkg.hotspot.interpreter; sapkg.jdi = sapkg.hotspot.jdi; @@ -116,27 +117,36 @@ function main(globals, jvmarg) { return args; } + // Handle __has__ specially to avoid metacircularity problems + // when called from __get__. + // Calling + // this.__has__(name) + // will in turn call + // this.__call__('__has__', name) + // which is not handled below + function __has__(name) { + if (typeof(name) == 'number') { + return so["has(int)"](name); + } else { + if (name == '__wrapped__') { + return true; + } else if (so["has(java.lang.String)"](name)) { + return true; + } else if (name.equals('toString')) { + return true; + } else { + return false; + } + } + } + if (so instanceof sapkg.utilities.soql.ScriptObject) { return new JSAdapter() { - __getIds__: function() { - return so.getIds(); + __getIds__: function() { + return so.getIds(); }, - __has__ : function(name) { - if (typeof(name) == 'number') { - return so["has(int)"](name); - } else { - if (name == '__wrapped__') { - return true; - } else if (so["has(java.lang.String)"](name)) { - return true; - } else if (name.equals('toString')) { - return true; - } else { - return false; - } - } - }, + __has__ : __has__, __delete__ : function(name) { if (typeof(name) == 'number') { @@ -147,7 +157,8 @@ function main(globals, jvmarg) { }, __get__ : function(name) { - if (! this.__has__(name)) { + // don't call this.__has__(name); see comments above function __has__ + if (! __has__.call(this, name)) { return undefined; } if (typeof(name) == 'number') { @@ -162,7 +173,7 @@ function main(globals, jvmarg) { var args = prepareArgsArray(arguments); var r; try { - r = value.call(args); + r = value.call(Java.to(args, 'java.lang.Object[]')); } catch (e) { println("call to " + name + " failed!"); throw e; @@ -204,6 +215,18 @@ function main(globals, jvmarg) { } // define "writeln" and "write" if not defined + if (typeof(println) == 'undefined') { + println = function (str) { + java.lang.System.out.println(String(str)); + } + } + + if (typeof(print) == 'undefined') { + print = function (str) { + java.lang.System.out.print(String(str)); + } + } + if (typeof(writeln) == 'undefined') { writeln = println; } @@ -235,7 +258,7 @@ function main(globals, jvmarg) { this.jclasses = function() { forEachKlass(function (clazz) { - writeln(clazz.getName().asString() + " @" + clazz.getHandle().toString()); + writeln(clazz.getName().asString() + " @" + clazz.getAddress().toString()); }); } registerCommand("classes", "classes", "jclasses"); @@ -490,14 +513,14 @@ function systemLoader() { function forEachKlass(callback) { var VisitorClass = sapkg.memory.SystemDictionary.ClassVisitor; var visitor = new VisitorClass() { visit: callback }; - sa.sysDict["classesDo(sun.jvm.hotspot.memory.SystemDictionary$ClassVisitor)"](visitor); + sa.sysDict["classesDo(sun.jvm.hotspot.memory.SystemDictionary.ClassVisitor)"](visitor); } // iterate system dictionary for each 'Klass' and initiating loader function forEachKlassAndLoader(callback) { var VisitorClass = sapkg.memory.SystemDictionary.ClassAndLoaderVisitor; var visitor = new VisitorClass() { visit: callback }; - sa.sysDict["classesDo(sun.jvm.hotspot.memory.SystemDictionary$ClassAndLoaderVisitor)"](visitor); + sa.sysDict["classesDo(sun.jvm.hotspot.memory.SystemDictionary.ClassAndLoaderVisitor)"](visitor); } // iterate system dictionary for each primitive array klass @@ -522,7 +545,12 @@ function obj2oop(obj) { // iterates Java heap for each Oop function forEachOop(callback) { - sa.objHeap.iterate(new sapkg.oops.HeapVisitor() { doObj: callback }); + function empty() { } + sa.objHeap.iterate(new sapkg.oops.HeapVisitor() { + prologue: empty, + doObj: callback, + epilogue: empty + }); } // iterates Java heap for each Oop of given 'klass'. @@ -536,8 +564,14 @@ function forEachOopOfKlass(callback, klass, includeSubtypes) { if (includeSubtypes == undefined) { includeSubtypes = true; } + + function empty() { } sa.objHeap.iterateObjectsOfKlass( - new sapkg.oops.HeapVisitor() { doObj: callback }, + new sapkg.oops.HeapVisitor() { + prologue: empty, + doObj: callback, + epilogue: empty + }, klass, includeSubtypes); } @@ -746,9 +780,9 @@ while (tmp.itr.hasNext()) { // ignore; continue; } else { - // some type names have ':'. replace to make it as a + // some type names have ':', '<', '>', '*', ' '. replace to make it as a // JavaScript identifier - tmp.name = tmp.name.replace(':', '_').replace('<', '_').replace('>', '_').replace('*', '_').replace(' ', '_'); + tmp.name = ("" + tmp.name).replace(/[:<>* ]/g, '_'); eval("function read" + tmp.name + "(addr) {" + " return readVMType('" + tmp.name + "', addr);}"); eval("function print" + tmp.name + "(addr) {" + From 7d471dd141cca96be282d0dbe3019011068cc5ab Mon Sep 17 00:00:00 2001 From: Henry Jen Date: Fri, 9 Aug 2013 09:05:20 -0700 Subject: [PATCH 02/72] 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 7ade7987a0a8ccfde017811623d338b4c4b80237 Mon Sep 17 00:00:00 2001 From: Stefan Karlsson Date: Fri, 16 Aug 2013 13:22:32 +0200 Subject: [PATCH 03/72] 8007074: SIGSEGV at ParMarkBitMap::verify_clear() Replace the broken large pages implementation on Linux. New flag: -XX:+UseTransparentHugePages - Linux specific flag to turn on transparent huge page hinting with madvise(..., MAP_HUGETLB). Changed behavior: -XX:+UseLargePages - tries to use -XX:+UseTransparentHugePages before trying other large pages implementations (on Linux). Changed behavior: -XX:+UseHugeTLBFS - Use upfront allocation of Large Pages instead of using the broken implementation to dynamically committing large pages. Changed behavior: -XX:LargePageSizeInBytes - Turned off the ability to use this flag on Linux and provides warning to user if set to a value different than the OS chosen large page size. Changed behavior: Setting no large page size - Now defaults to use -XX:UseTransparentHugePages if the OS supports it. Previously, -XX:+UseHugeTLBFS was chosen if the OS was configured to use large pages. Reviewed-by: tschatzl, dcubed, brutisso --- hotspot/src/os/bsd/vm/os_bsd.cpp | 9 +- hotspot/src/os/linux/vm/globals_linux.hpp | 3 + hotspot/src/os/linux/vm/os_linux.cpp | 586 ++++++++++++++---- hotspot/src/os/linux/vm/os_linux.hpp | 14 + hotspot/src/os/solaris/vm/os_solaris.cpp | 8 +- hotspot/src/os/windows/vm/os_windows.cpp | 13 +- .../gc_implementation/g1/g1CollectedHeap.cpp | 8 +- .../g1/g1CollectorPolicy.cpp | 3 +- .../src/share/vm/memory/collectorPolicy.cpp | 2 + .../src/share/vm/memory/genCollectedHeap.cpp | 29 +- hotspot/src/share/vm/memory/metaspace.cpp | 2 +- hotspot/src/share/vm/memory/universe.cpp | 32 +- hotspot/src/share/vm/memory/universe.hpp | 2 +- hotspot/src/share/vm/prims/jni.cpp | 6 + hotspot/src/share/vm/runtime/globals.hpp | 3 + hotspot/src/share/vm/runtime/os.hpp | 4 +- hotspot/src/share/vm/runtime/virtualspace.cpp | 205 +++++- hotspot/src/share/vm/runtime/virtualspace.hpp | 1 + hotspot/src/share/vm/services/memTracker.hpp | 9 + .../share/vm/utilities/globalDefinitions.hpp | 16 + 20 files changed, 796 insertions(+), 159 deletions(-) diff --git a/hotspot/src/os/bsd/vm/os_bsd.cpp b/hotspot/src/os/bsd/vm/os_bsd.cpp index 1db3739fa84..6b636d379de 100644 --- a/hotspot/src/os/bsd/vm/os_bsd.cpp +++ b/hotspot/src/os/bsd/vm/os_bsd.cpp @@ -2325,7 +2325,9 @@ void os::large_page_init() { } -char* os::reserve_memory_special(size_t bytes, char* req_addr, bool exec) { +char* os::reserve_memory_special(size_t bytes, size_t alignment, char* req_addr, bool exec) { + fatal("This code is not used or maintained."); + // "exec" is passed in but not used. Creating the shared image for // the code cache doesn't have an SHM_X executable permission to check. assert(UseLargePages && UseSHM, "only for SHM large pages"); @@ -4752,3 +4754,8 @@ int os::get_core_path(char* buffer, size_t bufferSize) { return n; } +#ifndef PRODUCT +void TestReserveMemorySpecial_test() { + // No tests available for this platform +} +#endif diff --git a/hotspot/src/os/linux/vm/globals_linux.hpp b/hotspot/src/os/linux/vm/globals_linux.hpp index af4947b1b86..4dfccc3f6ee 100644 --- a/hotspot/src/os/linux/vm/globals_linux.hpp +++ b/hotspot/src/os/linux/vm/globals_linux.hpp @@ -40,6 +40,9 @@ product(bool, UseHugeTLBFS, false, \ "Use MAP_HUGETLB for large pages") \ \ + product(bool, UseTransparentHugePages, false, \ + "Use MADV_HUGEPAGE for large pages") \ + \ product(bool, LoadExecStackDllInVMThread, true, \ "Load DLLs with executable-stack attribute in the VM Thread") \ \ diff --git a/hotspot/src/os/linux/vm/os_linux.cpp b/hotspot/src/os/linux/vm/os_linux.cpp index df58be635d1..23d3457046d 100644 --- a/hotspot/src/os/linux/vm/os_linux.cpp +++ b/hotspot/src/os/linux/vm/os_linux.cpp @@ -2720,36 +2720,7 @@ void os::pd_commit_memory_or_exit(char* addr, size_t size, bool exec, int os::Linux::commit_memory_impl(char* addr, size_t size, size_t alignment_hint, bool exec) { - int err; - if (UseHugeTLBFS && alignment_hint > (size_t)vm_page_size()) { - int prot = exec ? PROT_READ|PROT_WRITE|PROT_EXEC : PROT_READ|PROT_WRITE; - uintptr_t res = - (uintptr_t) ::mmap(addr, size, prot, - MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS|MAP_HUGETLB, - -1, 0); - if (res != (uintptr_t) MAP_FAILED) { - if (UseNUMAInterleaving) { - numa_make_global(addr, size); - } - return 0; - } - - err = errno; // save errno from mmap() call above - - if (!recoverable_mmap_error(err)) { - // However, it is not clear that this loss of our reserved mapping - // happens with large pages on Linux or that we cannot recover - // from the loss. For now, we just issue a warning and we don't - // call vm_exit_out_of_memory(). This issue is being tracked by - // JBS-8007074. - warn_fail_commit_memory(addr, size, alignment_hint, exec, err); -// vm_exit_out_of_memory(size, OOM_MMAP_ERROR, -// "committing reserved memory."); - } - // Fall through and try to use small pages - } - - err = os::Linux::commit_memory_impl(addr, size, exec); + int err = os::Linux::commit_memory_impl(addr, size, exec); if (err == 0) { realign_memory(addr, size, alignment_hint); } @@ -2774,7 +2745,7 @@ void os::pd_commit_memory_or_exit(char* addr, size_t size, } void os::pd_realign_memory(char *addr, size_t bytes, size_t alignment_hint) { - if (UseHugeTLBFS && alignment_hint > (size_t)vm_page_size()) { + if (UseTransparentHugePages && alignment_hint > (size_t)vm_page_size()) { // We don't check the return value: madvise(MADV_HUGEPAGE) may not // be supported or the memory may already be backed by huge pages. ::madvise(addr, bytes, MADV_HUGEPAGE); @@ -2787,7 +2758,7 @@ void os::pd_free_memory(char *addr, size_t bytes, size_t alignment_hint) { // uncommitted at all. We don't do anything in this case to avoid creating a segment with // small pages on top of the SHM segment. This method always works for small pages, so we // allow that in any case. - if (alignment_hint <= (size_t)os::vm_page_size() || !UseSHM) { + if (alignment_hint <= (size_t)os::vm_page_size() || can_commit_large_page_memory()) { commit_memory(addr, bytes, alignment_hint, !ExecMem); } } @@ -3157,11 +3128,31 @@ bool os::unguard_memory(char* addr, size_t size) { return linux_mprotect(addr, size, PROT_READ|PROT_WRITE); } +bool os::Linux::transparent_huge_pages_sanity_check(bool warn, size_t page_size) { + bool result = false; + void *p = mmap(NULL, page_size * 2, PROT_READ|PROT_WRITE, + MAP_ANONYMOUS|MAP_PRIVATE, + -1, 0); + if (p != MAP_FAILED) { + void *aligned_p = align_ptr_up(p, page_size); + + result = madvise(aligned_p, page_size, MADV_HUGEPAGE) == 0; + + munmap(p, page_size * 2); + } + + if (warn && !result) { + warning("TransparentHugePages is not supported by the operating system."); + } + + return result; +} + bool os::Linux::hugetlbfs_sanity_check(bool warn, size_t page_size) { bool result = false; - void *p = mmap (NULL, page_size, PROT_READ|PROT_WRITE, - MAP_ANONYMOUS|MAP_PRIVATE|MAP_HUGETLB, - -1, 0); + void *p = mmap(NULL, page_size, PROT_READ|PROT_WRITE, + MAP_ANONYMOUS|MAP_PRIVATE|MAP_HUGETLB, + -1, 0); if (p != MAP_FAILED) { // We don't know if this really is a huge page or not. @@ -3182,12 +3173,10 @@ bool os::Linux::hugetlbfs_sanity_check(bool warn, size_t page_size) { } fclose(fp); } - munmap (p, page_size); - if (result) - return true; + munmap(p, page_size); } - if (warn) { + if (warn && !result) { warning("HugeTLBFS is not supported by the operating system."); } @@ -3235,82 +3224,114 @@ static void set_coredump_filter(void) { static size_t _large_page_size = 0; -void os::large_page_init() { - if (!UseLargePages) { - UseHugeTLBFS = false; - UseSHM = false; - return; - } +size_t os::Linux::find_large_page_size() { + size_t large_page_size = 0; - if (FLAG_IS_DEFAULT(UseHugeTLBFS) && FLAG_IS_DEFAULT(UseSHM)) { - // If UseLargePages is specified on the command line try both methods, - // if it's default, then try only HugeTLBFS. - if (FLAG_IS_DEFAULT(UseLargePages)) { - UseHugeTLBFS = true; - } else { - UseHugeTLBFS = UseSHM = true; - } - } - - if (LargePageSizeInBytes) { - _large_page_size = LargePageSizeInBytes; - } else { - // large_page_size on Linux is used to round up heap size. x86 uses either - // 2M or 4M page, depending on whether PAE (Physical Address Extensions) - // mode is enabled. AMD64/EM64T uses 2M page in 64bit mode. IA64 can use - // page as large as 256M. - // - // Here we try to figure out page size by parsing /proc/meminfo and looking - // for a line with the following format: - // Hugepagesize: 2048 kB - // - // If we can't determine the value (e.g. /proc is not mounted, or the text - // format has been changed), we'll use the largest page size supported by - // the processor. + // large_page_size on Linux is used to round up heap size. x86 uses either + // 2M or 4M page, depending on whether PAE (Physical Address Extensions) + // mode is enabled. AMD64/EM64T uses 2M page in 64bit mode. IA64 can use + // page as large as 256M. + // + // Here we try to figure out page size by parsing /proc/meminfo and looking + // for a line with the following format: + // Hugepagesize: 2048 kB + // + // If we can't determine the value (e.g. /proc is not mounted, or the text + // format has been changed), we'll use the largest page size supported by + // the processor. #ifndef ZERO - _large_page_size = IA32_ONLY(4 * M) AMD64_ONLY(2 * M) IA64_ONLY(256 * M) SPARC_ONLY(4 * M) - ARM_ONLY(2 * M) PPC_ONLY(4 * M); + large_page_size = IA32_ONLY(4 * M) AMD64_ONLY(2 * M) IA64_ONLY(256 * M) SPARC_ONLY(4 * M) + ARM_ONLY(2 * M) PPC_ONLY(4 * M); #endif // ZERO - FILE *fp = fopen("/proc/meminfo", "r"); - if (fp) { - while (!feof(fp)) { - int x = 0; - char buf[16]; - if (fscanf(fp, "Hugepagesize: %d", &x) == 1) { - if (x && fgets(buf, sizeof(buf), fp) && strcmp(buf, " kB\n") == 0) { - _large_page_size = x * K; - break; - } - } else { - // skip to next line - for (;;) { - int ch = fgetc(fp); - if (ch == EOF || ch == (int)'\n') break; - } + FILE *fp = fopen("/proc/meminfo", "r"); + if (fp) { + while (!feof(fp)) { + int x = 0; + char buf[16]; + if (fscanf(fp, "Hugepagesize: %d", &x) == 1) { + if (x && fgets(buf, sizeof(buf), fp) && strcmp(buf, " kB\n") == 0) { + large_page_size = x * K; + break; + } + } else { + // skip to next line + for (;;) { + int ch = fgetc(fp); + if (ch == EOF || ch == (int)'\n') break; } } - fclose(fp); } + fclose(fp); } - // print a warning if any large page related flag is specified on command line - bool warn_on_failure = !FLAG_IS_DEFAULT(UseHugeTLBFS); + if (!FLAG_IS_DEFAULT(LargePageSizeInBytes) && LargePageSizeInBytes != large_page_size) { + warning("Setting LargePageSizeInBytes has no effect on this OS. Large page size is " + SIZE_FORMAT "%s.", byte_size_in_proper_unit(large_page_size), + proper_unit_for_byte_size(large_page_size)); + } + return large_page_size; +} + +size_t os::Linux::setup_large_page_size() { + _large_page_size = Linux::find_large_page_size(); const size_t default_page_size = (size_t)Linux::page_size(); if (_large_page_size > default_page_size) { _page_sizes[0] = _large_page_size; _page_sizes[1] = default_page_size; _page_sizes[2] = 0; } - UseHugeTLBFS = UseHugeTLBFS && - Linux::hugetlbfs_sanity_check(warn_on_failure, _large_page_size); - if (UseHugeTLBFS) + return _large_page_size; +} + +bool os::Linux::setup_large_page_type(size_t page_size) { + if (FLAG_IS_DEFAULT(UseHugeTLBFS) && + FLAG_IS_DEFAULT(UseSHM) && + FLAG_IS_DEFAULT(UseTransparentHugePages)) { + // If UseLargePages is specified on the command line try all methods, + // if it's default, then try only UseTransparentHugePages. + if (FLAG_IS_DEFAULT(UseLargePages)) { + UseTransparentHugePages = true; + } else { + UseHugeTLBFS = UseTransparentHugePages = UseSHM = true; + } + } + + if (UseTransparentHugePages) { + bool warn_on_failure = !FLAG_IS_DEFAULT(UseTransparentHugePages); + if (transparent_huge_pages_sanity_check(warn_on_failure, page_size)) { + UseHugeTLBFS = false; + UseSHM = false; + return true; + } + UseTransparentHugePages = false; + } + + if (UseHugeTLBFS) { + bool warn_on_failure = !FLAG_IS_DEFAULT(UseHugeTLBFS); + if (hugetlbfs_sanity_check(warn_on_failure, page_size)) { + UseSHM = false; + return true; + } + UseHugeTLBFS = false; + } + + return UseSHM; +} + +void os::large_page_init() { + if (!UseLargePages) { + UseHugeTLBFS = false; + UseTransparentHugePages = false; UseSHM = false; + return; + } - UseLargePages = UseHugeTLBFS || UseSHM; + size_t large_page_size = Linux::setup_large_page_size(); + UseLargePages = Linux::setup_large_page_type(large_page_size); set_coredump_filter(); } @@ -3319,16 +3340,22 @@ void os::large_page_init() { #define SHM_HUGETLB 04000 #endif -char* os::reserve_memory_special(size_t bytes, char* req_addr, bool exec) { +char* os::Linux::reserve_memory_special_shm(size_t bytes, size_t alignment, char* req_addr, bool exec) { // "exec" is passed in but not used. Creating the shared image for // the code cache doesn't have an SHM_X executable permission to check. assert(UseLargePages && UseSHM, "only for SHM large pages"); + assert(is_ptr_aligned(req_addr, os::large_page_size()), "Unaligned address"); + + if (!is_size_aligned(bytes, os::large_page_size()) || alignment > os::large_page_size()) { + return NULL; // Fallback to small pages. + } key_t key = IPC_PRIVATE; char *addr; bool warn_on_failure = UseLargePages && (!FLAG_IS_DEFAULT(UseLargePages) || + !FLAG_IS_DEFAULT(UseSHM) || !FLAG_IS_DEFAULT(LargePageSizeInBytes) ); char msg[128]; @@ -3376,42 +3403,219 @@ char* os::reserve_memory_special(size_t bytes, char* req_addr, bool exec) { return NULL; } - if ((addr != NULL) && UseNUMAInterleaving) { - numa_make_global(addr, bytes); + return addr; +} + +static void warn_on_large_pages_failure(char* req_addr, size_t bytes, int error) { + assert(error == ENOMEM, "Only expect to fail if no memory is available"); + + bool warn_on_failure = UseLargePages && + (!FLAG_IS_DEFAULT(UseLargePages) || + !FLAG_IS_DEFAULT(UseHugeTLBFS) || + !FLAG_IS_DEFAULT(LargePageSizeInBytes)); + + if (warn_on_failure) { + char msg[128]; + jio_snprintf(msg, sizeof(msg), "Failed to reserve large pages memory req_addr: " + PTR_FORMAT " bytes: " SIZE_FORMAT " (errno = %d).", req_addr, bytes, error); + warning(msg); + } +} + +char* os::Linux::reserve_memory_special_huge_tlbfs_only(size_t bytes, char* req_addr, bool exec) { + assert(UseLargePages && UseHugeTLBFS, "only for Huge TLBFS large pages"); + assert(is_size_aligned(bytes, os::large_page_size()), "Unaligned size"); + assert(is_ptr_aligned(req_addr, os::large_page_size()), "Unaligned address"); + + int prot = exec ? PROT_READ|PROT_WRITE|PROT_EXEC : PROT_READ|PROT_WRITE; + char* addr = (char*)::mmap(req_addr, bytes, prot, + MAP_PRIVATE|MAP_ANONYMOUS|MAP_HUGETLB, + -1, 0); + + if (addr == MAP_FAILED) { + warn_on_large_pages_failure(req_addr, bytes, errno); + return NULL; } - // The memory is committed - MemTracker::record_virtual_memory_reserve_and_commit((address)addr, bytes, mtNone, CALLER_PC); + assert(is_ptr_aligned(addr, os::large_page_size()), "Must be"); return addr; } +char* os::Linux::reserve_memory_special_huge_tlbfs_mixed(size_t bytes, size_t alignment, char* req_addr, bool exec) { + size_t large_page_size = os::large_page_size(); + + assert(bytes >= large_page_size, "Shouldn't allocate large pages for small sizes"); + + // Allocate small pages. + + char* start; + if (req_addr != NULL) { + assert(is_ptr_aligned(req_addr, alignment), "Must be"); + assert(is_size_aligned(bytes, alignment), "Must be"); + start = os::reserve_memory(bytes, req_addr); + assert(start == NULL || start == req_addr, "Must be"); + } else { + start = os::reserve_memory_aligned(bytes, alignment); + } + + if (start == NULL) { + return NULL; + } + + assert(is_ptr_aligned(start, alignment), "Must be"); + + // os::reserve_memory_special will record this memory area. + // Need to release it here to prevent overlapping reservations. + MemTracker::record_virtual_memory_release((address)start, bytes); + + char* end = start + bytes; + + // Find the regions of the allocated chunk that can be promoted to large pages. + char* lp_start = (char*)align_ptr_up(start, large_page_size); + char* lp_end = (char*)align_ptr_down(end, large_page_size); + + size_t lp_bytes = lp_end - lp_start; + + assert(is_size_aligned(lp_bytes, large_page_size), "Must be"); + + if (lp_bytes == 0) { + // The mapped region doesn't even span the start and the end of a large page. + // Fall back to allocate a non-special area. + ::munmap(start, end - start); + return NULL; + } + + int prot = exec ? PROT_READ|PROT_WRITE|PROT_EXEC : PROT_READ|PROT_WRITE; + + + void* result; + + if (start != lp_start) { + result = ::mmap(start, lp_start - start, prot, + MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, + -1, 0); + if (result == MAP_FAILED) { + ::munmap(lp_start, end - lp_start); + return NULL; + } + } + + result = ::mmap(lp_start, lp_bytes, prot, + MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED|MAP_HUGETLB, + -1, 0); + if (result == MAP_FAILED) { + warn_on_large_pages_failure(req_addr, bytes, errno); + // If the mmap above fails, the large pages region will be unmapped and we + // have regions before and after with small pages. Release these regions. + // + // | mapped | unmapped | mapped | + // ^ ^ ^ ^ + // start lp_start lp_end end + // + ::munmap(start, lp_start - start); + ::munmap(lp_end, end - lp_end); + return NULL; + } + + if (lp_end != end) { + result = ::mmap(lp_end, end - lp_end, prot, + MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, + -1, 0); + if (result == MAP_FAILED) { + ::munmap(start, lp_end - start); + return NULL; + } + } + + return start; +} + +char* os::Linux::reserve_memory_special_huge_tlbfs(size_t bytes, size_t alignment, char* req_addr, bool exec) { + assert(UseLargePages && UseHugeTLBFS, "only for Huge TLBFS large pages"); + assert(is_ptr_aligned(req_addr, alignment), "Must be"); + assert(is_power_of_2(alignment), "Must be"); + assert(is_power_of_2(os::large_page_size()), "Must be"); + assert(bytes >= os::large_page_size(), "Shouldn't allocate large pages for small sizes"); + + if (is_size_aligned(bytes, os::large_page_size()) && alignment <= os::large_page_size()) { + return reserve_memory_special_huge_tlbfs_only(bytes, req_addr, exec); + } else { + return reserve_memory_special_huge_tlbfs_mixed(bytes, alignment, req_addr, exec); + } +} + +char* os::reserve_memory_special(size_t bytes, size_t alignment, char* req_addr, bool exec) { + assert(UseLargePages, "only for large pages"); + + char* addr; + if (UseSHM) { + addr = os::Linux::reserve_memory_special_shm(bytes, alignment, req_addr, exec); + } else { + assert(UseHugeTLBFS, "must be"); + addr = os::Linux::reserve_memory_special_huge_tlbfs(bytes, alignment, req_addr, exec); + } + + if (addr != NULL) { + if (UseNUMAInterleaving) { + numa_make_global(addr, bytes); + } + + // The memory is committed + MemTracker::record_virtual_memory_reserve_and_commit((address)addr, bytes, mtNone, CALLER_PC); + } + + return addr; +} + +bool os::Linux::release_memory_special_shm(char* base, size_t bytes) { + // detaching the SHM segment will also delete it, see reserve_memory_special_shm() + return shmdt(base) == 0; +} + +bool os::Linux::release_memory_special_huge_tlbfs(char* base, size_t bytes) { + return pd_release_memory(base, bytes); +} + bool os::release_memory_special(char* base, size_t bytes) { + assert(UseLargePages, "only for large pages"); + MemTracker::Tracker tkr = MemTracker::get_virtual_memory_release_tracker(); - // detaching the SHM segment will also delete it, see reserve_memory_special() - int rslt = shmdt(base); - if (rslt == 0) { + + bool res; + if (UseSHM) { + res = os::Linux::release_memory_special_shm(base, bytes); + } else { + assert(UseHugeTLBFS, "must be"); + res = os::Linux::release_memory_special_huge_tlbfs(base, bytes); + } + + if (res) { tkr.record((address)base, bytes); - return true; } else { tkr.discard(); - return false; } + + return res; } size_t os::large_page_size() { return _large_page_size; } -// HugeTLBFS allows application to commit large page memory on demand; -// with SysV SHM the entire memory region must be allocated as shared +// With SysV SHM the entire memory region must be allocated as shared // memory. +// HugeTLBFS allows application to commit large page memory on demand. +// However, when committing memory with HugeTLBFS fails, the region +// that was supposed to be committed will lose the old reservation +// and allow other threads to steal that memory region. Because of this +// behavior we can't commit HugeTLBFS memory. bool os::can_commit_large_page_memory() { - return UseHugeTLBFS; + return UseTransparentHugePages; } bool os::can_execute_large_page_memory() { - return UseHugeTLBFS; + return UseTransparentHugePages || UseHugeTLBFS; } // Reserve memory at an arbitrary address, only if that area is @@ -4563,21 +4767,23 @@ jint os::init_2(void) UseNUMA = false; } } - // With SHM large pages we cannot uncommit a page, so there's not way + // With SHM and HugeTLBFS large pages we cannot uncommit a page, so there's no way // we can make the adaptive lgrp chunk resizing work. If the user specified - // both UseNUMA and UseLargePages (or UseSHM) on the command line - warn and + // both UseNUMA and UseLargePages (or UseSHM/UseHugeTLBFS) on the command line - warn and // disable adaptive resizing. - if (UseNUMA && UseLargePages && UseSHM) { - if (!FLAG_IS_DEFAULT(UseNUMA)) { - if (FLAG_IS_DEFAULT(UseLargePages) && FLAG_IS_DEFAULT(UseSHM)) { + if (UseNUMA && UseLargePages && !can_commit_large_page_memory()) { + if (FLAG_IS_DEFAULT(UseNUMA)) { + UseNUMA = false; + } else { + if (FLAG_IS_DEFAULT(UseLargePages) && + FLAG_IS_DEFAULT(UseSHM) && + FLAG_IS_DEFAULT(UseHugeTLBFS)) { UseLargePages = false; } else { - warning("UseNUMA is not fully compatible with SHM large pages, disabling adaptive resizing"); + warning("UseNUMA is not fully compatible with SHM/HugeTLBFS large pages, disabling adaptive resizing"); UseAdaptiveSizePolicy = false; UseAdaptiveNUMAChunkSizing = false; } - } else { - UseNUMA = false; } } if (!UseNUMA && ForceNUMA) { @@ -5848,3 +6054,149 @@ void MemNotifyThread::start() { } #endif // JAVASE_EMBEDDED + + +/////////////// Unit tests /////////////// + +#ifndef PRODUCT + +#define test_log(...) \ + do {\ + if (VerboseInternalVMTests) { \ + tty->print_cr(__VA_ARGS__); \ + tty->flush(); \ + }\ + } while (false) + +class TestReserveMemorySpecial : AllStatic { + public: + static void small_page_write(void* addr, size_t size) { + size_t page_size = os::vm_page_size(); + + char* end = (char*)addr + size; + for (char* p = (char*)addr; p < end; p += page_size) { + *p = 1; + } + } + + static void test_reserve_memory_special_huge_tlbfs_only(size_t size) { + if (!UseHugeTLBFS) { + return; + } + + test_log("test_reserve_memory_special_huge_tlbfs_only(" SIZE_FORMAT ")", size); + + char* addr = os::Linux::reserve_memory_special_huge_tlbfs_only(size, NULL, false); + + if (addr != NULL) { + small_page_write(addr, size); + + os::Linux::release_memory_special_huge_tlbfs(addr, size); + } + } + + static void test_reserve_memory_special_huge_tlbfs_only() { + if (!UseHugeTLBFS) { + return; + } + + size_t lp = os::large_page_size(); + + for (size_t size = lp; size <= lp * 10; size += lp) { + test_reserve_memory_special_huge_tlbfs_only(size); + } + } + + static void test_reserve_memory_special_huge_tlbfs_mixed(size_t size, size_t alignment) { + if (!UseHugeTLBFS) { + return; + } + + test_log("test_reserve_memory_special_huge_tlbfs_mixed(" SIZE_FORMAT ", " SIZE_FORMAT ")", + size, alignment); + + assert(size >= os::large_page_size(), "Incorrect input to test"); + + char* addr = os::Linux::reserve_memory_special_huge_tlbfs_mixed(size, alignment, NULL, false); + + if (addr != NULL) { + small_page_write(addr, size); + + os::Linux::release_memory_special_huge_tlbfs(addr, size); + } + } + + static void test_reserve_memory_special_huge_tlbfs_mixed_all_alignments(size_t size) { + size_t lp = os::large_page_size(); + size_t ag = os::vm_allocation_granularity(); + + for (size_t alignment = ag; is_size_aligned(size, alignment); alignment *= 2) { + test_reserve_memory_special_huge_tlbfs_mixed(size, alignment); + } + } + + static void test_reserve_memory_special_huge_tlbfs_mixed() { + size_t lp = os::large_page_size(); + size_t ag = os::vm_allocation_granularity(); + + test_reserve_memory_special_huge_tlbfs_mixed_all_alignments(lp); + test_reserve_memory_special_huge_tlbfs_mixed_all_alignments(lp + ag); + test_reserve_memory_special_huge_tlbfs_mixed_all_alignments(lp + lp / 2); + test_reserve_memory_special_huge_tlbfs_mixed_all_alignments(lp * 2); + test_reserve_memory_special_huge_tlbfs_mixed_all_alignments(lp * 2 + ag); + test_reserve_memory_special_huge_tlbfs_mixed_all_alignments(lp * 2 - ag); + test_reserve_memory_special_huge_tlbfs_mixed_all_alignments(lp * 2 + lp / 2); + test_reserve_memory_special_huge_tlbfs_mixed_all_alignments(lp * 10); + test_reserve_memory_special_huge_tlbfs_mixed_all_alignments(lp * 10 + lp / 2); + } + + static void test_reserve_memory_special_huge_tlbfs() { + if (!UseHugeTLBFS) { + return; + } + + test_reserve_memory_special_huge_tlbfs_only(); + test_reserve_memory_special_huge_tlbfs_mixed(); + } + + static void test_reserve_memory_special_shm(size_t size, size_t alignment) { + if (!UseSHM) { + return; + } + + test_log("test_reserve_memory_special_shm(" SIZE_FORMAT ", " SIZE_FORMAT ")", size, alignment); + + char* addr = os::Linux::reserve_memory_special_shm(size, alignment, NULL, false); + + if (addr != NULL) { + assert(is_ptr_aligned(addr, alignment), "Check"); + assert(is_ptr_aligned(addr, os::large_page_size()), "Check"); + + small_page_write(addr, size); + + os::Linux::release_memory_special_shm(addr, size); + } + } + + static void test_reserve_memory_special_shm() { + size_t lp = os::large_page_size(); + size_t ag = os::vm_allocation_granularity(); + + for (size_t size = ag; size < lp * 3; size += ag) { + for (size_t alignment = ag; is_size_aligned(size, alignment); alignment *= 2) { + test_reserve_memory_special_shm(size, alignment); + } + } + } + + static void test() { + test_reserve_memory_special_huge_tlbfs(); + test_reserve_memory_special_shm(); + } +}; + +void TestReserveMemorySpecial_test() { + TestReserveMemorySpecial::test(); +} + +#endif diff --git a/hotspot/src/os/linux/vm/os_linux.hpp b/hotspot/src/os/linux/vm/os_linux.hpp index 8c5032fc23b..5fa24499319 100644 --- a/hotspot/src/os/linux/vm/os_linux.hpp +++ b/hotspot/src/os/linux/vm/os_linux.hpp @@ -32,6 +32,7 @@ typedef int (*pthread_getattr_func_type) (pthread_t, pthread_attr_t *); class Linux { friend class os; + friend class TestReserveMemorySpecial; // For signal-chaining #define MAXSIGNUM 32 @@ -92,8 +93,21 @@ class Linux { static void rebuild_cpu_to_node_map(); static GrowableArray* cpu_to_node() { return _cpu_to_node; } + static size_t find_large_page_size(); + static size_t setup_large_page_size(); + + static bool setup_large_page_type(size_t page_size); + static bool transparent_huge_pages_sanity_check(bool warn, size_t pages_size); static bool hugetlbfs_sanity_check(bool warn, size_t page_size); + static char* reserve_memory_special_shm(size_t bytes, size_t alignment, char* req_addr, bool exec); + static char* reserve_memory_special_huge_tlbfs(size_t bytes, size_t alignment, char* req_addr, bool exec); + static char* reserve_memory_special_huge_tlbfs_only(size_t bytes, char* req_addr, bool exec); + static char* reserve_memory_special_huge_tlbfs_mixed(size_t bytes, size_t alignment, char* req_addr, bool exec); + + static bool release_memory_special_shm(char* base, size_t bytes); + static bool release_memory_special_huge_tlbfs(char* base, size_t bytes); + static void print_full_memory_info(outputStream* st); static void print_distro_info(outputStream* st); static void print_libversion_info(outputStream* st); diff --git a/hotspot/src/os/solaris/vm/os_solaris.cpp b/hotspot/src/os/solaris/vm/os_solaris.cpp index 0a94cb536ab..c3e6e879077 100644 --- a/hotspot/src/os/solaris/vm/os_solaris.cpp +++ b/hotspot/src/os/solaris/vm/os_solaris.cpp @@ -3385,7 +3385,7 @@ bool os::Solaris::setup_large_pages(caddr_t start, size_t bytes, size_t align) { return true; } -char* os::reserve_memory_special(size_t size, char* addr, bool exec) { +char* os::reserve_memory_special(size_t size, size_t alignment, char* addr, bool exec) { fatal("os::reserve_memory_special should not be called on Solaris."); return NULL; } @@ -6601,3 +6601,9 @@ int os::get_core_path(char* buffer, size_t bufferSize) { return strlen(buffer); } + +#ifndef PRODUCT +void TestReserveMemorySpecial_test() { + // No tests available for this platform +} +#endif diff --git a/hotspot/src/os/windows/vm/os_windows.cpp b/hotspot/src/os/windows/vm/os_windows.cpp index 0674e6f3c83..64a593377c3 100644 --- a/hotspot/src/os/windows/vm/os_windows.cpp +++ b/hotspot/src/os/windows/vm/os_windows.cpp @@ -3156,7 +3156,12 @@ bool os::can_execute_large_page_memory() { return true; } -char* os::reserve_memory_special(size_t bytes, char* addr, bool exec) { +char* os::reserve_memory_special(size_t bytes, size_t alignment, char* addr, bool exec) { + assert(UseLargePages, "only for large pages"); + + if (!is_size_aligned(bytes, os::large_page_size()) || alignment > os::large_page_size()) { + return NULL; // Fallback to small pages. + } const DWORD prot = exec ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE; const DWORD flags = MEM_RESERVE | MEM_COMMIT | MEM_LARGE_PAGES; @@ -5638,3 +5643,9 @@ BOOL os::Advapi32Dll::AdvapiAvailable() { } #endif + +#ifndef PRODUCT +void TestReserveMemorySpecial_test() { + // No tests available for this platform +} +#endif diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp index 97a9a1fa54d..b163a464247 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp @@ -2006,10 +2006,12 @@ jint G1CollectedHeap::initialize() { size_t init_byte_size = collector_policy()->initial_heap_byte_size(); size_t max_byte_size = collector_policy()->max_heap_byte_size(); + size_t heap_alignment = collector_policy()->max_alignment(); // Ensure that the sizes are properly aligned. Universe::check_alignment(init_byte_size, HeapRegion::GrainBytes, "g1 heap"); Universe::check_alignment(max_byte_size, HeapRegion::GrainBytes, "g1 heap"); + Universe::check_alignment(max_byte_size, heap_alignment, "g1 heap"); _cg1r = new ConcurrentG1Refine(this); @@ -2026,12 +2028,8 @@ jint G1CollectedHeap::initialize() { // If this happens then we could end up using a non-optimal // compressed oops mode. - // Since max_byte_size is aligned to the size of a heap region (checked - // above). - Universe::check_alignment(max_byte_size, HeapRegion::GrainBytes, "g1 heap"); - ReservedSpace heap_rs = Universe::reserve_heap(max_byte_size, - HeapRegion::GrainBytes); + heap_alignment); // It is important to do this in a way such that concurrent readers can't // temporarily think something is in the heap. (I've actually seen this diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp index 4c6d2bbf877..75497e7c37f 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp @@ -313,7 +313,8 @@ G1CollectorPolicy::G1CollectorPolicy() : void G1CollectorPolicy::initialize_flags() { set_min_alignment(HeapRegion::GrainBytes); size_t card_table_alignment = GenRemSet::max_alignment_constraint(rem_set_name()); - set_max_alignment(MAX2(card_table_alignment, min_alignment())); + size_t page_size = UseLargePages ? os::large_page_size() : os::vm_page_size(); + set_max_alignment(MAX3(card_table_alignment, min_alignment(), page_size)); if (SurvivorRatio < 1) { vm_exit_during_initialization("Invalid survivor ratio specified"); } diff --git a/hotspot/src/share/vm/memory/collectorPolicy.cpp b/hotspot/src/share/vm/memory/collectorPolicy.cpp index cba14a01459..6a1967daeda 100644 --- a/hotspot/src/share/vm/memory/collectorPolicy.cpp +++ b/hotspot/src/share/vm/memory/collectorPolicy.cpp @@ -193,6 +193,8 @@ size_t GenCollectorPolicy::compute_max_alignment() { alignment = lcm(os::large_page_size(), alignment); } + assert(alignment >= min_alignment(), "Must be"); + return alignment; } diff --git a/hotspot/src/share/vm/memory/genCollectedHeap.cpp b/hotspot/src/share/vm/memory/genCollectedHeap.cpp index e0f82c02d86..3a5ab210c83 100644 --- a/hotspot/src/share/vm/memory/genCollectedHeap.cpp +++ b/hotspot/src/share/vm/memory/genCollectedHeap.cpp @@ -95,13 +95,13 @@ jint GenCollectedHeap::initialize() { guarantee(HeapWordSize == wordSize, "HeapWordSize must equal wordSize"); // The heap must be at least as aligned as generations. - size_t alignment = Generation::GenGrain; + size_t gen_alignment = Generation::GenGrain; _gen_specs = gen_policy()->generations(); // Make sure the sizes are all aligned. for (i = 0; i < _n_gens; i++) { - _gen_specs[i]->align(alignment); + _gen_specs[i]->align(gen_alignment); } // Allocate space for the heap. @@ -109,9 +109,11 @@ jint GenCollectedHeap::initialize() { char* heap_address; size_t total_reserved = 0; int n_covered_regions = 0; - ReservedSpace heap_rs(0); + ReservedSpace heap_rs; - heap_address = allocate(alignment, &total_reserved, + size_t heap_alignment = collector_policy()->max_alignment(); + + heap_address = allocate(heap_alignment, &total_reserved, &n_covered_regions, &heap_rs); if (!heap_rs.is_reserved()) { @@ -168,6 +170,8 @@ char* GenCollectedHeap::allocate(size_t alignment, const size_t pageSize = UseLargePages ? os::large_page_size() : os::vm_page_size(); + assert(alignment % pageSize == 0, "Must be"); + for (int i = 0; i < _n_gens; i++) { total_reserved += _gen_specs[i]->max_size(); if (total_reserved < _gen_specs[i]->max_size()) { @@ -175,24 +179,17 @@ char* GenCollectedHeap::allocate(size_t alignment, } n_covered_regions += _gen_specs[i]->n_covered_regions(); } - assert(total_reserved % pageSize == 0, - err_msg("Gen size; total_reserved=" SIZE_FORMAT ", pageSize=" - SIZE_FORMAT, total_reserved, pageSize)); + assert(total_reserved % alignment == 0, + err_msg("Gen size; total_reserved=" SIZE_FORMAT ", alignment=" + SIZE_FORMAT, total_reserved, alignment)); // Needed until the cardtable is fixed to have the right number // of covered regions. n_covered_regions += 2; - if (UseLargePages) { - assert(total_reserved != 0, "total_reserved cannot be 0"); - total_reserved = round_to(total_reserved, os::large_page_size()); - if (total_reserved < os::large_page_size()) { - vm_exit_during_initialization(overflow_msg); - } - } + *_total_reserved = total_reserved; + *_n_covered_regions = n_covered_regions; - *_total_reserved = total_reserved; - *_n_covered_regions = n_covered_regions; *heap_rs = Universe::reserve_heap(total_reserved, alignment); return heap_rs->base(); } diff --git a/hotspot/src/share/vm/memory/metaspace.cpp b/hotspot/src/share/vm/memory/metaspace.cpp index f654a13878c..cd46888c9c2 100644 --- a/hotspot/src/share/vm/memory/metaspace.cpp +++ b/hotspot/src/share/vm/memory/metaspace.cpp @@ -345,7 +345,7 @@ class VirtualSpaceNode : public CHeapObj { }; // byte_size is the size of the associated virtualspace. -VirtualSpaceNode::VirtualSpaceNode(size_t byte_size) : _top(NULL), _next(NULL), _rs(0), _container_count(0) { +VirtualSpaceNode::VirtualSpaceNode(size_t byte_size) : _top(NULL), _next(NULL), _rs(), _container_count(0) { // align up to vm allocation granularity byte_size = align_size_up(byte_size, os::vm_allocation_granularity()); diff --git a/hotspot/src/share/vm/memory/universe.cpp b/hotspot/src/share/vm/memory/universe.cpp index d85d23e015b..143c0c00c45 100644 --- a/hotspot/src/share/vm/memory/universe.cpp +++ b/hotspot/src/share/vm/memory/universe.cpp @@ -681,17 +681,23 @@ static const uint64_t NarrowOopHeapMax = (uint64_t(max_juint) + 1); // 32Gb // OopEncodingHeapMax == NarrowOopHeapMax << LogMinObjAlignmentInBytes; -char* Universe::preferred_heap_base(size_t heap_size, NARROW_OOP_MODE mode) { +char* Universe::preferred_heap_base(size_t heap_size, size_t alignment, NARROW_OOP_MODE mode) { + assert(is_size_aligned((size_t)OopEncodingHeapMax, alignment), "Must be"); + assert(is_size_aligned((size_t)NarrowOopHeapMax, alignment), "Must be"); + assert(is_size_aligned(heap_size, alignment), "Must be"); + + uintx heap_base_min_address_aligned = align_size_up(HeapBaseMinAddress, alignment); + size_t base = 0; #ifdef _LP64 if (UseCompressedOops) { assert(mode == UnscaledNarrowOop || mode == ZeroBasedNarrowOop || mode == HeapBasedNarrowOop, "mode is invalid"); - const size_t total_size = heap_size + HeapBaseMinAddress; + const size_t total_size = heap_size + heap_base_min_address_aligned; // Return specified base for the first request. if (!FLAG_IS_DEFAULT(HeapBaseMinAddress) && (mode == UnscaledNarrowOop)) { - base = HeapBaseMinAddress; + base = heap_base_min_address_aligned; // If the total size is small enough to allow UnscaledNarrowOop then // just use UnscaledNarrowOop. @@ -742,6 +748,8 @@ char* Universe::preferred_heap_base(size_t heap_size, NARROW_OOP_MODE mode) { } } #endif + + assert(is_ptr_aligned((char*)base, alignment), "Must be"); return (char*)base; // also return NULL (don't care) for 32-bit VM } @@ -867,27 +875,33 @@ ReservedSpace Universe::reserve_heap(size_t heap_size, size_t alignment) { size_t total_reserved = align_size_up(heap_size, alignment); assert(!UseCompressedOops || (total_reserved <= (OopEncodingHeapMax - os::vm_page_size())), "heap size is too big for compressed oops"); - char* addr = Universe::preferred_heap_base(total_reserved, Universe::UnscaledNarrowOop); - ReservedHeapSpace total_rs(total_reserved, alignment, UseLargePages, addr); + bool use_large_pages = UseLargePages && is_size_aligned(alignment, os::large_page_size()); + assert(!UseLargePages + || UseParallelOldGC + || use_large_pages, "Wrong alignment to use large pages"); + + char* addr = Universe::preferred_heap_base(total_reserved, alignment, Universe::UnscaledNarrowOop); + + ReservedHeapSpace total_rs(total_reserved, alignment, use_large_pages, addr); if (UseCompressedOops) { if (addr != NULL && !total_rs.is_reserved()) { // Failed to reserve at specified address - the requested memory // region is taken already, for example, by 'java' launcher. // Try again to reserver heap higher. - addr = Universe::preferred_heap_base(total_reserved, Universe::ZeroBasedNarrowOop); + addr = Universe::preferred_heap_base(total_reserved, alignment, Universe::ZeroBasedNarrowOop); ReservedHeapSpace total_rs0(total_reserved, alignment, - UseLargePages, addr); + use_large_pages, addr); if (addr != NULL && !total_rs0.is_reserved()) { // Failed to reserve at specified address again - give up. - addr = Universe::preferred_heap_base(total_reserved, Universe::HeapBasedNarrowOop); + addr = Universe::preferred_heap_base(total_reserved, alignment, Universe::HeapBasedNarrowOop); assert(addr == NULL, ""); ReservedHeapSpace total_rs1(total_reserved, alignment, - UseLargePages, addr); + use_large_pages, addr); total_rs = total_rs1; } else { total_rs = total_rs0; diff --git a/hotspot/src/share/vm/memory/universe.hpp b/hotspot/src/share/vm/memory/universe.hpp index 1ebe5f2b57e..a8b541d03a1 100644 --- a/hotspot/src/share/vm/memory/universe.hpp +++ b/hotspot/src/share/vm/memory/universe.hpp @@ -346,7 +346,7 @@ class Universe: AllStatic { }; static NARROW_OOP_MODE narrow_oop_mode(); static const char* narrow_oop_mode_to_string(NARROW_OOP_MODE mode); - static char* preferred_heap_base(size_t heap_size, NARROW_OOP_MODE mode); + static char* preferred_heap_base(size_t heap_size, size_t alignment, NARROW_OOP_MODE mode); static char* preferred_metaspace_base(size_t heap_size, NARROW_OOP_MODE mode); static address narrow_oop_base() { return _narrow_oop._base; } static bool is_narrow_oop_base(void* addr) { return (narrow_oop_base() == (address)addr); } diff --git a/hotspot/src/share/vm/prims/jni.cpp b/hotspot/src/share/vm/prims/jni.cpp index 188cf4a6e60..acf79f53525 100644 --- a/hotspot/src/share/vm/prims/jni.cpp +++ b/hotspot/src/share/vm/prims/jni.cpp @@ -5027,9 +5027,15 @@ _JNI_IMPORT_OR_EXPORT_ jint JNICALL JNI_GetDefaultJavaVMInitArgs(void *args_) { tty->print_cr("Running test: " #unit_test_function_call); \ unit_test_function_call +// Forward declaration +void TestReservedSpace_test(); +void TestReserveMemorySpecial_test(); + void execute_internal_vm_tests() { if (ExecuteInternalVMTests) { tty->print_cr("Running internal VM tests"); + run_unit_test(TestReservedSpace_test()); + run_unit_test(TestReserveMemorySpecial_test()); run_unit_test(GlobalDefinitions::test_globals()); run_unit_test(GCTimerAllTest::all()); run_unit_test(arrayOopDesc::test_max_array_length()); diff --git a/hotspot/src/share/vm/runtime/globals.hpp b/hotspot/src/share/vm/runtime/globals.hpp index 9b67389af47..f54939096e9 100644 --- a/hotspot/src/share/vm/runtime/globals.hpp +++ b/hotspot/src/share/vm/runtime/globals.hpp @@ -1933,6 +1933,9 @@ class CommandLineFlags { notproduct(bool, ExecuteInternalVMTests, false, \ "Enable execution of internal VM tests.") \ \ + notproduct(bool, VerboseInternalVMTests, false, \ + "Turn on logging for internal VM tests.") \ + \ product_pd(bool, UseTLAB, "Use thread-local object allocation") \ \ product_pd(bool, ResizeTLAB, \ diff --git a/hotspot/src/share/vm/runtime/os.hpp b/hotspot/src/share/vm/runtime/os.hpp index 03497e1973b..38efad386f1 100644 --- a/hotspot/src/share/vm/runtime/os.hpp +++ b/hotspot/src/share/vm/runtime/os.hpp @@ -328,8 +328,8 @@ class os: AllStatic { static char* non_memory_address_word(); // reserve, commit and pin the entire memory region - static char* reserve_memory_special(size_t size, char* addr = NULL, - bool executable = false); + static char* reserve_memory_special(size_t size, size_t alignment, + char* addr, bool executable); static bool release_memory_special(char* addr, size_t bytes); static void large_page_init(); static size_t large_page_size(); diff --git a/hotspot/src/share/vm/runtime/virtualspace.cpp b/hotspot/src/share/vm/runtime/virtualspace.cpp index 9096a034cef..9e01fe0292f 100644 --- a/hotspot/src/share/vm/runtime/virtualspace.cpp +++ b/hotspot/src/share/vm/runtime/virtualspace.cpp @@ -42,8 +42,19 @@ // ReservedSpace + +// Dummy constructor +ReservedSpace::ReservedSpace() : _base(NULL), _size(0), _noaccess_prefix(0), + _alignment(0), _special(false), _executable(false) { +} + ReservedSpace::ReservedSpace(size_t size) { - initialize(size, 0, false, NULL, 0, false); + size_t page_size = os::page_size_for_region(size, size, 1); + bool large_pages = page_size != (size_t)os::vm_page_size(); + // Don't force the alignment to be large page aligned, + // since that will waste memory. + size_t alignment = os::vm_allocation_granularity(); + initialize(size, alignment, large_pages, NULL, 0, false); } ReservedSpace::ReservedSpace(size_t size, size_t alignment, @@ -129,16 +140,18 @@ void ReservedSpace::initialize(size_t size, size_t alignment, bool large, if (special) { - base = os::reserve_memory_special(size, requested_address, executable); + base = os::reserve_memory_special(size, alignment, requested_address, executable); if (base != NULL) { if (failed_to_reserve_as_requested(base, requested_address, size, true)) { // OS ignored requested address. Try different address. return; } - // Check alignment constraints + // Check alignment constraints. assert((uintptr_t) base % alignment == 0, - "Large pages returned a non-aligned address"); + err_msg("Large pages returned a non-aligned address, base: " + PTR_FORMAT " alignment: " PTR_FORMAT, + base, (void*)(uintptr_t)alignment)); _special = true; } else { // failed; try to reserve regular memory below @@ -715,4 +728,188 @@ void VirtualSpace::print() { tty->print_cr(" - [low_b, high_b]: [" INTPTR_FORMAT ", " INTPTR_FORMAT "]", low_boundary(), high_boundary()); } + +/////////////// Unit tests /////////////// + +#ifndef PRODUCT + +#define test_log(...) \ + do {\ + if (VerboseInternalVMTests) { \ + tty->print_cr(__VA_ARGS__); \ + tty->flush(); \ + }\ + } while (false) + +class TestReservedSpace : AllStatic { + public: + static void small_page_write(void* addr, size_t size) { + size_t page_size = os::vm_page_size(); + + char* end = (char*)addr + size; + for (char* p = (char*)addr; p < end; p += page_size) { + *p = 1; + } + } + + static void release_memory_for_test(ReservedSpace rs) { + if (rs.special()) { + guarantee(os::release_memory_special(rs.base(), rs.size()), "Shouldn't fail"); + } else { + guarantee(os::release_memory(rs.base(), rs.size()), "Shouldn't fail"); + } + } + + static void test_reserved_space1(size_t size, size_t alignment) { + test_log("test_reserved_space1(%p)", (void*) (uintptr_t) size); + + assert(is_size_aligned(size, alignment), "Incorrect input parameters"); + + ReservedSpace rs(size, // size + alignment, // alignment + UseLargePages, // large + NULL, // requested_address + 0); // noacces_prefix + + test_log(" rs.special() == %d", rs.special()); + + assert(rs.base() != NULL, "Must be"); + assert(rs.size() == size, "Must be"); + + assert(is_ptr_aligned(rs.base(), alignment), "aligned sizes should always give aligned addresses"); + assert(is_size_aligned(rs.size(), alignment), "aligned sizes should always give aligned addresses"); + + if (rs.special()) { + small_page_write(rs.base(), size); + } + + release_memory_for_test(rs); + } + + static void test_reserved_space2(size_t size) { + test_log("test_reserved_space2(%p)", (void*)(uintptr_t)size); + + assert(is_size_aligned(size, os::vm_allocation_granularity()), "Must be at least AG aligned"); + + ReservedSpace rs(size); + + test_log(" rs.special() == %d", rs.special()); + + assert(rs.base() != NULL, "Must be"); + assert(rs.size() == size, "Must be"); + + if (rs.special()) { + small_page_write(rs.base(), size); + } + + release_memory_for_test(rs); + } + + static void test_reserved_space3(size_t size, size_t alignment, bool maybe_large) { + test_log("test_reserved_space3(%p, %p, %d)", + (void*)(uintptr_t)size, (void*)(uintptr_t)alignment, maybe_large); + + assert(is_size_aligned(size, os::vm_allocation_granularity()), "Must be at least AG aligned"); + assert(is_size_aligned(size, alignment), "Must be at least aligned against alignment"); + + bool large = maybe_large && UseLargePages && size >= os::large_page_size(); + + ReservedSpace rs(size, alignment, large, false); + + test_log(" rs.special() == %d", rs.special()); + + assert(rs.base() != NULL, "Must be"); + assert(rs.size() == size, "Must be"); + + if (rs.special()) { + small_page_write(rs.base(), size); + } + + release_memory_for_test(rs); + } + + + static void test_reserved_space1() { + size_t size = 2 * 1024 * 1024; + size_t ag = os::vm_allocation_granularity(); + + test_reserved_space1(size, ag); + test_reserved_space1(size * 2, ag); + test_reserved_space1(size * 10, ag); + } + + static void test_reserved_space2() { + size_t size = 2 * 1024 * 1024; + size_t ag = os::vm_allocation_granularity(); + + test_reserved_space2(size * 1); + test_reserved_space2(size * 2); + test_reserved_space2(size * 10); + test_reserved_space2(ag); + test_reserved_space2(size - ag); + test_reserved_space2(size); + test_reserved_space2(size + ag); + test_reserved_space2(size * 2); + test_reserved_space2(size * 2 - ag); + test_reserved_space2(size * 2 + ag); + test_reserved_space2(size * 3); + test_reserved_space2(size * 3 - ag); + test_reserved_space2(size * 3 + ag); + test_reserved_space2(size * 10); + test_reserved_space2(size * 10 + size / 2); + } + + static void test_reserved_space3() { + size_t ag = os::vm_allocation_granularity(); + + test_reserved_space3(ag, ag , false); + test_reserved_space3(ag * 2, ag , false); + test_reserved_space3(ag * 3, ag , false); + test_reserved_space3(ag * 2, ag * 2, false); + test_reserved_space3(ag * 4, ag * 2, false); + test_reserved_space3(ag * 8, ag * 2, false); + test_reserved_space3(ag * 4, ag * 4, false); + test_reserved_space3(ag * 8, ag * 4, false); + test_reserved_space3(ag * 16, ag * 4, false); + + if (UseLargePages) { + size_t lp = os::large_page_size(); + + // Without large pages + test_reserved_space3(lp, ag * 4, false); + test_reserved_space3(lp * 2, ag * 4, false); + test_reserved_space3(lp * 4, ag * 4, false); + test_reserved_space3(lp, lp , false); + test_reserved_space3(lp * 2, lp , false); + test_reserved_space3(lp * 3, lp , false); + test_reserved_space3(lp * 2, lp * 2, false); + test_reserved_space3(lp * 4, lp * 2, false); + test_reserved_space3(lp * 8, lp * 2, false); + + // With large pages + test_reserved_space3(lp, ag * 4 , true); + test_reserved_space3(lp * 2, ag * 4, true); + test_reserved_space3(lp * 4, ag * 4, true); + test_reserved_space3(lp, lp , true); + test_reserved_space3(lp * 2, lp , true); + test_reserved_space3(lp * 3, lp , true); + test_reserved_space3(lp * 2, lp * 2, true); + test_reserved_space3(lp * 4, lp * 2, true); + test_reserved_space3(lp * 8, lp * 2, true); + } + } + + static void test_reserved_space() { + test_reserved_space1(); + test_reserved_space2(); + test_reserved_space3(); + } +}; + +void TestReservedSpace_test() { + TestReservedSpace::test_reserved_space(); +} + +#endif // PRODUCT + #endif diff --git a/hotspot/src/share/vm/runtime/virtualspace.hpp b/hotspot/src/share/vm/runtime/virtualspace.hpp index 0a959e900a0..bca9b6c14fc 100644 --- a/hotspot/src/share/vm/runtime/virtualspace.hpp +++ b/hotspot/src/share/vm/runtime/virtualspace.hpp @@ -53,6 +53,7 @@ class ReservedSpace VALUE_OBJ_CLASS_SPEC { public: // Constructor + ReservedSpace(); ReservedSpace(size_t size); ReservedSpace(size_t size, size_t alignment, bool large, char* requested_address = NULL, diff --git a/hotspot/src/share/vm/services/memTracker.hpp b/hotspot/src/share/vm/services/memTracker.hpp index 364c6b4f235..1072e5d6a3d 100644 --- a/hotspot/src/share/vm/services/memTracker.hpp +++ b/hotspot/src/share/vm/services/memTracker.hpp @@ -87,6 +87,8 @@ class MemTracker : AllStatic { MEMFLAGS flags, address pc = 0, Thread* thread = NULL) { } static inline void record_virtual_memory_commit(address addr, size_t size, address pc = 0, Thread* thread = NULL) { } + static inline void record_virtual_memory_release(address addr, size_t size, + Thread* thread = NULL) { } static inline void record_virtual_memory_type(address base, MEMFLAGS flags, Thread* thread = NULL) { } static inline Tracker get_realloc_tracker() { return _tkr; } @@ -372,6 +374,13 @@ class MemTracker : AllStatic { tkr.record(addr, size, flags, pc); } + static inline void record_virtual_memory_release(address addr, size_t size, + Thread* thread = NULL) { + if (is_on()) { + Tracker tkr(Tracker::Release, thread); + tkr.record(addr, size); + } + } // record memory type on virtual memory base address static inline void record_virtual_memory_type(address base, MEMFLAGS flags, diff --git a/hotspot/src/share/vm/utilities/globalDefinitions.hpp b/hotspot/src/share/vm/utilities/globalDefinitions.hpp index 3b4be625a35..bbee85c8b23 100644 --- a/hotspot/src/share/vm/utilities/globalDefinitions.hpp +++ b/hotspot/src/share/vm/utilities/globalDefinitions.hpp @@ -402,6 +402,14 @@ const jlong CompressedKlassPointersBase = NOT_LP64(0) LP64_ONLY(CONST64(0x800000 #define align_size_up_(size, alignment) (((size) + ((alignment) - 1)) & ~((alignment) - 1)) +inline bool is_size_aligned(size_t size, size_t alignment) { + return align_size_up_(size, alignment) == size; +} + +inline bool is_ptr_aligned(void* ptr, size_t alignment) { + return align_size_up_((intptr_t)ptr, (intptr_t)alignment) == (intptr_t)ptr; +} + inline intptr_t align_size_up(intptr_t size, intptr_t alignment) { return align_size_up_(size, alignment); } @@ -414,6 +422,14 @@ inline intptr_t align_size_down(intptr_t size, intptr_t alignment) { #define is_size_aligned_(size, alignment) ((size) == (align_size_up_(size, alignment))) +inline void* align_ptr_up(void* ptr, size_t alignment) { + return (void*)align_size_up((intptr_t)ptr, (intptr_t)alignment); +} + +inline void* align_ptr_down(void* ptr, size_t alignment) { + return (void*)align_size_down((intptr_t)ptr, (intptr_t)alignment); +} + // Align objects by rounding up their size, in HeapWord units. #define align_object_size_(size) align_size_up_(size, MinObjAlignment) From d0aa753d993b3d87e5ae673645a5dbce9a0021fe Mon Sep 17 00:00:00 2001 From: Jon Masamitsu Date: Fri, 16 Aug 2013 06:12:46 -0700 Subject: [PATCH 04/72] 8022817: CMS should not shrink if compaction was not done Reviewed-by: ysr, mgerdin --- .../concurrentMarkSweepGeneration.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp index fe53388a05f..04b550c718b 100644 --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp @@ -3460,7 +3460,9 @@ void ConcurrentMarkSweepGeneration::shrink_by(size_t bytes) { void ConcurrentMarkSweepGeneration::shrink(size_t bytes) { assert_locked_or_safepoint(Heap_lock); size_t size = ReservedSpace::page_align_size_down(bytes); - if (size > 0) { + // Only shrink if a compaction was done so that all the free space + // in the generation is in a contiguous block at the end. + if (size > 0 && did_compact()) { shrink_by(size); } } @@ -8696,9 +8698,10 @@ void SweepClosure::lookahead_and_flush(FreeChunk* fc, size_t chunk_size) { assert(inFreeRange(), "Should only be called if currently in a free range."); HeapWord* const eob = ((HeapWord*)fc) + chunk_size; assert(_sp->used_region().contains(eob - 1), - err_msg("eob = " PTR_FORMAT " out of bounds wrt _sp = [" PTR_FORMAT "," PTR_FORMAT ")" + err_msg("eob = " PTR_FORMAT " eob-1 = " PTR_FORMAT " _limit = " PTR_FORMAT + " out of bounds wrt _sp = [" PTR_FORMAT "," PTR_FORMAT ")" " when examining fc = " PTR_FORMAT "(" SIZE_FORMAT ")", - _limit, _sp->bottom(), _sp->end(), fc, chunk_size)); + eob, eob-1, _limit, _sp->bottom(), _sp->end(), fc, chunk_size)); if (eob >= _limit) { assert(eob == _limit || fc->is_free(), "Only a free chunk should allow us to cross over the limit"); if (CMSTraceSweeper) { From 0e8b1016432bdd072bc7c6e24e50e5de88ff32e0 Mon Sep 17 00:00:00 2001 From: Alan Bateman Date: Wed, 21 Aug 2013 09:59:12 +0100 Subject: [PATCH 05/72] 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 06/72] 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 07/72] 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 08/72] 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 09/72] 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 10/72] 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 11/72] 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 12/72] 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 13/72] 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 14/72] 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 15/72] 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 16/72] 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 17/72] 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 18/72] 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 19/72] 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 b2e2be304684bc50b36ea7e53bf7844521cf91cd Mon Sep 17 00:00:00 2001 From: Mike Duigou Date: Tue, 20 Aug 2013 17:44:35 -0700 Subject: [PATCH 20/72] 8023433: Improve 'make help' Reviewed-by: tbell --- NewMakefile.gmk | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/NewMakefile.gmk b/NewMakefile.gmk index 101ebe06278..4ddbc89c841 100644 --- a/NewMakefile.gmk +++ b/NewMakefile.gmk @@ -98,6 +98,7 @@ help: $(info . # corba and jdk) $(info . make all # Compile everything, all repos and images) $(info . make images # Create complete j2sdk and j2re images) + $(info . make docs # Create javadocs) $(info . make overlay-images # Create limited images for sparc 64 bit platforms) $(info . make profiles # Create complete j2re compact profile images) $(info . make bootcycle-images # Build images twice, second time with newly build JDK) @@ -109,7 +110,7 @@ help: $(info . make test # Run tests, default is all tests (see TEST below)) $(info ) $(info Targets for specific components) - $(info (Component is any of langtools, corba, jaxp, jaxws, hotspot, jdk, images or overlay-images)) + $(info (Component is any of langtools, corba, jaxp, jaxws, hotspot, jdk, nashorn, images, overlay-images, docs or test)) $(info . make # Build and everything it depends on. ) $(info . make -only # Build only, without dependencies. This) $(info . # is faster but can result in incorrect build results!) From 1e740c466f8264e4538c1a1134db49486cdfba01 Mon Sep 17 00:00:00 2001 From: Staffan Larsen Date: Wed, 21 Aug 2013 13:18:52 +0200 Subject: [PATCH 21/72] 8022808: Kitchensink hangs on macos Use pthread_mach_thread_np() instead of mach_thread_self() to avoid leaking resources Reviewed-by: dholmes, rbackman --- hotspot/src/os/bsd/vm/os_bsd.cpp | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/hotspot/src/os/bsd/vm/os_bsd.cpp b/hotspot/src/os/bsd/vm/os_bsd.cpp index 55043ad243a..cc6d13e2c1d 100644 --- a/hotspot/src/os/bsd/vm/os_bsd.cpp +++ b/hotspot/src/os/bsd/vm/os_bsd.cpp @@ -642,13 +642,14 @@ objc_registerThreadWithCollector_t objc_registerThreadWithCollectorFunction = NU #endif #ifdef __APPLE__ -static uint64_t locate_unique_thread_id() { +static uint64_t locate_unique_thread_id(mach_port_t mach_thread_port) { // Additional thread_id used to correlate threads in SA thread_identifier_info_data_t m_ident_info; mach_msg_type_number_t count = THREAD_IDENTIFIER_INFO_COUNT; - thread_info(::mach_thread_self(), THREAD_IDENTIFIER_INFO, + thread_info(mach_thread_port, THREAD_IDENTIFIER_INFO, (thread_info_t) &m_ident_info, &count); + return m_ident_info.thread_id; } #endif @@ -679,9 +680,14 @@ static void *java_start(Thread *thread) { } #ifdef __APPLE__ - // thread_id is mach thread on macos - osthread->set_thread_id(::mach_thread_self()); - osthread->set_unique_thread_id(locate_unique_thread_id()); + // thread_id is mach thread on macos, which pthreads graciously caches and provides for us + mach_port_t thread_id = ::pthread_mach_thread_np(::pthread_self()); + guarantee(thread_id != 0, "thread id missing from pthreads"); + osthread->set_thread_id(thread_id); + + uint64_t unique_thread_id = locate_unique_thread_id(thread_id); + guarantee(unique_thread_id != 0, "unique thread id was not found"); + osthread->set_unique_thread_id(unique_thread_id); #else // thread_id is pthread_id on BSD osthread->set_thread_id(::pthread_self()); @@ -843,8 +849,14 @@ bool os::create_attached_thread(JavaThread* thread) { // Store pthread info into the OSThread #ifdef __APPLE__ - osthread->set_thread_id(::mach_thread_self()); - osthread->set_unique_thread_id(locate_unique_thread_id()); + // thread_id is mach thread on macos, which pthreads graciously caches and provides for us + mach_port_t thread_id = ::pthread_mach_thread_np(::pthread_self()); + guarantee(thread_id != 0, "just checking"); + osthread->set_thread_id(thread_id); + + uint64_t unique_thread_id = locate_unique_thread_id(thread_id); + guarantee(unique_thread_id != 0, "just checking"); + osthread->set_unique_thread_id(unique_thread_id); #else osthread->set_thread_id(::pthread_self()); #endif @@ -1115,7 +1127,7 @@ size_t os::lasterror(char *buf, size_t len) { intx os::current_thread_id() { #ifdef __APPLE__ - return (intx)::mach_thread_self(); + return (intx)::pthread_mach_thread_np(::pthread_self()); #else return (intx)::pthread_self(); #endif From edd19c0f397d2a86a19899074dc3ff0bea88d602 Mon Sep 17 00:00:00 2001 From: Stuart Marks Date: Thu, 22 Aug 2013 15:54:50 -0700 Subject: [PATCH 22/72] 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 23/72] 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 24/72] 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 4c3c3b6caacc75eec2a3bfd4b66262a9b6c2e578 Mon Sep 17 00:00:00 2001 From: Bengt Rutisson Date: Wed, 21 Aug 2013 22:35:56 +0200 Subject: [PATCH 25/72] 8022872: G1: Use correct GC cause for young GC triggered by humongous allocations Reviewed-by: tonyp, tschatzl --- .../share/vm/gc_implementation/g1/g1CollectedHeap.cpp | 11 +++++++---- .../share/vm/gc_implementation/g1/g1CollectedHeap.hpp | 7 ++++--- .../vm/gc_implementation/g1/vm_operations_g1.cpp | 3 --- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp index 97a9a1fa54d..055474297a6 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp @@ -981,7 +981,8 @@ HeapWord* G1CollectedHeap::attempt_allocation_slow(size_t word_size, if (should_try_gc) { bool succeeded; - result = do_collection_pause(word_size, gc_count_before, &succeeded); + result = do_collection_pause(word_size, gc_count_before, &succeeded, + GCCause::_g1_inc_collection_pause); if (result != NULL) { assert(succeeded, "only way to get back a non-NULL result"); return result; @@ -1106,7 +1107,8 @@ HeapWord* G1CollectedHeap::attempt_allocation_humongous(size_t word_size, // enough space for the allocation to succeed after the pause. bool succeeded; - result = do_collection_pause(word_size, gc_count_before, &succeeded); + result = do_collection_pause(word_size, gc_count_before, &succeeded, + GCCause::_g1_humongous_allocation); if (result != NULL) { assert(succeeded, "only way to get back a non-NULL result"); return result; @@ -3700,14 +3702,15 @@ void G1CollectedHeap::gc_epilogue(bool full /* Ignored */) { HeapWord* G1CollectedHeap::do_collection_pause(size_t word_size, unsigned int gc_count_before, - bool* succeeded) { + bool* succeeded, + GCCause::Cause gc_cause) { assert_heap_not_locked_and_not_at_safepoint(); g1_policy()->record_stop_world_start(); VM_G1IncCollectionPause op(gc_count_before, word_size, false, /* should_initiate_conc_mark */ g1_policy()->max_pause_time_ms(), - GCCause::_g1_inc_collection_pause); + gc_cause); VMThread::execute(&op); HeapWord* result = op.result(); diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp index cfcbb3f7c94..aecaa5e97ac 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp @@ -776,9 +776,10 @@ protected: // it has to be read while holding the Heap_lock. Currently, both // methods that call do_collection_pause() release the Heap_lock // before the call, so it's easy to read gc_count_before just before. - HeapWord* do_collection_pause(size_t word_size, - unsigned int gc_count_before, - bool* succeeded); + HeapWord* do_collection_pause(size_t word_size, + unsigned int gc_count_before, + bool* succeeded, + GCCause::Cause gc_cause); // The guts of the incremental collection pause, executed by the vm // thread. It returns false if it is unable to do the collection due diff --git a/hotspot/src/share/vm/gc_implementation/g1/vm_operations_g1.cpp b/hotspot/src/share/vm/gc_implementation/g1/vm_operations_g1.cpp index 3be06e6ae10..9f298da3873 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/vm_operations_g1.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/vm_operations_g1.cpp @@ -70,9 +70,6 @@ VM_G1IncCollectionPause::VM_G1IncCollectionPause( guarantee(target_pause_time_ms > 0.0, err_msg("target_pause_time_ms = %1.6lf should be positive", target_pause_time_ms)); - guarantee(word_size == 0 || gc_cause == GCCause::_g1_inc_collection_pause, - "we can only request an allocation if the GC cause is for " - "an incremental GC pause"); _gc_cause = gc_cause; } From ff7c51cd184ccf7c61561554eaaab800bf461fb9 Mon Sep 17 00:00:00 2001 From: Brian Burkhalter Date: Thu, 22 Aug 2013 13:32:22 -0700 Subject: [PATCH 26/72] 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 27/72] 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 28/72] 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 29/72] 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 30/72] 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 31/72] 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 32/72] 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 33/72] 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 34/72] 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 35/72] 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 36/72] 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 37/72] 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 38/72] 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 39/72] 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 40/72] 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 41/72] 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 42/72] 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 43/72] 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 44/72] 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 f3ca3801d9915c9fa6b70bc085584e959bfcca67 Mon Sep 17 00:00:00 2001 From: Vladimir Kempik Date: Wed, 21 Aug 2013 22:12:11 -0700 Subject: [PATCH 45/72] 8020530: Non heap memory size calculated incorrectly Reviewed-by: coleenp, sla --- hotspot/src/share/vm/services/management.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/hotspot/src/share/vm/services/management.cpp b/hotspot/src/share/vm/services/management.cpp index a2c8944ee42..5cc0cc4ffcc 100644 --- a/hotspot/src/share/vm/services/management.cpp +++ b/hotspot/src/share/vm/services/management.cpp @@ -876,8 +876,6 @@ JVM_ENTRY(jobject, jmm_GetMemoryUsage(JNIEnv* env, jboolean heap)) total_used += u.used(); total_committed += u.committed(); - // if any one of the memory pool has undefined init_size or max_size, - // set it to -1 if (u.init_size() == (size_t)-1) { has_undefined_init_size = true; } @@ -894,6 +892,15 @@ JVM_ENTRY(jobject, jmm_GetMemoryUsage(JNIEnv* env, jboolean heap)) } } + // if any one of the memory pool has undefined init_size or max_size, + // set it to -1 + if (has_undefined_init_size) { + total_init = (size_t)-1; + } + if (has_undefined_max_size) { + total_max = (size_t)-1; + } + MemoryUsage usage((heap ? InitialHeapSize : total_init), total_used, total_committed, From 2df9b70f5e59694313df2acb99f92c2e701ce449 Mon Sep 17 00:00:00 2001 From: Harold Seigel Date: Thu, 22 Aug 2013 11:52:27 -0400 Subject: [PATCH 46/72] 7121403: [TESTBUG] runtime/7051189/Xchecksig.sh fails on 64bit solaris 8023393: Need to suppress info message if -Xcheck:jni used with libjsig.dylab on Mac OSX Rewrite 7051189 test in Java, port Linux fix for 7051189 to Mac OSX. Reviewed-by: coleenp, dholmes, mseledtsov, ccheung --- hotspot/src/os/bsd/vm/os_bsd.cpp | 8 +- hotspot/test/runtime/7051189/Xchecksig.sh | 126 ------------------ .../runtime/XCheckJniJsig/XCheckJSig.java | 82 ++++++++++++ 3 files changed, 88 insertions(+), 128 deletions(-) delete mode 100644 hotspot/test/runtime/7051189/Xchecksig.sh create mode 100644 hotspot/test/runtime/XCheckJniJsig/XCheckJSig.java diff --git a/hotspot/src/os/bsd/vm/os_bsd.cpp b/hotspot/src/os/bsd/vm/os_bsd.cpp index cc6d13e2c1d..1db3739fa84 100644 --- a/hotspot/src/os/bsd/vm/os_bsd.cpp +++ b/hotspot/src/os/bsd/vm/os_bsd.cpp @@ -3287,11 +3287,15 @@ void os::Bsd::install_signal_handlers() { // and if UserSignalHandler is installed all bets are off if (CheckJNICalls) { if (libjsig_is_loaded) { - tty->print_cr("Info: libjsig is activated, all active signal checking is disabled"); + if (PrintJNIResolving) { + tty->print_cr("Info: libjsig is activated, all active signal checking is disabled"); + } check_signals = false; } if (AllowUserSignalHandlers) { - tty->print_cr("Info: AllowUserSignalHandlers is activated, all active signal checking is disabled"); + if (PrintJNIResolving) { + tty->print_cr("Info: AllowUserSignalHandlers is activated, all active signal checking is disabled"); + } check_signals = false; } } diff --git a/hotspot/test/runtime/7051189/Xchecksig.sh b/hotspot/test/runtime/7051189/Xchecksig.sh deleted file mode 100644 index 143e1445624..00000000000 --- a/hotspot/test/runtime/7051189/Xchecksig.sh +++ /dev/null @@ -1,126 +0,0 @@ -# -# Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -# or visit www.oracle.com if you need additional information or have any -# questions. -# - - -# @test Xchecksig.sh -# @bug 7051189 -# @summary Need to suppress info message if -xcheck:jni used with libjsig.so -# @run shell Xchecksig.sh -# - -if [ "${TESTSRC}" = "" ] -then - TESTSRC=${PWD} - echo "TESTSRC not set. Using "${TESTSRC}" as default" -fi -echo "TESTSRC=${TESTSRC}" -## Adding common setup Variables for running shell tests. -. ${TESTSRC}/../../test_env.sh - -OS=`uname -s` -case "$OS" in - Windows_* | CYGWIN_* ) - printf "Not testing libjsig.so on Windows. PASSED.\n " - exit 0 - ;; -esac - -JAVA=${TESTJAVA}${FS}bin${FS}java - -# LD_PRELOAD arch needs to match the binary we run, so run the java -# 64-bit binary directly if we are testing 64-bit (bin/ARCH/java). -# Check if TESTVMOPS contains -d64, but cannot use -# java ${TESTVMOPS} to run "java -d64" with LD_PRELOAD. - -if [ ${OS} -eq "SunOS" ] -then - printf "SunOS test TESTVMOPTS = ${TESTVMOPTS}" - printf ${TESTVMOPTS} | grep d64 > /dev/null - if [ $? -eq 0 ] - then - printf "SunOS 64-bit test\n" - BIT_FLAG=-d64 - fi -fi - -ARCH=`uname -p` -case $ARCH in - i386) - if [ X${BIT_FLAG} != "X" ] - then - ARCH=amd64 - JAVA=${TESTJAVA}${FS}bin${FS}${ARCH}${FS}java - fi - ;; - sparc) - if [ X${BIT_FLAG} != "X" ] - then - ARCH=sparcv9 - JAVA=${TESTJAVA}${FS}bin${FS}${ARCH}${FS}java - fi - ;; - * ) - printf "Not testing architecture $ARCH, skipping test.\n" - exit 0 - ;; -esac - -LIBJSIG=${COMPILEJAVA}${FS}jre${FS}lib${FS}${ARCH}${FS}libjsig.so - -# If libjsig and binary do not match, skip test. - -A=`file ${LIBJSIG} | awk '{ print $3 }'` -B=`file ${JAVA} | awk '{ print $3 }'` - -if [ $A -ne $B ] -then - printf "Mismatching binary and library to preload, skipping test.\n" - exit 0 -fi - -if [ ! -f ${LIBJSIG} ] -then - printf "Skipping test: libjsig missing for given architecture: ${LIBJSIG}\n" - exit 0 -fi -# Use java -version to test, java version info appears on stderr, -# the libjsig message we are removing appears on stdout. - -# grep returns zero meaning found, non-zero means not found: - -LD_PRELOAD=${LIBJSIG} ${JAVA} ${TESTVMOPTS} -Xcheck:jni -version 2>&1 | grep "libjsig is activated" -if [ $? -eq 0 ]; then - printf "Failed: -Xcheck:jni prints message when libjsig.so is loaded.\n" - exit 1 -fi - - -LD_PRELOAD=${LIBJSIG} ${JAVA} ${TESTVMOPTS} -Xcheck:jni -verbose:jni -version 2>&1 | grep "libjsig is activated" -if [ $? != 0 ]; then - printf "Failed: -Xcheck:jni does not print message when libjsig.so is loaded and -verbose:jni is set.\n" - exit 1 -fi - -printf "PASSED\n" -exit 0 - diff --git a/hotspot/test/runtime/XCheckJniJsig/XCheckJSig.java b/hotspot/test/runtime/XCheckJniJsig/XCheckJSig.java new file mode 100644 index 00000000000..ae0ad73cd3d --- /dev/null +++ b/hotspot/test/runtime/XCheckJniJsig/XCheckJSig.java @@ -0,0 +1,82 @@ +/* + * 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 7051189 8023393 + * @summary Need to suppress info message if -Xcheck:jni is used with libjsig.so + * @library /testlibrary + * @run main XCheckJSig + */ + +import java.util.*; +import com.oracle.java.testlibrary.*; + +public class XCheckJSig { + public static void main(String args[]) throws Throwable { + + System.out.println("Regression test for bugs 7051189 and 8023393"); + if (!Platform.isSolaris() && !Platform.isLinux() && !Platform.isOSX()) { + System.out.println("Test only applicable on Solaris, Linux, and Mac OSX, skipping"); + return; + } + + String jdk_path = System.getProperty("test.jdk"); + String os_arch = Platform.getOsArch(); + String libjsig; + String env_var; + if (Platform.isOSX()) { + libjsig = jdk_path + "/jre/lib/server/libjsig.dylib"; + env_var = "DYLD_INSERT_LIBRARIES"; + } else { + libjsig = jdk_path + "/jre/lib/" + os_arch + "/libjsig.so"; + env_var = "LD_PRELOAD"; + } + String java_program; + if (Platform.isSolaris()) { + // On Solaris, need to call the 64-bit Java directly in order for + // LD_PRELOAD to work because libjsig.so is 64-bit. + java_program = jdk_path + "/jre/bin/" + os_arch + "/java"; + } else { + java_program = JDKToolFinder.getJDKTool("java"); + } + // If this test fails, these might be useful to know. + System.out.println("libjsig: " + libjsig); + System.out.println("osArch: " + os_arch); + System.out.println("java_program: " + java_program); + + ProcessBuilder pb = new ProcessBuilder(java_program, "-Xcheck:jni", "-version"); + Map env = pb.environment(); + env.put(env_var, libjsig); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldNotContain("libjsig is activated"); + output.shouldHaveExitValue(0); + + pb = new ProcessBuilder(java_program, "-Xcheck:jni", "-verbose:jni", "-version"); + env = pb.environment(); + env.put(env_var, libjsig); + output = new OutputAnalyzer(pb.start()); + output.shouldContain("libjsig is activated"); + output.shouldHaveExitValue(0); + } +} From f61c7dc88b26e52426264783dfdc63e097b60657 Mon Sep 17 00:00:00 2001 From: Ioi Lam Date: Thu, 22 Aug 2013 10:20:50 -0700 Subject: [PATCH 47/72] 8023406: make/windows/build_vm_def.sh takes too long even when BUILD_WIN_SA != 1 Avoid dumping C++ vtable when BUILD_WIN_SA != 1 Reviewed-by: dcubed, sla, tbell --- hotspot/make/windows/build_vm_def.sh | 18 ++++++++++++++++-- hotspot/make/windows/makefiles/debug.make | 3 --- hotspot/make/windows/makefiles/fastdebug.make | 3 --- hotspot/make/windows/makefiles/product.make | 3 --- .../make/windows/makefiles/projectcreator.make | 6 +++++- hotspot/make/windows/makefiles/vm.make | 8 ++++++++ 6 files changed, 29 insertions(+), 12 deletions(-) diff --git a/hotspot/make/windows/build_vm_def.sh b/hotspot/make/windows/build_vm_def.sh index c54a1803b93..fa82d26a81a 100644 --- a/hotspot/make/windows/build_vm_def.sh +++ b/hotspot/make/windows/build_vm_def.sh @@ -42,8 +42,6 @@ else MKS_HOME=`dirname "$SH"` fi -echo "EXPORTS" > vm1.def - AWK="$MKS_HOME/awk.exe" if [ ! -e $AWK ]; then AWK="$MKS_HOME/gawk.exe" @@ -55,6 +53,22 @@ CAT="$MKS_HOME/cat.exe" RM="$MKS_HOME/rm.exe" DUMPBIN="link.exe /dump" +if [ "$1" = "-nosa" ]; then + echo EXPORTS > vm.def + echo "" + echo "***" + echo "*** Not building SA: BUILD_WIN_SA != 1" + echo "*** C++ Vtables NOT included in vm.def" + echo "*** This jvm.dll will NOT work properly with SA." + echo "***" + echo "*** When in doubt, set BUILD_WIN_SA=1, clean and rebuild." + echo "***" + echo "" + exit +fi + +echo "EXPORTS" > vm1.def + # When called from IDE the first param should contain the link version, otherwise may be nill if [ "x$1" != "x" ]; then LD_VER="$1" diff --git a/hotspot/make/windows/makefiles/debug.make b/hotspot/make/windows/makefiles/debug.make index 2fca2182841..14a07083434 100644 --- a/hotspot/make/windows/makefiles/debug.make +++ b/hotspot/make/windows/makefiles/debug.make @@ -49,9 +49,6 @@ HS_BUILD_ID=$(HS_BUILD_VER)-debug # Force resources to be rebuilt every time $(Res_Files): FORCE -vm.def: $(Obj_Files) - sh $(WorkSpace)/make/windows/build_vm_def.sh - $(AOUT): $(Res_Files) $(Obj_Files) vm.def $(LD) @<< $(LD_FLAGS) /out:$@ /implib:$*.lib /def:vm.def $(Obj_Files) $(Res_Files) diff --git a/hotspot/make/windows/makefiles/fastdebug.make b/hotspot/make/windows/makefiles/fastdebug.make index cde98f214ea..a85e129cf6e 100644 --- a/hotspot/make/windows/makefiles/fastdebug.make +++ b/hotspot/make/windows/makefiles/fastdebug.make @@ -48,9 +48,6 @@ HS_BUILD_ID=$(HS_BUILD_VER)-fastdebug # Force resources to be rebuilt every time $(Res_Files): FORCE -vm.def: $(Obj_Files) - sh $(WorkSpace)/make/windows/build_vm_def.sh - $(AOUT): $(Res_Files) $(Obj_Files) vm.def $(LD) @<< $(LD_FLAGS) /out:$@ /implib:$*.lib /def:vm.def $(Obj_Files) $(Res_Files) diff --git a/hotspot/make/windows/makefiles/product.make b/hotspot/make/windows/makefiles/product.make index 407484cd46e..713ec0e54ca 100644 --- a/hotspot/make/windows/makefiles/product.make +++ b/hotspot/make/windows/makefiles/product.make @@ -51,9 +51,6 @@ HS_BUILD_ID=$(HS_BUILD_VER) # Force resources to be rebuilt every time $(Res_Files): FORCE -vm.def: $(Obj_Files) - sh $(WorkSpace)/make/windows/build_vm_def.sh - $(AOUT): $(Res_Files) $(Obj_Files) vm.def $(LD) @<< $(LD_FLAGS) /out:$@ /implib:$*.lib /def:vm.def $(Obj_Files) $(Res_Files) diff --git a/hotspot/make/windows/makefiles/projectcreator.make b/hotspot/make/windows/makefiles/projectcreator.make index a5336c6bf51..d512796f8fe 100644 --- a/hotspot/make/windows/makefiles/projectcreator.make +++ b/hotspot/make/windows/makefiles/projectcreator.make @@ -92,6 +92,10 @@ ProjectCreatorIDEOptions = \ -disablePch getThread_windows_$(Platform_arch).cpp \ -disablePch_compiler2 opcodes.cpp +!if "$(BUILD_WIN_SA)" != "1" +BUILD_VM_DEF_FLAG=-nosa +!endif + # Common options for the IDE builds for c1, and c2 ProjectCreatorIDEOptions=\ $(ProjectCreatorIDEOptions) \ @@ -104,7 +108,7 @@ ProjectCreatorIDEOptions=\ -jdkTargetRoot $(HOTSPOTJDKDIST) \ -define ALIGN_STACK_FRAMES \ -define VM_LITTLE_ENDIAN \ - -prelink "" "Generating vm.def..." "cd $(HOTSPOTBUILDSPACE)\%f\%b set HOTSPOTMKSHOME=$(HOTSPOTMKSHOME) set JAVA_HOME=$(HOTSPOTJDKDIST) $(HOTSPOTMKSHOME)\sh $(HOTSPOTWORKSPACE)\make\windows\build_vm_def.sh $(LD_VER)" \ + -prelink "" "Generating vm.def..." "cd $(HOTSPOTBUILDSPACE)\%f\%b set HOTSPOTMKSHOME=$(HOTSPOTMKSHOME) set JAVA_HOME=$(HOTSPOTJDKDIST) $(HOTSPOTMKSHOME)\sh $(HOTSPOTWORKSPACE)\make\windows\build_vm_def.sh $(BUILD_VM_DEF_FLAG) $(LD_VER)" \ -ignoreFile jsig.c \ -ignoreFile jvmtiEnvRecommended.cpp \ -ignoreFile jvmtiEnvStub.cpp \ diff --git a/hotspot/make/windows/makefiles/vm.make b/hotspot/make/windows/makefiles/vm.make index 8b5e23d4a28..229be6870a7 100644 --- a/hotspot/make/windows/makefiles/vm.make +++ b/hotspot/make/windows/makefiles/vm.make @@ -393,3 +393,11 @@ default:: _build_pch_file.obj: @echo #include "precompiled.hpp" > ../generated/_build_pch_file.cpp $(CXX) $(CXX_FLAGS) /Fp"vm.pch" /Yc"precompiled.hpp" /c ../generated/_build_pch_file.cpp + +!if "$(BUILD_WIN_SA)" != "1" +BUILD_VM_DEF_FLAG=-nosa +!endif + +vm.def: $(Obj_Files) + sh $(WorkSpace)/make/windows/build_vm_def.sh $(BUILD_VM_DEF_FLAG) + From 5c6c0a8d1dc5e47897094766190ebe5d8f3e5d14 Mon Sep 17 00:00:00 2001 From: Jiangli Zhou Date: Thu, 22 Aug 2013 19:27:42 -0400 Subject: [PATCH 48/72] 8023547: com/sun/jdi/RedefineMulti.sh fails with IllegalArgumentException after JDK-8021948 Need to check if the constant pool mapping returns 0. Reviewed-by: coleenp, sspitsyn --- .../src/share/vm/prims/jvmtiRedefineClasses.cpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp b/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp index dd1553af46c..803cf9a7545 100644 --- a/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp +++ b/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp @@ -1554,18 +1554,22 @@ bool VM_RedefineClasses::rewrite_cp_refs(instanceKlassHandle scratch_class, return false; } - // rewrite sourc file name index: + // rewrite source file name index: u2 source_file_name_idx = scratch_class->source_file_name_index(); if (source_file_name_idx != 0) { u2 new_source_file_name_idx = find_new_index(source_file_name_idx); - scratch_class->set_source_file_name_index(new_source_file_name_idx); + if (new_source_file_name_idx != 0) { + scratch_class->set_source_file_name_index(new_source_file_name_idx); + } } // rewrite class generic signature index: u2 generic_signature_index = scratch_class->generic_signature_index(); if (generic_signature_index != 0) { u2 new_generic_signature_index = find_new_index(generic_signature_index); - scratch_class->set_generic_signature_index(new_generic_signature_index); + if (new_generic_signature_index != 0) { + scratch_class->set_generic_signature_index(new_generic_signature_index); + } } return true; @@ -1737,7 +1741,10 @@ void VM_RedefineClasses::rewrite_cp_refs_in_method(methodHandle method, for (int i = 0; i < len; i++) { const u2 cp_index = elem[i].name_cp_index; - elem[i].name_cp_index = find_new_index(cp_index); + const u2 new_cp_index = find_new_index(cp_index); + if (new_cp_index != 0) { + elem[i].name_cp_index = new_cp_index; + } } } } // end rewrite_cp_refs_in_method() From ea17b8decf3f892b7d15750ef466e162abb717d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20Gr=C3=B6nlund?= Date: Fri, 23 Aug 2013 10:36:34 +0200 Subject: [PATCH 49/72] 8023457: Event based tracing framework needs a mutex for thread groups Reviewed-by: acorn, sla --- hotspot/src/share/vm/runtime/mutexLocker.cpp | 16 +++++++++++----- hotspot/src/share/vm/runtime/mutexLocker.hpp | 8 +++++--- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/hotspot/src/share/vm/runtime/mutexLocker.cpp b/hotspot/src/share/vm/runtime/mutexLocker.cpp index 14e65081d62..f513b7b376c 100644 --- a/hotspot/src/share/vm/runtime/mutexLocker.cpp +++ b/hotspot/src/share/vm/runtime/mutexLocker.cpp @@ -124,13 +124,15 @@ Monitor* GCTaskManager_lock = NULL; Mutex* Management_lock = NULL; Monitor* Service_lock = NULL; -Mutex* Stacktrace_lock = NULL; +Monitor* PeriodicTask_lock = NULL; -Monitor* JfrQuery_lock = NULL; +#ifdef INCLUDE_TRACE +Mutex* JfrStacktrace_lock = NULL; Monitor* JfrMsg_lock = NULL; Mutex* JfrBuffer_lock = NULL; Mutex* JfrStream_lock = NULL; -Monitor* PeriodicTask_lock = NULL; +Mutex* JfrThreadGroups_lock = NULL; +#endif #define MAX_NUM_MUTEX 128 static Monitor * _mutex_array[MAX_NUM_MUTEX]; @@ -206,7 +208,6 @@ void mutex_init() { def(Patching_lock , Mutex , special, true ); // used for safepointing and code patching. def(ObjAllocPost_lock , Monitor, special, false); def(Service_lock , Monitor, special, true ); // used for service thread operations - def(Stacktrace_lock , Mutex, special, true ); // used for JFR stacktrace database def(JmethodIdCreation_lock , Mutex , leaf, true ); // used for creating jmethodIDs. def(SystemDictionary_lock , Monitor, leaf, true ); // lookups done by VM thread @@ -272,11 +273,16 @@ void mutex_init() { def(Debug3_lock , Mutex , nonleaf+4, true ); def(ProfileVM_lock , Monitor, special, false); // used for profiling of the VMThread def(CompileThread_lock , Monitor, nonleaf+5, false ); + def(PeriodicTask_lock , Monitor, nonleaf+5, true); +#ifdef INCLUDE_TRACE def(JfrMsg_lock , Monitor, leaf, true); def(JfrBuffer_lock , Mutex, nonleaf+1, true); + def(JfrThreadGroups_lock , Mutex, nonleaf+1, true); def(JfrStream_lock , Mutex, nonleaf+2, true); - def(PeriodicTask_lock , Monitor, nonleaf+5, true); + def(JfrStacktrace_lock , Mutex, special, true ); +#endif + } GCMutexLocker::GCMutexLocker(Monitor * mutex) { diff --git a/hotspot/src/share/vm/runtime/mutexLocker.hpp b/hotspot/src/share/vm/runtime/mutexLocker.hpp index 7a2e240bd4f..d98b8d890fd 100644 --- a/hotspot/src/share/vm/runtime/mutexLocker.hpp +++ b/hotspot/src/share/vm/runtime/mutexLocker.hpp @@ -137,13 +137,15 @@ extern Mutex* HotCardCache_lock; // protects the hot card cache extern Mutex* Management_lock; // a lock used to serialize JVM management extern Monitor* Service_lock; // a lock used for service thread operation -extern Mutex* Stacktrace_lock; // used to guard access to the stacktrace table +extern Monitor* PeriodicTask_lock; // protects the periodic task structure -extern Monitor* JfrQuery_lock; // protects JFR use +#ifdef INCLUDE_TRACE +extern Mutex* JfrStacktrace_lock; // used to guard access to the JFR stacktrace table extern Monitor* JfrMsg_lock; // protects JFR messaging extern Mutex* JfrBuffer_lock; // protects JFR buffer operations extern Mutex* JfrStream_lock; // protects JFR stream access -extern Monitor* PeriodicTask_lock; // protects the periodic task structure +extern Mutex* JfrThreadGroups_lock; // protects JFR access to Thread Groups +#endif // A MutexLocker provides mutual exclusion with respect to a given mutex // for the scope which contains the locker. The lock is an OS lock, not From 6549fc2f25928669e9a0d4760fe455d53cdfe12a Mon Sep 17 00:00:00 2001 From: Alejandro Murillo Date: Fri, 23 Aug 2013 03:14:54 -0700 Subject: [PATCH 50/72] 8023635: new hotspot build - hs25-b48 Reviewed-by: jcoomes --- hotspot/make/hotspot_version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hotspot/make/hotspot_version b/hotspot/make/hotspot_version index c35e01558a7..a16ed251dc6 100644 --- a/hotspot/make/hotspot_version +++ b/hotspot/make/hotspot_version @@ -35,7 +35,7 @@ HOTSPOT_VM_COPYRIGHT=Copyright 2013 HS_MAJOR_VER=25 HS_MINOR_VER=0 -HS_BUILD_NUMBER=47 +HS_BUILD_NUMBER=48 JDK_MAJOR_VER=1 JDK_MINOR_VER=8 From 993de8ba281f16d97886fcfe90b62a6854783125 Mon Sep 17 00:00:00 2001 From: Bill Pittore Date: Fri, 23 Aug 2013 20:33:02 -0400 Subject: [PATCH 51/72] 8014135: The JVMTI specification does not conform to recent changes in JNI specification Added support for statically linked agents Reviewed-by: sspitsyn, bobv, coleenp --- hotspot/src/os/posix/vm/os_posix.cpp | 51 ++++++++- hotspot/src/os/windows/vm/os_windows.cpp | 69 ++++++++++++ hotspot/src/share/vm/prims/jvmti.xml | 117 +++++++++++++++++---- hotspot/src/share/vm/prims/jvmtiExport.cpp | 61 ++++++----- hotspot/src/share/vm/runtime/arguments.hpp | 19 ++++ hotspot/src/share/vm/runtime/os.cpp | 61 +++++++++++ hotspot/src/share/vm/runtime/os.hpp | 18 ++++ hotspot/src/share/vm/runtime/thread.cpp | 42 ++++---- 8 files changed, 373 insertions(+), 65 deletions(-) diff --git a/hotspot/src/os/posix/vm/os_posix.cpp b/hotspot/src/os/posix/vm/os_posix.cpp index bf6a1fafacd..d3ae881d931 100644 --- a/hotspot/src/os/posix/vm/os_posix.cpp +++ b/hotspot/src/os/posix/vm/os_posix.cpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 1999, 2012, 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 @@ -260,6 +260,55 @@ FILE* os::open(int fd, const char* mode) { return ::fdopen(fd, mode); } +void* os::get_default_process_handle() { + return (void*)::dlopen(NULL, RTLD_LAZY); +} + +// Builds a platform dependent Agent_OnLoad_ function name +// which is used to find statically linked in agents. +// Parameters: +// sym_name: Symbol in library we are looking for +// lib_name: Name of library to look in, NULL for shared libs. +// is_absolute_path == true if lib_name is absolute path to agent +// such as "/a/b/libL.so" +// == false if only the base name of the library is passed in +// such as "L" +char* os::build_agent_function_name(const char *sym_name, const char *lib_name, + bool is_absolute_path) { + char *agent_entry_name; + size_t len; + size_t name_len; + size_t prefix_len = strlen(JNI_LIB_PREFIX); + size_t suffix_len = strlen(JNI_LIB_SUFFIX); + const char *start; + + if (lib_name != NULL) { + len = name_len = strlen(lib_name); + if (is_absolute_path) { + // Need to strip path, prefix and suffix + if ((start = strrchr(lib_name, *os::file_separator())) != NULL) { + lib_name = ++start; + } + if (len <= (prefix_len + suffix_len)) { + return NULL; + } + lib_name += prefix_len; + name_len = strlen(lib_name) - suffix_len; + } + } + len = (lib_name != NULL ? name_len : 0) + strlen(sym_name) + 2; + agent_entry_name = NEW_C_HEAP_ARRAY_RETURN_NULL(char, len, mtThread); + if (agent_entry_name == NULL) { + return NULL; + } + strcpy(agent_entry_name, sym_name); + if (lib_name != NULL) { + strcat(agent_entry_name, "_"); + strncat(agent_entry_name, lib_name, name_len); + } + return agent_entry_name; +} + os::WatcherThreadCrashProtection::WatcherThreadCrashProtection() { assert(Thread::current()->is_Watcher_thread(), "Must be WatcherThread"); } diff --git a/hotspot/src/os/windows/vm/os_windows.cpp b/hotspot/src/os/windows/vm/os_windows.cpp index 0674e6f3c83..ffc894b1b6a 100644 --- a/hotspot/src/os/windows/vm/os_windows.cpp +++ b/hotspot/src/os/windows/vm/os_windows.cpp @@ -5394,6 +5394,75 @@ inline BOOL os::Advapi32Dll::AdvapiAvailable() { return true; } +void* os::get_default_process_handle() { + return (void*)GetModuleHandle(NULL); +} + +// Builds a platform dependent Agent_OnLoad_ function name +// which is used to find statically linked in agents. +// Additionally for windows, takes into account __stdcall names. +// Parameters: +// sym_name: Symbol in library we are looking for +// lib_name: Name of library to look in, NULL for shared libs. +// is_absolute_path == true if lib_name is absolute path to agent +// such as "C:/a/b/L.dll" +// == false if only the base name of the library is passed in +// such as "L" +char* os::build_agent_function_name(const char *sym_name, const char *lib_name, + bool is_absolute_path) { + char *agent_entry_name; + size_t len; + size_t name_len; + size_t prefix_len = strlen(JNI_LIB_PREFIX); + size_t suffix_len = strlen(JNI_LIB_SUFFIX); + const char *start; + + if (lib_name != NULL) { + len = name_len = strlen(lib_name); + if (is_absolute_path) { + // Need to strip path, prefix and suffix + if ((start = strrchr(lib_name, *os::file_separator())) != NULL) { + lib_name = ++start; + } else { + // Need to check for C: + if ((start = strchr(lib_name, ':')) != NULL) { + lib_name = ++start; + } + } + if (len <= (prefix_len + suffix_len)) { + return NULL; + } + lib_name += prefix_len; + name_len = strlen(lib_name) - suffix_len; + } + } + len = (lib_name != NULL ? name_len : 0) + strlen(sym_name) + 2; + agent_entry_name = NEW_C_HEAP_ARRAY_RETURN_NULL(char, len, mtThread); + if (agent_entry_name == NULL) { + return NULL; + } + if (lib_name != NULL) { + const char *p = strrchr(sym_name, '@'); + if (p != NULL && p != sym_name) { + // sym_name == _Agent_OnLoad@XX + strncpy(agent_entry_name, sym_name, (p - sym_name)); + agent_entry_name[(p-sym_name)] = '\0'; + // agent_entry_name == _Agent_OnLoad + strcat(agent_entry_name, "_"); + strncat(agent_entry_name, lib_name, name_len); + strcat(agent_entry_name, p); + // agent_entry_name == _Agent_OnLoad_lib_name@XX + } else { + strcpy(agent_entry_name, sym_name); + strcat(agent_entry_name, "_"); + strncat(agent_entry_name, lib_name, name_len); + } + } else { + strcpy(agent_entry_name, sym_name); + } + return agent_entry_name; +} + #else // Kernel32 API typedef BOOL (WINAPI* SwitchToThread_Fn)(void); diff --git a/hotspot/src/share/vm/prims/jvmti.xml b/hotspot/src/share/vm/prims/jvmti.xml index c23a7b5e1c3..87a28ae0cfc 100644 --- a/hotspot/src/share/vm/prims/jvmti.xml +++ b/hotspot/src/share/vm/prims/jvmti.xml @@ -1,7 +1,7 @@