changeset 9536:e233d4d68878

Merge
author mduigou
date Wed, 14 Aug 2013 15:53:13 -0700
parents e0f6039c0290 (current diff) 0abc86164e40 (diff)
children 068c47d1d7d2
files .hgtags .jcheck/conf makefiles/CompileNativeLibraries.gmk src/share/classes/java/beans/EventHandler.java src/share/classes/java/lang/invoke/LambdaConversionException.java src/share/classes/java/nio/file/Files.java src/share/classes/java/util/Collections.java src/share/classes/java/util/Comparator.java src/share/classes/java/util/Comparators.java src/share/classes/java/util/DoubleSummaryStatistics.java src/share/classes/java/util/HashMap.java src/share/classes/java/util/Hashtable.java src/share/classes/java/util/IdentityHashMap.java src/share/classes/java/util/IntSummaryStatistics.java src/share/classes/java/util/List.java src/share/classes/java/util/LongSummaryStatistics.java src/share/classes/java/util/Map.java src/share/classes/java/util/Optional.java src/share/classes/java/util/PriorityQueue.java src/share/classes/java/util/Queue.java src/share/classes/java/util/Random.java src/share/classes/java/util/StringJoiner.java src/share/classes/java/util/TreeMap.java src/share/classes/java/util/Vector.java src/share/classes/java/util/WeakHashMap.java src/share/classes/java/util/concurrent/AbstractExecutorService.java src/share/classes/java/util/concurrent/CompletableFuture.java src/share/classes/java/util/concurrent/CompletionStage.java src/share/classes/java/util/concurrent/ConcurrentHashMap.java src/share/classes/java/util/concurrent/ExecutorService.java src/share/classes/java/util/concurrent/Executors.java src/share/classes/java/util/concurrent/ForkJoinPool.java src/share/classes/java/util/concurrent/ForkJoinTask.java src/share/classes/java/util/concurrent/ScheduledExecutorService.java src/share/classes/java/util/concurrent/ScheduledThreadPoolExecutor.java src/share/classes/java/util/concurrent/TimeUnit.java src/share/classes/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java src/share/classes/java/util/concurrent/atomic/AtomicLongFieldUpdater.java src/share/classes/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java src/share/classes/java/util/function/BiConsumer.java src/share/classes/java/util/function/BiFunction.java src/share/classes/java/util/function/BiPredicate.java src/share/classes/java/util/function/BinaryOperator.java src/share/classes/java/util/function/BooleanSupplier.java src/share/classes/java/util/function/Consumer.java src/share/classes/java/util/function/DoubleBinaryOperator.java src/share/classes/java/util/function/DoubleConsumer.java src/share/classes/java/util/function/DoubleFunction.java src/share/classes/java/util/function/DoublePredicate.java src/share/classes/java/util/function/DoubleSupplier.java src/share/classes/java/util/function/DoubleToIntFunction.java src/share/classes/java/util/function/DoubleToLongFunction.java src/share/classes/java/util/function/DoubleUnaryOperator.java src/share/classes/java/util/function/Function.java src/share/classes/java/util/function/IntBinaryOperator.java src/share/classes/java/util/function/IntConsumer.java src/share/classes/java/util/function/IntFunction.java src/share/classes/java/util/function/IntPredicate.java src/share/classes/java/util/function/IntSupplier.java src/share/classes/java/util/function/IntToDoubleFunction.java src/share/classes/java/util/function/IntToLongFunction.java src/share/classes/java/util/function/IntUnaryOperator.java src/share/classes/java/util/function/LongBinaryOperator.java src/share/classes/java/util/function/LongConsumer.java src/share/classes/java/util/function/LongFunction.java src/share/classes/java/util/function/LongPredicate.java src/share/classes/java/util/function/LongSupplier.java src/share/classes/java/util/function/LongToDoubleFunction.java src/share/classes/java/util/function/LongToIntFunction.java src/share/classes/java/util/function/LongUnaryOperator.java src/share/classes/java/util/function/ObjDoubleConsumer.java src/share/classes/java/util/function/ObjIntConsumer.java src/share/classes/java/util/function/ObjLongConsumer.java src/share/classes/java/util/function/Predicate.java src/share/classes/java/util/function/Supplier.java src/share/classes/java/util/function/ToDoubleBiFunction.java src/share/classes/java/util/function/ToDoubleFunction.java src/share/classes/java/util/function/ToIntBiFunction.java src/share/classes/java/util/function/ToIntFunction.java src/share/classes/java/util/function/ToLongBiFunction.java src/share/classes/java/util/function/ToLongFunction.java src/share/classes/java/util/function/UnaryOperator.java src/share/classes/java/util/function/package-info.java src/share/classes/java/util/jar/JarFile.java src/share/classes/java/util/stream/AbstractPipeline.java src/share/classes/java/util/stream/AbstractShortCircuitTask.java src/share/classes/java/util/stream/AbstractTask.java src/share/classes/java/util/stream/CloseableStream.java src/share/classes/java/util/stream/Collector.java src/share/classes/java/util/stream/Collectors.java src/share/classes/java/util/stream/DelegatingStream.java src/share/classes/java/util/stream/DoublePipeline.java src/share/classes/java/util/stream/DoubleStream.java src/share/classes/java/util/stream/FindOps.java src/share/classes/java/util/stream/ForEachOps.java src/share/classes/java/util/stream/IntPipeline.java src/share/classes/java/util/stream/IntStream.java src/share/classes/java/util/stream/LongPipeline.java src/share/classes/java/util/stream/LongStream.java src/share/classes/java/util/stream/MatchOps.java src/share/classes/java/util/stream/Nodes.java src/share/classes/java/util/stream/ReduceOps.java src/share/classes/java/util/stream/ReferencePipeline.java src/share/classes/java/util/stream/Sink.java src/share/classes/java/util/stream/SliceOps.java src/share/classes/java/util/stream/SortedOps.java src/share/classes/java/util/stream/SpinedBuffer.java src/share/classes/java/util/stream/Stream.java src/share/classes/java/util/stream/StreamSpliterators.java src/share/classes/java/util/stream/StreamSupport.java src/share/classes/java/util/stream/Streams.java src/share/classes/java/util/stream/package-info.java src/solaris/native/java/lang/java_props_md.c test/Makefile test/ProblemList.txt test/java/util/Random/RandomStreamTest.java test/java/util/Spliterator/SpliteratorTraversingAndSplittingTest.java test/java/util/StringJoiner/MergeTest.java test/java/util/concurrent/CompletableFuture/Basic.java test/java/util/stream/test/org/openjdk/tests/java/util/stream/ConcatOpTest.java test/java/util/stream/test/org/openjdk/tests/java/util/stream/GroupByOpTest.java test/java/util/stream/test/org/openjdk/tests/java/util/stream/TabulatorsTest.java
diffstat 205 files changed, 24989 insertions(+), 2137 deletions(-) [+]
line wrap: on
line diff
--- a/.hgignore	Tue Aug 13 10:42:37 2013 -0700
+++ b/.hgignore	Wed Aug 14 15:53:13 2013 -0700
@@ -5,3 +5,19 @@
 ^make/netbeans/.*/dist/
 ^.hgtip
 .DS_Store
+^test-ng/gen-separate/
+^test-ng/lib/
+^.idea/
+^combo-tests/gen/
+^combo-tests/build/
+^out/
+.*\.rej$
+.*\.orig$
+.*\.iml$
+.*~$
+^webrev/
+webrev.zip$
+^.classpath
+^.project
+JTreport
+JTwork
--- a/.hgtags	Tue Aug 13 10:42:37 2013 -0700
+++ b/.hgtags	Wed Aug 14 15:53:13 2013 -0700
@@ -167,16 +167,20 @@
 b3246687c3695dff6f461bb407f9db88f7d072e7 jdk8-b43
 db471a7af03168e4441c245b1d9976f720a7cb77 jdk8-b44
 b92353a01aa049bc508fc56f0347d5934b7c4390 jdk8-b45
+077225955d5722f0fbd780650178c5931693c07e lambda-b45
 8d2ed9d58453c8049715a72a6d26b6b66b37a94c jdk8-b46
 00b22b23269a57d0bb46c57753be2fe9a9d2c1a3 jdk8-b47
 3e4ab821f46166fcf63e8fe5c8046216003c941f jdk8-b48
+b3b65a3d441e7f39cb68140d2db547704ea0a670 lambda-b48
 51707c3b75c0f521794d9ab425f4e5b2351c70c1 jdk8-b49
 e4bae5c53fca8fcb9393d47fd36a34b9e2e8d4ec jdk8-b50
+958eaa191b79bf79be82979240903199791ed9f7 lambda-b50
 e865efbc71059a414b3b2dd2e0adfcb3d2ab6ff9 jdk8-b51
 e8569a473cee7f4955bd9e76a9bdf6c6a07ced27 jdk8-b52
 2c6933c5106b81a8578b70996fe5b735fb3adb60 jdk8-b53
 70ad0ed1d6cef0e7712690d1bab21e4769708aad jdk8-b54
 1f3f4b333341873f00da3dee85e4879f0e89c9bb jdk8-b55
+2e6170973d921fe4b8d2dfd6032f5aaf4150a542 lambda-b56
 2e9eeef2909b33c9224a024afddb61ccb0b77f14 jdk8-b56
 51594d095a4bcffac4a314bf6e148214501399e0 jdk8-b57
 d94613ac03d8de375ef60493e2bb76dbd30d875d jdk8-b58
--- a/.jcheck/conf	Tue Aug 13 10:42:37 2013 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-project=jdk8
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/combo-tests/build.xml	Wed Aug 14 15:53:13 2013 -0700
@@ -0,0 +1,82 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project name="jdk" default="test">
+
+    <property name="build.dir" value="../../build/combo-tests" />
+    <property name="gen.dir" value="${build.dir}/gen" />
+    <property name="test.classes.dir" value="${build.dir}/test-classes"/>
+    <property name="test.reports.dir" value="${build.dir}/test-reports"/>
+    <property name="test.src.dir" value="tests"/>
+    <property name="lib.dir" location="lib" />
+    <property name="test.pattern" value="*Test" />
+    <property name="lambda.metafactory" value="" />
+    <property name="combo.debug" value="" />
+    <property name="heap.size" value="4G" />
+
+    <property name="lib.testng.jar" value="${lib.dir}/testng-6.7.jar"/>
+    <property name="lib.tools.jar" value="${java.home}/../lib/tools.jar"/>
+
+    <path id="test.class.path">
+        <pathelement path="${sun.boot.class.path}" />
+        <pathelement location="${test.classes.dir}" />
+        <pathelement location="${lib.testng.jar}"/>
+        <pathelement location="${lib.tools.jar}"/>
+    </path>
+
+    <taskdef name="testng" classpathref="test.class.path" classname="org.testng.TestNGAntTask" />
+
+    <target name="prepare">
+        <mkdir dir="${build.dir}"/>
+        <mkdir dir="${lib.dir}"/>
+        <mkdir dir="${test.classes.dir}"/>
+        <mkdir dir="${test.reports.dir}"/>
+    </target>
+
+    <target name="test-compile" depends="prepare">
+        <javac destdir="${test.classes.dir}" debug="on" srcdir="${test.src.dir}" fork="true"
+               classpathref="test.class.path">
+            <compilerarg value="-XDlambdaToMethod"/>
+        </javac>
+    </target>
+
+    <target name="test" depends="test-compile" >
+        <delete dir="${gen.dir}" />
+        <testng outputdir="${test.reports.dir}" usedefaultlisteners="false"
+                listeners="org.testng.reporters.FailedReporter,org.testng.reporters.XMLReporter">
+            <classpath refid="test.class.path" />
+            <classfileset dir="${test.classes.dir}" includes="**/${test.pattern}.class"/>
+            <jvmarg value="-Xms1G" />
+            <jvmarg value="-Xmx${heap.size}" />
+            <jvmarg value="-XX:+UseNUMA" />
+            <jvmarg value="-XX:+UseG1GC" />
+            <jvmarg value="-ea" />
+            <jvmarg value="-esa" />
+            <jvmarg value="-Xverify:all" />
+            <sysproperty key="lambda.metafactory" value="${lambda.metafactory}" />
+            <sysproperty key="combo.debug" value="${combo.debug}" />
+        </testng>
+    </target>
+   
+    <!-- New target added that uses a different set of listeners to show results in Aurora --> 
+    <target name="aurora-test" depends="test-compile" >
+        <testng outputdir="${test.reports.dir}" usedefaultlisteners="false"
+                listeners="org.testng.reporters.JUnitXMLReporter,org.testng.reporters.JUnitReportReporter,
+                           org.testng.reporters.XMLReporter">
+            <classpath refid="test.class.path" />
+            <classfileset dir="${test.classes.dir}" includes="**/${test.pattern}.class"/>
+            <jvmarg value="-Xms1G" />
+            <jvmarg value="-Xmx2G" />
+            <jvmarg value="-XX:+UseNUMA" />
+            <jvmarg value="-XX:+UseG1GC" />
+            <jvmarg value="-ea" />
+            <jvmarg value="-esa" />
+            <jvmarg value="-Xverify:all" />
+            <sysproperty key="lambda.metafactory" value="${lambda.metafactory}" />
+            <sysproperty key="combo.debug" value="${combo.debug}" />
+        </testng>
+    </target>
+
+    <target name="clean">
+        <delete dir="${build.dir}" />
+        <delete dir="${gen.dir}" />
+    </target>
+</project>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/combo-tests/tests/tools/javac/combo/BridgeMethodTestCase.java	Wed Aug 14 15:53:13 2013 -0700
@@ -0,0 +1,413 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  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 tools.javac.combo;
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.StringJoiner;
+
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.fail;
+
+/**
+ * BridgeMethodTestCase -- used for asserting linkage to bridges under separate compilation.
+ *
+ * Example test case:
+ *     public void test1() throws IOException, ReflectiveOperationException {
+ *         compileSpec("C(Bc1(A))");
+ *         assertLinkage("C", LINKAGE_ERROR, "B1");
+ *         recompileSpec("C(Bc1(Ac0))", "A");
+ *          assertLinkage("C", "A0", "B1");
+ *     }
+ *
+ * This compiles A, B, and C, asserts that C.m()Object does not exist, asserts
+ * that C.m()Number eventually invokes B.m()Number, recompiles B, and then asserts
+ * that the result of calling C.m()Object now arrives at A.
+ *
+ * @author Brian Goetz
+ */
+
+@Test
+public abstract class BridgeMethodTestCase extends JavacTemplateTestBase {
+
+    private static final String TYPE_LETTERS = "ABCDIJK";
+
+    private static final String BASE_INDEX_CLASS = "class C0 {\n" +
+                                                   "    int val;\n" +
+                                                   "    C0(int val) { this.val = val; }\n" +
+                                                   "    public int getVal() { return val; }\n" +
+                                                   "}\n";
+    
+    private static final String INDEX_CLASS_TEMPLATE = "class C#ID extends C#PREV {\n" +
+                                                       "    C#ID(int val) { super(val); }\n" +
+                                                       "}\n";
+
+
+
+    protected static String LINKAGE_ERROR = "-1";
+
+    private List<File> compileDirs = new ArrayList<>();
+
+    /**
+     * Compile all the classes in a class spec, and put them on the classpath.
+     *
+     * The spec is the specification for a nest of classes, using the following notation
+     * A, B represent abstract classes
+     * C represents a concrete class
+     * I, J, K represent interfaces
+     * Lowercase 'c' following a class means that the method m() is concrete
+     * Lowercase 'a' following a class or interface means that the method m() is abstract
+     * Lowercase 'd' following an interface means that the method m() is default
+     * A number 0, 1, or 2 following the lowercase letter indicates the return type of that method
+     * 0 = Object, 1 = Number, 2 = Integer (these form an inheritance chain so bridges are generated)
+     * A classes supertypes follow its method spec, in parentheses
+     * Examples:
+     *   C(Ia0, Jd0) -- C extends I and J, I has abstract m()Object, J has default m()Object
+     *   Cc1(Ia0) -- C has concrete m()Number, extends I with abstract m()Object
+     * If a type must appear multiple times, its full spec must be in the first occurrence
+     * Example:
+     *   C(I(Kd0), J(K))
+     */
+    protected void compileSpec(String spec) throws IOException {
+        compileSpec(spec, false);
+    }
+
+    protected void compileSpec(String spec, boolean debug) throws IOException {
+        ClassModel cm = new Parser(spec).parseClassModel();
+        for (int i = 0; i <= cm.maxIndex() ; i++) {
+            if (debug) System.out.println(indexClass(i));
+            addSourceFile(String.format("C%d.java", i), new StringTemplate(indexClass(i)));
+        }  
+        for (Map.Entry<String, ClassModel> e : classes(cm).entrySet()) {
+            if (debug) System.out.println(e.getValue().toSource());
+            addSourceFile(e.getKey() + ".java", new StringTemplate(e.getValue().toSource()));
+        }
+        compileDirs.add(compile(true));
+        resetSourceFiles();
+        assertCompileSucceeded();
+    }
+
+    /**
+     * Recompile only a subset of classes in the class spec, as named by names,
+     * and put them on the classpath such that they shadow earlier versions of that class.
+     */
+    protected void recompileSpec(String spec, String... names) throws IOException {
+        List<String> nameList = Arrays.asList(names);
+        ClassModel cm = new Parser(spec).parseClassModel();
+        for (int i = 0; i <= cm.maxIndex() ; i++) {
+            addSourceFile(String.format("C%d.java", i), new StringTemplate(indexClass(i)));
+        }
+        for (Map.Entry<String, ClassModel> e : classes(cm).entrySet())
+            if (nameList.contains(e.getKey()))
+                addSourceFile(e.getKey() + ".java", new StringTemplate(e.getValue().toSource()));
+        compileDirs.add(compile(Arrays.asList(classPaths()), true));
+        resetSourceFiles();
+        assertCompileSucceeded();
+    }
+
+    protected void assertLinkage(String name, String... expected) throws ReflectiveOperationException {
+        for (int i=0; i<expected.length; i++) {
+            String e = expected[i];
+            if (e.equals(LINKAGE_ERROR)) {
+                try {
+                    int actual = invoke(name, i);
+                    fail("Expected linkage error, got" + fromNum(actual));
+                }
+                catch (LinkageError x) {
+                    // success
+                }
+            }
+            else {
+                if (e.length() == 1)
+                    e += "0";
+                int expectedInt = toNum(e);
+                int actual = invoke(name, i);
+                if (expectedInt != actual)
+                    fail(String.format("Expected %s but found %s for %s.m()%d", fromNum(expectedInt), fromNum(actual), name, i));
+            }
+        }
+    }
+
+    private Map<String, ClassModel> classes(ClassModel cm) {
+        HashMap<String, ClassModel> m = new HashMap<>();
+        classesHelper(cm, m);
+        return m;
+    }
+
+    private String indexClass(int index) {
+        if (index == 0) {
+            return BASE_INDEX_CLASS;
+        } else {
+            return INDEX_CLASS_TEMPLATE
+                    .replace("#ID", String.valueOf(index))
+                    .replace("#PREV", String.valueOf(index - 1));
+        }
+    }
+
+    private static String overrideName(int index) {
+        return "C" + index;
+    }
+
+    private void classesHelper(ClassModel cm, Map<String, ClassModel> m) {
+        if (!m.containsKey(cm.name))
+            m.put(cm.name, cm);
+        for (ClassModel s : cm.supertypes)
+            classesHelper(s, m);
+    }
+
+    private static String fromNum(int num) {
+        return String.format("%c%d", TYPE_LETTERS.charAt(num / 10), num % 10);
+    }
+
+    private static int toNum(String name, int index) {
+        return 10*(TYPE_LETTERS.indexOf(name.charAt(0))) + index;
+    }
+
+    private static int toNum(String string) {
+        return 10*(TYPE_LETTERS.indexOf(string.charAt(0))) + Integer.parseInt(string.substring(1, 2));
+    }
+
+    private int invoke(String name, int index) throws ReflectiveOperationException {
+        File[] files = classPaths();
+        Class clazz = loadClass(name, files);
+        Method[] ms = clazz.getMethods();
+        for (Method m : ms) {
+            if (m.getName().equals("m") && m.getReturnType().getName().equals(overrideName(index))) {
+                m.setAccessible(true);
+                Object instance = clazz.newInstance();
+                Object c0 = m.invoke(instance);
+                Method getVal = c0.getClass().getMethod("getVal");
+                getVal.setAccessible(true);
+                return (int)getVal.invoke(c0);
+            }
+        }
+        throw new NoSuchMethodError("cannot find method m()" + index + " in class " + name);
+    }
+
+    private File[] classPaths() {
+        File[] files = new File[compileDirs.size()];
+        for (int i=0; i<files.length; i++)
+            files[files.length - i - 1] = compileDirs.get(i);
+        return files;
+    }
+
+    @BeforeMethod
+    @Override
+    public void reset() {
+        compileDirs.clear();
+        super.reset();
+    }
+
+    private static class ClassModel {
+
+        enum MethodType {
+            ABSTRACT('a'), CONCRETE('c'), DEFAULT('d');
+
+            public final char designator;
+
+            MethodType(char designator) {
+                this.designator = designator;
+            }
+
+            public static MethodType find(char c) {
+                for (MethodType m : values())
+                    if (m.designator == c)
+                        return m;
+                throw new IllegalArgumentException();
+            }
+        }
+
+        private final String name;
+        private final boolean isInterface;
+        private final List<ClassModel> supertypes;
+        private final MethodType methodType;
+        private final int methodIndex;
+
+        private ClassModel(String name,
+                           boolean anInterface,
+                           List<ClassModel> supertypes,
+                           MethodType methodType,
+                           int methodIndex) {
+            this.name = name;
+            isInterface = anInterface;
+            this.supertypes = supertypes;
+            this.methodType = methodType;
+            this.methodIndex = methodIndex;
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder sb = new StringBuilder();
+            sb.append(name);
+            if (methodType != null) {
+                sb.append(methodType.designator);
+                sb.append(methodIndex);
+            }
+            if (!supertypes.isEmpty()) {
+                sb.append("(");
+                for (int i=0; i<supertypes.size(); i++) {
+                    if (i > 0)
+                        sb.append(",");
+                    sb.append(supertypes.get(i).toString());
+                }
+                sb.append(")");
+            }
+            return sb.toString();
+        }
+
+        int maxIndex() {
+            int maxSoFar = methodIndex;
+            for (ClassModel cm : supertypes) {
+                maxSoFar = Math.max(cm.maxIndex(), maxSoFar);
+            }
+            return maxSoFar;
+        }
+
+        public String toSource() {
+            String extendsClause = "";
+            String implementsClause = "";
+            String methodBody = "";
+            boolean isAbstract = "AB".contains(name);
+
+            for (ClassModel s : supertypes) {
+                if (!s.isInterface) {
+                    extendsClause = String.format("extends %s", s.name);
+                    break;
+                }
+            }
+
+            StringJoiner sj = new StringJoiner(", ");
+            for (ClassModel s : supertypes)
+                if (s.isInterface)
+                    sj.add(s.name);
+            if (sj.length() > 0) {
+                if (isInterface)
+                    implementsClause = "extends " + sj.toString();
+                else
+                implementsClause = "implements " + sj.toString();
+            }
+            if (methodType != null) {
+                switch (methodType) {
+                    case ABSTRACT:
+                        methodBody = String.format("public abstract %s m();", overrideName(methodIndex));
+                        break;
+                    case CONCRETE:
+                        methodBody = String.format("public %s m() { return new %s(%d); };",
+                                overrideName(methodIndex), overrideName(methodIndex), toNum(name, methodIndex));
+                        break;
+                    case DEFAULT:
+                        methodBody = String.format("public default %s m() { return new %s(%d); };",
+                                overrideName(methodIndex), overrideName(methodIndex), toNum(name, methodIndex));
+                        break;
+
+                }
+            }
+
+            return String.format("public %s %s %s %s %s {  %s }", isAbstract ? "abstract" : "",
+                                 isInterface ? "interface" : "class",
+                                 name, extendsClause, implementsClause, methodBody);
+        }
+    }
+
+    private static class Parser {
+        private final String input;
+        private final char[] chars;
+        private int index;
+
+        private Parser(String s) {
+            input = s;
+            chars = s.toCharArray();
+        }
+
+        private char peek() {
+            return index < chars.length ? chars[index] : 0;
+        }
+
+        private boolean peek(String validChars) {
+            return validChars.indexOf(peek()) >= 0;
+        }
+
+        private char advanceIf(String validChars) {
+            if (peek(validChars))
+                return chars[index++];
+            else
+                return 0;
+        }
+
+        private char advanceIfDigit() {
+            return advanceIf("0123456789");
+        }
+
+        private int index() {
+            StringBuilder buf = new StringBuilder();
+            char c = advanceIfDigit();
+            while (c != 0) {
+                buf.append(c);
+                c = advanceIfDigit();
+            }
+            return Integer.valueOf(buf.toString());
+        }
+
+        private char advance() {
+            return chars[index++];
+        }
+
+        private char expect(String validChars) {
+            char c = advanceIf(validChars);
+            if (c == 0)
+                throw new IllegalArgumentException(String.format("Expecting %s at position %d of %s", validChars, index, input));
+            return c;
+        }
+
+        public ClassModel parseClassModel() {
+            List<ClassModel> supers = new ArrayList<>();
+            char name = expect(TYPE_LETTERS);
+            boolean isInterface = "IJK".indexOf(name) >= 0;
+            ClassModel.MethodType methodType = peek(isInterface ? "ad" : "ac") ? ClassModel.MethodType.find(advance()) : null;
+            int methodIndex = 0;
+            if (methodType != null) {
+                methodIndex = index();
+            }
+            if (peek() == '(') {
+                advance();
+                supers.add(parseClassModel());
+                while (peek() == ',') {
+                    advance();
+                    supers.add(parseClassModel());
+                }
+                expect(")");
+            }
+            return new ClassModel(new String(new char[]{ name }), isInterface, supers, methodType, methodIndex);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/combo-tests/tests/tools/javac/combo/BridgeMethodsLinearTest.java	Wed Aug 14 15:53:13 2013 -0700
@@ -0,0 +1,1083 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  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 tools.javac.combo;
+
+import java.io.IOException;
+
+import org.testng.annotations.Test;
+
+/**
+ * BridgeMethodsLinearTest
+ *
+ * @author Brian Goetz
+ */
+@Test
+public class BridgeMethodsLinearTest extends BridgeMethodTestCase {
+
+    /*
+     * Cc1(A) -> Cc1(Ac0)
+     *
+     * 0*: Inherited from A
+     * 1: Declared in C
+     */
+    public void test1() throws IOException, ReflectiveOperationException {
+        compileSpec("Cc1(A)");
+        assertLinkage("C", LINKAGE_ERROR, "C1");
+        recompileSpec("Cc1(Ac0)", "A");
+        assertLinkage("C", "A0", "C1");
+    }
+
+    /*
+     * Cc1(I) -> Cc1(Id0)
+     *
+     * 0*: Inherited default from I
+     * 1: Declared in C
+     */
+    public void test2() throws IOException, ReflectiveOperationException {
+        compileSpec("Cc1(I)");
+        assertLinkage("C", LINKAGE_ERROR, "C1");
+        recompileSpec("Cc1(Id0)", "I");
+        assertLinkage("C", "I0", "C1");
+    }
+
+    /*
+     * C(Bc1(A)) -> C(Bc1(Ac0))
+     *
+     * 0*: Inherited from A
+     * 1: Inherited from B
+     */
+    public void test3() throws IOException, ReflectiveOperationException {
+        compileSpec("C(Bc1(A))");
+        assertLinkage("C", LINKAGE_ERROR, "B1");
+        recompileSpec("C(Bc1(Ac0))", "A");
+        assertLinkage("C", "A0", "B1");
+    }
+
+    /*
+     * C(B(Ac0)) -> C(Bc1(Ac0))
+     *
+     * 0: Inherited from B (through bridge)
+     * 1: Inherited from B
+     */
+    public void test4() throws IOException, ReflectiveOperationException {
+        compileSpec("C(B(Ac0))");
+        assertLinkage("C", "A0", LINKAGE_ERROR);
+        recompileSpec("C(Bc1(Ac0))", "B");
+        assertLinkage("C", "B1", "B1");
+    }
+
+    /*
+     * C(B(A)) -> C(Bc1(Ac0))
+     *
+     * 0: Inherited from B (through bridge)
+     * 1: Inherited from B
+     */
+    public void test5() throws IOException, ReflectiveOperationException {
+        compileSpec("C(B(A))");
+        assertLinkage("C", LINKAGE_ERROR, LINKAGE_ERROR);
+        recompileSpec("C(Bc1(Ac0))", "A", "B");
+        assertLinkage("C", "B1", "B1");
+    }
+
+    /*
+     * C(Ac1(I)) -> C(Ac1(Id0))
+     *
+     * 0*: Inherited default from I
+     * 1: Inherited from A
+     */
+    public void test6() throws IOException, ReflectiveOperationException {
+        compileSpec("C(Ac1(I))");
+        assertLinkage("C", LINKAGE_ERROR, "A1");
+        recompileSpec("C(Ac1(Id0))", "I");
+        assertLinkage("C", "I0", "A1");
+    }
+
+    /*
+     * C(A(Id0)) -> C(Ac1(Id0))
+     *
+     * 0: Inherited from A (through bridge)
+     * 1: Inherited from A
+     */
+    public void test7() throws IOException, ReflectiveOperationException {
+        compileSpec("C(A(Id0))");
+        assertLinkage("C", "I0", LINKAGE_ERROR);
+        recompileSpec("C(Ac1(Id0))", "A");
+        assertLinkage("C", "A1", "A1");
+    }
+
+    /*
+     * C(A(I)) -> C(Ac1(Id0))
+     *
+     * 0*: Inherited from A (through bridge)
+     * 1*: Inherited from A
+     */
+    public void test8() throws IOException, ReflectiveOperationException {
+        compileSpec("C(A(I))");
+        assertLinkage("C", LINKAGE_ERROR, LINKAGE_ERROR);
+        recompileSpec("C(Ac1(Id0))", "A", "I");
+        assertLinkage("C", "A1", "A1");
+    }
+
+    /*
+     * C(Id1(J)) -> C(Id1(Jd0))
+     *
+     * 0*: Inherited default from J
+     * 1: Inherited default from I
+     */
+    public void test9() throws IOException, ReflectiveOperationException {
+        compileSpec("C(Id1(J))");
+        assertLinkage("C", LINKAGE_ERROR, "I1");
+        recompileSpec("C(Id1(Jd0))", "J");
+        assertLinkage("C", "J0", "I1");
+    }
+
+    /*
+     * C(I(Jd0)) -> C(Id1(Jd0))
+     *
+     * 0: Inherited default from I (through bridge)
+     * 1: Inherited default from I
+     */
+    public void test10() throws IOException, ReflectiveOperationException {
+        compileSpec("C(I(Jd0))");
+        assertLinkage("C", "J0", LINKAGE_ERROR);
+        recompileSpec("C(Id1(Jd0))", "I");
+        assertLinkage("C", "I1", "I1");
+    }
+
+    /*
+     * C(I(J)) -> C(Id1(Jd0))
+     *
+     * 0: Inherited default from I (through bridge)
+     * 1: Inherited default from I
+     */
+    public void test11() throws IOException, ReflectiveOperationException {
+        compileSpec("C(I(J))");
+        assertLinkage("C", LINKAGE_ERROR, LINKAGE_ERROR);
+        recompileSpec("C(Id1(Jd0))", "I", "J");
+        assertLinkage("C", "I1", "I1");
+    }
+
+    /*
+     * Cc2(B(Ac0)) -> Cc2(Bc1(Ac0))
+     *
+     * 0: Declared in C (through bridge)
+     * 1*: Inherited from B
+     * 2: Declared in C
+     */
+    public void test12() throws IOException, ReflectiveOperationException {
+        compileSpec("Cc2(B(Ac0))");
+        assertLinkage("C", "C2", LINKAGE_ERROR, "C2");
+        recompileSpec("Cc2(Bc1(Ac0))", "B");
+        assertLinkage("C", "C2", "B1", "C2");
+    }
+
+    /*
+     * Cc2(B(Aa0)) -> Cc2(Bc1(Aa0))
+     *
+     * 0: Bridge in C (through bridge)
+     * 1*: Inherited from B
+     * 2: Declared in C
+     */
+    public void test13() throws IOException, ReflectiveOperationException {
+        compileSpec("Cc2(B(Aa0))");
+        assertLinkage("C", "C2", LINKAGE_ERROR, "C2");
+        recompileSpec("Cc2(Bc1(Aa0))", "B");
+        assertLinkage("C", "C2", "B1", "C2");
+    }
+
+    /*
+     * Cc2(Bc1(A)) -> Cc2(Bc1(Ac0))
+     *
+     * 0*: Inherited from A
+     * 1: Declared in C (through bridge)
+     * 2: Declared in C
+     */
+    public void test14() throws IOException, ReflectiveOperationException {
+        compileSpec("Cc2(Bc1(A))");
+        assertLinkage("C", LINKAGE_ERROR, "C2", "C2");
+        recompileSpec("Cc2(Bc1(Ac0))", "A");
+        assertLinkage("C", "A0", "C2", "C2");
+    }
+
+    /*
+     * Cc2(Ba1(A)) -> Cc2(Ba1(Ac0))
+     *
+     * 0*: Inherited from A
+     * 1: Declared in C (through bridge)
+     * 2: Declared in C
+     */
+    public void test15() throws IOException, ReflectiveOperationException {
+        compileSpec("Cc2(Ba1(A))");
+        assertLinkage("C", LINKAGE_ERROR, "C2", "C2");
+        recompileSpec("Cc2(Ba1(Ac0))", "A");
+        assertLinkage("C", "A0", "C2", "C2");
+    }
+
+    /*
+     * Cc2(B(A)) -> Cc2(Bc1(Ac0))
+     *
+     * 0*: Inherited from B (through bridge)
+     * 1*: Inherited from B
+     * 2: Declared in C
+     */
+    public void test16() throws IOException, ReflectiveOperationException {
+        compileSpec("Cc2(B(A))");
+        assertLinkage("C", LINKAGE_ERROR, LINKAGE_ERROR, "C2");
+        recompileSpec("Cc2(Bc1(Ac0))", "B", "A");
+        assertLinkage("C", "B1", "B1", "C2");
+    }
+
+    /*
+     * Cc2(A(Id0)) -> Cc2(Ac1(Id0))
+     *
+     * 0: Declared in C (through bridge)
+     * 1*: Inherited from A
+     * 2: Declared in C
+     */
+    public void test17() throws IOException, ReflectiveOperationException {
+        compileSpec("Cc2(A(Id0))");
+        assertLinkage("C", "C2", LINKAGE_ERROR, "C2");
+        recompileSpec("Cc2(Ac1(Id0))", "A");
+        assertLinkage("C", "C2", "A1", "C2");
+    }
+
+    /*
+     * Cc2(A(Ia0)) -> Cc2(Ac1(Ia0))
+     *
+     * 0: Declared in C (through bridge)
+     * 1*: Inherited from A
+     * 2: Declared in C
+     */
+    public void test18() throws IOException, ReflectiveOperationException {
+        compileSpec("Cc2(A(Ia0))");
+        assertLinkage("C", "C2", LINKAGE_ERROR, "C2");
+        recompileSpec("Cc2(Ac1(Ia0))", "A");
+        assertLinkage("C", "C2", "A1", "C2");
+    }
+
+    /*
+     * Cc2(Ac1(I)) -> Cc2(Ac1(Id0))
+     *
+     * 0*: Inherited from I
+     * 1: Declared in C (through bridge)
+     * 2: Declared in C
+     */
+    public void test19() throws IOException, ReflectiveOperationException {
+        compileSpec("Cc2(Ac1(I))");
+        assertLinkage("C", LINKAGE_ERROR, "C2", "C2");
+        recompileSpec("Cc2(Ac1(Id0))", "I");
+        assertLinkage("C", "I0", "C2", "C2");
+    }
+
+    /*
+     * Cc2(Aa1(I)) -> Cc2(Aa1(Id0))
+     *
+     * 0*: Inherited from I
+     * 1: Declared in C (through bridge)
+     * 2: Declared in C
+     */
+    public void test20() throws IOException, ReflectiveOperationException {
+        compileSpec("Cc2(Aa1(I))");
+        assertLinkage("C", LINKAGE_ERROR, "C2", "C2");
+        recompileSpec("Cc2(Aa1(Id0))", "I");
+        assertLinkage("C", "I0", "C2", "C2");
+    }
+
+    /*
+     * Cc2(A(I)) -> Cc2(Ac1(Id0))
+     *
+     * 0*: Inherited from A (through bridge)
+     * 1*: Inherited from A
+     * 2: Declared in C
+     */
+    public void test21() throws IOException, ReflectiveOperationException {
+        compileSpec("Cc2(A(I))");
+        assertLinkage("C", LINKAGE_ERROR, LINKAGE_ERROR, "C2");
+        recompileSpec("Cc2(Ac1(Id0))", "A", "I");
+        assertLinkage("C", "A1", "A1", "C2");
+    }
+
+    /*
+     * Cc2(J(Id0)) -> Cc2(Jd1(Id0))
+     *
+     * 0: Declared in C (through bridge)
+     * 1*: Inherited default from J
+     * 2: Declared in C
+     */
+    public void test22() throws IOException, ReflectiveOperationException {
+        compileSpec("Cc2(J(Id0))");
+        assertLinkage("C", "C2", LINKAGE_ERROR, "C2");
+        recompileSpec("Cc2(Jd1(Id0))", "J");
+        assertLinkage("C", "C2", "J1", "C2");
+    }
+
+    /*
+     * Cc2(J(Ia0)) -> Cc2(Jd1(Ia0))
+     *
+     * 0: Declared in C (through bridge)
+     * 1*: Inherited default from J
+     * 2: Declared in C
+     */
+    public void test23() throws IOException, ReflectiveOperationException {
+        compileSpec("Cc2(J(Ia0))");
+        assertLinkage("C", "C2", LINKAGE_ERROR, "C2");
+        recompileSpec("Cc2(Jd1(Ia0))", "J");
+        assertLinkage("C", "C2", "J1", "C2");
+    }
+
+    /*
+     * Cc2(Jd1(I)) -> Cc2(Jd1(Id0))
+     *
+     * 0*: Inherited default from I
+     * 1: Declared in C (through bridge)
+     * 2: Declared in C
+     */
+    public void test24() throws IOException, ReflectiveOperationException {
+        compileSpec("Cc2(Jd1(I))");
+        assertLinkage("C", LINKAGE_ERROR, "C2", "C2");
+        recompileSpec("Cc2(Jd1(Id0))", "I");
+        assertLinkage("C", "I0", "C2", "C2");
+    }
+
+    /*
+     * Cc2(Ja1(I)) -> Cc2(Ja1(Id0))
+     *
+     * 0*: Inherited default from I
+     * 1: Declared in C (through bridge)
+     * 2: Declared in C
+     */
+    public void test25() throws IOException, ReflectiveOperationException {
+        compileSpec("Cc2(Ja1(I))");
+        assertLinkage("C", LINKAGE_ERROR, "C2", "C2");
+        recompileSpec("Cc2(Ja1(Id0))", "I");
+        assertLinkage("C", "I0", "C2", "C2");
+    }
+
+    /*
+     * Cc2(J(I)) -> Cc2(Jd1(Id0))
+     *
+     * 0*: Inherited default from J (through bridge)
+     * 1*: Inherited default from J
+     * 2: Declared in C
+     */
+    public void test26() throws IOException, ReflectiveOperationException {
+        compileSpec("Cc2(J(I))");
+        assertLinkage("C", LINKAGE_ERROR, LINKAGE_ERROR, "C2");
+        recompileSpec("Cc2(Jd1(Id0))", "J", "I");
+        assertLinkage("C", "J1", "J1", "C2");
+    }
+
+    /*
+     * C(Ac1, I) -> C(Ac1, Id0)
+     *
+     * 0*: Inherited default from I
+     * 1: Inherited from A
+     */
+    public void test27() throws IOException, ReflectiveOperationException {
+        compileSpec("C(Ac1,I)");
+        assertLinkage("C", LINKAGE_ERROR, "A1");
+        recompileSpec("C(Ac1,Id0)", "I");
+        assertLinkage("C", "I0", "A1");
+    }
+
+    /*
+     * C(A, Id0) -> C(Ac1, Id0)
+     *
+     * 0*: Inherited default from I
+     * 1: Inherited from A
+     */
+    public void test28() throws IOException, ReflectiveOperationException {
+        compileSpec("C(A,Id0)");
+        assertLinkage("C", "I0", LINKAGE_ERROR);
+        recompileSpec("C(Ac1,Id0)", "A");
+        assertLinkage("C", "I0", "A1");
+    }
+
+    /*
+     * C(A, I) -> C(Ac1, Id0)
+     *
+     * 0*: Inherited default from I
+     * 1: Inherited from A
+     */
+    public void test29() throws IOException, ReflectiveOperationException {
+        compileSpec("C(A,I)");
+        assertLinkage("C", LINKAGE_ERROR, LINKAGE_ERROR);
+        recompileSpec("C(Ac1,Id0)", "A", "I");
+        assertLinkage("C", "I0", "A1");
+    }
+
+    /*
+     * Cc2(Ac1, I) -> Cc2(Ac1, Id0)
+     *
+     * 0*: Inherited default from I
+     * 1: Declared in C (through bridge)
+     * 2: Declared in C
+     */
+    public void test30() throws IOException, ReflectiveOperationException {
+        compileSpec("Cc2(Ac1,I)");
+        assertLinkage("C", LINKAGE_ERROR, "C2", "C2");
+        recompileSpec("Cc2(Ac1,Id0)", "I");
+        assertLinkage("C", "I0", "C2", "C2");
+    }
+
+    /*
+     * Cc2(Aa1, I) -> Cc2(Aa1, Id0)
+     *
+     * 0*: Inherited default from I
+     * 1: Declared in C (through bridge)
+     * 2: Declared in C
+     */
+    public void test31() throws IOException, ReflectiveOperationException {
+        compileSpec("Cc2(Aa1,I)");
+        assertLinkage("C", LINKAGE_ERROR, "C2", "C2");
+        recompileSpec("Cc2(Aa1,Id0)", "I");
+        assertLinkage("C", "I0", "C2", "C2");
+    }
+
+    /*
+     * Cc2(A, Id0) -> Cc2(Ac1, Id0)
+     *
+     * 0: Declared in C (through bridge)
+     * 1*: Inherited from A
+     * 2: Declared in C
+     */
+    public void test32() throws IOException, ReflectiveOperationException {
+        compileSpec("Cc2(A,Id0)");
+        assertLinkage("C", "C2", LINKAGE_ERROR, "C2");
+        recompileSpec("Cc2(Ac1,Id0)", "A");
+        assertLinkage("C", "C2", "A1", "C2");
+    }
+
+    /*
+     * Cc2(A, Ia0) -> Cc2(Ac1, Ia0)
+     *
+     * 0: Declared in C (through bridge)
+     * 1*: Inherited from A
+     * 2: Declared in C
+     */
+    public void test33() throws IOException, ReflectiveOperationException {
+        compileSpec("Cc2(A,Ia0)");
+        assertLinkage("C", "C2", LINKAGE_ERROR, "C2");
+        recompileSpec("Cc2(Ac1,Ia0)", "A");
+        assertLinkage("C", "C2", "A1", "C2");
+    }
+
+    /*
+     * Cc2(A, I) -> Cc2(Ac1, Id0)
+     *
+     * 0*: Inherited from A
+     * 1*: Inherited default from I
+     * 2: Declared in C
+     */
+    public void test34() throws IOException, ReflectiveOperationException {
+        compileSpec("Cc2(A,I)");
+        assertLinkage("C", LINKAGE_ERROR, LINKAGE_ERROR, "C2");
+        recompileSpec("Cc2(Ac1,Id0)", "A", "I");
+        assertLinkage("C", "I0", "A1", "C2");
+    }
+
+    /*
+     * Cc2(Id0, J) -> Cc2(Id0, Jd1)
+     *
+     * 0: Declared in C (through bridge)
+     * 1*: Inherited default from J
+     * 2: Declared in C
+     */
+    public void test35() throws IOException, ReflectiveOperationException {
+        compileSpec("Cc2(Id0,J)");
+        assertLinkage("C", "C2", LINKAGE_ERROR, "C2");
+        recompileSpec("Cc2(Id0,Jd1)", "J");
+        assertLinkage("C", "C2", "J1", "C2");
+    }
+
+    /*
+     * Cc2(Ia0, J) -> Cc2(Ia0, Jd1)
+     *
+     * 0: Declared in C (through bridge)
+     * 1*: Inherited default from J
+     * 2: Declared in C
+     */
+    public void test36() throws IOException, ReflectiveOperationException {
+        compileSpec("Cc2(Ia0,J)");
+        assertLinkage("C", "C2", LINKAGE_ERROR, "C2");
+        recompileSpec("Cc2(Ia0,Jd1)", "J");
+        assertLinkage("C", "C2", "J1", "C2");
+    }
+
+    /*
+     * Cc2(I, J) -> Cc2(Id0, Jd1)
+     *
+     * 0*: Inherited default from I
+     * 1*: Inherited default from J
+     * 2: Declared in C
+     */
+    public void test37() throws IOException, ReflectiveOperationException {
+        compileSpec("Cc2(I,J)");
+        assertLinkage("C", LINKAGE_ERROR, LINKAGE_ERROR, "C2");
+        recompileSpec("Cc2(Id0,Jd1)", "I", "J");
+        assertLinkage("C", "I0", "J1", "C2");
+    }
+
+    /*
+     * C(A(Id0), J(Id0)) -> C(Ac1(Id0), J(Id0))
+     *
+     * 0: Inherited default from I
+     * 0*: Inherited from A (through bridge)
+     * 1*: Inherited from A
+     */
+    public void test38() throws IOException, ReflectiveOperationException {
+        compileSpec("C(A(Id0),J(Id0))");
+        assertLinkage("C", "I0", LINKAGE_ERROR);
+        recompileSpec("C(Ac1(Id0),J(Id0))", "A");
+        assertLinkage("C", "A1", "A1");
+    }
+
+    /*
+     * C(A(Id0), J(Id0)) -> C(A(Id0), Jd1(Id0))
+     *
+     * 0: Inherited default from I
+     * 0: Inherited default from J (through bridge)
+     * 1*: Inherited default from J
+     */
+    public void test39() throws IOException, ReflectiveOperationException {
+        compileSpec("C(A(Id0),J(Id0))");
+        assertLinkage("C", "I0", LINKAGE_ERROR);
+        recompileSpec("C(A(Id0),Jd1(Id0))", "J");
+        assertLinkage("C", "J1", "J1");
+    }
+
+    /*
+     * C(A(Id0), J(Id0)) -> C(Ac2(Id0), Jd1(Id0))
+     *
+     * 0: Inherited default from I
+     * 0*: Inherited from A (new bridge in A beats new bridge in J)
+     * 1*: Inherited default from J
+     * 2: Inherited from A
+     */
+    public void test40() throws IOException, ReflectiveOperationException {
+        compileSpec("C(A(Id0),J(Id0))");
+        assertLinkage("C", "I0", LINKAGE_ERROR);
+        recompileSpec("C(Ac2(Id0),Jd1(Id0))", "A", "J");
+        assertLinkage("C", "A2", "J1", "A2");
+    }
+
+    /*
+     * C(J(Id0), K(Id0)) -> C(Jd1(Id0), K(Id0))
+     *
+     * 0: Inherited from I
+     * 0*: Inherited default from J (through bridge)
+     * 1: Inherited default from J
+     */
+    public void test41() throws IOException, ReflectiveOperationException {
+        compileSpec("C(J(Id0),K(Id0))");
+        assertLinkage("C", "I0", LINKAGE_ERROR);
+        recompileSpec("C(Jd1(Id0),K(Id0))", "J");
+        assertLinkage("C", "J1", "J1");
+    }
+
+    /*
+     * C(Ac2(Id0), J(Id0)) -> C(Ac2(Id0), Jd1(Id0))
+     *
+     * 0: Inherited from A (bridge in A beats new bridge in J)
+     * 1*: Inherited default from J
+     * 2: Inherited from A
+     */
+    public void test42() throws IOException, ReflectiveOperationException {
+        compileSpec("C(Ac2(Id0),J(Id0))");
+        assertLinkage("C", "A2", LINKAGE_ERROR, "A2");
+        recompileSpec("C(Ac2(Id0),Jd1(Id0))", "J");
+        assertLinkage("C", "A2", "J1", "A2");
+    }
+
+    /*
+     * C(Ac2(Ia0), J(Ia0)) -> C(Ac2(Ia0), Jd1(Ia0))
+     *
+     * 0: Inherited from A (bridge in A beats new bridge in J)
+     * 1*: Inherited default from J
+     * 2: Inherited from A
+     */
+    public void test43() throws IOException, ReflectiveOperationException {
+        compileSpec("C(Ac2(Ia0),J(Ia0))");
+        assertLinkage("C", "A2", LINKAGE_ERROR, "A2");
+        recompileSpec("C(Ac2(Ia0),Jd1(Ia0))", "J");
+        assertLinkage("C", "A2", "J1", "A2");
+    }
+
+    /*
+     * C(A(Id0), Jd1(Id0)) -> C(Ac2(Id0), Jd1(Id0))
+     *
+     * 0: Inherited from J
+     * 0*: Inherited from A (new bridge in A beats bridge in J)
+     * 1: Inherited default from J
+     * 2*: Inherited from A
+     */
+    public void test44() throws IOException, ReflectiveOperationException {
+        compileSpec("C(A(Id0),Jd1(Id0))");
+        assertLinkage("C", "J1", "J1", LINKAGE_ERROR);
+        recompileSpec("C(Ac2(Id0),Jd1(Id0))", "A");
+        assertLinkage("C", "A2", "J1", "A2");
+    }
+
+    /*
+     * C(A(Ia0), Jd1(Ia0)) -> C(Ac2(Ia0), Jd1(Ia0))
+     *
+     * 0: Inherited from J
+     * 0*: Inherited from A (new bridge in A beats bridge in J)
+     * 1: Inherited default from J
+     * 2*: Inherited from A
+     */
+    public void test45() throws IOException, ReflectiveOperationException {
+        compileSpec("C(A(Ia0),Jd1(Ia0))");
+        assertLinkage("C", "J1", "J1", LINKAGE_ERROR);
+        recompileSpec("C(Ac2(Ia0),Jd1(Ia0))", "A");
+        assertLinkage("C", "A2", "J1", "A2");
+    }
+
+    /*
+     * Cc2(A(Id0), J(Id0)) -> Cc2(Ac1(Id0), J(Id0))
+     *
+     * 0: Declared in C (through bridge)
+     * 1*: Inherited from A
+     * 2: Declared in C
+     */
+    public void test46() throws IOException, ReflectiveOperationException {
+        compileSpec("Cc2(A(Id0),J(Id0))");
+        assertLinkage("C", "C2", LINKAGE_ERROR, "C2");
+        recompileSpec("Cc2(Ac1(Id0),J(Id0))", "A");
+        assertLinkage("C", "C2", "A1", "C2");
+    }
+
+    /*
+     * Cc2(A(Ia0), J(Ia0)) -> Cc2(Ac1(Ia0), J(Ia0))
+     *
+     * 0: Declared in C (through bridge)
+     * 1*: Inherited from A
+     * 2: Declared in C
+     */
+    public void test47() throws IOException, ReflectiveOperationException {
+        compileSpec("Cc2(A(Ia0),J(Ia0))");
+        assertLinkage("C", "C2", LINKAGE_ERROR, "C2");
+        recompileSpec("Cc2(Ac1(Ia0),J(Ia0))", "A");
+        assertLinkage("C", "C2", "A1", "C2");
+    }
+
+    /*
+     * Cc2(A(Id0), J(Id0)) -> Cc2(A(Id0), Jd1(Id0))
+     *
+     * 0: Declared in C (through bridge)
+     * 1*: Inherited default from J
+     * 2: Declared in C
+     */
+    public void test48() throws IOException, ReflectiveOperationException {
+        compileSpec("Cc2(A(Id0),J(Id0))");
+        assertLinkage("C", "C2", LINKAGE_ERROR, "C2");
+        recompileSpec("Cc2(A(Id0),Jd1(Id0))", "J");
+        assertLinkage("C", "C2", "J1", "C2");
+    }
+
+    /*
+     * Cc2(A(Ia0), J(Ia0)) -> Cc2(A(Ia0), Jd1(Ia0))
+     *
+     * 0: Declared in C (through bridge)
+     * 1*: Inherited default from J
+     * 2: Declared in C
+     */
+    public void test49() throws IOException, ReflectiveOperationException {
+        compileSpec("Cc2(A(Ia0),J(Ia0))");
+        assertLinkage("C", "C2", LINKAGE_ERROR, "C2");
+        recompileSpec("Cc2(A(Ia0),Jd1(Ia0))", "J");
+        assertLinkage("C", "C2", "J1", "C2");
+    }
+
+
+    /*
+     * Cc3(A(Id0), J(Id0)) -> Cc3(Ac1(Id0), Jd2(Id0))
+     *
+     * 0: Bridge in C
+     * 1*: Inherited from A
+     * 2*: Inherited default from J
+     * 3: Declared in C
+     */
+    public void test50() throws IOException, ReflectiveOperationException {
+        compileSpec("Cc3(A(Id0),J(Id0))");
+        assertLinkage("C", "C3", LINKAGE_ERROR, LINKAGE_ERROR, "C3");
+        recompileSpec("Cc3(Ac1(Id0),Jd2(Id0))", "A", "J");
+        assertLinkage("C", "C3", "A1", "J2", "C3");
+    }
+
+    /*
+     * Cc3(A(Ia0), J(Ia0)) -> Cc3(Ac1(Ia0), Jd2(Ia0))
+     *
+     * 0: Bridge in C
+     * 1*: Inherited from A
+     * 2*: Inherited default from J
+     * 3: Declared in C
+     */
+    public void test51() throws IOException, ReflectiveOperationException {
+        compileSpec("Cc3(A(Ia0),J(Ia0))");
+        assertLinkage("C", "C3", LINKAGE_ERROR, LINKAGE_ERROR, "C3");
+        recompileSpec("Cc3(Ac1(Ia0),Jd2(Ia0))", "A", "J");
+        assertLinkage("C", "C3", "A1", "J2", "C3");
+    }
+
+    /*
+     * Cc2(J(Id0), K(Id0)) -> Cc2(Jd1(Id0), K(Id0))
+     *
+     * 0: Declared in C (through bridge)
+     * 1*: Inherited default from J
+     * 2: Declared in C
+     */
+    public void test52() throws IOException, ReflectiveOperationException {
+        compileSpec("Cc2(J(Id0),K(Id0))");
+        assertLinkage("C", "C2", LINKAGE_ERROR, "C2");
+        recompileSpec("Cc2(Jd1(Id0),K(Id0))", "J");
+        assertLinkage("C", "C2", "J1", "C2");
+    }
+
+    /*
+     * Cc2(J(Ia0), K(Ia0)) -> Cc2(Jd1(Ia0), K(Ia0))
+     *
+     * 0: Declared in C (through bridge)
+     * 1*: Inherited default from J
+     * 2: Declared in C
+     */
+    public void test53() throws IOException, ReflectiveOperationException {
+        compileSpec("Cc2(J(Ia0),K(Ia0))");
+        assertLinkage("C", "C2", LINKAGE_ERROR, "C2");
+        recompileSpec("Cc2(Jd1(Ia0),K(Ia0))", "J");
+        assertLinkage("C", "C2", "J1", "C2");
+    }
+
+    /*
+     * Cc3(J(Id0), K(Id0)) -> Cc3(Jd1(Id0), Kd2(Id0))
+     *
+     * 0: Declared in C (through bridge)
+     * 1*: Inherited default from J
+     * 2*: Inherited default from K
+     * 3: Declared in C
+     */
+    public void test54() throws IOException, ReflectiveOperationException {
+        compileSpec("Cc3(J(Id0),K(Id0))");
+        assertLinkage("C", "C3", LINKAGE_ERROR, LINKAGE_ERROR, "C3");
+        recompileSpec("Cc3(Jd1(Id0),Kd2(Id0))", "J", "K");
+        assertLinkage("C", "C3", "J1", "K2", "C3");
+    }
+
+    /*
+     * Cc3(J(Ia0), K(Ia0)) -> Cc3(Jd1(Ia0), Kd2(Ia0))
+     *
+     * 0: Declared in C (through bridge)
+     * 1*: Inherited default from J
+     * 2*: Inherited default from K
+     * 3: Declared in C
+     */
+    public void test55() throws IOException, ReflectiveOperationException {
+        compileSpec("Cc3(J(Ia0),K(Ia0))");
+        assertLinkage("C", "C3", LINKAGE_ERROR, LINKAGE_ERROR, "C3");
+        recompileSpec("Cc3(Jd1(Ia0),Kd2(Ia0))", "J", "K");
+        assertLinkage("C", "C3", "J1", "K2", "C3");
+    }
+
+    /*
+     * Cc3(Ac1(Id0), J(Id0)) -> Cc3(Ac1(Id0), Jd2(Id0))
+     *
+     * 0: Declared in C (through bridge)
+     * 1: Declared in C (through bridge)
+     * 2*: Inherited default from J
+     * 3: Declared in C
+     */
+    public void test56() throws IOException, ReflectiveOperationException {
+        compileSpec("Cc3(Ac1(Id0),J(Id0))");
+        assertLinkage("C", "C3", "C3", LINKAGE_ERROR, "C3");
+        recompileSpec("Cc3(Ac1(Id0),Jd2(Id0))", "J");
+        assertLinkage("C", "C3", "C3", "J2", "C3");
+    }
+
+    /*
+     * Cc3(Ac1(Ia0), J(Ia0)) -> Cc3(Ac1(Ia0), Jd2(Ia0))
+     *
+     * 0: Declared in C (through bridge)
+     * 1: Declared in C (through bridge)
+     * 2*: Inherited default from J
+     * 3: Declared in C
+     */
+    public void test57() throws IOException, ReflectiveOperationException {
+        compileSpec("Cc3(Ac1(Ia0),J(Ia0))");
+        assertLinkage("C", "C3", "C3", LINKAGE_ERROR, "C3");
+        recompileSpec("Cc3(Ac1(Ia0),Jd2(Ia0))", "J");
+        assertLinkage("C", "C3", "C3", "J2", "C3");
+    }
+
+    /*
+     * Cc3(Aa1(Id0), J(Id0)) -> Cc3(Aa1(Id0), Jd2(Id0))
+     *
+     * 0: Declared in C (through bridge)
+     * 1: Declared in C (through bridge)
+     * 2*: Inherited default from J
+     * 3: Declared in C
+     */
+    public void test58() throws IOException, ReflectiveOperationException {
+        compileSpec("Cc3(Aa1(Id0),J(Id0))");
+        assertLinkage("C", "C3", "C3", LINKAGE_ERROR, "C3");
+        recompileSpec("Cc3(Aa1(Id0),Jd2(Id0))", "J");
+        assertLinkage("C", "C3", "C3", "J2", "C3");
+    }
+
+    /*
+     * Cc3(Aa1(Ia0), J(Ia0)) -> Cc3(Aa1(Ia0), Jd2(Ia0))
+     *
+     * 0: Declared in C (through bridge)
+     * 1: Declared in C (through bridge)
+     * 2*: Inherited default from J
+     * 3: Declared in C
+     */
+    public void test59() throws IOException, ReflectiveOperationException {
+        compileSpec("Cc3(Aa1(Ia0),J(Ia0))");
+        assertLinkage("C", "C3", "C3", LINKAGE_ERROR, "C3");
+        recompileSpec("Cc3(Aa1(Ia0),Jd2(Ia0))", "J");
+        assertLinkage("C", "C3", "C3", "J2", "C3");
+    }
+
+    /*
+     * Cc3(A(Id0), Jd2(Id0)) -> Cc3(Ac1(Id0), Jd2(Id0))
+     *
+     * 0: Declared in C (through bridge)
+     * 1*: Inherited from A
+     * 2: Declared in C (through bridge)
+     * 3: Declared in C
+     */
+    public void test60() throws IOException, ReflectiveOperationException {
+        compileSpec("Cc3(A(Id0),Jd2(Id0))");
+        assertLinkage("C", "C3", LINKAGE_ERROR, "C3", "C3");
+        recompileSpec("Cc3(Ac1(Id0),Jd2(Id0))", "A");
+        assertLinkage("C", "C3", "A1", "C3", "C3");
+    }
+
+    /*
+     * Cc3(A(Im0), Jd2(Ia0)) -> Cc3(Ac1(Im0), Jd2(Ia0))
+     *
+     * 0: Declared in C (through bridge)
+     * 1*: Inherited from A
+     * 2: Declared in C (through bridge)
+     * 3: Declared in C
+     */
+    public void test61() throws IOException, ReflectiveOperationException {
+        compileSpec("Cc3(A(Ia0),Jd2(Ia0))");
+        assertLinkage("C", "C3", LINKAGE_ERROR, "C3", "C3");
+        recompileSpec("Cc3(Ac1(Ia0),Jd2(Ia0))", "A");
+        assertLinkage("C", "C3", "A1", "C3", "C3");
+    }
+
+    /*
+     * Cc3(A(Im0), Ja2(Id0)) -> Cc3(Ac1(Id0), Ja2(Id0))
+     *
+     * 0: Declared in C (through bridge)
+     * 1*: Inherited from A
+     * 2: Declared in C (through bridge)
+     * 3: Declared in C
+     */
+    public void test62() throws IOException, ReflectiveOperationException {
+        compileSpec("Cc3(A(Id0),Ja2(Id0))");
+        assertLinkage("C", "C3", LINKAGE_ERROR, "C3", "C3");
+        recompileSpec("Cc3(Ac1(Id0),Ja2(Id0))", "A");
+        assertLinkage("C", "C3", "A1", "C3", "C3");
+    }
+
+    /*
+     * Cc3(A(Im0), Ja2(Ia0)) -> Cc3(Ac1(Ia0), Ja2(Ia0))
+     *
+     * 0: Declared in C (through bridge)
+     * 1*: Inherited from A
+     * 2: Declared in C (through bridge)
+     * 3: Declared in C
+     */
+    public void test63() throws IOException, ReflectiveOperationException {
+        compileSpec("Cc3(A(Ia0),Ja2(Ia0))");
+        assertLinkage("C", "C3", LINKAGE_ERROR, "C3", "C3");
+        recompileSpec("Cc3(Ac1(Ia0),Ja2(Ia0))", "A");
+        assertLinkage("C", "C3", "A1", "C3", "C3");
+    }
+
+    /*
+     * Cc3(Jd1(Id0), K(Id0)) -> Cc3(Jd1(Id0), Kd2(Id0))
+     *
+     * 0: Declared in C (through bridge)
+     * 1: Declared in C (through bridge)
+     * 2*: Inherited default from K
+     * 3: Declared in C
+     */
+    public void test64() throws IOException, ReflectiveOperationException {
+        compileSpec("Cc3(Jd1(Id0),K(Id0))");
+        assertLinkage("C", "C3", "C3", LINKAGE_ERROR, "C3");
+        recompileSpec("Cc3(Jd1(Id0),Kd2(Id0))", "K");
+        assertLinkage("C", "C3", "C3", "K2", "C3");
+    }
+
+    /*
+     * Cc3(Jd1(Ia0), K(Ia0)) -> Cc3(Jd1(Ia0), Kd2(Ia0))
+     *
+     * 0: Declared in C (through bridge)
+     * 1: Declared in C (through bridge)
+     * 2*: Inherited default from K
+     * 3: Declared in C
+     */
+    public void test65() throws IOException, ReflectiveOperationException {
+        compileSpec("Cc3(Jd1(Ia0),K(Ia0))");
+        assertLinkage("C", "C3", "C3", LINKAGE_ERROR, "C3");
+        recompileSpec("Cc3(Jd1(Ia0),Kd2(Ia0))", "K");
+        assertLinkage("C", "C3", "C3", "K2", "C3");
+    }
+
+    /*
+     * Cc3(Ja1(Id0), K(Id0)) -> Cc3(Ja1(Id0), Kd2(Id0))
+     *
+     * 0: Declared in C (through bridge)
+     * 1: Declared in C (through bridge)
+     * 2*: Inherited default from K
+     * 3: Declared in C
+     */
+    public void test66() throws IOException, ReflectiveOperationException {
+        compileSpec("Cc3(Jd1(Id0),K(Id0))");
+        assertLinkage("C", "C3", "C3", LINKAGE_ERROR, "C3");
+        recompileSpec("Cc3(Jd1(Id0),Kd2(Id0))", "K");
+        assertLinkage("C", "C3", "C3", "K2", "C3");
+    }
+
+    /*
+     * Cc3(Ja1(Ia0), K(Ia0)) -> Cc3(Ja1(Ia0), Kd2(Ia0))
+     *
+     * 0: Declared in C (through bridge)
+     * 1: Declared in C (through bridge)
+     * 2*: Inherited default from K
+     * 3: Declared in C
+     */
+    public void test67() throws IOException, ReflectiveOperationException {
+        compileSpec("Cc3(Jd1(Ia0),K(Ia0))");
+        assertLinkage("C", "C3", "C3", LINKAGE_ERROR, "C3");
+        recompileSpec("Cc3(Jd1(Ia0),Kd2(Ia0))", "K");
+        assertLinkage("C", "C3", "C3", "K2", "C3");
+    }
+
+    // Dan's set A
+    public void testA1() throws IOException, ReflectiveOperationException {
+        compileSpec("C(Id0)");
+        assertLinkage("C", "I0");
+    }
+
+    public void testA2() throws IOException, ReflectiveOperationException {
+        compileSpec("C(A(Id0))");
+        assertLinkage("C", "I0");
+    }
+
+    public void testA3() throws IOException, ReflectiveOperationException {
+        compileSpec("C(A(Id0),J)");
+        assertLinkage("C", "I0");
+    }
+
+    public void testA4() throws IOException, ReflectiveOperationException {
+        compileSpec("D(C(Id0),Jd0(Id0))");
+        assertLinkage("D", "J0");
+        assertLinkage("C", "I0");
+    }
+    /* Doesn't compile
+    public void testA5() throws IOException, ReflectiveOperationException {
+        compileSpec("C(A(Id0),Jd0)");
+        assertLinkage("C", "J0");
+        assertLinkage("A", "I0");
+    }
+    */
+    /* Doesn't compile
+    public void testA6() throws IOException, ReflectiveOperationException {
+        compileSpec("C(A(Id0,Jd0))");
+        assertLinkage("C", "J0");
+        assertLinkage("A", "I0");
+    }
+    */
+    /* Doesn't compile
+    public void testA7() throws IOException, ReflectiveOperationException {
+        compileSpec("C(A(I0,Jd0))");
+        assertLinkage("C", "J0");
+        assertLinkage("A", "I0");
+    }
+    */
+    public void testA8() throws IOException, ReflectiveOperationException {
+        compileSpec("C(Ac0(Id0))");
+        assertLinkage("C", "A0");
+    }
+
+    /* Doesn't compile
+    public void testA9() throws IOException, ReflectiveOperationException {
+        compileSpec("C(Ac0,Id0)");
+        assertLinkage("C", "A0");
+    }
+    */
+
+    // Dan's set B
+
+    /* B1 can't be done, needs a second concrete class D
+    public void testB1() throws IOException, ReflectiveOperationException {
+        compileSpec("Cc1(Dc0)");
+        assertLinkage("C", "C1", "C1");
+        assertLinkage("D", "A0", LINKAGE_ERROR);
+    }
+    */
+
+    public void testB2() throws IOException, ReflectiveOperationException {
+        compileSpec("Cc1(Ac0)");
+        assertLinkage("C", "C1", "C1");
+    }
+
+    //??? B3 seems to suggest that we should create an abstract class
+    //public void testB3() throws IOException, ReflectiveOperationException {
+    //    compileSpec("Ba1(Cc0)");
+    //    assertLinkage("B", "C0", "A1");
+    //}
+
+    // B4 needs too many classes
+
+    public void testB5() throws IOException, ReflectiveOperationException {
+        compileSpec("Cc1(Aa1(Id0))");
+        assertLinkage("C", "C1", "C1");
+    }
+
+    public void testB6() throws IOException, ReflectiveOperationException {
+        compileSpec("C(Ac1(Id0))");
+        assertLinkage("C", "A1", "A1");
+    }
+
+    public void testB7() throws IOException, ReflectiveOperationException {
+        compileSpec("Cc1(Id0)");
+        assertLinkage("C", "C1", "C1");
+    }
+
+    public void testB8() throws IOException, ReflectiveOperationException {
+        compileSpec("C(Jd1(Id0))");
+        assertLinkage("C", "J1", "J1");
+    }
+
+    // B9 needs too many classes
+
+    // The rest of Dan's tests need generics
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/combo-tests/tests/tools/javac/combo/ComboTestBase.java	Wed Aug 14 15:53:13 2013 -0700
@@ -0,0 +1,273 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  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 tools.javac.combo;
+
+import com.sun.tools.javac.util.Pair;
+import org.testng.annotations.AfterSuite;
+import org.testng.annotations.Test;
+
+import java.io.*;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.*;
+
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
+
+/**
+ * ComboTestBase
+ *
+ * @author Brian Goetz
+ */
+public abstract class ComboTestBase<T extends ComboTestBase<T>> extends JavacTemplateTestBase {
+    private final static Map<Class, ComboTestMetadata> metadataMap = new HashMap<>();
+    private final static boolean DEBUG_PROPERTY_SET = !System.getProperty("combo.debug", "").equals("");
+    private final static long timestamp = System.currentTimeMillis();
+    private final static Map</* filename */ String,
+                             Map</* combo vars */ Map<String, String>, /* data */ Map<String, String>>> debugInfo
+            = new HashMap<>();
+
+    protected final ComboTestMetadata<T> metadata;
+    protected final Object[] comboArgs;
+    private boolean debugOnly = false;
+
+    // This class cannot have a constructor; it interferes with testng's ability to find the factory method
+    //in subclasses.  Anything that would be done by a constructor should insteady be done by init blocks
+    //or the pseudoConstructor() method.
+
+    /* init */ {
+        metadata = getMetadata((Class<T>) getClass());
+        comboArgs = new Object[metadata.dimensions.length];
+    }
+
+    /**
+     * This method is meant to be called from an @Factory method in the subclass, passing its own class literal
+     * as the clazz argument.  It will introspect over the provided class, find the dimension variables, and
+     * generate the combinatorial explosion of test cases.  (It consults shouldSkip() to determine if a particular
+     * combination should be skipped.)
+     */
+    public static<T extends ComboTestBase> Object[] factory(Class<T> clazz) throws ReflectiveOperationException {
+        int index = 0;
+        try {
+            ComboTestMetadata<T> md = getMetadata(clazz);
+            List<T> list = new ArrayList<>();
+            for (Object[] args : md.makeLoop()) {
+                T instance = md.makeInstance(args);
+                if (!instance.shouldSkip()) {
+                    instance.pseudoConstructor(args);
+                    list.add(instance);
+                    instance.templates.put("__INDEX__", instance.new StringTemplate(Integer.toString(index++)));
+                    if (DEBUG_PROPERTY_SET)
+                        ((ComboTestBase) instance).debugOnly = true;
+                }
+            }
+
+            return list.toArray();
+        } catch (Throwable t) {
+            // This is a needed annoyance; TestNG swallows exception data from exceptions thrown from @Factory methods
+            t.printStackTrace(System.err);
+            t.printStackTrace(System.out);
+            throw t;
+        }
+    }
+
+    /** For debugging of test cases -- sets tests into debug-only mode, where we print out the instantiations of
+     * the dimension variables and the templates.
+     */
+    public static<T extends ComboTestBase> Object[] debugFactory(Class<T> clazz) throws ReflectiveOperationException {
+        Object[] results = factory(clazz);
+        for (Object o : results)
+            ((ComboTestBase) o).debugOnly = true;
+        return results;
+    }
+
+    private static<T extends ComboTestBase<T>> ComboTestMetadata<T> getMetadata(Class<T> clazz) {
+        try {
+            ComboTestMetadata<T> md = metadataMap.get(clazz);
+            if (md == null) {
+                md = new ComboTestMetadata<T>(clazz);
+                metadataMap.put(clazz, md);
+            }
+            return md;
+        } catch (ReflectiveOperationException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    // Should be private, but can't be
+    void pseudoConstructor(Object[] args) throws ReflectiveOperationException {
+        System.arraycopy(args, 0, comboArgs, 0, args.length);
+    }
+
+    private void addTemplates() throws ReflectiveOperationException {
+        for (int i=0; i<comboArgs.length; i++)
+            addTemplate(metadata.dimensions[i].name, asTemplate(comboArgs[i]));
+
+        for (ComboTestMetadata.TemplateMember<TemplateVar, Field> m : metadata.templateFields)
+            addTemplate(m.name, asTemplate(m.member.get(this)));
+
+        for (ComboTestMetadata.TemplateMember<TemplateVar, Method> m : metadata.templateMethods)
+            addTemplate(m.name, asTemplate(m.member.invoke(this)));
+    }
+
+    private void addAllSourceFiles() throws ReflectiveOperationException {
+        for (ComboTestMetadata.TemplateMember<SourceFile, Field> m : metadata.sourceFields)
+            addSourceFile(m.name, asTemplate(m.member.get(this)));
+
+        for (ComboTestMetadata.TemplateMember<SourceFile, Method> m : metadata.sourceMethods)
+            addSourceFile(m.name, asTemplate(m.member.invoke(this)));
+    }
+
+    private void addSourceFiles(String group) throws ReflectiveOperationException {
+        for (ComboTestMetadata.TemplateMember<SourceFile, Field> m : metadata.sourceFields)
+            if (group.equals(m.annotation.group()))
+                addSourceFile(m.name, asTemplate(m.member.get(this)));
+
+        for (ComboTestMetadata.TemplateMember<SourceFile, Method> m : metadata.sourceMethods)
+            if (group.equals(m.annotation.group()))
+                addSourceFile(m.name, asTemplate(m.member.invoke(this)));
+    }
+
+    /**
+     * Should the current combination of inputs be skipped?  Default implementation returns false for
+     * all combinations (indicating all combinations are valid.)
+     */
+    protected boolean shouldSkip() {
+        return false;
+    }
+
+    protected boolean shouldRun() {
+        return false;
+    }
+
+    /**
+     * Called after test() compiles, allowing subclass an opportunity to examine diagonstics and assert
+     * their properties.  Default implementation calls assertCompileSucceeded().
+     * @param group
+     */
+    protected void postCompile(String group) {
+        assertCompileSucceeded();
+    }
+
+    protected String[] getCompileOptions(String group) {
+        return new String[0];
+    }
+
+    /**
+     * Called before test() compiles, allowing subclass an opportunity to set compilation options.
+     */
+    protected void preCompile(String group) {
+    }
+
+    @Test
+    public void test() throws Exception {
+        if (debugOnly) {
+            addTemplates();
+            addAllSourceFiles();
+            System.out.println("Test case : " + getTestCaseDescription());
+            for (Pair<String, Template> e : sourceFiles)
+                System.out.println("Source file " + e.fst + ": " + e.snd);
+
+            String testFile = getClass().getName();
+            Map<Map<String, String>, Map<String, String>> testCaseMap = debugInfo.get(testFile);
+            if (testCaseMap == null) {
+                testCaseMap = new HashMap<>();
+                debugInfo.put(testFile, testCaseMap);
+            }
+
+            Map<String, String> comboKeys = new HashMap<>();
+            for (int i=0; i<metadata.dimensions.length; i++)
+                comboKeys.put(metadata.dimensions[i].name, comboArgs[i].toString());
+            String compileOptions = Arrays.asList(getCompileOptions("")).toString();
+            Map<String, String> data = new HashMap<>();
+            int count = 0;
+            for (Pair<String, Template> e : sourceFiles) {
+                count++;
+                data.put("File." + count + ".FileName", e.fst);
+                data.put("File." + count + ".Source", e.snd.toString());
+                data.put("File." + count + ".Group", "");
+                data.put("File." + count + ".CompileOptions", compileOptions);
+            }
+            Object prev = testCaseMap.put(comboKeys, data);
+            if (prev != null)
+                fail(String.format("Duplicate key for file %s, keys %s", testFile, comboKeys.toString()));
+        }
+        else {
+            boolean generate = shouldRun();
+            boolean errors = false;
+            List<File> files = new ArrayList<>();
+            List<String> groupsReversed = new ArrayList<>(metadata.groups);
+            Collections.reverse(groupsReversed);
+            for (String g : groupsReversed) {
+                addTemplates();
+                addSourceFiles(g);
+                preCompile(g);
+                addCompileOptions(getCompileOptions(g));
+                for (File f : files)
+                    addClassPath(f);
+                files.add(0, compile(generate));
+                errors |= diags.errorsFound();
+                postCompile(g);
+                reset();
+            }
+
+            if (generate && !errors) {
+                run(loadClass("Main", files.toArray(new File[files.size()])));
+            }
+        }
+    }
+
+    @AfterSuite
+    public void dumpDebug() throws IOException {
+        if (DEBUG_PROPERTY_SET) {
+            for (Map.Entry<String, Map<Map<String, String>, Map<String, String>>> f : debugInfo.entrySet()) {
+                File out = new File(String.format("ComboLog-%s-%d.ser", f.getKey(), timestamp));
+                try (ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream(out))) {
+                    os.writeObject(f.getValue());
+                }
+            }
+        }
+    }
+
+    protected void run(Class<?> clazz) throws ReflectiveOperationException {
+        assertTrue(clazz != null);
+    }
+
+    protected String getTestCaseDescription() {
+        StringBuilder sb = new StringBuilder();
+        sb.append("ComboTest[").append(getClass().getName()).append(": ");
+        for (int i=0; i<metadata.dimensions.length; i++)
+            sb.append(metadata.dimensions[i].name).append(" = ").append(comboArgs[i]).append(", ");
+        sb.append("]");
+        return sb.toString();
+    }
+
+    protected boolean skipConstrained(int arity, Enum... enums) {
+        for (int i=arity; i<enums.length; i++)
+            if (enums[i].ordinal() != 0)
+                return true;
+        return false;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/combo-tests/tests/tools/javac/combo/ComboTestDebug.java	Wed Aug 14 15:53:13 2013 -0700
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  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 tools.javac.combo;
+
+import java.io.*;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+
+/**
+ * ComboTestDebug -- utility program for dumping or comparing combo test debug logs.  Debug logs can be
+ * used for debugging combo tests, as they contain all the generated source files and options (but are
+ * primarily used for testing for regressions in the combo test framework when changes are made to the
+ * framework.)
+ *
+ * @author Brian Goetz
+ */
+public class ComboTestDebug {
+    public static List<String> files = new ArrayList<>();
+    public static boolean compare;
+
+    private static void compareFiles(String s1, String s2) throws IOException, ClassNotFoundException {
+        Map</* combo vars */ Map<String, String>,
+                /* data */ Map<String, String>> f1, f2;
+        try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(s1))) {
+            f1 = (Map<Map<String, String>, Map<String, String>>) ois.readObject();
+        }
+        try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(s2))) {
+            f2 = (Map<Map<String, String>, Map<String, String>>) ois.readObject();
+        }
+
+        if (f1.size() != f2.size())
+            System.out.printf("Number of test cases differ: %d, %d%n", f1.size(), f2.size());
+
+        if (!f1.keySet().equals(f2.keySet())) {
+            System.out.printf("Test cases differ%n");
+            for (Map<String, String> k : f1.keySet()) {
+                if (!f2.containsKey(k))
+                    System.out.printf("Only in file 1: test case %s%n", k);
+            }
+            for (Map<String, String> k : f2.keySet()) {
+                if (!f1.containsKey(k))
+                    System.out.printf("Only in file 2: test case %s%n", k);
+            }
+        }
+
+        for (Map<String, String> k : f1.keySet()) {
+            if (!f2.keySet().contains(k))
+                continue;
+            Map<String, String> d1 = f1.get(k);
+            Map<String, String> d2 = f2.get(k);
+            if (!d1.equals(d2)) {
+                System.out.printf("Test case %s%n", k);
+                for (String s : d1.keySet())
+                    if (!d2.containsKey(s))
+                        System.out.printf("  Only in file 1: key %s%n", s);
+                    else {
+                        if (!d1.get(s).equals(d2.get(s))) {
+                            System.out.printf("  Key values differ for key %s: [%s] [%s]%n", s, d1.get(s), d2.get(s));
+                        }
+                    }
+                for (String s : d2.keySet())
+                    if (!d1.containsKey(s))
+                        System.out.printf("  Only in file 2: key %s%n", s);
+                System.out.println();
+            }
+        }
+    }
+
+    private static void dumpFile(String s) throws IOException, ClassNotFoundException {
+        try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(s))) {
+            Map</* combo vars */ Map<String, String>,
+                /* data */ Map<String, String>> debugInfo;
+
+            debugInfo = (Map<Map<String, String>, Map<String, String>>) ois.readObject();
+            System.out.printf("%d test cases%n%n", debugInfo.size());
+            for (Map.Entry<Map<String, String>, Map<String, String>> e : debugInfo.entrySet()) {
+                System.out.println("Test case: " + e.getKey());
+                for (Map.Entry<String, String> de : new TreeMap<>(e.getValue()).entrySet())
+                    System.out.printf("  %s = %s%n", de.getKey(), de.getValue());
+                System.out.println();
+            }
+        }
+
+    }
+
+    public static void main(String[] args) throws IOException, ClassNotFoundException {
+        for (String a : args) {
+            if (a.equals("-c"))
+                compare = true;
+            else if (a.startsWith("-"))
+                usage();
+            else
+                files.add(a);
+        }
+
+        if (compare) {
+            if (files.size() != 2)
+                usage();
+            compareFiles(files.get(0), files.get(1));
+        }
+        else {
+            for (String f : files)
+                dumpFile(f);
+        }
+    }
+
+    public static void usage() {
+        System.out.println("Usage: ComboTestDebug [ -c ] files...");
+        System.exit(0);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/combo-tests/tests/tools/javac/combo/ComboTestMetadata.java	Wed Aug 14 15:53:13 2013 -0700
@@ -0,0 +1,190 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  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 tools.javac.combo;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Member;
+import java.lang.reflect.Method;
+import java.util.*;
+
+/**
+ * ComboTestMetadata
+ *
+ * @author Brian Goetz*/
+class ComboTestMetadata<T> {
+    public final Class<T> clazz;
+    public final Constructor<T> ctor;
+    public final List<TemplateMember<TemplateVar, Field>> templateFields = new ArrayList<>();
+    public final List<TemplateMember<TemplateVar, Method>> templateMethods = new ArrayList<>();
+    public final List<TemplateMember<SourceFile, Field>> sourceFields = new ArrayList<>();
+    public final List<TemplateMember<SourceFile, Method>> sourceMethods = new ArrayList<>();
+    public final Set<String> groups = new TreeSet<>();
+    public final Dimension[] dimensions;
+
+    public ComboTestMetadata(Class<T> clazz) throws ReflectiveOperationException {
+        this.clazz = clazz;
+        Constructor[] constructors = clazz.getConstructors();
+        ctor = (constructors.length == 1 && constructors[0].getParameterTypes().length > 0) ? constructors[0] : null;
+
+        Map<DimensionVar, Field> tmpDimFields = new LinkedHashMap<>();
+        for (Field f : clazz.getDeclaredFields()) {
+            TemplateVar template = f.getAnnotation(TemplateVar.class);
+            if (template != null) {
+                if (!Template.class.isAssignableFrom(f.getType()) && !String.class.isAssignableFrom(f.getType()))
+                    throw new AssertionError(String.format("Found @TemplateVar on field %s whose type is not Template or String", f));
+                f.setAccessible(true);
+                templateFields.add(new TemplateMember<>(template.value(), template, f));
+            }
+
+            SourceFile source = f.getAnnotation(SourceFile.class);
+            if (source != null) {
+                if (!Template.class.isAssignableFrom(f.getType()) && !String.class.isAssignableFrom(f.getType()))
+                    throw new AssertionError(String.format("Found @SourceFile on field %s whose type is not Template or String", f));
+                f.setAccessible(true);
+                sourceFields.add(new TemplateMember<>(source.value(), source, f));
+                groups.add(source.group());
+            }
+            
+            DimensionVar dim = f.getAnnotation(DimensionVar.class);
+            if (dim != null) 
+                tmpDimFields.put(dim, f);
+        }
+
+        for (Method m : clazz.getDeclaredMethods()) {
+            TemplateVar template = m.getAnnotation(TemplateVar.class);
+            if (template != null) {
+                if (!Template.class.isAssignableFrom(m.getReturnType()) && !String.class.isAssignableFrom(m.getReturnType()))
+                    throw new AssertionError(String.format("Found @TemplateVar on method %s whose return type is not Template or String", m));
+                m.setAccessible(true);
+                templateMethods.add(new TemplateMember<>(template.value(), template, m));
+            }
+
+            SourceFile source = m.getAnnotation(SourceFile.class);
+            if (source != null) {
+                if (!Template.class.isAssignableFrom(m.getReturnType()) && !String.class.isAssignableFrom(m.getReturnType()))
+                    throw new AssertionError(String.format("Found @SourceFile on method %s whose return type is not Template or String ", m));
+                sourceMethods.add(new TemplateMember<>(source.value(), source, m));
+                groups.add(source.group());
+            }
+        }
+
+        if (constructors.length > 1)
+            throw new AssertionError(String.format("Multiple constructors for class %s", clazz));
+        else if (ctor != null && !tmpDimFields.isEmpty())
+            throw new AssertionError(String.format("Class %s has both constructors and fields with @DimensionVar", clazz));
+        else if (constructors.length == 0 && tmpDimFields.isEmpty())
+            throw new AssertionError(String.format("Class %s has neither constructors nor fields with @DimensionVar", clazz));
+        else if (ctor != null) {
+            Class<?>[] argTypes = ctor.getParameterTypes();
+            Annotation[][] paramAnnotations = ctor.getParameterAnnotations();
+            dimensions = new Dimension[argTypes.length];
+            for (int i = 0, argTypesLength = argTypes.length; i < argTypesLength; i++) {
+                DimensionVar cd = null;
+                for (Annotation a : paramAnnotations[i])
+                    if (a instanceof DimensionVar) {
+                        cd = (DimensionVar) a;
+                        break;
+                    }
+                if (cd == null)
+                    throw new AssertionError(String.format("Parameter %d of constructor %s does not have @DimensionVar annotation", i, ctor));
+                dimensions[i] = new Dimension(cd, argTypes[i], String.format("Parameter %d of constructor %s", i, ctor));
+            }
+        }
+        else {
+            dimensions = new Dimension[tmpDimFields.size()];
+            int i = 0;
+            for (Map.Entry<DimensionVar, Field> e : tmpDimFields.entrySet())
+                dimensions[i++] = new Dimension(e.getKey(), e.getValue());
+        }
+    }
+
+    public T makeInstance(Object[] args) throws ReflectiveOperationException {
+        if (ctor != null)
+            return ctor.newInstance(args);
+        else {
+            T t = clazz.newInstance();
+            for (int i=0; i< dimensions.length; i++)
+                dimensions[i].field.set(t, args[i]);
+            return t;
+        }
+    }
+
+    public SyntheticLoop makeLoop() {
+        int n = dimensions.length;
+        Object[][] dimValues = new Object[n][];
+        for (int i=0; i<n; i++)
+            dimValues[i] = dimensions[i].values;
+        return new SyntheticLoop(dimValues);
+    }
+
+    static class Dimension {
+        public final Object[] values;
+        public final String name;
+        public final Field field;
+
+        public Dimension(DimensionVar dv, Field f) throws ReflectiveOperationException {
+            field = f;
+            field.setAccessible(true);
+            name = dv.value();
+            values = getValues(dv, f.getType(), String.format("Field %s", f.getName()));
+        }
+
+        public Dimension(DimensionVar dv, Class<?> paramType, String descr) throws ReflectiveOperationException {
+            field = null;
+            name = dv.value();
+            values = getValues(dv, paramType, descr);
+        }
+
+        private Object[] getValues(DimensionVar dv, Class<?> clazz, String descr) throws ReflectiveOperationException {
+            if (Enum.class.isAssignableFrom(clazz) && Template.class.isAssignableFrom(clazz)) {
+                Method m = clazz.getDeclaredMethod("values");
+                m.setAccessible(true);
+                return (Template[]) m.invoke(null);
+            }
+            else if (int.class.isAssignableFrom(clazz)) {
+                Object[] ts = new Object[dv.rangeUpper() - dv.rangeLower() + 1];
+                for (int i=dv.rangeLower(); i <= dv.rangeUpper(); i++)
+                    ts[i-dv.rangeLower()] = i;
+                return ts;
+            }
+            else
+                throw new AssertionError(String.format("Invalid type %s for %s", clazz.getName(), descr));
+        }
+    }
+
+    static class TemplateMember<A extends Annotation, M extends Member> {
+        public final String name;
+        public final A annotation;
+        public final M member;
+
+        TemplateMember(String name, A annotation, M member) {
+            this.name = name;
+            this.annotation = annotation;
+            this.member = member;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/combo-tests/tests/tools/javac/combo/Diagnostics.java	Wed Aug 14 15:53:13 2013 -0700
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  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 tools.javac.combo;
+
+import javax.tools.Diagnostic;
+import javax.tools.JavaFileObject;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+* A container for compiler diagnostics, separated into errors and warnings,
+ * used by JavacTemplateTestBase.
+ *
+ * @author Brian Goetz
+*/
+public class Diagnostics implements javax.tools.DiagnosticListener<JavaFileObject> {
+
+    protected List<String> errors = new ArrayList<>();
+    protected List<String> warnings = new ArrayList<>();
+
+    public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
+        switch (diagnostic.getKind()) {
+            case ERROR:
+                errors.add(diagnostic.getCode());
+                break;
+
+            case WARNING:
+            case MANDATORY_WARNING:
+                warnings.add(diagnostic.getCode());
+                break;
+        }
+    }
+
+    /** Were there any errors found? */
+    public boolean errorsFound() {
+        return !errors.isEmpty();
+    }
+
+    /** How many errors were found? */
+    public int getErrorCount() {
+        return errors.size();
+    }
+
+    /** Get the error keys */
+    public List<String> errors() {
+        return errors;
+    }
+
+    public String toString() { return errors.toString(); }
+
+    /** Clear all diagnostic state */
+    public void reset() {
+        errors.clear();
+        warnings.clear();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/combo-tests/tests/tools/javac/combo/DimensionVar.java	Wed Aug 14 15:53:13 2013 -0700
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  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 tools.javac.combo;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+* DimensionVar
+*/
+@Retention(RetentionPolicy.RUNTIME)
+@java.lang.annotation.Target({ElementType.PARAMETER, ElementType.FIELD})
+public @interface DimensionVar {
+    String value();
+    int rangeLower() default 0;
+    int rangeUpper() default 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/combo-tests/tests/tools/javac/combo/JavacTemplateTestBase.java	Wed Aug 14 15:53:13 2013 -0700
@@ -0,0 +1,364 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  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 tools.javac.combo;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
+import javax.tools.JavaCompiler;
+import javax.tools.JavaFileObject;
+import javax.tools.SimpleJavaFileObject;
+import javax.tools.StandardJavaFileManager;
+import javax.tools.StandardLocation;
+import javax.tools.ToolProvider;
+
+import com.sun.source.util.JavacTask;
+import com.sun.tools.javac.util.Pair;
+import org.testng.ITestResult;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.AfterSuite;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.fail;
+
+/**
+ * Base class for template-driven TestNG javac tests that support on-the-fly
+ * source file generation, compilation, classloading, execution, and separate
+ * compilation.
+ *
+ * <p>Manages a set of templates (which have embedded tags of the form
+ * {@code #\{NAME\}}), source files (which are also templates), and compile
+ * options.  Test cases can register templates and source files, cause them to
+ * be compiled, validate whether the set of diagnostic messages output by the
+ * compiler is correct, and optionally load and run the compiled classes.
+ *
+ * @author Brian Goetz
+ */
+@Test
+public abstract class JavacTemplateTestBase {
+    private static final Set<String> suiteErrors = Collections.synchronizedSet(new HashSet<>());
+    private static final AtomicInteger counter = new AtomicInteger();
+    private static final File root = new File(System.getProperty("user.dir"), "gen");
+    private static final File nullDir = new File(System.getProperty("user.dir"), "empty");
+
+    protected final Map<String, Template> templates = new HashMap<>();
+    protected final Diagnostics diags = new Diagnostics();
+    protected final List<Pair<String, Template>> sourceFiles = new ArrayList<>();
+    protected final List<String> compileOptions = new ArrayList<>();
+    protected final List<File> classpaths = new ArrayList<>();
+    protected final Template.Resolver defaultResolver = new MapResolver(templates);
+
+    private Template.Resolver currentResolver = defaultResolver;
+
+    /** Add a template with a specified name */
+    protected void addTemplate(String name, Template t) {
+        templates.put(name, t);
+    }
+
+    /** Add a template with a specified name */
+    protected void addTemplate(String name, String s) {
+        templates.put(name, new StringTemplate(s));
+    }
+
+    /** Add a source file */
+    protected void addSourceFile(String name, Template t) {
+        sourceFiles.add(new Pair<>(name, t));
+    }
+
+    /** Add a File to the class path to be used when loading classes; File values
+     * will generally be the result of a previous call to {@link #compile()}.
+     * This enables testing of separate compilation scenarios if the class path
+     * is set up properly.
+     */
+    protected void addClassPath(File path) {
+        classpaths.add(path);
+    }
+
+    /**
+     * Add a set of compilation command-line options
+     */
+    protected void addCompileOptions(String... opts) {
+        Collections.addAll(compileOptions, opts);
+    }
+
+    /** Reset the compile options to the default (empty) value */
+    protected void resetCompileOptions() { compileOptions.clear(); }
+
+    /** Remove all templates */
+    protected void resetTemplates() { templates.clear(); }
+
+    /** Remove accumulated diagnostics */
+    protected void resetDiagnostics() { diags.reset(); }
+
+    /** Remove all source files */
+    protected void resetSourceFiles() { sourceFiles.clear(); }
+
+    /** Remove registered class paths */
+    protected void resetClassPaths() { classpaths.clear(); }
+
+    // Before each test method, reset everything
+    @BeforeMethod
+    public void reset() {
+        resetCompileOptions();
+        resetDiagnostics();
+        resetSourceFiles();
+        resetTemplates();
+        resetClassPaths();
+    }
+
+    // After each test method, if the test failed, capture source files and diagnostics and put them in the log
+    @AfterMethod
+    public void copyErrors(ITestResult result) {
+        if (!result.isSuccess()) {
+            suiteErrors.addAll(diags.errors());
+
+            List<Object> list = new ArrayList<>();
+            Collections.addAll(list, result.getParameters());
+            list.add("Test case: " + getTestCaseDescription());
+            for (Pair<String, Template> e : sourceFiles)
+                list.add("Source file " + e.fst + ": " + e.snd);
+            if (diags.getErrorCount() != 0)
+                list.add("Compile diagnostics: " + diags.toString());
+            result.setParameters(list.toArray(new Object[list.size()]));
+        }
+    }
+
+    @AfterSuite
+    // After the suite is done, dump any errors to output
+    public void dumpErrors() {
+        if (!suiteErrors.isEmpty())
+            System.err.println("Errors found in test suite: " + suiteErrors);
+    }
+
+    /**
+     * Get a description of this test case; since test cases may be combinatorially
+     * generated, this should include all information needed to describe the test case
+     */
+    protected String getTestCaseDescription() {
+        return this.toString();
+    }
+
+    /** Assert that all previous calls to compile() succeeded */
+    protected void assertCompileSucceeded() {
+        if (diags.errorsFound())
+            fail("Expected successful compilation");
+    }
+
+    /**
+     * If the provided boolean is true, assert all previous compiles succeeded,
+     * otherwise assert that a compile failed.
+     * */
+    protected void assertCompileSucceededIff(boolean b) {
+        if (b)
+            assertCompileSucceeded();
+        else
+            assertCompileFailed();
+    }
+
+    /** Assert that a previous call to compile() failed */
+    protected void assertCompileFailed() {
+        if (!diags.errorsFound())
+            fail("Expected failed compilation");
+    }
+
+    /** Assert that a previous call to compile() failed with a specific error key */
+    protected void assertCompileFailed(String message) {
+        if (!diags.errorsFound())
+            fail("Expected failed compilation: " + message);
+    }
+
+    /** Assert that a previous call to compile() failed with all of the specified error keys */
+    protected void assertCompileErrors(String... keys) {
+        if (!diags.errorsFound())
+            fail("Expected failed compilation");
+        for (String k : keys)
+            if (!diags.errors().contains(k))
+                fail("Expected compilation error " + k);
+    }
+
+    /** Convert an object, which may be a Template or a String, into a Template */
+    protected Template asTemplate(Object o) {
+        if (o instanceof Template)
+            return (Template) o;
+        else if (o instanceof String)
+            return new StringTemplate((String) o);
+        else
+            return new StringTemplate(o.toString());
+    }
+
+    /** Compile all registered source files */
+    protected void compile() throws IOException {
+        compile(false);
+    }
+
+    /** Compile all registered source files, optionally generating class files
+     * and returning a File describing the directory to which they were written */
+    protected File compile(boolean generate) throws IOException {
+        List<JavaFileObject> files = new ArrayList<>();
+        for (Pair<String, Template> e : sourceFiles)
+            files.add(new FileAdapter(e.fst, asTemplate(e.snd)));
+        return compile(classpaths, files, generate);
+    }
+
+    /** Compile all registered source files, using the provided list of class paths
+     * for finding required classfiles, optionally generating class files
+     * and returning a File describing the directory to which they were written */
+    protected File compile(List<File> classpaths, boolean generate) throws IOException {
+        List<JavaFileObject> files = new ArrayList<>();
+        for (Pair<String, Template> e : sourceFiles)
+            files.add(new FileAdapter(e.fst, asTemplate(e.snd)));
+        return compile(classpaths, files, generate);
+    }
+
+    private File compile(List<File> classpaths, List<JavaFileObject> files, boolean generate) throws IOException {
+        JavaCompiler systemJavaCompiler = ToolProvider.getSystemJavaCompiler();
+        StandardJavaFileManager fm = systemJavaCompiler.getStandardFileManager(null, null, null);
+        if (classpaths.size() > 0)
+            fm.setLocation(StandardLocation.CLASS_PATH, classpaths);
+        JavacTask ct = (JavacTask) systemJavaCompiler.getTask(null, fm, diags, compileOptions, null, files);
+        if (generate) {
+            File destDir = new File(root, Integer.toString(counter.incrementAndGet()));
+            // @@@ Assert that this directory didn't exist, or start counter at max+1
+            destDir.mkdirs();
+            fm.setLocation(StandardLocation.CLASS_OUTPUT, Arrays.asList(destDir));
+            ct.generate();
+            return destDir;
+        }
+        else {
+            ct.analyze();
+            return nullDir;
+        }
+    }
+
+    /** Load the given class using the provided list of class paths */
+    protected Class<?> loadClass(String className, File... destDirs) {
+        try {
+            List<URL> list = new ArrayList<>();
+            for (File f : destDirs)
+                list.add(new URL("file:" + f.toString().replace("\\", "/") + "/"));
+            return Class.forName(className, true, new URLClassLoader(list.toArray(new URL[list.size()])));
+        } catch (ClassNotFoundException | MalformedURLException e) {
+            throw new RuntimeException("Error loading class " + className, e);
+        }
+    }
+
+    /** An implementation of Template which is backed by a String */
+    protected class StringTemplate implements Template {
+        protected final String template;
+
+        public StringTemplate(String template) {
+            this.template = template;
+        }
+
+        public String expand(String selector) {
+            return Behavior.expandTemplate(template, currentResolver);
+        }
+
+        public String toString() {
+            return expand("");
+        }
+
+        public StringTemplate with(final String key, final String value) {
+            return new StringTemplateWithResolver(template, new KeyResolver(key, value));
+        }
+
+    }
+
+    /** An implementation of Template which is backed by a String and which
+     * encapsulates a Resolver for resolving embedded tags. */
+    protected class StringTemplateWithResolver extends StringTemplate {
+        private final Resolver localResolver;
+
+        public StringTemplateWithResolver(String template, Resolver localResolver) {
+            super(template);
+            this.localResolver = localResolver;
+        }
+
+        @Override
+        public String expand(String selector) {
+            Resolver saved = currentResolver;
+            currentResolver = new ChainedResolver(currentResolver, localResolver);
+            try {
+                return super.expand(selector);
+            }
+            finally {
+                currentResolver = saved;
+            }
+        }
+
+        @Override
+        public StringTemplate with(String key, String value) {
+            return new StringTemplateWithResolver(template, new ChainedResolver(localResolver, new KeyResolver(key, value)));
+        }
+    }
+
+    /** A Resolver which uses a Map to resolve tags */
+    private class KeyResolver implements Template.Resolver {
+        private final String key;
+        private final String value;
+
+        public KeyResolver(String key, String value) {
+            this.key = key;
+            this.value = value;
+        }
+
+        @Override
+        public Template lookup(String k) {
+            return key.equals(k) ? new StringTemplate(value) : null;
+        }
+    }
+
+    private class FileAdapter extends SimpleJavaFileObject {
+        private final String filename;
+        private final Template template;
+
+        public FileAdapter(String filename, Template template) {
+            super(URI.create("myfo:/" + filename), Kind.SOURCE);
+            this.template = template;
+            this.filename = filename;
+        }
+
+        public CharSequence getCharContent(boolean ignoreEncodingErrors) {
+            return toString();
+        }
+
+        public String toString() {
+            return Template.Behavior.expandTemplate(template.expand(filename), defaultResolver);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/combo-tests/tests/tools/javac/combo/SeparateCompilationComboTest.java	Wed Aug 14 15:53:13 2013 -0700
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  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 tools.javac.combo;
+
+import org.testng.annotations.Factory;
+
+import java.lang.reflect.Method;
+
+import static org.testng.Assert.assertEquals;
+
+/**
+ * SeparateCompilationComboTest
+ */
+public class SeparateCompilationComboTest extends ComboTestBase<SeparateCompilationComboTest> {
+    @Factory
+    public static Object[] testCombo() throws Exception {
+        return factory(SeparateCompilationComboTest.class);
+    }
+
+    @DimensionVar("FOO") Dummy dummy;
+
+    @SourceFile(value="Main.java", group="B") String a2 = "public class Main { public String main() { return Other.b(); } }";
+    @SourceFile(value="Other.java", group="B") String b2 = "public class Other { public static String b() { return \"1\"; } }";
+    @SourceFile(value="Other.java", group="A") String b1 = "public class Other { public static String b() { return \"2\"; } }";
+
+    @Override
+    protected boolean shouldRun() {
+        return true;
+    }
+
+    @Override
+    protected void run(Class<?> clazz) throws ReflectiveOperationException {
+        Object obj = clazz.newInstance();
+        Method m = clazz.getMethod("main");
+        String result = (String) m.invoke(obj);
+        assertEquals("2", result);
+    }
+
+    static enum Dummy implements Template {
+        A();
+
+        public String expand(String selector) { return toString(); }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/combo-tests/tests/tools/javac/combo/SeparateCompilationComboTest2.java	Wed Aug 14 15:53:13 2013 -0700
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  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 tools.javac.combo;
+
+import org.testng.annotations.Factory;
+
+import java.lang.reflect.Method;
+
+import static org.testng.Assert.assertEquals;
+
+/**
+ * SeparateCompilationComboTest2
+ */
+public class SeparateCompilationComboTest2 extends ComboTestBase<SeparateCompilationComboTest2> {
+    @Factory
+    public static Object[] testCombo() throws Exception {
+        return factory(SeparateCompilationComboTest2.class);
+    }
+
+    @DimensionVar("FOO") Dummy dummy;
+
+    @SourceFile(value="Main.java", group="A" )
+    String main = "public class Main { public String main() { return new B().x(); } }";
+    @SourceFile(value="B.java", group="B" )
+    String b = "public class B extends C { public String x() { return \"2\"; } }";
+    @SourceFile(value="C.java", group="C" )
+    String c = "public class C { public String x() { return \"1\"; } }";
+
+    @Override
+    protected boolean shouldRun() {
+        return true;
+    }
+
+    @Override
+    protected void run(Class<?> clazz) throws ReflectiveOperationException {
+        Object obj = clazz.newInstance();
+        Method m = clazz.getMethod("main");
+        String result = (String) m.invoke(obj);
+        assertEquals("2", result);
+    }
+
+    static enum Dummy implements Template {
+        A();
+
+        public String expand(String selector) { return toString(); }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/combo-tests/tests/tools/javac/combo/SeparateCompilationTest.java	Wed Aug 14 15:53:13 2013 -0700
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  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 tools.javac.combo;
+
+import org.testng.annotations.Test;
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.Method;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+/**
+ * SeparateCompilationTest -- test of test framework to do separate compilation
+ */
+@Test
+public class SeparateCompilationTest extends JavacTemplateTestBase {
+
+    public void testCompletelySeparate() throws ReflectiveOperationException, IOException {
+        addSourceFile("A.java", new StringTemplate("public class A { public String a() throws Throwable { return Class.forName(\"B\").getName(); } }"));
+        File aFile = compile(true);
+        assertCompileSucceeded();
+        reset();
+
+        addSourceFile("B.java", new StringTemplate("public class B {  }"));
+        File bFile = compile(true);
+        assertCompileSucceeded();
+
+        Class clazz = loadClass("A", aFile, bFile);
+        Method m = clazz.getMethod("a");
+        Object instance = clazz.newInstance();
+        String x = (String) m.invoke(instance);
+        assertEquals("B", x);
+    }
+
+    public void testIdenticalRecompile() throws ReflectiveOperationException, IOException {
+        addSourceFile("A.java", new StringTemplate("public class A { public String a() { return B.b(); } }"));
+        addSourceFile("B.java", new StringTemplate("public class B { public static String b() { return \"1\"; } }"));
+        File aFile = compile(true);
+        assertCompileSucceeded();
+        // Deleting B.class is not generally needed for test cases that simply replace B, but here we're testing the framework's ability to find B elsewhere
+        File bClass = new File(aFile, "B.class");
+        assertTrue(bClass.exists());
+        boolean deleted = bClass.delete();
+        assertTrue(deleted);
+        reset();
+
+        addSourceFile("B.java", new StringTemplate("public class B { public static String b() { return \"1\"; } }"));
+        File bFile = compile(true);
+        assertCompileSucceeded();
+
+        Class clazz = loadClass("A", bFile, aFile);
+        Method m = clazz.getMethod("a");
+        Object instance = clazz.newInstance();
+        String x = (String) m.invoke(instance);
+        assertEquals("1", x);
+    }
+
+    public void testConsistentRecompile() throws ReflectiveOperationException, IOException {
+        addSourceFile("A.java", new StringTemplate("public class A { public String a() { return B.b(); } }"));
+        addSourceFile("B.java", new StringTemplate("public class B { public static String b() { return \"1\"; } }"));
+        File aFile = compile(true);
+        assertCompileSucceeded();
+        reset();
+
+        addSourceFile("B.java", new StringTemplate("public class B { public static String b() { return \"2\"; } }"));
+        File bFile = compile(true);
+        assertCompileSucceeded();
+
+        Class clazz = loadClass("A", bFile, aFile);
+        Method m = clazz.getMethod("a");
+        Object instance = clazz.newInstance();
+        String x = (String) m.invoke(instance);
+        assertEquals("2", x);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/combo-tests/tests/tools/javac/combo/SourceFile.java	Wed Aug 14 15:53:13 2013 -0700
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  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 tools.javac.combo;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * SourceFile
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@java.lang.annotation.Target({ElementType.METHOD, ElementType.FIELD})
+public @interface SourceFile {
+    String value();
+    String group() default "";
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/combo-tests/tests/tools/javac/combo/StackProcessingUtils.java	Wed Aug 14 15:53:13 2013 -0700
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  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 tools.javac.combo;
+
+/**
+ * Utility class for defining stack processing-like operations
+ *
+ * @author Maurizio Cimadamore
+ */
+public class StackProcessingUtils {
+
+    /**
+     * interface representing a stack item - each item has an arity ---
+     * if arity is > 0 - then the item is an operator
+     */
+    public interface StackItem<T extends StackItem<T>> {
+        int arity();
+    }
+
+    /**
+     * A reducer takes an element of the stack and produces a result of a given
+     * type by applying the stack item to zero or more operands
+     */
+    public interface StackReducer<I extends StackItem<I>, T, O> {
+        T reduce(I item, T[] operands, O o);
+        Class<T> resultToken();
+        O reducerArg(I item, int i);
+    }
+
+    static class StackResult<T> {
+        T result;
+        int nextPos;
+
+        StackResult(T result, int nextPos) {
+            this.result = result;
+            this.nextPos = nextPos;
+        }
+    }
+
+    public static <I extends StackItem<I>, T, O> T process(I[] elems, StackReducer<I, T, O> reducer, O o) {
+        StackResult<T> result = processInternal(0, elems, reducer, o);
+        assert result.nextPos == elems.length;
+        return result.result;
+    }
+
+    private static <I extends StackItem<I>, T, O> StackResult<T> processInternal(int start, I[] elems, StackReducer<I, T, O> reducer, O o) {
+        @SuppressWarnings("unchecked")
+        I head = elems[start];
+        T[] operands = (T[])java.lang.reflect.Array.newInstance(reducer.resultToken(), head.arity());
+        int nextPos = start + 1;
+        for (int i = 0 ; i < head.arity() ; i++) {
+            StackResult<T> partialResult = processInternal(nextPos, elems, reducer, reducer.reducerArg(head, i));
+            nextPos = partialResult.nextPos;
+            operands[i] = partialResult.result;
+        }
+        return new StackResult<T>(reducer.reduce(head, operands, o), nextPos);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/combo-tests/tests/tools/javac/combo/StringTemplateTest.java	Wed Aug 14 15:53:13 2013 -0700
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  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 tools.javac.combo;
+
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.assertEquals;
+
+/**
+ * StringTemplateTest
+ */
+@Test
+public class StringTemplateTest extends JavacTemplateTestBase {
+    private void assertTemplate(String expected, Template template) {
+        String result = template.expand("");
+        assertEquals(result, expected, "for " + template);
+    }
+
+    public void testStringTemplate() {
+        assertTemplate("XYZ", new StringTemplate("XYZ"));
+        addTemplate("NONE", "SOME");
+        assertTemplate("SOME", new StringTemplate("#{NONE}"));
+
+        addTemplate("A", "#{B}");
+        addTemplate("B", "C");
+        assertTemplate("C", new StringTemplate("#{A}"));
+    }
+
+    public void testChainedTemplate() {
+        assertTemplate("A", new StringTemplate("#{A}").with("A", "A"));
+        assertTemplate("AB", new StringTemplate("#{A}#{B}").with("A", "A").with("B", "B"));
+        assertTemplate("TWO", new StringTemplate("#{A}").with("A", "ONE").with("A", "TWO"));
+        addTemplate("A", "BASE_A");
+        addTemplate("AA", "#{A}");
+        assertTemplate("FAKE_A", new StringTemplate("#{A}").with("A", "FAKE_A"));
+        assertTemplate("BASE_A", new StringTemplate("#{AA}"));
+        assertTemplate("FAKE_A", new StringTemplate("#{AA}").with("A", "FAKE_A"));
+
+        addTemplate("X", new StringTemplate("#{A}").with("A", "intercepted"));
+        assertTemplate("intercepted", new StringTemplate("#{B}").with("B", "#{X}"));
+        addTemplate("Y", new StringTemplate("#{A}"));
+        assertTemplate("again", new StringTemplate("#{B}").with("B", "#{Y}").with("A", "again"));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/combo-tests/tests/tools/javac/combo/SyntheticLoop.java	Wed Aug 14 15:53:13 2013 -0700
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  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 tools.javac.combo;
+
+import java.util.Iterator;
+
+/**
+ * SyntheticLoop -- exhaustively generate a set of combinations of variables
+ *
+ * @author Brian Goetz
+ */
+public class SyntheticLoop implements Iterable<Object[]> {
+    final int dimensions;
+    final int[] maxs;
+    final Object[][] values;
+
+    /** Simple version -- generate the cartesian product of the provided sets of axis values */
+    public SyntheticLoop(Object[][] dimValues) {
+        dimensions = dimValues.length;
+        maxs = new int[dimensions];
+        values = new Object[dimensions][];
+        for (int i=0; i<dimensions; i++) {
+            values[i] = dimValues[i];
+            maxs[i] = values[i].length;
+        }
+    }
+
+//    /** Complex version -- allow the contents of some dimensions to depend on previous dimensions, such
+//     * as generating tuples (a,b) where foo(b) <= foo(a).  Of the two arrays provided, for each index i,
+//     * exactly one of dimValues[i], dimGenerators[i] must be non-null.
+//     */
+//    public SyntheticLoop(Object[][] dimValues, DimensionFactory[] dimGenerators) {
+//        @@@NYI
+//    }
+
+    public Iterator<Object[]> iterator() {
+        return new Iterator<Object[]>() {
+            final int[] idxs = new int[dimensions];
+            boolean hasNext = (dimensions > 0);
+
+            public boolean hasNext() {
+                return hasNext;
+            }
+
+            public Object[] next() {
+                Object[] ret = new Object[dimensions];
+                for (int i=0; i<dimensions; i++)
+                    ret[i] = values[i][idxs[i]];
+                hasNext = !advance(dimensions-1);
+                return ret;
+            }
+
+            public void remove() { throw new UnsupportedOperationException(); }
+
+            private boolean advance(int i) {
+                if (i < 0)
+                    return true;
+                if (++idxs[i] == maxs[i]) {
+                    idxs[i] = 0;
+                    return advance(i - 1);
+                }
+                return false;
+            }
+        };
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/combo-tests/tests/tools/javac/combo/SyntheticLoopTest.java	Wed Aug 14 15:53:13 2013 -0700
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  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 tools.javac.combo;
+
+import org.testng.annotations.Test;
+
+import java.util.Iterator;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+/**
+ * SyntheticLoopTest
+ */
+@Test
+public class SyntheticLoopTest {
+    public void testEmpty() {
+        SyntheticLoop sl = new SyntheticLoop(new Object[0][]);
+        Iterator<Object[]> it = sl.iterator();
+        assertTrue(!it.hasNext());
+    }
+
+    private void assertSL(String expected, SyntheticLoop sl) {
+        StringBuilder sb = new StringBuilder();
+        for (Object[] row : sl) {
+            for (Object o : row) {
+                sb.append(o);
+            }
+            sb.append(" ");
+        }
+        assertEquals(sb.toString(), expected);
+    }
+
+    private void assertSL(int size, SyntheticLoop sl) {
+        int count = 0;
+        for (Object row : sl) {
+            ++count;
+        }
+        assertEquals(count, size);
+    }
+
+    public void testSimple() {
+        Object[] abc = {"A", "B", "C"};
+        assertSL("A B C ", new SyntheticLoop(new Object[][] {abc}));
+        assertSL("AA AB AC BA BB BC CA CB CC ", new SyntheticLoop(new Object[][] {abc, abc}));
+        assertSL(9, new SyntheticLoop(new Object[][] {abc, abc}));
+        assertSL(9, new SyntheticLoop(new Object[][] {abc, abc, new Object[] { "X" }}));
+        assertSL(27, new SyntheticLoop(new Object[][] {abc, abc, abc}));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/combo-tests/tests/tools/javac/combo/Template.java	Wed Aug 14 15:53:13 2013 -0700
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  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 tools.javac.combo;
+
+import java.util.Map;
+import java.util.Objects;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * A template into which tags of the form {@code #\{KEY\}} or
+ * {@code #\{KEY.SUBKEY\}} can be expanded.
+ */
+public interface Template {
+    String expand(String selector);
+
+    interface Resolver {
+        public Template lookup(String key);
+    }
+
+    public static class Behavior {
+        private static final Pattern pattern = Pattern.compile("#\\{([A-Z_][A-Z0-9_]*(?:\\[\\d+\\])?)(?:\\.([A-Z0-9_]*))?\\}");
+
+        public static String expandTemplate(String template, final Map<String, Template> vars) {
+            return expandTemplate(template, new MapResolver(vars));
+        }
+
+        public static String expandTemplate(String template, Resolver res) {
+            CharSequence in = template;
+            StringBuffer out = new StringBuffer();
+            while (true) {
+                boolean more = false;
+                Matcher m = pattern.matcher(in);
+                while (m.find()) {
+                    String major = m.group(1);
+                    String minor = m.group(2);
+                    Template key = res.lookup(major);
+                    if (key == null)
+                        throw new IllegalStateException("Unknown major key " + major);
+
+                    String replacement = key.expand(minor == null ? "" : minor);
+                    more |= pattern.matcher(replacement).find();
+                    m.appendReplacement(out, replacement);
+                }
+                m.appendTail(out);
+                if (!more)
+                    return out.toString();
+                else {
+                    in = out;
+                    out = new StringBuffer();
+                }
+            }
+        }
+
+    }
+}
+
+class MapResolver implements Template.Resolver {
+    private final Map<String, Template> vars;
+
+    public MapResolver(Map<String, Template> vars) {this.vars = vars;}
+
+    public Template lookup(String key) {
+        return vars.get(key);
+    }
+}
+
+class ChainedResolver implements Template.Resolver {
+    private final Template.Resolver upstreamResolver, thisResolver;
+
+    public ChainedResolver(Template.Resolver upstreamResolver, Template.Resolver thisResolver) {
+        this.upstreamResolver = upstreamResolver;
+        this.thisResolver = thisResolver;
+    }
+
+    public Template.Resolver getUpstreamResolver() {
+        return upstreamResolver;
+    }
+
+    @Override
+    public Template lookup(String key) {
+        Template result = thisResolver.lookup(key);
+        if (result == null)
+            result = upstreamResolver.lookup(key);
+        return result;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/combo-tests/tests/tools/javac/combo/TemplateTest.java	Wed Aug 14 15:53:13 2013 -0700
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  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 tools.javac.combo;
+
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.Test;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.testng.Assert.assertEquals;
+
+/**
+ * TemplateTest
+ */
+@Test
+public class TemplateTest {
+    Map<String, Template> vars = new HashMap<>();
+
+    @BeforeTest
+    void before() { vars.clear(); }
+
+    private void assertTemplate(String expected, String template) {
+        String result = Template.Behavior.expandTemplate(template, vars);
+        assertEquals(result, expected, "for " + template);
+    }
+
+    private String dotIf(String s) {
+        return s == null || s.isEmpty() ? "" : "." + s;
+    }
+
+    public void testTemplateExpansion() {
+        vars.put("A", s -> "a" + dotIf(s));
+        vars.put("B", s -> "b" + dotIf(s));
+        vars.put("C", s -> "#{A}#{B}");
+        vars.put("D", s -> "#{A" + dotIf(s) + "}#{B" + dotIf(s) + "}");
+        vars.put("_D", s -> "d");
+
+        assertTemplate("", "");
+        assertTemplate("foo", "foo");
+        assertTemplate("a", "#{A}");
+        assertTemplate("a", "#{A.}");
+        assertTemplate("a.FOO", "#{A.FOO}");
+        assertTemplate("aa", "#{A}#{A}");
+        assertTemplate("ab", "#{C}");
+        assertTemplate("ab", "#{C.FOO}");
+        assertTemplate("ab", "#{C.}");
+        assertTemplate("a.FOOb.FOO", "#{D.FOO}");
+        assertTemplate("ab", "#{D}");
+        assertTemplate("d", "#{_D}");
+        assertTemplate("#{A", "#{A");
+    }
+
+    public void testIndexedTemplate() {
+        vars.put("A[0]", s -> "a" );
+        vars.put("A[1]", s -> "b" );
+        vars.put("A[2]", s -> "c" );
+        vars.put("X", s -> "0");
+        assertTemplate("a", "#{A[0]}");
+        assertTemplate("b", "#{A[1]}");
+        assertTemplate("c", "#{A[2]}");
+    }
+
+    public void testAngleBrackets() {
+        vars.put("X", s -> "xyz");
+        assertTemplate("List<String> ls = xyz;", "List<String> ls = #{X};");
+    }
+
+    @Test(expectedExceptions = IllegalStateException.class )
+    public void testUnknownKey() {
+        assertTemplate("#{Q}", "#{Q}");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/combo-tests/tests/tools/javac/combo/TemplateVar.java	Wed Aug 14 15:53:13 2013 -0700
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  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 tools.javac.combo;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * ComboTemplate
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@java.lang.annotation.Target({ElementType.METHOD, ElementType.FIELD})
+public @interface TemplateVar {
+    String value();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/combo-tests/tests/tools/javac/lambda/ConditionalExpressionTest.java	Wed Aug 14 15:53:13 2013 -0700
@@ -0,0 +1,271 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  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 tools.javac.lambda;
+
+import org.testng.annotations.Factory;
+import tools.javac.combo.ComboTestBase;
+import tools.javac.combo.DimensionVar;
+import tools.javac.combo.SourceFile;
+import tools.javac.combo.Template;
+import tools.javac.combo.TemplateVar;
+
+/**
+ * ConditionalExpressionTest
+ */
+public class ConditionalExpressionTest extends ComboTestBase<ConditionalExpressionTest> {
+    @Factory
+    public static Object[] testConditionalExpression() throws Exception {
+        return factory(ConditionalExpressionTest.class);
+    }
+
+    @DimensionVar("TYPE1") Type type1;
+    @DimensionVar("TYPE2") Type type2;
+    @DimensionVar("TARGET") Type target;
+    @DimensionVar("STMT") Statement stmt;
+
+    @SourceFile("Main.java")
+    String clientFile = "public class Main {\n"
+            + " #{STMT_DECL};\n"
+            + " #{DECL.1};\n"
+            + " #{DECL.2};\n"  
+            + " void test(boolean cond) { \n"
+            + "   #{STMT};"
+            + " }\n"
+            +"}";
+
+    @Override
+    protected void postCompile(String grp) {
+        CondResult res = Type.condType(type1, type2);
+        if (!res.check(type1, type2, target)) {
+            assertCompileFailed();
+        } else {
+            assertCompileSucceeded();
+        }
+    }
+
+    @Override
+    protected boolean shouldSkip() {
+        return target == Type.INT_CONST;
+    }
+
+    interface CondResult {
+        boolean check(Type op1, Type op2, Type target);
+    }
+
+    static CondResult ERR = new CondResult() {
+        public boolean check(Type op1, Type op2, Type target) { return false; }
+    };
+
+    static CondResult TARGET = new CondResult() {
+        public boolean check(Type op1, Type op2, Type target) {
+           return op1.compatibleWith(target) && op2.compatibleWith(target);
+        }
+    };
+
+    enum TypeKind {
+        NUMERIC,
+        BOOLEAN,
+        OTHER;
+    }
+
+    enum Type implements Template, CondResult {
+        BYTE("byte", "0", TypeKind.NUMERIC),
+        SHORT("short", "0", TypeKind.NUMERIC),
+        INT("int", "0", TypeKind.NUMERIC),
+        INT_CONST("int", "0", TypeKind.NUMERIC),
+        LONG("long", "0", TypeKind.NUMERIC),
+        FLOAT("float", "0", TypeKind.NUMERIC),
+        DOUBLE("double", "0", TypeKind.NUMERIC),
+        CHAR("char", "'0'", TypeKind.NUMERIC),
+        BOOLEAN("boolean", "false", TypeKind.BOOLEAN),
+        J_L_BYTE("Byte", "null", TypeKind.NUMERIC),
+        J_L_SHORT("Short", "null", TypeKind.NUMERIC),
+        J_L_INT("Integer", "null", TypeKind.NUMERIC),
+        J_L_LONG("Long", "null", TypeKind.NUMERIC),
+        J_L_FLOAT("Float", "null", TypeKind.NUMERIC),
+        J_L_DOUBLE("Double", "null", TypeKind.NUMERIC),
+        J_L_CHAR("Character", "null", TypeKind.NUMERIC),
+        J_L_BOOLEAN("Boolean", "null", TypeKind.BOOLEAN),
+        NUMBER("Number", "null", TypeKind.OTHER),
+        SERIAL("java.io.Serializable", "null", TypeKind.OTHER);
+
+        public boolean check(Type op1, Type op2, Type target) {
+            return compatibleWith(target);
+        }
+
+        public boolean isErroneous() {
+            return false;
+        }
+
+        public String expand(String qualifier) {
+            return typeStr;
+        }
+
+        boolean compatibleWith(Type that) {
+            return that.anyOf(compatibleWith[this.ordinal()]);
+        }
+
+        boolean anyOf(Type... ts) {
+            for (Type t : ts) {
+                if (t == this) return true;
+            }
+            return false;
+        }
+
+        Type unbox() {
+            switch (this) {
+                case BYTE:
+                case J_L_BYTE: return BYTE;
+                case SHORT:
+                case J_L_SHORT: return SHORT;
+                case INT:
+                case INT_CONST:
+                case J_L_INT: return INT;
+                case LONG:
+                case J_L_LONG: return LONG;
+                case FLOAT:
+                case J_L_FLOAT: return FLOAT;
+                case DOUBLE:
+                case J_L_DOUBLE: return DOUBLE;
+                case BOOLEAN:
+                case J_L_BOOLEAN: return BOOLEAN;
+                case CHAR:
+                case J_L_CHAR: return CHAR;                
+                default:
+                    return null;
+            }
+        }
+
+        String typeStr;
+        String defaultVal;
+        TypeKind kind;
+
+        Type(String typeStr, String defaultVal, TypeKind kind) {
+            this.typeStr = typeStr;
+            this.defaultVal = defaultVal;
+            this.kind = kind;
+        }
+
+        static CondResult condType(Type type1, Type type2) {
+            if (type1.kind == TypeKind.BOOLEAN && type2.kind == TypeKind.BOOLEAN) {
+                //boolean conditional
+                return BOOLEAN;
+            } else if (type1.kind == TypeKind.NUMERIC && type2.kind == TypeKind.NUMERIC) {                    
+                //numeric conditional
+                Type unbox1 = type1.unbox();
+                Type unbox2 = type2.unbox();
+                if (type1 == INT_CONST &&     
+                        unbox2.anyOf(CHAR, BYTE, SHORT)) {
+                    return unbox2;
+                }
+                if (type2 == INT_CONST &&     
+                        unbox1.anyOf(CHAR, BYTE, SHORT)) {
+                    return unbox1;
+                }
+                if (unbox1 == unbox2) {
+                    return unbox1;
+                }
+                if (unbox1 == CHAR) {
+                    return condType(INT, unbox2);
+                }
+                if (unbox2 == CHAR) {
+                    return condType(unbox1, INT);
+                }
+                if (unbox1.compatibleWith(unbox2)) {
+                    return unbox2;
+                } else if (unbox2.compatibleWith(unbox1)) {
+                    return unbox1;
+                } else {
+                    return ERR;
+                }
+            } else {
+                //reference conditional
+                return TARGET;
+            }
+        }
+
+        static Type[][] compatibleWith = new Type[][] {
+        /* BYTE */        { BYTE, SHORT, INT, LONG, FLOAT, DOUBLE, J_L_BYTE, NUMBER, SERIAL },
+        /* SHORT */       { SHORT, INT, LONG, FLOAT, DOUBLE, J_L_SHORT, NUMBER, SERIAL },
+        /* INT */         { INT, LONG, FLOAT, DOUBLE, J_L_INT, NUMBER, SERIAL },
+        /* INT_CONST */   { INT, LONG, FLOAT, DOUBLE, J_L_INT, NUMBER, SERIAL },
+        /* LONG */        { LONG, FLOAT, DOUBLE, J_L_LONG, NUMBER, SERIAL },
+        /* FLOAT */       { FLOAT, DOUBLE, J_L_FLOAT, NUMBER, SERIAL },
+        /* DOUBLE */      { DOUBLE, J_L_DOUBLE, NUMBER, SERIAL },
+        /* CHAR */        { CHAR, INT, LONG, FLOAT, DOUBLE, J_L_CHAR, SERIAL },
+        /* BOOLEAN */     { BOOLEAN, J_L_BOOLEAN, SERIAL },
+        /* J_L_BYTE */    { J_L_BYTE, BYTE, SHORT, INT, LONG, FLOAT, DOUBLE, NUMBER, SERIAL },
+        /* J_L_SHORT */   { J_L_SHORT, SHORT, INT, LONG, FLOAT, DOUBLE, NUMBER, SERIAL },
+        /* J_L_INT */     { J_L_INT, INT, LONG, FLOAT, DOUBLE, NUMBER, SERIAL },
+        /* J_L_LONG */    { J_L_LONG, LONG, FLOAT, DOUBLE, NUMBER, SERIAL },
+        /* J_L_FLOAT */   { J_L_FLOAT, FLOAT, DOUBLE, NUMBER, SERIAL },
+        /* J_L_DOUBLE */  { J_L_DOUBLE, DOUBLE, NUMBER, SERIAL },
+        /* J_L_CHAR */    { J_L_CHAR, CHAR, INT, LONG, FLOAT, DOUBLE, SERIAL },
+        /* J_L_BOOLEAN */ { J_L_BOOLEAN, BOOLEAN, SERIAL },
+        /* NUMBER */      { NUMBER, SERIAL },
+        /* SERIAL */      { SERIAL } };
+    }
+
+    enum Statement implements Template {
+        ASSIGN("#{TARGET} t = cond ? #{EXPR.1} : #{EXPR.2}"),
+        METHOD("m(cond ? #{EXPR.1} : #{EXPR.2})");
+
+        String stmtStr;
+
+        Statement(String stmtStr) {
+            this.stmtStr = stmtStr;
+        }
+
+        public String expand(String qual) {
+            return stmtStr;
+        }
+    }
+
+    @TemplateVar("STMT_DECL")
+    Template stmt_decl = new Template() {
+        public String expand(String selector) {            
+            return stmt == Statement.ASSIGN ? "" : "void m(#{TARGET} arg) { }";
+        }
+    };
+
+    @TemplateVar("DECL")
+    Template decl = new Template() {
+        public String expand(String selector) {
+            int sel = Integer.valueOf(selector);
+            Type t = sel == 1 ? type1 : type2;
+            return t == Type.INT_CONST ? "" : String.format("#{TYPE%d} m%d() { return %s; }", sel, sel, t.defaultVal);
+        }
+    };
+
+    @TemplateVar("EXPR")
+    Template expr = new Template() {
+        public String expand(String selector) {
+            int sel = Integer.valueOf(selector);
+            Type t = sel == 1 ? type1 : type2;
+            return t == Type.INT_CONST ? t.defaultVal : String.format("m%d()", sel);
+        }
+    };
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/combo-tests/tests/tools/javac/lambda/DefaultMethodAddTest.java	Wed Aug 14 15:53:13 2013 -0700
@@ -0,0 +1,170 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  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 tools.javac.lambda;
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.Method;
+import java.lang.reflect.InvocationTargetException;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.testng.annotations.Factory;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+import tools.javac.combo.*;
+
+/**
+ * DefaultMethodAddTest: Test default method by running bytecode compiled at different times
+ *                       where conflicting default methods are added or declared
+ */
+public class DefaultMethodAddTest extends ComboTestBase<DefaultMethodAddTest> {
+    @Factory
+    public static Object[] testDefaultMethodAdd() throws Exception {
+        return factory(DefaultMethodAddTest.class);
+    }
+    
+    @DimensionVar("SHAPE") CShapes shapeType;
+    
+    /**
+     * The separate-compilation operation to be performed, such as adding a default method, 
+     * adding an abstract itnerface method, redeclaring an inherited default method as 
+     * abstract interface method, etc
+     */     
+    @DimensionVar("ADD") AddType addType;
+        
+    @SourceFile(value="B.java", group="A")
+    String interfaceBModified = "interface B #{SHAPE.B_DECL} { #{ADD} }";
+    
+    @SourceFile(value="B.java", group="B")
+    String interfaceB =         "interface B #{SHAPE.B_DECL} {}";
+    
+    @SourceFile(value="A.java", group="B")
+    String interfaceA =         "interface A { default String m() { return \"A\"; } }";
+    
+    @SourceFile(value="C.java", group="B")
+    String classC = "#{SHAPE.C}";
+    
+    @SourceFile(value="Main.java", group="B")
+    String classMain = "public class Main {\n" +
+                       "    public String main() {\n" +
+                       "        return new C().m();\n" +                       
+                       "    }\n" +
+                       "}";    
+
+    @Override
+    protected boolean shouldRun() { return true; }
+    
+    @Override
+    protected void run(Class<?> clazz) throws ReflectiveOperationException {
+        Method m = clazz.getMethod("main");
+        Object obj = clazz.newInstance();
+        String result = null, output = null;
+        try {
+            result = (String) m.invoke(obj);
+        } catch (InvocationTargetException ex) {
+            output = ex.getCause().toString();
+        }        
+        if(shapeType == CShapes.C_B_A) {
+            if(addType == AddType.ADD) {
+                assertEquals(output, null);
+                assertEquals(result, "B");
+            }
+            else //redeclare
+                assertEquals(output, "java.lang.AbstractMethodError: Method B.m()Ljava/lang/String; is abstract");
+        }
+        else if(shapeType == CShapes.C_I_AB2) {
+            assertEquals(output, null);
+            assertEquals(result, "A");
+        }
+        else if(shapeType == CShapes.C_CI) {
+            assertEquals(output, null);
+            assertEquals(result, "D");
+        }
+        else if(shapeType == CShapes.C_I_AB3) {
+            assertEquals(output, null);
+            assertEquals(result, "AB");
+        }
+        else            
+            assertTrue(output.matches("java.lang.AbstractMethodError: Conflicting default methods: .+[.]m .+[.]m"));        
+    }
+    
+    enum CShapes implements Template { //shapes of class hirarchy
+        //class C implements interface A, B
+        C_AB("",            
+           "class C implements A, B {}"), 
+        //class C implments interface B, B extends interface A
+        C_B_A("extends A", 
+           "class C implements B {}"),
+        //class C implments interface AB, AB extends interface A, B
+        C_I_AB("", 
+           "interface AB extends A, B {  }\n" + 
+           "class C implements AB {}"),
+        //class C implments interface AB, AB extends interface A, B and explicitly inherits the default method in A
+        C_I_AB2("", 
+        "interface AB extends A, B { default String m() { return A.super.m(); } }\n" + 
+        "class C implements AB {}"),
+        //class C implments interface AB, AB extends interface A, B and overrides the default method inherited
+        C_I_AB3("", 
+        "interface AB extends A, B { default String m() { return \"AB\"; } }\n" + 
+        "class C implements AB {}"),
+        //class C extends Class D implements Interface B
+        C_CI("", 
+            "class D { public String m() { return \"D\"; } }\n" + 
+            "class C extends D implements B {}");
+        
+        private final String sB_DECL;
+        private final String sC;
+        
+        CShapes(String sB_DECL, String sC) {
+            this.sB_DECL = sB_DECL;
+            this.sC = sC;
+        }
+        
+        public String expand(String selector) {
+            switch(selector) {
+                case "B_DECL": return sB_DECL;
+                case "C": return sC;
+                default: return toString();
+            }            
+        }        
+    }
+    
+    enum AddType implements Template { // add by adding default method or abstract interface method
+        ADD("default String m() { return \"B\"; }"),
+        REDECLARE("String m();");
+        
+        final String newCode;
+        
+        AddType(String str) {
+            newCode = str;
+        }
+        
+        public String expand(String selector) {
+            return newCode;        
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/combo-tests/tests/tools/javac/lambda/DefaultMethodRemoveTest.java	Wed Aug 14 15:53:13 2013 -0700
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  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 tools.javac.lambda;
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.Method;
+import java.lang.reflect.InvocationTargetException;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.testng.annotations.Factory;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+import tools.javac.combo.*;
+
+/**
+ * DefaultMethodRemoveTest: Test default method by running bytecode compiled at different times
+ *                          where default methods are removed or redeclared
+ */
+public class DefaultMethodRemoveTest extends ComboTestBase<DefaultMethodRemoveTest> {
+    @Factory
+    public static Object[] testDefalutMethodRemove() throws Exception {
+        return factory(DefaultMethodRemoveTest.class);
+    }
+    
+    @DimensionVar("SHAPE") CShapes shapeType;
+    
+    /**
+     * The separate-compilation operation to be performed, such as removing a default method, 
+     * redeclaring as abstract interface method, etc
+     */  
+    @DimensionVar("REMOVE") RemoveType removeType;
+    
+    @SourceFile(value="B.java", group="A")
+    String interfaceBModified = "interface B #{SHAPE.B_DECL} { #{REMOVE} }";
+      
+    @SourceFile(value="A.java", group="B")
+    String interfaceA = "interface A { default String m() { return \"A\"; } }";
+    
+    @SourceFile(value="B.java", group="B")
+    String interfaceB = "interface B #{SHAPE.B_DECL} { default String m() { return \"B\"; } }";
+        
+    @SourceFile(value="C.java", group="B")
+    String classC = "#{SHAPE.C}";
+    
+    @SourceFile(value="Main.java", group="B")
+    String classMain = "public class Main {\n" +
+                       "    public String main() {\n" +
+                       "        return new C().m();\n" +                       
+                       "    }\n" +
+                       "}";    
+
+    @Override
+    protected boolean shouldRun() { return true; }
+    
+    @Override
+    protected void postCompile(String group) {
+        if( group.equals("A") && shapeType == CShapes.C_B_AD && removeType == RemoveType.REMOVE )
+            assertCompileErrors("compiler.err.types.incompatible.unrelated.defaults");
+    }
+
+    @Override
+    protected void run(Class<?> clazz) throws ReflectiveOperationException {
+        Method m = clazz.getMethod("main");
+        Object obj = clazz.newInstance();
+        String result = null, output = null;
+        try {
+            result = (String) m.invoke(obj);
+        } catch (InvocationTargetException ex) {
+            output = ex.getCause().toString();            
+        }
+        if(shapeType == CShapes.C_B_A) {
+            if(removeType == RemoveType.REMOVE)
+                assertEquals(result, "A");
+            else
+                assertEquals(output, "java.lang.AbstractMethodError: Method B.m()Ljava/lang/String; is abstract");
+        }
+        else if(shapeType == CShapes.C_CI)
+            assertEquals(result, "D");
+        else if(shapeType == CShapes.C_B_AD) {
+            if(removeType == RemoveType.REMOVE)
+                assertEquals(output, "java.lang.AbstractMethodError: C.m()Ljava/lang/String;");
+            else    
+                assertEquals(output, "java.lang.AbstractMethodError: Method B.m()Ljava/lang/String; is abstract");
+        }
+        else { //C_B
+            if( removeType == RemoveType.REMOVE)
+                assertEquals(output, "java.lang.NoSuchMethodError: C.m()Ljava/lang/String;");
+            else
+                assertEquals(output, "java.lang.AbstractMethodError: C.m()Ljava/lang/String;");
+        }
+    }
+    
+    enum CShapes implements Template { //shapes of class hirarchy
+        //class C implements interface B
+        C_B("", 
+            "class C implements B {}"), 
+        //class C implments interface B, B extends interface A
+        C_B_A("extends A", 
+              "class C implements B {}"),
+        //class C implments interface B, B extends interface A, D
+        C_B_AD("extends A, D", 
+               "interface D { default String m() { return \"D\"; } }\n" + 
+               "class C implements B {}"),
+        //class C extends Class D implements Interface B
+        C_CI("", 
+             "class D { public String m() { return \"D\"; } }\n" + 
+             "class C extends D implements B {}");
+        
+        private final String sB_DECL;
+        private final String sC;
+        
+        CShapes(String sB_DECL, String sC) {
+            this.sB_DECL = sB_DECL;
+            this.sC = sC;            
+        }
+        
+        public String expand(String selector) {
+            switch(selector) {
+                case "B_DECL": return sB_DECL;
+                case "C": return sC;                
+                default: return toString();
+            }
+        }        
+    }
+    
+    enum RemoveType implements Template { //remove by removing default method code or redeclaring the interface method
+        REMOVE(""),
+        REDECLARE("String m();");
+        
+        final String newCode;
+        
+        RemoveType(String str) {
+            newCode = str;
+        }
+        
+        public String expand(String selector) {
+            return newCode;        
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/combo-tests/tests/tools/javac/lambda/LambdaArgAdaptationTest.java	Wed Aug 14 15:53:13 2013 -0700
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  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 tools.javac.lambda;
+
+import org.testng.annotations.Factory;
+import tools.javac.combo.ComboTestBase;
+import tools.javac.combo.DimensionVar;
+import tools.javac.combo.SourceFile;
+import tools.javac.combo.Template;
+
+import java.lang.reflect.Method;
+import java.util.EnumMap;
+import java.util.EnumSet;
+
+import static org.testng.Assert.assertEquals;
+
+/**
+ * LambdaArgAdaptationTest
+ */
+public class LambdaArgAdaptationTest extends ComboTestBase<LambdaArgAdaptationTest> {
+    @Factory
+    public static Object[] testArgAdaptation() throws Exception {
+        return factory(LambdaArgAdaptationTest.class);
+    }
+
+    @DimensionVar("FROM") Types fromType;
+    @DimensionVar("TO") Types toType;
+
+    @SourceFile("Sam.java")
+    String samFile = "public interface Sam { String m(#{FROM} arg); }";
+
+    @SourceFile("Main.java")
+    String clientFile = "public class Main {\n"
+                        +"  static String m(#{TO} arg) { \n"
+                        +"    return String.valueOf(arg);\n"
+                        +"  }\n"
+                        +"  public String main() { \n"
+                        + "   Sam s = Main::m;\n"
+                        + "   return s.m(#{FROM.ARG});\n"
+                        + " }\n"
+                        +"}";
+
+
+    @Override
+    protected String[] getCompileOptions(String group) {
+        return new String[] { "-XDlambdaToMethod" };
+    }
+
+    @Override
+    protected void postCompile(String group) {
+        if (fromType == Types.VOID || toType == Types.VOID)
+            assertCompileFailed();
+        else if (fromType.pr == PR.REF && toType.pr == PR.REF)
+            assertCompileSucceededIff(toType.clazz.isAssignableFrom(fromType.clazz));
+        else if (fromType.pr == PR.PRIM && toType.pr == PR.REF)
+            assertCompileSucceededIff(toType.clazz.isAssignableFrom(Types.boxMap.get(fromType).clazz));
+        else if (fromType.pr == PR.REF && toType.pr == PR.PRIM)
+            assertCompileSucceededIff(fromType.unboxed != null && Types.widenMap.get(fromType.unboxed).contains(toType));
+        else if (fromType.pr == PR.PRIM && toType.pr == PR.PRIM)
+            assertCompileSucceededIff(Types.widenMap.get(fromType).contains(toType));
+        else
+            assertCompileSucceeded();
+    }
+
+    @Override
+    protected boolean shouldRun() { return true; }
+
+    @Override
+    protected void run(Class<?> clazz) throws ReflectiveOperationException {
+        Method m = clazz.getMethod("main");
+        Object obj = clazz.newInstance();
+        String result = (String) m.invoke(obj);
+        String formatted = fromType.asObject.toString();
+        if (fromType == Types.CHAR || fromType == Types.BOXED_CHAR) {
+            result = result.replace("A", "65");
+            formatted = formatted.replace("A", "65");
+        }
+        assertEquals(result.replace(".0", ""), formatted.replace(".0", ""));
+    }
+}
+
+enum PR {PRIM, REF}
+
+enum Types implements Template {
+    BYTE(PR.PRIM, "byte", byte.class, "(byte) 1", (byte) 1),
+    SHORT(PR.PRIM, "short", short.class, "(short) 2", (short) 2),
+    CHAR(PR.PRIM, "char", char.class, "'A'", 'A'),
+    INT(PR.PRIM, "int", int.class, "3", 3),
+    LONG(PR.PRIM, "long", long.class, "4L", 4L),
+    FLOAT(PR.PRIM, "float", float.class, "5.0f", 5.0f),
+    DOUBLE(PR.PRIM, "double", double.class, "6.0", 6.0),
+    BOOLEAN(PR.PRIM, "boolean", boolean.class, "true", true),
+    VOID(PR.PRIM, "void", void.class, "null", null),
+    BOXED_BYTE(PR.REF, "Byte", Byte.class, "Byte.valueOf((byte) 1)", (byte) 1, BYTE),
+    BOXED_SHORT(PR.REF, "Short", Short.class, "Short.valueOf((short) 2)", (short) 2, SHORT),
+    BOXED_CHAR(PR.REF, "Character", Character.class, "Character.valueOf('A')", 'A', CHAR),
+    BOXED_INT(PR.REF, "Integer", Integer.class, "Integer.valueOf(3)", 3, INT),
+    BOXED_LONG(PR.REF, "Long", Long.class, "Long.valueOf(4)", (long) 4, LONG),
+    BOXED_FLOAT(PR.REF, "Float", Float.class, "Float.valueOf(5.0f)", 5.0f, FLOAT),
+    BOXED_DOUBLE(PR.REF, "Double", Double.class, "Double.valueOf(6.0)", 6.0, DOUBLE),
+    BOXED_BOOLEAN(PR.REF, "Boolean", Boolean.class, "Boolean.valueOf(true)", true, BOOLEAN),
+    NUMBER(PR.REF, "Number", Number.class, "9", 9),
+    OBJECT(PR.REF, "Object", Object.class, "10", 10),
+    STRING(PR.REF, "String", String.class, "\"foo\"", "foo");
+
+    public static EnumMap<Types, Types> boxMap = new EnumMap<>(Types.class);
+    public static EnumMap<Types, Types> unboxMap = new EnumMap<>(Types.class);
+    public static EnumMap<Types, EnumSet<Types>> widenMap = new EnumMap<>(Types.class);
+
+    static {
+        for (Types t : values()) {
+            if (t.unboxed != null) {
+                boxMap.put(t.unboxed, t);
+                unboxMap.put(t, t.unboxed);
+            }
+        }
+
+        widenMap.put(BYTE, EnumSet.of(BYTE, SHORT, INT, LONG, FLOAT, DOUBLE));
+        widenMap.put(SHORT, EnumSet.of(SHORT, INT, LONG, FLOAT, DOUBLE));
+        widenMap.put(CHAR, EnumSet.of(CHAR, INT, LONG, FLOAT, DOUBLE));
+        widenMap.put(INT, EnumSet.of(INT, LONG, FLOAT, DOUBLE));
+        widenMap.put(LONG, EnumSet.of(LONG, FLOAT, DOUBLE));
+        widenMap.put(FLOAT, EnumSet.of(FLOAT, DOUBLE));
+        widenMap.put(DOUBLE, EnumSet.of(DOUBLE));
+        widenMap.put(BOOLEAN, EnumSet.of(BOOLEAN));
+    }
+
+    final PR pr;
+    final String name;
+    final Class<?> clazz;
+    final String valueString;
+    final Object asObject;
+    final Types unboxed;
+
+    Types(PR pr, String name, Class<?> clazz, String valueString, Object asObject) {
+        this (pr, name, clazz, valueString, asObject, null);
+    }
+
+    Types(PR pr, String name, Class<?> clazz, String valueString, Object asObject, Types unboxed) {
+        this.pr = pr;
+        this.name = name;
+        this.clazz = clazz;
+        this.valueString = valueString;
+        this.asObject = asObject;
+        this.unboxed = unboxed;
+    }
+
+    public String expand(String selector) {
+        switch (selector) {
+            case "ARG": return valueString;
+            default: return name;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/combo-tests/tests/tools/javac/lambda/LambdaCaptureTest.java	Wed Aug 14 15:53:13 2013 -0700
@@ -0,0 +1,261 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  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 tools.javac.lambda;
+
+import org.testng.annotations.Factory;
+import org.testng.annotations.Test;
+import tools.javac.combo.*;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.testng.Assert.assertEquals;
+
+/**
+ * LambdaCaptureTest
+ *
+ * @author Brian Goetz
+ */
+public class LambdaCaptureTest extends ComboTestBase<LambdaCaptureTest> {
+    @Factory
+    public static Object[] testCombo() throws Exception {
+        return factory(LambdaCaptureTest.class);
+    }
+
+    final int arity;
+    final ArgType[] argTypes;
+    final int capArity;
+    final CapType[] capTypes;
+    final boolean shouldSkip;
+
+    public LambdaCaptureTest(@DimensionVar(value = "ARITY", rangeLower = 0, rangeUpper = 2) int arity,
+                             @DimensionVar("ARGTYPE1") ArgType argType1,
+                             @DimensionVar("ARGTYPE2") ArgType argType2,
+                             @DimensionVar(value = "CAP_ARITY", rangeLower = 0, rangeUpper = 2) int capArity,
+                             @DimensionVar("CAPTYPE1") CapType capType1,
+                             @DimensionVar("CAPTYPE2") CapType capType2) {
+        this.arity = arity;
+        this.capArity = capArity;
+        this.argTypes = new ArgType[] { argType1, argType2 };
+        this.capTypes = new CapType[] { capType1, capType2 };
+        shouldSkip = skipConstrained(arity, argTypes) || skipConstrained(capArity, capTypes);
+    }
+
+    @Override
+    protected String[] getCompileOptions(String group) {
+        return new String[] { "-XDlambdaToMethod" };
+    }
+
+    @SourceFile("Main.java") String test
+            = "public class Main {\n"
+            + "  #{CAPTYPE1} f0 = #{CAPV.1};\n"
+            + "  #{CAPTYPE2} f1 = #{CAPV.2};\n"
+            + "  interface Target { String m(#{SAM_FORMALS}); }\n"
+            + "  public String convert() { #{CAPTYPE1} loc0 = #{CAPV.1};\n"
+            + "                            #{CAPTYPE2} loc1 = #{CAPV.2};\n"
+            + "                            Target lambda = (#{LAMBDA_FORMALS}) -> String.format(\"#{FORMAT_STRING}\" #{FORMAT_ARGS});\n"
+            + "                            return lambda.m(#{INVOKE_ARGS}); }\n"
+            + "}";
+
+    @TemplateVar("LAMBDA_FORMALS") Template formalArgs = new Template() {
+        public String expand(String selector) {
+            List<String> list = new ArrayList<>();
+            for (int i=0; i<arity; i++)
+                list.add(argTypes[i].typeName + " a" + i);
+            return intersperse(list, ", ");
+        }
+    };
+
+    @TemplateVar("SAM_FORMALS") Template samArgs = new Template() {
+        public String expand(String selector) {
+            List<String> list = new ArrayList<>();
+            for (int i=0; i<arity; i++)
+                list.add(argTypes[i].typeName + " a" + i);
+            return intersperse(list, ", ");
+        }
+    };
+
+    @TemplateVar("FORMAT_STRING") Template formatString = new Template() {
+        public String expand(String selector) {
+            List<String> list = new ArrayList<>();
+            for (int i=0; i<capArity; i++)
+                list.add(capTypes[i].argType.format);
+            for (int i=0; i<arity; i++)
+                list.add(argTypes[i].format);
+            return intersperse(list, " ");
+        }
+    };
+
+    @TemplateVar("FORMAT_ARGS") Template formatArgs = new Template() {
+        public String expand(String selector) {
+            List<String> list = new ArrayList<>();
+            for (int i=0; i<capArity; i++)
+                list.add((capTypes[i].lf == LF.LOCAL ? "loc" : "f") + i);
+            for (int i=0; i<arity; i++)
+                list.add("a" + i);
+            return ((list.size()) > 0 ? ", " : "") + intersperse(list, ", ");
+        }
+    };
+
+    @TemplateVar("INVOKE_ARGS") Template invokeArgs = new Template() {
+        public String expand(String selector) {
+            List<String> list = new ArrayList<>();
+            for (int i=0; i<arity; i++)
+                list.add(argTypes[i].formatValue(i+capArity));
+            return intersperse(list, ", ");
+        }
+    };
+
+    @TemplateVar("CAPV") Template capv = new Template() {
+        public String expand(String selector) {
+            int i = Integer.parseInt(selector) - 1;
+            return capTypes[i].argType.formatValue(i);
+        }
+    };
+
+    private String intersperse(List<String> list, String delim) {
+        StringBuilder sb = new StringBuilder();
+        boolean first = true;
+        for (String s : list) {
+            if (!first)
+                sb.append(delim);
+            first = false;
+            sb.append(s);
+        }
+        return sb.toString();
+    }
+
+    @Override
+    protected boolean shouldSkip() {
+        return shouldSkip;
+    }
+
+    @Override
+    protected boolean shouldRun() {
+        return true;
+    }
+
+    @Override
+    protected void run(Class<?> clazz) throws ReflectiveOperationException {
+        Object obj = clazz.newInstance();
+        Method m = clazz.getMethod("convert");
+        Object o = m.invoke(obj);
+
+        List<String> list = new ArrayList<>();
+        for (int i=0; i<capArity; i++)
+            list.add(capTypes[i].argType.formatResult(i));
+        for (int i=0; i<arity; i++)
+            list.add(argTypes[i].formatResult(i+capArity));
+        String result = intersperse(list, " ");
+        assertEquals(result, o);
+    }
+
+    static enum ArgType implements Template {
+        LONG("long", "Long", "J%d", null) {
+            String formatValue(int x) { return String.format("(long) %d", x); }
+            String formatResult(int x) { return "J" + Integer.toString(x); }
+        },
+        BYTE("byte", "Byte", "B%d", LONG) {
+            String formatValue(int x) { return String.format("(byte) %d", x); }
+            String formatResult(int x) { return "B" + Integer.toString(x); }
+        },
+        SHORT("short", "Short", "S%d", LONG) {
+            String formatValue(int x) { return String.format("(short) %d", x); }
+            String formatResult(int x) { return "S" + Integer.toString(x); }
+        },
+        CHAR("char", "Character", "C%c", LONG) {
+            String formatValue(int x) { return String.format("(char) (((int) 'A') + %d)", x); }
+            String formatResult(int x) { return "C" + (char) (((int) 'A') + x); }
+        },
+        INT("int", "Integer", "I%d", LONG) {
+            String formatValue(int x) { return String.format("%d", x); }
+            String formatResult(int x) { return "I" + Integer.toString(x); }
+        },
+        BOOLEAN("boolean", "Boolean", "Z%b", null) {
+            String formatValue(int x) { return String.format("%d %% 2 != 0", x); }
+            String formatResult(int x) { return "Z" + (x % 2 != 0); }
+        },
+        DOUBLE("double", "Double", "D%f", null) {
+            String formatValue(int x) { return String.format("(double) %d", x); }
+            String formatResult(int x) { return "D" + String.format("%f", (double) x); }
+        },
+        FLOAT("float", "Float", "F%f", DOUBLE) {
+            String formatValue(int x) { return String.format("(float) %d", x); }
+            String formatResult(int x) { return "F" + String.format("%f", (float) x); }
+        },
+        OBJECT("Object", "Object", "O%s", null) {
+            String formatValue(int x) { return String.format("Integer.toString(%d)", x); }
+            String formatResult(int x) { return "O" + Integer.toString(x); }
+        },
+        STRING("String", "String", "S%s", null) {
+            String formatValue(int x) { return String.format("Integer.toString(%d)", x); }
+            String formatResult(int x) { return "S" + Integer.toString(x); }
+        };
+
+        final String typeName, boxed, format;
+        final ArgType widened;
+
+        ArgType(String typeName, String boxed, String format, ArgType widened) {
+            this.typeName = typeName;
+            this.boxed = boxed;
+            this.format = format;
+            this.widened = widened;
+        }
+
+        abstract String formatValue(int x);
+        abstract String formatResult(int x);
+
+        public String expand(String selector) {
+            return typeName;
+        }
+    }
+
+    private static enum LF { LOCAL, FIELD }
+
+    static enum CapType implements Template {
+        LOCAL_INT(ArgType.INT, LF.LOCAL),
+        LOCAL_LONG(ArgType.LONG, LF.LOCAL),
+        LOCAL_STRING(ArgType.STRING, LF.LOCAL),
+        FIELD_INT(ArgType.INT, LF.FIELD),
+        FIELD_LONG(ArgType.LONG, LF.FIELD),
+        FIELD_STRING(ArgType.STRING, LF.FIELD);
+
+        final ArgType argType;
+        final LF lf;
+
+        CapType(ArgType argType, LF lf) {
+            this.argType = argType;
+            this.lf = lf;
+        }
+
+        public String expand(String selector) {
+            return argType.typeName;
+        }
+    }
+}
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/combo-tests/tests/tools/javac/lambda/LambdaConversionTest.java	Wed Aug 14 15:53:13 2013 -0700
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  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 tools.javac.lambda;
+
+import org.testng.annotations.Factory;
+import tools.javac.combo.*;
+
+/**
+ * LambdaConversionTestCase
+ *
+ * @author Maurizio Cimadamore
+ */
+public class LambdaConversionTest extends ComboTestBase<LambdaConversionTest> {
+
+    @Factory
+    public static Object[] testCombo() throws Exception {
+        return factory(LambdaConversionTest.class);
+    }
+
+    @DimensionVar("PACKAGE")  PackageKind  samPkg;
+    @DimensionVar("MODIFIER") ModifierKind modKind;
+    @DimensionVar("CLASS")    SamKind      samKind;
+    @DimensionVar("METH")     MethodKind   meth;
+    @DimensionVar("RET")      TypeKind     retType;
+    @DimensionVar("ARG")      TypeKind     argType;
+    @DimensionVar("THROWN")   TypeKind     thrownType;
+
+    @SourceFile("Sam.java")
+    String samSource = "#{PACKAGE.PACKAGE_DECL} \n #{CLASS}";
+
+    @SourceFile("PackageClass.java")
+    String packageSource = "#{PACKAGE.PACKAGE_DECL}\n #{MODIFIER} class PackageClass extends Exception { }";
+
+    @SourceFile("Client.java")
+    String clientSource = "#{PACKAGE.IMPORT_STATEMENT}\n class Client { Sam s = x -> null; }";
+
+    @Override
+    protected void postCompile(String group) {
+        if (samKind != SamKind.INTERFACE) {
+            assertCompileFailed("SAM type must be an interface");
+        } else if (meth != MethodKind.NON_GENERIC) {
+            assertCompileFailed("target method must be non-generic");
+        } else if (samPkg != PackageKind.NO_PKG &&
+                   modKind != ModifierKind.PUBLIC &&
+                   (retType == TypeKind.PKG_CLASS
+                           || argType == TypeKind.PKG_CLASS
+                           || thrownType == TypeKind.PKG_CLASS)) {
+            assertCompileFailed("target must not contain inaccessible types");
+        } else {
+            assertCompileSucceeded();
+        }
+    }
+
+    static enum PackageKind implements Template {
+        NO_PKG(""),
+        PKG_A("a");
+
+        String pkg;
+
+        PackageKind(String pkg) {
+            this.pkg = pkg;
+        }
+
+        public String expand(String selector) {
+            if (this == NO_PKG)
+                return "";
+            switch (selector) {
+                case "PACKAGE_DECL": return String.format("package %s;", pkg);
+                case "IMPORT_STATEMENT":  return String.format("import %s.*;", pkg);
+                default: throw new IllegalArgumentException(selector);
+            }
+        }
+    }
+
+    static enum SamKind implements Template {
+        CLASS("public class Sam {  }"),
+        ABSTRACT_CLASS("public abstract class Sam {  }"),
+        ANNOTATION("public @interface Sam {  }"),
+        ENUM("public enum Sam { }"),
+        INTERFACE("public interface Sam { \n #{METH}; \n }");
+
+        String template;
+
+        SamKind(String template) { this.template = template; }
+
+        public String expand(String selector) { return template; }
+    }
+
+    static enum ModifierKind implements Template {
+        PUBLIC("public"),
+        PACKAGE("");
+
+        String template;
+
+        ModifierKind(String template) { this.template = template; }
+
+        public String expand(String selector) { return template; }
+    }
+
+    static enum TypeKind implements Template {
+        EXCEPTION("Exception"),
+        PKG_CLASS("PackageClass");
+
+        String template;
+
+        private TypeKind(String template) { this.template = template; }
+
+        public String expand(String selector) { return template; }
+    }
+
+    static enum MethodKind implements Template {
+        NONE(""),
+        NON_GENERIC("public #{RET} m(#{ARG} s) throws #{THROWN};"),
+        GENERIC("public <X> #{RET} m(#{ARG} s) throws #{THROWN};");
+
+        String template;
+
+        private MethodKind(String template) { this.template = template; }
+
+        public String expand(String selector) { return template; }
+    }
+
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/combo-tests/tests/tools/javac/lambda/LambdaExpressionTypeInferenceTest.java	Wed Aug 14 15:53:13 2013 -0700
@@ -0,0 +1,423 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  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 tools.javac.lambda;
+
+import org.testng.annotations.Factory;
+import tools.javac.combo.ComboTestBase;
+import tools.javac.combo.DimensionVar;
+import tools.javac.combo.SourceFile;
+import tools.javac.combo.Template;
+
+import static tools.javac.combo.StackProcessingUtils.*;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+/**
+ * LambdaExpressionTypeInferenceTest
+ */
+public class LambdaExpressionTypeInferenceTest extends ComboTestBase<LambdaExpressionTypeInferenceTest> {
+    @Factory
+    public static Object[] testLambdaExpressionInference() throws Exception {
+        return factory(LambdaExpressionTypeInferenceTest.class);
+    }
+
+    @DimensionVar("FORMAL_SHAPE") FormalTypeShape formalShape;
+    @DimensionVar("TREE_SHAPE") TreeShape treeShape;
+    @DimensionVar("ARG_SHAPE_1") ArgTypeShape argShape1;
+    @DimensionVar("ARG_SHAPE_2") ArgTypeShape argShape2;
+    @DimensionVar("ARG_SHAPE_3") ArgTypeShape argShape3;
+
+    @SourceFile("SAM.java")
+    String samFile = "public interface SAM<X,Y> {\n"
+            +"  Y apply(X x);\n"
+            +"}";
+
+
+    @SourceFile("Main.java")
+    String clientFile = "import java.util.*;\n"
+            +"public class Main {\n"
+            +"  <A,R> void m(#{FORMAL_SHAPE} x) { }\n"
+            +"  void test() {\n"
+            +"     m(#{TREE_SHAPE});\n"
+            +"  }\n"
+            +"}";
+
+    @Override
+    protected void postCompile(String grp) {
+        if (treeShape.compute().typeCheck(formalShape.compute(), new Type[] { argShape1.compute(), argShape2.compute(), argShape3.compute() }).isErroneous()) {
+            assertCompileFailed();
+        } else {
+            assertCompileSucceeded();
+        }
+    }
+
+    @Override
+    protected boolean shouldSkip() {
+        return argShape2.ordinal() != 0 && treeShape.depth < 2 || argShape3.ordinal() != 0 && treeShape.depth < 3;
+    }
+
+    static class Tree {
+        TreeTag treeTag;
+        Tree[] subtrees;
+
+        Tree(TreeTag treeTag, Tree... subtrees) {
+            this.treeTag = treeTag;
+            this.subtrees = subtrees;
+        }
+
+        public String toString() {
+            Object[] substrings = new Object[subtrees.length];
+            for (int i = 0; i < subtrees.length; i++) {
+                substrings[i] = subtrees[i].toString();
+            }
+            return String.format(treeTag.treeStr, substrings);
+        }
+
+        Type typeCheck(Type target, Type[] argtypes) {
+            switch (treeTag) {
+                case INT:   
+                   Type type = new Type(TypeToken.INTEGER);
+                   return type.compatibleWith(target) ? type : errType;
+                case STRING:
+                   type = new Type(TypeToken.STRING);
+                   return type.compatibleWith(target) ? type : errType;
+                case EXPR_LAMBDA:
+                    Type restype = target.getReturnType();
+                    if (restype == null) {
+                        return errType;
+                    }
+                    Type argtype = target.getArgType();
+                    int idx = subtrees[0].treeTag.argIndex();
+                    if (idx >= 0 && !argtypes[idx].compatibleWith(argtype)) {
+                        //arg type mismatch
+                        return errType;
+                    }
+                    
+                    for (int i = 1; i < subtrees.length; i++) {
+                        if (subtrees[i].typeCheck(restype, argtypes).isErroneous()) {
+                            return errType;
+                        }
+                    }
+                    return target;
+                case COND:
+                    Type typeToCheck = target;
+                    if (subtrees[0].treeTag == TreeTag.INT && subtrees[1].treeTag == TreeTag.INT) {
+                        Type owntype = new Type(TypeToken.INTEGER);
+                        return owntype.compatibleWith(target) ? owntype : errType;
+                    } else {
+                        for (int i = 0; i < subtrees.length; i++) {
+                            if (subtrees[i].typeCheck(target, argtypes).isErroneous()) {
+                                return errType;
+                            }
+                        }
+                        return target;
+                    }
+                default:
+                    throw new AssertionError();
+            }
+        }
+    }
+
+    enum TreeTag implements StackItem<TreeTag> {
+        INT("1", 0),
+        STRING("\"\"", 0),
+        COND("true ? %s : %s", 2),
+        EXPR_LAMBDA("(%s)->%s", 2),
+        IMPLICIT_1("x1", 0),
+        IMPLICIT_2("x2", 0),
+        IMPLICIT_3("x3", 0),
+        EXPLICIT_1("#{ARG_SHAPE_1} x1", 0),
+        EXPLICIT_2("#{ARG_SHAPE_2} x2", 0),
+        EXPLICIT_3("#{ARG_SHAPE_3} x3", 0);
+
+        String treeStr;
+        int arity;
+
+        TreeTag(String treeStr, int arity) {
+            this.treeStr = treeStr;
+            this.arity = arity;
+        }
+
+        public int arity() {
+            return arity;
+        }
+
+        Tree apply(Tree... args) {
+            return new Tree(this, args);
+        }
+
+        int argIndex() {
+            switch (this) {
+                case EXPLICIT_1:
+                    return 0;
+                case EXPLICIT_2:
+                    return 1;
+                case EXPLICIT_3:
+                    return 2;
+                default:
+                    return -1;
+            }
+        }
+    }
+
+    enum TreeShape implements Template, StackReducer<TreeTag, Tree, Void> {
+        LAMBDA_INT(1, TreeTag.EXPR_LAMBDA, TreeTag.EXPLICIT_1, TreeTag.INT),
+        LAMBDA_STRING(1, TreeTag.EXPR_LAMBDA, TreeTag.EXPLICIT_1, TreeTag.STRING),
+        LAMBDA_COND_INT_INT(1, TreeTag.EXPR_LAMBDA, TreeTag.EXPLICIT_1, TreeTag.COND, TreeTag.INT, TreeTag.INT),
+        IMPL_LAMBDA_INT(1, TreeTag.EXPR_LAMBDA, TreeTag.IMPLICIT_1, TreeTag.INT),
+        IMPL_LAMBDA_STRING(1, TreeTag.EXPR_LAMBDA, TreeTag.IMPLICIT_1, TreeTag.STRING),
+        IMPL_LAMBDA_COND_INT_INT(1, TreeTag.EXPR_LAMBDA, TreeTag.IMPLICIT_1, TreeTag.COND, TreeTag.INT, TreeTag.INT),
+        LAMBDA_LAMBDA_INT(2, TreeTag.EXPR_LAMBDA, TreeTag.EXPLICIT_1, TreeTag.EXPR_LAMBDA, TreeTag.EXPLICIT_2, TreeTag.INT),
+        LAMBDA_LAMBDA_STRING(2, TreeTag.EXPR_LAMBDA, TreeTag.EXPLICIT_1, TreeTag.EXPR_LAMBDA, TreeTag.EXPLICIT_2, TreeTag.STRING),
+        LAMBDA_LAMBDA_COND_INT_INT(2, TreeTag.EXPR_LAMBDA, TreeTag.EXPLICIT_1, TreeTag.EXPR_LAMBDA, TreeTag.EXPLICIT_2, TreeTag.COND, TreeTag.INT, TreeTag.INT),
+        LAMBDA_IMPL_LAMBDA_INT(2, TreeTag.EXPR_LAMBDA, TreeTag.EXPLICIT_1, TreeTag.EXPR_LAMBDA, TreeTag.IMPLICIT_2, TreeTag.INT),
+        LAMBDA_IMPL_LAMBDA_STRING(2, TreeTag.EXPR_LAMBDA, TreeTag.EXPLICIT_1, TreeTag.EXPR_LAMBDA, TreeTag.IMPLICIT_2, TreeTag.STRING),
+        LAMBDA_IMPL_LAMBDA_COND_INT_INT(2, TreeTag.EXPR_LAMBDA, TreeTag.EXPLICIT_1, TreeTag.EXPR_LAMBDA, TreeTag.IMPLICIT_2, TreeTag.COND, TreeTag.INT, TreeTag.INT),
+        LAMBDA_COND_LAMBDA_INT_INT(2, TreeTag.EXPR_LAMBDA, TreeTag.EXPLICIT_1, TreeTag.COND, TreeTag.EXPR_LAMBDA, TreeTag.EXPLICIT_2, TreeTag.INT, TreeTag.INT),
+        LAMBDA_COND_LAMBDA_STRING_INT(2, TreeTag.EXPR_LAMBDA, TreeTag.EXPLICIT_1, TreeTag.COND, TreeTag.EXPR_LAMBDA, TreeTag.EXPLICIT_2, TreeTag.STRING, TreeTag.INT),
+        LAMBDA_COND_LAMBDA_COND_INT_INT_INT(2, TreeTag.EXPR_LAMBDA, TreeTag.EXPLICIT_1, TreeTag.COND, TreeTag.EXPR_LAMBDA, TreeTag.EXPLICIT_2, TreeTag.COND, TreeTag.INT, TreeTag.INT, TreeTag.INT),
+        LAMBDA_COND_IMPL_LAMBDA_INT_INT(2, TreeTag.EXPR_LAMBDA, TreeTag.EXPLICIT_1, TreeTag.COND, TreeTag.EXPR_LAMBDA, TreeTag.IMPLICIT_2, TreeTag.INT, TreeTag.INT),
+        LAMBDA_COND_IMPL_LAMBDA_STRING_INT(2, TreeTag.EXPR_LAMBDA, TreeTag.EXPLICIT_1, TreeTag.COND, TreeTag.EXPR_LAMBDA, TreeTag.IMPLICIT_2, TreeTag.STRING, TreeTag.INT),
+        LAMBDA_COND_IMPL_LAMBDA_COND_INT_INT_INT(2, TreeTag.EXPR_LAMBDA, TreeTag.EXPLICIT_1, TreeTag.COND, TreeTag.EXPR_LAMBDA, TreeTag.IMPLICIT_2, TreeTag.COND, TreeTag.INT, TreeTag.INT, TreeTag.INT),
+        LAMBDA_LAMBDA_LAMBDA_INT(3, TreeTag.EXPR_LAMBDA, TreeTag.EXPLICIT_1, TreeTag.EXPR_LAMBDA, TreeTag.EXPLICIT_2, TreeTag.EXPR_LAMBDA, TreeTag.EXPLICIT_3, TreeTag.INT),
+        LAMBDA_LAMBDA_LAMBDA_STRING(3, TreeTag.EXPR_LAMBDA, TreeTag.EXPLICIT_1, TreeTag.EXPR_LAMBDA, TreeTag.EXPLICIT_2, TreeTag.EXPR_LAMBDA, TreeTag.EXPLICIT_3, TreeTag.STRING),
+        LAMBDA_LAMBDA_LAMBDA_COND_INT_INT(3, TreeTag.EXPR_LAMBDA, TreeTag.EXPLICIT_1, TreeTag.EXPR_LAMBDA, TreeTag.EXPLICIT_2, TreeTag.EXPR_LAMBDA, TreeTag.EXPLICIT_3, TreeTag.COND, TreeTag.INT, TreeTag.INT),
+        LAMBDA_LAMBDA_IMPL_LAMBDA_INT(3, TreeTag.EXPR_LAMBDA, TreeTag.EXPLICIT_1, TreeTag.EXPR_LAMBDA, TreeTag.EXPLICIT_2, TreeTag.EXPR_LAMBDA, TreeTag.IMPLICIT_3, TreeTag.INT),
+        LAMBDA_LAMBDA_IMPL_LAMBDA_STRING(3, TreeTag.EXPR_LAMBDA, TreeTag.EXPLICIT_1, TreeTag.EXPR_LAMBDA, TreeTag.EXPLICIT_2, TreeTag.EXPR_LAMBDA, TreeTag.IMPLICIT_3, TreeTag.STRING),
+        LAMBDA_LAMBDA_IMPL_LAMBDA_COND_INT_INT(3, TreeTag.EXPR_LAMBDA, TreeTag.EXPLICIT_1, TreeTag.EXPR_LAMBDA, TreeTag.EXPLICIT_2, TreeTag.EXPR_LAMBDA, TreeTag.IMPLICIT_3, TreeTag.COND, TreeTag.INT, TreeTag.INT);
+
+        TreeTag[] treeTags;
+        int depth;
+
+        TreeShape(int depth, TreeTag... treeTags) {
+            this.depth = depth;
+            this.treeTags = treeTags;
+        }
+
+        Tree compute() {
+            return process(treeTags, this, null);
+        }
+
+        public String expand(String selector) {
+            return compute().toString();
+        }
+
+        public Tree reduce(TreeTag tag, Tree[] args, Void _unused) {
+            return new Tree(tag, args);
+        }
+
+        public Void reducerArg(TreeTag item, int i) { return null; }
+
+        public Class<Tree> resultToken() {
+            return Tree.class;
+        }
+    }
+
+    static class Type {
+        TypeToken typeToken;
+        Type[] typeargs;
+
+        Type(TypeToken typeToken, Type... typeargs) {
+            this.typeToken = typeToken;
+            this.typeargs = typeargs;
+        }
+
+        public String toString() {
+            Object[] typeargStrings = new Object[typeargs.length];
+            for (int i = 0; i < typeargs.length; i++) {
+                typeargStrings[i] = typeargs[i].toString();
+            }
+            return String.format(typeToken.tokenStr, typeargStrings);
+        }
+
+        boolean isErroneous() { return false; }
+
+        Type getReturnType() {
+            return typeToken == TypeToken.SAM ?
+                typeargs[1] : null;
+        }
+
+        Type getArgType() {
+            return typeToken == TypeToken.SAM ?
+                typeargs[0] : null;
+        }
+
+        boolean isFree() {
+            switch (typeToken) {
+                case A:
+                case R:
+                    return true;
+                default:
+                    for (Type t : typeargs) {
+                        if (t.isFree()) return true;
+                    }
+                    return false;    
+            }
+        }
+
+        boolean isFreeVar() {
+            switch (typeToken) {
+                case A:
+                case R:
+                    return true;
+                default:                    
+                    return false;    
+            }
+        }
+
+        boolean compatibleWith(Type that) {
+            if (that.isFreeVar()) {
+                return true;
+            } else {
+                if (typeToken != that.typeToken)
+                    return false;
+                if (typeargs.length != that.typeargs.length) {
+                    return false;
+                }
+                for (int i = 0; i < typeargs.length ; i++) {
+                    if (!typeargs[i].compatibleWith(that.typeargs[i]))
+                        return false;
+                }
+                return true;
+            }
+        }
+    }
+
+    static Type errType = new Type(null) {
+        boolean isErroneous() {
+            return true;
+        }
+    };
+
+    enum TypeToken implements StackItem<TypeToken> {
+        STRING("String", 0),
+        INTEGER("Integer", 0),
+        A("A", 0),
+        R("R", 0),
+        LIST("List<%s>", 1),
+        SAM("SAM<%s,%s>", 2);
+
+        int arity;
+        String tokenStr;
+
+        TypeToken(String tokenStr, int arity) {
+            this.tokenStr = tokenStr;
+            this.arity = arity;
+        }
+
+        public int arity() {
+            return arity;
+        }
+    }
+
+    enum ArgTypeShape implements Template, StackReducer<TypeToken, Type, Void> {
+        STRING(TypeToken.STRING),
+        INTEGER(TypeToken.INTEGER),
+        LIST_STRING(TypeToken.LIST, TypeToken.STRING),
+        LIST_INTEGER(TypeToken.LIST, TypeToken.INTEGER);
+
+        TypeToken[] tokens;
+
+        ArgTypeShape(TypeToken... tokens) {
+            this.tokens = tokens;
+        }
+
+        Type compute() {
+            return process(tokens, this, null);
+        }
+
+        public String expand(String selector) {
+            return compute().toString();
+        }
+
+        public Type reduce(TypeToken token, Type[] args, Void _unused) {
+            return new Type(token, args);
+        }
+
+        public Void reducerArg(TypeToken item, int i) { return null; }
+
+        public Class<Type> resultToken() {
+            return Type.class;
+        }
+    }
+
+    enum FormalTypeShape implements Template, StackReducer<TypeToken, Type, Void> {
+        SAM_String_String(TypeToken.SAM, TypeToken.STRING, TypeToken.STRING),
+        SAM_Integer_String(TypeToken.SAM, TypeToken.INTEGER, TypeToken.STRING),
+        SAM_List_String_String(TypeToken.SAM, TypeToken.LIST, TypeToken.STRING, TypeToken.STRING),
+        SAM_List_Integer_String(TypeToken.SAM, TypeToken.LIST, TypeToken.INTEGER, TypeToken.STRING),
+        SAM_A_String(TypeToken.SAM, TypeToken.A, TypeToken.STRING),
+        SAM_List_A_String(TypeToken.SAM, TypeToken.LIST, TypeToken.A, TypeToken.STRING),
+        SAM_String_R(TypeToken.SAM, TypeToken.STRING, TypeToken.R),
+        SAM_A_R(TypeToken.SAM, TypeToken.A, TypeToken.R),
+        SAM_List_A_R(TypeToken.SAM, TypeToken.LIST, TypeToken.A, TypeToken.R),
+        SAM_String_SAM_String_String(TypeToken.SAM, TypeToken.STRING, TypeToken.SAM, TypeToken.STRING, TypeToken.STRING),
+        SAM_String_SAM_Integer_String(TypeToken.SAM, TypeToken.STRING, TypeToken.SAM, TypeToken.INTEGER, TypeToken.STRING),
+        SAM_String_SAM_List_String_String(TypeToken.SAM, TypeToken.STRING, TypeToken.SAM, TypeToken.LIST, TypeToken.STRING, TypeToken.STRING),
+        SAM_String_SAM_List_Integer_String(TypeToken.SAM, TypeToken.STRING, TypeToken.SAM, TypeToken.LIST, TypeToken.INTEGER, TypeToken.STRING),
+        SAM_String_SAM_A_String(TypeToken.SAM, TypeToken.STRING, TypeToken.SAM, TypeToken.A, TypeToken.STRING),
+        SAM_String_SAM_List_A_String(TypeToken.SAM, TypeToken.STRING, TypeToken.SAM, TypeToken.LIST, TypeToken.A, TypeToken.STRING),
+        SAM_String_SAM_String_R(TypeToken.SAM, TypeToken.STRING, TypeToken.SAM, TypeToken.STRING, TypeToken.R),
+        SAM_String_SAM_A_R(TypeToken.SAM, TypeToken.STRING, TypeToken.SAM, TypeToken.A, TypeToken.R),
+        SAM_String_SAM_List_A_R(TypeToken.SAM, TypeToken.STRING, TypeToken.SAM, TypeToken.LIST, TypeToken.A, TypeToken.R),
+        SAM_A_SAM_String_String(TypeToken.SAM, TypeToken.A, TypeToken.SAM, TypeToken.STRING, TypeToken.STRING),
+        SAM_String_SAM_String_SAM_String_String(TypeToken.SAM, TypeToken.STRING, TypeToken.SAM, TypeToken.STRING, TypeToken.SAM, TypeToken.STRING, TypeToken.STRING),
+        SAM_String_SAM_String_SAM_Integer_String(TypeToken.SAM, TypeToken.STRING, TypeToken.SAM, TypeToken.STRING, TypeToken.SAM, TypeToken.INTEGER, TypeToken.STRING),
+        SAM_String_SAM_String_SAM_List_String_String(TypeToken.SAM, TypeToken.STRING, TypeToken.SAM, TypeToken.STRING, TypeToken.SAM, TypeToken.LIST, TypeToken.STRING, TypeToken.STRING),
+        SAM_String_SAM_String_SAM_List_Integer_String(TypeToken.SAM, TypeToken.STRING, TypeToken.SAM, TypeToken.STRING, TypeToken.SAM, TypeToken.LIST, TypeToken.INTEGER, TypeToken.STRING),
+        SAM_String_SAM_String_SAM_A_String(TypeToken.SAM, TypeToken.STRING, TypeToken.SAM, TypeToken.STRING, TypeToken.SAM, TypeToken.A, TypeToken.STRING),
+        SAM_String_SAM_String_SAM_List_A_String(TypeToken.SAM, TypeToken.STRING, TypeToken.SAM, TypeToken.STRING, TypeToken.SAM, TypeToken.LIST, TypeToken.A, TypeToken.STRING),
+        SAM_String_SAM_String_SAM_String_R(TypeToken.SAM, TypeToken.STRING, TypeToken.SAM, TypeToken.STRING, TypeToken.SAM, TypeToken.STRING, TypeToken.R),
+        SAM_String_SAM_String_SAM_A_R(TypeToken.SAM, TypeToken.STRING, TypeToken.SAM, TypeToken.STRING, TypeToken.SAM, TypeToken.A, TypeToken.R),
+        SAM_String_SAM_String_SAM_List_A_R(TypeToken.SAM, TypeToken.STRING, TypeToken.SAM, TypeToken.STRING, TypeToken.SAM, TypeToken.LIST, TypeToken.A, TypeToken.R),
+        SAM_String_SAM_A_SAM_String_String(TypeToken.SAM, TypeToken.STRING, TypeToken.SAM, TypeToken.A, TypeToken.SAM, TypeToken.STRING, TypeToken.STRING),
+        SAM_String_SAM_A_SAM_String_R(TypeToken.SAM, TypeToken.STRING, TypeToken.SAM, TypeToken.A, TypeToken.SAM, TypeToken.STRING, TypeToken.R);
+
+        TypeToken[] tokens;
+
+        FormalTypeShape(TypeToken... tokens) {
+            this.tokens = tokens;
+        }
+
+        Type compute() {
+            return process(tokens, this, null);
+        }
+
+        public String expand(String selector) {
+            return compute().toString();
+        }
+
+        public Type reduce(TypeToken token, Type[] args, Void _unused) {
+            return new Type(token, args);
+        }
+
+        public Void reducerArg(TypeToken item, int i) { return null; }
+
+        public Class<Type> resultToken() {
+            return Type.class;
+        }
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/combo-tests/tests/tools/javac/lambda/LambdaReturnAdaptationTest.java	Wed Aug 14 15:53:13 2013 -0700
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  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 tools.javac.lambda;
+
+import org.testng.annotations.Factory;
+import tools.javac.combo.*;
+
+import java.lang.reflect.Method;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+/**
+ * LambaReturnAdaptationTest
+ */
+public class LambdaReturnAdaptationTest extends ComboTestBase<LambdaReturnAdaptationTest> {
+    @Factory
+    public static Object[] testReturnAdaptation() throws Exception {
+        return factory(LambdaReturnAdaptationTest.class);
+    }
+
+    @DimensionVar("FROM") Types fromType;
+    @DimensionVar("TO") Types toType;
+
+    @SourceFile("Sam.java")
+    String samFile = "public interface Sam { #{TO} m(int arg); }";
+
+    @SourceFile("Main.java")
+    String clientFile = "public class Main {\n"
+                        +"  static #{FROM} m(int arg) { \n"
+                        +"    #{RET};\n"
+                        +"  }\n"
+                        +"  public #{TO} main() { \n"
+                        + "   Sam s = Main::m;\n"
+                        + "   #{RET_MAIN};\n"
+                        + " }\n"
+                        +"}";
+
+    @TemplateVar("RET")
+    Template retTemplate = new Template() {
+        public String expand(String selector) {
+            if (fromType == Types.VOID)
+                return "";
+            else if (fromType == Types.STRING)
+                return "return \"66\"";
+            else if (fromType == Types.BOOLEAN || fromType == Types.BOXED_BOOLEAN)
+                return "return true";
+            else if (fromType.unboxed != null)
+                return "return (" + fromType.unboxed.name + ") arg";
+            else
+                return "return (" + fromType.name + ") arg";
+        }
+    };
+
+    @TemplateVar("RET_MAIN")
+    Template retMainTemplate = new Template() {
+        public String expand(String selector) {
+            return toType == Types.VOID ? "s.m(66)" : "return s.m(66)";
+        }
+    };
+
+    @Override
+    protected String[] getCompileOptions(String group) {
+        return new String[] { "-XDlambdaToMethod" };
+    }
+
+    @Override
+    protected void postCompile(String group) {
+        if (fromType != Types.VOID && toType == Types.VOID)
+            assertCompileSucceeded();
+        else if (fromType == Types.VOID && toType != Types.VOID)
+            assertCompileFailed();
+        else if (fromType == Types.VOID && toType == Types.VOID)
+            assertCompileSucceeded();
+        else if (fromType.pr == PR.REF && toType.pr == PR.REF)
+            assertCompileSucceededIff(toType.clazz.isAssignableFrom(fromType.clazz));
+        else if (fromType.pr == PR.PRIM && toType.pr == PR.REF)
+            assertCompileSucceededIff(toType.clazz.isAssignableFrom(Types.boxMap.get(fromType).clazz));
+        else if (fromType.pr == PR.REF && toType.pr == PR.PRIM)
+            assertCompileSucceededIff(fromType.unboxed != null && Types.widenMap.get(fromType.unboxed).contains(toType));
+        else if (fromType.pr == PR.PRIM && toType.pr == PR.PRIM)
+            assertCompileSucceededIff(Types.widenMap.get(fromType).contains(toType));
+        else
+            assertCompileSucceeded();
+    }
+
+    @Override
+    protected boolean shouldRun() { return true; }
+
+    @Override
+    protected void run(Class<?> clazz) throws ReflectiveOperationException {
+        Method m = clazz.getMethod("main");
+        Object obj = clazz.newInstance();
+        Object in = 66;
+        Object out = m.invoke(obj);
+        if (toType == Types.VOID)
+            assertTrue(out == null);
+        else if (fromType == Types.BOOLEAN || fromType == Types.BOXED_BOOLEAN)
+            assertEquals("true", out.toString());
+        else
+            assertEquals(in.toString(), out.toString().replace("B", "66").replace(".0", ""));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/combo-tests/tests/tools/javac/lambda/MethodRefCaptureTest.java	Wed Aug 14 15:53:13 2013 -0700
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  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 tools.javac.lambda;
+
+import org.testng.annotations.Factory;
+import tools.javac.combo.*;
+
+/**
+ * MethodRefCaptureTest
+ *
+ * @author Brian Goetz
+ */
+public class MethodRefCaptureTest extends ComboTestBase<MethodRefCaptureTest> {
+    @Factory
+    public static Object[] testCombo() throws Exception {
+        return factory(MethodRefCaptureTest.class);
+    }
+
+    @DimensionVar("VAR") ContextKind context;
+    @DimensionVar("LOCATION") LocationKind location;
+    @DimensionVar("ACC") AccessibilityKind accessibility;
+    @DimensionVar("METHOD") RefKind ref;
+
+    @TemplateVar("PACKAGE")
+    String makePackage() {
+        return location == LocationKind.OTHER_PACKAGE ? "package a;" : "";
+    }
+
+    // @@@ not yet used
+    @TemplateVar("MAIN") String main = "public static void main(String[] args) { #{METHOD.SAMTYPE} x = #{VAR.REF}";
+
+    @SourceFile("Sam1.java") String sam1 = "#{PACKAGE} \npublic interface Sam1 { public String get(String s); }";
+    @SourceFile("Sam2.java") String sam2 = "#{PACKAGE} \npublic interface Sam2<T> { public String get(T target, String s); }";
+    @SourceFile("Sam3.java") String sam3 = "#{PACKAGE} \npublic interface Sam3<T> { public T get(String s); }";
+    @SourceFile("A.java") String mainFile = "#{LOCATION.CAPTURING_CLASS}";
+    @SourceFile("Target.java") String extFile = "#{LOCATION.EXT_CLASS}";
+
+    @Override
+    protected String[] getCompileOptions(String group) {
+        return new String[] { "-XDlambdaToMethod" };
+    }
+
+    @Override
+    protected void postCompile(String group) {
+        if (location == LocationKind.OTHER_FILE && accessibility == AccessibilityKind.PRIVATE)
+            assertCompileFailed();
+        else if (location == LocationKind.OTHER_PACKAGE && accessibility != AccessibilityKind.PUBLIC)
+            assertCompileFailed();
+        else
+            assertCompileSucceeded();
+    }
+
+
+    static enum ContextKind implements Template {
+        STATIC_FIELD_INIT("static #{METHOD.SAMTYPE} var = #{METHOD.MREF};"),
+        STATIC_FIELD_CLINIT("static #{METHOD.SAMTYPE} var; static { var = #{METHOD.MREF}; };"),
+        INSTANCE_FIELD_INIT("#{METHOD.SAMTYPE} var = #{METHOD.MREF};"),
+        LOCAL_VAR("void m() { #{METHOD.SAMTYPE} var = #{METHOD.MREF}; };"),
+        METHOD_CALL("static void m(#{METHOD.SAMTYPE} s) { }; static void m() { m(#{METHOD.MREF}); };"),
+        RETURN("#{METHOD.SAMTYPE} m() { return #{METHOD.MREF}; };"),
+        ARRAY_INITIALIZER("#{METHOD.SAMTYPE}[] var = (#{METHOD.SAMTYPE}[]) new #{METHOD.ERASED_SAMTYPE}[] { (#{METHOD.SAMTYPE}) #{METHOD.MREF} };"),
+        CONDITIONAL("#{METHOD.SAMTYPE} var = new Object().equals(new Object()) ? #{METHOD.MREF} : #{METHOD.MREF};"),
+        CAST("#{METHOD.SAMTYPE} var = (#{METHOD.SAMTYPE}) #{METHOD.MREF};");
+
+        private final String t1;
+
+        ContextKind(String t1) { this.t1 = t1; }
+
+        public String expand(String selector) {
+            switch (selector) {
+                case "DECL": return t1;
+                default:     throw new IllegalArgumentException(selector);
+            }
+        }
+    }
+
+    static enum LocationKind implements Template {
+        SAME_CLASS("class Target { \n#{VAR.DECL} \n#{METHOD.DECL} }"),
+        ENCLOSING_CLASS("class Target { \n#{METHOD.DECL} \nstatic class Capturing { #{VAR.DECL} } }"),
+        SIBLING_INNER_CLASS("class Outer { \nstatic class Capturing { #{VAR.DECL} }  \nstatic class Target { #{METHOD.DECL} } }"),
+        NESTED_CLASS("class Capturing { \n#{VAR.DECL} \nstatic class Target { #{METHOD.DECL} } }"),
+        OTHER_FILE("class Capturing { \n#{VAR.DECL} }", "class Target { \n#{METHOD.DECL} }"),
+        OTHER_PACKAGE("package a; \nimport b.*; \nclass Capturing { \n#{VAR.DECL} }",
+                      "package b; \npublic class Target { \n#{METHOD.DECL} }");
+
+        private final String t1, t2;
+
+        LocationKind(String t1, String t2) {
+            this.t1 = t1;
+            this.t2 = t2;
+        }
+        LocationKind(String t1) { this(t1, "class Unused {}"); }
+
+        public String expand(String selector) {
+            switch (selector) {
+                case "CAPTURING_CLASS": return t1;
+                case "EXT_CLASS":       return t2;
+                default:                throw new IllegalArgumentException(selector);
+            }
+        }
+    }
+
+    static enum AccessibilityKind implements Template {
+        PUBLIC("public"),
+        PROTECTED("protected"),
+        PACKAGE(""),
+        PRIVATE("private");
+
+        private final String template;
+
+        AccessibilityKind(String template) { this.template = template; }
+
+        public String expand(String selector) { return template; }
+    }
+
+    static enum RefKind implements Template {
+        STATIC(0, "Target::staticMethod", "static #{ACC} String staticMethod(String s) { return \"1\"; }"),
+        UNBOUND_INSTANCE(1, "Target::instanceMethod", "#{ACC} String instanceMethod(String s) { return \"2\"; }"),
+        BOUND_INSTANCE(0, "(new Target())::instanceMethod", "#{ACC} String instanceMethod(String s) { return \"3\"; }"),
+        CTOR(2, "Target::new", "#{ACC} Target(String s) { }"),
+//    UNBOUND_INNER_CTOR,
+//    BOUND_INNER_CTOR
+//    , SUPER
+        ;
+
+        private static final String[] sams = { "Sam1", "Sam2<Target>", "Sam3<Target>" };
+        private final int samNo;
+        private final String t1, t2;
+
+        RefKind(int samNo, String t1, String t2) { this.samNo = samNo; this.t1 = t1; this.t2 = t2; }
+
+        public String expand(String selector) {
+            switch (selector) {
+                case "MREF": return t1;
+                case "DECL": return t2;
+                case "SAMTYPE": return sams[samNo];
+                case "ERASED_SAMTYPE": return sams[samNo].replaceAll("<Target>", "<?>");
+                default:   throw new IllegalArgumentException(selector);
+            }
+        }
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/combo-tests/tests/tools/javac/lambda/NestedGenericMethodCallTest.java	Wed Aug 14 15:53:13 2013 -0700
@@ -0,0 +1,410 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  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 tools.javac.lambda;
+
+import org.testng.annotations.Factory;
+import org.testng.annotations.Test;
+import tools.javac.combo.ComboTestBase;
+import tools.javac.combo.DimensionVar;
+import tools.javac.combo.SourceFile;
+import tools.javac.combo.Template;
+
+import static tools.javac.combo.StackProcessingUtils.*;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+/**
+ * NestedGenericMethodCallTest
+ */
+public class NestedGenericMethodCallTest extends ComboTestBase<NestedGenericMethodCallTest> {
+    @Factory
+    public static Object[] testNestedGenericMethodCallType() throws Exception {
+        return factory(NestedGenericMethodCallTest.class);
+    }
+
+    @Test(enabled=false)
+    public void test() throws Exception {
+        //disabled as the test has never been updated to support graph inference
+        super.test();
+    }
+
+    @DimensionVar("ID_METHOD") IdMethod idMethod;
+    @DimensionVar("NIL_METHOD") NilMethod nilMethod;
+    @DimensionVar("CONS_METHOD") ConsMethod consMethod;
+    @DimensionVar("SHAPE") Shape shape;
+    @DimensionVar("TARGET") Type target;
+
+    @SourceFile("Main.java")
+    String clientFile = "import java.util.*;\n"
+            +"public class Main {\n"
+            +"  #{ID_METHOD}\n"
+            +"  #{NIL_METHOD}\n"
+            +"  #{CONS_METHOD}\n"
+            +"  void test() { \n"
+            + "   #{TARGET} t = #{SHAPE};\n"
+            + " }\n"
+            +"}";
+
+    @Override
+    protected void postCompile(String grp) {
+        Type res = shape.compile(idMethod, nilMethod, consMethod, target);
+        if (res.asSubtypeOf(target).isError()) {
+            assertCompileFailed("Bad result = " + res);
+        } else {
+            assertCompileSucceeded();
+        }
+    }
+
+    @Override
+    protected boolean shouldSkip() {
+        return target.free || target == Type.ERROR;
+    }
+
+    enum Type implements Template {
+        Z("Z", true),
+        OBJECT("Object", false),
+        STRING("String", false),
+        LIST_Z("List<Z>", true),
+        LIST_OBJECT("List<Object>", false),
+        LIST_STRING("List<String>", false),
+        ERROR("<any>", false);
+
+        String typeStr;
+        boolean free;
+
+        Type(String typeStr, boolean free) {
+            this.typeStr = typeStr;
+            this.free = free;
+        }
+
+        boolean isError() {
+            return this == ERROR;
+        }
+
+        Type asSubtypeOf(Type that) {
+            return asSubtypeMap[this.ordinal()][that.ordinal()];
+        }
+ 
+        boolean isSubtypeOf(Type that) {
+            return !asSubtypeOf(that).isError();
+        }
+
+        public String expand(String selector) {
+            return typeStr;
+        }
+
+        enum ConstraintKind {
+            Z_EXT_OBJ(false, OBJECT),
+            Z_EXT_STRING(false, STRING),
+            Z_EXT_LIST_OBJECT(false, LIST_OBJECT),
+            Z_EXT_LIST_STRING(false, STRING),
+            Z_SUP_OBJECT(true, OBJECT),
+            Z_SUP_STRING(true, STRING),
+            Z_SUP_LIST_OBJECT(true, LIST_OBJECT),
+            Z_SUP_LIST_STRING(true, LIST_STRING),
+            ERROR(false, Type.ERROR);
+
+            boolean isSuper;
+            Type type;
+
+            ConstraintKind(boolean isSuper, Type type) {
+                this.isSuper = isSuper;
+                this.type = type;
+            }
+        }
+
+        static Type[][] asSubtypeMap = new Type[][] {
+                //                   Z           OBJECT      STRING       LIST_Z      LIST_OBJECT      LIST_STRING        ERROR
+                { /* Z           */  OBJECT     ,OBJECT     ,STRING      ,ERROR      ,LIST_OBJECT     ,LIST_STRING       ,ERROR        },
+                { /* OBJECT      */  OBJECT     ,OBJECT     ,ERROR       ,ERROR      ,ERROR           ,ERROR             ,ERROR        },
+                { /* STRING      */  STRING     ,STRING     ,STRING      ,ERROR      ,ERROR           ,ERROR             ,ERROR        },
+                { /* LIST_Z      */  LIST_OBJECT,LIST_OBJECT,ERROR       ,LIST_OBJECT,LIST_OBJECT     ,LIST_STRING       ,ERROR        },
+                { /* LIST_OBJECT */  LIST_OBJECT,LIST_OBJECT,ERROR       ,LIST_OBJECT,LIST_OBJECT     ,ERROR             ,ERROR        },
+                { /* LIST_STRING */  LIST_STRING,LIST_STRING,ERROR       ,LIST_STRING,ERROR           ,LIST_STRING       ,ERROR        },
+                { /* ERROR       */  ERROR      ,ERROR      ,ERROR       ,ERROR      ,ERROR           ,ERROR             ,ERROR        }};
+
+        static boolean isSubtypes(Type[] ts1, Type[] ts2) {
+            assertEquals(ts1.length, ts2.length);
+            for (int i = 0; i < ts1.length ; i++) {
+                if (!ts1[i].isSubtypeOf(ts2[i])) return false;
+            }
+            return true;
+        }
+
+        static Type listOf(Type t) {
+            switch (t) {
+                case OBJECT: return LIST_OBJECT;
+                case STRING: return LIST_STRING;
+                case Z: return LIST_Z;              
+                default: return ERROR;
+            }
+        }
+
+        static Type elemtype(Type t) {
+            switch (t) {
+                case LIST_OBJECT: return OBJECT;
+                case LIST_STRING: return STRING;
+                case LIST_Z: return Z;
+                default: return ERROR;
+            }
+        }   
+
+        static Type lub(Type t1, Type t2) {
+            if (!t1.asSubtypeOf(t2).isError()) {
+                return t2;
+            } else if (!t2.asSubtypeOf(t1).isError()) {
+                return t1;
+            } else {
+                return Type.ERROR;
+            }
+        }
+    }
+
+    interface MethodSig {
+        Type apply(Type target, Type... argTypes);
+        Type[] getFormals();
+    }
+
+    enum IdMethod implements Template, MethodSig {
+        NON_GENERIC_1("String id(String s) { return null; };", Type.STRING),
+        NON_GENERIC_2("List<String> id(List<String> s) { return null; };", Type.LIST_STRING),
+        GENERIC_1("<Z> Z id(Z z) { return null; };", Type.Z),
+        GENERIC_2("<Z> List<Z> id(List<Z> z) { return null; };", Type.LIST_Z);
+
+        String sig;
+        Type formal;
+
+        IdMethod(String sig, Type formal) {
+            this.sig = sig;
+            this.formal = formal;
+        }
+
+        public String expand(String selector) {
+            return sig;
+        }
+
+        public Type apply(Type target, Type... argTypes) {
+            return argTypes[0].asSubtypeOf(formal);
+        }
+
+        public Type[] getFormals() {
+            return new Type[] { formal };
+        }
+    }
+
+    enum NilMethod implements Template, MethodSig {
+        NON_GENERIC("List<String> nil() { return null; }", Type.LIST_STRING),
+        GENERIC("<Z> List<Z> nil() { return null; }", Type.LIST_Z);
+
+        String sig;
+        Type returnType;
+
+        NilMethod(String sig, Type returnType) {
+            this.sig = sig;
+            this.returnType = returnType;
+        }
+
+        public String expand(String selector) {
+            return sig;
+        }
+
+        public Type apply(Type target, Type... argTypes) {            
+            return this == NON_GENERIC ?
+                Type.LIST_STRING :
+                returnType.asSubtypeOf(target);
+        }
+
+        public Type[] getFormals() {
+            return null;
+        }
+    }
+
+    enum ConsMethod implements Template, MethodSig {
+        NON_GENERIC("List<String> cons(String s, List<String> ls) { return null; }", Type.STRING, Type.LIST_STRING) {
+            Type getReturnType(Type target, Type... argTypes) { return Type.LIST_STRING; }
+        },
+        GENERIC_1("<Z> List<Z> cons(Z z, List<String> ls) { return null; }", Type.Z, Type.LIST_STRING) {
+            Type getReturnType(Type target, Type... argTypes) { 
+                 switch (target) {
+                     case LIST_OBJECT:
+                     case LIST_STRING:
+                        return Type.LIST_Z.asSubtypeOf(target);
+                     default:
+                        return Type.listOf(argTypes[0].asSubtypeOf(Type.Z));
+                 }
+            }
+        },
+        GENERIC_2("<Z> List<Z> cons(String s, List<Z> lz) { return null; }", Type.STRING, Type.LIST_Z) {
+            Type getReturnType(Type target, Type... argTypes) { return Type.listOf(Type.elemtype(argTypes[1].asSubtypeOf(Type.LIST_Z))); }
+        },
+        GENERIC_3("<Z> List<Z> cons(Z z, List<Z> lz) { return null; }", Type.Z, Type.LIST_Z) {
+            Type getReturnType(Type target, Type... argTypes) {
+                Type lub = Type.lub(argTypes[0], Type.elemtype(argTypes[1].asSubtypeOf(Type.LIST_Z)));
+                return lub.isError() ? lub : Type.listOf(lub);
+            }
+        },
+        GENERIC_4("<U, V> List<U> cons(U z, List<V> lz) { return null; }", Type.Z, Type.LIST_Z) {
+            Type getReturnType(Type target, Type... argTypes) { 
+                switch (target) {
+                    case LIST_OBJECT:
+                    case LIST_STRING:
+                        return Type.LIST_Z.asSubtypeOf(target);
+                    default:
+                        return Type.listOf(argTypes[0].asSubtypeOf(Type.Z));
+                }
+            }
+        };
+
+        String sig;
+        Type[] formals;
+
+        ConsMethod(String sig, Type... formals) {
+            this.sig = sig;
+            this.formals = formals;
+        }
+
+        public String expand(String selector) {
+            return sig;
+        }
+
+        public Type apply(Type target, Type... argTypes) {
+            return Type.isSubtypes(argTypes, formals) ?
+                    getReturnType(target, argTypes) : Type.ERROR;
+        }
+
+        abstract Type getReturnType(Type target, Type... argTypes);
+
+        public Type[] getFormals() {
+            return formals;
+        }
+    }
+
+    enum Token implements StackItem<Token> {
+        NIL(0, "nil"),
+        DIAMOND(0, "new ArrayList<>"),
+        STRING(0, "\"\""),
+        ID(1, "id"),
+        CONS(2, "cons");
+
+        int arity;
+        String tokenStr;
+
+        Token(int arity, String tokenStr) {
+            this.arity = arity;
+            this.tokenStr = tokenStr;
+        }
+
+        public int arity() { return arity; }
+    }
+
+    enum Shape implements Template {
+        NIL(Token.NIL),
+        ID_NIL(Token.ID, Token.NIL),
+        ID_ID_NIL(Token.ID, Token.ID, Token.NIL),
+        CONS_STRING_NIL(Token.CONS, Token.STRING, Token.NIL),
+        CONS_STRING_ID_NIL(Token.CONS, Token.STRING, Token.ID, Token.NIL),
+        CONS_ID_STRING_NIL(Token.CONS, Token.ID, Token.STRING, Token.NIL),
+        CONS_ID_STRING_ID_NIL(Token.CONS, Token.ID, Token.STRING, Token.ID, Token.NIL),
+        CONS_ID_STRING_CONS_STRING_NIL(Token.CONS, Token.ID, Token.STRING, Token.CONS, Token.STRING, Token.NIL),
+        CONS_ID_STRING_CONS_ID_STRING_NIL(Token.CONS, Token.ID, Token.STRING, Token.CONS, Token.ID, Token.STRING, Token.NIL),
+        CONS_ID_STRING_CONS_STRING_ID_NIL(Token.CONS, Token.ID, Token.STRING, Token.CONS, Token.STRING, Token.ID, Token.NIL),
+        CONS_ID_STRING_CONS_ID_STRING_ID_NIL(Token.CONS, Token.ID, Token.STRING, Token.CONS, Token.ID, Token.STRING, Token.ID, Token.NIL),
+        CONS_ID_STRING_ID_CONS_ID_STRING_ID_NIL(Token.CONS, Token.ID, Token.STRING, Token.ID, Token.CONS, Token.ID, Token.STRING, Token.ID, Token.NIL),
+        ID_CONS_ID_STRING_ID_CONS_ID_STRING_ID_NIL(Token.ID, Token.CONS, Token.ID, Token.STRING, Token.ID, Token.CONS, Token.ID, Token.STRING, Token.ID, Token.NIL),
+        DIAMOND(Token.DIAMOND),
+        ID_DIAMOND(Token.ID, Token.DIAMOND),
+        CONS_STRING_DIAMOND(Token.CONS, Token.STRING, Token.DIAMOND),
+        CONS_STRING_ID_DIAMOND(Token.CONS, Token.STRING, Token.ID, Token.DIAMOND),
+        CONS_ID_STRING_DIAMOND(Token.CONS, Token.ID, Token.STRING, Token.DIAMOND),
+        CONS_ID_STRING_ID_DIAMOND(Token.CONS, Token.ID, Token.STRING, Token.ID, Token.DIAMOND),
+        CONS_ID_STRING_CONS_STRING_DIAMOND(Token.CONS, Token.ID, Token.STRING, Token.CONS, Token.STRING, Token.DIAMOND),
+        CONS_ID_STRING_CONS_ID_STRING_DIAMOND(Token.CONS, Token.ID, Token.STRING, Token.CONS, Token.ID, Token.STRING, Token.DIAMOND),
+        CONS_ID_STRING_CONS_STRING_ID_DIAMOND(Token.CONS, Token.ID, Token.STRING, Token.CONS, Token.STRING, Token.ID, Token.DIAMOND),
+        CONS_ID_STRING_CONS_ID_STRING_ID_DIAMOND(Token.CONS, Token.ID, Token.STRING, Token.CONS, Token.ID, Token.STRING, Token.ID, Token.DIAMOND),
+        CONS_ID_STRING_ID_CONS_ID_STRING_ID_DIAMOND(Token.CONS, Token.ID, Token.STRING, Token.ID, Token.CONS, Token.ID, Token.STRING, Token.ID, Token.DIAMOND),
+        ID_CONS_ID_STRING_ID_CONS_ID_STRING_ID_DIAMOND(Token.ID, Token.CONS, Token.ID, Token.STRING, Token.ID, Token.CONS, Token.ID, Token.STRING, Token.ID, Token.DIAMOND);
+
+        Token[] tokens;
+
+        Shape(Token... tokens) {
+            this.tokens = tokens;
+        }
+
+        Type compile(final IdMethod idMethod, final NilMethod nilMethod, final ConsMethod consMethod, Type target) {
+            return process(tokens, new StackReducer<Token, Type, Type>() {
+                public Type reduce(Token t, Type[] operands, Type target) {
+                    switch (t) {
+                        case DIAMOND: return Type.LIST_Z.asSubtypeOf(target);
+                        case NIL: return nilMethod.apply(target, operands);
+                        case STRING: return Type.STRING;
+                        case ID: return idMethod.apply(target, operands);
+                        case CONS: return consMethod.apply(target, operands);
+                        default: throw new AssertionError();
+                    }
+                }
+                public Class<Type> resultToken() { return Type.class; }
+                public Type reducerArg(Token item, int i) {
+                    switch (item) {
+                        case ID:
+                            return idMethod.getFormals()[i];
+                        case CONS:
+                            return consMethod.getFormals()[i];
+                        default: return Type.OBJECT;
+                    }
+                }
+            }, target);
+        }
+
+        public String expand(String selector) {
+            return process(tokens, new StackReducer<Token, String, Void>() {
+                public String reduce(Token t, String[] operands, Void _unused) {
+                    switch (t) {
+                        case DIAMOND:
+                        case NIL:
+                        case ID:
+                        case CONS:
+                            StringBuilder buf = new StringBuilder();
+                            String sep = "";
+                            for (int i = 0; i < t.arity; i ++) {
+                                buf.append(sep);
+                                buf.append(operands[i]);
+                                sep = ",";
+                            }
+                            buf.insert(0, "(");
+                            buf.insert(0, t.tokenStr);
+                            buf.append(")");
+                            return buf.toString();
+                        case STRING:
+                            return t.tokenStr;
+                        default: throw new AssertionError();
+                    }
+                }
+                public Class<String> resultToken() { return String.class; }
+                public Void reducerArg(Token item, int i) { return null; }
+            }, null);
+        }
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/combo-tests/tests/tools/javac/lambda/SourceTargetVersionTest.java	Wed Aug 14 15:53:13 2013 -0700
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  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 tools.javac.lambda;
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.Method;
+import java.lang.reflect.InvocationTargetException;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.testng.annotations.Factory;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+import tools.javac.combo.*;
+
+/**
+ * SourceTargetVersionTest: 
+ * Test source and class file compatibility by compiling and running lambda specific code 
+ * against some class files compiled separately with different source and target option 
+ * (1.5, 1.6, and 1.7).
+ * The goal is achieved by putting source files in different groups (A, B, C..,), each group 
+ * is set with its own compile options, and we compile in the reverse alphebetic order for the 
+ * groups (..., C, B, A) to set a previously compiled group of files as classpath for the next group. 
+ * And when executing, we Run class Main with classpath A:B:C... in the order. 
+ * 
+ */
+public class SourceTargetVersionTest extends ComboTestBase<SourceTargetVersionTest> {
+    @Factory
+    public static Object[] testSourceTarget() throws Exception {
+        return factory(SourceTargetVersionTest.class);
+    }
+   
+    @DimensionVar("SHAPE") CShapes shapeType;
+    @DimensionVar("CLIENT_CODE") ClientType clientType;
+    @DimensionVar("RELEASE") ReleaseVersion rv;
+    
+    @SourceFile(value="A.java", group="B")
+    String interfaceA = "interface A { #{SHAPE.METHOD} }";    
+    
+    @SourceFile(value="B.java", group="A")
+    String interfaceB = "interface B #{SHAPE.EXTEND} { default String m() { return \"B\"; } }";
+    
+    @SourceFile(value="C.java", group="A")
+    String classC = "class C #{SHAPE.IMPLEMENT} {\n" +
+                    "    #{CLIENT_CODE}\n" +
+                    "}";
+    
+    @SourceFile(value="Main.java", group="A")
+    String classMain = "public class Main {\n" +
+                       "    public String main() {\n" +
+                       "        return new C().m();\n" +                       
+                       "    }\n" +
+                       "}";
+    
+    @TemplateVar("LAMBDA_EXP") String le = "public String m() {\n" +
+                                           "    A a = () -> \"A\";\n" +
+                                           "    return a.m();\n" +
+                                           "}";
+    @TemplateVar("METHOD_REF") String mr = "String foo() {\n" +
+                                           "    return \"foo\";\n" +
+                                           "}\n\n" +
+                                           
+                                           "public String m() {\n" +
+                                           "    A a = this::foo;\n" +
+                                           "    return a.m();\n" +
+                                           "}";
+    
+    @Override
+    protected boolean shouldSkip() {
+        return (shapeType == CShapes.C_AB && clientType != ClientType.DEF_MED) ||
+               (shapeType == CShapes.C && clientType == ClientType.DEF_MED);
+    }
+
+    @Override
+    protected boolean shouldRun() { return true; }
+
+    @Override
+    protected void run(Class<?> clazz) throws ReflectiveOperationException {
+        Method m = clazz.getMethod("main");
+        Object obj = clazz.newInstance();
+        String result = (String) m.invoke(obj);
+        String expected = clientType.returnValue;
+        assertEquals(result, expected);
+    }
+    
+    @Override
+    protected String[] getCompileOptions(String group) {
+        switch(group) {
+            case "B": return new String[]{"-source", rv.versionStr, "-target", rv.versionStr};
+            default: return new String[0];
+        }
+    }
+       
+    enum CShapes implements Template { //shapes of class hirarchy
+        //class C implements interface A, B
+        C_AB("", "", "implements A, B"), 
+        //class C implments interface B, B extends interface A
+        C_B_A("String m();", "extends A", "implements B"), 
+        //class C
+        C("String m();", "", ""); 
+        
+        private final String absMethod;
+        private final String extend;
+        private final String implement;
+        
+        CShapes(String absMethod, String extend, String implement) {
+            this.absMethod = absMethod;
+            this.extend = extend;
+            this.implement = implement;
+        }
+                
+        public String expand(String selector) {
+            switch(selector) {
+                case "METHOD": return absMethod;
+                case "EXTEND": return extend;
+                case "IMPLEMENT": return implement;
+                default: return toString();
+            }
+        }        
+    }
+    
+    enum ClientType implements Template { // jdk8 specific code in client program
+        LAMBDA_EXP("#{LAMBDA_EXP}", "A"), // lambda expressions
+        METHOD_REF("#{METHOD_REF}", "foo"), // method references
+        DEF_MED("", "B"); // default method inheritance
+        
+        private final String clientCode;
+        private final String returnValue;
+        
+        ClientType(String str, String ret) {
+            clientCode = str;
+            returnValue = ret;
+        }
+        
+        public String expand(String selector) {
+            return clientCode;        
+        }
+    }
+    
+    enum ReleaseVersion implements Template {
+        FIVE("1.5"),
+        SIX("1.6"),
+        SEVEN("1.7");
+        
+        final String versionStr;
+        
+        ReleaseVersion(String vstr) {
+            versionStr = vstr;
+        }
+        
+        public String expand(String selector) {
+            return toString();        
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/combo-tests/tests/tools/javac/lambda/StaticMethodTest.java	Wed Aug 14 15:53:13 2013 -0700
@@ -0,0 +1,155 @@
+/*
+ * 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 tools.javac.lambda;
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.Method;
+import java.lang.reflect.InvocationTargetException;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.testng.annotations.Factory;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+import tools.javac.combo.*;
+
+/**
+ * StaticMethodTest: Test static methods in interfaces by running bytecode 
+ *                   compiled at different times; where a static method is added/declared
+ *                   in one interface and only that interface is recompiled.
+ *
+ *                   Static methods in interface are not inherited and 
+ *                   are not visible to any implementing (extending) classes (interfaces).
+ * @bug    8005968
+ * @author sogoel
+ * 
+ */
+public class StaticMethodTest extends ComboTestBase<StaticMethodTest> {
+    @Factory
+    public static Object[] testStaticMethod() throws Exception {
+        return factory(StaticMethodTest.class);
+    }
+    
+    @DimensionVar("SHAPE") CShapes shapeType;
+    
+    @DimensionVar("ADD") AddType addType;
+        
+    @SourceFile(value="B.java", group="A")
+    String interfaceBModified = "interface B #{SHAPE.B_DECL} { #{ADD} }";
+    
+    @SourceFile(value="B.java", group="B")
+    String interfaceB =         "interface B #{SHAPE.B_DECL} {}";
+    
+    @SourceFile(value="A.java", group="B")
+    String interfaceA =         "interface A { static String m() { return \"A\"; } }";
+    
+    @SourceFile(value="C.java", group="B")
+    String classC = "#{SHAPE.C}";
+    
+    @SourceFile(value="Main.java", group="B")
+    String classMain = "public class Main {\n" +
+                       "    public String main() {\n" +
+                       "        return new C().m();\n" +
+                       "    }\n" +
+                       "}";
+
+    @Override
+    protected boolean shouldRun() { return true; }
+
+    @Override
+    protected void run(Class<?> clazz) throws ReflectiveOperationException {
+        Method m = clazz.getMethod("main");
+        Object obj = clazz.newInstance();
+        String result = null, output = null;
+        try {
+            result = (String) m.invoke(obj);
+        } catch (InvocationTargetException ex) {
+            output = ex.getCause().toString();
+        }
+        assertEquals(output, null);
+        assertEquals(result, "C");
+    }
+
+    /*
+     * In order for class Main to compile in group B, object of class C should have
+     * access to a method m(). Therefore, a method m() is needed in class C.
+     * static m() in interfaces A, B is not visible to C.
+     */
+    static String methodSig = "public String m () { return \"C\"; }"; 
+    enum CShapes implements Template { //shapes of class hierarchy
+        //class C implements interface A, B
+        C_AB("",
+           "class C implements A, B { " + methodSig + " }"), 
+        //class C implements interface B, B extends interface A
+        C_B_A("extends A",
+           "class C implements B { " + methodSig + " }"),
+        //class C implements interface AB, AB extends interface A, B
+        C_I_AB("",
+           "interface AB extends A, B {  }\n" +
+           "class C implements AB { " + methodSig + " }"),
+        //class C implements interface AB, AB extends interface A, B and defines its own static method 
+        C_I_AB2("",
+        "interface AB extends A, B { static String m() { return \"AB\"; } }\n" +
+        "class C implements AB { " + methodSig + " }"),
+        //class C extends Class D implements Interface B
+        C_CI("",
+            "class D { public String m() { return \"D\"; } }\n" +
+            "class C extends D implements B { " + methodSig + " }");
+
+        private final String sB_DECL;
+        private final String sC;
+
+        CShapes(String sB_DECL, String sC) {
+            this.sB_DECL = sB_DECL;
+            this.sC = sC;
+        }
+
+        public String expand(String selector) {
+            switch(selector) {
+                case "B_DECL": return sB_DECL;
+                case "C": return sC;
+                default: return toString();
+            }
+        }
+    }
+
+    enum AddType implements Template { // add by adding static method or abstract interface method
+        ADD("static String m() { return \"B\"; }"),
+        REDECLARE("String m();");
+
+        final String newCode;
+
+        AddType(String str) {
+            newCode = str;
+        }
+
+        public String expand(String selector) {
+            return newCode;
+        }
+    }
+}
+
--- a/make/common/internal/Defs-langtools.gmk	Tue Aug 13 10:42:37 2013 -0700
+++ b/make/common/internal/Defs-langtools.gmk	Wed Aug 14 15:53:13 2013 -0700
@@ -28,7 +28,8 @@
 IMPORT_RT_PACKAGES +=               \
       javax/annotation/processing   \
       javax/lang/model              \
-      javax/tools
+      javax/tools                   \
+      com/sun/runtime
 
 IMPORT_TOOLS_PACKAGES +=            \
       com/sun/javadoc               \
--- a/make/docs/NON_CORE_PKGS.gmk	Tue Aug 13 10:42:37 2013 -0700
+++ b/make/docs/NON_CORE_PKGS.gmk	Wed Aug 14 15:53:13 2013 -0700
@@ -84,6 +84,8 @@
 
 SCTPAPI_PKGS     = com.sun.nio.sctp
 
+LAMBDA_RTAPI     = com.sun.runtime
+
 ifeq ($(PLATFORM), macosx)
 APPLE_EXT_PKGS   = com.apple.concurrent   \
                    com.apple.eawt         \
@@ -101,5 +103,6 @@
                    $(HTTPSERVER_PKGS) \
                    $(SMARTCARDIO_PKGS) \
                    $(SCTPAPI_PKGS) \
+                   $(LAMBDA_RTAPI) \
                    $(APPLE_EXT_PKGS)
 
--- a/make/java/java/FILES_java.gmk	Tue Aug 13 10:42:37 2013 -0700
+++ b/make/java/java/FILES_java.gmk	Wed Aug 14 15:53:13 2013 -0700
@@ -300,12 +300,20 @@
 	java/util/EnumMap.java \
     java/util/Arrays.java \
     java/util/ArraysParallelSortHelpers.java \
+    java/util/ArrayPrefixHelpers.java \
+    java/util/ArraySortHelpers.java \
     java/util/DualPivotQuicksort.java \
     java/util/TimSort.java \
     java/util/ComparableTimSort.java \
+    java/util/Comparators.java \
     java/util/ConcurrentModificationException.java \
+    java/util/OptionalDouble.java \
+    java/util/OptionalInt.java \
+    java/util/Optional.java \
+    java/util/OptionalLong.java \
     java/util/ServiceLoader.java \
     java/util/ServiceConfigurationError.java \
+    java/util/StringJoiner.java \
     java/util/Timer.java \
     java/util/TimerTask.java \
     java/util/Objects.java \
@@ -334,6 +342,8 @@
     java/util/concurrent/CyclicBarrier.java \
     java/util/concurrent/DelayQueue.java \
     java/util/concurrent/Delayed.java \
+    java/util/concurrent/DoubleAdder.java \
+    java/util/concurrent/DoubleMaxUpdater.java \
     java/util/concurrent/Exchanger.java \
     java/util/concurrent/ExecutionException.java \
     java/util/concurrent/Executor.java \
@@ -348,6 +358,10 @@
     java/util/concurrent/LinkedBlockingDeque.java \
     java/util/concurrent/LinkedBlockingQueue.java \
     java/util/concurrent/LinkedTransferQueue.java \
+    java/util/concurrent/LongAdder.java \
+    java/util/concurrent/LongAdderTable.java \
+    java/util/concurrent/LongMaxUpdater.java \
+    java/util/concurrent/package-info.java \
     java/util/concurrent/Phaser.java \
     java/util/concurrent/PriorityBlockingQueue.java \
     java/util/concurrent/RecursiveAction.java \
@@ -360,6 +374,8 @@
     java/util/concurrent/ScheduledFuture.java \
     java/util/concurrent/ScheduledThreadPoolExecutor.java \
     java/util/concurrent/Semaphore.java \
+    java/util/concurrent/SequenceLock.java \
+    java/util/concurrent/Striped64.java \
     java/util/concurrent/SynchronousQueue.java \
     java/util/concurrent/ThreadFactory.java \
     java/util/concurrent/ThreadLocalRandom.java \
@@ -379,18 +395,17 @@
     java/util/concurrent/atomic/AtomicReferenceArray.java \
     java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java \
     java/util/concurrent/atomic/AtomicStampedReference.java \
-    java/util/concurrent/atomic/DoubleAccumulator.java \
-    java/util/concurrent/atomic/DoubleAdder.java \
-    java/util/concurrent/atomic/LongAccumulator.java \
-    java/util/concurrent/atomic/LongAdder.java \
-    java/util/concurrent/atomic/Striped64.java \
+    java/util/concurrent/atomic/package-info.java \
+    java/util/concurrent/extra/AtomicDoubleArray.java \
+    java/util/concurrent/extra/AtomicDouble.java \
+    java/util/concurrent/extra/ReadMostlyVector.java \
     java/util/concurrent/locks/AbstractOwnableSynchronizer.java \
     java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java \
     java/util/concurrent/locks/AbstractQueuedSynchronizer.java \
-    java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java \
     java/util/concurrent/locks/Condition.java \
     java/util/concurrent/locks/Lock.java \
     java/util/concurrent/locks/LockSupport.java \
+    java/util/concurrent/locks/package-info.java \
     java/util/concurrent/locks/ReadWriteLock.java \
     java/util/concurrent/locks/ReentrantLock.java \
     java/util/concurrent/locks/ReentrantReadWriteLock.java \
--- a/make/java/java/Makefile	Tue Aug 13 10:42:37 2013 -0700
+++ b/make/java/java/Makefile	Wed Aug 14 15:53:13 2013 -0700
@@ -37,7 +37,7 @@
 JAVAC_MAX_WARNINGS=true
 include $(BUILDDIR)/common/Defs.gmk
 
-AUTO_FILES_JAVA_DIRS = java/util/function
+AUTO_FILES_JAVA_DIRS = java/util/concurrent java/util/function java/util/stream
 
 # windows compiler flags
 ifeq ($(PLATFORM),windows)
@@ -51,7 +51,7 @@
 OTHER_CFLAGS += -DJDK_MAJOR_VERSION='"$(JDK_MAJOR_VERSION)"' \
                 -DJDK_MINOR_VERSION='"$(JDK_MINOR_VERSION)"' \
                 -DJDK_MICRO_VERSION='"$(JDK_MICRO_VERSION)"' \
-                -DJDK_BUILD_NUMBER='"$(JDK_BUILD_NUMBER)"' 
+                -DJDK_BUILD_NUMBER='"$(JDK_BUILD_NUMBER)"'
 
 ifdef JDK_UPDATE_VERSION
 OTHER_CFLAGS += -DJDK_UPDATE_VERSION='"$(JDK_UPDATE_VERSION)"'
@@ -279,7 +279,7 @@
 $(GENSRCDIR)/java/lang/UNIXProcess.java: $(PLATFORM_UNIX_PROCESS)
 	$(install-file)
 
-clean:: 
+clean::
 	$(RM) $(GENSRCDIR)/java/lang/UNIXProcess.java
 
 endif
@@ -293,10 +293,10 @@
 #
 # Special rules.
 #
-clean:: 
+clean::
 	$(RM) -r $(CLASSHDRDIR)
 
-clobber:: 
+clobber::
 	$(RM) -r $(CLASSBINDIR)/java/io $(CLASSBINDIR)/java/lang \
 		$(CLASSBINDIR)/java/security $(CLASSBINDIR)/java/util \
 		$(CLASSBINDIR)/sun/misc
@@ -313,12 +313,6 @@
 CAL_PROPS = calendars.properties
 
 #
-# Rule to copy Hijrah-umalqura calendar properties file.
-#
-HIJRAH_UMALQURA_PROPS = hijrah-config-umalqura.properties
-
-
-#
 # Rule to copy tzmappings file on Windows
 #
 ifeq ($(PLATFORM), windows)
@@ -330,7 +324,7 @@
 	$(call chmod-file, 444)
 endif
 
-build: $(LIBDIR)/$(PROPS) $(LIBDIR)/$(CAL_PROPS) $(LIBDIR)/$(HIJRAH_UMALQURA_PROPS) $(TZMAP)
+build: $(LIBDIR)/$(PROPS) $(LIBDIR)/$(CAL_PROPS) $(TZMAP)
 
 $(LIBDIR)/$(PROPS): $(PLATFORM_SRC)/lib/$(PROPS)
 	$(install-file)
@@ -338,10 +332,7 @@
 $(LIBDIR)/$(CAL_PROPS): $(SHARE_SRC)/lib/$(CAL_PROPS)
 	$(install-file)
 
-$(LIBDIR)/$(HIJRAH_UMALQURA_PROPS): $(SHARE_SRC)/lib/$(HIJRAH_UMALQURA_PROPS)
-	$(install-file)
-
-clean:: 
+clean::
 	$(RM) -r $(LIBDIR)/$(PROPS) $(TZMAP)
 
 #
@@ -362,12 +353,12 @@
 	$(MV) $@.temp $@
 	$(call chmod-file, 444)
 
-clean:: 
+clean::
 	$(RM) $(CURDATA)
 
 
 #
-# Rules to create $(GENSRCDIR)/sun/lang/CharacterData*.java 
+# Rules to create $(GENSRCDIR)/sun/lang/CharacterData*.java
 #
 CHARACTERDATA = $(BUILDDIR)/tools/GenerateCharacter
 UNICODEDATA   = $(BUILDDIR)/tools/UnicodeData
@@ -422,12 +413,12 @@
 	$(install-file)
 
 clean::
-	$(RM) $(GENSRCDIR)/java/lang/CharacterDataLatin1.java 
+	$(RM) $(GENSRCDIR)/java/lang/CharacterDataLatin1.java
 	$(RM) $(GENSRCDIR)/java/lang/CharacterData00.java
-	$(RM) $(GENSRCDIR)/java/lang/CharacterData01.java 
+	$(RM) $(GENSRCDIR)/java/lang/CharacterData01.java
 	$(RM) $(GENSRCDIR)/java/lang/CharacterData02.java
 	$(RM) $(GENSRCDIR)/java/lang/CharacterData0E.java
-	$(RM) $(GENSRCDIR)/java/lang/CharacterDataUndefined.java 
+	$(RM) $(GENSRCDIR)/java/lang/CharacterDataUndefined.java
 	$(RM) $(GENSRCDIR)/java/lang/CharacterDataPrivateUse.java
 
 #
@@ -448,7 +439,7 @@
 	build.tools.generatecharacter.CharacterName \
 		$(UNICODEDATA)/UnicodeData.txt $(UNINAME)
 
-clean:: 
+clean::
 	$(RM) $(UNINAME)
 
 #
@@ -456,15 +447,15 @@
 #
 
 #
-# Rule to precompile CoreResourceBundleControl.java 
+# Rule to precompile CoreResourceBundleControl.java
 #
 LOCALES_GEN_SH = localelist.sh
 
 $(GENSRCDIR)/sun/util/CoreResourceBundleControl.java: \
 	$(SHARE_SRC)/classes/sun/util/CoreResourceBundleControl-XLocales.java.template $(LOCALES_GEN_SH)
-	@$(prep-target) 
+	@$(prep-target)
 	NAWK="$(NAWK)" SED="$(SED)" $(SH) $(LOCALES_GEN_SH) "$(JRE_NONEXIST_LOCALES)" \
-		$< $@ 
+		$< $@
 clean::
 	$(RM) $(GENSRCDIR)/sun/util/CoreResourceBundleControl.java
 
--- a/make/netbeans/common/java-data-native.ent	Tue Aug 13 10:42:37 2013 -0700
+++ b/make/netbeans/common/java-data-native.ent	Wed Aug 14 15:53:13 2013 -0700
@@ -31,13 +31,13 @@
  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 -->
 
-<java-data xmlns="http://www.netbeans.org/ns/freeform-project-java/3">
+<java-data xmlns="http://www.netbeans.org/ns/freeform-project-java/4">
     <compilation-unit>
         <package-root>${root}/src/share/classes</package-root>
         <package-root>${root}/src/macosx/classes</package-root>
         <package-root>${root}/src/solaris/classes</package-root>
         <package-root>${root}/src/windows/classes</package-root>
-        <classpath mode="boot">${bootstrap.jdk}/jre/lib/rt.jar</classpath>
+<!--        <classpath mode="boot">${bootstrap.jdk}/jre/lib/rt.jar</classpath> -->
         <built-to>${root}/build/${platform}-${arch}/classes</built-to>
         <javadoc-built-to>${root}/build/${platform}-${arch}/docs/api</javadoc-built-to>
         <source-level>1.8</source-level>
--- a/make/netbeans/common/java-data-no-native.ent	Tue Aug 13 10:42:37 2013 -0700
+++ b/make/netbeans/common/java-data-no-native.ent	Wed Aug 14 15:53:13 2013 -0700
@@ -31,10 +31,10 @@
  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 -->
 
-<java-data xmlns="http://www.netbeans.org/ns/freeform-project-java/3">
+<java-data xmlns="http://www.netbeans.org/ns/freeform-project-java/4">
     <compilation-unit>
         <package-root>${root}/src/share/classes</package-root>
-        <classpath mode="boot">${bootstrap.jdk}/jre/lib/rt.jar</classpath>
+<!--        <classpath mode="boot">${bootstrap.jdk}/jre/lib/rt.jar</classpath> -->
         <built-to>${root}/build/${platform}-${arch}/classes</built-to>
         <javadoc-built-to>${root}/build/${platform}-${arch}/docs/api</javadoc-built-to>
         <source-level>1.8</source-level>
--- a/make/netbeans/common/shared.xml	Tue Aug 13 10:42:37 2013 -0700
+++ b/make/netbeans/common/shared.xml	Wed Aug 14 15:53:13 2013 -0700
@@ -77,10 +77,10 @@
         <echo level="verbose">System configuration claims architecture is ${platform}-${arch}</echo>
         <property name="build.dir" location="${root}/build/${platform}-${arch}"/>
         <property name="bin.dir" location="${build.dir}/bin"/>
-        <property name="make.dir" location="${root}/make"/> <!-- this is old build make files! -->
+        <property name="make.dir" location="${root}/makefiles"/>
         <property name="gensrc.dir" location="${build.dir}/gensrc"/>
         <property name="classes.dir" location="${build.dir}/classes"/>
-        <property name="jtreg.dir" location="${build.dir}/jtreg/${ant.project.name}"/>
+        <property name="jtreg.dir" location="${build.dir}/testoutput"/>
         <property name="dist.dir" value="${root}/dist"/>
         <property name="includes" value="(nothing)"/>
         <property name="excludes" value=""/>
--- a/make/org/Makefile	Tue Aug 13 10:42:37 2013 -0700
+++ b/make/org/Makefile	Wed Aug 14 15:53:13 2013 -0700
@@ -31,7 +31,7 @@
 PRODUCT = org
 include $(BUILDDIR)/common/Defs.gmk
 
-SUBDIRS = ietf jcp
+SUBDIRS = asm ietf jcp
 include $(BUILDDIR)/common/Subdirs.gmk
 
 all build clean clobber::
--- a/src/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/src/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java	Wed Aug 14 15:53:13 2013 -0700
@@ -193,8 +193,8 @@
         } else {
             return new ConstantCallSite(
                     MethodHandles.Lookup.IMPL_LOOKUP
-                         .findConstructor(innerClass, constructorType)
-                         .asType(constructorType.changeReturnType(samBase)));
+                                        .findConstructor(innerClass, constructorType)
+                                        .asType(constructorType.changeReturnType(samBase)));
         }
     }
 
@@ -320,8 +320,8 @@
         TypeConvertingMethodAdapter mv
                 = new TypeConvertingMethodAdapter(
                     cw.visitMethod(ACC_PRIVATE + ACC_FINAL,
-                    NAME_METHOD_WRITE_REPLACE, DESCR_METHOD_WRITE_REPLACE,
-                    null, null));
+                                                                 NAME_METHOD_WRITE_REPLACE, DESCR_METHOD_WRITE_REPLACE,
+                                                                 null, null));
 
         mv.visitCode();
         mv.visitTypeInsn(NEW, NAME_SERIALIZED_LAMBDA);
--- a/src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java	Wed Aug 14 15:53:13 2013 -0700
@@ -295,6 +295,9 @@
 
         String invokerDesc = invokerType.toMethodDescriptorString();
         mv = cw.visitMethod(Opcodes.ACC_STATIC, invokerName, invokerDesc, null, null);
+
+        // Force inlining of this invoker method.
+        mv.visitAnnotation("Ljava/lang/invoke/ForceInline;", true);
     }
 
     /**
@@ -521,9 +524,6 @@
         // Mark this method as a compiled LambdaForm
         mv.visitAnnotation("Ljava/lang/invoke/LambdaForm$Compiled;", true);
 
-        // Force inlining of this invoker method.
-        mv.visitAnnotation("Ljava/lang/invoke/ForceInline;", true);
-
         // iterate over the form's names, generating bytecode instructions for each
         // start iterating at the first name following the arguments
         for (int i = lambdaForm.arity; i < lambdaForm.names.length; i++) {
@@ -943,9 +943,6 @@
         // Suppress this method in backtraces displayed to the user.
         mv.visitAnnotation("Ljava/lang/invoke/LambdaForm$Hidden;", true);
 
-        // Don't inline the interpreter entry.
-        mv.visitAnnotation("Ljava/lang/invoke/DontInline;", true);
-
         // create parameter array
         emitIconstInsn(invokerType.parameterCount());
         mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
@@ -1008,9 +1005,6 @@
         // Suppress this method in backtraces displayed to the user.
         mv.visitAnnotation("Ljava/lang/invoke/LambdaForm$Hidden;", true);
 
-        // Force inlining of this invoker method.
-        mv.visitAnnotation("Ljava/lang/invoke/ForceInline;", true);
-
         // Load receiver
         emitAloadInsn(0);
 
--- a/src/share/classes/java/lang/invoke/LambdaForm.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/src/share/classes/java/lang/invoke/LambdaForm.java	Wed Aug 14 15:53:13 2013 -0700
@@ -69,7 +69,7 @@
  * A lambda has a void result if and only if its result index is -1.
  * If a temporary has the type "V", it cannot be the subject of a NameRef,
  * even though possesses a number.
- * Note that all reference types are erased to "L", which stands for {@code Object).
+ * Note that all reference types are erased to "L", which stands for {@code Object}.
  * All subword types (boolean, byte, short, char) are erased to "I" which is {@code int}.
  * The other types stand for the usual primitive types.
  * <p>
@@ -592,7 +592,6 @@
     private int invocationCounter = 0;
 
     @Hidden
-    @DontInline
     /** Interpretively invoke this form on the given arguments. */
     Object interpretWithArguments(Object... argumentValues) throws Throwable {
         if (TRACE_INTERPRETER)
@@ -607,7 +606,6 @@
     }
 
     @Hidden
-    @DontInline
     /** Evaluate a single Name within this form, applying its function to its arguments. */
     Object interpretName(Name name, Object[] values) throws Throwable {
         if (TRACE_INTERPRETER)
--- a/src/share/classes/java/lang/invoke/MemberName.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/src/share/classes/java/lang/invoke/MemberName.java	Wed Aug 14 15:53:13 2013 -0700
@@ -236,8 +236,7 @@
             assert(MethodHandleNatives.refKindIsMethod(refKind));
             if (clazz.isInterface())
                 assert(refKind == REF_invokeInterface ||
-                       refKind == REF_invokeStatic    ||
-                       refKind == REF_invokeSpecial   ||
+                       refKind == REF_invokeStatic ||
                        refKind == REF_invokeVirtual && isObjectPublicMethod());
         } else {
             assert(false);
@@ -270,7 +269,7 @@
             assert(refKind == REF_invokeSpecial) : this;
             return true;
         }
-        assert(false) : this+" != "+MethodHandleNatives.refKindName((byte)originalRefKind);
+        assert(false) : this;
         return true;
     }
     private boolean staticIsConsistent() {
@@ -288,8 +287,12 @@
             assert(vmindex >= 0) : vmindex + ":" + this;
             assert(vmtarget instanceof Class);
         } else {
-            if (MethodHandleNatives.refKindDoesDispatch(refKind))
-                assert(vmindex >= 0) : vmindex + ":" + this;
+            if (MethodHandleNatives.refKindDoesDispatch(refKind)) {
+                // invokeStatic can reference either method table or interface table
+                if (refKind != REF_invokeStatic) {
+                    assert(vmindex >= 0) : vmindex + ":" + this;
+                }
+            }
             else
                 assert(vmindex < 0) : vmindex;
             assert(vmtarget instanceof MemberName) : vmtarget + " in " + this;
@@ -487,19 +490,14 @@
         if (this.type == null)
             this.type = new Object[] { m.getReturnType(), m.getParameterTypes() };
         if (wantSpecial) {
-            assert(!isAbstract()) : this;
             if (getReferenceKind() == REF_invokeVirtual)
                 changeReferenceKind(REF_invokeSpecial, REF_invokeVirtual);
-            else if (getReferenceKind() == REF_invokeInterface)
-                // invokeSpecial on a default method
-                changeReferenceKind(REF_invokeSpecial, REF_invokeInterface);
         }
     }
     public MemberName asSpecial() {
         switch (getReferenceKind()) {
         case REF_invokeSpecial:     return this;
         case REF_invokeVirtual:     return clone().changeReferenceKind(REF_invokeSpecial, REF_invokeVirtual);
-        case REF_invokeInterface:   return clone().changeReferenceKind(REF_invokeSpecial, REF_invokeInterface);
         case REF_newInvokeSpecial:  return clone().changeReferenceKind(REF_invokeSpecial, REF_newInvokeSpecial);
         }
         throw new IllegalArgumentException(this.toString());
--- a/src/share/classes/java/lang/invoke/MethodHandleImpl.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/src/share/classes/java/lang/invoke/MethodHandleImpl.java	Wed Aug 14 15:53:13 2013 -0700
@@ -312,9 +312,9 @@
     }
 
     static class AsVarargsCollector extends MethodHandle {
-        private final MethodHandle target;
-        private final Class<?> arrayType;
-        private MethodHandle cache;
+        MethodHandle target;
+        final Class<?> arrayType;
+        MethodHandle cache;
 
         AsVarargsCollector(MethodHandle target, MethodType type, Class<?> arrayType) {
             super(type, reinvokerForm(type));
--- a/src/share/classes/java/lang/invoke/MethodHandleInfo.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/src/share/classes/java/lang/invoke/MethodHandleInfo.java	Wed Aug 14 15:53:13 2013 -0700
@@ -27,10 +27,10 @@
 import java.lang.invoke.MethodHandleNatives.Constants;
 
 /**
- * Cracking (reflecting) method handles back into their constituent symbolic parts.
- *
+ * Cracking (reflecting) method handles back into their constituent symbolic parts. 
+ * 
  */
-final class MethodHandleInfo {
+public final class MethodHandleInfo {
    public static final int
        REF_getField                = Constants.REF_getField,
        REF_getStatic               = Constants.REF_getStatic,
@@ -72,15 +72,15 @@
        return methodType;
    }
 
-   public int getModifiers() {
-       return -1; //TODO
-   }
+    public int getModifiers() {
+        return -1; //TODO
+    }
 
    public int getReferenceKind() {
        return referenceKind;
    }
-
-   static String getReferenceKindString(int referenceKind) {
+    
+   public static String getReferenceKindString(int referenceKind) {
         switch (referenceKind) {
             case REF_getField: return "getfield";
             case REF_getStatic: return "getstatic";
--- a/src/share/classes/java/lang/invoke/MethodHandleNatives.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/src/share/classes/java/lang/invoke/MethodHandleNatives.java	Wed Aug 14 15:53:13 2013 -0700
@@ -215,6 +215,7 @@
     static boolean refKindDoesDispatch(byte refKind) {
         assert(refKindIsValid(refKind));
         return (refKind == REF_invokeVirtual ||
+                refKind == REF_invokeStatic ||
                 refKind == REF_invokeInterface);
     }
     static {
--- a/src/share/classes/java/lang/invoke/MethodHandleProxies.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/src/share/classes/java/lang/invoke/MethodHandleProxies.java	Wed Aug 14 15:53:13 2013 -0700
@@ -142,7 +142,7 @@
     @CallerSensitive
     public static
     <T> T asInterfaceInstance(final Class<T> intfc, final MethodHandle target) {
-        if (!intfc.isInterface() || !Modifier.isPublic(intfc.getModifiers()))
+        if (!intfc.isInterface()/* || !Modifier.isPublic(intfc.getModifiers())*/)
             throw new IllegalArgumentException("not a public interface: "+intfc.getName());
         final MethodHandle mh;
         if (System.getSecurityManager() != null) {
--- a/src/share/classes/java/nio/file/DirectoryStream.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/src/share/classes/java/nio/file/DirectoryStream.java	Wed Aug 14 15:53:13 2013 -0700
@@ -28,16 +28,21 @@
 import java.util.Iterator;
 import java.io.Closeable;
 import java.io.IOException;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
 
 /**
  * An object to iterate over the entries in a directory. A directory stream
- * allows for the convenient use of the for-each construct to iterate over a
- * directory.
+ * allows for the convenient use of the for-each construct or the {@link
+ * Stream} API to iterate over a directory.
  *
  * <p> <b> While {@code DirectoryStream} extends {@code Iterable}, it is not a
- * general-purpose {@code Iterable} as it supports only a single {@code
- * Iterator}; invoking the {@link #iterator iterator} method to obtain a second
- * or subsequent iterator throws {@code IllegalStateException}. </b>
+ * general-purpose {@code Iterable}. A {@code DirectoryStream} supports only a
+ * single iteration via either the {@link #iterator iterator} or the {@link
+ * #stream stream} method. Invoking either method to do a second or
+ * subsequent iteration throws {@code IllegalStateException}. </b>
  *
  * <p> An important property of the directory stream's {@code Iterator} is that
  * its {@link Iterator#hasNext() hasNext} method is guaranteed to read-ahead by
@@ -61,13 +66,13 @@
  *   }
  * </pre>
  *
- * <p> Once a directory stream is closed, then further access to the directory,
- * using the {@code Iterator}, behaves as if the end of stream has been reached.
- * Due to read-ahead, the {@code Iterator} may return one or more elements
- * after the directory stream has been closed. Once these buffered elements
- * have been read, then subsequent calls to the {@code hasNext} method returns
- * {@code false}, and subsequent calls to the {@code next} method will throw
- * {@code NoSuchElementException}.
+ * <p> Once a directory stream is closed, then further access to the
+ * directory, using the {@code Iterator} or {@code Stream}, behaves as if the
+ * end of stream has been reached. Due to read-ahead, one or more elements may
+ * be returned after the directory stream has been closed. Once these buffered
+ * elements have been read, then subsequent calls to the {@code hasNext}
+ * method returns {@code false}, and subsequent calls to the {@code next}
+ * method will throw {@code NoSuchElementException}.
  *
  * <p> A directory stream is not required to be <i>asynchronously closeable</i>.
  * If a thread is blocked on the directory stream's iterator reading from the
@@ -75,13 +80,14 @@
  * second thread may block until the read operation is complete.
  *
  * <p> If an I/O error is encountered when accessing the directory then it
- * causes the {@code Iterator}'s {@code hasNext} or {@code next} methods to
- * throw {@link DirectoryIteratorException} with the {@link IOException} as the
- * cause. As stated above, the {@code hasNext} method is guaranteed to
- * read-ahead by at least one element. This means that if {@code hasNext} method
- * returns {@code true}, and is followed by a call to the {@code next} method,
- * then it is guaranteed that the {@code next} method will not fail with a
- * {@code DirectoryIteratorException}.
+ * causes the methods to throw {@link DirectoryIteratorException} with the
+ * {@link IOException} as the cause. This could be the {@code Iterator}'s
+ * {@code hasNext} or {@code next} method or one of the {@code Stream} methods.
+ * As stated above, the {@code hasNext} method is guaranteed to read-ahead by
+ * at least one element. This means that if {@code hasNext} method returns
+ * {@code true}, and is followed by a call to the {@code next} method, then it
+ * is guaranteed that the {@code next} method will not fail with a {@code
+ * DirectoryIteratorException}.
  *
  * <p> The elements returned by the iterator are in no specific order. Some file
  * systems maintain special links to the directory itself and the directory's
@@ -151,9 +157,23 @@
      * @return  the iterator associated with this {@code DirectoryStream}
      *
      * @throws  IllegalStateException
-     *          if this directory stream is closed or the iterator has already
-     *          been returned
+     *          if this directory stream is closed or the iterator or stream
+     *          has already been returned
      */
     @Override
     Iterator<T> iterator();
+
+    /**
+     * Returns the stream associated with this {@code DirectoryStream}.
+     *
+     * @return the stream associated with this {@code DirectoryStream}
+     *
+     * @throws IllegalStateException
+     *         if this directory stream is closed or the iterator or stream
+     *         has already been returned
+     * @since 1.8
+     */
+    default Stream<T> stream() {
+        return StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator(), Spliterator.DISTINCT), false);
+    }
 }
--- a/src/share/classes/java/nio/file/Files.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/src/share/classes/java/nio/file/Files.java	Wed Aug 14 15:53:13 2013 -0700
@@ -25,24 +25,54 @@
 
 package java.nio.file;
 
-import java.nio.file.attribute.*;
-import java.nio.file.spi.FileSystemProvider;
-import java.nio.file.spi.FileTypeDetector;
-import java.nio.channels.Channels;
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.Closeable;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Reader;
+import java.io.UncheckedIOException;
+import java.io.Writer;
+import java.nio.ByteBuffer;
 import java.nio.channels.FileChannel;
 import java.nio.channels.SeekableByteChannel;
-import java.io.Closeable;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.Reader;
-import java.io.Writer;
-import java.io.BufferedReader;
-import java.io.BufferedWriter;
-import java.io.InputStreamReader;
-import java.io.OutputStreamWriter;
-import java.io.IOException;
-import java.io.UncheckedIOException;
-import java.util.*;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetDecoder;
+import java.nio.charset.CharsetEncoder;
+import java.nio.file.attribute.BasicFileAttributeView;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.nio.file.attribute.DosFileAttributes;
+import java.nio.file.attribute.FileAttribute;
+import java.nio.file.attribute.FileAttributeView;
+import java.nio.file.attribute.FileOwnerAttributeView;
+import java.nio.file.attribute.FileStoreAttributeView;
+import java.nio.file.attribute.FileTime;
+import java.nio.file.attribute.PosixFileAttributeView;
+import java.nio.file.attribute.PosixFileAttributes;
+import java.nio.file.attribute.PosixFilePermission;
+import java.nio.file.attribute.UserPrincipal;
+import java.nio.file.spi.FileSystemProvider;
+import java.nio.file.spi.FileTypeDetector;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.MayHoldCloseableResource;
+import java.util.Objects;
+import java.util.ServiceLoader;
+import java.util.Set;
+import java.util.Spliterator;
+import java.util.Spliterators;
 import java.util.function.BiPredicate;
 import java.util.stream.CloseableStream;
 import java.util.stream.DelegatingStream;
@@ -74,6 +104,21 @@
         return path.getFileSystem().provider();
     }
 
+    /**
+     * Convert a Closeable to a Runnable by converting checked IOException
+     * to UncheckedIOException
+     */
+    private static Runnable asUncheckedRunnable(Closeable c) {
+        return () -> {
+            try {
+                c.close();
+            }
+            catch (IOException e) {
+                throw new UncheckedIOException(e);
+            }
+        };
+    }
+
     // -- File contents --
 
     /**
@@ -3228,29 +3273,7 @@
     // -- Stream APIs --
 
     /**
-     * Implementation of CloseableStream
-     */
-    private static class DelegatingCloseableStream<T> extends DelegatingStream<T>
-        implements CloseableStream<T>
-    {
-        private final Closeable closeable;
-
-        DelegatingCloseableStream(Closeable c, Stream<T> delegate) {
-            super(delegate);
-            this.closeable = c;
-        }
-
-        public void close() {
-            try {
-                closeable.close();
-            } catch (IOException ex) {
-                throw new UncheckedIOException(ex);
-            }
-        }
-    }
-
-    /**
-     * Return a lazily populated {@code CloseableStream}, the elements of
+     * Return a lazily populated {@code Stream}, the elements of
      * which are the entries in the directory.  The listing is not recursive.
      *
      * <p> The elements of the stream are {@link Path} objects that are
@@ -3265,7 +3288,7 @@
      * method.
      *
      * <p> When not using the try-with-resources construct, then the stream's
-     * {@link CloseableStream#close close} method should be invoked after the
+     * {@link Stream#close close} method should be invoked after the
      * operation is completed so as to free any resources held for the open
      * directory. Operating on a closed stream behaves as if the end of stream
      * has been reached. Due to read-ahead, one or more elements may be
@@ -3278,7 +3301,7 @@
      *
      * @param   dir  The path to the directory
      *
-     * @return  The {@code CloseableStream} describing the content of the
+     * @return  The {@code Stream} describing the content of the
      *          directory
      *
      * @throws  NotDirectoryException
@@ -3294,43 +3317,47 @@
      * @see     #newDirectoryStream(Path)
      * @since   1.8
      */
-    public static CloseableStream<Path> list(Path dir) throws IOException {
+    @MayHoldCloseableResource.HoldsResource
+    public static Stream<Path> list(Path dir) throws IOException {
         DirectoryStream<Path> ds = Files.newDirectoryStream(dir);
-        final Iterator<Path> delegate = ds.iterator();
+        try {
+            final Iterator<Path> delegate = ds.iterator();
 
-        // Re-wrap DirectoryIteratorException to UncheckedIOException
-        Iterator<Path> it = new Iterator<Path>() {
-            public boolean hasNext() {
-                try {
-                    return delegate.hasNext();
-                } catch (DirectoryIteratorException e) {
-                    throw new UncheckedIOException(e.getCause());
+            // Re-wrap DirectoryIteratorException to UncheckedIOException
+            Iterator<Path> it = new Iterator<Path>() {
+                public boolean hasNext() {
+                    try {
+                        return delegate.hasNext();
+                    } catch (DirectoryIteratorException e) {
+                        throw new UncheckedIOException(e.getCause());
+                    }
                 }
-            }
-            public Path next() {
-                try {
-                    return delegate.next();
-                } catch (DirectoryIteratorException e) {
-                    throw new UncheckedIOException(e.getCause());
+                public Path next() {
+                    try {
+                        return delegate.next();
+                    } catch (DirectoryIteratorException e) {
+                        throw new UncheckedIOException(e.getCause());
+                    }
                 }
-            }
-        };
+            };
 
-        Stream<Path> s = StreamSupport.stream(
-                Spliterators.spliteratorUnknownSize(it, Spliterator.DISTINCT),
-                false);
-        return new DelegatingCloseableStream<>(ds, s);
+            return StreamSupport.stream(Spliterators.spliteratorUnknownSize(it, Spliterator.DISTINCT), false)
+                                .onClose(asUncheckedRunnable(ds));
+        } catch (Error|RuntimeException e) {
+            ds.close();
+            throw e;
+        }
     }
 
     /**
-     * Return a {@code CloseableStream} that is lazily populated with {@code
+     * Return a {@code Stream} that is lazily populated with {@code
      * Path} by walking the file tree rooted at a given starting file.  The
      * file tree is traversed <em>depth-first</em>, the elements in the stream
      * are {@link Path} objects that are obtained as if by {@link
      * Path#resolve(Path) resolving} the relative path against {@code start}.
      *
      * <p> The {@code stream} walks the file tree as elements are consumed.
-     * The {@code CloseableStream} returned is guaranteed to have at least one
+     * The {@code Stream} returned is guaranteed to have at least one
      * element, the starting file itself. For each file visited, the stream
      * attempts to read its {@link BasicFileAttributes}. If the file is a
      * directory and can be opened successfully, entries in the directory, and
@@ -3371,7 +3398,7 @@
      * (or directory), then it is ignored and not included in the stream.
      *
      * <p> When not using the try-with-resources construct, then the stream's
-     * {@link CloseableStream#close close} method should be invoked after the
+     * {@link Stream#close close} method should be invoked after the
      * operation is completed so as to free any resources held for the open
      * directory. Operate the stream after it is closed will throw an
      * {@link java.lang.IllegalStateException}.
@@ -3388,7 +3415,7 @@
      * @param   options
      *          options to configure the traversal
      *
-     * @return  the {@link CloseableStream} of {@link Path}
+     * @return  the {@link Stream} of {@link Path}
      *
      * @throws  IllegalArgumentException
      *          if the {@code maxDepth} parameter is negative
@@ -3401,21 +3428,23 @@
      *          if an I/O error is thrown when accessing the starting file.
      * @since   1.8
      */
-    public static CloseableStream<Path> walk(Path start, int maxDepth,
-                                             FileVisitOption... options)
-        throws IOException
-    {
+    @MayHoldCloseableResource.HoldsResource
+    public static Stream<Path> walk(Path start, int maxDepth,
+                                    FileVisitOption... options)
+            throws IOException {
         FileTreeIterator iterator = new FileTreeIterator(start, maxDepth, options);
-
-        Stream<Path> s = StreamSupport.stream(
-                Spliterators.spliteratorUnknownSize(iterator, Spliterator.DISTINCT),
-                false).
-                map(entry -> entry.file());
-        return new DelegatingCloseableStream<>(iterator, s);
+        try {
+            return StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, Spliterator.DISTINCT), false)
+                                .onClose(iterator::close)
+                                .map(entry -> entry.file());
+        } catch (Error|RuntimeException e) {
+            iterator.close();
+            throw e;
+        }
     }
 
     /**
-     * Return a {@code CloseableStream} that is lazily populated with {@code
+     * Return a {@code Stream} that is lazily populated with {@code
      * Path} by walking the file tree rooted at a given starting file.  The
      * file tree is traversed <em>depth-first</em>, the elements in the stream
      * are {@link Path} objects that are obtained as if by {@link
@@ -3433,7 +3462,7 @@
      * @param   options
      *          options to configure the traversal
      *
-     * @return  the {@link CloseableStream} of {@link Path}
+     * @return  the {@link Stream} of {@link Path}
      *
      * @throws  SecurityException
      *          If the security manager denies access to the starting file.
@@ -3446,15 +3475,15 @@
      * @see     #walk(Path, int, FileVisitOption...)
      * @since   1.8
      */
-    public static CloseableStream<Path> walk(Path start,
-                                             FileVisitOption... options)
-        throws IOException
-    {
+    @MayHoldCloseableResource.HoldsResource
+    public static Stream<Path> walk(Path start,
+                                    FileVisitOption... options)
+            throws IOException {
         return walk(start, Integer.MAX_VALUE, options);
     }
 
     /**
-     * Return a {@code CloseableStream} that is lazily populated with {@code
+     * Return a {@code Stream} that is lazily populated with {@code
      * Path} by searching for files in a file tree rooted at a given starting
      * file.
      *
@@ -3463,7 +3492,7 @@
      * {@link BiPredicate} is invoked with its {@link Path} and {@link
      * BasicFileAttributes}. The {@code Path} object is obtained as if by
      * {@link Path#resolve(Path) resolving} the relative path against {@code
-     * start} and is only included in the returned {@link CloseableStream} if
+     * start} and is only included in the returned {@link Stream} if
      * the {@code BiPredicate} returns true. Compare to calling {@link
      * java.util.stream.Stream#filter filter} on the {@code Stream}
      * returned by {@code walk} method, this method may be more efficient by
@@ -3484,7 +3513,7 @@
      * @param   options
      *          options to configure the traversal
      *
-     * @return  the {@link CloseableStream} of {@link Path}
+     * @return  the {@link Stream} of {@link Path}
      *
      * @throws  IllegalArgumentException
      *          if the {@code maxDepth} parameter is negative
@@ -3499,24 +3528,26 @@
      * @see     #walk(Path, int, FileVisitOption...)
      * @since   1.8
      */
-    public static CloseableStream<Path> find(Path start,
-                                             int maxDepth,
-                                             BiPredicate<Path, BasicFileAttributes> matcher,
-                                             FileVisitOption... options)
-        throws IOException
-    {
+    @MayHoldCloseableResource.HoldsResource
+    public static Stream<Path> find(Path start,
+                                    int maxDepth,
+                                    BiPredicate<Path, BasicFileAttributes> matcher,
+                                    FileVisitOption... options)
+            throws IOException {
         FileTreeIterator iterator = new FileTreeIterator(start, maxDepth, options);
-
-        Stream<Path> s = StreamSupport.stream(
-                Spliterators.spliteratorUnknownSize(iterator, Spliterator.DISTINCT),
-                false).
-                filter(entry -> matcher.test(entry.file(), entry.attributes())).
-                map(entry -> entry.file());
-        return new DelegatingCloseableStream<>(iterator, s);
+        try {
+            return StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, Spliterator.DISTINCT), false)
+                                .onClose(iterator::close)
+                                .filter(entry -> matcher.test(entry.file(), entry.attributes()))
+                                .map(entry -> entry.file());
+        } catch (Error|RuntimeException e) {
+            iterator.close();
+            throw e;
+        }
     }
 
     /**
-     * Read all lines from a file as a {@code CloseableStream}.  Unlike {@link
+     * Read all lines from a file as a {@code Stream}.  Unlike {@link
      * #readAllLines(Path, Charset) readAllLines}, this method does not read
      * all lines into a {@code List}, but instead populates lazily as the stream
      * is consumed.
@@ -3534,7 +3565,7 @@
      * it is also wrapped as an {@code UncheckedIOException}.
      *
      * <p> When not using the try-with-resources construct, then stream's
-     * {@link CloseableStream#close close} method should be invoked after
+     * {@link Stream#close close} method should be invoked after
      * operation is completed so as to free any resources held for the open
      * file.
      *
@@ -3543,7 +3574,7 @@
      * @param   cs
      *          the charset to use for decoding
      *
-     * @return  the lines from the file as a {@code CloseableStream}
+     * @return  the lines from the file as a {@code Stream}
      *
      * @throws  IOException
      *          if an I/O error occurs opening the file
@@ -3557,10 +3588,14 @@
      * @see     java.io.BufferedReader#lines()
      * @since   1.8
      */
-    public static CloseableStream<String> lines(Path path, Charset cs)
-        throws IOException
-    {
+    @MayHoldCloseableResource.HoldsResource
+    public static Stream<String> lines(Path path, Charset cs) throws IOException {
         BufferedReader br = Files.newBufferedReader(path, cs);
-        return new DelegatingCloseableStream<>(br, br.lines());
+        try {
+            return br.lines().onClose(asUncheckedRunnable(br));
+        } catch (Error|RuntimeException e) {
+            br.close();
+            throw e;
+        }
     }
 }
--- a/src/share/classes/java/util/ArrayDeque.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/src/share/classes/java/util/ArrayDeque.java	Wed Aug 14 15:53:13 2013 -0700
@@ -888,6 +888,19 @@
             elements[i] = s.readObject();
     }
 
+    /**
+     * Creates a <em><a href="Spliterator.html#binding">late-binding</a></em>
+     * and <em>fail-fast</em> {@link Spliterator} over the elements in this
+     * deque.
+     *
+     * <p>The {@code Spliterator} reports {@link Spliterator#SIZED},
+     * {@link Spliterator#SUBSIZED}, {@link Spliterator#ORDERED}, and
+     * {@link Spliterator#NONNULL}.  Overriding implementations should document
+     * the reporting of additional characteristic values.
+     *
+     * @return a {@code Spliterator} over the elements in this deque
+     * @since 1.8
+     */
     public Spliterator<E> spliterator() {
         return new DeqSpliterator<E>(this, -1, -1);
     }
--- a/src/share/classes/java/util/ArrayList.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/src/share/classes/java/util/ArrayList.java	Wed Aug 14 15:53:13 2013 -0700
@@ -1238,6 +1238,20 @@
         }
     }
 
+    /**
+     * Creates a <em><a href="Spliterator.html#binding">late-binding</a></em>
+     * and <em>fail-fast</em> {@link Spliterator} over the elements in this
+     * list.
+     *
+     * <p>The {@code Spliterator} reports {@link Spliterator#SIZED},
+     * {@link Spliterator#SUBSIZED}, and {@link Spliterator#ORDERED}.
+     * Overriding implementations should document the reporting of additional
+     * characteristic values.
+     *
+     * @return a {@code Spliterator} over the elements in this list
+     * @since 1.8
+     */
+    @Override
     public Spliterator<E> spliterator() {
         return new ArrayListSpliterator<>(this, 0, -1, 0);
     }
--- a/src/share/classes/java/util/Arrays.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/src/share/classes/java/util/Arrays.java	Wed Aug 14 15:53:13 2013 -0700
@@ -1568,7 +1568,7 @@
     // Parallel prefix
 
     /**
-     * Cumulates, in parallel, each element of the given array in place,
+     * Cumulates in parallel each element of the given array in place,
      * using the supplied function. For example if the array initially
      * holds {@code [2, 1, 0, 3]} and the operation performs addition,
      * then upon return the array holds {@code [2, 3, 3, 6]}.
@@ -1613,7 +1613,7 @@
     }
 
     /**
-     * Cumulates, in parallel, each element of the given array in place,
+     * Cumulates in parallel each element of the given array in place,
      * using the supplied function. For example if the array initially
      * holds {@code [2, 1, 0, 3]} and the operation performs addition,
      * then upon return the array holds {@code [2, 3, 3, 6]}.
@@ -1656,19 +1656,16 @@
     }
 
     /**
-     * Cumulates, in parallel, each element of the given array in place,
+     * Cumulates in parallel each element of the given array in place,
      * using the supplied function. For example if the array initially
-     * holds {@code [2.0, 1.0, 0.0, 3.0]} and the operation performs addition,
-     * then upon return the array holds {@code [2.0, 3.0, 3.0, 6.0]}.
+     * holds {@code [2, 1, 0, 3]} and the operation performs addition,
+     * then upon return the array holds {@code [2, 3, 3, 6]}.
      * Parallel prefix computation is usually more efficient than
      * sequential loops for large arrays.
      *
-     * <p> Because floating-point operations may not be strictly associative,
-     * the returned result may not be identical to the value that would be
-     * obtained if the operation was performed sequentially.
-     *
      * @param array the array, which is modified in-place by this method
-     * @param op a side-effect-free function to perform the cumulation
+     * @param op a side-effect-free, associative function to perform the
+     * cumulation
      * @throws NullPointerException if the specified array or function is null
      * @since 1.8
      */
@@ -1702,7 +1699,7 @@
     }
 
     /**
-     * Cumulates, in parallel, each element of the given array in place,
+     * Cumulates in parallel each element of the given array in place,
      * using the supplied function. For example if the array initially
      * holds {@code [2, 1, 0, 3]} and the operation performs addition,
      * then upon return the array holds {@code [2, 3, 3, 6]}.
--- a/src/share/classes/java/util/Collection.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/src/share/classes/java/util/Collection.java	Wed Aug 14 15:53:13 2013 -0700
@@ -504,7 +504,10 @@
      *
      * <p>The returned {@code Spliterator} must report the characteristic
      * {@link Spliterator#SIZED}; implementations should document any additional
-     * characteristic values reported by the returned Spliterator.
+     * characteristic values reported by the returned spliterator.  If
+     * this collection contains no elements then the returned spliterator is
+     * only required to report {@link Spliterator#SIZED} and is not required to
+     * report additional characteristic values (if any).
      *
      * <p>The default implementation should be overridden by subclasses that
      * can return a more efficient spliterator.  In order to
@@ -535,9 +538,18 @@
      * The returned {@code Spliterator} additionally reports
      * {@link Spliterator#SUBSIZED}.
      *
+     * <p>If a spliterator covers no elements then the reporting of additional
+     * characteristic values, beyond that of {@code SIZED} and {@code SUBSIZED},
+     * does not aid clients to control, specialize or simplify computation.
+     * However, this does enable shared use of an immutable and empty
+     * spliterator instance (see {@link Spliterators#emptySpliterator()} for
+     * empty collections, and enables clients to determine if such a spliterator
+     * covers no elements.
+     *
      * @return a {@code Spliterator} over the elements in this collection
      * @since 1.8
      */
+    @Override
     default Spliterator<E> spliterator() {
         return Spliterators.spliterator(this, 0);
     }
--- a/src/share/classes/java/util/Collections.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/src/share/classes/java/util/Collections.java	Wed Aug 14 15:53:13 2013 -0700
@@ -27,7 +27,6 @@
 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.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,14 @@
         public Spliterator<E> spliterator() {
             return (Spliterator<E>)c.spliterator();
         }
-
+        @Override
+        public Stream<E> stream() {
+            return (Stream<E>)c.stream();
+        }
+        @Override
+        public Stream<E> parallelStream() {
+            return (Stream<E>)c.parallelStream();
+        }
     }
 
     /**
@@ -2009,8 +2016,8 @@
      * through the returned collection.<p>
      *
      * 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}:
      * <pre>
      *  Collection c = Collections.synchronizedCollection(myCollection);
      *     ...
@@ -2120,6 +2127,14 @@
         public Spliterator<E> spliterator() {
             return c.spliterator(); // Must be manually synched by user!
         }
+        @Override
+        public Stream<E> stream() {
+            return c.stream(); // Must be manually synched by user!
+        }
+        @Override
+        public Stream<E> parallelStream() {
+            return c.parallelStream(); // Must be manually synched by user!
+        }
         private void writeObject(ObjectOutputStream s) throws IOException {
             synchronized (mutex) {s.defaultWriteObject();}
         }
@@ -3172,6 +3187,10 @@
         }
         @Override
         public Spliterator<E> spliterator() {return c.spliterator();}
+        @Override
+        public Stream<E> stream()           {return c.stream();}
+        @Override
+        public Stream<E> parallelStream()   {return c.parallelStream();}
     }
 
     /**
@@ -5097,6 +5116,22 @@
                                                    ") > toIndex(" + toIndex + ")");
             return new CopiesList<>(toIndex - fromIndex, element);
         }
+
+        // Override default methods in Collection
+        @Override
+        public Stream<E> stream() {
+            return IntStream.range(0, n).mapToObj(i -> element);
+        }
+
+        @Override
+        public Stream<E> parallelStream() {
+            return IntStream.range(0, n).parallel().mapToObj(i -> element);
+        }
+
+        @Override
+        public Spliterator<E> spliterator() {
+            return stream().spliterator();
+        }
     }
 
     /**
@@ -5504,6 +5539,10 @@
 
         @Override
         public Spliterator<E> spliterator() {return s.spliterator();}
+        @Override
+        public Stream<E> stream()           {return s.stream();}
+        @Override
+        public Stream<E> parallelStream()   {return s.parallelStream();}
 
         private static final long serialVersionUID = 2454657854757543876L;
 
@@ -5569,10 +5608,14 @@
         @Override
         public void forEach(Consumer<? super E> action) {q.forEach(action);}
         @Override
-        public Spliterator<E> spliterator() {return q.spliterator();}
-        @Override
         public boolean removeIf(Predicate<? super E> filter) {
             return q.removeIf(filter);
         }
+        @Override
+        public Spliterator<E> spliterator() {return q.spliterator();}
+        @Override
+        public Stream<E> stream()           {return q.stream();}
+        @Override
+        public Stream<E> parallelStream()   {return q.parallelStream();}
     }
 }
--- a/src/share/classes/java/util/HashSet.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/src/share/classes/java/util/HashSet.java	Wed Aug 14 15:53:13 2013 -0700
@@ -312,6 +312,18 @@
         }
     }
 
+    /**
+     * Creates a <em><a href="Spliterator.html#binding">late-binding</a></em>
+     * and <em>fail-fast</em> {@link Spliterator} over the elements in this
+     * set.
+     *
+     * <p>The {@code Spliterator} reports {@link Spliterator#SIZED} and
+     * {@link Spliterator#DISTINCT}.  Overriding implementations should document
+     * the reporting of additional characteristic values.
+     *
+     * @return a {@code Spliterator} over the elements in this set
+     * @since 1.8
+     */
     public Spliterator<E> spliterator() {
         return new HashMap.KeySpliterator<E,Object>(map, 0, -1, 0, 0);
     }
--- a/src/share/classes/java/util/LinkedHashMap.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/src/share/classes/java/util/LinkedHashMap.java	Wed Aug 14 15:53:13 2013 -0700
@@ -129,10 +129,20 @@
  * exception for its correctness:   <i>the fail-fast behavior of iterators
  * should be used only to detect bugs.</i>
  *
+ * <p>The spliterators returned by the spliterator method of the collections
+ * returned by all of this class's collection view methods are
+ * <em><a href="Spliterator.html#binding">late-binding</a></em>,
+ * <em>fail-fast</em>, and additionally report {@link Spliterator#ORDERED}.
+ *
  * <p>This class is a member of the
  * <a href="{@docRoot}/../technotes/guides/collections/index.html">
  * Java Collections Framework</a>.
  *
+ * @implNote
+ * The spliterators returned by the spliterator method of the collections
+ * returned by all of this class's collection view methods are created from
+ * the iterators of the corresponding collections.
+ *
  * @param <K> the type of keys maintained by this map
  * @param <V> the type of mapped values
  *
--- a/src/share/classes/java/util/LinkedHashSet.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/src/share/classes/java/util/LinkedHashSet.java	Wed Aug 14 15:53:13 2013 -0700
@@ -170,13 +170,23 @@
     }
 
     /**
-     * Creates a {@code Spliterator}, over the elements in this set, that
-     * reports {@code SIZED}, {@code DISTINCT} and {@code ORDERED}.
-     * Overriding implementations are expected to document if the
-     * {@code Spliterator} reports any additional and relevant characteristic
-     * values.
+     * Creates a <em><a href="Spliterator.html#binding">late-binding</a></em>
+     * and <em>fail-fast</em> {@code Spliterator} over the elements in this set.
+     *
+     * <p>The {@code Spliterator} reports {@link Spliterator#SIZED},
+     * {@link Spliterator#DISTINCT}, and {@code ORDERED}.  Implementations
+     * should document the reporting of additional characteristic values.
+     *
+     * @implNote
+     * The implementation creates a
+     * <em><a href="Spliterator.html#binding">late-binding</a></em> spliterator
+     * from the set's {@code Iterator}.  The spliterator inherits the
+     * <em>fail-fast</em> properties of the set's iterator.
+     * The created {@code Spliterator} additionally reports
+     * {@link Spliterator#SUBSIZED}.
      *
      * @return a {@code Spliterator} over the elements in this set
+     * @since 1.8
      */
     @Override
     public Spliterator<E> spliterator() {
--- a/src/share/classes/java/util/LinkedList.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/src/share/classes/java/util/LinkedList.java	Wed Aug 14 15:53:13 2013 -0700
@@ -1149,6 +1149,23 @@
             linkLast((E)s.readObject());
     }
 
+    /**
+     * Creates a <em><a href="Spliterator.html#binding">late-binding</a></em>
+     * and <em>fail-fast</em> {@link Spliterator} over the elements in this
+     * list.
+     *
+     * <p>The {@code Spliterator} reports {@link Spliterator#SIZED} and
+     * {@link Spliterator#ORDERED}.  Overriding implementations should document
+     * the reporting of additional characteristic values.
+     *
+     * @implNote
+     * The {@code Spliterator} additionally reports {@link Spliterator#SUBSIZED}
+     * and implements {@code trySplit} to permit limited parallelism..
+     *
+     * @return a {@code Spliterator} over the elements in this list
+     * @since 1.8
+     */
+    @Override
     public Spliterator<E> spliterator() {
         return new LLSpliterator<E>(this, -1, 0);
     }
--- a/src/share/classes/java/util/List.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/src/share/classes/java/util/List.java	Wed Aug 14 15:53:13 2013 -0700
@@ -671,7 +671,7 @@
      * The default implementation creates a
      * <em><a href="Spliterator.html#binding">late-binding</a></em> spliterator
      * from the list's {@code Iterator}.  The spliterator inherits the
-     * <em>fail-fast</em> properties of the collection's iterator.
+     * <em>fail-fast</em> properties of the list's iterator.
      *
      * @implNote
      * The created {@code Spliterator} additionally reports
--- a/src/share/classes/java/util/Map.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/src/share/classes/java/util/Map.java	Wed Aug 14 15:53:13 2013 -0700
@@ -579,10 +579,12 @@
     }
 
     /**
-     * Performs the given action on each entry in this map, in the order entries
-     * are returned by an entry set iterator (which may be unspecified), until
-     * all entries have been processed or the action throws an {@code Exception}.
-     * Exceptions thrown by the action are relayed to the caller.
+     * Performs the given action on each entry in this map until all entries
+     * have been processed or the action throws an {@code Exception}.
+     * Exceptions thrown by the action are relayed to the caller. The entries
+     * will be processed in the same order as the entry set iterator unless that
+     * order is unspecified in which case implementations may use an order which
+     * differs from the entry set iterator.
      *
      * <p>The default implementation should be overridden by implementations if
      * they can provide a more performant implementation than an iterator-based
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/MayHoldCloseableResource.java	Wed Aug 14 15:53:13 2013 -0700
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  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.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * An object that may (but need not) hold one or more references to
+ * resources that will be released when closed.  Such objects may be
+ * used with try-with-resources or related {@code try...finally}
+ * constructions that ensure they are closed as soon as they are no
+ * longer needed.  Interface {@code MayHoldCloseableResource} indicates that
+ * only a minority of usages warrant resource control constructions:
+ * those specialized to known resource-bearing instances, or those
+ * that must operate in complete generality.
+ *
+ * <p>For example, most usages of the {@link java.util.stream.Stream}
+ * classes operate on data sources such as an array, {@code
+ * Collection}, or generator function that do not require or benefit
+ * from explicit resource control.  However, some uses of IO channels
+ * as data sources do.
+ *
+ * <p>Annotation {@link HoldsResource} may be used to guide users or static
+ * analysis tools to deciding whether resource-control constructions are
+ * warranted when using particular instantiations of
+ * {@code MayHoldCloseableResource}.
+ *
+ * @see AutoCloseable
+ * @see HoldsResource
+ */
+public interface MayHoldCloseableResource extends AutoCloseable {
+    /**
+     * Closes this resource, relinquishing any underlying resources.
+     * This method is invoked automatically on objects managed by the
+     * {@code try}-with-resources statement.
+     *
+     * Implementers of this interface are strongly encouraged
+     * to make their {@code close} methods idempotent.
+     *
+     * @see AutoCloseable#close()
+     */
+    @Override
+    void close();
+
+    /**
+     * Indicates that a variable holding a {@code MayHoldCloseableResource} or
+     * a method returning a {@code MayHoldCloseableResource} definitely does
+     * hold a closeable resource.
+     */
+    @Retention(RetentionPolicy.CLASS)
+    @Documented
+    @interface HoldsResource { }
+}
--- a/src/share/classes/java/util/PrimitiveIterator.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/src/share/classes/java/util/PrimitiveIterator.java	Wed Aug 14 15:53:13 2013 -0700
@@ -56,12 +56,12 @@
  * primitive values occur when operating on primitive subtype specializations.
  *
  * @param <T> the type of elements returned by this PrimitiveIterator.  The
- *        type must be a wrapper type for a primitive type, such as
- *        {@code Integer} for the primitive {@code int} type.
+ * type must be a wrapper type for a primitive type, such as {@code Integer}
+ * for the primitive {@code int} type.
  * @param <T_CONS> the type of primitive consumer.  The type must be a
- *        primitive specialization of {@link java.util.function.Consumer} for
- *        {@code T}, such as {@link java.util.function.IntConsumer} for
- *        {@code Integer}.
+ * primitive specialization of {@link java.util.function.Consumer} for
+ * {@code T}, such as {@link java.util.function.IntConsumer} for
+ * {@code Integer}.
  *
  * @since 1.8
  */
--- a/src/share/classes/java/util/PriorityQueue.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/src/share/classes/java/util/PriorityQueue.java	Wed Aug 14 15:53:13 2013 -0700
@@ -795,6 +795,19 @@
         heapify();
     }
 
+    /**
+     * Creates a <em><a href="Spliterator.html#binding">late-binding</a></em>
+     * and <em>fail-fast</em> {@link Spliterator} over the elements in this
+     * queue.
+     *
+     * <p>The {@code Spliterator} reports {@link Spliterator#SIZED},
+     * {@link Spliterator#SUBSIZED}, and {@link Spliterator#NONNULL}.
+     * Overriding implementations should document the reporting of additional
+     * characteristic values.
+     *
+     * @return a {@code Spliterator} over the elements in this queue
+     * @since 1.8
+     */
     public final Spliterator<E> spliterator() {
         return new PriorityQueueSpliterator<E>(this, 0, -1, 0);
     }
--- a/src/share/classes/java/util/Random.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/src/share/classes/java/util/Random.java	Wed Aug 14 15:53:13 2013 -0700
@@ -26,9 +26,13 @@
 package java.util;
 import java.io.*;
 import java.util.concurrent.atomic.AtomicLong;
+import java.util.function.DoubleConsumer;
+import java.util.function.IntConsumer;
+import java.util.function.LongConsumer;
 import java.util.stream.DoubleStream;
 import java.util.stream.IntStream;
 import java.util.stream.LongStream;
+import java.util.stream.StreamSupport;
 
 import sun.misc.Unsafe;
 
@@ -85,6 +89,13 @@
     private static final long addend = 0xBL;
     private static final long mask = (1L << 48) - 1;
 
+    private static final double DOUBLE_UNIT = 1.0 / (1L << 53);
+
+    // IllegalArgumentException messages
+    static final String BadBound = "bound must be positive";
+    static final String BadRange = "bound must be greater than origin";
+    static final String BadSize  = "size must be non-negative";
+
     /**
      * Creates a new random number generator. This constructor sets
      * the seed of the random number generator to a value very likely
@@ -222,6 +233,85 @@
     }
 
     /**
+     * The form of nextLong used by LongStream Spliterators.  If
+     * origin is greater than bound, acts as unbounded form of
+     * nextLong, else as bounded form.
+     *
+     * @param origin the least value, unless greater than bound
+     * @param bound the upper bound (exclusive), must not equal origin
+     * @return a pseudorandom value
+     */
+    final long internalNextLong(long origin, long bound) {
+        long r = nextLong();
+        if (origin < bound) {
+            long n = bound - origin, m = n - 1;
+            if ((n & m) == 0L)  // power of two
+                r = (r & m) + origin;
+            else if (n > 0L) {  // reject over-represented candidates
+                for (long u = r >>> 1;            // ensure nonnegative
+                     u + m - (r = u % n) < 0L;    // rejection check
+                     u = nextLong() >>> 1) // retry
+                    ;
+                r += origin;
+            }
+            else {              // range not representable as long
+                while (r < origin || r >= bound)
+                    r = nextLong();
+            }
+        }
+        return r;
+    }
+
+    /**
+     * The form of nextInt used by IntStream Spliterators.
+     * 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) {
+        if (origin < bound) {
+            int r = next(31);
+            int n = bound - origin, m = n - 1;
+            if ((n & m) == 0)
+                r = (int)((n * (long)r) >> 31) + origin;
+            else if (n > 0) {
+                for (int u = r;
+                     u - (r = u % n) + m < 0;
+                     u = next(31))
+                    ;
+                r += origin;
+            }
+            else {
+                while (r < origin || r >= bound)
+                    r = next(32);
+            }
+            return r;
+        }
+        else {
+            return next(32);
+        }
+    }
+
+    /**
+     * The form of nextDouble used by DoubleStream Spliterators.
+     *
+     * @param origin the least value, unless greater than bound
+     * @param bound the upper bound (exclusive), must not equal origin
+     * @return a pseudorandom value
+     */
+    final double internalNextDouble(double origin, double bound) {
+        double r = nextDouble();
+        if (origin < bound) {
+            r = r * (bound - origin) + origin;
+            if (r >= bound) // correct for rounding
+                r = Double.longBitsToDouble(Double.doubleToLongBits(bound) - 1);
+        }
+        return r;
+    }
+
+    /**
      * Returns the next pseudorandom, uniformly distributed {@code int}
      * value from this random number generator's sequence. The general
      * contract of {@code nextInt} is that one {@code int} value is
@@ -289,7 +379,7 @@
      * greatly increases the length of the sequence of values returned by
      * successive calls to this method if n is a small power of two.
      *
-     * @param n the bound on the random number to be returned.  Must be
+     * @param bound the bound on the random number to be returned.  Must be
      *        positive.
      * @return the next pseudorandom, uniformly distributed {@code int}
      *         value between {@code 0} (inclusive) and {@code n} (exclusive)
@@ -297,20 +387,39 @@
      * @throws IllegalArgumentException if n is not positive
      * @since 1.2
      */
+    public int nextInt(int bound) {
+        if (bound <= 0)
+            throw new IllegalArgumentException(BadBound);
 
-    public int nextInt(int n) {
-        if (n <= 0)
-            throw new IllegalArgumentException("n must be positive");
+        int r = next(31);
+        int m = bound - 1;
+        if ((bound & m) == 0)  // i.e., bound is a power of 2
+            r = (int)((bound * (long)r) >> 31);
+        else {
+            for (int u = r;
+                 u - (r = u % bound) + m < 0;
+                 u = next(31))
+                ;
+        }
+        return r;
+    }
 
-        if ((n & -n) == n)  // i.e., n is a power of 2
-            return (int)((n * (long)next(31)) >> 31);
-
-        int bits, val;
-        do {
-            bits = next(31);
-            val = bits % n;
-        } while (bits - val + (n-1) < 0);
-        return val;
+    /**
+     * 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) {
+        // @@@ Document algorithm as for other int methods?
+        if (origin >= bound)
+            throw new IllegalArgumentException(BadRange);
+        return internalNextInt(origin, bound);
     }
 
     /**
@@ -338,6 +447,40 @@
     }
 
     /**
+     * Returns a pseudorandom {@code long} value between zero (inclusive)
+     * and the specified bound (exclusive).
+     *
+     * @param bound the bound on the random number to be returned.  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);
+        return internalNextLong(0, bound);
+    }
+
+    /**
+     * 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 the next pseudorandom, uniformly distributed
      * {@code boolean} value from this random number generator's
      * sequence. The general contract of {@code nextBoolean} is that one
@@ -442,8 +585,42 @@
      * @see Math#random
      */
     public double nextDouble() {
-        return (((long)(next(26)) << 27) + next(27))
-            / (double)(1L << 53);
+        return (((long)(next(26)) << 27) + next(27)) * DOUBLE_UNIT;
+    }
+
+    /**
+     * Returns a pseudorandom {@code double} value between 0.0
+     * (inclusive) and the specified bound (exclusive).
+     *
+     * @param bound the bound on the random number to be returned.  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 = nextDouble() * 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
+     * @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);
     }
 
     private double nextNextGaussian;
@@ -513,57 +690,430 @@
         }
     }
 
+    // stream methods, coded in a way intended to better isolate for
+    // maintenance purposes the small differences across forms.
+
     /**
-     * Returns a stream of pseudorandom, uniformly distributed
-     * {@code integer} values from this random number generator's
-     * sequence. Values are obtained as needed by calling
-     * {@link #nextInt()}.
+     * Returns a stream producing the given {@code streamSize} number of
+     * pseudorandom {@code int} values.
      *
-     * @return an infinite stream of {@code integer} values
-     * @since 1.8
+     * @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.
+     *
+     * @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 IntStream.generate(this::nextInt);
+        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, each conforming to the given
+     * origin and bound.
+     *
+     * @param streamSize the number of values to generate
+     * @param randomNumberOrigin the origin of each random value
+     * @param randomNumberBound the bound of each random value
+     * @return a stream of pseudorandom {@code int} values,
+     *         each with the given origin and bound
+     * @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, each conforming to the given origin and bound.
+     *
+     * @implNote This method is implemented to be equivalent to {@code
+     * ints(Long.MAX_VALUE, randomNumberOrigin, randomNumberBound)}.
+     *
+     * @param randomNumberOrigin the origin of each random value
+     * @param randomNumberBound the bound of each random value
+     * @return a stream of pseudorandom {@code int} values,
+     *         each with the given origin and bound
+     * @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.
+     *
+     * @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.
+     *
+     * @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, each conforming to the
+     * given origin and bound.
+     *
+     * @param streamSize the number of values to generate
+     * @param randomNumberOrigin the origin of each random value
+     * @param randomNumberBound the bound of each random value
+     * @return a stream of pseudorandom {@code long} values,
+     *         each with the given origin and bound
+     * @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, each conforming to the given origin and bound.
+     *
+     * @implNote This method is implemented to be equivalent to {@code
+     * longs(Long.MAX_VALUE, randomNumberOrigin, randomNumberBound)}.
+     *
+     * @param randomNumberOrigin the origin of each random value
+     * @param randomNumberBound the bound of each random value
+     * @return a stream of pseudorandom {@code long} values,
+     *         each with the given origin and bound
+     * @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, each between zero
+     * (inclusive) and one (exclusive).
+     *
+     * @param streamSize the number of values to generate
+     * @return a stream of {@code double} values
+     * @throws IllegalArgumentException if {@code streamSize} is
+     *         less than zero
+     */
+    public DoubleStream doubles(long streamSize) {
+        if (streamSize < 0L)
+            throw new IllegalArgumentException(BadSize);
+        return StreamSupport.doubleStream
+                (new RandomDoublesSpliterator
+                         (this, 0L, streamSize, Double.MAX_VALUE, 0.0),
+                 false);
+    }
+
+    /**
+     * Returns an effectively unlimited stream of pseudorandom {@code
+     * double} values, each between zero (inclusive) and one
+     * (exclusive).
+     *
+     * @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 of pseudorandom, uniformly distributed
-     * {@code long} values from this random number generator's
-     * sequence. Values are obtained as needed by calling
-     * {@link #nextLong()}.
+     * Returns a stream producing the given {@code streamSize} number of
+     * pseudorandom {@code double} values, each conforming to the
+     * given origin and bound.
      *
-     * @return an infinite stream of {@code long} values
-     * @since 1.8
+     * @param streamSize the number of values to generate
+     * @param randomNumberOrigin the origin of each random value
+     * @param randomNumberBound the bound of each random value
+     * @return a stream of pseudorandom {@code double} values,
+     * each with the given origin and bound
+     * @throws IllegalArgumentException if {@code streamSize} is
+     * less than zero
+     * @throws IllegalArgumentException if {@code randomNumberOrigin}
+     *         is greater than or equal to {@code randomNumberBound}
      */
-    public LongStream longs() {
-        return LongStream.generate(this::nextLong);
+    public DoubleStream doubles(long streamSize, double randomNumberOrigin,
+                                double randomNumberBound) {
+        if (streamSize < 0L)
+            throw new IllegalArgumentException(BadSize);
+        if (!(randomNumberOrigin < randomNumberBound))
+            throw new IllegalArgumentException(BadRange);
+        return StreamSupport.doubleStream
+                (new RandomDoublesSpliterator
+                         (this, 0L, streamSize, randomNumberOrigin, randomNumberBound),
+                 false);
+    }
+
+    /**
+     * Returns an effectively unlimited stream of pseudorandom {@code
+     * double} values, each conforming to the given origin and bound.
+     *
+     * @implNote This method is implemented to be equivalent to {@code
+     * doubles(Long.MAX_VALUE, randomNumberOrigin, randomNumberBound)}.
+     *
+     * @param randomNumberOrigin the origin of each random value
+     * @param randomNumberBound the bound of each random value
+     * @return a stream of pseudorandom {@code double} values,
+     * each with the given origin and bound
+     * @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);
     }
 
     /**
-     * Returns a stream of pseudorandom, uniformly distributed
-     * {@code double} values between {@code 0.0} and {@code 1.0}
-     * from this random number generator's sequence. Values are
-     * obtained as needed by calling {@link #nextDouble()}.
-     *
-     * @return an infinite stream of {@code double} values
-     * @since 1.8
+     * 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.
      */
-    public DoubleStream doubles() {
-        return DoubleStream.generate(this::nextDouble);
+    static final class RandomIntsSpliterator implements Spliterator.OfInt {
+        final Random rng;
+        long index;
+        final long fence;
+        final int origin;
+        final int bound;
+        RandomIntsSpliterator(Random rng, long index, long fence,
+                              int origin, int bound) {
+            this.rng = rng; this.index = index; this.fence = fence;
+            this.origin = origin; this.bound = bound;
+        }
+
+        public RandomIntsSpliterator trySplit() {
+            long i = index, m = (i + fence) >>> 1;
+            return (m <= i) ? null :
+                   new RandomIntsSpliterator(rng, i, index = m, origin, bound);
+        }
+
+        public long estimateSize() {
+            return fence - index;
+        }
+
+        public int characteristics() {
+            return (Spliterator.SIZED | Spliterator.SUBSIZED |
+                    Spliterator.NONNULL | Spliterator.IMMUTABLE);
+        }
+
+        public boolean tryAdvance(IntConsumer consumer) {
+            if (consumer == null) throw new NullPointerException();
+            long i = index, f = fence;
+            if (i < f) {
+                consumer.accept(rng.internalNextInt(origin, bound));
+                index = i + 1;
+                return true;
+            }
+            return false;
+        }
+
+        public void forEachRemaining(IntConsumer consumer) {
+            if (consumer == null) throw new NullPointerException();
+            long i = index, f = fence;
+            if (i < f) {
+                index = f;
+                Random r = rng;
+                int o = origin, b = bound;
+                do {
+                    consumer.accept(r.internalNextInt(o, b));
+                } while (++i < f);
+            }
+        }
     }
 
     /**
-     * Returns a stream of pseudorandom, Gaussian ("normally")
-     * distributed {@code double} values with mean {@code 0.0}
-     * and standard deviation {@code 1.0} from this random number
-     * generator's sequence. Values are obtained as needed by
-     * calling {@link #nextGaussian()}.
-     *
-     * @return an infinite stream of {@code double} values
-     * @since 1.8
+     * Spliterator for long streams.
      */
-    public DoubleStream gaussians() {
-        return DoubleStream.generate(this::nextGaussian);
+    static final class RandomLongsSpliterator implements Spliterator.OfLong {
+        final Random rng;
+        long index;
+        final long fence;
+        final long origin;
+        final long bound;
+        RandomLongsSpliterator(Random rng, long index, long fence,
+                               long origin, long bound) {
+            this.rng = rng; this.index = index; this.fence = fence;
+            this.origin = origin; this.bound = bound;
+        }
+
+        public RandomLongsSpliterator trySplit() {
+            long i = index, m = (i + fence) >>> 1;
+            return (m <= i) ? null :
+                   new RandomLongsSpliterator(rng, i, index = m, origin, bound);
+        }
+
+        public long estimateSize() {
+            return fence - index;
+        }
+
+        public int characteristics() {
+            return (Spliterator.SIZED | Spliterator.SUBSIZED |
+                    Spliterator.NONNULL | Spliterator.IMMUTABLE);
+        }
+
+        public boolean tryAdvance(LongConsumer consumer) {
+            if (consumer == null) throw new NullPointerException();
+            long i = index, f = fence;
+            if (i < f) {
+                consumer.accept(rng.internalNextLong(origin, bound));
+                index = i + 1;
+                return true;
+            }
+            return false;
+        }
+
+        public void forEachRemaining(LongConsumer consumer) {
+            if (consumer == null) throw new NullPointerException();
+            long i = index, f = fence;
+            if (i < f) {
+                index = f;
+                Random r = rng;
+                long o = origin, b = bound;
+                do {
+                    consumer.accept(r.internalNextLong(o, b));
+                } while (++i < f);
+            }
+        }
+
+    }
+
+    /**
+     * Spliterator for double streams.
+     */
+    static final class RandomDoublesSpliterator implements Spliterator.OfDouble {
+        final Random rng;
+        long index;
+        final long fence;
+        final double origin;
+        final double bound;
+        RandomDoublesSpliterator(Random rng, long index, long fence,
+                                 double origin, double bound) {
+            this.rng = rng; this.index = index; this.fence = fence;
+            this.origin = origin; this.bound = bound;
+        }
+
+        public RandomDoublesSpliterator trySplit() {
+            long i = index, m = (i + fence) >>> 1;
+            return (m <= i) ? null :
+                   new RandomDoublesSpliterator(rng, i, index = m, origin, bound);
+        }
+
+        public long estimateSize() {
+            return fence - index;
+        }
+
+        public int characteristics() {
+            return (Spliterator.SIZED | Spliterator.SUBSIZED |
+                    Spliterator.NONNULL | Spliterator.IMMUTABLE);
+        }
+
+        public boolean tryAdvance(DoubleConsumer consumer) {
+            if (consumer == null) throw new NullPointerException();
+            long i = index, f = fence;
+            if (i < f) {
+                consumer.accept(rng.internalNextDouble(origin, bound));
+                index = i + 1;
+                return true;
+            }
+            return false;
+        }
+
+        public void forEachRemaining(DoubleConsumer consumer) {
+            if (consumer == null) throw new NullPointerException();
+            long i = index, f = fence;
+            if (i < f) {
+                index = f;
+                Random r = rng;
+                double o = origin, b = bound;
+                do {
+                    consumer.accept(r.internalNextDouble(o, b));
+                } while (++i < f);
+            }
+        }
     }
 
     /**
--- a/src/share/classes/java/util/Set.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/src/share/classes/java/util/Set.java	Wed Aug 14 15:53:13 2013 -0700
@@ -394,7 +394,7 @@
      * The default implementation creates a
      * <em><a href="Spliterator.html#binding">late-binding</a></em> spliterator
      * from the set's {@code Iterator}.  The spliterator inherits the
-     * <em>fail-fast</em> properties of the collection's iterator.
+     * <em>fail-fast</em> properties of the set's iterator.
      *
      * @implNote
      * The created {@code Spliterator} additionally reports
--- a/src/share/classes/java/util/SortedSet.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/src/share/classes/java/util/SortedSet.java	Wed Aug 14 15:53:13 2013 -0700
@@ -238,7 +238,7 @@
      * The default implementation creates a
      * <em><a href="Spliterator.html#binding">late-binding</a></em> spliterator
      * from the sorted set's {@code Iterator}.  The spliterator inherits the
-     * <em>fail-fast</em> properties of the collection's iterator.  The
+     * <em>fail-fast</em> properties of the set's iterator.  The
      * spliterator's comparator is the same as the sorted set's comparator.
      *
      * @implNote
--- a/src/share/classes/java/util/Spliterator.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/src/share/classes/java/util/Spliterator.java	Wed Aug 14 15:53:13 2013 -0700
@@ -74,7 +74,11 @@
  * source prior to binding are reflected when the Spliterator is traversed.
  * After binding a Spliterator should, on a best-effort basis, throw
  * {@link ConcurrentModificationException} if structural interference is
- * detected.  Spliterators that do this are called <em>fail-fast</em>.
+ * detected.  Spliterators that do this are called <em>fail-fast</em>.  The
+ * bulk traversal method ({@link #forEachRemaining forEachRemaining()}) of a
+ * Spliterator may optimize traversal and check for structural interface after
+ * all elements have been traversed, rather than checking per-element and
+ * failing immediately.
  *
  * <p>Spliterators can provide an estimate of the number of remaining elements
  * via the {@link #estimateSize} method.  Ideally, as reflected in characteristic
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/SplittableRandom.java	Wed Aug 14 15:53:13 2013 -0700
@@ -0,0 +1,985 @@
+/*
+ * 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.net.InetAddress;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.Spliterator;
+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 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:
+ *
+ * <ul>
+ *
+ * <li>Series of generated values pass the DieHarder suite testing
+ * independence and uniformity properties of random number generators.
+ * (Most recently validated with <a
+ * href="http://www.phy.duke.edu/~rgb/General/dieharder.php"> version
+ * 3.31.1</a>.) 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 <em>period</em>
+ * (length of any series of generated values before it repeats) is at
+ * least 2<sup>64</sup>. </li>
+ *
+ * <li> 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.  </li>
+ *
+ * <li>Instances of SplittableRandom are <em>not</em> 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()}.
+ *
+ * <li>This class provides additional methods for generating random
+ * streams, that employ the above techniques when used in {@code
+ * stream.parallel()} mode.</li>
+ *
+ * </ul>
+ *
+ * @author  Guy Steele
+ * @author  Doug Lea
+ * @since   1.8
+ */
+public 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 2<sup>14</sup>, 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. 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(mix64((((long)hashedHostAddress()) << 32) ^
+                             System.currentTimeMillis()) ^
+                       mix64(System.nanoTime()));
+
+    /**
+     * Returns hash of local host IP address, if available; else 0.
+     */
+    private static int hashedHostAddress() {
+        try {
+            return InetAddress.getLocalHost().hashCode();
+        } catch (Exception ex) {
+            return 0;
+        }
+    }
+
+    // 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 (2<sup>64</sup>) 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 bound on the random number to be returned.  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 bound on the random number to be returned.  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 bound on the random number to be returned.  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
+     * @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, each conforming to the
+     * given origin and bound.
+     *
+     * @param streamSize the number of values to generate
+     * @param randomNumberOrigin the origin of each random value
+     * @param randomNumberBound the bound of each random value
+     * @return a stream of pseudorandom {@code int} values,
+     *         each with the given origin and bound
+     * @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, each conforming to the given origin and bound.
+     *
+     * @implNote This method is implemented to be equivalent to {@code
+     * ints(Long.MAX_VALUE, randomNumberOrigin, randomNumberBound)}.
+     *
+     * @param randomNumberOrigin the origin of each random value
+     * @param randomNumberBound the bound of each random value
+     * @return a stream of pseudorandom {@code int} values,
+     *         each with the given origin and bound
+     * @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, each conforming to the
+     * given origin and bound.
+     *
+     * @param streamSize the number of values to generate
+     * @param randomNumberOrigin the origin of each random value
+     * @param randomNumberBound the bound of each random value
+     * @return a stream of pseudorandom {@code long} values,
+     *         each with the given origin and bound
+     * @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, each conforming to the given origin and bound.
+     *
+     * @implNote This method is implemented to be equivalent to {@code
+     * longs(Long.MAX_VALUE, randomNumberOrigin, randomNumberBound)}.
+     *
+     * @param randomNumberOrigin the origin of each random value
+     * @param randomNumberBound the bound of each random value
+     * @return a stream of pseudorandom {@code long} values,
+     *         each with the given origin and bound
+     * @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, each between zero
+     * (inclusive) and one (exclusive).
+     *
+     * @param streamSize the number of values to generate
+     * @return a stream of {@code double} values
+     * @throws IllegalArgumentException if {@code streamSize} is
+     *         less than zero
+     */
+    public DoubleStream doubles(long streamSize) {
+        if (streamSize < 0L)
+            throw new IllegalArgumentException(BadSize);
+        return StreamSupport.doubleStream
+            (new RandomDoublesSpliterator
+             (this, 0L, streamSize, Double.MAX_VALUE, 0.0),
+             false);
+    }
+
+    /**
+     * Returns an effectively unlimited stream of pseudorandom {@code
+     * double} values, each between zero (inclusive) and one
+     * (exclusive).
+     *
+     * @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, each conforming to the
+     * given origin and bound.
+     *
+     * @param streamSize the number of values to generate
+     * @param randomNumberOrigin the origin of each random value
+     * @param randomNumberBound the bound of each random value
+     * @return a stream of pseudorandom {@code double} values,
+     * each with the given origin and bound
+     * @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, each conforming to the given origin and bound.
+     *
+     * @implNote This method is implemented to be equivalent to {@code
+     * doubles(Long.MAX_VALUE, randomNumberOrigin, randomNumberBound)}.
+     *
+     * @param randomNumberOrigin the origin of each random value
+     * @param randomNumberBound the bound of each random value
+     * @return a stream of pseudorandom {@code double} values,
+     * each with the given origin and bound
+     * @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);
+            }
+        }
+    }
+
+}
--- a/src/share/classes/java/util/TreeMap.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/src/share/classes/java/util/TreeMap.java	Wed Aug 14 15:53:13 2013 -0700
@@ -790,8 +790,19 @@
 
     /**
      * Returns a {@link Set} view of the keys contained in this map.
-     * The set's iterator returns the keys in ascending order.
-     * The set is backed by the map, so changes to the map are
+     *
+     * <p>The set's iterator returns the keys in ascending order.
+     * The set's spliterator is
+     * <em><a href="Spliterator.html#binding">late-binding</a></em>,
+     * <em>fail-fast</em>, and additionally reports {@link Spliterator#SORTED}
+     * and {@link Spliterator#ORDERED} with an encounter order that is ascending
+     * key order.  The spliterator's comparator (see
+     * {@link java.util.Spliterator#getComparator()}) is {@code null} if
+     * the tree map's comparator (see {@link #comparator()}) is {@code null}.
+     * Otherwise, the spliterator's comparator is the same as or imposes the
+     * same total ordering as the tree map's comparator.
+     *
+     * <p>The set is backed by the map, so changes to the map are
      * reflected in the set, and vice-versa.  If the map is modified
      * while an iteration over the set is in progress (except through
      * the iterator's own {@code remove} operation), the results of
@@ -823,9 +834,15 @@
 
     /**
      * Returns a {@link Collection} view of the values contained in this map.
-     * The collection's iterator returns the values in ascending order
-     * of the corresponding keys.
-     * The collection is backed by the map, so changes to the map are
+     *
+     * <p>The collection's iterator returns the values in ascending order
+     * of the corresponding keys. The collection's spliterator is
+     * <em><a href="Spliterator.html#binding">late-binding</a></em>,
+     * <em>fail-fast</em>, and additionally reports {@link Spliterator#ORDERED}
+     * with an encounter order that is ascending order of the corresponding
+     * keys.
+     *
+     * <p>The collection is backed by the map, so changes to the map are
      * reflected in the collection, and vice-versa.  If the map is
      * modified while an iteration over the collection is in progress
      * (except through the iterator's own {@code remove} operation),
@@ -843,8 +860,15 @@
 
     /**
      * Returns a {@link Set} view of the mappings contained in this map.
-     * The set's iterator returns the entries in ascending key order.
-     * The set is backed by the map, so changes to the map are
+     *
+     * <p>The set's iterator returns the entries in ascending key order. The
+     * sets's spliterator is
+     * <em><a href="Spliterator.html#binding">late-binding</a></em>,
+     * <em>fail-fast</em>, and additionally reports {@link Spliterator#SORTED} and
+     * {@link Spliterator#ORDERED} with an encounter order that is ascending key
+     * order.
+     *
+     * <p>The set is backed by the map, so changes to the map are
      * reflected in the set, and vice-versa.  If the map is modified
      * while an iteration over the set is in progress (except through
      * the iterator's own {@code remove} operation, or through the
@@ -2944,16 +2968,11 @@
 
         @Override
         public Comparator<Map.Entry<K, V>> getComparator() {
-            // Since SORTED is reported and Map.Entry elements are not comparable
-            // then a non-null comparator needs to be returned
+            // Adapt or create a key-based comparator
             if (tree.comparator != null) {
-                // Adapt the existing non-null comparator to compare entries
-                // by key
                 return Map.Entry.comparingByKey(tree.comparator);
             }
             else {
-                // Return a comparator of entries by key, with K assumed to be
-                // of Comparable
                 return (Comparator<Map.Entry<K, V>> & Serializable) (e1, e2) -> {
                     @SuppressWarnings("unchecked")
                     Comparable<? super K> k1 = (Comparable<? super K>) e1.getKey();
--- a/src/share/classes/java/util/TreeSet.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/src/share/classes/java/util/TreeSet.java	Wed Aug 14 15:53:13 2013 -0700
@@ -533,6 +533,25 @@
         tm.readTreeSet(size, s, PRESENT);
     }
 
+    /**
+     * Creates a <em><a href="Spliterator.html#binding">late-binding</a></em>
+     * and <em>fail-fast</em> {@link Spliterator} over the elements in this
+     * set.
+     *
+     * <p>The {@code Spliterator} reports {@link Spliterator#SIZED},
+     * {@link Spliterator#DISTINCT}, {@link Spliterator#SORTED}, and
+     * {@link Spliterator#ORDERED}.  Overriding implementations should document
+     * the reporting of additional characteristic values.
+     *
+     * <p>The spliterator's comparator (see
+     * {@link java.util.Spliterator#getComparator()}) is {@code null} if
+     * the tree set's comparator (see {@link #comparator()}) is {@code null}.
+     * Otherwise, the spliterator's comparator is the same as or imposes the
+     * same total ordering as the tree set's comparator.
+     *
+     * @return a {@code Spliterator} over the elements in this set
+     * @since 1.8
+     */
     public Spliterator<E> spliterator() {
         return TreeMap.keySpliteratorFor(m);
     }
--- a/src/share/classes/java/util/Vector.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/src/share/classes/java/util/Vector.java	Wed Aug 14 15:53:13 2013 -0700
@@ -1323,6 +1323,19 @@
         modCount++;
     }
 
+    /**
+     * Creates a <em><a href="Spliterator.html#binding">late-binding</a></em>
+     * and <em>fail-fast</em> {@link Spliterator} over the elements in this
+     * list.
+     *
+     * <p>The {@code Spliterator} reports {@link Spliterator#SIZED},
+     * {@link Spliterator#SUBSIZED}, and {@link Spliterator#ORDERED}.
+     * Overriding implementations should document the reporting of additional
+     * characteristic values.
+     *
+     * @return a {@code Spliterator} over the elements in this list
+     * @since 1.8
+     */
     @Override
     public Spliterator<E> spliterator() {
         return new VectorSpliterator<>(this, null, 0, -1, 0);
--- a/src/share/classes/java/util/concurrent/ArrayBlockingQueue.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/src/share/classes/java/util/concurrent/ArrayBlockingQueue.java	Wed Aug 14 15:53:13 2013 -0700
@@ -1396,6 +1396,19 @@
 //         }
     }
 
+    /**
+     * Creates a {@link Spliterator} over the elements in this queue.
+     *
+     * <p>The {@code Spliterator} reports {@link Spliterator#CONCURRENT},
+     * {@link Spliterator#ORDERED}, and {@link Spliterator#NONNULL}.
+     *
+     * @implNote
+     * The {@code Spliterator} implements {@code trySplit} to permit limited
+     * parallelism..
+     *
+     * @return a {@code Spliterator} over the elements in this queue
+     * @since 1.8
+     */
     public Spliterator<E> spliterator() {
         return Spliterators.spliterator
             (this, Spliterator.ORDERED | Spliterator.NONNULL |
--- a/src/share/classes/java/util/concurrent/ConcurrentHashMap.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/src/share/classes/java/util/concurrent/ConcurrentHashMap.java	Wed Aug 14 15:53:13 2013 -0700
@@ -1200,11 +1200,14 @@
      * operations.  It does not support the {@code add} or
      * {@code addAll} operations.
      *
-     * <p>The view's {@code iterator} is a "weakly consistent" iterator
-     * that will never throw {@link ConcurrentModificationException},
-     * and guarantees to traverse elements as they existed upon
-     * construction of the iterator, and may (but is not guaranteed to)
-     * reflect any modifications subsequent to construction.
+     * <p>The view's {@code iterator} and {@code spliterator} are a
+     * "weakly consistent": they will never throw
+     * {@link ConcurrentModificationException}; are guaranteed to traverse
+     * elements as they existed upon construction; and may (but is not
+     * guaranteed to) reflect any modifications subsequent to construction.
+     *
+     * <p>The view's {@code spliterator} reports {@link Spliterator#CONCURRENT},
+     * {@link Spliterator#DISTINCT}, and {@link Spliterator#NONNULL}.
      *
      * @return the set view
      */
@@ -1223,11 +1226,14 @@
      * {@code retainAll}, and {@code clear} operations.  It does not
      * support the {@code add} or {@code addAll} operations.
      *
-     * <p>The view's {@code iterator} is a "weakly consistent" iterator
-     * that will never throw {@link ConcurrentModificationException},
-     * and guarantees to traverse elements as they existed upon
-     * construction of the iterator, and may (but is not guaranteed to)
-     * reflect any modifications subsequent to construction.
+     * <p>The view's {@code iterator} and {@code spliterator} are a
+     * "weakly consistent": they will never throw
+     * {@link ConcurrentModificationException}; are guaranteed to traverse
+     * elements as they existed upon construction; and may (but is not
+     * guaranteed to) reflect any modifications subsequent to construction.
+     *
+     * <p>The view's {@code spliterator} reports {@link Spliterator#CONCURRENT}
+     * and {@link Spliterator#NONNULL}.
      *
      * @return the collection view
      */
@@ -1245,11 +1251,14 @@
      * {@code removeAll}, {@code retainAll}, and {@code clear}
      * operations.
      *
-     * <p>The view's {@code iterator} is a "weakly consistent" iterator
-     * that will never throw {@link ConcurrentModificationException},
-     * and guarantees to traverse elements as they existed upon
-     * construction of the iterator, and may (but is not guaranteed to)
-     * reflect any modifications subsequent to construction.
+     * <p>The view's {@code iterator} and {@code spliterator} are a
+     * "weakly consistent": they will never throw
+     * {@link ConcurrentModificationException}; are guaranteed to traverse
+     * elements as they existed upon construction; and may (but is not
+     * guaranteed to) reflect any modifications subsequent to construction.
+     *
+     * <p>The view's {@code spliterator} reports {@link Spliterator#CONCURRENT},
+     * {@link Spliterator#DISTINCT}, and {@link Spliterator#NONNULL}.
      *
      * @return the set view
      */
--- a/src/share/classes/java/util/concurrent/ConcurrentLinkedDeque.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/src/share/classes/java/util/concurrent/ConcurrentLinkedDeque.java	Wed Aug 14 15:53:13 2013 -0700
@@ -1493,6 +1493,19 @@
         }
     }
 
+    /**
+     * Creates a {@link Spliterator} over the elements in this deque.
+     *
+     * <p>The {@code Spliterator} reports {@link Spliterator#CONCURRENT},
+     * {@link Spliterator#ORDERED}, and {@link Spliterator#NONNULL}.
+     *
+     * @implNote
+     * The {@code Spliterator} implements {@code trySplit} to permit limited
+     * parallelism..
+     *
+     * @return a {@code Spliterator} over the elements in this deque
+     * @since 1.8
+     */
     public Spliterator<E> spliterator() {
         return new CLDSpliterator<E>(this);
     }
--- a/src/share/classes/java/util/concurrent/ConcurrentLinkedQueue.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/src/share/classes/java/util/concurrent/ConcurrentLinkedQueue.java	Wed Aug 14 15:53:13 2013 -0700
@@ -881,6 +881,20 @@
         }
     }
 
+    /**
+     * Creates a {@link Spliterator} over the elements in this queue.
+     *
+     * <p>The {@code Spliterator} reports {@link Spliterator#CONCURRENT},
+     * {@link Spliterator#ORDERED}, and {@link Spliterator#NONNULL}.
+     *
+     * @implNote
+     * The {@code Spliterator} implements {@code trySplit} to permit limited
+     * parallelism..
+     *
+     * @return a {@code Spliterator} over the elements in this queue
+     * @since 1.8
+     */
+    @Override
     public Spliterator<E> spliterator() {
         return new CLQSpliterator<E>(this);
     }
--- a/src/share/classes/java/util/concurrent/ConcurrentSkipListMap.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/src/share/classes/java/util/concurrent/ConcurrentSkipListMap.java	Wed Aug 14 15:53:13 2013 -0700
@@ -34,6 +34,7 @@
  */
 
 package java.util.concurrent;
+import java.io.Serializable;
 import java.util.AbstractCollection;
 import java.util.AbstractMap;
 import java.util.AbstractSet;
@@ -1795,8 +1796,18 @@
 
     /**
      * Returns a {@link NavigableSet} view of the keys contained in this map.
-     * The set's iterator returns the keys in ascending order.
-     * The set is backed by the map, so changes to the map are
+     *
+     * <p>The set's iterator returns the keys in ascending order.
+     * The set's spliterator additionally reports {@link Spliterator#CONCURRENT},
+     * {@link Spliterator#NONNULL}, {@link Spliterator#SORTED} and
+     * {@link Spliterator#ORDERED} with an encounter order that is ascending
+     * key order.  The spliterator's comparator (see
+     * {@link java.util.Spliterator#getComparator()}) is {@code null} if
+     * the map's comparator (see {@link #comparator()}) is {@code null}.
+     * Otherwise, the spliterator's comparator is the same as or imposes the
+     * same total ordering as the map's comparator.
+     *
+     * <p>The set is backed by the map, so changes to the map are
      * reflected in the set, and vice-versa.  The set supports element
      * removal, which removes the corresponding mapping from the map,
      * via the {@code Iterator.remove}, {@code Set.remove},
@@ -1804,10 +1815,10 @@
      * operations.  It does not support the {@code add} or {@code addAll}
      * operations.
      *
-     * <p>The view's {@code iterator} is a "weakly consistent" iterator that
-     * will never throw {@link java.util.ConcurrentModificationException
-     * ConcurrentModificationException}, and guarantees to traverse elements
-     * as they existed upon construction of the iterator, and may (but is not
+     * <p>The view's {@code iterator} and {@code spliterator} are a
+     * "weakly consistent": they will never throw
+     * {@link java.util.ConcurrentModificationException}; are guaranteed to
+     * traverse elements as they existed upon construction; and may (but is not
      * guaranteed to) reflect any modifications subsequent to construction.
      *
      * <p>This method is equivalent to method {@code navigableKeySet}.
@@ -1826,9 +1837,14 @@
 
     /**
      * Returns a {@link Collection} view of the values contained in this map.
-     * The collection's iterator returns the values in ascending order
-     * of the corresponding keys.
-     * The collection is backed by the map, so changes to the map are
+     *
+     * <p>The collection's iterator returns the values in ascending order
+     * of the corresponding keys. The collections's spliterator additionally
+     * reports {@link Spliterator#CONCURRENT}, {@link Spliterator#NONNULL}, and
+     * {@link Spliterator#ORDERED} with an encounter order that is ascending
+     * order of the corresponding keys.
+     *
+     * <p>The collection is backed by the map, so changes to the map are
      * reflected in the collection, and vice-versa.  The collection
      * supports element removal, which removes the corresponding
      * mapping from the map, via the {@code Iterator.remove},
@@ -1836,10 +1852,10 @@
      * {@code retainAll} and {@code clear} operations.  It does not
      * support the {@code add} or {@code addAll} operations.
      *
-     * <p>The view's {@code iterator} is a "weakly consistent" iterator that
-     * will never throw {@link java.util.ConcurrentModificationException
-     * ConcurrentModificationException}, and guarantees to traverse elements
-     * as they existed upon construction of the iterator, and may (but is not
+     * <p>The view's {@code iterator} and {@code spliterator} are a
+     * "weakly consistent": they will never throw
+     * {@link java.util.ConcurrentModificationException}; are guaranteed to
+     * traverse elements as they existed upon construction; and may (but is not
      * guaranteed to) reflect any modifications subsequent to construction.
      */
     public Collection<V> values() {
@@ -1849,8 +1865,14 @@
 
     /**
      * Returns a {@link Set} view of the mappings contained in this map.
-     * The set's iterator returns the entries in ascending key order.
-     * The set is backed by the map, so changes to the map are
+     *
+     * <p>The set's iterator returns the entries in ascending key order.  The
+     * set's spliterator additionally reports {@link Spliterator#CONCURRENT},
+     * {@link Spliterator#NONNULL}, {@link Spliterator#SORTED}, and
+     * {@link Spliterator#ORDERED} with an encounter order that is ascending
+     * key order.
+     *
+     * <p>The set is backed by the map, so changes to the map are
      * reflected in the set, and vice-versa.  The set supports element
      * removal, which removes the corresponding mapping from the map,
      * via the {@code Iterator.remove}, {@code Set.remove},
@@ -1858,15 +1880,15 @@
      * operations.  It does not support the {@code add} or
      * {@code addAll} operations.
      *
-     * <p>The view's {@code iterator} is a "weakly consistent" iterator that
-     * will never throw {@link java.util.ConcurrentModificationException
-     * ConcurrentModificationException}, and guarantees to traverse elements
-     * as they existed upon construction of the iterator, and may (but is not
+     * <p>The view's {@code iterator} and {@code spliterator} are a
+     * "weakly consistent": they will never throw
+     * {@link java.util.ConcurrentModificationException}; are guaranteed to
+     * traverse elements as they existed upon construction; and may (but is not
      * guaranteed to) reflect any modifications subsequent to construction.
      *
-     * <p>The {@code Map.Entry} elements returned by
-     * {@code iterator.next()} do <em>not</em> support the
-     * {@code setValue} operation.
+     * <p>The {@code Map.Entry} elements traversed by the {@code iterator}
+     * or {@code spliterator} do <em>not</em> support the {@code setValue}
+     * operation.
      *
      * @return a set view of the mappings contained in this map,
      *         sorted in ascending key order
@@ -3434,7 +3456,8 @@
         }
 
         public int characteristics() {
-            return Spliterator.CONCURRENT | Spliterator.NONNULL;
+            return Spliterator.CONCURRENT | Spliterator.ORDERED |
+                Spliterator.NONNULL;
         }
     }
 
@@ -3528,8 +3551,17 @@
         }
 
         public final Comparator<Map.Entry<K,V>> getComparator() {
-            return comparator == null ? null :
-                Map.Entry.comparingByKey(comparator);
+            // Adapt or create a key-based comparator
+           if (comparator != null) {
+                return Map.Entry.comparingByKey(comparator);
+            }
+            else {
+                return (Comparator<Map.Entry<K, V>> & Serializable) (e1, e2) -> {
+                    @SuppressWarnings("unchecked")
+                    Comparable<? super K> k1 = (Comparable<? super K>) e1.getKey();
+                    return k1.compareTo(e2.getKey());
+                };
+            }
         }
     }
 
--- a/src/share/classes/java/util/concurrent/ConcurrentSkipListSet.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/src/share/classes/java/util/concurrent/ConcurrentSkipListSet.java	Wed Aug 14 15:53:13 2013 -0700
@@ -480,6 +480,24 @@
         return new ConcurrentSkipListSet<E>(m.descendingMap());
     }
 
+    /**
+     * Creates a {@link Spliterator} over the elements in this set.
+     *
+     * <p>The {@code Spliterator} reports {@link Spliterator#CONCURRENT},
+     * {@link Spliterator#NONNULL}, {@link Spliterator#DISTINCT},
+     * {@link Spliterator#SORTED}, and {@link Spliterator#ORDERED} with an
+     * encounter order that is ascending order.  Overriding implementations
+     * should document the reporting of additional characteristic values.
+     *
+     * <p>The spliterator's comparator (see
+     * {@link java.util.Spliterator#getComparator()}) is {@code null} if
+     * the set's comparator (see {@link #comparator()}) is {@code null}.
+     * Otherwise, the spliterator's comparator is the same as or imposes the
+     * same total ordering as the set's comparator.
+     *
+     * @return a {@code Spliterator} over the elements in this set
+     * @since 1.8
+     */
     @SuppressWarnings("unchecked")
     public Spliterator<E> spliterator() {
         if (m instanceof ConcurrentSkipListMap)
--- a/src/share/classes/java/util/concurrent/CopyOnWriteArrayList.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/src/share/classes/java/util/concurrent/CopyOnWriteArrayList.java	Wed Aug 14 15:53:13 2013 -0700
@@ -1101,6 +1101,21 @@
         return new COWIterator<E>(elements, index);
     }
 
+    /**
+     * Creates a {@link Spliterator} over the elements in this list.
+     *
+     * <p>The {@code Spliterator} reports {@link Spliterator#IMMUTABLE},
+     * {@link Spliterator#ORDERED}, {@link Spliterator#SIZED}, and
+     * {@link Spliterator#SUBSIZED}.
+     *
+     * <p>The spliterator provides a snapshot of the state of the list
+     * when the spliterator was constructed. No synchronization is needed while
+     * operating on the spliterator. The spliterator does <em>NOT</em> support
+     * the {@code remove}, {@code set} or {@code add} methods.
+     *
+     * @return a {@code Spliterator} over the elements in this list
+     * @since 1.8
+     */
     public Spliterator<E> spliterator() {
         return Spliterators.spliterator
             (getArray(), Spliterator.IMMUTABLE | Spliterator.ORDERED);
--- a/src/share/classes/java/util/concurrent/CopyOnWriteArraySet.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/src/share/classes/java/util/concurrent/CopyOnWriteArraySet.java	Wed Aug 14 15:53:13 2013 -0700
@@ -404,6 +404,22 @@
         al.forEach(action);
     }
 
+    /**
+     * Creates a {@link Spliterator} over the elements in this set in the order
+     * in which these elements were added.
+     *
+     * <p>The {@code Spliterator} reports {@link Spliterator#IMMUTABLE},
+     * {@link Spliterator#DISTINCT}, {@link Spliterator#SIZED}, and
+     * {@link Spliterator#SUBSIZED}.
+     *
+     * <p>The spliterator provides a snapshot of the state of the set
+     * when the spliterator was constructed. No synchronization is needed while
+     * operating on the spliterator. The spliterator does <em>NOT</em> support
+     * the {@code remove}, {@code set} or {@code add} methods.
+     *
+     * @return a {@code Spliterator} over the elements in this list
+     * @since 1.8
+     */
     public Spliterator<E> spliterator() {
         return Spliterators.spliterator
             (al.getArray(), Spliterator.IMMUTABLE | Spliterator.DISTINCT);
--- a/src/share/classes/java/util/concurrent/LinkedBlockingDeque.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/src/share/classes/java/util/concurrent/LinkedBlockingDeque.java	Wed Aug 14 15:53:13 2013 -0700
@@ -1270,6 +1270,19 @@
         }
     }
 
+    /**
+     * Creates a {@link Spliterator} over the elements in this deque.
+     *
+     * <p>The {@code Spliterator} reports {@link Spliterator#CONCURRENT},
+     * {@link Spliterator#ORDERED}, and {@link Spliterator#NONNULL}.
+     *
+     * @implNote
+     * The {@code Spliterator} implements {@code trySplit} to permit limited
+     * parallelism..
+     *
+     * @return a {@code Spliterator} over the elements in this deque
+     * @since 1.8
+     */
     public Spliterator<E> spliterator() {
         return new LBDSpliterator<E>(this);
     }
--- a/src/share/classes/java/util/concurrent/LinkedBlockingQueue.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/src/share/classes/java/util/concurrent/LinkedBlockingQueue.java	Wed Aug 14 15:53:13 2013 -0700
@@ -973,6 +973,19 @@
         }
     }
 
+    /**
+     * Creates a {@link Spliterator} over the elements in this queue.
+     *
+     * <p>The {@code Spliterator} reports {@link Spliterator#CONCURRENT},
+     * {@link Spliterator#ORDERED}, and {@link Spliterator#NONNULL}.
+     *
+     * @implNote
+     * The {@code Spliterator} implements {@code trySplit} to permit limited
+     * parallelism..
+     *
+     * @return a {@code Spliterator} over the elements in this queue
+     * @since 1.8
+     */
     public Spliterator<E> spliterator() {
         return new LBQSpliterator<E>(this);
     }
--- a/src/share/classes/java/util/concurrent/LinkedTransferQueue.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/src/share/classes/java/util/concurrent/LinkedTransferQueue.java	Wed Aug 14 15:53:13 2013 -0700
@@ -1018,6 +1018,19 @@
         }
     }
 
+    /**
+     * Creates a {@link Spliterator} over the elements in this queue.
+     *
+     * <p>The {@code Spliterator} reports {@link Spliterator#CONCURRENT},
+     * {@link Spliterator#ORDERED}, and {@link Spliterator#NONNULL}.
+     *
+     * @implNote
+     * The {@code Spliterator} implements {@code trySplit} to permit limited
+     * parallelism..
+     *
+     * @return a {@code Spliterator} over the elements in this queue
+     * @since 1.8
+     */
     public Spliterator<E> spliterator() {
         return new LTQSpliterator<E>(this);
     }
--- a/src/share/classes/java/util/concurrent/PriorityBlockingQueue.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/src/share/classes/java/util/concurrent/PriorityBlockingQueue.java	Wed Aug 14 15:53:13 2013 -0700
@@ -1005,6 +1005,18 @@
         }
     }
 
+    /**
+     * Creates a {@link Spliterator} over the elements in this queue.
+     *
+     * <p>The {@code Spliterator} reports {@link Spliterator#SIZED} and
+     * {@link Spliterator#NONNULL}.
+     *
+     * @implNote
+     * The {@code Spliterator} additionally reports {@link Spliterator#SUBSIZED}.
+     *
+     * @return a {@code Spliterator} over the elements in this queue
+     * @since 1.8
+     */
     public Spliterator<E> spliterator() {
         return new PBQSpliterator<E>(this, null, 0, -1);
     }
--- a/src/share/classes/java/util/concurrent/SynchronousQueue.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/src/share/classes/java/util/concurrent/SynchronousQueue.java	Wed Aug 14 15:53:13 2013 -0700
@@ -1077,6 +1077,12 @@
         public void remove() { throw new IllegalStateException(); }
     }
 
+    /**
+     * Return an empty spliterator in which calls to
+     * {@link java.util.Spliterator#trySplit()} always return {@code null}.
+     *
+     * @return an empty spliterator.
+     */
     public Spliterator<E> spliterator() {
         return Spliterators.emptySpliterator();
     }
--- a/src/share/classes/java/util/concurrent/ThreadLocalRandom.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/src/share/classes/java/util/concurrent/ThreadLocalRandom.java	Wed Aug 14 15:53:13 2013 -0700
@@ -1,33 +1,4 @@
 /*
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/*
- * This file is available under and governed by the GNU General Public
- * License version 2 only, as published by the Free Software Foundation.
- * However, the following notice accompanied the original version of this
- * file:
- *
  * Written by Doug Lea with assistance from members of JCP JSR-166
  * Expert Group and released to the public domain, as explained at
  * http://creativecommons.org/publicdomain/zero/1.0/
@@ -37,11 +8,16 @@
 
 import java.io.ObjectStreamField;
 import java.util.Random;
+import java.util.Spliterator;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicLong;
+import java.util.function.DoubleConsumer;
+import java.util.function.IntConsumer;
+import java.util.function.LongConsumer;
 import java.util.stream.DoubleStream;
 import java.util.stream.IntStream;
 import java.util.stream.LongStream;
+import java.util.stream.StreamSupport;
 
 /**
  * A random number generator isolated to the current thread.  Like the
@@ -85,28 +61,26 @@
      * application-level overhead and footprint of most concurrent
      * programs.
      *
+     * Even though this class subclasses java.util.Random, it uses the
+     * same basic algorithm as java.util.SplittableRandom.  (See its
+     * internal documentation for explanations, which are not repeated
+     * here.)  Because ThreadLocalRandoms are not splittable
+     * though, we use only a single 64bit gamma.
+     *
      * Because this class is in a different package than class Thread,
      * field access methods use Unsafe to bypass access control rules.
-     * The base functionality of Random methods is conveniently
-     * isolated in method next(bits), that just reads and writes the
-     * Thread field rather than its own field.  However, to conform to
-     * the requirements of the Random superclass constructor, the
-     * common static ThreadLocalRandom maintains an "initialized"
-     * field for the sake of rejecting user calls to setSeed while
-     * still allowing a call from constructor.  Note that
-     * serialization is completely unnecessary because there is only a
-     * static singleton.  But we generate a serial form containing
-     * "rnd" and "initialized" fields to ensure compatibility across
-     * versions.
+     * To conform to the requirements of the Random superclass
+     * constructor, the common static ThreadLocalRandom maintains an
+     * "initialized" field for the sake of rejecting user calls to
+     * setSeed while still allowing a call from constructor.  Note
+     * that serialization is completely unnecessary because there is
+     * only a static singleton.  But we generate a serial form
+     * containing "rnd" and "initialized" fields to ensure
+     * compatibility across versions.
      *
-     * Per-thread initialization is similar to that in the no-arg
-     * Random constructor, but we avoid correlation among not only
-     * initial seeds of those created in different threads, but also
-     * those created using class Random itself; while at the same time
-     * not changing any statistical properties.  So we use the same
-     * underlying multiplicative sequence, but start the sequence far
-     * away from the base version, and then merge (xor) current time
-     * and per-thread probe bits to generate initial values.
+     * Implementations of non-core methods are mostly the same as in
+     * SplittableRandom, that were in part derived from a previous
+     * version of this class.
      *
      * The nextLocalGaussian ThreadLocal supports the very rarely used
      * nextGaussian method by providing a holder for the second of a
@@ -115,24 +89,51 @@
      * but we provide identical statistical properties.
      */
 
-    // same constants as Random, but must be redeclared because private
-    private static final long multiplier = 0x5DEECE66DL;
-    private static final long addend = 0xBL;
-    private static final long mask = (1L << 48) - 1;
-    private static final int PROBE_INCREMENT = 0x61c88647;
-
-    /** Generates the basis for per-thread initial seed values */
-    private static final AtomicLong seedGenerator =
-        new AtomicLong(1269533684904616924L);
-
     /** Generates per-thread initialization/probe field */
     private static final AtomicInteger probeGenerator =
-        new AtomicInteger(0xe80f8647);
+        new AtomicInteger();
+
+    /**
+     * The next seed for default constructors.
+     */
+    private static final AtomicLong seedGenerator =
+        new AtomicLong(mix64(System.currentTimeMillis()) ^
+                       mix64(System.nanoTime()));
+
+    /**
+     * The seed increment
+     */
+    private static final long GAMMA = 0x9e3779b97f4a7c15L;
+
+    /**
+     * The increment for generating probe values
+     */
+    private static final int PROBE_INCREMENT = 0x9e3779b9;
+
+    /**
+     * The increment of seedGenerator per new instance
+     */
+    private static final long SEEDER_INCREMENT = 0xbb67ae8584caa73bL;
+
+    // Constants from SplittableRandom
+    private static final double DOUBLE_UNIT = 1.0 / (1L << 53);
+    private static final float  FLOAT_UNIT  = 1.0f / (1 << 24);
 
     /** Rarely-used holder for the second of a pair of Gaussians */
     private static final ThreadLocal<Double> nextLocalGaussian =
         new ThreadLocal<Double>();
 
+    private static long mix64(long z) {
+        z = (z ^ (z >>> 33)) * 0xff51afd7ed558ccdL;
+        z = (z ^ (z >>> 33)) * 0xc4ceb9fe1a85ec53L;
+        return z ^ (z >>> 33);
+    }
+
+    private static int mix32(long z) {
+        z = (z ^ (z >>> 33)) * 0xff51afd7ed558ccdL;
+        return (int)(((z ^ (z >>> 33)) * 0xc4ceb9fe1a85ec53L) >>> 32);
+    }
+
     /**
      * Field used only during singleton initialization.
      * True when constructor completes.
@@ -155,16 +156,11 @@
      * rely on (static) atomic generators to initialize the values.
      */
     static final void localInit() {
-        int p = probeGenerator.getAndAdd(PROBE_INCREMENT);
+        int p = probeGenerator.addAndGet(PROBE_INCREMENT);
         int probe = (p == 0) ? 1 : p; // skip 0
-        long current, next;
-        do { // same sequence as j.u.Random but different initial value
-            current = seedGenerator.get();
-            next = current * 181783497276652981L;
-        } while (!seedGenerator.compareAndSet(current, next));
-        long r = next ^ ((long)probe << 32) ^ System.nanoTime();
+        long seed = mix64(seedGenerator.getAndAdd(SEEDER_INCREMENT));
         Thread t = Thread.currentThread();
-        UNSAFE.putLong(t, SEED, r);
+        UNSAFE.putLong(t, SEED, seed);
         UNSAFE.putInt(t, PROBE, probe);
     }
 
@@ -191,124 +187,267 @@
             throw new UnsupportedOperationException();
     }
 
-    protected int next(int bits) {
+    final long nextSeed() {
         Thread t; long r; // read and update per-thread seed
-        UNSAFE.putLong
-            (t = Thread.currentThread(), SEED,
-             r = (UNSAFE.getLong(t, SEED) * multiplier + addend) & mask);
-        return (int) (r >>> (48-bits));
+        UNSAFE.putLong(t = Thread.currentThread(), SEED,
+                       r = UNSAFE.getLong(t, SEED) + GAMMA);
+        return r;
+    }
+
+    // We must define this, but never use it.
+    protected int next(int bits) {
+        return (int)(mix64(nextSeed()) >>> (64 - bits));
+    }
+
+    // IllegalArgumentException messages
+    static final String BadBound = "bound must be positive";
+    static final String BadRange = "bound must be greater than origin";
+    static final String BadSize  = "size must be non-negative";
+
+    /**
+     * The form of nextLong used by LongStream Spliterators.  If
+     * origin is greater than bound, acts as unbounded form of
+     * nextLong, else as bounded form.
+     *
+     * @param origin the least value, unless greater than bound
+     * @param bound the upper bound (exclusive), must not equal origin
+     * @return a pseudorandom value
+     */
+    final long internalNextLong(long origin, long bound) {
+        long r = 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;
     }
 
     /**
-     * Returns a pseudorandom, uniformly distributed value between the
-     * given least value (inclusive) and bound (exclusive).
+     * The form of nextInt used by IntStream Spliterators.
+     * Exactly the same as long version, except for types.
+     *
+     * @param 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 least the least value returned
-     * @param bound the upper bound (exclusive)
-     * @throws IllegalArgumentException if least greater than or equal
-     * to bound
-     * @return the next value
+     * @param origin the least value, unless greater than bound
+     * @param bound the upper bound (exclusive), must not equal origin
+     * @return a pseudorandom value
+     */
+    final double internalNextDouble(double origin, double bound) {
+        double r = (nextLong() >>> 11) * DOUBLE_UNIT;
+        if (origin < bound) {
+            r = r * (bound - origin) + origin;
+            if (r >= bound) // correct for rounding
+                r = Double.longBitsToDouble(Double.doubleToLongBits(bound) - 1);
+        }
+        return r;
+    }
+
+    /**
+     * Returns a pseudorandom {@code int} value.
+     *
+     * @return a pseudorandom {@code int} value
      */
-    public int nextInt(int least, int bound) {
-        if (least >= bound)
-            throw new IllegalArgumentException();
-        return nextInt(bound - least) + least;
+    public int nextInt() {
+        return mix32(nextSeed());
+    }
+
+    /**
+     * Returns a pseudorandom {@code int} value between zero (inclusive)
+     * and the specified bound (exclusive).
+     *
+     * @param bound the bound on the random number to be returned.  Must be
+     *        positive.
+     * @return a pseudorandom {@code int} value between zero
+     *         (inclusive) and the bound (exclusive)
+     * @throws IllegalArgumentException if {@code bound} is not positive
+     */
+    public int nextInt(int bound) {
+        if (bound <= 0)
+            throw new IllegalArgumentException(BadBound);
+        int r = mix32(nextSeed());
+        int m = bound - 1;
+        if ((bound & m) == 0) // power of two
+            r &= m;
+        else { // reject over-represented candidates
+            for (int u = r >>> 1;
+                 u + m - (r = u % bound) < 0;
+                 u = mix32(nextSeed()) >>> 1)
+                ;
+        }
+        return r;
     }
 
     /**
-     * Returns a pseudorandom, uniformly distributed value
-     * between 0 (inclusive) and the specified value (exclusive).
+     * Returns a pseudorandom {@code int} value between the specified
+     * origin (inclusive) and the specified bound (exclusive).
      *
-     * @param n the bound on the random number to be returned.  Must be
-     *        positive.
-     * @return the next value
-     * @throws IllegalArgumentException if n is not positive
+     * @param origin the least value 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 long nextLong(long n) {
-        if (n <= 0)
-            throw new IllegalArgumentException("n must be positive");
-        // Divide n by two until small enough for nextInt. On each
-        // iteration (at most 31 of them but usually much less),
-        // randomly choose both whether to include high bit in result
-        // (offset) and whether to continue with the lower vs upper
-        // half (which makes a difference only if odd).
-        long offset = 0;
-        while (n >= Integer.MAX_VALUE) {
-            int bits = next(2);
-            long half = n >>> 1;
-            long nextn = ((bits & 2) == 0) ? half : n - half;
-            if ((bits & 1) == 0)
-                offset += n - nextn;
-            n = nextn;
-        }
-        return offset + nextInt((int) n);
+    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());
     }
 
-    @Override
-    public IntStream ints() {
-        return IntStream.generate(() -> current().nextInt());
-    }
-
-    @Override
-    public LongStream longs() {
-        return LongStream.generate(() -> current().nextLong());
-    }
-
-    @Override
-    public DoubleStream doubles() {
-        return DoubleStream.generate(() -> current().nextDouble());
-    }
-
-    @Override
-    public DoubleStream gaussians() {
-        return DoubleStream.generate(() -> current().nextGaussian());
+    /**
+     * Returns a pseudorandom {@code long} value between zero (inclusive)
+     * and the specified bound (exclusive).
+     *
+     * @param bound the bound on the random number to be returned.  Must be
+     *        positive.
+     * @return a pseudorandom {@code long} value between zero
+     *         (inclusive) and the bound (exclusive)
+     * @throws IllegalArgumentException if {@code bound} is not positive
+     */
+    public long nextLong(long bound) {
+        if (bound <= 0)
+            throw new IllegalArgumentException(BadBound);
+        long r = mix64(nextSeed());
+        long m = bound - 1;
+        if ((bound & m) == 0L) // power of two
+            r &= m;
+        else { // reject over-represented candidates
+            for (long u = r >>> 1;
+                 u + m - (r = u % bound) < 0L;
+                 u = mix64(nextSeed()) >>> 1)
+                ;
+        }
+        return r;
     }
 
     /**
-     * Returns a pseudorandom, uniformly distributed value between the
-     * given least value (inclusive) and bound (exclusive).
+     * Returns a pseudorandom {@code long} value between the specified
+     * origin (inclusive) and the specified bound (exclusive).
      *
-     * @param least the least value returned
+     * @param origin the least value returned
      * @param bound the upper bound (exclusive)
-     * @return the next value
-     * @throws IllegalArgumentException if least greater than or equal
-     * to bound
+     * @return a pseudorandom {@code long} value between the origin
+     *         (inclusive) and the bound (exclusive)
+     * @throws IllegalArgumentException if {@code origin} is greater than
+     *         or equal to {@code bound}
      */
-    public long nextLong(long least, long bound) {
-        if (least >= bound)
-            throw new IllegalArgumentException();
-        return nextLong(bound - least) + least;
+    public long nextLong(long origin, long bound) {
+        if (origin >= bound)
+            throw new IllegalArgumentException(BadRange);
+        return internalNextLong(origin, bound);
+    }
+
+    /**
+     * Returns a pseudorandom {@code double} value between zero
+     * (inclusive) and one (exclusive).
+     *
+     * @return a pseudorandom {@code double} value between zero
+     * (inclusive) and one (exclusive)
+     */
+    public double nextDouble() {
+        return (mix64(nextSeed()) >>> 11) * DOUBLE_UNIT;
     }
 
     /**
-     * Returns a pseudorandom, uniformly distributed {@code double} value
-     * between 0 (inclusive) and the specified value (exclusive).
+     * Returns a pseudorandom {@code double} value between 0.0
+     * (inclusive) and the specified bound (exclusive).
      *
-     * @param n the bound on the random number to be returned.  Must be
+     * @param bound the bound on the random number to be returned.  Must be
      *        positive.
-     * @return the next value
-     * @throws IllegalArgumentException if n is not positive
+     * @return a pseudorandom {@code double} value between zero
+     *         (inclusive) and the bound (exclusive)
+     * @throws IllegalArgumentException if {@code bound} is not positive
      */
-    public double nextDouble(double n) {
-        if (n <= 0)
-            throw new IllegalArgumentException("n must be positive");
-        return nextDouble() * n;
+    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, uniformly distributed value between the
-     * given least value (inclusive) and bound (exclusive).
+     * Returns a pseudorandom {@code double} value between the specified
+     * origin (inclusive) and bound (exclusive).
      *
-     * @param least the least value returned
-     * @param bound the upper bound (exclusive)
-     * @return the next value
-     * @throws IllegalArgumentException if least greater than or equal
-     * to bound
+     * @param origin the least value returned
+     * @param bound the upper bound
+     * @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 least, double bound) {
-        if (least >= bound)
-            throw new IllegalArgumentException();
-        return nextDouble() * (bound - least) + least;
+    public double nextDouble(double origin, double bound) {
+        if (!(origin < bound))
+            throw new IllegalArgumentException(BadRange);
+        return internalNextDouble(origin, bound);
+    }
+
+    /**
+     * Returns a pseudorandom {@code boolean} value.
+     *
+     * @return a pseudorandom {@code boolean} value
+     */
+    public boolean nextBoolean() {
+        return mix32(nextSeed()) < 0;
+    }
+
+    /**
+     * Returns a pseudorandom {@code float} value between zero
+     * (inclusive) and one (exclusive).
+     *
+     * @return a pseudorandom {@code float} value between zero
+     * (inclusive) and one (exclusive)
+     */
+    public float nextFloat() {
+        return (mix32(nextSeed()) >>> 8) * FLOAT_UNIT;
     }
 
     public double nextGaussian() {
@@ -329,6 +468,442 @@
         return v1 * multiplier;
     }
 
+    // stream methods, coded in a way intended to better isolate for
+    // maintenance purposes the small differences across forms.
+
+    /**
+     * Returns a stream producing the given {@code streamSize} number of
+     * pseudorandom {@code int} values.
+     *
+     * @param streamSize the number of values to generate
+     * @return a stream of pseudorandom {@code int} values
+     * @throws IllegalArgumentException if {@code streamSize} is
+     *         less than zero
+     */
+    @Override
+    public IntStream ints(long streamSize) {
+        if (streamSize < 0L)
+            throw new IllegalArgumentException(BadSize);
+        return StreamSupport.intStream
+            (new RandomIntsSpliterator
+             (0L, streamSize, Integer.MAX_VALUE, 0),
+             false);
+    }
+
+    /**
+     * Returns an effectively unlimited stream of pseudorandom {@code int}
+     * values.
+     *
+     * @implNote This method is implemented to be equivalent to {@code
+     * ints(Long.MAX_VALUE)}.
+     *
+     * @return a stream of pseudorandom {@code int} values
+     */
+    @Override
+    public IntStream ints() {
+        return StreamSupport.intStream
+            (new RandomIntsSpliterator
+             (0L, Long.MAX_VALUE, Integer.MAX_VALUE, 0),
+             false);
+    }
+
+    /**
+     * Returns a stream producing the given {@code streamSize} number of
+     * pseudorandom {@code int} values, each conforming to the given
+     * origin and bound.
+     *
+     * @param streamSize the number of values to generate
+     * @param randomNumberOrigin the origin of each random value
+     * @param randomNumberBound the bound of each random value
+     * @return a stream of pseudorandom {@code int} values,
+     *         each with the given origin and bound
+     * @throws IllegalArgumentException if {@code streamSize} is
+     *         less than zero, or {@code randomNumberOrigin}
+     *         is greater than or equal to {@code randomNumberBound}
+     */
+    @Override
+    public IntStream ints(long streamSize, int randomNumberOrigin,
+                          int randomNumberBound) {
+        if (streamSize < 0L)
+            throw new IllegalArgumentException(BadSize);
+        if (randomNumberOrigin >= randomNumberBound)
+            throw new IllegalArgumentException(BadRange);
+        return StreamSupport.intStream
+            (new RandomIntsSpliterator
+             (0L, streamSize, randomNumberOrigin, randomNumberBound),
+             false);
+    }
+
+    /**
+     * Returns an effectively unlimited stream of pseudorandom {@code
+     * int} values, each conforming to the given origin and bound.
+     *
+     * @implNote This method is implemented to be equivalent to {@code
+     * ints(Long.MAX_VALUE, randomNumberOrigin, randomNumberBound)}.
+     *
+     * @param randomNumberOrigin the origin of each random value
+     * @param randomNumberBound the bound of each random value
+     * @return a stream of pseudorandom {@code int} values,
+     *         each with the given origin and bound
+     * @throws IllegalArgumentException if {@code randomNumberOrigin}
+     *         is greater than or equal to {@code randomNumberBound}
+     */
+    @Override
+    public IntStream ints(int randomNumberOrigin, int randomNumberBound) {
+        if (randomNumberOrigin >= randomNumberBound)
+            throw new IllegalArgumentException(BadRange);
+        return StreamSupport.intStream
+            (new RandomIntsSpliterator
+             (0L, Long.MAX_VALUE, randomNumberOrigin, randomNumberBound),
+             false);
+    }
+
+    /**
+     * Returns a stream producing the given {@code streamSize} number of
+     * pseudorandom {@code long} values.
+     *
+     * @param streamSize the number of values to generate
+     * @return a stream of pseudorandom {@code long} values
+     * @throws IllegalArgumentException if {@code streamSize} is
+     *         less than zero
+     */
+    @Override
+    public LongStream longs(long streamSize) {
+        if (streamSize < 0L)
+            throw new IllegalArgumentException(BadSize);
+        return StreamSupport.longStream
+            (new RandomLongsSpliterator
+             (0L, streamSize, Long.MAX_VALUE, 0L),
+             false);
+    }
+
+    /**
+     * Returns an effectively unlimited stream of pseudorandom {@code long}
+     * values.
+     *
+     * @implNote This method is implemented to be equivalent to {@code
+     * longs(Long.MAX_VALUE)}.
+     *
+     * @return a stream of pseudorandom {@code long} values
+     */
+    @Override
+    public LongStream longs() {
+        return StreamSupport.longStream
+            (new RandomLongsSpliterator
+             (0L, Long.MAX_VALUE, Long.MAX_VALUE, 0L),
+             false);
+    }
+
+    /**
+     * Returns a stream producing the given {@code streamSize} number of
+     * pseudorandom {@code long} values, each conforming to the
+     * given origin and bound.
+     *
+     * @param streamSize the number of values to generate
+     * @param randomNumberOrigin the origin of each random value
+     * @param randomNumberBound the bound of each random value
+     * @return a stream of pseudorandom {@code long} values,
+     *         each with the given origin and bound
+     * @throws IllegalArgumentException if {@code streamSize} is
+     *         less than zero, or {@code randomNumberOrigin}
+     *         is greater than or equal to {@code randomNumberBound}
+     */
+    @Override
+    public LongStream longs(long streamSize, long randomNumberOrigin,
+                            long randomNumberBound) {
+        if (streamSize < 0L)
+            throw new IllegalArgumentException(BadSize);
+        if (randomNumberOrigin >= randomNumberBound)
+            throw new IllegalArgumentException(BadRange);
+        return StreamSupport.longStream
+            (new RandomLongsSpliterator
+             (0L, streamSize, randomNumberOrigin, randomNumberBound),
+             false);
+    }
+
+    /**
+     * Returns an effectively unlimited stream of pseudorandom {@code
+     * long} values, each conforming to the given origin and bound.
+     *
+     * @implNote This method is implemented to be equivalent to {@code
+     * longs(Long.MAX_VALUE, randomNumberOrigin, randomNumberBound)}.
+     *
+     * @param randomNumberOrigin the origin of each random value
+     * @param randomNumberBound the bound of each random value
+     * @return a stream of pseudorandom {@code long} values,
+     *         each with the given origin and bound
+     * @throws IllegalArgumentException if {@code randomNumberOrigin}
+     *         is greater than or equal to {@code randomNumberBound}
+     */
+    @Override
+    public LongStream longs(long randomNumberOrigin, long randomNumberBound) {
+        if (randomNumberOrigin >= randomNumberBound)
+            throw new IllegalArgumentException(BadRange);
+        return StreamSupport.longStream
+            (new RandomLongsSpliterator
+             (0L, Long.MAX_VALUE, randomNumberOrigin, randomNumberBound),
+             false);
+    }
+
+    /**
+     * Returns a stream producing the given {@code streamSize} number of
+     * pseudorandom {@code double} values, each between zero
+     * (inclusive) and one (exclusive).
+     *
+     * @param streamSize the number of values to generate
+     * @return a stream of {@code double} values
+     * @throws IllegalArgumentException if {@code streamSize} is
+     *         less than zero
+     */
+    @Override
+    public DoubleStream doubles(long streamSize) {
+        if (streamSize < 0L)
+            throw new IllegalArgumentException(BadSize);
+        return StreamSupport.doubleStream
+            (new RandomDoublesSpliterator
+             (0L, streamSize, Double.MAX_VALUE, 0.0),
+             false);
+    }
+
+    /**
+     * Returns an effectively unlimited stream of pseudorandom {@code
+     * double} values, each between zero (inclusive) and one
+     * (exclusive).
+     *
+     * @implNote This method is implemented to be equivalent to {@code
+     * doubles(Long.MAX_VALUE)}.
+     *
+     * @return a stream of pseudorandom {@code double} values
+     */
+    @Override
+    public DoubleStream doubles() {
+        return StreamSupport.doubleStream
+            (new RandomDoublesSpliterator
+             (0L, Long.MAX_VALUE, Double.MAX_VALUE, 0.0),
+             false);
+    }
+
+    /**
+     * Returns a stream producing the given {@code streamSize} number of
+     * pseudorandom {@code double} values, each conforming to the
+     * given origin and bound.
+     *
+     * @param streamSize the number of values to generate
+     * @param randomNumberOrigin the origin of each random value
+     * @param randomNumberBound the bound of each random value
+     * @return a stream of pseudorandom {@code double} values,
+     * each with the given origin and bound
+     * @throws IllegalArgumentException if {@code streamSize} is
+     * less than zero
+     * @throws IllegalArgumentException if {@code randomNumberOrigin}
+     *         is greater than or equal to {@code randomNumberBound}
+     */
+    @Override
+    public DoubleStream doubles(long streamSize, double randomNumberOrigin,
+                                double randomNumberBound) {
+        if (streamSize < 0L)
+            throw new IllegalArgumentException(BadSize);
+        if (!(randomNumberOrigin < randomNumberBound))
+            throw new IllegalArgumentException(BadRange);
+        return StreamSupport.doubleStream
+            (new RandomDoublesSpliterator
+             (0L, streamSize, randomNumberOrigin, randomNumberBound),
+             false);
+    }
+
+    /**
+     * Returns an effectively unlimited stream of pseudorandom {@code
+     * double} values, each conforming to the given origin and bound.
+     *
+     * @implNote This method is implemented to be equivalent to {@code
+     * doubles(Long.MAX_VALUE, randomNumberOrigin, randomNumberBound)}.
+     *
+     * @param randomNumberOrigin the origin of each random value
+     * @param randomNumberBound the bound of each random value
+     * @return a stream of pseudorandom {@code double} values,
+     * each with the given origin and bound
+     * @throws IllegalArgumentException if {@code randomNumberOrigin}
+     *         is greater than or equal to {@code randomNumberBound}
+     */
+    @Override
+    public DoubleStream doubles(double randomNumberOrigin, double randomNumberBound) {
+        if (!(randomNumberOrigin < randomNumberBound))
+            throw new IllegalArgumentException(BadRange);
+        return StreamSupport.doubleStream
+            (new RandomDoublesSpliterator
+             (0L, Long.MAX_VALUE, randomNumberOrigin, randomNumberBound),
+             false);
+    }
+
+    /**
+     * Spliterator for int streams.  We multiplex the four int
+     * versions into one class by treating a bound less than origin as
+     * unbounded, and also by treating "infinite" as equivalent to
+     * Long.MAX_VALUE. For splits, it uses the standard divide-by-two
+     * approach. The long and double versions of this class are
+     * identical except for types.
+     */
+    static final class RandomIntsSpliterator implements Spliterator.OfInt {
+        long index;
+        final long fence;
+        final int origin;
+        final int bound;
+        RandomIntsSpliterator(long index, long fence,
+                              int origin, int bound) {
+            this.index = index; this.fence = fence;
+            this.origin = origin; this.bound = bound;
+        }
+
+        public RandomIntsSpliterator trySplit() {
+            long i = index, m = (i + fence) >>> 1;
+            return (m <= i) ? null :
+                new RandomIntsSpliterator(i, index = m, origin, bound);
+        }
+
+        public long estimateSize() {
+            return fence - index;
+        }
+
+        public int characteristics() {
+            return (Spliterator.SIZED | Spliterator.SUBSIZED |
+                    Spliterator.NONNULL | Spliterator.IMMUTABLE);
+        }
+
+        public boolean tryAdvance(IntConsumer consumer) {
+            if (consumer == null) throw new NullPointerException();
+            long i = index, f = fence;
+            if (i < f) {
+                consumer.accept(ThreadLocalRandom.current().internalNextInt(origin, bound));
+                index = i + 1;
+                return true;
+            }
+            return false;
+        }
+
+        public void forEachRemaining(IntConsumer consumer) {
+            if (consumer == null) throw new NullPointerException();
+            long i = index, f = fence;
+            if (i < f) {
+                index = f;
+                int o = origin, b = bound;
+                ThreadLocalRandom rng = ThreadLocalRandom.current();
+                do {
+                    consumer.accept(rng.internalNextInt(o, b));
+                } while (++i < f);
+            }
+        }
+    }
+
+    /**
+     * Spliterator for long streams.
+     */
+    static final class RandomLongsSpliterator implements Spliterator.OfLong {
+        long index;
+        final long fence;
+        final long origin;
+        final long bound;
+        RandomLongsSpliterator(long index, long fence,
+                               long origin, long bound) {
+            this.index = index; this.fence = fence;
+            this.origin = origin; this.bound = bound;
+        }
+
+        public RandomLongsSpliterator trySplit() {
+            long i = index, m = (i + fence) >>> 1;
+            return (m <= i) ? null :
+                new RandomLongsSpliterator(i, index = m, origin, bound);
+        }
+
+        public long estimateSize() {
+            return fence - index;
+        }
+
+        public int characteristics() {
+            return (Spliterator.SIZED | Spliterator.SUBSIZED |
+                    Spliterator.NONNULL | Spliterator.IMMUTABLE);
+        }
+
+        public boolean tryAdvance(LongConsumer consumer) {
+            if (consumer == null) throw new NullPointerException();
+            long i = index, f = fence;
+            if (i < f) {
+                consumer.accept(ThreadLocalRandom.current().internalNextLong(origin, bound));
+                index = i + 1;
+                return true;
+            }
+            return false;
+        }
+
+        public void forEachRemaining(LongConsumer consumer) {
+            if (consumer == null) throw new NullPointerException();
+            long i = index, f = fence;
+            if (i < f) {
+                index = f;
+                long o = origin, b = bound;
+                ThreadLocalRandom rng = ThreadLocalRandom.current();
+                do {
+                    consumer.accept(rng.internalNextLong(o, b));
+                } while (++i < f);
+            }
+        }
+
+    }
+
+    /**
+     * Spliterator for double streams.
+     */
+    static final class RandomDoublesSpliterator implements Spliterator.OfDouble {
+        long index;
+        final long fence;
+        final double origin;
+        final double bound;
+        RandomDoublesSpliterator(long index, long fence,
+                                 double origin, double bound) {
+            this.index = index; this.fence = fence;
+            this.origin = origin; this.bound = bound;
+        }
+
+        public RandomDoublesSpliterator trySplit() {
+            long i = index, m = (i + fence) >>> 1;
+            return (m <= i) ? null :
+                new RandomDoublesSpliterator(i, index = m, origin, bound);
+        }
+
+        public long estimateSize() {
+            return fence - index;
+        }
+
+        public int characteristics() {
+            return (Spliterator.SIZED | Spliterator.SUBSIZED |
+                    Spliterator.NONNULL | Spliterator.IMMUTABLE);
+        }
+
+        public boolean tryAdvance(DoubleConsumer consumer) {
+            if (consumer == null) throw new NullPointerException();
+            long i = index, f = fence;
+            if (i < f) {
+                consumer.accept(ThreadLocalRandom.current().internalNextDouble(origin, bound));
+                index = i + 1;
+                return true;
+            }
+            return false;
+        }
+
+        public void forEachRemaining(DoubleConsumer consumer) {
+            if (consumer == null) throw new NullPointerException();
+            long i = index, f = fence;
+            if (i < f) {
+                index = f;
+                double o = origin, b = bound;
+                ThreadLocalRandom rng = ThreadLocalRandom.current();
+                do {
+                    consumer.accept(rng.internalNextDouble(o, b));
+                } while (++i < f);
+            }
+        }
+    }
+
+
     // Within-package utilities
 
     /*
@@ -401,23 +976,26 @@
      */
     private static final ObjectStreamField[] serialPersistentFields = {
             new ObjectStreamField("rnd", long.class),
-            new ObjectStreamField("initialized", boolean.class)
+            new ObjectStreamField("initialized", boolean.class),
     };
 
     /**
      * Saves the {@code ThreadLocalRandom} to a stream (that is, serializes it).
+     * @param s the stream
+     * @throws java.io.IOException if an I/O error occurs
      */
-    private void writeObject(java.io.ObjectOutputStream out)
+    private void writeObject(java.io.ObjectOutputStream s)
         throws java.io.IOException {
 
-        java.io.ObjectOutputStream.PutField fields = out.putFields();
+        java.io.ObjectOutputStream.PutField fields = s.putFields();
         fields.put("rnd", UNSAFE.getLong(Thread.currentThread(), SEED));
         fields.put("initialized", true);
-        out.writeFields();
+        s.writeFields();
     }
 
     /**
      * Returns the {@link #current() current} thread's {@code ThreadLocalRandom}.
+     * @return the {@link #current() current} thread's {@code ThreadLocalRandom}
      */
     private Object readResolve() {
         return current();
--- a/src/share/classes/java/util/stream/AbstractPipeline.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/src/share/classes/java/util/stream/AbstractPipeline.java	Wed Aug 14 15:53:13 2013 -0700
@@ -71,6 +71,9 @@
  */
 abstract class AbstractPipeline<E_IN, E_OUT, S extends BaseStream<E_OUT, S>>
         extends PipelineHelper<E_OUT> implements BaseStream<E_OUT, S> {
+    private static final String MSG_STREAM_LINKED = "stream has already been operated upon or closed";
+    private static final String MSG_CONSUMED = "source already consumed or closed";
+
     /**
      * Backlink to the head of the pipeline chain (self if this is the source
      * stage).
@@ -137,6 +140,8 @@
      */
     private boolean sourceAnyStateful;
 
+    private Runnable sourceCloseAction;
+
     /**
      * True if pipeline is parallel, otherwise the pipeline is sequential; only
      * valid for the source stage.
@@ -195,7 +200,7 @@
      */
     AbstractPipeline(AbstractPipeline<?, E_IN, ?> previousStage, int opFlags) {
         if (previousStage.linkedOrConsumed)
-            throw new IllegalStateException("stream has already been operated upon");
+            throw new IllegalStateException(MSG_STREAM_LINKED);
         previousStage.linkedOrConsumed = true;
         previousStage.nextStage = this;
 
@@ -221,7 +226,7 @@
     final <R> R evaluate(TerminalOp<E_OUT, R> terminalOp) {
         assert getOutputShape() == terminalOp.inputShape();
         if (linkedOrConsumed)
-            throw new IllegalStateException("stream has already been operated upon");
+            throw new IllegalStateException(MSG_STREAM_LINKED);
         linkedOrConsumed = true;
 
         return isParallel()
@@ -238,7 +243,7 @@
     @SuppressWarnings("unchecked")
     final Node<E_OUT> evaluateToArrayNode(IntFunction<E_OUT[]> generator) {
         if (linkedOrConsumed)
-            throw new IllegalStateException("stream has already been operated upon");
+            throw new IllegalStateException(MSG_STREAM_LINKED);
         linkedOrConsumed = true;
 
         // If the last intermediate operation is stateful then
@@ -266,7 +271,7 @@
             throw new IllegalStateException();
 
         if (linkedOrConsumed)
-            throw new IllegalStateException("stream has already been operated upon");
+            throw new IllegalStateException(MSG_STREAM_LINKED);
         linkedOrConsumed = true;
 
         if (sourceStage.sourceSpliterator != null) {
@@ -282,7 +287,7 @@
             return s;
         }
         else {
-            throw new IllegalStateException("source already consumed");
+            throw new IllegalStateException(MSG_CONSUMED);
         }
     }
 
@@ -302,12 +307,33 @@
         return (S) this;
     }
 
+    @Override
+    public void close() {
+        linkedOrConsumed = true;
+        sourceSupplier = null;
+        sourceSpliterator = null;
+        if (sourceStage.sourceCloseAction != null) {
+            sourceStage.sourceCloseAction.run();
+            sourceStage.sourceCloseAction = null;
+        }
+    }
+
+    @Override
+    public S onClose(Runnable closeHandler) {
+        Runnable existingHandler = sourceStage.sourceCloseAction;
+        sourceStage.sourceCloseAction =
+                (existingHandler == null)
+                ? closeHandler
+                : Streams.composeWithExceptions(existingHandler, closeHandler);
+        return (S) this;
+    }
+
     // Primitive specialization use co-variant overrides, hence is not final
     @Override
     @SuppressWarnings("unchecked")
     public Spliterator<E_OUT> spliterator() {
         if (linkedOrConsumed)
-            throw new IllegalStateException("stream has already been operated upon");
+            throw new IllegalStateException(MSG_STREAM_LINKED);
         linkedOrConsumed = true;
 
         if (this == sourceStage) {
@@ -324,7 +350,7 @@
                 return lazySpliterator(s);
             }
             else {
-                throw new IllegalStateException("source already consumed");
+                throw new IllegalStateException(MSG_CONSUMED);
             }
         }
         else {
@@ -424,7 +450,7 @@
             sourceStage.sourceSupplier = null;
         }
         else {
-            throw new IllegalStateException("source already consumed");
+            throw new IllegalStateException(MSG_CONSUMED);
         }
 
         if (isParallel()) {
--- a/src/share/classes/java/util/stream/BaseStream.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/src/share/classes/java/util/stream/BaseStream.java	Wed Aug 14 15:53:13 2013 -0700
@@ -24,18 +24,96 @@
  */
 package java.util.stream;
 
+import java.util.Collection;
+import java.util.MayHoldCloseableResource;
 import java.util.Iterator;
 import java.util.Spliterator;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.IntConsumer;
+import java.util.function.Predicate;
 
 /**
- * Base interface for stream types such as {@link Stream}, {@link IntStream},
- * etc.  Contains methods common to all stream types.
+ * A sequence of elements supporting sequential and parallel aggregate
+ * operations.  The following example illustrates an aggregate operation using
+ * {@link Stream} and {@link IntStream}:
+ *
+ * <pre>{@code
+ *     int sum = widgets.stream()
+ *                      .filter(w -> w.getColor() == RED)
+ *                      .mapToInt(w -> w.getWeight())
+ *                      .sum();
+ * }</pre>
+ *
+ * In this example, {@code widgets} is a {@code Collection<Widget>}.  We create
+ * a stream of {@code Widget} objects via {@link Collection#stream Collection.stream()},
+ * filter it to produce a stream containing only the red widgets, and then
+ * transform it into a stream of {@code int} values representing the weight of
+ * each red widget. Then this stream is summed to produce a total weight.
+ *
+ * <p>To perform a computation, stream
+ * <a href="package-summary.html#StreamOps">operations</a> are composed into a
+ * <em>stream pipeline</em>.  A stream pipeline consists of a source (which
+ * might be an array, a collection, a generator function, an IO channel,
+ * etc), zero or more <em>intermediate operations</em> (which transform a
+ * stream into another stream, such as {@link Stream#filter(Predicate)}), and a
+ * <em>terminal operation</em> (which produces a result or side-effect, such
+ * as {@link IntStream#sum()} or {@link IntStream#forEach(IntConsumer)}).
+ * Streams are lazy; computation on the source data is only performed when the
+ * terminal operation is initiated, and source elements are consumed only
+ * as needed.
+ *
+ * <p>Collections and streams, while bearing some superficial similarities,
+ * have different goals.  Collections are primarily concerned with the efficient
+ * management of, and access to, their elements.  By contrast, streams do not
+ * provide a means to directly access or manipulate their elements, and are
+ * instead concerned with declaratively describing their source and the
+ * computational operations which will be performed in aggregate on that source.
+ * However, if the provided stream operations do not offer the desired
+ * functionality, the {@link #iterator()} and {@link #spliterator()} operations
+ * can be used to perform a controlled traversal.
  *
- * @param <T> type of stream elements
- * @param <S> type of stream implementing {@code BaseStream}
+ * <p>A stream pipeline, like the "widgets" example above, can be viewed as
+ * a <em>query</em> on the stream source.  Unless the source was explicitly
+ * designed for concurrent modification (such as a {@link ConcurrentHashMap}),
+ * unpredictable or erroneous behavior may result from modifying the stream
+ * source while it is being queried.
+ *
+ * <p>Most stream operations accept parameters that describe user-specified
+ * behavior, such as the lambda expression {@code w -> w.getWeight()} passed to
+ * {@code mapToInt} in the example above.  Such parameters are always instances
+ * of a <a href="../function/package-summary.html">functional interface</a> such
+ * as {@link java.util.function.Function}, and are often lambda expressions or
+ * method references.  These parameters can never be null, should not modify the
+ * stream source, and should be
+ * <a href="package-summary.html#NonInterference">effectively stateless</a>
+ * (their result should not depend on any state that might change during
+ * execution of the stream pipeline.)
+ *
+ * <p>A stream should be operated on (invoking an intermediate or terminal stream
+ * operation) only once.  This rules out, for example, "forked" streams, where
+ * the same source feeds two or more pipelines, or multiple traversals of the
+ * same stream.  A stream implementation may throw {@link IllegalStateException}
+ * if it detects that the stream is being reused. However, since some stream
+ * operations may return their receiver rather than a new stream object, it may
+ * not be possible to detect reuse in all cases.
+ *
+ * <p>Stream pipelines may execute either sequentially or in
+ * <a href="package-summary.html#Parallelism">parallel</a>.  This
+ * execution mode is a property of the stream.  Streams are created
+ * with an initial choice of sequential or parallel execution.  (For example,
+ * {@link Collection#stream() Collection.stream()} creates a sequential stream,
+ * and {@link Collection#parallelStream() Collection.parallelStream()} creates
+ * a parallel one.)  This choice of execution mode may be modified by the
+ * {@link #sequential()} or {@link #parallel()} methods, and may be queried with
+ * the {@link #isParallel()} method.
+ *
+ * @param <T> the type of the stream elements
+ * @param <S> the type of of the stream implementing {@code BaseStream}
  * @since 1.8
+ * @see <a href="package-summary.html">java.util.stream</a>
  */
-public interface BaseStream<T, S extends BaseStream<T, S>> {
+public interface BaseStream<T, S extends BaseStream<T, S>>
+        extends MayHoldCloseableResource {
     /**
      * Returns an iterator for the elements of this stream.
      *
@@ -57,14 +135,11 @@
     Spliterator<T> spliterator();
 
     /**
-     * Returns whether this stream, when executed, would execute in parallel
-     * (assuming no further modification of the stream, such as appending
-     * further intermediate operations or changing its parallelism).  Calling
-     * this method after invoking an intermediate or terminal stream operation
-     * method may yield unpredictable results.
+     * Returns whether this stream, if a terminal operation were to be executed,
+     * would execute in parallel.  Calling this method after invoking an
+     * terminal stream operation method may yield unpredictable results.
      *
      * @return {@code true} if this stream would execute in parallel if executed
-     * without further modification otherwise {@code false}
      */
     boolean isParallel();
 
@@ -95,7 +170,8 @@
     /**
      * Returns an equivalent stream that is
      * <a href="package-summary.html#Ordering">unordered</a>.  May return
-     * itself if the stream was already unordered.
+     * itself, either because the stream was already unordered, or because
+     * the underlying stream state was modified to be unordered.
      *
      * <p>This is an <a href="package-summary.html#StreamOps">intermediate
      * operation</a>.
@@ -103,4 +179,22 @@
      * @return an unordered stream
      */
     S unordered();
+
+    /**
+     * Returns an equivalent stream with an additional close handler.  Close
+     * handlers are run when the {@link MayHoldCloseableResource#close()} method
+     * is called on the stream, and are executed in the order they were
+     * added.  All close handlers are run, even if earlier close handlers throw
+     * exceptions.  If any close handler throws an exception, the first
+     * exception thrown will be relayed to the caller of {@code close()}, with
+     * any remaining exceptions added to that exception as suppressed exceptions.
+     * May return itself.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @param closeHandler A task to execute when the stream is closed
+     * @return a stream with a handler that is run if the stream is closed
+     */
+    S onClose(Runnable closeHandler);
 }
--- a/src/share/classes/java/util/stream/CloseableStream.java	Tue Aug 13 10:42:37 2013 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,57 +0,0 @@
-/*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  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.stream;
-
-/**
- * A {@code CloseableStream} is a {@code Stream} that can be closed.
- * The close method is invoked to release resources that the object is
- * holding (such as open files).
- *
- * @param <T> The type of stream elements
- * @since 1.8
- */
-public interface CloseableStream<T> extends Stream<T>, AutoCloseable {
-
-    /**
-     * Closes this resource, relinquishing any underlying resources.
-     * This method is invoked automatically on objects managed by the
-     * {@code try}-with-resources statement.  Does nothing if called when
-     * the resource has already been closed.
-     *
-     * This method does not allow throwing checked {@code Exception}s like
-     * {@link AutoCloseable#close() AutoCloseable.close()}. Cases where the
-     * close operation may fail require careful attention by implementers. It
-     * is strongly advised to relinquish the underlying resources and to
-     * internally <em>mark</em> the resource as closed. The {@code close}
-     * method is unlikely to be invoked more than once and so this ensures
-     * that the resources are released in a timely manner. Furthermore it
-     * reduces problems that could arise when the resource wraps, or is
-     * wrapped, by another resource.
-     *
-     * @see AutoCloseable#close()
-     */
-    void close();
-}
--- a/src/share/classes/java/util/stream/Collector.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/src/share/classes/java/util/stream/Collector.java	Wed Aug 14 15:53:13 2013 -0700
@@ -26,6 +26,7 @@
 
 import java.util.Collections;
 import java.util.EnumSet;
+import java.util.Objects;
 import java.util.Set;
 import java.util.function.BiConsumer;
 import java.util.function.BinaryOperator;
@@ -33,71 +34,74 @@
 import java.util.function.Supplier;
 
 /**
- * A <a href="package-summary.html#Reduction">reduction operation</a> that
- * folds input elements into a mutable result container, optionally transforming
+ * A <a href="package-summary.html#Reduction">mutable reduction operation</a> that
+ * accumulates input elements into a mutable result container, optionally transforming
  * the accumulated result into a final representation after all input elements
- * have been processed.
+ * have been processed.  Reduction operations can be performed either sequentially
+ * or in parallel.
  *
  * <p>Examples of mutable reduction operations include:
  * accumulating elements into a {@code Collection}; concatenating
  * strings using a {@code StringBuilder}; computing summary information about
  * elements such as sum, min, max, or average; computing "pivot table" summaries
- * such as "maximum valued transaction by seller", etc.  Reduction operations
- * can be performed either sequentially or in parallel.
- *
- * <p>The following are examples of using the predefined {@code Collector}
- * implementations in {@link Collectors} with the {@code Stream} API to perform
- * mutable reduction tasks:
- * <pre>{@code
- *     // Accumulate names into a List
- *     List<String> list = people.stream().map(Person::getName).collect(Collectors.toList());
- *
- *     // Accumulate names into a TreeSet
- *     Set<String> list = people.stream().map(Person::getName).collect(Collectors.toCollection(TreeSet::new));
- *
- *     // Convert elements to strings and concatenate them, separated by commas
- *     String joined = things.stream()
- *                           .map(Object::toString)
- *                           .collect(Collectors.joining(", "));
- *
- *     // Find highest-paid employee
- *     Employee highestPaid = employees.stream()
- *                                     .collect(Collectors.maxBy(Comparators.comparing(Employee::getSalary)))
- *                                     .get();
- *
- *     // Group employees by department
- *     Map<Department, List<Employee>> byDept
- *         = employees.stream()
- *                    .collect(Collectors.groupingBy(Employee::getDepartment));
- *
- *     // Find highest-paid employee by department
- *     Map<Department, Optional<Employee>> highestPaidByDept
- *         = employees.stream()
- *                    .collect(Collectors.groupingBy(Employee::getDepartment,
- *                                                   Collectors.maxBy(Comparators.comparing(Employee::getSalary))));
- *
- *     // Partition students into passing and failing
- *     Map<Boolean, List<Student>> passingFailing =
- *         students.stream()
- *                 .collect(Collectors.partitioningBy(s -> s.getGrade() >= PASS_THRESHOLD));
- *
- * }</pre>
+ * such as "maximum valued transaction by seller", etc.  The class {@link Collectors}
+ * provides implementations of many common mutable reductions.
  *
  * <p>A {@code Collector} is specified by four functions that work together to
  * accumulate entries into a mutable result container, and optionally perform
- * a final transform on the result.  They are: creation of a new result container,
- * incorporating a new data element into a result container, combining two
- * result containers into one, and performing a final transform on the container.
- * The combiner function is used during parallel operations, where
- * subsets of the input are accumulated into separate result
- * containers, and then the subresults merged into a combined result.  The
- * combiner function may merge one set of subresults into the other and return
- * that, or it may return a new object to describe the combined results.
+ * a final transform on the result.  They are: <ul>
+ *     <li>creation of a new result container ({@link #supplier()})</li>
+ *     <li>incorporating a new data element into a result container ({@link #accumulator()})</li>
+ *     <li>combining two result containers into one ({@link #combiner()})</li>
+ *     <li>performing an optional final transform on the container ({@link #finisher()})</li>
+ * </ul>
  *
  * <p>Collectors also have a set of characteristics, such as
- * {@link Characteristics#CONCURRENT}.  These characteristics provide
- * hints that can be used by a reduction implementation to provide better
- * performance.
+ * {@link Characteristics#CONCURRENT}, that provide hints that can be used by a
+ * reduction implementation to provide better performance.
+ *
+ * <p>A sequential implementation of a reduction using a collector would
+ * create a single result container using the supplier function, and invoke the
+ * accumulator function once for each input element.  A parallel implementation
+ * would partition the input, create a result container for each partition,
+ * accumulate the contents of each partition into a subresult for that partition,
+ * and then use the combiner function to merge the subresults into a combined
+ * result.
+ *
+ * <p>To ensure that sequential and parallel executions produce equivalent
+ * results, the collector functions must satisfy an <em>identity</em> and an
+ * <a href="package-summary.html#Associativity">associativity</a> constraints.
+ *
+ * <p>The identity constraint says that for any partially accumulated result,
+ * combining it with an empty result container must produce an equivalent
+ * result.  That is, for a partially accumulated result {@code a} that is the
+ * result of any series of accumulator and combiner invocations, {@code a} must
+ * be equivalent to {@code combiner.apply(a, supplier.get())}.
+ *
+ * <p>The associativity constraint says that splitting the computation must
+ * produce an equivalent result.  That is, for any input elements {@code t1}
+ * and {@code t2}, the results {@code r1} and {@code r2} in the computation
+ * below must be equivalent:
+ * <pre>{@code
+ *     A a1 = supplier.get();
+ *     accumulator.accept(a1, t1);
+ *     accumulator.accept(a1, t2);
+ *     R r1 = finisher.apply(a1);  // result without splitting
+ *
+ *     A a2 = supplier.get();
+ *     accumulator.accept(a2, t1);
+ *     A a3 = supplier.get();
+ *     accumulator.accept(a3, t2);
+ *     R r2 = finisher.apply(combiner.apply(a2, a3));  // result with splitting
+ * } </pre>
+ *
+ * <p>For collectors that do not have the {@code UNORDERED} characteristic,
+ * two accumulated results {@code a1} and {@code a2} are equivalent if
+ * {@code finisher.apply(a1).equals(finisher.apply(a2))}.  For unordered
+ * collectors, equivalence is relaxed to allow for non-equality related to
+ * differences in order.  (For example, an unordered collector that accumulated
+ * elements to a {@code List} would consider two lists equivalent if they
+ * contained the same elements, ignoring order.)
  *
  * <p>Libraries that implement reduction based on {@code Collector}, such as
  * {@link Stream#collect(Collector)}, must adhere to the following constraints:
@@ -132,6 +136,20 @@
  *     originating data is unordered.</li>
  * </ul>
  *
+ * <p>In addition to the predefined implementations in {@link Collectors}, the
+ * static factory methods {@link #of(Supplier, BiConsumer, BinaryOperator, Characteristics...)}
+ * can be used to construct collectors.  For example, you could create a collector
+ * that accumulates widgets into into a {@code TreeSet} with:
+ *
+ * <pre>{@code
+ *     Collector<Widget, ?, TreeSet<Widget>> intoSet =
+ *         Collector.of(TreeSet::new, TreeSet::add,
+ *                      (left, right) -> { left.addAll(right); return left; });
+ * }</pre>
+ *
+ * (This behavior is also implemented by the predefined collector
+ * {@link Collectors#toCollection(Supplier)}).
+ *
  * @apiNote
  * Performing a reduction operation with a {@code Collector} should produce a
  * result equivalent to:
@@ -144,20 +162,28 @@
  *
  * <p>However, the library is free to partition the input, perform the reduction
  * on the partitions, and then use the combiner function to combine the partial
- * results to achieve a parallel reduction.  Depending on the specific reduction
+ * results to achieve a parallel reduction.  (Depending on the specific reduction
  * operation, this may perform better or worse, depending on the relative cost
- * of the accumulator and combiner functions.
+ * of the accumulator and combiner functions.)
+ *
+ * <p>Collectors are designed to be <em>composed</em>; many of the methods
+ * in {@link Collectors} are functions that take a collector and produce
+ * a new collector.  For example, given the following collector that computes
+ * the sum of the salaries of a stream of employees:
  *
- * <p>An example of an operation that can be easily modeled by {@code Collector}
- * is accumulating elements into a {@code TreeSet}. In this case, the {@code
- * resultSupplier()} function is {@code () -> new Treeset<T>()}, the
- * {@code accumulator} function is
- * {@code (set, element) -> set.add(element) }, and the combiner
- * function is {@code (left, right) -> { left.addAll(right); return left; }}.
- * (This behavior is implemented by
- * {@code Collectors.toCollection(TreeSet::new)}).
+ * <pre>{@code
+ *     Collector<Employee, ?, Integer> summingSalaries
+ *         = Collectors.summingInt(Employee::getSalary))
+ * } </pre>
  *
- * TODO Associativity and commutativity
+ * If we wanted to create a collector to tabulate the sum of salaries by
+ * department, we could reuse the "sum of salaries" logic using
+ * {@link Collectors#groupingBy(Function, Collector)}:
+ *
+ * <pre>{@code
+ *     Collector<Employee, ?, Map<Department, Integer>> summingSalariesByDept
+ *         = Collectors.groupingBy(Employee::getDepartment, summingSalaries);
+ * } </pre>
  *
  * @see Stream#collect(Collector)
  * @see Collectors
@@ -177,25 +203,25 @@
     Supplier<A> supplier();
 
     /**
-     * A function that folds a new value into a mutable result container.
+     * A function that folds a value into a mutable result container.
      *
-     * @return a function which folds a new value into a mutable result container
+     * @return a function which folds a value into a mutable result container
      */
     BiConsumer<A, T> accumulator();
 
     /**
      * A function that accepts two partial results and merges them.  The
      * combiner function may fold state from one argument into the other and
-     * return that, or may return a new result object.
+     * return that, or may return a new result container.
      *
-     * @return a function which combines two partial results into a cumulative
+     * @return a function which combines two partial results into a combined
      * result
      */
     BinaryOperator<A> combiner();
 
     /**
      * Perform the final transformation from the intermediate accumulation type
-     * {@code A} to the final result representation {@code R}.
+     * {@code A} to the final result type {@code R}.
      *
      * <p>If the characteristic {@code IDENTITY_TRANSFORM} is
      * set, this function may be presumed to be an identity transform with an
@@ -228,12 +254,17 @@
      * @param <T> The type of input elements for the new collector
      * @param <R> The type of intermediate accumulation result, and final result,
      *           for the new collector
+     * @throws NullPointerException if any argument is null
      * @return the new {@code Collector}
      */
     public static<T, R> Collector<T, R, R> of(Supplier<R> supplier,
                                               BiConsumer<R, T> accumulator,
                                               BinaryOperator<R> combiner,
                                               Characteristics... characteristics) {
+        Objects.requireNonNull(supplier);
+        Objects.requireNonNull(accumulator);
+        Objects.requireNonNull(combiner);
+        Objects.requireNonNull(characteristics);
         Set<Characteristics> cs = (characteristics.length == 0)
                                   ? Collectors.CH_ID
                                   : Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.IDENTITY_FINISH,
@@ -254,6 +285,7 @@
      * @param <T> The type of input elements for the new collector
      * @param <A> The intermediate accumulation type of the new collector
      * @param <R> The final result type of the new collector
+     * @throws NullPointerException if any argument is null
      * @return the new {@code Collector}
      */
     public static<T, A, R> Collector<T, A, R> of(Supplier<A> supplier,
@@ -261,6 +293,11 @@
                                                  BinaryOperator<A> combiner,
                                                  Function<A, R> finisher,
                                                  Characteristics... characteristics) {
+        Objects.requireNonNull(supplier);
+        Objects.requireNonNull(accumulator);
+        Objects.requireNonNull(combiner);
+        Objects.requireNonNull(finisher);
+        Objects.requireNonNull(characteristics);
         Set<Characteristics> cs = Collectors.CH_NOID;
         if (characteristics.length > 0) {
             cs = EnumSet.noneOf(Characteristics.class);
@@ -288,8 +325,9 @@
         CONCURRENT,
 
         /**
-         * Indicates that the result container has no intrinsic order, such as
-         * a {@link Set}.
+         * Indicates that the collection operation does not commit to preserving
+         * the encounter order of input elements.  (This might be true if the
+         * result container has no intrinsic order, such as a {@link Set}.)
          */
         UNORDERED,
 
--- a/src/share/classes/java/util/stream/Collectors.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/src/share/classes/java/util/stream/Collectors.java	Wed Aug 14 15:53:13 2013 -0700
@@ -62,37 +62,35 @@
  * operations, such as accumulating elements into collections, summarizing
  * elements according to various criteria, etc.
  *
- * <p>The following are examples of using the predefined {@code Collector}
- * implementations in {@link Collectors} with the {@code Stream} API to perform
- * mutable reduction tasks:
+ * <p>The following are examples of using the predefined collectors to perform
+ * common mutable reduction tasks:
  *
  * <pre>{@code
  *     // Accumulate names into a List
  *     List<String> list = people.stream().map(Person::getName).collect(Collectors.toList());
  *
  *     // Accumulate names into a TreeSet
- *     Set<String> list = people.stream().map(Person::getName).collect(Collectors.toCollection(TreeSet::new));
+ *     Set<String> set = people.stream().map(Person::getName).collect(Collectors.toCollection(TreeSet::new));
  *
  *     // Convert elements to strings and concatenate them, separated by commas
  *     String joined = things.stream()
  *                           .map(Object::toString)
  *                           .collect(Collectors.joining(", "));
  *
- *     // Find highest-paid employee
- *     Employee highestPaid = employees.stream()
- *                                     .collect(Collectors.maxBy(Comparator.comparing(Employee::getSalary)))
- *                                     .get();
+ *     // Compute sum of salaries of employee
+ *     int highestPaid = employees.stream()
+ *                                .collect(Collectors.summingInt(Employee::getSalary)));
  *
  *     // Group employees by department
  *     Map<Department, List<Employee>> byDept
  *         = employees.stream()
  *                    .collect(Collectors.groupingBy(Employee::getDepartment));
  *
- *     // Find highest-paid employee by department
- *     Map<Department, Optional<Employee>> highestPaidByDept
+ *     // Compute sum of salaries by department
+ *     Map<Department, Integer> highestPaidByDept
  *         = employees.stream()
  *                    .collect(Collectors.groupingBy(Employee::getDepartment,
- *                                                   Collectors.maxBy(Comparator.comparing(Employee::getSalary))));
+ *                                                   Collectors.summingInt(Employee::getSalary)));
  *
  *     // Partition students into passing and failing
  *     Map<Boolean, List<Student>> passingFailing =
@@ -101,8 +99,6 @@
  *
  * }</pre>
  *
- * TODO explanation of parallel collection
- *
  * @since 1.8
  */
 public final class Collectors {
@@ -217,7 +213,8 @@
     /**
      * Returns a {@code Collector} that accumulates the input elements into a
      * new {@code List}. There are no guarantees on the type, mutability,
-     * serializability, or thread-safety of the {@code List} returned.
+     * serializability, or thread-safety of the {@code List} returned; if more
+     * control over the returned {@code List} is required, use {@link #toCollection(Supplier)}.
      *
      * @param <T> the type of the input elements
      * @return a {@code Collector} which collects all the input elements into a
@@ -233,7 +230,9 @@
     /**
      * Returns a {@code Collector} that accumulates the input elements into a
      * new {@code Set}. There are no guarantees on the type, mutability,
-     * serializability, or thread-safety of the {@code Set} returned.
+     * serializability, or thread-safety of the {@code Set} returned; if more
+     * control over the returned {@code List} is required, use
+     * {@link #toCollection(Supplier)}.
      *
      * <p>This is an {@link Collector.Characteristics#UNORDERED unordered}
      * Collector.
@@ -354,6 +353,43 @@
     }
 
     /**
+     * Adapts a {@code Collector} to perform an additional finishing
+     * transformation.  For example, one could adapt the {@link #toList()}
+     * collector to always produce an immutable list with:
+     * <pre>{@code
+     *     List<String> people
+     *         = people.stream().collect(collectingAndThen(toList(), Collections::unmodifiableList));
+     * }</pre>
+     *
+     * @param <T> the type of the input elements
+     * @param <A> intermediate accumulation type of the downstream collector
+     * @param <R> result type of the downstream collector
+     * @param <RR> result type of the resulting collector
+     * @param finisher a function to be applied to the final result of the downstream collector
+     * @param downstream a collector
+     * @return a collector which performs the action of the downstream collector,
+     * followed by an additional finishing step
+     */
+    public static<T,A,R,RR> Collector<T,A,RR> collectingAndThen(Collector<T,A,R> downstream,
+                                                                Function<R,RR> finisher) {
+        Set<Collector.Characteristics> characteristics = downstream.characteristics();
+        if (characteristics.contains(Collector.Characteristics.IDENTITY_FINISH)) {
+            if (characteristics.size() == 1)
+                characteristics = Collectors.CH_NOID;
+            else {
+                characteristics = EnumSet.copyOf(characteristics);
+                characteristics.remove(Collector.Characteristics.IDENTITY_FINISH);
+                characteristics = Collections.unmodifiableSet(characteristics);
+            }
+        }
+        return new CollectorImpl<>(downstream.supplier(),
+                                   downstream.accumulator(),
+                                   downstream.combiner(),
+                                   downstream.finisher().andThen(finisher),
+                                   characteristics);
+    }
+
+    /**
      * Returns a {@code Collector} accepting elements of type {@code T} that
      * counts the number of input elements.  If no elements are present, the
      * result is 0.
--- a/src/share/classes/java/util/stream/DelegatingStream.java	Tue Aug 13 10:42:37 2013 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,270 +0,0 @@
-/*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  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.stream;
-
-import java.util.Comparator;
-import java.util.Iterator;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.Spliterator;
-import java.util.function.BiConsumer;
-import java.util.function.BiFunction;
-import java.util.function.BinaryOperator;
-import java.util.function.Consumer;
-import java.util.function.Function;
-import java.util.function.IntFunction;
-import java.util.function.Predicate;
-import java.util.function.Supplier;
-import java.util.function.ToDoubleFunction;
-import java.util.function.ToIntFunction;
-import java.util.function.ToLongFunction;
-
-/**
- * A {@code Stream} implementation that delegates operations to another {@code
- * Stream}.
- *
- * @param <T> type of stream elements for this stream and underlying delegate
- * stream
- *
- * @since 1.8
- */
-public class DelegatingStream<T> implements Stream<T> {
-    final private Stream<T> delegate;
-
-    /**
-     * Construct a {@code Stream} that delegates operations to another {@code
-     * Stream}.
-     *
-     * @param delegate the underlying {@link Stream} to which we delegate all
-     *                 {@code Stream} methods
-     * @throws NullPointerException if the delegate is null
-     */
-    public DelegatingStream(Stream<T> delegate) {
-        this.delegate = Objects.requireNonNull(delegate);
-    }
-
-    // -- BaseStream methods --
-
-    @Override
-    public Spliterator<T> spliterator() {
-        return delegate.spliterator();
-    }
-
-    @Override
-    public boolean isParallel() {
-        return delegate.isParallel();
-    }
-
-    @Override
-    public Iterator<T> iterator() {
-        return delegate.iterator();
-    }
-
-    // -- Stream methods --
-
-    @Override
-    public Stream<T> filter(Predicate<? super T> predicate) {
-        return delegate.filter(predicate);
-    }
-
-    @Override
-    public <R> Stream<R> map(Function<? super T, ? extends R> mapper) {
-        return delegate.map(mapper);
-    }
-
-    @Override
-    public IntStream mapToInt(ToIntFunction<? super T> mapper) {
-        return delegate.mapToInt(mapper);
-    }
-
-    @Override
-    public LongStream mapToLong(ToLongFunction<? super T> mapper) {
-        return delegate.mapToLong(mapper);
-    }
-
-    @Override
-    public DoubleStream mapToDouble(ToDoubleFunction<? super T> mapper) {
-        return delegate.mapToDouble(mapper);
-    }
-
-    @Override
-    public <R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper) {
-        return delegate.flatMap(mapper);
-    }
-
-    @Override
-    public IntStream flatMapToInt(Function<? super T, ? extends IntStream> mapper) {
-        return delegate.flatMapToInt(mapper);
-    }
-
-    @Override
-    public LongStream flatMapToLong(Function<? super T, ? extends LongStream> mapper) {
-        return delegate.flatMapToLong(mapper);
-    }
-
-    @Override
-    public DoubleStream flatMapToDouble(Function<? super T, ? extends DoubleStream> mapper) {
-        return delegate.flatMapToDouble(mapper);
-    }
-
-    @Override
-    public Stream<T> distinct() {
-        return delegate.distinct();
-    }
-
-    @Override
-    public Stream<T> sorted() {
-        return delegate.sorted();
-    }
-
-    @Override
-    public Stream<T> sorted(Comparator<? super T> comparator) {
-        return delegate.sorted(comparator);
-    }
-
-    @Override
-    public void forEach(Consumer<? super T> action) {
-        delegate.forEach(action);
-    }
-
-    @Override
-    public void forEachOrdered(Consumer<? super T> action) {
-        delegate.forEachOrdered(action);
-    }
-
-    @Override
-    public Stream<T> peek(Consumer<? super T> consumer) {
-        return delegate.peek(consumer);
-    }
-
-    @Override
-    public Stream<T> limit(long maxSize) {
-        return delegate.limit(maxSize);
-    }
-
-    @Override
-    public Stream<T> substream(long startingOffset) {
-        return delegate.substream(startingOffset);
-    }
-
-    @Override
-    public Stream<T> substream(long startingOffset, long endingOffset) {
-        return delegate.substream(startingOffset, endingOffset);
-    }
-
-    @Override
-    public <A> A[] toArray(IntFunction<A[]> generator) {
-        return delegate.toArray(generator);
-    }
-
-    @Override
-    public Object[] toArray() {
-        return delegate.toArray();
-    }
-
-    @Override
-    public T reduce(T identity, BinaryOperator<T> accumulator) {
-        return delegate.reduce(identity, accumulator);
-    }
-
-    @Override
-    public Optional<T> reduce(BinaryOperator<T> accumulator) {
-        return delegate.reduce(accumulator);
-    }
-
-    @Override
-    public <U> U reduce(U identity, BiFunction<U, ? super T, U> accumulator,
-                        BinaryOperator<U> combiner) {
-        return delegate.reduce(identity, accumulator, combiner);
-    }
-
-    @Override
-    public <R> R collect(Supplier<R> resultFactory,
-                         BiConsumer<R, ? super T> accumulator,
-                         BiConsumer<R, R> combiner) {
-        return delegate.collect(resultFactory, accumulator, combiner);
-    }
-
-    @Override
-    public <R, A> R collect(Collector<? super T, A, ? extends R> collector) {
-        return delegate.collect(collector);
-    }
-
-    @Override
-    public Optional<T> max(Comparator<? super T> comparator) {
-        return delegate.max(comparator);
-    }
-
-    @Override
-    public Optional<T> min(Comparator<? super T> comparator) {
-        return delegate.min(comparator);
-    }
-
-    @Override
-    public long count() {
-        return delegate.count();
-    }
-
-    @Override
-    public boolean anyMatch(Predicate<? super T> predicate) {
-        return delegate.anyMatch(predicate);
-    }
-
-    @Override
-    public boolean allMatch(Predicate<? super T> predicate) {
-        return delegate.allMatch(predicate);
-    }
-
-    @Override
-    public boolean noneMatch(Predicate<? super T> predicate) {
-        return delegate.noneMatch(predicate);
-    }
-
-    @Override
-    public Optional<T> findFirst() {
-        return delegate.findFirst();
-    }
-
-    @Override
-    public Optional<T> findAny() {
-        return delegate.findAny();
-    }
-
-    @Override
-    public Stream<T> unordered() {
-        return delegate.unordered();
-    }
-
-    @Override
-    public Stream<T> sequential() {
-        return delegate.sequential();
-    }
-
-    @Override
-    public Stream<T> parallel() {
-        return delegate.parallel();
-    }
-}
--- a/src/share/classes/java/util/stream/DistinctOps.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/src/share/classes/java/util/stream/DistinctOps.java	Wed Aug 14 15:53:13 2013 -0700
@@ -101,7 +101,7 @@
                 if (StreamOpFlag.DISTINCT.isKnown(flags)) {
                     return sink;
                 } else if (StreamOpFlag.SORTED.isKnown(flags)) {
-                    return new Sink.ChainedReference<T>(sink) {
+                    return new Sink.ChainedReference<T, T>(sink) {
                         boolean seenNull;
                         T lastSeen;
 
@@ -132,7 +132,7 @@
                         }
                     };
                 } else {
-                    return new Sink.ChainedReference<T>(sink) {
+                    return new Sink.ChainedReference<T, T>(sink) {
                         Set<T> seen;
 
                         @Override
--- a/src/share/classes/java/util/stream/DoublePipeline.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/src/share/classes/java/util/stream/DoublePipeline.java	Wed Aug 14 15:53:13 2013 -0700
@@ -191,7 +191,7 @@
                                        StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
             @Override
             Sink<Double> opWrapSink(int flags, Sink<Double> sink) {
-                return new Sink.ChainedDouble(sink) {
+                return new Sink.ChainedDouble<Double>(sink) {
                     @Override
                     public void accept(double t) {
                         downstream.accept(mapper.applyAsDouble(t));
@@ -208,7 +208,7 @@
                                                             StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
             @Override
             Sink<Double> opWrapSink(int flags, Sink<U> sink) {
-                return new Sink.ChainedDouble(sink) {
+                return new Sink.ChainedDouble<U>(sink) {
                     @Override
                     @SuppressWarnings("unchecked")
                     public void accept(double t) {
@@ -226,7 +226,7 @@
                                                    StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
             @Override
             Sink<Double> opWrapSink(int flags, Sink<Integer> sink) {
-                return new Sink.ChainedDouble(sink) {
+                return new Sink.ChainedDouble<Integer>(sink) {
                     @Override
                     public void accept(double t) {
                         downstream.accept(mapper.applyAsInt(t));
@@ -243,7 +243,7 @@
                                                     StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
             @Override
             Sink<Double> opWrapSink(int flags, Sink<Long> sink) {
-                return new Sink.ChainedDouble(sink) {
+                return new Sink.ChainedDouble<Long>(sink) {
                     @Override
                     public void accept(double t) {
                         downstream.accept(mapper.applyAsLong(t));
@@ -259,7 +259,7 @@
                                         StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT | StreamOpFlag.NOT_SIZED) {
             @Override
             Sink<Double> opWrapSink(int flags, Sink<Double> sink) {
-                return new Sink.ChainedDouble(sink) {
+                return new Sink.ChainedDouble<Double>(sink) {
                     @Override
                     public void begin(long size) {
                         downstream.begin(-1);
@@ -267,10 +267,11 @@
 
                     @Override
                     public void accept(double t) {
-                        // We can do better that this too; optimize for depth=0 case and just grab spliterator and forEach it
-                        DoubleStream result = mapper.apply(t);
-                        if (result != null)
-                            result.sequential().forEach(i -> downstream.accept(i));
+                        try (DoubleStream result = mapper.apply(t)) {
+                            // We can do better that this too; optimize for depth=0 case and just grab spliterator and forEach it
+                            if (result != null)
+                                result.sequential().forEach(i -> downstream.accept(i));
+                        }
                     }
                 };
             }
@@ -296,7 +297,7 @@
                                        StreamOpFlag.NOT_SIZED) {
             @Override
             Sink<Double> opWrapSink(int flags, Sink<Double> sink) {
-                return new Sink.ChainedDouble(sink) {
+                return new Sink.ChainedDouble<Double>(sink) {
                     @Override
                     public void begin(long size) {
                         downstream.begin(-1);
@@ -313,16 +314,16 @@
     }
 
     @Override
-    public final DoubleStream peek(DoubleConsumer consumer) {
-        Objects.requireNonNull(consumer);
+    public final DoubleStream peek(DoubleConsumer action) {
+        Objects.requireNonNull(action);
         return new StatelessOp<Double>(this, StreamShape.DOUBLE_VALUE,
                                        0) {
             @Override
             Sink<Double> opWrapSink(int flags, Sink<Double> sink) {
-                return new Sink.ChainedDouble(sink) {
+                return new Sink.ChainedDouble<Double>(sink) {
                     @Override
                     public void accept(double t) {
-                        consumer.accept(t);
+                        action.accept(t);
                         downstream.accept(t);
                     }
                 };
@@ -436,14 +437,14 @@
     }
 
     @Override
-    public final <R> R collect(Supplier<R> resultFactory,
+    public final <R> R collect(Supplier<R> supplier,
                                ObjDoubleConsumer<R> accumulator,
                                BiConsumer<R, R> combiner) {
         BinaryOperator<R> operator = (left, right) -> {
             combiner.accept(left, right);
             return left;
         };
-        return evaluate(ReduceOps.makeDouble(resultFactory, accumulator, operator));
+        return evaluate(ReduceOps.makeDouble(supplier, accumulator, operator));
     }
 
     @Override
--- a/src/share/classes/java/util/stream/DoubleStream.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/src/share/classes/java/util/stream/DoubleStream.java	Wed Aug 14 15:53:13 2013 -0700
@@ -25,12 +25,14 @@
 package java.util.stream;
 
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.DoubleSummaryStatistics;
 import java.util.Objects;
 import java.util.OptionalDouble;
 import java.util.PrimitiveIterator;
 import java.util.Spliterator;
 import java.util.Spliterators;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.function.BiConsumer;
 import java.util.function.DoubleBinaryOperator;
 import java.util.function.DoubleConsumer;
@@ -45,40 +47,79 @@
 import java.util.function.Supplier;
 
 /**
- * A sequence of primitive double elements supporting sequential and parallel
- * bulk operations. Streams support lazy intermediate operations (transforming
- * a stream to another stream) such as {@code filter} and {@code map}, and terminal
- * operations (consuming the contents of a stream to produce a result or
- * side-effect), such as {@code forEach}, {@code findFirst}, and {@code
- * iterator}.  Once an operation has been performed on a stream, it
- * is considered <em>consumed</em> and no longer usable for other operations.
+ * A sequence of elements supporting sequential and parallel aggregate
+ * operations.  The following example illustrates an aggregate operation using
+ * {@link Stream} and {@link DoubleStream}:
+ *
+ * <pre>{@code
+ *     double sum = widgets.stream()
+ *                         .filter(w -> w.getColor() == RED)
+ *                         .mapToDouble(w -> w.getWeight())
+ *                         .sum();
+ * }</pre>
  *
- * <p>For sequential stream pipelines, all operations are performed in the
- * <a href="package-summary.html#Ordering">encounter order</a> of the pipeline
- * source, if the pipeline source has a defined encounter order.
+ * In this example, {@code widgets} is a {@code Collection<Widget>}.  We create
+ * a stream of {@code Widget} objects via {@link Collection#stream Collection.stream()},
+ * filter it to produce a stream containing only the red widgets, and then
+ * transform it into a stream of {@code double} values representing the weight of
+ * each red widget. Then this stream is summed to produce a total weight.
+ *
+ * <p>To perform a computation, stream
+ * <a href="package-summary.html#StreamOps">operations</a> are composed into a
+ * <em>stream pipeline</em>.  A stream pipeline consists of a source (which
+ * might be an array, a collection, a generator function, an IO channel,
+ * etc), zero or more <em>intermediate operations</em> (which transform a
+ * stream into another stream, such as {@link DoubleStream#filter(DoublePredicate)}), and a
+ * <em>terminal operation</em> (which produces a result or side-effect, such
+ * as {@link DoubleStream#sum()} or {@link DoubleStream#forEach(DoubleConsumer)}.
+ * Streams are lazy; computation on the source data is only performed when the
+ * terminal operation is initiated, and source elements are consumed only
+ * as needed.
  *
- * <p>For parallel stream pipelines, unless otherwise specified, intermediate
- * stream operations preserve the <a href="package-summary.html#Ordering">
- * encounter order</a> of their source, and terminal operations
- * respect the encounter order of their source, if the source
- * has an encounter order.  Provided that and parameters to stream operations
- * satisfy the <a href="package-summary.html#NonInterference">non-interference
- * requirements</a>, and excepting differences arising from the absence of
- * a defined encounter order, the result of a stream pipeline should be the
- * stable across multiple executions of the same operations on the same source.
- * However, the timing and thread in which side-effects occur (for those
- * operations which are allowed to produce side-effects, such as
- * {@link #forEach(DoubleConsumer)}), are explicitly nondeterministic for parallel
- * execution of stream pipelines.
+ * <p>Collections and streams, while bearing some superficial similarities,
+ * have different goals.  Collections are primarily concerned with the efficient
+ * management of, and access to, their elements.  By contrast, streams do not
+ * provide a means to directly access or manipulate their elements, and are
+ * instead concerned with declaratively describing their source and the
+ * computational operations which will be performed in aggregate on that source.
+ * However, if the provided stream operations do not offer the desired
+ * functionality, the {@link #iterator()} and {@link #spliterator()} operations
+ * can be used to perform a controlled traversal.
+ *
+ * <p>A stream pipeline, like the "widgets" example above, can be viewed as
+ * a <em>query</em> on the stream source.  Unless the source was explicitly
+ * designed for concurrent modification (such as a {@link ConcurrentHashMap}),
+ * unpredictable or erroneous behavior may result from modifying the stream
+ * source while it is being queried.
  *
- * <p>Unless otherwise noted, passing a {@code null} argument to any stream
- * method may result in a {@link NullPointerException}.
+ * <p>Most stream operations accept parameters that describe user-specified
+ * behavior, such as the lambda expression {@code w -> w.getWeight()} passed to
+ * {@code mapToDouble} in the example above.  Such parameters are always instances
+ * of a <a href="../function/package-summary.html">functional interface</a> such
+ * as {@link java.util.function.Function}, and are often lambda expressions or
+ * method references.  These parameters can never be null, should not modify the
+ * stream source, and should be
+ * <a href="package-summary.html#NonInterference">effectively stateless</a>
+ * (their result should not depend on any state that might change during
+ * execution of the stream pipeline.)
  *
- * @apiNote
- * Streams are not data structures; they do not manage the storage for their
- * elements, nor do they support access to individual elements.  However,
- * you can use the {@link #iterator()} or {@link #spliterator()} operations to
- * perform a controlled traversal.
+ * <p>A stream should be operated on (invoking an intermediate or terminal stream
+ * operation) only once.  This rules out, for example, "forked" streams, where
+ * the same source feeds two or more pipelines, or multiple traversals of the
+ * same stream.  A stream implementation may throw {@link IllegalStateException}
+ * if it detects that the stream is being reused. However, since some stream
+ * operations may return their receiver rather than a new stream object, it may
+ * not be possible to detect reuse in all cases.
+ *
+ * <p>Stream pipelines may execute either sequentially or in
+ * <a href="package-summary.html#Parallelism">parallel</a>.  This
+ * execution mode is a property of the stream.  Streams are created
+ * with an initial choice of sequential or parallel execution.  (For example,
+ * {@link Collection#stream() Collection.stream()} creates a sequential stream,
+ * and {@link Collection#parallelStream() Collection.parallelStream()} creates
+ * a parallel one.)  This choice of execution mode may be modified by the
+ * {@link #sequential()} or {@link #parallel()} methods, and may be queried with
+ * the {@link #isParallel()} method.
  *
  * @since 1.8
  * @see <a href="package-summary.html">java.util.stream</a>
@@ -159,22 +200,13 @@
     /**
      * Returns a stream consisting of the results of replacing each element of
      * this stream with the contents of the stream produced by applying the
-     * provided mapping function to each element.
+     * provided mapping function to each element.  (If the result of the mapping
+     * function is {@code null}, this is treated as if the result was an empty
+     * stream.)
      *
      * <p>This is an <a href="package-summary.html#StreamOps">intermediate
      * operation</a>.
      *
-     * @apiNote
-     * The {@code flatMap()} operation has the effect of applying a one-to-many
-     * tranformation to the elements of the stream, and then flattening the
-     * resulting elements into a new stream. For example, if {@code orders}
-     * is a stream of purchase orders, and each purchase order contains a
-     * collection of line items, then the following produces a stream of line
-     * items:
-     * <pre>{@code
-     *     orderStream.flatMap(order -> order.getLineItems().stream())...
-     * }</pre>
-     *
      * @param mapper a <a href="package-summary.html#NonInterference">
      *               non-interfering, stateless</a> function to apply to
      *               each element which produces an {@code DoubleStream} of new
@@ -232,12 +264,12 @@
      *         .collect(Collectors.toDoubleSummaryStastistics());
      * }</pre>
      *
-     * @param consumer a <a href="package-summary.html#NonInterference">
+     * @param action a <a href="package-summary.html#NonInterference">
      *                 non-interfering</a> action to perform on the elements as
      *                 they are consumed from the stream
      * @return the new stream
      */
-    DoubleStream peek(DoubleConsumer consumer);
+    DoubleStream peek(DoubleConsumer action);
 
     /**
      * Returns a stream consisting of the elements of this stream, truncated
@@ -254,8 +286,8 @@
 
     /**
      * Returns a stream consisting of the remaining elements of this stream
-     * after indexing {@code startInclusive} elements into the stream. If the
-     * {@code startInclusive} index lies past the end of this stream then an
+     * after discarding the first {@code startInclusive} elements of the stream.
+     * If this stream contains fewer than {@code startInclusive} elements then an
      * empty stream will be returned.
      *
      * <p>This is a <a href="package-summary.html#StreamOps">stateful
@@ -269,10 +301,10 @@
 
     /**
      * Returns a stream consisting of the remaining elements of this stream
-     * after indexing {@code startInclusive} elements into the stream and
-     * truncated to contain no more than {@code endExclusive - startInclusive}
-     * elements. If the {@code startInclusive} index lies past the end
-     * of this stream then an empty stream will be returned.
+     * after discarding the first {@code startInclusive} elements and truncating
+     * the result to be no longer than {@code endExclusive - startInclusive}
+     * elements in length. If this stream contains fewer than
+     * {@code startInclusive} elements then an empty stream will be returned.
      *
      * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
      * stateful intermediate operation</a>.
@@ -421,12 +453,12 @@
     /**
      * Performs a <a href="package-summary.html#MutableReduction">mutable
      * reduction</a> operation on the elements of this stream.  A mutable
-     * reduction is one in which the reduced value is a mutable value holder,
+     * reduction is one in which the reduced value is a mutable result container,
      * such as an {@code ArrayList}, and elements are incorporated by updating
-     * the state of the result, rather than by replacing the result.  This
+     * the state of the result rather than by replacing the result.  This
      * produces a result equivalent to:
      * <pre>{@code
-     *     R result = resultFactory.get();
+     *     R result = supplier.get();
      *     for (double element : this stream)
      *         accumulator.accept(result, element);
      *     return result;
@@ -440,7 +472,7 @@
      * operation</a>.
      *
      * @param <R> type of the result
-     * @param resultFactory a function that creates a new result container.
+     * @param supplier a function that creates a new result container.
      *                      For a parallel execution, this function may be
      *                      called multiple times and must return a fresh value
      *                      each time.
@@ -455,7 +487,7 @@
      * @return the result of the reduction
      * @see Stream#collect(Supplier, BiConsumer, BiConsumer)
      */
-    <R> R collect(Supplier<R> resultFactory,
+    <R> R collect(Supplier<R> supplier,
                   ObjDoubleConsumer<R> accumulator,
                   BiConsumer<R, R> combiner);
 
@@ -467,12 +499,15 @@
      * yield more accurate results.  If any stream element is a {@code NaN} or
      * the sum is at any point a {@code NaN} then the sum will be {@code NaN}.
      * This is a special case of a
-     * <a href="package-summary.html#MutableReduction">reduction</a> and is
+     * <a href="package-summary.html#Reduction">reduction</a> and is
      * equivalent to:
      * <pre>{@code
      *     return reduce(0, Double::sum);
      * }</pre>
      *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
      * @return the sum of elements in this stream
      */
     double sum();
@@ -483,12 +518,15 @@
      * element will be {@code Double.NaN} if any stream element was NaN. Unlike
      * the numerical comparison operators, this method considers negative zero
      * to be strictly smaller than positive zero. This is a special case of a
-     * <a href="package-summary.html#MutableReduction">reduction</a> and is
+     * <a href="package-summary.html#Reduction">reduction</a> and is
      * equivalent to:
      * <pre>{@code
      *     return reduce(Double::min);
      * }</pre>
      *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
      * @return an {@code OptionalDouble} containing the minimum element of this
      * stream, or an empty optional if the stream is empty
      */
@@ -501,12 +539,15 @@
      * the numerical comparison operators, this method considers negative zero
      * to be strictly smaller than positive zero. This is a
      * special case of a
-     * <a href="package-summary.html#MutableReduction">reduction</a> and is
+     * <a href="package-summary.html#Reduction">reduction</a> and is
      * equivalent to:
      * <pre>{@code
      *     return reduce(Double::max);
      * }</pre>
      *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
      * @return an {@code OptionalDouble} containing the maximum element of this
      * stream, or an empty optional if the stream is empty
      */
@@ -514,7 +555,7 @@
 
     /**
      * Returns the count of elements in this stream.  This is a special case of
-     * a <a href="package-summary.html#MutableReduction">reduction</a> and is
+     * a <a href="package-summary.html#Reduction">reduction</a> and is
      * equivalent to:
      * <pre>{@code
      *     return mapToLong(e -> 1L).sum();
@@ -535,7 +576,10 @@
      * magnitude tend to yield more accurate results. If any recorded value is
      * a {@code NaN} or the sum is at any point a {@code NaN} then the average
      * will be {@code NaN}. This is a special case of a
-     * <a href="package-summary.html#MutableReduction">reduction</a>.
+     * <a href="package-summary.html#Reduction">reduction</a>.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
      *
      * @return an {@code OptionalDouble} containing the average element of this
      * stream, or an empty optional if the stream is empty
@@ -545,7 +589,10 @@
     /**
      * Returns a {@code DoubleSummaryStatistics} describing various summary data
      * about the elements of this stream.  This is a special
-     * case of a <a href="package-summary.html#MutableReduction">reduction</a>.
+     * case of a <a href="package-summary.html#Reduction">reduction</a>.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
      *
      * @return a {@code DoubleSummaryStatistics} describing various summary data
      * about the elements of this stream
@@ -602,9 +649,8 @@
 
     /**
      * Returns an {@link OptionalDouble} describing the first element of this
-     * stream (in the encounter order), or an empty {@code OptionalDouble} if
-     * the stream is empty.  If the stream has no encounter order, then any
-     * element may be returned.
+     * stream, or an empty {@code OptionalDouble} if the stream is empty.  If
+     * the stream has no encounter order, then any element may be returned.
      *
      * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
      * terminal operation</a>.
@@ -624,8 +670,8 @@
      * <p>The behavior of this operation is explicitly nondeterministic; it is
      * free to select any element in the stream.  This is to allow for maximal
      * performance in parallel operations; the cost is that multiple invocations
-     * on the same source may not return the same result.  (If the first element
-     * in the encounter order is desired, use {@link #findFirst()} instead.)
+     * on the same source may not return the same result.  (If a stable result
+     * is desired, use {@link #findFirst()} instead.)
      *
      * @return an {@code OptionalDouble} describing some element of this stream,
      * or an empty {@code OptionalDouble} if the stream is empty
@@ -637,6 +683,9 @@
      * Returns a {@code Stream} consisting of the elements of this stream,
      * boxed to {@code Double}.
      *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
      * @return a {@code Stream} consistent of the elements of this stream,
      * each boxed to a {@code Double}
      */
@@ -686,7 +735,7 @@
     }
 
     /**
-     * Returns a sequential stream whose elements are the specified values.
+     * Returns a sequential ordered stream whose elements are the specified values.
      *
      * @param values the elements of the new stream
      * @return the new stream
@@ -696,7 +745,7 @@
     }
 
     /**
-     * Returns an infinite sequential {@code DoubleStream} produced by iterative
+     * Returns an infinite sequential ordered {@code DoubleStream} produced by iterative
      * application of a function {@code f} to an initial element {@code seed},
      * producing a {@code Stream} consisting of {@code seed}, {@code f(seed)},
      * {@code f(f(seed))}, etc.
@@ -734,8 +783,8 @@
     }
 
     /**
-     * Returns a sequential {@code DoubleStream} where each element is
-     * generated by an {@code DoubleSupplier}.  This is suitable for generating
+     * Returns a sequential stream where each element is generated by
+     * the provided {@code DoubleSupplier}.  This is suitable for generating
      * constant streams, streams of random elements, etc.
      *
      * @param s the {@code DoubleSupplier} for generated elements
@@ -748,15 +797,16 @@
     }
 
     /**
-     * Creates a lazy concatenated {@code DoubleStream} whose elements are all the
-     * elements of a first {@code DoubleStream} succeeded by all the elements of the
-     * second {@code DoubleStream}. The resulting stream is ordered if both
+     * Creates a lazily concatenated stream whose elements are all the
+     * elements of the first stream followed by all the elements of the
+     * second stream. The resulting stream is ordered if both
      * of the input streams are ordered, and parallel if either of the input
-     * streams is parallel.
+     * streams is parallel.  When the resulting stream is closed, the close
+     * handlers for both input streams are invoked.
      *
      * @param a the first stream
-     * @param b the second stream to concatenate on to end of the first stream
-     * @return the concatenation of the two streams
+     * @param b the second stream
+     * @return the concatenation of the two input streams
      */
     public static DoubleStream concat(DoubleStream a, DoubleStream b) {
         Objects.requireNonNull(a);
@@ -764,15 +814,16 @@
 
         Spliterator.OfDouble split = new Streams.ConcatSpliterator.OfDouble(
                 a.spliterator(), b.spliterator());
-        return StreamSupport.doubleStream(split, a.isParallel() || b.isParallel());
+        DoubleStream stream = StreamSupport.doubleStream(split, a.isParallel() || b.isParallel());
+        return stream.onClose(Streams.composedClose(a, b));
     }
 
     /**
      * A mutable builder for a {@code DoubleStream}.
      *
-     * <p>A stream builder has a lifecycle, where it starts in a building
-     * phase, during which elements can be added, and then transitions to a
-     * built phase, after which elements may not be added.  The built phase
+     * <p>A stream builder has a lifecycle, which starts in a building
+     * phase, during which elements can be added, and then transitions to a built
+     * phase, after which elements may not be added.  The built phase
      * begins when the {@link #build()} method is called, which creates an
      * ordered stream whose elements are the elements that were added to the
      * stream builder, in the order they were added.
--- a/src/share/classes/java/util/stream/IntPipeline.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/src/share/classes/java/util/stream/IntPipeline.java	Wed Aug 14 15:53:13 2013 -0700
@@ -189,7 +189,7 @@
                                                      StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
             @Override
             Sink<Integer> opWrapSink(int flags, Sink<Long> sink) {
-                return new Sink.ChainedInt(sink) {
+                return new Sink.ChainedInt<Long>(sink) {
                     @Override
                     @SuppressWarnings("unchecked")
                     public void accept(int t) {
@@ -206,7 +206,7 @@
                                                        StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
             @Override
             Sink<Integer> opWrapSink(int flags, Sink<Double> sink) {
-                return new Sink.ChainedInt(sink) {
+                return new Sink.ChainedInt<Double>(sink) {
                     @Override
                     @SuppressWarnings("unchecked")
                     public void accept(int t) {
@@ -229,7 +229,7 @@
                                         StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
             @Override
             Sink<Integer> opWrapSink(int flags, Sink<Integer> sink) {
-                return new Sink.ChainedInt(sink) {
+                return new Sink.ChainedInt<Integer>(sink) {
                     @Override
                     public void accept(int t) {
                         downstream.accept(mapper.applyAsInt(t));
@@ -246,7 +246,7 @@
                                                              StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
             @Override
             Sink<Integer> opWrapSink(int flags, Sink<U> sink) {
-                return new Sink.ChainedInt(sink) {
+                return new Sink.ChainedInt<U>(sink) {
                     @Override
                     @SuppressWarnings("unchecked")
                     public void accept(int t) {
@@ -264,7 +264,7 @@
                                                      StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
             @Override
             Sink<Integer> opWrapSink(int flags, Sink<Long> sink) {
-                return new Sink.ChainedInt(sink) {
+                return new Sink.ChainedInt<Long>(sink) {
                     @Override
                     public void accept(int t) {
                         downstream.accept(mapper.applyAsLong(t));
@@ -281,7 +281,7 @@
                                                        StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
             @Override
             Sink<Integer> opWrapSink(int flags, Sink<Double> sink) {
-                return new Sink.ChainedInt(sink) {
+                return new Sink.ChainedInt<Double>(sink) {
                     @Override
                     public void accept(int t) {
                         downstream.accept(mapper.applyAsDouble(t));
@@ -297,7 +297,7 @@
                                         StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT | StreamOpFlag.NOT_SIZED) {
             @Override
             Sink<Integer> opWrapSink(int flags, Sink<Integer> sink) {
-                return new Sink.ChainedInt(sink) {
+                return new Sink.ChainedInt<Integer>(sink) {
                     @Override
                     public void begin(long size) {
                         downstream.begin(-1);
@@ -305,10 +305,11 @@
 
                     @Override
                     public void accept(int t) {
-                        // We can do better that this too; optimize for depth=0 case and just grab spliterator and forEach it
-                        IntStream result = mapper.apply(t);
-                        if (result != null)
-                            result.sequential().forEach(i -> downstream.accept(i));
+                        try (IntStream result = mapper.apply(t)) {
+                            // We can do better that this too; optimize for depth=0 case and just grab spliterator and forEach it
+                            if (result != null)
+                                result.sequential().forEach(i -> downstream.accept(i));
+                        }
                     }
                 };
             }
@@ -334,7 +335,7 @@
                                         StreamOpFlag.NOT_SIZED) {
             @Override
             Sink<Integer> opWrapSink(int flags, Sink<Integer> sink) {
-                return new Sink.ChainedInt(sink) {
+                return new Sink.ChainedInt<Integer>(sink) {
                     @Override
                     public void begin(long size) {
                         downstream.begin(-1);
@@ -351,16 +352,16 @@
     }
 
     @Override
-    public final IntStream peek(IntConsumer consumer) {
-        Objects.requireNonNull(consumer);
+    public final IntStream peek(IntConsumer action) {
+        Objects.requireNonNull(action);
         return new StatelessOp<Integer>(this, StreamShape.INT_VALUE,
                                         0) {
             @Override
             Sink<Integer> opWrapSink(int flags, Sink<Integer> sink) {
-                return new Sink.ChainedInt(sink) {
+                return new Sink.ChainedInt<Integer>(sink) {
                     @Override
                     public void accept(int t) {
-                        consumer.accept(t);
+                        action.accept(t);
                         downstream.accept(t);
                     }
                 };
@@ -475,14 +476,14 @@
     }
 
     @Override
-    public final <R> R collect(Supplier<R> resultFactory,
+    public final <R> R collect(Supplier<R> supplier,
                                ObjIntConsumer<R> accumulator,
                                BiConsumer<R, R> combiner) {
         BinaryOperator<R> operator = (left, right) -> {
             combiner.accept(left, right);
             return left;
         };
-        return evaluate(ReduceOps.makeInt(resultFactory, accumulator, operator));
+        return evaluate(ReduceOps.makeInt(supplier, accumulator, operator));
     }
 
     @Override
--- a/src/share/classes/java/util/stream/IntStream.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/src/share/classes/java/util/stream/IntStream.java	Wed Aug 14 15:53:13 2013 -0700
@@ -25,6 +25,7 @@
 package java.util.stream;
 
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.IntSummaryStatistics;
 import java.util.Objects;
 import java.util.OptionalDouble;
@@ -32,6 +33,7 @@
 import java.util.PrimitiveIterator;
 import java.util.Spliterator;
 import java.util.Spliterators;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.function.BiConsumer;
 import java.util.function.Function;
 import java.util.function.IntBinaryOperator;
@@ -46,40 +48,79 @@
 import java.util.function.Supplier;
 
 /**
- * A sequence of primitive integer elements supporting sequential and parallel
- * bulk operations. Streams support lazy intermediate operations (transforming
- * a stream to another stream) such as {@code filter} and {@code map}, and terminal
- * operations (consuming the contents of a stream to produce a result or
- * side-effect), such as {@code forEach}, {@code findFirst}, and {@code
- * iterator}.  Once an operation has been performed on a stream, it
- * is considered <em>consumed</em> and no longer usable for other operations.
+ * A sequence of elements supporting sequential and parallel aggregate
+ * operations.  The following example illustrates an aggregate operation using
+ * {@link Stream} and {@link IntStream}:
+ *
+ * <pre>{@code
+ *     int sum = widgets.stream()
+ *                      .filter(w -> w.getColor() == RED)
+ *                      .mapToInt(w -> w.getWeight())
+ *                      .sum();
+ * }</pre>
  *
- * <p>For sequential stream pipelines, all operations are performed in the
- * <a href="package-summary.html#Ordering">encounter order</a> of the pipeline
- * source, if the pipeline source has a defined encounter order.
+ * In this example, {@code widgets} is a {@code Collection<Widget>}.  We create
+ * a stream of {@code Widget} objects via {@link Collection#stream Collection.stream()},
+ * filter it to produce a stream containing only the red widgets, and then
+ * transform it into a stream of {@code int} values representing the weight of
+ * each red widget. Then this stream is summed to produce a total weight.
+ *
+ * <p>To perform a computation, stream
+ * <a href="package-summary.html#StreamOps">operations</a> are composed into a
+ * <em>stream pipeline</em>.  A stream pipeline consists of a source (which
+ * might be an array, a collection, a generator function, an IO channel,
+ * etc), zero or more <em>intermediate operations</em> (which transform a
+ * stream into another stream, such as {@link IntStream#filter(IntPredicate)}), and a
+ * <em>terminal operation</em> (which produces a result or side-effect, such
+ * as {@link IntStream#sum()} or {@link IntStream#forEach(IntConsumer)}).
+ * Streams are lazy; computation on the source data is only performed when the
+ * terminal operation is initiated, and source elements are consumed only
+ * as needed.
  *
- * <p>For parallel stream pipelines, unless otherwise specified, intermediate
- * stream operations preserve the <a href="package-summary.html#Ordering">
- * encounter order</a> of their source, and terminal operations
- * respect the encounter order of their source, if the source
- * has an encounter order.  Provided that and parameters to stream operations
- * satisfy the <a href="package-summary.html#NonInterference">non-interference
- * requirements</a>, and excepting differences arising from the absence of
- * a defined encounter order, the result of a stream pipeline should be the
- * stable across multiple executions of the same operations on the same source.
- * However, the timing and thread in which side-effects occur (for those
- * operations which are allowed to produce side-effects, such as
- * {@link #forEach(IntConsumer)}), are explicitly nondeterministic for parallel
- * execution of stream pipelines.
+ * <p>Collections and streams, while bearing some superficial similarities,
+ * have different goals.  Collections are primarily concerned with the efficient
+ * management of, and access to, their elements.  By contrast, streams do not
+ * provide a means to directly access or manipulate their elements, and are
+ * instead concerned with declaratively describing their source and the
+ * computational operations which will be performed in aggregate on that source.
+ * However, if the provided stream operations do not offer the desired
+ * functionality, the {@link #iterator()} and {@link #spliterator()} operations
+ * can be used to perform a controlled traversal.
+ *
+ * <p>A stream pipeline, like the "widgets" example above, can be viewed as
+ * a <em>query</em> on the stream source.  Unless the source was explicitly
+ * designed for concurrent modification (such as a {@link ConcurrentHashMap}),
+ * unpredictable or erroneous behavior may result from modifying the stream
+ * source while it is being queried.
  *
- * <p>Unless otherwise noted, passing a {@code null} argument to any stream
- * method may result in a {@link NullPointerException}.
+ * <p>Most stream operations accept parameters that describe user-specified
+ * behavior, such as the lambda expression {@code w -> w.getWeight()} passed to
+ * {@code mapToInt} in the example above.  Such parameters are always instances
+ * of a <a href="../function/package-summary.html">functional interface</a> such
+ * as {@link java.util.function.Function}, and are often lambda expressions or
+ * method references.  These parameters can never be null, should not modify the
+ * stream source, and should be
+ * <a href="package-summary.html#NonInterference">effectively stateless</a>
+ * (their result should not depend on any state that might change during
+ * execution of the stream pipeline.)
  *
- * @apiNote
- * Streams are not data structures; they do not manage the storage for their
- * elements, nor do they support access to individual elements.  However,
- * you can use the {@link #iterator()} or {@link #spliterator()} operations to
- * perform a controlled traversal.
+ * <p>A stream should be operated on (invoking an intermediate or terminal stream
+ * operation) only once.  This rules out, for example, "forked" streams, where
+ * the same source feeds two or more pipelines, or multiple traversals of the
+ * same stream.  A stream implementation may throw {@link IllegalStateException}
+ * if it detects that the stream is being reused. However, since some stream
+ * operations may return their receiver rather than a new stream object, it may
+ * not be possible to detect reuse in all cases.
+ *
+ * <p>Stream pipelines may execute either sequentially or in
+ * <a href="package-summary.html#Parallelism">parallel</a>.  This
+ * execution mode is a property of the stream.  Streams are created
+ * with an initial choice of sequential or parallel execution.  (For example,
+ * {@link Collection#stream() Collection.stream()} creates a sequential stream,
+ * and {@link Collection#parallelStream() Collection.parallelStream()} creates
+ * a parallel one.)  This choice of execution mode may be modified by the
+ * {@link #sequential()} or {@link #parallel()} methods, and may be queried with
+ * the {@link #isParallel()} method.
  *
  * @since 1.8
  * @see <a href="package-summary.html">java.util.stream</a>
@@ -160,22 +201,13 @@
     /**
      * Returns a stream consisting of the results of replacing each element of
      * this stream with the contents of the stream produced by applying the
-     * provided mapping function to each element.
+     * provided mapping function to each element.  (If the result of the mapping
+     * function is {@code null}, this is treated as if the result was an empty
+     * stream.)
      *
      * <p>This is an <a href="package-summary.html#StreamOps">intermediate
      * operation</a>.
      *
-     * @apiNote
-     * The {@code flatMap()} operation has the effect of applying a one-to-many
-     * tranformation to the elements of the stream, and then flattening the
-     * resulting elements into a new stream. For example, if {@code orders}
-     * is a stream of purchase orders, and each purchase order contains a
-     * collection of line items, then the following produces a stream of line
-     * items:
-     * <pre>{@code
-     *     orderStream.flatMap(order -> order.getLineItems().stream())...
-     * }</pre>
-     *
      * @param mapper a <a href="package-summary.html#NonInterference">
      *               non-interfering, stateless</a> function to apply to
      *               each element which produces an {@code IntStream} of new
@@ -230,12 +262,12 @@
      *         .collect(Collectors.toIntSummaryStastistics());
      * }</pre>
      *
-     * @param consumer a <a href="package-summary.html#NonInterference">
+     * @param action a <a href="package-summary.html#NonInterference">
      *                 non-interfering</a> action to perform on the elements as
      *                 they are consumed from the stream
      * @return the new stream
      */
-    IntStream peek(IntConsumer consumer);
+    IntStream peek(IntConsumer action);
 
     /**
      * Returns a stream consisting of the elements of this stream, truncated
@@ -252,8 +284,8 @@
 
     /**
      * Returns a stream consisting of the remaining elements of this stream
-     * after indexing {@code startInclusive} elements into the stream. If the
-     * {@code startInclusive} index lies past the end of this stream then an
+     * after discarding the first {@code startInclusive} elements of the stream.
+     * If this stream contains fewer than {@code startInclusive} elements then an
      * empty stream will be returned.
      *
      * <p>This is a <a href="package-summary.html#StreamOps">stateful
@@ -267,10 +299,10 @@
 
     /**
      * Returns a stream consisting of the remaining elements of this stream
-     * after indexing {@code startInclusive} elements into the stream and
-     * truncated to contain no more than {@code endExclusive - startInclusive}
-     * elements. If the {@code startInclusive} index lies past the end
-     * of this stream then an empty stream will be returned.
+     * after discarding the first {@code startInclusive} elements and truncating
+     * the result to be no longer than {@code endExclusive - startInclusive}
+     * elements in length. If this stream contains fewer than
+     * {@code startInclusive} elements then an empty stream will be returned.
      *
      * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
      * stateful intermediate operation</a>.
@@ -419,12 +451,12 @@
     /**
      * Performs a <a href="package-summary.html#MutableReduction">mutable
      * reduction</a> operation on the elements of this stream.  A mutable
-     * reduction is one in which the reduced value is a mutable value holder,
+     * reduction is one in which the reduced value is a mutable result container,
      * such as an {@code ArrayList}, and elements are incorporated by updating
-     * the state of the result, rather than by replacing the result.  This
+     * the state of the result rather than by replacing the result.  This
      * produces a result equivalent to:
      * <pre>{@code
-     *     R result = resultFactory.get();
+     *     R result = supplier.get();
      *     for (int element : this stream)
      *         accumulator.accept(result, element);
      *     return result;
@@ -437,7 +469,7 @@
      * operation</a>.
      *
      * @param <R> type of the result
-     * @param resultFactory a function that creates a new result container.
+     * @param supplier a function that creates a new result container.
      *                      For a parallel execution, this function may be
      *                      called multiple times and must return a fresh value
      *                      each time.
@@ -452,18 +484,21 @@
      * @return the result of the reduction
      * @see Stream#collect(Supplier, BiConsumer, BiConsumer)
      */
-    <R> R collect(Supplier<R> resultFactory,
+    <R> R collect(Supplier<R> supplier,
                   ObjIntConsumer<R> accumulator,
                   BiConsumer<R, R> combiner);
 
     /**
      * Returns the sum of elements in this stream.  This is a special case
-     * of a <a href="package-summary.html#MutableReduction">reduction</a>
+     * of a <a href="package-summary.html#Reduction">reduction</a>
      * and is equivalent to:
      * <pre>{@code
      *     return reduce(0, Integer::sum);
      * }</pre>
      *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
      * @return the sum of elements in this stream
      */
     int sum();
@@ -471,7 +506,7 @@
     /**
      * Returns an {@code OptionalInt} describing the minimum element of this
      * stream, or an empty optional if this stream is empty.  This is a special
-     * case of a <a href="package-summary.html#MutableReduction">reduction</a>
+     * case of a <a href="package-summary.html#Reduction">reduction</a>
      * and is equivalent to:
      * <pre>{@code
      *     return reduce(Integer::min);
@@ -479,7 +514,6 @@
      *
      * <p>This is a <a href="package-summary.html#StreamOps">terminal operation</a>.
      *
-
      * @return an {@code OptionalInt} containing the minimum element of this
      * stream, or an empty {@code OptionalInt} if the stream is empty
      */
@@ -488,7 +522,7 @@
     /**
      * Returns an {@code OptionalInt} describing the maximum element of this
      * stream, or an empty optional if this stream is empty.  This is a special
-     * case of a <a href="package-summary.html#MutableReduction">reduction</a>
+     * case of a <a href="package-summary.html#Reduction">reduction</a>
      * and is equivalent to:
      * <pre>{@code
      *     return reduce(Integer::max);
@@ -504,7 +538,7 @@
 
     /**
      * Returns the count of elements in this stream.  This is a special case of
-     * a <a href="package-summary.html#MutableReduction">reduction</a> and is
+     * a <a href="package-summary.html#Reduction">reduction</a> and is
      * equivalent to:
      * <pre>{@code
      *     return mapToLong(e -> 1L).sum();
@@ -520,7 +554,10 @@
      * Returns an {@code OptionalDouble} describing the arithmetic mean of elements of
      * this stream, or an empty optional if this stream is empty.  This is a
      * special case of a
-     * <a href="package-summary.html#MutableReduction">reduction</a>.
+     * <a href="package-summary.html#Reduction">reduction</a>.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
      *
      * @return an {@code OptionalDouble} containing the average element of this
      * stream, or an empty optional if the stream is empty
@@ -530,7 +567,10 @@
     /**
      * Returns an {@code IntSummaryStatistics} describing various
      * summary data about the elements of this stream.  This is a special
-     * case of a <a href="package-summary.html#MutableReduction">reduction</a>.
+     * case of a <a href="package-summary.html#Reduction">reduction</a>.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
      *
      * @return an {@code IntSummaryStatistics} describing various summary data
      * about the elements of this stream
@@ -587,9 +627,8 @@
 
     /**
      * Returns an {@link OptionalInt} describing the first element of this
-     * stream (in the encounter order), or an empty {@code OptionalInt} if the
-     * stream is empty.  If the stream has no encounter order, then any element
-     * may be returned.
+     * stream, or an empty {@code OptionalInt} if the stream is empty.  If the
+     * stream has no encounter order, then any element may be returned.
      *
      * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
      * terminal operation</a>.
@@ -609,8 +648,8 @@
      * <p>The behavior of this operation is explicitly nondeterministic; it is
      * free to select any element in the stream.  This is to allow for maximal
      * performance in parallel operations; the cost is that multiple invocations
-     * on the same source may not return the same result.  (If the first element
-     * in the encounter order is desired, use {@link #findFirst()} instead.)
+     * on the same source may not return the same result.  (If a stable result
+     * is desired, use {@link #findFirst()} instead.)
      *
      * @return an {@code OptionalInt} describing some element of this stream, or
      * an empty {@code OptionalInt} if the stream is empty
@@ -622,6 +661,9 @@
      * Returns a {@code LongStream} consisting of the elements of this stream,
      * converted to {@code long}.
      *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
      * @return a {@code LongStream} consisting of the elements of this stream,
      * converted to {@code long}
      */
@@ -631,6 +673,9 @@
      * Returns a {@code DoubleStream} consisting of the elements of this stream,
      * converted to {@code double}.
      *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
      * @return a {@code DoubleStream} consisting of the elements of this stream,
      * converted to {@code double}
      */
@@ -640,6 +685,9 @@
      * Returns a {@code Stream} consisting of the elements of this stream,
      * each boxed to an {@code Integer}.
      *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
      * @return a {@code Stream} consistent of the elements of this stream,
      * each boxed to an {@code Integer}
      */
@@ -688,7 +736,7 @@
     }
 
     /**
-     * Returns a sequential stream whose elements are the specified values.
+     * Returns a sequential ordered stream whose elements are the specified values.
      *
      * @param values the elements of the new stream
      * @return the new stream
@@ -698,7 +746,7 @@
     }
 
     /**
-     * Returns an infinite sequential {@code IntStream} produced by iterative
+     * Returns an infinite sequential ordered {@code IntStream} produced by iterative
      * application of a function {@code f} to an initial element {@code seed},
      * producing a {@code Stream} consisting of {@code seed}, {@code f(seed)},
      * {@code f(f(seed))}, etc.
@@ -736,8 +784,8 @@
     }
 
     /**
-     * Returns a sequential {@code IntStream} where each element is
-     * generated by an {@code IntSupplier}.  This is suitable for generating
+     * Returns a sequential stream where each element is generated by
+     * the provided {@code IntSupplier}.  This is suitable for generating
      * constant streams, streams of random elements, etc.
      *
      * @param s the {@code IntSupplier} for generated elements
@@ -750,7 +798,7 @@
     }
 
     /**
-     * Returns a sequential {@code IntStream} from {@code startInclusive}
+     * Returns a sequential ordered {@code IntStream} from {@code startInclusive}
      * (inclusive) to {@code endExclusive} (exclusive) by an incremental step of
      * {@code 1}.
      *
@@ -776,7 +824,7 @@
     }
 
     /**
-     * Returns a sequential {@code IntStream} from {@code startInclusive}
+     * Returns a sequential ordered {@code IntStream} from {@code startInclusive}
      * (inclusive) to {@code endInclusive} (inclusive) by an incremental step of
      * {@code 1}.
      *
@@ -802,15 +850,16 @@
     }
 
     /**
-     * Creates a lazy concatenated {@code IntStream} whose elements are all the
-     * elements of a first {@code IntStream} succeeded by all the elements of the
-     * second {@code IntStream}. The resulting stream is ordered if both
+     * Creates a lazily concatenated stream whose elements are all the
+     * elements of the first stream followed by all the elements of the
+     * second stream. The resulting stream is ordered if both
      * of the input streams are ordered, and parallel if either of the input
-     * streams is parallel.
+     * streams is parallel.  When the resulting stream is closed, the close
+     * handlers for both input streams are invoked.
      *
      * @param a the first stream
-     * @param b the second stream to concatenate on to end of the first stream
-     * @return the concatenation of the two streams
+     * @param b the second stream
+     * @return the concatenation of the two input streams
      */
     public static IntStream concat(IntStream a, IntStream b) {
         Objects.requireNonNull(a);
@@ -818,15 +867,16 @@
 
         Spliterator.OfInt split = new Streams.ConcatSpliterator.OfInt(
                 a.spliterator(), b.spliterator());
-        return StreamSupport.intStream(split, a.isParallel() || b.isParallel());
+        IntStream stream = StreamSupport.intStream(split, a.isParallel() || b.isParallel());
+        return stream.onClose(Streams.composedClose(a, b));
     }
 
     /**
      * A mutable builder for an {@code IntStream}.
      *
-     * <p>A stream builder has a lifecycle, where it starts in a building
-     * phase, during which elements can be added, and then transitions to a
-     * built phase, after which elements may not be added.  The built phase
+     * <p>A stream builder has a lifecycle, which starts in a building
+     * phase, during which elements can be added, and then transitions to a built
+     * phase, after which elements may not be added.  The built phase
      * begins when the {@link #build()} method is called, which creates an
      * ordered stream whose elements are the elements that were added to the
      * stream builder, in the order they were added.
--- a/src/share/classes/java/util/stream/LongPipeline.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/src/share/classes/java/util/stream/LongPipeline.java	Wed Aug 14 15:53:13 2013 -0700
@@ -186,7 +186,7 @@
                                                     StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
             @Override
             Sink<Long> opWrapSink(int flags, Sink<Double> sink) {
-                return new Sink.ChainedLong(sink) {
+                return new Sink.ChainedLong<Double>(sink) {
                     @Override
                     public void accept(long t) {
                         downstream.accept((double) t);
@@ -208,7 +208,7 @@
                                      StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
             @Override
             Sink<Long> opWrapSink(int flags, Sink<Long> sink) {
-                return new Sink.ChainedLong(sink) {
+                return new Sink.ChainedLong<Long>(sink) {
                     @Override
                     @SuppressWarnings("unchecked")
                     public void accept(long t) {
@@ -226,7 +226,7 @@
                                                           StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
             @Override
             Sink<Long> opWrapSink(int flags, Sink<U> sink) {
-                return new Sink.ChainedLong(sink) {
+                return new Sink.ChainedLong<U>(sink) {
                     @Override
                     @SuppressWarnings("unchecked")
                     public void accept(long t) {
@@ -244,7 +244,7 @@
                                                  StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
             @Override
             Sink<Long> opWrapSink(int flags, Sink<Integer> sink) {
-                return new Sink.ChainedLong(sink) {
+                return new Sink.ChainedLong<Integer>(sink) {
                     @Override
                     @SuppressWarnings("unchecked")
                     public void accept(long t) {
@@ -262,7 +262,7 @@
                                                     StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
             @Override
             Sink<Long> opWrapSink(int flags, Sink<Double> sink) {
-                return new Sink.ChainedLong(sink) {
+                return new Sink.ChainedLong<Double>(sink) {
                     @Override
                     public void accept(long t) {
                         downstream.accept(mapper.applyAsDouble(t));
@@ -278,7 +278,7 @@
                                      StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT | StreamOpFlag.NOT_SIZED) {
             @Override
             Sink<Long> opWrapSink(int flags, Sink<Long> sink) {
-                return new Sink.ChainedLong(sink) {
+                return new Sink.ChainedLong<Long>(sink) {
                     @Override
                     public void begin(long size) {
                         downstream.begin(-1);
@@ -286,10 +286,11 @@
 
                     @Override
                     public void accept(long t) {
-                        // We can do better that this too; optimize for depth=0 case and just grab spliterator and forEach it
-                        LongStream result = mapper.apply(t);
-                        if (result != null)
-                            result.sequential().forEach(i -> downstream.accept(i));
+                        try (LongStream result = mapper.apply(t)) {
+                            // We can do better that this too; optimize for depth=0 case and just grab spliterator and forEach it
+                            if (result != null)
+                                result.sequential().forEach(i -> downstream.accept(i));
+                        }
                     }
                 };
             }
@@ -315,7 +316,7 @@
                                      StreamOpFlag.NOT_SIZED) {
             @Override
             Sink<Long> opWrapSink(int flags, Sink<Long> sink) {
-                return new Sink.ChainedLong(sink) {
+                return new Sink.ChainedLong<Long>(sink) {
                     @Override
                     public void begin(long size) {
                         downstream.begin(-1);
@@ -332,16 +333,16 @@
     }
 
     @Override
-    public final LongStream peek(LongConsumer consumer) {
-        Objects.requireNonNull(consumer);
+    public final LongStream peek(LongConsumer action) {
+        Objects.requireNonNull(action);
         return new StatelessOp<Long>(this, StreamShape.LONG_VALUE,
                                      0) {
             @Override
             Sink<Long> opWrapSink(int flags, Sink<Long> sink) {
-                return new Sink.ChainedLong(sink) {
+                return new Sink.ChainedLong<Long>(sink) {
                     @Override
                     public void accept(long t) {
-                        consumer.accept(t);
+                        action.accept(t);
                         downstream.accept(t);
                     }
                 };
--- a/src/share/classes/java/util/stream/LongStream.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/src/share/classes/java/util/stream/LongStream.java	Wed Aug 14 15:53:13 2013 -0700
@@ -25,6 +25,7 @@
 package java.util.stream;
 
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.LongSummaryStatistics;
 import java.util.Objects;
 import java.util.OptionalDouble;
@@ -32,6 +33,7 @@
 import java.util.PrimitiveIterator;
 import java.util.Spliterator;
 import java.util.Spliterators;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.function.BiConsumer;
 import java.util.function.Function;
 import java.util.function.LongBinaryOperator;
@@ -46,40 +48,79 @@
 import java.util.function.Supplier;
 
 /**
- * A sequence of primitive long elements supporting sequential and parallel
- * bulk operations. Streams support lazy intermediate operations (transforming
- * a stream to another stream) such as {@code filter} and {@code map}, and terminal
- * operations (consuming the contents of a stream to produce a result or
- * side-effect), such as {@code forEach}, {@code findFirst}, and {@code
- * iterator}.  Once an operation has been performed on a stream, it
- * is considered <em>consumed</em> and no longer usable for other operations.
+ * A sequence of elements supporting sequential and parallel aggregate
+ * operations.  The following example illustrates an aggregate operation using
+ * {@link Stream} and {@link LongStream}:
+ *
+ * <pre>{@code
+ *     long sum = widgets.stream()
+ *                       .filter(w -> w.getColor() == RED)
+ *                       .mapToLong(w -> w.getWeight())
+ *                       .sum();
+ * }</pre>
  *
- * <p>For sequential stream pipelines, all operations are performed in the
- * <a href="package-summary.html#Ordering">encounter order</a> of the pipeline
- * source, if the pipeline source has a defined encounter order.
+ * In this example, {@code widgets} is a {@code Collection<Widget>}.  We create
+ * a stream of {@code Widget} objects via {@link Collection#stream Collection.stream()},
+ * filter it to produce a stream containing only the red widgets, and then
+ * transform it into a stream of {@code long} values representing the weight of
+ * each red widget. Then this stream is summed to produce a total weight.
+ *
+ * <p>To perform a computation, stream
+ * <a href="package-summary.html#StreamOps">operations</a> are composed into a
+ * <em>stream pipeline</em>.  A stream pipeline consists of a source (which
+ * might be an array, a collection, a generator function, an IO channel,
+ * etc), zero or more <em>intermediate operations</em> (which transform a
+ * stream into another stream, such as {@link LongStream#filter(LongPredicate)}), and a
+ * <em>terminal operation</em> (which produces a result or side-effect, such
+ * as {@link LongStream#sum()} or {@link LongStream#forEach(LongConsumer)}).
+ * Streams are lazy; computation on the source data is only performed when the
+ * terminal operation is initiated, and source elements are consumed only
+ * as needed.
  *
- * <p>For parallel stream pipelines, unless otherwise specified, intermediate
- * stream operations preserve the <a href="package-summary.html#Ordering">
- * encounter order</a> of their source, and terminal operations
- * respect the encounter order of their source, if the source
- * has an encounter order.  Provided that and parameters to stream operations
- * satisfy the <a href="package-summary.html#NonInterference">non-interference
- * requirements</a>, and excepting differences arising from the absence of
- * a defined encounter order, the result of a stream pipeline should be the
- * stable across multiple executions of the same operations on the same source.
- * However, the timing and thread in which side-effects occur (for those
- * operations which are allowed to produce side-effects, such as
- * {@link #forEach(LongConsumer)}), are explicitly nondeterministic for parallel
- * execution of stream pipelines.
+ * <p>Collections and streams, while bearing some superficial similarities,
+ * have different goals.  Collections are primarily concerned with the efficient
+ * management of, and access to, their elements.  By contrast, streams do not
+ * provide a means to directly access or manipulate their elements, and are
+ * instead concerned with declaratively describing their source and the
+ * computational operations which will be performed in aggregate on that source.
+ * However, if the provided stream operations do not offer the desired
+ * functionality, the {@link #iterator()} and {@link #spliterator()} operations
+ * can be used to perform a controlled traversal.
+ *
+ * <p>A stream pipeline, like the "widgets" example above, can be viewed as
+ * a <em>query</em> on the stream source.  Unless the source was explicitly
+ * designed for concurrent modification (such as a {@link ConcurrentHashMap}),
+ * unpredictable or erroneous behavior may result from modifying the stream
+ * source while it is being queried.
  *
- * <p>Unless otherwise noted, passing a {@code null} argument to any stream
- * method may result in a {@link NullPointerException}.
+ * <p>Most stream operations accept parameters that describe user-specified
+ * behavior, such as the lambda expression {@code w -> w.getWeight()} passed to
+ * {@code mapToLong} in the example above.  Such parameters are always instances
+ * of a <a href="../function/package-summary.html">functional interface</a> such
+ * as {@link java.util.function.Function}, and are often lambda expressions or
+ * method references.  These parameters can never be null, should not modify the
+ * stream source, and should be
+ * <a href="package-summary.html#NonInterference">effectively stateless</a>
+ * (their result should not depend on any state that might change during
+ * execution of the stream pipeline.)
  *
- * @apiNote
- * Streams are not data structures; they do not manage the storage for their
- * elements, nor do they support access to individual elements.  However,
- * you can use the {@link #iterator()} or {@link #spliterator()} operations to
- * perform a controlled traversal.
+ * <p>A stream should be operated on (invoking an intermediate or terminal stream
+ * operation) only once.  This rules out, for example, "forked" streams, where
+ * the same source feeds two or more pipelines, or multiple traversals of the
+ * same stream.  A stream implementation may throw {@link IllegalStateException}
+ * if it detects that the stream is being reused. However, since some stream
+ * operations may return their receiver rather than a new stream object, it may
+ * not be possible to detect reuse in all cases.
+ *
+ * <p>Stream pipelines may execute either sequentially or in
+ * <a href="package-summary.html#Parallelism">parallel</a>.  This
+ * execution mode is a property of the stream.  Streams are created
+ * with an initial choice of sequential or parallel execution.  (For example,
+ * {@link Collection#stream() Collection.stream()} creates a sequential stream,
+ * and {@link Collection#parallelStream() Collection.parallelStream()} creates
+ * a parallel one.)  This choice of execution mode may be modified by the
+ * {@link #sequential()} or {@link #parallel()} methods, and may be queried with
+ * the {@link #isParallel()} method.
  *
  * @since 1.8
  * @see <a href="package-summary.html">java.util.stream</a>
@@ -160,22 +201,13 @@
     /**
      * Returns a stream consisting of the results of replacing each element of
      * this stream with the contents of the stream produced by applying the
-     * provided mapping function to each element.
+     * provided mapping function to each element.  (If the result of the mapping
+     * function is {@code null}, this is treated as if the result was an empty
+     * stream.)
      *
      * <p>This is an <a href="package-summary.html#StreamOps">intermediate
      * operation</a>.
      *
-     * @apiNote
-     * The {@code flatMap()} operation has the effect of applying a one-to-many
-     * tranformation to the elements of the stream, and then flattening the
-     * resulting elements into a new stream. For example, if {@code orders}
-     * is a stream of purchase orders, and each purchase order contains a
-     * collection of line items, then the following produces a stream of line
-     * items:
-     * <pre>{@code
-     *     orderStream.flatMap(order -> order.getLineItems().stream())...
-     * }</pre>
-     *
      * @param mapper a <a href="package-summary.html#NonInterference">
      *               non-interfering, stateless</a> function to apply to
      *               each element which produces an {@code LongStream} of new
@@ -230,12 +262,12 @@
      *         .collect(Collectors.toLongSummaryStastistics());
      * }</pre>
      *
-     * @param consumer a <a href="package-summary.html#NonInterference">
+     * @param action a <a href="package-summary.html#NonInterference">
      *                 non-interfering</a> action to perform on the elements as
      *                 they are consumed from the stream
      * @return the new stream
      */
-    LongStream peek(LongConsumer consumer);
+    LongStream peek(LongConsumer action);
 
     /**
      * Returns a stream consisting of the elements of this stream, truncated
@@ -252,8 +284,8 @@
 
     /**
      * Returns a stream consisting of the remaining elements of this stream
-     * after indexing {@code startInclusive} elements into the stream. If the
-     * {@code startInclusive} index lies past the end of this stream then an
+     * after discarding the first {@code startInclusive} elements of the stream.
+     * If this stream contains fewer than {@code startInclusive} elements then an
      * empty stream will be returned.
      *
      * <p>This is a <a href="package-summary.html#StreamOps">stateful
@@ -267,10 +299,10 @@
 
     /**
      * Returns a stream consisting of the remaining elements of this stream
-     * after indexing {@code startInclusive} elements into the stream and
-     * truncated to contain no more than {@code endExclusive - startInclusive}
-     * elements. If the {@code startInclusive} index lies past the end
-     * of this stream then an empty stream will be returned.
+     * after discarding the first {@code startInclusive} elements and truncating
+     * the result to be no longer than {@code endExclusive - startInclusive}
+     * elements in length. If this stream contains fewer than
+     * {@code startInclusive} elements then an empty stream will be returned.
      *
      * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
      * stateful intermediate operation</a>.
@@ -419,9 +451,9 @@
     /**
      * Performs a <a href="package-summary.html#MutableReduction">mutable
      * reduction</a> operation on the elements of this stream.  A mutable
-     * reduction is one in which the reduced value is a mutable value holder,
+     * reduction is one in which the reduced value is a mutable result container,
      * such as an {@code ArrayList}, and elements are incorporated by updating
-     * the state of the result, rather than by replacing the result.  This
+     * the state of the result rather than by replacing the result.  This
      * produces a result equivalent to:
      * <pre>{@code
      *     R result = resultFactory.get();
@@ -458,12 +490,15 @@
 
     /**
      * Returns the sum of elements in this stream.  This is a special case
-     * of a <a href="package-summary.html#MutableReduction">reduction</a>
+     * of a <a href="package-summary.html#Reduction">reduction</a>
      * and is equivalent to:
      * <pre>{@code
      *     return reduce(0, Long::sum);
      * }</pre>
      *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
      * @return the sum of elements in this stream
      */
     long sum();
@@ -471,7 +506,7 @@
     /**
      * Returns an {@code OptionalLong} describing the minimum element of this
      * stream, or an empty optional if this stream is empty.  This is a special
-     * case of a <a href="package-summary.html#MutableReduction">reduction</a>
+     * case of a <a href="package-summary.html#Reduction">reduction</a>
      * and is equivalent to:
      * <pre>{@code
      *     return reduce(Long::min);
@@ -479,7 +514,6 @@
      *
      * <p>This is a <a href="package-summary.html#StreamOps">terminal operation</a>.
      *
-
      * @return an {@code OptionalLong} containing the minimum element of this
      * stream, or an empty {@code OptionalLong} if the stream is empty
      */
@@ -488,7 +522,7 @@
     /**
      * Returns an {@code OptionalLong} describing the maximum element of this
      * stream, or an empty optional if this stream is empty.  This is a special
-     * case of a <a href="package-summary.html#MutableReduction">reduction</a>
+     * case of a <a href="package-summary.html#Reduction">reduction</a>
      * and is equivalent to:
      * <pre>{@code
      *     return reduce(Long::max);
@@ -504,7 +538,7 @@
 
     /**
      * Returns the count of elements in this stream.  This is a special case of
-     * a <a href="package-summary.html#MutableReduction">reduction</a> and is
+     * a <a href="package-summary.html#Reduction">reduction</a> and is
      * equivalent to:
      * <pre>{@code
      *     return map(e -> 1L).sum();
@@ -520,7 +554,10 @@
      * Returns an {@code OptionalDouble} describing the arithmetic mean of elements of
      * this stream, or an empty optional if this stream is empty.  This is a
      * special case of a
-     * <a href="package-summary.html#MutableReduction">reduction</a>.
+     * <a href="package-summary.html#Reduction">reduction</a>.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
      *
      * @return an {@code OptionalDouble} containing the average element of this
      * stream, or an empty optional if the stream is empty
@@ -530,7 +567,10 @@
     /**
      * Returns a {@code LongSummaryStatistics} describing various summary data
      * about the elements of this stream.  This is a special case of a
-     * <a href="package-summary.html#MutableReduction">reduction</a>.
+     * <a href="package-summary.html#Reduction">reduction</a>.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
      *
      * @return a {@code LongSummaryStatistics} describing various summary data
      * about the elements of this stream
@@ -587,9 +627,8 @@
 
     /**
      * Returns an {@link OptionalLong} describing the first element of this
-     * stream (in the encounter order), or an empty {@code OptionalLong} if the
-     * stream is empty.  If the stream has no encounter order, then any element
-     * may be returned.
+     * stream, or an empty {@code OptionalLong} if the stream is empty.  If the
+     * stream has no encounter order, then any element may be returned.
      *
      * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
      * terminal operation</a>.
@@ -609,8 +648,8 @@
      * <p>The behavior of this operation is explicitly nondeterministic; it is
      * free to select any element in the stream.  This is to allow for maximal
      * performance in parallel operations; the cost is that multiple invocations
-     * on the same source may not return the same result.  (If the first element
-     * in the encounter order is desired, use {@link #findFirst()} instead.)
+     * on the same source may not return the same result.  (If a stable result
+     * is desired, use {@link #findFirst()} instead.)
      *
      * @return an {@code OptionalLong} describing some element of this stream,
      * or an empty {@code OptionalLong} if the stream is empty
@@ -622,6 +661,9 @@
      * Returns a {@code DoubleStream} consisting of the elements of this stream,
      * converted to {@code double}.
      *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
      * @return a {@code DoubleStream} consisting of the elements of this stream,
      * converted to {@code double}
      */
@@ -631,6 +673,9 @@
      * Returns a {@code Stream} consisting of the elements of this stream,
      * each boxed to a {@code Long}.
      *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
      * @return a {@code Stream} consistent of the elements of this stream,
      * each boxed to {@code Long}
      */
@@ -679,7 +724,7 @@
     }
 
     /**
-     * Returns a sequential stream whose elements are the specified values.
+     * Returns a sequential ordered stream whose elements are the specified values.
      *
      * @param values the elements of the new stream
      * @return the new stream
@@ -689,7 +734,7 @@
     }
 
     /**
-     * Returns an infinite sequential {@code LongStream} produced by iterative
+     * Returns an infinite sequential ordered {@code LongStream} produced by iterative
      * application of a function {@code f} to an initial element {@code seed},
      * producing a {@code Stream} consisting of {@code seed}, {@code f(seed)},
      * {@code f(f(seed))}, etc.
@@ -727,9 +772,9 @@
     }
 
     /**
-     * Returns a sequential {@code LongStream} where each element is generated
-     * by a {@code LongSupplier}.  This is suitable for generating constant
-     * streams, streams of random elements, etc.
+     * Returns a sequential stream where each element is generated by
+     * the provided {@code LongSupplier}.  This is suitable for generating
+     * constant streams, streams of random elements, etc.
      *
      * @param s the {@code LongSupplier} for generated elements
      * @return a new sequential {@code LongStream}
@@ -741,7 +786,7 @@
     }
 
     /**
-     * Returns a sequential {@code LongStream} from {@code startInclusive}
+     * Returns a sequential ordered {@code LongStream} from {@code startInclusive}
      * (inclusive) to {@code endExclusive} (exclusive) by an incremental step of
      * {@code 1}.
      *
@@ -774,7 +819,7 @@
     }
 
     /**
-     * Returns a sequential {@code LongStream} from {@code startInclusive}
+     * Returns a sequential ordered {@code LongStream} from {@code startInclusive}
      * (inclusive) to {@code endInclusive} (inclusive) by an incremental step of
      * {@code 1}.
      *
@@ -808,15 +853,16 @@
     }
 
     /**
-     * Creates a lazy concatenated {@code LongStream} whose elements are all the
-     * elements of a first {@code LongStream} succeeded by all the elements of the
-     * second {@code LongStream}. The resulting stream is ordered if both
+     * Creates a lazily concatenated stream whose elements are all the
+     * elements of the first stream followed by all the elements of the
+     * second stream. The resulting stream is ordered if both
      * of the input streams are ordered, and parallel if either of the input
-     * streams is parallel.
+     * streams is parallel.  When the resulting stream is closed, the close
+     * handlers for both input streams are invoked.
      *
      * @param a the first stream
-     * @param b the second stream to concatenate on to end of the first stream
-     * @return the concatenation of the two streams
+     * @param b the second stream
+     * @return the concatenation of the two input streams
      */
     public static LongStream concat(LongStream a, LongStream b) {
         Objects.requireNonNull(a);
@@ -824,15 +870,16 @@
 
         Spliterator.OfLong split = new Streams.ConcatSpliterator.OfLong(
                 a.spliterator(), b.spliterator());
-        return StreamSupport.longStream(split, a.isParallel() || b.isParallel());
+        LongStream stream = StreamSupport.longStream(split, a.isParallel() || b.isParallel());
+        return stream.onClose(Streams.composedClose(a, b));
     }
 
     /**
      * A mutable builder for a {@code LongStream}.
      *
-     * <p>A stream builder has a lifecycle, where it starts in a building
-     * phase, during which elements can be added, and then transitions to a
-     * built phase, after which elements may not be added.  The built phase
+     * <p>A stream builder has a lifecycle, which starts in a building
+     * phase, during which elements can be added, and then transitions to a built
+     * phase, after which elements may not be added.  The built phase begins
      * begins when the {@link #build()} method is called, which creates an
      * ordered stream whose elements are the elements that were added to the
      * stream builder, in the order they were added.
--- a/src/share/classes/java/util/stream/PipelineHelper.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/src/share/classes/java/util/stream/PipelineHelper.java	Wed Aug 14 15:53:13 2013 -0700
@@ -28,7 +28,7 @@
 import java.util.function.IntFunction;
 
 /**
- * Helper class for executing <a href="package-summary.html#StreamPipelines">
+ * Helper class for executing <a href="package-summary.html#StreamOps">
  * stream pipelines</a>, capturing all of the information about a stream
  * pipeline (output shape, intermediate operations, stream flags, parallelism,
  * etc) in one place.
--- a/src/share/classes/java/util/stream/ReferencePipeline.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/src/share/classes/java/util/stream/ReferencePipeline.java	Wed Aug 14 15:53:13 2013 -0700
@@ -163,7 +163,7 @@
                                      StreamOpFlag.NOT_SIZED) {
             @Override
             Sink<P_OUT> opWrapSink(int flags, Sink<P_OUT> sink) {
-                return new Sink.ChainedReference<P_OUT>(sink) {
+                return new Sink.ChainedReference<P_OUT, P_OUT>(sink) {
                     @Override
                     public void begin(long size) {
                         downstream.begin(-1);
@@ -173,7 +173,7 @@
                     @SuppressWarnings("unchecked")
                     public void accept(P_OUT u) {
                         if (predicate.test(u))
-                            downstream.accept((Object) u);
+                            downstream.accept(u);
                     }
                 };
             }
@@ -188,7 +188,7 @@
                                      StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
             @Override
             Sink<P_OUT> opWrapSink(int flags, Sink<R> sink) {
-                return new Sink.ChainedReference<P_OUT>(sink) {
+                return new Sink.ChainedReference<P_OUT, R>(sink) {
                     @Override
                     public void accept(P_OUT u) {
                         downstream.accept(mapper.apply(u));
@@ -205,7 +205,7 @@
                                               StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
             @Override
             Sink<P_OUT> opWrapSink(int flags, Sink<Integer> sink) {
-                return new Sink.ChainedReference<P_OUT>(sink) {
+                return new Sink.ChainedReference<P_OUT, Integer>(sink) {
                     @Override
                     public void accept(P_OUT u) {
                         downstream.accept(mapper.applyAsInt(u));
@@ -222,7 +222,7 @@
                                       StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
             @Override
             Sink<P_OUT> opWrapSink(int flags, Sink<Long> sink) {
-                return new Sink.ChainedReference<P_OUT>(sink) {
+                return new Sink.ChainedReference<P_OUT, Long>(sink) {
                     @Override
                     public void accept(P_OUT u) {
                         downstream.accept(mapper.applyAsLong(u));
@@ -239,7 +239,7 @@
                                         StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
             @Override
             Sink<P_OUT> opWrapSink(int flags, Sink<Double> sink) {
-                return new Sink.ChainedReference<P_OUT>(sink) {
+                return new Sink.ChainedReference<P_OUT, Double>(sink) {
                     @Override
                     public void accept(P_OUT u) {
                         downstream.accept(mapper.applyAsDouble(u));
@@ -257,7 +257,7 @@
                                      StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT | StreamOpFlag.NOT_SIZED) {
             @Override
             Sink<P_OUT> opWrapSink(int flags, Sink<R> sink) {
-                return new Sink.ChainedReference<P_OUT>(sink) {
+                return new Sink.ChainedReference<P_OUT, R>(sink) {
                     @Override
                     public void begin(long size) {
                         downstream.begin(-1);
@@ -266,10 +266,11 @@
                     @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<? extends R> result = mapper.apply(u);
-                        if (result != null)
-                            result.sequential().forEach(downstream);
+                        try (Stream<? extends R> result = mapper.apply(u)) {
+                            // We can do better that this too; optimize for depth=0 case and just grab spliterator and forEach it
+                            if (result != null)
+                                result.sequential().forEach(downstream);
+                        }
                     }
                 };
             }
@@ -284,7 +285,7 @@
                                               StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT | StreamOpFlag.NOT_SIZED) {
             @Override
             Sink<P_OUT> opWrapSink(int flags, Sink<Integer> sink) {
-                return new Sink.ChainedReference<P_OUT>(sink) {
+                return new Sink.ChainedReference<P_OUT, Integer>(sink) {
                     IntConsumer downstreamAsInt = downstream::accept;
                     @Override
                     public void begin(long size) {
@@ -293,10 +294,11 @@
 
                     @Override
                     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
-                        IntStream result = mapper.apply(u);
-                        if (result != null)
-                            result.sequential().forEach(downstreamAsInt);
+                        try (IntStream result = mapper.apply(u)) {
+                            // We can do better that this too; optimize for depth=0 case and just grab spliterator and forEach it
+                            if (result != null)
+                                result.sequential().forEach(downstreamAsInt);
+                        }
                     }
                 };
             }
@@ -311,7 +313,7 @@
                                                      StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT | StreamOpFlag.NOT_SIZED) {
             @Override
             Sink<P_OUT> opWrapSink(int flags, Sink<Double> sink) {
-                return new Sink.ChainedReference<P_OUT>(sink) {
+                return new Sink.ChainedReference<P_OUT, Double>(sink) {
                     DoubleConsumer downstreamAsDouble = downstream::accept;
                     @Override
                     public void begin(long size) {
@@ -320,10 +322,11 @@
 
                     @Override
                     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
-                        DoubleStream result = mapper.apply(u);
-                        if (result != null)
-                            result.sequential().forEach(downstreamAsDouble);
+                        try (DoubleStream result = mapper.apply(u)) {
+                            // We can do better that this too; optimize for depth=0 case and just grab spliterator and forEach it
+                            if (result != null)
+                                result.sequential().forEach(downstreamAsDouble);
+                        }
                     }
                 };
             }
@@ -338,7 +341,7 @@
                                                    StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT | StreamOpFlag.NOT_SIZED) {
             @Override
             Sink<P_OUT> opWrapSink(int flags, Sink<Long> sink) {
-                return new Sink.ChainedReference<P_OUT>(sink) {
+                return new Sink.ChainedReference<P_OUT, Long>(sink) {
                     LongConsumer downstreamAsLong = downstream::accept;
                     @Override
                     public void begin(long size) {
@@ -347,10 +350,11 @@
 
                     @Override
                     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
-                        LongStream result = mapper.apply(u);
-                        if (result != null)
-                            result.sequential().forEach(downstreamAsLong);
+                        try (LongStream result = mapper.apply(u)) {
+                            // We can do better that this too; optimize for depth=0 case and just grab spliterator and forEach it
+                            if (result != null)
+                                result.sequential().forEach(downstreamAsLong);
+                        }
                     }
                 };
             }
@@ -358,17 +362,17 @@
     }
 
     @Override
-    public final Stream<P_OUT> peek(Consumer<? super P_OUT> tee) {
-        Objects.requireNonNull(tee);
+    public final Stream<P_OUT> peek(Consumer<? super P_OUT> action) {
+        Objects.requireNonNull(action);
         return new StatelessOp<P_OUT, P_OUT>(this, StreamShape.REFERENCE,
                                      0) {
             @Override
             Sink<P_OUT> opWrapSink(int flags, Sink<P_OUT> sink) {
-                return new Sink.ChainedReference<P_OUT>(sink) {
+                return new Sink.ChainedReference<P_OUT, P_OUT>(sink) {
                     @Override
                     @SuppressWarnings("unchecked")
                     public void accept(P_OUT u) {
-                        tee.accept(u);
+                        action.accept(u);
                         downstream.accept(u);
                     }
                 };
@@ -495,7 +499,7 @@
     }
 
     @Override
-    public final <R, A> R collect(Collector<? super P_OUT, A, ? extends R> collector) {
+    public final <R, A> R collect(Collector<? super P_OUT, A, R> collector) {
         A container;
         if (isParallel()
                 && (collector.characteristics().contains(Collector.Characteristics.CONCURRENT))
@@ -513,10 +517,10 @@
     }
 
     @Override
-    public final <R> R collect(Supplier<R> resultFactory,
+    public final <R> R collect(Supplier<R> supplier,
                                BiConsumer<R, ? super P_OUT> accumulator,
                                BiConsumer<R, R> combiner) {
-        return evaluate(ReduceOps.makeRef(resultFactory, accumulator, combiner));
+        return evaluate(ReduceOps.makeRef(supplier, accumulator, combiner));
     }
 
     @Override
--- a/src/share/classes/java/util/stream/Sink.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/src/share/classes/java/util/stream/Sink.java	Wed Aug 14 15:53:13 2013 -0700
@@ -241,11 +241,10 @@
      * implementation of the {@code accept()} method must call the correct
      * {@code accept()} method on the downstream {@code Sink}.
      */
-    static abstract class ChainedReference<T> implements Sink<T> {
-        @SuppressWarnings("rawtypes")
-        protected final Sink downstream;
+    static abstract class ChainedReference<T, E_OUT> implements Sink<T> {
+        protected final Sink<? super E_OUT> downstream;
 
-        public ChainedReference(Sink downstream) {
+        public ChainedReference(Sink<? super E_OUT> downstream) {
             this.downstream = Objects.requireNonNull(downstream);
         }
 
@@ -274,11 +273,10 @@
      * 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<E_OUT> implements Sink.OfInt {
+        protected final Sink<? super E_OUT> downstream;
 
-        public ChainedInt(Sink downstream) {
+        public ChainedInt(Sink<? super E_OUT> downstream) {
             this.downstream = Objects.requireNonNull(downstream);
         }
 
@@ -307,11 +305,10 @@
      * 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<E_OUT> implements Sink.OfLong {
+        protected final Sink<? super E_OUT> downstream;
 
-        public ChainedLong(Sink downstream) {
+        public ChainedLong(Sink<? super E_OUT> downstream) {
             this.downstream = Objects.requireNonNull(downstream);
         }
 
@@ -340,11 +337,10 @@
      * 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<E_OUT> implements Sink.OfDouble {
+        protected final Sink<? super E_OUT> downstream;
 
-        public ChainedDouble(Sink downstream) {
+        public ChainedDouble(Sink<? super E_OUT> downstream) {
             this.downstream = Objects.requireNonNull(downstream);
         }
 
--- a/src/share/classes/java/util/stream/SliceOps.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/src/share/classes/java/util/stream/SliceOps.java	Wed Aug 14 15:53:13 2013 -0700
@@ -182,7 +182,7 @@
 
             @Override
             Sink<T> opWrapSink(int flags, Sink<T> sink) {
-                return new Sink.ChainedReference<T>(sink) {
+                return new Sink.ChainedReference<T, T>(sink) {
                     long n = skip;
                     long m = limit >= 0 ? limit : Long.MAX_VALUE;
 
@@ -291,7 +291,7 @@
 
             @Override
             Sink<Integer> opWrapSink(int flags, Sink<Integer> sink) {
-                return new Sink.ChainedInt(sink) {
+                return new Sink.ChainedInt<Integer>(sink) {
                     long n = skip;
                     long m = limit >= 0 ? limit : Long.MAX_VALUE;
 
@@ -400,7 +400,7 @@
 
             @Override
             Sink<Long> opWrapSink(int flags, Sink<Long> sink) {
-                return new Sink.ChainedLong(sink) {
+                return new Sink.ChainedLong<Long>(sink) {
                     long n = skip;
                     long m = limit >= 0 ? limit : Long.MAX_VALUE;
 
@@ -509,7 +509,7 @@
 
             @Override
             Sink<Double> opWrapSink(int flags, Sink<Double> sink) {
-                return new Sink.ChainedDouble(sink) {
+                return new Sink.ChainedDouble<Double>(sink) {
                     long n = skip;
                     long m = limit >= 0 ? limit : Long.MAX_VALUE;
 
--- a/src/share/classes/java/util/stream/SortedOps.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/src/share/classes/java/util/stream/SortedOps.java	Wed Aug 14 15:53:13 2013 -0700
@@ -129,7 +129,7 @@
         }
 
         @Override
-        public Sink<T> opWrapSink(int flags, Sink sink) {
+        public Sink<T> opWrapSink(int flags, Sink<T> sink) {
             Objects.requireNonNull(sink);
 
             // If the input is already naturally sorted and this operation
@@ -280,12 +280,12 @@
     /**
      * {@link ForkJoinTask} for implementing sort on SIZED reference streams.
      */
-    private static final class SizedRefSortingSink<T> extends Sink.ChainedReference<T> {
+    private static final class SizedRefSortingSink<T> extends Sink.ChainedReference<T, T> {
         private final Comparator<? super T> comparator;
         private T[] array;
         private int offset;
 
-        SizedRefSortingSink(Sink<T> sink, Comparator<? super T> comparator) {
+        SizedRefSortingSink(Sink<? super T> sink, Comparator<? super T> comparator) {
             super(sink);
             this.comparator = comparator;
         }
@@ -320,11 +320,11 @@
     /**
      * {@link Sink} for implementing sort on reference streams.
      */
-    private static final class RefSortingSink<T> extends Sink.ChainedReference<T> {
+    private static final class RefSortingSink<T> extends Sink.ChainedReference<T, T> {
         private final Comparator<? super T> comparator;
         private ArrayList<T> list;
 
-        RefSortingSink(Sink<T> sink, Comparator<? super T> comparator) {
+        RefSortingSink(Sink<? super T> sink, Comparator<? super T> comparator) {
             super(sink);
             this.comparator = comparator;
         }
@@ -352,11 +352,11 @@
     /**
      * {@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<Integer> {
         private int[] array;
         private int offset;
 
-        SizedIntSortingSink(Sink downstream) {
+        SizedIntSortingSink(Sink<? super Integer> downstream) {
             super(downstream);
         }
 
@@ -386,10 +386,10 @@
     /**
      * {@link Sink} for implementing sort on int streams.
      */
-    private static final class IntSortingSink extends Sink.ChainedInt {
+    private static final class IntSortingSink extends Sink.ChainedInt<Integer> {
         private SpinedBuffer.OfInt b;
 
-        IntSortingSink(Sink sink) {
+        IntSortingSink(Sink<? super Integer> sink) {
             super(sink);
         }
 
@@ -417,11 +417,11 @@
     /**
      * {@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<Long> {
         private long[] array;
         private int offset;
 
-        SizedLongSortingSink(Sink downstream) {
+        SizedLongSortingSink(Sink<? super Long> downstream) {
             super(downstream);
         }
 
@@ -451,10 +451,10 @@
     /**
      * {@link Sink} for implementing sort on long streams.
      */
-    private static final class LongSortingSink extends Sink.ChainedLong {
+    private static final class LongSortingSink extends Sink.ChainedLong<Long> {
         private SpinedBuffer.OfLong b;
 
-        LongSortingSink(Sink sink) {
+        LongSortingSink(Sink<? super Long> sink) {
             super(sink);
         }
 
@@ -482,11 +482,11 @@
     /**
      * {@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<Double> {
         private double[] array;
         private int offset;
 
-        SizedDoubleSortingSink(Sink downstream) {
+        SizedDoubleSortingSink(Sink<? super Double> downstream) {
             super(downstream);
         }
 
@@ -516,10 +516,10 @@
     /**
      * {@link Sink} for implementing sort on double streams.
      */
-    private static final class DoubleSortingSink extends Sink.ChainedDouble {
+    private static final class DoubleSortingSink extends Sink.ChainedDouble<Double> {
         private SpinedBuffer.OfDouble b;
 
-        DoubleSortingSink(Sink sink) {
+        DoubleSortingSink(Sink<? super Double> sink) {
             super(sink);
         }
 
--- a/src/share/classes/java/util/stream/Stream.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/src/share/classes/java/util/stream/Stream.java	Wed Aug 14 15:53:13 2013 -0700
@@ -25,12 +25,14 @@
 package java.util.stream;
 
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.Comparator;
 import java.util.Iterator;
 import java.util.Objects;
 import java.util.Optional;
 import java.util.Spliterator;
 import java.util.Spliterators;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.function.BiConsumer;
 import java.util.function.BiFunction;
 import java.util.function.BinaryOperator;
@@ -44,51 +46,82 @@
 import java.util.function.ToLongFunction;
 import java.util.function.UnaryOperator;
 
-// @@@ Specification to-do list @@@
-// - Describe the difference between sequential and parallel streams
-// - More general information about reduce, better definitions for associativity, more description of
-//   how reduce employs parallelism, more examples
-// - Role of stream flags in various operations, specifically ordering
-//   - Whether each op preserves encounter order
-// @@@ Specification to-do list @@@
-
 /**
- * A sequence of elements supporting sequential and parallel bulk operations.
- * Streams support lazy intermediate operations (transforming a stream to
- * another stream) such as {@code filter} and {@code map}, and terminal
- * operations (consuming the contents of a stream to produce a result or
- * side-effect), such as {@code forEach}, {@code findFirst}, and {@code
- * iterator}.  Once an operation has been performed on a stream, it
- * is considered <em>consumed</em> and no longer usable for other operations.
+ * A sequence of elements supporting sequential and parallel aggregate
+ * operations.  The following example illustrates an aggregate operation using
+ * {@link Stream} and {@link IntStream}:
+ *
+ * <pre>{@code
+ *     int sum = widgets.stream()
+ *                      .filter(w -> w.getColor() == RED)
+ *                      .mapToInt(w -> w.getWeight())
+ *                      .sum();
+ * }</pre>
  *
- * <p>For sequential stream pipelines, all operations are performed in the
- * <a href="package-summary.html#Ordering">encounter order</a> of the pipeline
- * source, if the pipeline source has a defined encounter order.
+ * In this example, {@code widgets} is a {@code Collection<Widget>}.  We create
+ * a stream of {@code Widget} objects via {@link Collection#stream Collection.stream()},
+ * filter it to produce a stream containing only the red widgets, and then
+ * transform it into a stream of {@code int} values representing the weight of
+ * each red widget. Then this stream is summed to produce a total weight.
+ *
+ * <p>To perform a computation, stream
+ * <a href="package-summary.html#StreamOps">operations</a> are composed into a
+ * <em>stream pipeline</em>.  A stream pipeline consists of a source (which
+ * might be an array, a collection, a generator function, an I/O channel,
+ * etc), zero or more <em>intermediate operations</em> (which transform a
+ * stream into another stream, such as {@link Stream#filter(Predicate)}), and a
+ * <em>terminal operation</em> (which produces a result or side-effect, such
+ * as {@link Stream#count()} or {@link Stream#forEach(Consumer)}).
+ * Streams are lazy; computation on the source data is only performed when the
+ * terminal operation is initiated, and source elements are consumed only
+ * as needed.
  *
- * <p>For parallel stream pipelines, unless otherwise specified, intermediate
- * stream operations preserve the <a href="package-summary.html#Ordering">
- * encounter order</a> of their source, and terminal operations
- * respect the encounter order of their source, if the source
- * has an encounter order.  Provided that and parameters to stream operations
- * satisfy the <a href="package-summary.html#NonInterference">non-interference
- * requirements</a>, and excepting differences arising from the absence of
- * a defined encounter order, the result of a stream pipeline should be the
- * stable across multiple executions of the same operations on the same source.
- * However, the timing and thread in which side-effects occur (for those
- * operations which are allowed to produce side-effects, such as
- * {@link #forEach(Consumer)}), are explicitly nondeterministic for parallel
- * execution of stream pipelines.
+ * <p>Collections and streams, while bearing some superficial similarities,
+ * have different goals.  Collections are primarily concerned with the efficient
+ * management of, and access to, their elements.  By contrast, streams do not
+ * provide a means to directly access or manipulate their elements, and are
+ * instead concerned with declaratively describing their source and the
+ * computational operations which will be performed in aggregate on that source.
+ * However, if the provided stream operations do not offer the desired
+ * functionality, the {@link #iterator()} and {@link #spliterator()} operations
+ * can be used to perform a controlled traversal.
+ *
+ * <p>A stream pipeline, like the "widgets" example above, can be viewed as
+ * a <em>query</em> on the stream source.  Unless the source was explicitly
+ * designed for concurrent modification (such as a {@link ConcurrentHashMap}),
+ * unpredictable or erroneous behavior may result from modifying the stream
+ * source while it is being queried.
  *
- * <p>Unless otherwise noted, passing a {@code null} argument to any stream
- * method may result in a {@link NullPointerException}.
+ * <p>Most stream operations accept parameters that describe user-specified
+ * behavior, such as the lambda expression {@code w -> w.getWeight()} passed to
+ * {@code mapToInt} in the example above.  Such parameters are always instances
+ * of a <a href="../function/package-summary.html">functional interface</a> such
+ * as {@link java.util.function.Function}, and are often lambda expressions or
+ * method references.  These parameters can never be null, should not modify the
+ * stream source, and should be
+ * <a href="package-summary.html#NonInterference">effectively stateless</a>
+ * (their result should not depend on any state that might change during
+ * execution of the stream pipeline.)
  *
- * @apiNote
- * Streams are not data structures; they do not manage the storage for their
- * elements, nor do they support access to individual elements.  However,
- * you can use the {@link #iterator()} or {@link #spliterator()} operations to
- * perform a controlled traversal.
+ * <p>A stream should be operated on (invoking an intermediate or terminal stream
+ * operation) only once.  This rules out, for example, "forked" streams, where
+ * the same source feeds two or more pipelines, or multiple traversals of the
+ * same stream.  A stream implementation may throw {@link IllegalStateException}
+ * if it detects that the stream is being reused. However, since some stream
+ * operations may return their receiver rather than a new stream object, it may
+ * not be possible to detect reuse in all cases.
  *
- * @param <T> type of elements
+ * <p>Stream pipelines may execute either sequentially or in
+ * <a href="package-summary.html#Parallelism">parallel</a>.  This
+ * execution mode is a property of the stream.  Streams are created
+ * with an initial choice of sequential or parallel execution.  (For example,
+ * {@link Collection#stream() Collection.stream()} creates a sequential stream,
+ * and {@link Collection#parallelStream() Collection.parallelStream()} creates
+ * a parallel one.)  This choice of execution mode may be modified by the
+ * {@link #sequential()} or {@link #parallel()} methods, and may be queried with
+ * the {@link #isParallel()} method.
+ *
+ * @param <T> the type of the stream elements
  * @since 1.8
  * @see <a href="package-summary.html">java.util.stream</a>
  */
@@ -168,9 +201,9 @@
     /**
      * Returns a stream consisting of the results of replacing each element of
      * this stream with the contents of the stream produced by applying the
-     * provided mapping function to each element.  If the result of the mapping
-     * function is {@code null}, this is treated as if the result is an empty
-     * stream.
+     * provided mapping function to each element.  (If the result of the mapping
+     * function is {@code null}, this is treated as if the result was an empty
+     * stream.)
      *
      * <p>This is an <a href="package-summary.html#StreamOps">intermediate
      * operation</a>.
@@ -197,9 +230,9 @@
     /**
      * Returns an {@code IntStream} consisting of the results of replacing each
      * element of this stream with the contents of the stream produced by
-     * applying the provided mapping function to each element.  If the result of
-     * the mapping function is {@code null}, this is treated as if the result is
-     * an empty stream.
+     * applying the provided mapping function to each element.  (If the result
+     * of the mapping function is {@code null}, this is treated as if the result
+     * was an empty stream.)
      *
      * <p>This is an <a href="package-summary.html#StreamOps">intermediate
      * operation</a>.
@@ -214,9 +247,9 @@
     /**
      * Returns a {@code LongStream} consisting of the results of replacing each
      * element of this stream with the contents of the stream produced
-     * by applying the provided mapping function to each element.  If the result
-     * of the mapping function is {@code null}, this is treated as if the
-     * result is an empty stream.
+     * by applying the provided mapping function to each element.  (If the result
+     * of the mapping function is {@code null}, this is treated as if the result
+     * was an empty stream.)
      *
      * <p>This is an <a href="package-summary.html#StreamOps">intermediate
      * operation</a>.
@@ -231,9 +264,9 @@
     /**
      * Returns a {@code DoubleStream} consisting of the results of replacing each
      * element of this stream with the contents of the stream produced
-     * by applying the provided mapping function to each element.  If the result
+     * by applying the provided mapping function to each element.  (If the result
      * of the mapping function is {@code null}, this is treated as if the result
-     * is an empty stream.
+     * was an empty stream.)
      *
      * <p>This is an <a href="package-summary.html#StreamOps">intermediate
      * operation</a>.
@@ -260,7 +293,7 @@
      * Returns a stream consisting of the elements of this stream, sorted
      * according to natural order.  If the elements of this stream are not
      * {@code Comparable}, a {@code java.lang.ClassCastException} may be thrown
-     * when the stream pipeline is executed.
+     * when the terminal operation is executed.
      *
      * <p>This is a <a href="package-summary.html#StreamOps">stateful
      * intermediate operation</a>.
@@ -307,12 +340,12 @@
      *         .collect(Collectors.intoList());
      * }</pre>
      *
-     * @param consumer a <a href="package-summary.html#NonInterference">
+     * @param action a <a href="package-summary.html#NonInterference">
      *                 non-interfering</a> action to perform on the elements as
      *                 they are consumed from the stream
      * @return the new stream
      */
-    Stream<T> peek(Consumer<? super T> consumer);
+    Stream<T> peek(Consumer<? super T> action);
 
     /**
      * Returns a stream consisting of the elements of this stream, truncated
@@ -329,8 +362,8 @@
 
     /**
      * Returns a stream consisting of the remaining elements of this stream
-     * after indexing {@code startInclusive} elements into the stream. If the
-     * {@code startInclusive} index lies past the end of this stream then an
+     * after discarding the first {@code startInclusive} elements of the stream.
+     * If this stream contains fewer than {@code startInclusive} elements then an
      * empty stream will be returned.
      *
      * <p>This is a <a href="package-summary.html#StreamOps">stateful
@@ -344,10 +377,10 @@
 
     /**
      * Returns a stream consisting of the remaining elements of this stream
-     * after indexing {@code startInclusive} elements into the stream and
-     * truncated to contain no more than {@code endExclusive - startInclusive}
-     * elements. If the {@code startInclusive} index lies past the end
-     * of this stream then an empty stream will be returned.
+     * after discarding the first {@code startInclusive} elements and truncating
+     * the result to be no longer than {@code endExclusive - startInclusive}
+     * elements in length. If this stream contains fewer than
+     * {@code startInclusive} elements then an empty stream will be returned.
      *
      * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
      * stateful intermediate operation</a>.
@@ -405,11 +438,23 @@
 
     /**
      * Returns an array containing the elements of this stream, using the
-     * provided {@code generator} function to allocate the returned array.
+     * provided {@code generator} function to allocate the returned array, as
+     * well as any additional arrays that might be required for a partitioned
+     * execution or for resizing.
      *
      * <p>This is a <a href="package-summary.html#StreamOps">terminal
      * operation</a>.
      *
+     * @apiNote
+     * The generator function takes an integer, which is the size of the
+     * desired array, and produces an array of the desired size.  This can be
+     * concisely expressed with an array constructor reference:
+     * <pre>{@code
+     *     Person[] men = people.stream()
+     *                          .filter(p -> p.getGender() == MALE)
+     *                          .toArray(Person[]::new);
+     * }</pre>
+     *
      * @param <A> the element type of the resulting array
      * @param generator a function which produces a new array of the desired
      *                  type and the provided length
@@ -451,7 +496,7 @@
      *     Integer sum = integers.reduce(0, (a, b) -> a+b);
      * }</pre>
      *
-     * or more compactly:
+     * or:
      *
      * <pre>{@code
      *     Integer sum = integers.reduce(0, Integer::sum);
@@ -511,7 +556,7 @@
     /**
      * Performs a <a href="package-summary.html#Reduction">reduction</a> on the
      * elements of this stream, using the provided identity, accumulation
-     * function, and a combining functions.  This is equivalent to:
+     * function, and combining functions.  This is equivalent to:
      * <pre>{@code
      *     U result = identity;
      *     for (T element : this stream)
@@ -537,8 +582,8 @@
      * by an explicit combination of {@code map} and {@code reduce} operations.
      * The {@code accumulator} function acts as a fused mapper and accumulator,
      * which can sometimes be more efficient than separate mapping and reduction,
-     * such as in the case where knowing the previously reduced value allows you
-     * to avoid some computation.
+     * such as when knowing the previously reduced value allows you to avoid
+     * some computation.
      *
      * @param <U> The type of the result
      * @param identity the identity value for the combiner function
@@ -561,12 +606,12 @@
     /**
      * Performs a <a href="package-summary.html#MutableReduction">mutable
      * reduction</a> operation on the elements of this stream.  A mutable
-     * reduction is one in which the reduced value is a mutable value holder,
+     * reduction is one in which the reduced value is a mutable result container,
      * such as an {@code ArrayList}, and elements are incorporated by updating
-     * the state of the result, rather than by replacing the result.  This
+     * the state of the result rather than by replacing the result.  This
      * produces a result equivalent to:
      * <pre>{@code
-     *     R result = resultFactory.get();
+     *     R result = supplier.get();
      *     for (T element : this stream)
      *         accumulator.accept(result, element);
      *     return result;
@@ -579,10 +624,11 @@
      * operation</a>.
      *
      * @apiNote There are many existing classes in the JDK whose signatures are
-     * a good match for use as arguments to {@code collect()}.  For example,
-     * the following will accumulate strings into an ArrayList:
+     * well-suited for use with method references as arguments to {@code collect()}.
+     * For example, the following will accumulate strings into an {@code ArrayList}:
      * <pre>{@code
-     *     List<String> asList = stringStream.collect(ArrayList::new, ArrayList::add, ArrayList::addAll);
+     *     List<String> asList = stringStream.collect(ArrayList::new, ArrayList::add,
+     *                                                ArrayList::addAll);
      * }</pre>
      *
      * <p>The following will take a stream of strings and concatenates them into a
@@ -594,7 +640,7 @@
      * }</pre>
      *
      * @param <R> type of the result
-     * @param resultFactory a function that creates a new result container.
+     * @param supplier a function that creates a new result container.
      *                      For a parallel execution, this function may be
      *                      called multiple times and must return a fresh value
      *                      each time.
@@ -608,24 +654,24 @@
      *                 must be compatible with the accumulator function
      * @return the result of the reduction
      */
-    <R> R collect(Supplier<R> resultFactory,
+    <R> R collect(Supplier<R> supplier,
                   BiConsumer<R, ? super T> accumulator,
                   BiConsumer<R, R> combiner);
 
     /**
      * Performs a <a href="package-summary.html#MutableReduction">mutable
      * reduction</a> operation on the elements of this stream using a
-     * {@code Collector} object to describe the reduction.  A {@code Collector}
+     * {@code Collector}.  A {@code Collector}
      * encapsulates the functions used as arguments to
      * {@link #collect(Supplier, BiConsumer, BiConsumer)}, allowing for reuse of
-     * collection strategies, and composition of collect operations such as
+     * collection strategies and composition of collect operations such as
      * multiple-level grouping or partitioning.
      *
      * <p>This is a <a href="package-summary.html#StreamOps">terminal
      * operation</a>.
      *
      * <p>When executed in parallel, multiple intermediate results may be
-     * instantiated, populated, and merged, so as to maintain isolation of
+     * instantiated, populated, and merged so as to maintain isolation of
      * mutable data structures.  Therefore, even when executed in parallel
      * with non-thread-safe data structures (such as {@code ArrayList}), no
      * additional synchronization is needed for a parallel reduction.
@@ -638,16 +684,16 @@
      *
      * <p>The following will classify {@code Person} objects by city:
      * <pre>{@code
-     *     Map<String, Collection<Person>> peopleByCity
-     *         = personStream.collect(Collectors.groupBy(Person::getCity));
+     *     Map<String, List<Person>> peopleByCity
+     *         = personStream.collect(Collectors.groupingBy(Person::getCity));
      * }</pre>
      *
      * <p>The following will classify {@code Person} objects by state and city,
      * cascading two {@code Collector}s together:
      * <pre>{@code
-     *     Map<String, Map<String, Collection<Person>>> peopleByStateAndCity
-     *         = personStream.collect(Collectors.groupBy(Person::getState,
-     *                                                   Collectors.groupBy(Person::getCity)));
+     *     Map<String, Map<String, List<Person>>> peopleByStateAndCity
+     *         = personStream.collect(Collectors.groupingBy(Person::getState,
+     *                                                      Collectors.groupingBy(Person::getCity)));
      * }</pre>
      *
      * @param <R> the type of the result
@@ -657,12 +703,12 @@
      * @see #collect(Supplier, BiConsumer, BiConsumer)
      * @see Collectors
      */
-    <R, A> R collect(Collector<? super T, A, ? extends R> collector);
+    <R, A> R collect(Collector<? super T, A, R> collector);
 
     /**
      * Returns the minimum element of this stream according to the provided
      * {@code Comparator}.  This is a special case of a
-     * <a href="package-summary.html#MutableReduction">reduction</a>.
+     * <a href="package-summary.html#Reduction">reduction</a>.
      *
      * <p>This is a <a href="package-summary.html#StreamOps">terminal operation</a>.
      *
@@ -677,7 +723,7 @@
     /**
      * Returns the maximum element of this stream according to the provided
      * {@code Comparator}.  This is a special case of a
-     * <a href="package-summary.html#MutableReduction">reduction</a>.
+     * <a href="package-summary.html#Reduction">reduction</a>.
      *
      * <p>This is a <a href="package-summary.html#StreamOps">terminal
      * operation</a>.
@@ -692,7 +738,7 @@
 
     /**
      * Returns the count of elements in this stream.  This is a special case of
-     * a <a href="package-summary.html#MutableReduction">reduction</a> and is
+     * a <a href="package-summary.html#Reduction">reduction</a> and is
      * equivalent to:
      * <pre>{@code
      *     return mapToLong(e -> 1L).sum();
@@ -753,10 +799,9 @@
     boolean noneMatch(Predicate<? super T> predicate);
 
     /**
-     * Returns an {@link Optional} describing the first element of this stream
-     * (in the encounter order), or an empty {@code Optional} if the stream is
-     * empty.  If the stream has no encounter order, then any element may be
-     * returned.
+     * Returns an {@link Optional} describing the first element of this stream,
+     * or an empty {@code Optional} if the stream is empty.  If the stream has
+     * no encounter order, then any element may be returned.
      *
      * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
      * terminal operation</a>.
@@ -777,8 +822,8 @@
      * <p>The behavior of this operation is explicitly nondeterministic; it is
      * free to select any element in the stream.  This is to allow for maximal
      * performance in parallel operations; the cost is that multiple invocations
-     * on the same source may not return the same result.  (If the first element
-     * in the encounter order is desired, use {@link #findFirst()} instead.)
+     * on the same source may not return the same result.  (If a stable result
+     * is desired, use {@link #findFirst()} instead.)
      *
      * @return an {@code Optional} describing some element of this stream, or an
      * empty {@code Optional} if the stream is empty
@@ -821,20 +866,19 @@
     }
 
     /**
-     * Returns a sequential stream whose elements are the specified values.
+     * Returns a sequential ordered stream whose elements are the specified values.
      *
      * @param <T> the type of stream elements
      * @param values the elements of the new stream
      * @return the new stream
      */
     @SafeVarargs
-    @SuppressWarnings("varargs") // Creating a stream from an array is safe
     public static<T> Stream<T> of(T... values) {
         return Arrays.stream(values);
     }
 
     /**
-     * Returns an infinite sequential {@code Stream} produced by iterative
+     * Returns an infinite sequential ordered {@code Stream} produced by iterative
      * application of a function {@code f} to an initial element {@code seed},
      * producing a {@code Stream} consisting of {@code seed}, {@code f(seed)},
      * {@code f(f(seed))}, etc.
@@ -872,8 +916,8 @@
     }
 
     /**
-     * Returns a sequential {@code Stream} where each element is
-     * generated by a {@code Supplier}.  This is suitable for generating
+     * Returns a sequential stream where each element is generated by
+     * the provided {@code Supplier}.  This is suitable for generating
      * constant streams, streams of random elements, etc.
      *
      * @param <T> the type of stream elements
@@ -887,16 +931,16 @@
     }
 
     /**
-     * Creates a lazy concatenated {@code Stream} whose elements are all the
-     * elements of a first {@code Stream} succeeded by all the elements of the
-     * second {@code Stream}. The resulting stream is ordered if both
+     * Creates a lazily concatenated stream whose elements are all the
+     * elements of the first stream followed by all the elements of the
+     * second stream. The resulting stream is ordered if both
      * of the input streams are ordered, and parallel if either of the input
-     * streams is parallel.
+     * streams is parallel.  When the resulting stream is closed, the close
+     * handlers for both input streams are invoked.
      *
      * @param <T> The type of stream elements
      * @param a the first stream
-     * @param b the second stream to concatenate on to end of the first
-     *        stream
+     * @param b the second stream
      * @return the concatenation of the two input streams
      */
     public static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b) {
@@ -906,7 +950,8 @@
         @SuppressWarnings("unchecked")
         Spliterator<T> split = new Streams.ConcatSpliterator.OfRef<>(
                 (Spliterator<T>) a.spliterator(), (Spliterator<T>) b.spliterator());
-        return StreamSupport.stream(split, a.isParallel() || b.isParallel());
+        Stream<T> stream = StreamSupport.stream(split, a.isParallel() || b.isParallel());
+        return stream.onClose(Streams.composedClose(a, b));
     }
 
     /**
@@ -915,7 +960,7 @@
      * {@code Builder} (without the copying overhead that comes from using
      * an {@code ArrayList} as a temporary buffer.)
      *
-     * <p>A {@code Stream.Builder} has a lifecycle, where it starts in a building
+     * <p>A stream builder has a lifecycle, which starts in a building
      * phase, during which elements can be added, and then transitions to a built
      * phase, after which elements may not be added.  The built phase begins
      * when the {@link #build()} method is called, which creates an ordered
--- a/src/share/classes/java/util/stream/StreamSpliterators.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/src/share/classes/java/util/stream/StreamSpliterators.java	Wed Aug 14 15:53:13 2013 -0700
@@ -1326,7 +1326,7 @@
                 return new InfiniteSupplyingSpliterator.OfLong(estimate = estimate >>> 1, s);
             }
         }
-
+        
         static final class OfDouble extends InfiniteSupplyingSpliterator<Double>
                 implements Spliterator.OfDouble {
             final DoubleSupplier s;
--- a/src/share/classes/java/util/stream/StreamSupport.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/src/share/classes/java/util/stream/StreamSupport.java	Wed Aug 14 15:53:13 2013 -0700
@@ -32,12 +32,8 @@
  * Low-level utility methods for creating and manipulating streams.
  *
  * <p>This class is mostly for library writers presenting stream views
- * of their data structures; most static stream methods for end users are in
- * {@link Streams}.
- *
- * <p>Unless otherwise stated, streams are created as sequential
- * streams.  A sequential stream can be transformed into a parallel stream by
- * calling the {@code parallel()} method on the created stream.
+ * of data structures; most static stream methods intended for end users are in
+ * the various {@code Stream} classes.
  *
  * @since 1.8
  */
@@ -80,7 +76,7 @@
      * {@code Supplier} of {@code Spliterator}.
      *
      * <p>The {@link Supplier#get()} method will be invoked on the supplier no
-     * more than once, and after the terminal operation of the stream pipeline
+     * more than once, and only after the terminal operation of the stream pipeline
      * commences.
      *
      * <p>For spliterators that report a characteristic of {@code IMMUTABLE}
@@ -88,7 +84,7 @@
      * <a href="../Spliterator.html#binding">late-binding</a>, it is likely
      * more efficient to use {@link #stream(java.util.Spliterator, boolean)}
      * instead.
-     * The use of a {@code Supplier} in this form provides a level of
+     * <p>The use of a {@code Supplier} in this form provides a level of
      * indirection that reduces the scope of potential interference with the
      * source.  Since the supplier is only invoked after the terminal operation
      * commences, any modifications to the source up to the start of the
@@ -148,7 +144,7 @@
      * {@code Supplier} of {@code Spliterator.OfInt}.
      *
      * <p>The {@link Supplier#get()} method will be invoked on the supplier no
-     * more than once, and after the terminal operation of the stream pipeline
+     * more than once, and only after the terminal operation of the stream pipeline
      * commences.
      *
      * <p>For spliterators that report a characteristic of {@code IMMUTABLE}
@@ -156,7 +152,7 @@
      * <a href="../Spliterator.html#binding">late-binding</a>, it is likely
      * more efficient to use {@link #intStream(java.util.Spliterator.OfInt, boolean)}
      * instead.
-     * The use of a {@code Supplier} in this form provides a level of
+     * <p>The use of a {@code Supplier} in this form provides a level of
      * indirection that reduces the scope of potential interference with the
      * source.  Since the supplier is only invoked after the terminal operation
      * commences, any modifications to the source up to the start of the
@@ -215,7 +211,7 @@
      * {@code Supplier} of {@code Spliterator.OfLong}.
      *
      * <p>The {@link Supplier#get()} method will be invoked on the supplier no
-     * more than once, and after the terminal operation of the stream pipeline
+     * more than once, and only after the terminal operation of the stream pipeline
      * commences.
      *
      * <p>For spliterators that report a characteristic of {@code IMMUTABLE}
@@ -223,7 +219,7 @@
      * <a href="../Spliterator.html#binding">late-binding</a>, it is likely
      * more efficient to use {@link #longStream(java.util.Spliterator.OfLong, boolean)}
      * instead.
-     * The use of a {@code Supplier} in this form provides a level of
+     * <p>The use of a {@code Supplier} in this form provides a level of
      * indirection that reduces the scope of potential interference with the
      * source.  Since the supplier is only invoked after the terminal operation
      * commences, any modifications to the source up to the start of the
@@ -282,7 +278,7 @@
      * {@code Supplier} of {@code Spliterator.OfDouble}.
      *
      * <p>The {@link Supplier#get()} method will be invoked on the supplier no
-     * more than once, and after the terminal operation of the stream pipeline
+     * more than once, and only after the terminal operation of the stream pipeline
      * commences.
      *
      * <p>For spliterators that report a characteristic of {@code IMMUTABLE}
@@ -290,7 +286,7 @@
      * <a href="../Spliterator.html#binding">late-binding</a>, it is likely
      * more efficient to use {@link #doubleStream(java.util.Spliterator.OfDouble, boolean)}
      * instead.
-     * The use of a {@code Supplier} in this form provides a level of
+     * <p>The use of a {@code Supplier} in this form provides a level of
      * indirection that reduces the scope of potential interference with the
      * source.  Since the supplier is only invoked after the terminal operation
      * commences, any modifications to the source up to the start of the
--- a/src/share/classes/java/util/stream/Streams.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/src/share/classes/java/util/stream/Streams.java	Wed Aug 14 15:53:13 2013 -0700
@@ -25,6 +25,7 @@
 package java.util.stream;
 
 import java.util.Comparator;
+import java.util.MayHoldCloseableResource;
 import java.util.Objects;
 import java.util.Spliterator;
 import java.util.function.Consumer;
@@ -833,4 +834,61 @@
             }
         }
     }
+
+    /**
+     * Given two Runnables, return a Runnable that executes both in sequence,
+     * even if the first throws an exception, and if both throw exceptions, add
+     * any exceptions thrown by the second as suppressed exceptions of the first.
+     */
+    static Runnable composeWithExceptions(Runnable a, Runnable b) {
+        return new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    a.run();
+                }
+                catch (Error|RuntimeException e1) {
+                    try {
+                        b.run();
+                    }
+                    catch (Error|RuntimeException e2) {
+                        e1.addSuppressed(e2);
+                    }
+                    finally {
+                        throw e1;
+                    }
+                }
+                b.run();
+            }
+        };
+    }
+
+    /**
+     * Given two MayHoldCloseableResource objects, return a Runnable that
+     * executes both of their close methods in sequence,
+     * even if the first throws an exception, and if both throw exceptions, add
+     * any exceptions thrown by the second as suppressed exceptions of the first.
+     */
+    static Runnable composedClose(MayHoldCloseableResource a, MayHoldCloseableResource b) {
+        return new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    a.close();
+                }
+                catch (Error|RuntimeException e1) {
+                    try {
+                        b.close();
+                    }
+                    catch (Error|RuntimeException e2) {
+                        e1.addSuppressed(e2);
+                    }
+                    finally {
+                        throw e1;
+                    }
+                }
+                b.close();
+            }
+        };
+    }
 }
--- a/src/share/classes/java/util/stream/package-info.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/src/share/classes/java/util/stream/package-info.java	Wed Aug 14 15:53:13 2013 -0700
@@ -24,347 +24,482 @@
  */
 
 /**
- * <h1>java.util.stream</h1>
- *
- * Classes to support functional-style operations on streams of values, as in the following:
+ * Classes to support functional-style operations on streams of values, as in
+ * the following:
  *
  * <pre>{@code
- *     int sumOfWeights = blocks.stream().filter(b -> b.getColor() == RED)
- *                                       .mapToInt(b -> b.getWeight())
- *                                       .sum();
+ *     int sum = widgets.stream()
+ *                      .filter(b -> b.getColor() == RED)
+ *                      .mapToInt(b -> b.getWeight())
+ *                      .sum();
  * }</pre>
  *
- * <p>Here we use {@code blocks}, which might be a {@code Collection}, as a source for a stream,
- * and then perform a filter-map-reduce ({@code sum()} is an example of a <a href="package-summary.html#Reduction">reduction</a>
- * operation) on the stream to obtain the sum of the weights of the red blocks.
+ * <p>Here we use {@code widgets}, a {@code Collection<Widget>},
+ * as a source for a stream, and then perform a filter-map-reduce ({@code sum()}
+ * is an example of a <a href="package-summary.html#Reduction">reduction</a>
+ * operation) on the stream to obtain the sum of the weights of the red widgets.
  *
- * <p>The key abstraction used in this approach is {@link java.util.stream.Stream}, as well as its primitive
- * specializations {@link java.util.stream.IntStream}, {@link java.util.stream.LongStream},
- * and {@link java.util.stream.DoubleStream}.  Streams differ from Collections in several ways:
+ * <p>The key abstraction introduced in this package is <em>stream</em>.  The
+ * classes {@link java.util.stream.Stream}, {@link java.util.stream.IntStream},
+ * {@link java.util.stream.LongStream}, and {@link java.util.stream.DoubleStream}
+ * are streams over objects and the primitive {@code int}, {@code long} and {
+ * {@code double} types.  Streams differ from collections in several ways:
  *
  * <ul>
- *     <li>No storage.  A stream is not a data structure that stores elements; instead, they
- *     carry values from a source (which could be a data structure, a generator, an IO channel, etc)
- *     through a pipeline of computational operations.</li>
- *     <li>Functional in nature.  An operation on a stream produces a result, but does not modify
- *     its underlying data source.  For example, filtering a {@code Stream} produces a new {@code Stream},
- *     rather than removing elements from the underlying source.</li>
- *     <li>Laziness-seeking.  Many stream operations, such as filtering, mapping, or duplicate removal,
- *     can be implemented lazily, exposing opportunities for optimization.  (For example, "find the first
- *     {@code String} matching a pattern" need not examine all the input strings.)  Stream operations
- *     are divided into intermediate ({@code Stream}-producing) operations and terminal (value-producing)
- *     operations; all intermediate operations are lazy.</li>
- *     <li>Possibly unbounded.  While collections have a finite size, streams need not.  Operations
- *     such as {@code limit(n)} or {@code findFirst()} can allow computations on infinite streams
- *     to complete in finite time.</li>
+ *     <li>No storage.  A stream is not a data structure that stores elements;
+ *     instead, it conveys values from a source such as a data structure,
+ *     an array, a generator function, or an I/O channel, through a pipeline of
+ *     computational operations.</li>
+ *     <li>Functional in nature.  An operation on a stream produces a result,
+ *     but does not modify its source.  For example, filtering a {@code Stream}
+ *     obtained from a collection produces a new {@code Stream} without the
+ *     filtered elements, rather than removing elements from the source
+ *     collection.</li>
+ *     <li>Laziness-seeking.  Many stream operations, such as filtering, mapping,
+ *     or duplicate removal, can be implemented lazily, exposing opportunities
+ *     for optimization.  (For example, "find the first {@code String} with
+ *     three consecutive vowels" need not examine all the input strings.)
+ *     Stream operations are divided into intermediate ({@code Stream}-producing)
+ *     operations and terminal (value- or side-effect-producing) operations.
+ *     Intermediate operations are always lazy.</li>
+ *     <li>Possibly unbounded.  While collections have a finite size, streams
+ *     need not.  Short-circuting operations such as {@code limit(n)} or
+ *     {@code findFirst()} can allow computations on infinite streams to
+ *     complete in finite time.</li>
+ *     <li>Consumable. The elements of a stream are only be visited once during
+ *     the life of a stream. Like an {@link java.util.Iterator}, a new stream
+ *     must be generated to revisit the same elements of the source.
+ *     </li>
+ * </ul>
+ *
+ * Streams can be obtained in a number of ways. Some examples include:
+ * <ul>
+ *     <li>From a {@link java.util.Collection} via the {@code stream()} and
+ *     {@code parallelStream()} methods;</li>
+ *     <li>From an array via {@link java.util.Arrays#stream(Object[])};</li>
+ *     <li>The lines of a file can be obtained from {@link java.io.BufferedReader#lines()};</li>
+ *     <li>Streams of file paths can be obtained from methods in {@link java.nio.file.Files};</li>
+ *     <li>Streams of random numbers can be obtained from {@link java.util.Random#ints()};</li>
+ *     <li>Numerous other stream-bearing methods in the JDK, including
+ *     {@link java.util.BitSet#stream()},
+ *     {@link java.util.regex.Pattern#splitAsStream(java.lang.CharSequence)},
+ *     and {@link java.util.jar.JarFile#stream()}.</li>
  * </ul>
  *
- * <h2><a name="StreamPipelines">Stream pipelines</a></h2>
+ * <p>Additional stream sources can be provided by third-party libraries using
+ * <a href="package-summary.html#StreamSources">these techniques</a>.
+ *
+ * <h2><a name="StreamOps">Stream operations and pipelines</a></h2>
  *
- * <p>Streams are used to create <em>pipelines</em> of <a href="package-summary.html#StreamOps">operations</a>.  A
- * complete stream pipeline has several components: a source (which may be a {@code Collection},
- * an array, a generator function, or an IO channel); zero or more <em>intermediate operations</em>
- * such as {@code Stream.filter} or {@code Stream.map}; and a <em>terminal operation</em> such
- * as {@code Stream.forEach} or {@code java.util.stream.Stream.reduce}.  Stream operations may take as parameters
- * <em>function values</em> (which are often lambda expressions, but could be method references
- * or objects) which parameterize the behavior of the operation, such as a {@code Predicate}
- * passed to the {@code Stream#filter} method.
+ * <p>Stream <a href="package-summary.html#StreamOps">operations</a> are
+ * combined to form <em>stream pipelines</em>. A stream pipeline consists of a
+ * source (such as a {@code Collection}, an array, a generator function, or an
+ * I/O channel); followed by zero or more <em>intermediate operations</em> such
+ * as {@code Stream.filter} or {@code Stream.map}; and a <em>terminal
+ * operation</em> such as {@code Stream.forEach} or {@code Stream.reduce}.
  *
- * <p>Intermediate operations return a new {@code Stream}.  They are lazy; executing an
- * intermediate operation such as {@link java.util.stream.Stream#filter Stream.filter} does
- * not actually perform any filtering, instead creating a new {@code Stream} that, when
- * traversed, contains the elements of the initial {@code Stream} that match the
- * given {@code Predicate}.  Consuming elements from the  stream source does not
- * begin until the terminal operation is executed.
+ * <p>Intermediate operations return a new {@code Stream}.  They are always
+ * <em>lazy</em>; executing an intermediate operation such as
+ * {@code Stream.filter} does not actually perform any filtering, but instead
+ * creates a new {@code Stream} that, when traversed, contains the elements of
+ * the initial {@code Stream} that match the given {@code Predicate}.  Traversal
+ * of the pipeline source does not begin until the terminal operation of the
+ * pipeline is executed.
  *
- * <p>Terminal operations consume the {@code Stream} and produce a result or a side-effect.
- * After a terminal operation is performed, the stream can no longer be used and you must
- * return to the data source, or select a new data source, to get a new stream. For example,
- * obtaining the sum of weights of all red blocks, and then of all blue blocks, requires a
- * filter-map-reduce on two different streams:
- * <pre>{@code
- *     int sumOfRedWeights  = blocks.stream().filter(b -> b.getColor() == RED)
- *                                           .mapToInt(b -> b.getWeight())
- *                                           .sum();
- *     int sumOfBlueWeights = blocks.stream().filter(b -> b.getColor() == BLUE)
- *                                           .mapToInt(b -> b.getWeight())
- *                                           .sum();
- * }</pre>
- *
- * <p>However, there are other techniques that allow you to obtain both results in a single
- * pass if multiple traversal is impractical or inefficient.  TODO provide link
+ * <p>Terminal operations, such as {@code Stream.forEach} or
+ * {@code IntStream.sum}, may traverse the stream to produce a result or a
+ * side-effect. After the terminal operation is performed, the stream pipeline
+ * is considered consumed, and can no longer be used; if you need to traverse
+ * the same data source again, you must return to the data source to get a new
+ * stream.
  *
- * <h3><a name="StreamOps">Stream operations</a></h3>
+ * <p> Processing streams lazily allows for significant efficiencies; in a
+ * pipeline such as the filter-map-sum example above, filtering, mapping, and
+ * summing can be fused into a single pass on the data, with minimal
+ * intermediate state. Laziness also allows avoiding examining all the data
+ * when it is not necessary; for operations such as "find the first string
+ * longer than 1000 characters", it is only necessary to examine just enough
+ * strings to find one that has the desired characteristics without examining
+ * all of the strings available from the source. (This behavior becomes even
+ * more important when the input stream is infinite and not merely large.)
  *
- * <p>Intermediate stream operation (such as {@code filter} or {@code sorted}) always produce a
- * new {@code Stream}, and are always<em>lazy</em>.  Executing a lazy operations does not
- * trigger processing of the stream contents; all processing is deferred until the terminal
- * operation commences.  Processing streams lazily allows for significant efficiencies; in a
- * pipeline such as the filter-map-sum example above, filtering, mapping, and addition can be
- * fused into a single pass, with minimal intermediate state.  Laziness also enables us to avoid
- * examining all the data when it is not necessary; for operations such as "find the first
- * string longer than 1000 characters", one need not examine all the input strings, just enough
- * to find one that has the desired characteristics.  (This behavior becomes even more important
- * when the input stream is infinite and not merely large.)
+ * <h3>Stream operations</h3>
  *
- * <p>Intermediate operations are further divided into <em>stateless</em> and <em>stateful</em>
- * operations.  Stateless operations retain no state from previously seen values when processing
- * a new value; examples of stateless intermediate operations include {@code filter} and
- * {@code map}.  Stateful operations may incorporate state from previously seen elements in
- * processing new values; examples of stateful intermediate operations include {@code distinct}
- * and {@code sorted}.  Stateful operations may need to process the entire input before
- * producing a result; for example, one cannot produce any results from sorting a stream until
- * one has seen all elements of the stream.  As a result, under parallel computation, some
- * pipelines containing stateful intermediate operations have to be executed in multiple passes.
- * Pipelines containing exclusively stateless intermediate operations can be processed in a
- * single pass, whether sequential or parallel.
+ * <p>Stream operations are divided into intermediate and terminal operations.
+ * Intermediate operations are further divided into <em>stateless</em> and
+ * <em>stateful</em> operations.  Stateless operations retain no state from
+ * previously seen values when processing a new value--each value is processed
+ * independently of operations on other values. Stateless intermediate
+ * operations include {@code filter} and {@code map}.  Stateful operations may
+ * incorporate state from previously seen elements in processing new values.
+ * Examples of stateful intermediate operations include {@code distinct} and
+ * {@code sorted}.  Stateful operations may need to process the entire input
+ * before producing a result.  For example, one cannot produce any results from
+ * sorting a stream until one has seen all elements of the stream.  As a result,
+ * under parallel computation, some pipelines containing stateful intermediate
+ * operations have to be executed in multiple passes or may need to buffer
+ * significant data.  Pipelines containing exclusively stateless intermediate
+ * operations can be processed in a single pass, whether sequential or parallel,
+ * with minimal data buffering.
  *
- * <p>Further, some operations are deemed <em>short-circuiting</em> operations.  An intermediate
- * operation is short-circuiting if, when presented with infinite input, it may produce a
- * finite stream as a result.  A terminal operation is short-circuiting if, when presented with
- * infinite input, it may terminate in finite time.  (Having a short-circuiting operation is a
- * necessary, but not sufficient, condition for the processing of an infinite stream to
- * terminate normally in finite time.)
+ * <p>Further, some operations are deemed <em>short-circuiting</em> operations.
+ * An intermediate operation is short-circuiting if, when presented with
+ * infinite input, it may produce a finite stream as a result.  A terminal
+ * operation is short-circuiting if, when presented with infinite input, it may
+ * terminate in finite time.  (Having a short-circuiting operation is a
+ * necessary, but not sufficient, condition for the processing of an infinite
+ * stream to terminate normally in finite time.)
  *
- * Terminal operations (such as {@code forEach} or {@code findFirst}) are always eager
- * (they execute completely before returning), and produce a non-{@code Stream} result, such
- * as a primitive value or a {@code Collection}, or have side-effects.
+ * <p>With the exception of the {@code iterator()} and {@code spliterator()}
+ * terminal operations (which are provided as an "escape hatch" to enable
+ * arbitrary stream traversals in the event that the existing operations are not
+ * sufficient to the task), terminal operations are always <em>eager</em>,
+ * executing completely before returning.
  *
  * <h3>Parallelism</h3>
  *
- * <p>By recasting aggregate operations as a pipeline of operations on a stream of values, many
- * aggregate operations can be more easily parallelized.  A {@code Stream} can execute either
- * in serial or in parallel.  When streams are created, they are either created as sequential
- * or parallel streams; the parallel-ness of streams can also be switched by the
- * {@link java.util.stream Stream#sequential()} and {@link java.util.stream.Stream#parallel()}
- * operations.  The {@code Stream} implementations in the JDK create serial streams unless
- * parallelism is explicitly requested.  For example, {@code Collection} has methods
+ * <p>Processing values with an explicit loop is inherently serial. To more
+ * easily parallelize operations it helps to recast the computations as
+ * aggregate operations upon a stream of values. Aggregate operations behave as
+ * if each stream value is processed independently of (and possibly
+ * simultaneously to) all other values in the stream. All streams can execute
+ * either in serial or in parallel with an identical set of operations
+ * available for both modes. The stream
+ * implementations in the JDK create serial streams unless parallelism is
+ * explicitly requested.  For example, {@code Collection} has methods
  * {@link java.util.Collection#stream} and {@link java.util.Collection#parallelStream},
- * which produce sequential and parallel streams respectively; other stream-bearing methods
- * such as {@link java.util.stream.IntStream#range(int, int)} produce sequential
- * streams but these can be efficiently parallelized by calling {@code parallel()} on the
- * result. The set of operations on serial and parallel streams is identical. To execute the
- * "sum of weights of blocks" query in parallel, we would do:
+ * which produce sequential and parallel streams respectively; other
+ * stream-bearing methods such as {@link java.util.stream.IntStream#range(int, int)}
+ * produce sequential streams but these can be efficiently parallelized by
+ * calling {@code parallel()} on the result. To execute the prior "sum of
+ * weights of widgets" query in parallel, we would do:
+ *
+ * <pre>{@literal
+ *     int sumOfWeights = widgets.}<b>{@literal parallelStream()}</b>{@literal .filter(b -> b.getColor() == RED)
+ *                                                .mapToInt(b -> b.getWeight())
+ *                                                .sum();
+ * }</pre>
+ *
+ * <p>The only difference between the serial and parallel versions of this
+ * example is the creation of the initial stream, "{@code parallelStream()}"
+ * versus "{@code stream()}". Whether a stream will execute in serial or
+ * parallel can be determined with the {@code isParallel()} method and can also
+ * be modified before execution using the
+ * {@link java.util.stream.BaseStream#sequential()} and
+ * {@link java.util.stream.BaseStream#parallel()} operations.  When the terminal
+ * operation is initiated, the stream pipeline is executed sequentially or in
+ * parallel depending on the mode of the stream on which it is invoked.
+ *
+ * <p>Except for operations identified as explicitly nondeterministic (such
+ * as {@code findAny())}, whether a stream executes sequentially or in parallel
+ * should not change the result of the computation.
+ *
+ * <p>Most stream operations accept parameters that describe user-specified
+ * behavior, which are often lambda expressions.  To preserve correct behavior,
+ * these <em>behavioral parameters</em> must be <em>non-interfering</em>, and in
+ * most cases must be <em>stateless</em>.  Such parameters are always instances
+ * of a <a href="../function/package-summary.html">functional interface</a> such
+ * as {@link java.util.function.Function}, and are often lambda expressions or
+ * method references.
+ *
+ * <h3><a name="Non-Interference">Non-interference</a></h3>
+ *
+ * Streams enable you to execute possibly-parallel aggregate operations over a
+ * variety of data sources, including even non-thread-safe collections such as
+ * {@code ArrayList}. This is possible only if we can prevent
+ * <em>interference</em> with the data source during the execution of a stream
+ * pipeline. (Except for the escape-hatch methods {@code iterator()} and
+ * {@code spliterator()}, execution begins when the terminal operation is
+ * invoked, and ends when the terminal operation completes.) For most data
+ * sources, preventing interference means ensuring that the data source is
+ * <em>not modified at all</em> during the execution of the stream pipeline.
+ * The concurrent collections, which are specifically
+ * designed to handle concurrent modification, do allow modification during
+ * stream execution.
+ *
+ * <p>Accordingly, behavioral parameters passed to stream methods should never
+ * modify the stream's data source.  An implementation is said to
+ * <em>interfere</em> with the data source if it modifies, or causes to be
+ * modified, the stream's data source.  The need for non-interference applies
+ * to all pipelines, not just parallel ones.  Unless the stream source is
+ * concurrent, modifying a stream's data source during execution of a stream
+ * pipeline can cause exceptions, incorrect answers, or nonconformant results.
+ *
+ * <p>Further, results may be nondeterministic or incorrect if the behavioral
+ * parameters of stream operations are <em>stateful</em>.  A stateful lambda
+ * (or other object implementing the appropriate functional interface) is one
+ * whose result depends on any state which might change during the execution
+ * of the stream pipeline.  An example of a stateful lambda is:
  *
  * <pre>{@code
- *     int sumOfWeights = blocks.parallelStream().filter(b -> b.getColor() == RED)
- *                                               .mapToInt(b -> b.getWeight())
- *                                               .sum();
+ *     Set<Integer> seen = Collections.synchronizedSet(new HashSet<>());
+ *     stream.parallel().map(e -> { if (seen.add(e)) return 0; else return e; })...
+ * }</pre>
+ *
+ * Here, if the mapping operation is performed in parallel, the results for the
+ * same input could vary from run to run, due to thread scheduling differences,
+ * whereas, with a stateless lambda expression the results would always be the
+ * same.
+ *
+ * For well-behaved stream sources, the source can be modified before the
+ * terminal operation commences and those modifications will be reflected in
+ * the covered elements.  For example, consider the following code:
+ *
+ * <pre>{@code
+ *     List<String> l = new ArrayList(Arrays.asList("one", "two"));
+ *     Stream<String> sl = l.stream();
+ *     l.add("three");
+ *     String s = sl.collect(joining(" "));
  * }</pre>
  *
- * <p>The only difference between the serial and parallel versions of this example code is
- * the creation of the initial {@code Stream}.  Whether a {@code Stream} will execute in serial
- * or parallel can be determined by the {@code Stream#isParallel} method.  When the terminal
- * operation is initiated, the entire stream pipeline is either executed sequentially or in
- * parallel, determined by the last operation that affected the stream's serial-parallel
- * orientation (which could be the stream source, or the {@code sequential()} or
- * {@code parallel()} methods.)
+ * First a list is created consisting of two strings: "one"; and "two". Then a
+ * stream is created from that list. Next the list is modified by adding a third
+ * string: "three". Finally the elements of the stream are collected and joined
+ * together. Since the list was modified before the terminal {@code collect}
+ * operation commenced the result will be a string of "one two three". All the
+ * streams returned from JDK classes are well-behaved in this manner; for
+ * streams generated by other libraries, see
+ * <a href="package-summary.html#StreamSources">Low-level stream
+ * construction</a> for requirements for building well-behaved streams.
+ *
+ * ** The example isn't about concurrent sources **
+ * <p>Some streams, particularly those whose stream sources are concurrent, can
+ * tolerate concurrent modification during execution of a stream pipeline.
+ * However, in no case should behavioral parameters to stream operations modify
+ * the stream source.  For example, constructions like the following may fail
+ * to terminate, produce inaccurate results, or throw {@link java.util.ConcurrentModificationException}:
+ * <pre>{@code
+ *     List<String> l = new ArrayList(Arrays.asList("one", "two"));
+ *     Stream<String> sl = l.stream();
+ *     String s = sl.peek(s -> l.add("BAD LAMBDA")).collect(joining(" "));
+ * }</pre>
+ * will fail as the {@code peek} operation will attempt to add the string
+ * "BAD LAMBDA" to the source after the terminal operation has commenced.
+ *
+ * <h3>Side-effects</h3>
  *
- * <p>In order for the results of parallel operations to be deterministic and consistent with
- * their serial equivalent, the function values passed into the various stream operations should
- * be <a href="#NonInteference"><em>stateless</em></a>.
+ * Side-effects in behavioral parameters to stream operations are, in general,
+ * discouraged, as they can often lead to unwitting violations of the
+ * statelessness requirement, as well as other thread-safety hazards.  Many
+ * computations where one might be tempted to use side effects can be more
+ * safely and efficiently expressed without side-effects, such as using
+ * <a href="package-summary.html#Reduction">reduction</a> instead of mutable
+ * accumulators. (Side-effects such as using {@code println()} for debugging
+ * purposes are usually harmless.)  A small number of stream operations, such as
+ * {@code forEach()} and {@code peek()}, can only operate only via side-effects;
+ * these should be used with care.
+ *
+ * <p>As an example of how to transform a stream pipeline that inappropriately
+ * uses side-effects to one that does not, the following code searches a stream
+ * of strings for those matching a given regular expression, and puts the
+ * matches in a list.
+ *
+ * <pre>{@code
+ *     ArrayList<String> results = new ArrayList<>();
+ *     stream.filter(s -> pattern.matcher(s).matches())
+ *           .forEach(s -> results.add(s));  // BAD!  Uses side-effects!
+ * }</pre>
+ *
+ * This code uses side-effects unnecessarily.  If executed in parallel, the
+ * non-thread-safety of {@code ArrayList} would cause incorrect results, and
+ * adding needed synchronization would cause contention, undermining the
+ * benefit of parallelism.  And, using side-effects here are completely
+ * unnecessarily; the {@code forEach()} can be replaced with a reduction
+ * operation that is safer, more efficient, and more amenable to
+ * parallelization.
+ *
+ * <pre>{@code
+ *     List<String>results =
+ *         stream.filter(s -> pattern.matcher(s).matches())
+ *               .collect(Collectors.toList());  // No side-effects!
+ * }</pre>
  *
  * <h3><a name="Ordering">Ordering</a></h3>
  *
- * <p>Streams may or may not have an <em>encounter order</em>.  An encounter
- * order specifies the order in which elements are provided by the stream to the
- * operations pipeline.  Whether or not there is an encounter order depends on
- * the source, the intermediate  operations, and the terminal operation.
- * Certain stream sources (such as {@code List} or arrays) are intrinsically
- * ordered, whereas others (such as {@code HashSet}) are not.  Some intermediate
- * operations may impose an encounter order on an otherwise unordered stream,
- * such as {@link java.util.stream.Stream#sorted()}, and others may render an
- * ordered stream unordered (such as {@link java.util.stream.Stream#unordered()}).
- * Some terminal operations may ignore encounter order, such as
- * {@link java.util.stream.Stream#forEach}.
+ * <p>Streams may or may not have a defined <em>encounter order</em>.  Whether
+ * or not a stream has an encounter order depends on the source and the
+ * intermediate operations.  Certain stream sources (such as {@code List} or
+ * arrays) are intrinsically ordered, whereas others (such as {@code HashSet})
+ * are not.  Some intermediate operations, such as {@code sorted()}, may impose
+ * an encounter order on an otherwise unordered stream, and others may render an
+ * ordered stream unordered, such as {@link java.util.stream.BaseStream#unordered()}.
+ * Further, some terminal operations may ignore encounter order, such as
+ * {@code forEach()}.
  *
- * <p>If a Stream is ordered, most operations are constrained to operate on the
+ * <p>If a stream is ordered, most operations are constrained to operate on the
  * elements in their encounter order; if the source of a stream is a {@code List}
  * containing {@code [1, 2, 3]}, then the result of executing {@code map(x -> x*2)}
  * must be {@code [2, 4, 6]}.  However, if the source has no defined encounter
- * order, than any of the six permutations of the values {@code [2, 4, 6]} would
- * be a valid result. Many operations can still be efficiently parallelized even
- * under ordering constraints.
+ * order, then any of the six permutations of the values {@code [2, 4, 6]} would
+ * be a valid result.
  *
  * <p>For sequential streams, ordering is only relevant to the determinism
  * of operations performed repeatedly on the same source.  (An {@code ArrayList}
  * is constrained to iterate elements in order; a {@code HashSet} is not, and
  * repeated iteration might produce a different order.)
  *
- * <p>For parallel streams, relaxing the ordering constraint can enable
- * optimized implementation for some operations.  For example, duplicate
- * filtration on an ordered stream must completely process the first partition
- * before it can return any elements from a subsequent partition, even if those
- * elements are available earlier.  On the other hand, without the constraint of
- * ordering, duplicate filtration can be done more efficiently by using
- * a shared {@code ConcurrentHashSet}.  There will be cases where the stream
- * is structurally ordered (the source is ordered and the intermediate
- * operations are order-preserving), but the user does not particularly care
- * about the encounter order.  In some cases, explicitly de-ordering the stream
- * with the {@link java.util.stream.Stream#unordered()} method may result in
+ * <p>For parallel streams, relaxing the ordering constraint can sometimes enable
+ * more efficient implementation for some operations.  Certain aggregate operations,
+ * such as filtering duplicates ({@code distinct()}) or grouped reductions
+ * ({@code Collectors.groupingBy()}) can be performed more efficiently using
+ * concurrent data structures rather than merging if ordering of elements
+ * is not relevant.  Operations that are intrinsically tied to encounter order,
+ * such as {@code limit()} or {@code forEachOrdered()}, may require
+ * buffering to ensure proper ordering, undermining the benefit of parallelism.
+ * In cases where the stream is structurally ordered (the source is ordered and
+ * the intermediate operations are order-preserving), but the user does not
+ * particularly <em>care</em> about the encounter order, explicitly de-ordering
+ * the stream with {@link java.util.stream.BaseStream#unordered()} may result in
  * improved parallel performance for some stateful or terminal operations.
- *
- * <h3><a name="Non-Interference">Non-interference</a></h3>
- *
- * The {@code java.util.stream} package enables you to execute possibly-parallel
- * bulk-data operations over a variety of data sources, including even non-thread-safe
- * collections such as {@code ArrayList}.  This is possible only if we can
- * prevent <em>interference</em> with the data source during the execution of a
- * stream pipeline.  (Execution begins when the terminal operation is invoked, and ends
- * when the terminal operation completes.)  For most data sources, preventing interference
- * means ensuring that the data source is <em>not modified at all</em> during the execution
- * of the stream pipeline.  (Some data sources, such as concurrent collections, are
- * specifically designed to handle concurrent modification.)
- *
- * <p>Accordingly, lambda expressions (or other objects implementing the appropriate functional
- * interface) passed to stream methods should never modify the stream's data source.  An
- * implementation is said to <em>interfere</em> with the data source if it modifies, or causes
- * to be modified, the stream's data source.  The need for non-interference applies to all
- * pipelines, not just parallel ones.  Unless the stream source is concurrent, modifying a
- * stream's data source during execution of a stream pipeline can cause exceptions, incorrect
- * answers, or nonconformant results.
- *
- * <p>Further, results may be nondeterministic or incorrect if the lambda expressions passed to
- * stream operations are <em>stateful</em>.  A stateful lambda (or other object implementing the
- * appropriate functional interface) is one whose result depends on any state which might change
- * during the execution of the stream pipeline.  An example of a stateful lambda is:
- * <pre>{@code
- *     Set<Integer> seen = Collections.synchronizedSet(new HashSet<>());
- *     stream.parallel().map(e -> { if (seen.add(e)) return 0; else return e; })...
- * }</pre>
- * Here, if the mapping operation is performed in parallel, the results for the same input
- * could vary from run to run, due to thread scheduling differences, whereas, with a stateless
- * lambda expression the results would always be the same.
- *
- * <h3>Side-effects</h3>
+ * However, most stream pipelines, such as the "sum of weight of blocks" example
+ * above, can still be efficiently parallelized even under ordering constraints.
  *
  * <h2><a name="Reduction">Reduction operations</a></h2>
  *
- * A <em>reduction</em> operation takes a stream of elements and processes them in a way
- * that reduces to a single value or summary description, such as finding the sum or maximum
- * of a set of numbers.  (In more complex scenarios, the reduction operation might need to
- * extract data from the elements before reducing that data to a single value, such as
- * finding the sum of weights of a set of blocks.  This would require extracting the weight
- * from each block before summing up the weights.)
+ * A <em>reduction</em> operation (also called a <em>fold</em>) takes a sequence
+ * of input elements and combines them into a single summary result by repeated
+ * application of a combining operation, such as finding the sum or maximum of
+ * a set of numbers, or accumulating them into a list.  The streams classes have
+ * many forms of reduction operations, called
+ * {@link java.util.stream.Stream#reduce(java.util.function.BinaryOperator) reduce()}
+ * and {@link java.util.stream.Stream#collect(java.util.stream.Collector) collect()},
+ * for performing reductions.
  *
- * <p>Of course, such operations can be readily implemented as simple sequential loops, as in:
+ * <p>Of course, such operations can be readily implemented as simple sequential
+ * loops, as in:
  * <pre>{@code
  *    int sum = 0;
  *    for (int x : numbers) {
  *       sum += x;
  *    }
  * }</pre>
- * However, there may be a significant advantage to preferring a {@link java.util.stream.Stream#reduce reduce operation}
- * over a mutative accumulation such as the above -- a properly constructed reduce operation is
- * inherently parallelizable so long as the
- * {@link java.util.function.BinaryOperator reduction operaterator}
- * has the right characteristics. Specifically the operator must be
- * <a href="#Associativity">associative</a>.  For example, given a
- * stream of numbers for which we want to find the sum, we can write:
+ * However, there may be a significant reason to prefer a reduce operation
+ * over a mutative accumulation such as the above.  Not only is a reduction
+ * "more abstract" -- it operates on the stream as a whole rather than individual
+ * elements -- but a properly constructed reduce operation is inherently
+ * parallelizable, so long as the function(s) used to process the elements
+ * have the right characteristics.  (Specifically, operators passed to
+ * {@code reduce()} must be <a href="package-summary.html#Associativity">associative</a>.)
+ * For example, given a stream of numbers for which we want to find the sum, we
+ * can write:
  * <pre>{@code
- *    int sum = numbers.reduce(0, (x,y) -> x+y);
+ *    int sum = numbers.stream().reduce(0, (x,y) -> x+y);
+ * }</pre>
+ * or:
+ * <pre>{@code
+ *    int sum = numbers.stream().reduce(0, Integer::sum);
  * }</pre>
- * or more succinctly:
+ *
+ * <p>These reduction operations can run safely in parallel with almost no
+ * modification:
  * <pre>{@code
- *    int sum = numbers.reduce(0, Integer::sum);
+ *    int sum = numbers.parallelStream().reduce(0, Integer::sum);
  * }</pre>
  *
- * <p>(The primitive specializations of {@link java.util.stream.Stream}, such as
- * {@link java.util.stream.IntStream}, even have convenience methods for common reductions,
- * such as {@link java.util.stream.IntStream#sum() sum} and {@link java.util.stream.IntStream#max() max},
- * which are implemented as simple wrappers around reduce.)
+ * <p>The primitive stream classes, such as {@link java.util.stream.IntStream},
+ * have convenience methods for common reductions, such as
+ * {@link java.util.stream.IntStream#sum() sum()} and {@link java.util.stream.IntStream#max() max()}.
  *
- * <p>Reduction parallellizes well since the implementation of {@code reduce} can operate on
- * subsets of the stream in parallel, and then combine the intermediate results to get the final
- * correct answer.  Even if you were to use a parallelizable form of the
- * {@link java.util.stream.Stream#forEach(Consumer) forEach()} method
- * in place of the original for-each loop above, you would still have to provide thread-safe
- * updates to the shared accumulating variable {@code sum}, and the required synchronization
- * would likely eliminate any performance gain from parallelism. Using a {@code reduce} method
- * instead removes all of the burden of parallelizing the reduction operation, and the library
- * can provide an efficient parallel implementation with no additional synchronization needed.
+ * <p>Reduction parallellizes well because the implementation of {@code reduce()}
+ * can operate on subsets of the stream in parallel, and then combine the
+ * intermediate results to get the final correct answer.  Even if you were to
+ * use a parallelizable form of {@link java.util.stream.Stream#forEach(Consumer) forEach()}
+ * in place of the original for-each loop above, you would still have to provide
+ * thread-safe updates to the shared accumulating variable {@code sum}, and
+ * the required synchronization would likely eliminate any performance gain from
+ * parallelism. Using a {@code reduce()} method instead removes all of the
+ * burden of parallelizing the reduction operation, and the library can provide
+ * an efficient parallel implementation with no additional synchronization.
  *
- * <p>The "blocks" examples shown earlier shows how reduction combines with other operations
- * to replace for loops with bulk operations.  If {@code blocks} is a collection of {@code Block}
- * objects, which have a {@code getWeight} method, we can find the heaviest block with:
+ * <p>The "widgets" examples shown earlier shows how reduction combines with
+ * other operations to replace for loops with bulk operations.  If {@code widgets}
+ * is a collection of {@code Widget} objects, which have a {@code getWeight} method,
+ * we can find the heaviest widget with:
  * <pre>{@code
- *     OptionalInt heaviest = blocks.stream()
- *                                  .mapToInt(Block::getWeight)
- *                                  .reduce(Integer::max);
+ *     OptionalInt heaviest = widgets.stream()
+ *                                   .mapToInt(Widget::getWeight)
+ *                                   .reduce(Integer::max);
  * }</pre>
  *
- * <p>In its more general form, a {@code reduce} operation on elements of type {@code <T>}
- * yielding a result of type {@code <U>} requires three parameters:
+ * <p>In its more general form, a {@code reduce} operation on elements of type
+ * {@code <T>} yielding a result of type {@code <U>} requires three parameters:
  * <pre>{@code
  * <U> U reduce(U identity,
- *              BiFunction<U, ? super T, U> accumlator,
+ *              BiFunction<U, ? super T, U> accumulator,
  *              BinaryOperator<U> combiner);
  * }</pre>
- * Here, the <em>identity</em> element is both an initial seed for the reduction, and a default
- * result if there are no elements. The <em>accumulator</em> function takes a partial result and
- * the next element, and produce a new partial result. The <em>combiner</em> function combines
- * the partial results of two accumulators to produce a new partial result, and eventually the
- * final result.
+ * Here, the <em>identity</em> element is both an initial seed for the reduction,
+ * and a default result if there are no elements. The <em>accumulator</em>
+ * function takes a partial result and the next element, and produce a new
+ * partial result. The <em>combiner</em> function combines the partial results
+ * of two accumulators to produce a new partial result, and eventually the final
+ * result.  (The combiner is necessary in parallel reductions, where the input
+ * is partitioned, a partial accumulation is computed for each partition, and
+ * then the partial results are combined.)
  *
- * <p>This form is a generalization of the two-argument form, and is also a generalization of
- * the map-reduce construct illustrated above.  If we wanted to re-cast the simple {@code sum}
- * example using the more general form, {@code 0} would be the identity element, while
- * {@code Integer::sum} would be both the accumulator and combiner. For the sum-of-weights
- * example, this could be re-cast as:
+ * <p>This form is a generalization of the two-argument form, and is also a
+ * generalization of the map-reduce construct illustrated above.  If we wanted
+ * to re-cast the simple {@code sum} example using the more general form,
+ * {@code 0} would be the identity element, while {@code Integer::sum} would be
+ * both the accumulator and combiner. For the sum-of-weights example, this could
+ * be re-cast as:
  * <pre>{@code
- *     int sumOfWeights = blocks.stream().reduce(0,
- *                                               (sum, b) -> sum + b.getWeight())
- *                                               Integer::sum);
+ *     int sumOfWeights = widgets.stream().reduce(0,
+ *                                                (sum, b) -> sum + b.getWeight())
+ *                                                Integer::sum);
  * }</pre>
- * though the map-reduce form is more readable and generally preferable.  The generalized form
- * is provided for cases where significant work can be optimized away by combining mapping and
- * reducing into a single function.
+ * though the map-reduce form is more readable and therefore generally preferable.
+ * The generalized form is provided for cases where significant work can be
+ * optimized away by combining mapping and reducing into a single function.
  *
- * <p>More formally, the {@code identity} value must be an <em>identity</em> for the combiner
- * function. This means that for all {@code u}, {@code combiner.apply(identity, u)} is equal
- * to {@code u}. Additionally, the {@code combiner} function must be
- * <a href="#Associativity">associative</a> and must be compatible with the {@code accumulator}
- * function; for all {@code u} and {@code t}, the following must hold:
- * <pre>{@code
- *     combiner.apply(u, accumulator.apply(identity, t)) == accumulator.apply(u, t)
- * }</pre>
+ * <p>More formally, the {@code identity} value must be an <em>identity</em> for
+ * the combiner function. This means that for all {@code u},
+ * {@code combiner.apply(identity, u)} is equal to {@code u}. Additionally, the
+ * {@code combiner} function must be <a href="package-summary.html#Associativity">associative</a> and
+ * must be compatible with the {@code accumulator} function; for all {@code u}
+ * and {@code t}, {@code combiner.apply(u, accumulator.apply(identity, t))} must
+ * be {@code equals()} to {@code accumulator.apply(u, t)}.
  *
  * <h3><a name="MutableReduction">Mutable Reduction</a></h3>
  *
- * A <em>mutable</em> reduction operation is similar to an ordinary reduction, in that it reduces
- * a stream of values to a single value, but instead of producing a distinct single-valued result, it
- * mutates a general <em>result container</em>, such as a {@code Collection} or {@code StringBuilder},
+ * A <em>mutable reduction operation</em> accumulates input elements into a
+ * mutable result container, such as a {@code Collection} or {@code StringBuilder},
  * as it processes the elements in the stream.
  *
- * <p>For example, if we wanted to take a stream of strings and concatenate them into a single
- * long string, we <em>could</em> achieve this with ordinary reduction:
+ * <p>If we wanted to take a stream of strings and concatenate them into a
+ * single long string, we <em>could</em> achieve this with ordinary reduction:
  * <pre>{@code
  *     String concatenated = strings.reduce("", String::concat)
  * }</pre>
  *
- * We would get the desired result, and it would even work in parallel.  However, we might not
- * be happy about the performance!  Such an implementation would do a great deal of string
- * copying, and the run time would be <em>O(n^2)</em> in the number of elements.  A more
- * performant approach would be to accumulate the results into a {@link java.lang.StringBuilder}, which
- * is a mutable container for accumulating strings.  We can use the same technique to
+ * We would get the desired result, and it would even work in parallel.  However,
+ * we might not be happy about the performance!  Such an implementation would do
+ * a great deal of string copying, and the run time would be <em>O(n^2)</em> in
+ * the number of characters.  A more performant approach would be to accumulate
+ * the results into a {@link java.lang.StringBuilder}, which is a mutable
+ * container for accumulating strings.  We can use the same technique to
  * parallelize mutable reduction as we do with ordinary reduction.
  *
- * <p>The mutable reduction operation is called {@link java.util.stream.Stream#collect(Collector) collect()}, as it
- * collects together the desired results into a result container such as {@code StringBuilder}.
- * A {@code collect} operation requires three things: a factory function which will construct
- * new instances of the result container, an accumulating function that will update a result
- * container by incorporating a new element, and a combining function that can take two
- * result containers and merge their contents.  The form of this is very similar to the general
+ * <p>The mutable reduction operation is called {@link java.util.stream.Stream#collect(Collector) collect()},
+ * as it collects together the desired results into a result container such
+ * as {@code StringBuilder}. A {@code collect} operation requires three things:
+ * a factory function to construct new instances of the result container, an
+ * accumulating function that will incorporate an input element into a result
+ * container, and a combining function that can take two result containers and
+ * merge their contents.  The form of this is very similar to the general
  * form of ordinary reduction:
  * <pre>{@code
  * <R> R collect(Supplier<R> resultFactory,
  *               BiConsumer<R, ? super T> accumulator,
  *               BiConsumer<R, R> combiner);
  * }</pre>
- * As with {@code reduce()}, the benefit of expressing {@code collect} in this abstract way is
- * that it is directly amenable to parallelization: we can accumulate partial results in parallel
- * and then combine them.  For example, to collect the String representations of the elements
- * in a stream into an {@code ArrayList}, we could write the obvious sequential for-each form:
+ * As with {@code reduce()}, the benefit of expressing {@code collect} in this
+ * abstract way is that it is directly amenable to parallelization: we can
+ * accumulate partial results in parallel and then combine them, so long as the
+ * accumulation and combining functions satisfy the appropriate requirements.
+ * For example, to collect the String representations of the elements in a
+ * stream into an {@code ArrayList}, we could write the obvious sequential
+ * for-each form:
  * <pre>{@code
  *     ArrayList<String> strings = new ArrayList<>();
  *     for (T element : stream) {
@@ -377,56 +512,72 @@
  *                                                (c, e) -> c.add(e.toString()),
  *                                                (c1, c2) -> c1.addAll(c2));
  * }</pre>
- * or, noting that we have buried a mapping operation inside the accumulator function, more
- * succinctly as:
+ * or, noting that we have buried a mapping operation inside the accumulator
+ * function, more succinctly as:
  * <pre>{@code
  *     ArrayList<String> strings = stream.map(Object::toString)
  *                                       .collect(ArrayList::new, ArrayList::add, ArrayList::addAll);
  * }</pre>
- * Here, our supplier is just the {@link java.util.ArrayList#ArrayList() ArrayList constructor}, the
- * accumulator adds the stringified element to an {@code ArrayList}, and the combiner simply
- * uses {@link java.util.ArrayList#addAll addAll} to copy the strings from one container into the other.
+ * Here, our supplier is just the {@link java.util.ArrayList#ArrayList()
+ * ArrayList constructor}, the accumulator adds the stringified element to an
+ * {@code ArrayList}, and the combiner simply uses {@link java.util.ArrayList#addAll addAll}
+ * to copy the strings from one container into the other.
  *
- * <p>As with the regular reduction operation, the ability to parallelize only comes if an
- * <a href="package-summary.html#Associativity">associativity</a> condition is met. The {@code combiner} is associative
- * if for result containers {@code r1}, {@code r2}, and {@code r3}:
+ * <p>Packaging mutable reductions into a collector has another advantage:
+ * composability.  The class {@link java.util.stream.Collectors} contains a
+ * number of predefined factories for collectors, including some combinators
+ * that take one collector and produce a derived collector.  For example, given
+ * the following collector that computes the sum of the salaries of a stream of
+ * employees:
+ *
  * <pre>{@code
- *    combiner.accept(r1, r2);
- *    combiner.accept(r1, r3);
- * }</pre>
- * is equivalent to
- * <pre>{@code
- *    combiner.accept(r2, r3);
- *    combiner.accept(r1, r2);
- * }</pre>
- * where equivalence means that {@code r1} is left in the same state (according to the meaning
- * of {@link java.lang.Object#equals equals} for the element types). Similarly, the {@code resultFactory}
- * must act as an <em>identity</em> with respect to the {@code combiner} so that for any result
- * container {@code r}:
+ *     Collector<Employee, ?, Integer> summingSalaries
+ *         = Collectors.summingInt(Employee::getSalary))
+ * } </pre>
+ *
+ * If we wanted to create a collector to tabulate the sum of salaries by
+ * department, we could reuse {@code summingSalaries} using
+ * {@link java.util.stream.Collectors#groupingBy(java.util.function.Function, java.util.stream.Collector)}:
+ *
  * <pre>{@code
- *     combiner.accept(r, resultFactory.get());
- * }</pre>
- * does not modify the state of {@code r} (again according to the meaning of
- * {@link java.lang.Object#equals equals}). Finally, the {@code accumulator} and {@code combiner} must be
- * compatible such that for a result container {@code r} and element {@code t}:
- * <pre>{@code
- *    r2 = resultFactory.get();
- *    accumulator.accept(r2, t);
- *    combiner.accept(r, r2);
- * }</pre>
- * is equivalent to:
+ *     Map<Department, Integer> salariesByDept
+ *         = employees.stream().collect(Collectors.groupingBy(Employee::getDepartment,
+ *                                                            summingSalaries));
+ * } </pre>
+ *
+ * <p>As with the regular reduction operation, the ability to parallelize only
+ * comes if appropriate conditions are met.  For any partially accumulated result,
+ * combining it with an empty result container must produce an equivalent
+ * result.  That is, for a partially accumulated result {@code a} that is the
+ * result of any series of accumulator and combiner invocations, {@code a} must
+ * be equivalent to {@code combiner.apply(a, supplier.get())}.
+ *
+ * <p>Further, however the computation is split, it must produce an equivalent
+ * result.  For any input elements {@code t1} and {@code t2}, the results
+ * {@code r1} and {@code r2} in the computation below must be equivalent:
  * <pre>{@code
- *    accumulator.accept(r,t);
- * }</pre>
- * where equivalence means that {@code r} is left in the same state (again according to the
- * meaning of {@link java.lang.Object#equals equals}).
+ *     A a1 = supplier.get();
+ *     accumulator.accept(a1, t1);
+ *     accumulator.accept(a1, t2);
+ *     R r1 = finisher.apply(a1);  // result without splitting
  *
- * <p> The three aspects of {@code collect}: supplier, accumulator, and combiner, are often very
- * tightly coupled, and it is convenient to introduce the notion of a {@link java.util.stream.Collector} as
- * being an object that embodies all three aspects. There is a {@link java.util.stream.Stream#collect(Collector) collect}
- * method that simply takes a {@code Collector} and returns the resulting container.
- * The above example for collecting strings into a {@code List} can be rewritten using a
- * standard {@code Collector} as:
+ *     A a2 = supplier.get();
+ *     accumulator.accept(a2, t1);
+ *     A a3 = supplier.get();
+ *     accumulator.accept(a3, t2);
+ *     R r2 = finisher.apply(combiner.apply(a2, a3));  // result with splitting
+ * } </pre>
+ *
+ * <p>Here, equivalence generally means according to {@link java.lang.Object#equals(Object)},
+ * but in some cases equivalence may be relaxed to account for differences in
+ * order.
+ *
+ * <p> The three aspects of {@code collect}: supplier, accumulator, and combiner,
+ * are often very tightly coupled, and it is convenient to introduce the notion
+ * of a {@link java.util.stream.Collector} as being an object that embodies all
+ * three aspects. There is a {@link java.util.stream.Stream#collect(Collector) collect}
+ * method that simply takes a {@code Collector}. The above example for collecting
+ * strings into a {@code List} can be rewritten using a standard {@code Collector} as:
  * <pre>{@code
  *     ArrayList<String> strings = stream.map(Object::toString)
  *                                       .collect(Collectors.toList());
@@ -434,35 +585,33 @@
  *
  * <h3><a name="ConcurrentReduction">Reduction, Concurrency, and Ordering</a></h3>
  *
- * With some complex reduction operations, for example a collect that produces a
- * {@code Map}, such as:
+ * With some complex reduction operations, for example a {@code collect()} that
+ * produces a {@code Map}, such as:
  * <pre>{@code
  *     Map<Buyer, List<Transaction>> salesByBuyer
  *         = txns.parallelStream()
  *               .collect(Collectors.groupingBy(Transaction::getBuyer));
  * }</pre>
- * (where {@link java.util.stream.Collectors#groupingBy} is a utility function
- * that returns a {@link java.util.stream.Collector} for grouping sets of elements based on some key)
  * it may actually be counterproductive to perform the operation in parallel.
  * This is because the combining step (merging one {@code Map} into another by key)
  * can be expensive for some {@code Map} implementations.
  *
  * <p>Suppose, however, that the result container used in this reduction
  * was a concurrently modifiable collection -- such as a
- * {@link java.util.concurrent.ConcurrentHashMap ConcurrentHashMap}. In that case,
- * the parallel invocations of the accumulator could actually deposit their results
- * concurrently into the same shared result container, eliminating the need for the combiner to
- * merge distinct result containers. This potentially provides a boost
- * to the parallel execution performance. We call this a <em>concurrent</em> reduction.
+ * {@link java.util.concurrent.ConcurrentHashMap}. In that case, the parallel
+ * invocations of the accumulator could actually deposit their results
+ * concurrently into the same shared result container, eliminating the need for
+ * the combiner to merge distinct result containers. This potentially provides
+ * a boost to the parallel execution performance. We call this a <em>concurrent</em>
+ * reduction.
  *
- * <p>A {@link java.util.stream.Collector} that supports concurrent reduction is marked with the
- * {@link java.util.stream.Collector.Characteristics#CONCURRENT} characteristic.
- * Having a concurrent collector is a necessary condition for performing a
- * concurrent reduction, but that alone is not sufficient. If you imagine multiple
- * accumulators depositing results into a shared container, the order in which
- * results are deposited is non-deterministic. Consequently, a concurrent reduction
- * is only possible if ordering is not important for the stream being processed.
- * The {@link java.util.stream.Stream#collect(Collector)}
+ * <p>A {@link java.util.stream.Collector} that supports concurrent reduction is
+ * marked with the {@link java.util.stream.Collector.Characteristics#CONCURRENT}
+ * characteristic.  However, a concurrent collection also has a downside.  If
+ * multiple threads are depositing results concurrently into a shared container,
+ * the order in which results are deposited is non-deterministic. Consequently,
+ * a concurrent reduction is only possible if ordering is not important for the
+ * stream being processed. The {@link java.util.stream.Stream#collect(Collector)}
  * implementation will only perform a concurrent reduction if
  * <ul>
  * <li>The stream is parallel;</li>
@@ -472,15 +621,16 @@
  * <li>Either the stream is unordered, or the collector has the
  * {@link java.util.stream.Collector.Characteristics#UNORDERED} characteristic.
  * </ul>
- * For example:
+ * You can ensure the stream is unordered by using the
+ * {@link java.util.stream.BaseStream#unordered()} method.  For example:
  * <pre>{@code
  *     Map<Buyer, List<Transaction>> salesByBuyer
  *         = txns.parallelStream()
  *               .unordered()
  *               .collect(groupingByConcurrent(Transaction::getBuyer));
  * }</pre>
- * (where {@link java.util.stream.Collectors#groupingByConcurrent} is the concurrent companion
- * to {@code groupingBy}).
+ * (where {@link java.util.stream.Collectors#groupingByConcurrent} is the
+ * concurrent equivalent of {@code groupingBy}).
  *
  * <p>Note that if it is important that the elements for a given key appear in the
  * order they appear in the source, then we cannot use a concurrent reduction,
@@ -488,79 +638,73 @@
  * be constrained to implement either a sequential reduction or a merge-based
  * parallel reduction.
  *
- * <h2><a name="Associativity">Associativity</a></h2>
+ * <h3><a name="Associativity">Associativity</a></h3>
  *
- * An operator or function {@code op} is <em>associative</em> if the following holds:
+ * An operator or function {@code op} is <em>associative</em> if the following
+ * holds:
  * <pre>{@code
  *     (a op b) op c == a op (b op c)
  * }</pre>
- * The importance of this to parallel evaluation can be seen if we expand this to four terms:
+ * The importance of this to parallel evaluation can be seen if we expand this
+ * to four terms:
  * <pre>{@code
  *     a op b op c op d == (a op b) op (c op d)
  * }</pre>
- * So we can evaluate {@code (a op b)} in parallel with {@code (c op d)} and then invoke {@code op} on
- * the results.
- * TODO what does associative mean for mutative combining functions?
- * FIXME: we described mutative associativity above.
+ * So we can evaluate {@code (a op b)} in parallel with {@code (c op d)}, and
+ * then invoke {@code op} on the results.
  *
- * <h2><a name="StreamSources">Stream sources</a></h2>
- * TODO where does this section go?
+ * <h2><a name="StreamSources">Low-level stream construction</a></h2>
  *
- * XXX - change to section to stream construction gradually introducing more
- *       complex ways to construct
- *     - construction from Collection
- *     - construction from Iterator
- *     - construction from array
- *     - construction from generators
- *     - construction from spliterator
+ * So far, all the stream examples have used methods like
+ * {@link java.util.Collection#stream()} or {@link java.util.Arrays#stream(Object[])}
+ * to obtain a stream.  How are those stream-bearing methods implemented?
+ *
+ * <p>The class {@link java.util.stream.StreamSupport} has a number of low-level
+ * methods for creating a stream, all using some form of a {@link java.util.Spliterator}.
+ * A spliterator is the parallel analogue of an {@link java.util.Iterator}; it
+ * describes a (possibly infinite) collection of elements, with support for
+ * sequentially advancing, bulk traversal, and splitting off some portion of the
+ * input into another spliterator which can be processed in parallel.  At the
+ * lowest level, all streams are driven by a spliterator.
  *
- * XXX - the following is quite low-level but important aspect of stream constriction
- *
- * <p>A pipeline is initially constructed from a spliterator (see {@link java.util.Spliterator}) supplied by a stream source.
- * The spliterator covers elements of the source and provides element traversal operations
- * for a possibly-parallel computation.  See methods on {@link java.util.stream.Streams} for construction
- * of pipelines using spliterators.
+ * <p>There are a number of implementation choices in implementing a spliterator,
+ * nearly all of which are tradeoffs between simplicity of implementation and
+ * runtime performance of streams using that spliterator.  The simplest, but
+ * least performant, way to create a spliterator is to create one from an iterator
+ * using {@link java.util.Spliterators#spliteratorUnknownSize(java.util.Iterator, int)}.
+ * While such a spliterator will work, it will likely offer poor parallel
+ * performance, since we have lost sizing information (how big is the underlying
+ * data set), as well as being constrained to a simplistic splitting algorithm.
  *
- * <p>A source may directly supply a spliterator.  If so, the spliterator is traversed, split, or queried
- * for estimated size after, and never before, the terminal operation commences. It is strongly recommended
- * that the spliterator report a characteristic of {@code IMMUTABLE} or {@code CONCURRENT}, or be
- * <em>late-binding</em> and not bind to the elements it covers until traversed, split or queried for
- * estimated size.
+ * <p>A higher-quality spliterator will provide balanced and known-size splits,
+ * accurate sizing information, and a number of other
+ * {@link java.util.Spliterator#characteristics() characteristics} of the
+ * spliterator or data that can be used by implementations to optimize
+ * execution.
  *
- * <p>If a source cannot directly supply a recommended spliterator then it may indirectly supply a spliterator
- * using a {@code Supplier}.  The spliterator is obtained from the supplier after, and never before, the terminal
+ * <p>Spliterators for mutable data sources have an additional challenge; timing
+ * of binding to the data, since the data could change between the time the
+ * spliterator is created and the time the stream pipeline is executed.  Ideally,
+ * a spliterator for a stream would report a characteristic of {@code IMMUTABLE}
+ * or {@code CONCURRENT}; if not it should be <a href="../Spliterator.html#binding"><em>late-binding</em></a>.
+ * If a source cannot directly supply a recommended spliterator, it may
+ * indirectly supply a spliterator using a {@code Supplier}, and construct a
+ * stream via the {@code Supplier}-accepting versions of
+ * {@link java.util.stream.StreamSupport#stream(Supplier, int, boolean) stream()}.
+ * The spliterator is obtained from the supplier only after the terminal
  * operation of the stream pipeline commences.
  *
- * <p>Such requirements significantly reduce the scope of potential interference to the interval starting
- * with the commencing of the terminal operation and ending with the producing a result or side-effect.  See
- * <a href="package-summary.html#Non-Interference">Non-Interference</a> for
- * more details.
- *
- * XXX - move the following to the non-interference section
- *
- * <p>A source can be modified before the terminal operation commences and those modifications will be reflected in
- * the covered elements.  Afterwards, and depending on the properties of the source, further modifications
- * might not be reflected and the throwing of a {@code ConcurrentModificationException} may occur.
+ * <p>These requirements significantly reduce the scope of potential interference
+ * between mutations of the stream source and execution of stream pipelines.
+ * Streams based on spliterators with the desired characteristics, or those using
+ * the Supplier-based factory forms, are immune to modifications of the data
+ * source prior to commencement of the terminal operation (provided the behavioral
+ * parameters to the stream operations meet the required criteria for non-interference
+ * and statelessness).  See <a href="package-summary.html#Non-Interference">Non-Interference</a>
+ * for more details.
  *
- * <p>For example, consider the following code:
- * <pre>{@code
- *     List<String> l = new ArrayList(Arrays.asList("one", "two"));
- *     Stream<String> sl = l.stream();
- *     l.add("three");
- *     String s = sl.collect(joining(" "));
- * }</pre>
- * First a list is created consisting of two strings: "one"; and "two". Then a stream is created from that list.
- * Next the list is modified by adding a third string: "three".  Finally the elements of the stream are collected
- * and joined together.  Since the list was modified before the terminal {@code collect} operation commenced
- * the result will be a string of "one two three". However, if the list is modified after the terminal operation
- * commences, as in:
- * <pre>{@code
- *     List<String> l = new ArrayList(Arrays.asList("one", "two"));
- *     Stream<String> sl = l.stream();
- *     String s = sl.peek(s -> l.add("BAD LAMBDA")).collect(joining(" "));
- * }</pre>
- * then a {@code ConcurrentModificationException} will be thrown since the {@code peek} operation will attempt
- * to add the string "BAD LAMBDA" to the list after the terminal operation has commenced.
+ * @since 1.8
  */
+package java.util.stream;
 
-package java.util.stream;
+import java.util.function.BinaryOperator;
\ No newline at end of file
--- a/src/share/lib/security/java.security-linux	Tue Aug 13 10:42:37 2013 -0700
+++ b/src/share/lib/security/java.security-linux	Wed Aug 14 15:53:13 2013 -0700
@@ -197,14 +197,12 @@
                com.sun.org.apache.xalan.internal.xsltc.trax.,\
                com.sun.org.apache.xalan.internal.xsltc.util.,\
                com.sun.org.apache.xml.internal.res.,\
-               com.sun.org.apache.xml.internal.security.,\
                com.sun.org.apache.xml.internal.serializer.utils.,\
                com.sun.org.apache.xml.internal.utils.,\
                com.sun.org.glassfish.,\
                com.oracle.xmlns.internal.,\
                com.oracle.webservices.internal.,\
 	       oracle.jrockit.jfr.,\
-               org.jcp.xml.dsig.internal.,\
                jdk.internal.,\
                jdk.nashorn.internal.,\
                jdk.nashorn.tools.
@@ -241,14 +239,12 @@
                    com.sun.org.apache.xalan.internal.xsltc.trax.,\
                    com.sun.org.apache.xalan.internal.xsltc.util.,\
                    com.sun.org.apache.xml.internal.res.,\
-                   com.sun.org.apache.xml.internal.security.,\
                    com.sun.org.apache.xml.internal.serializer.utils.,\
                    com.sun.org.apache.xml.internal.utils.,\
                    com.sun.org.glassfish.,\
                    com.oracle.xmlns.internal.,\
                    com.oracle.webservices.internal.,\
 		   oracle.jrockit.jfr.,\
-                   org.jcp.xml.dsig.internal.,\
                    jdk.internal.,\
                    jdk.nashorn.internal.,\
                    jdk.nashorn.tools.
--- a/src/share/native/common/check_code.c	Tue Aug 13 10:42:37 2013 -0700
+++ b/src/share/native/common/check_code.c	Wed Aug 14 15:53:13 2013 -0700
@@ -1301,7 +1301,10 @@
                    && clazz_info != context->currentclass_info
                    && clazz_info != context->superclass_info) {
                 int not_found = 1;
-
+                jclass cb = object_fullinfo_to_classclass(context, clazz_info);
+                int is_interface = cb && JVM_IsInterface(env, cb);
+
+                if (!is_interface) {
                 jclass super = (*env)->GetSuperclass(env, context->class);
                 while(super != 0) {
                     jclass tmp_cb;
@@ -1329,6 +1332,7 @@
                 }
             }
         }
+        }
         if (opcode == JVM_OPC_invokeinterface) {
             unsigned int args1;
             unsigned int args2;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test-ng/README	Wed Aug 14 15:53:13 2013 -0700
@@ -0,0 +1,20 @@
+Running the TestNG based unit tests requires downloading the TestNG
+library and placing its jar file into the lib subdirectory:
+
+   # download and install TestNG
+   wget http://testng.org/testng-x.y.z.zip
+   unzip testng-x.y.z.zip
+   mkdir lib
+   cp testng-x.y.z/testng.jar lib
+
+   # run tests
+   ant test
+
+This will fail with a message like
+
+    taskdef class org.testng.TestNGAntTask cannot be found
+
+if the TestNG jar file is not installed properly or if the wrong
+version is present. (Check build.xml to find the version of TestNG
+that is required.)  Only the jar file is necessary. The unzipped
+hierarchy can be removed.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test-ng/agent/Readme	Wed Aug 14 15:53:13 2013 -0700
@@ -0,0 +1,118 @@
+To run this:
+   1.  unzip the bundle to a dir called agent (you should have already done 
+       so, to be reading this)
+   2.  have the latest version of lambda repo built fully and in your PATH
+   3.  you can use the pre-built dist/SerializationInjector.jar if not you
+       can build it with "ant -f agent/make/build.xml dist"
+   4.  before running this modify the conf/agent.props if required, but not
+       necessary.
+   5.  At the time of this writing only test-ng's test-libs are supported.
+
+       make the following changes in the lambda/jdk/test-ng/build.xml
+       for the test-libs target, you might want to bump the heap from 2g
+       to 4g if your choice of platform and the JVM allows.
+
+       <jvmarg value="-javaagent:/YOUR_PATH/agent/dist/SerializationInjectorAgent.jar=/YOUR_PATH/agent/conf/agent.props"/>
+
+       actual patch shown in appendix
+
+   6.  to run simply run the test-ng test as "ant test-libs"
+       Note: make sure are running with the very latest lambda build
+   7.  what you expect to see is in the Appendix.
+       Note: you will see on failure which is a serialization negative test
+
+Details:
+Directory structure:
+    src   - containing the sources
+    build - intermediate classes
+    dist  - jar used as an agent
+    make  - build.xml and an nbproject, feel free to modify it
+            requires jdk8 with asm that recognizes v52.0 classfiles
+    conf  - config files
+
+Description of sources:
+    Agent.java: installs an agent.
+    SerializationInjector: does the following
+       * parses properties and initializes the output
+       * initialize and install the VM shutdown hook, to print the test
+         statistics.
+       * using asm interrogates the target class, upon encountering an
+         indy, will save the params, invokes the indy, and restores the
+         original args to the indy 
+       * invoke the indy
+       * invoke the SerializeAndDeserializeTest (SAND).
+         with the lambdaObject returned by the indy and the
+         non-primitive parameters and these will be passed to SAND.
+	     Primitives are excluded
+     TestLambdaSerialization:
+       * the SAND will check the arguments if they are Serializable, if so,
+         then the LamdbaObject will be Serialized and Deserialized, and the 
+         deserialized LambdaObject will be returned, otherwise the original
+         LambdaObject will be returned,  the outcome and exception if any 
+         will be recorded.
+         
+         The final report will be printed out when the JVM terminates.
+     
+Running the agent:
+java -jar path_to/jtreg.jar \
+     -javaoption:"-javaagent:path_to/agent/dist/SerializationInjectorAgent.jar=/w/ksrini/Lambda/agent.props" \
+     test/foo/Lambda2.java
+
+agent.props is a property file by which one can specify
+   * a regular expression to exclude classes
+   * specify an output file to log details
+   * specifiy debugging if required
+
+ex:
+com.oracle.lambda.exclude.files=^java.*|^sun.misc.*|^javax.*
+com.oracle.lambda.log.file=some_path/agent.log
+com.oracle.lambda.debug=true
+
+A note about logfiles, the agent is installed into jtreg, however jtreg
+may invoke a test in a different VM as specified by the test and/or command
+line. 
+
+Thus if a file exists the agent will create a unique file in the specified 
+directory. Therefore it is recommended that the desired output directory is
+clean before starting a new test.
+
+
+Appendix:
+
+1. Patch to install the agent into test-ng
+diff --git a/test-ng/build.xml b/test-ng/build.xml
+--- a/test-ng/build.xml
++++ b/test-ng/build.xml
+@@ -55,6 +56,7 @@
+             <jvmarg value="-esa" />
+             <jvmarg value="-Xverify:all" />
+             <jvmarg value="-Xmx2g" />
++            <jvmarg value="-javaagent:/YOUR_PATH/agent/dist/SerializationInjectorAgent.jar=/YOUR_PATH/agent/conf/agent.props"/>
+         </testng>
+     </target>
+
+
+2. sample log
+[testng] [TestNG] Running:
+   [testng]   Ant suite
+   [testng]
+   [testng]
+   [testng] ===============================================
+   [testng] Ant suite
+   [testng] Total tests run: 7338, Failures: 1, Skips: 0
+   [testng] ===============================================
+   [testng]
+   [testng] Lambda Serialization Test Status:
+   [testng]   success: 2432727
+   [testng]   failed : 1099035
+   [testng] Non Serializable Class(es):
+   [testng]   NonSerializableObject: java.util.stream.op.Nodes$ArrayNode [92]
+   [testng] Throwable:
+   [testng]   null
+   [testng]
+   [testng]   NonSerializableObject: java.util.stream.op.Nodes$ConcNode [71]
+   [testng] Throwable:
+   [testng]   null
+   [testng]
+   [testng]   NonSerializableObject: org.openjdk.tests.java.util.stream.op.Group
+........
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test-ng/agent/conf/agent.props	Wed Aug 14 15:53:13 2013 -0700
@@ -0,0 +1,6 @@
+#com.oracle.lambda.exclude.files=java..*|sun.*|javax.*|org.testng.*|com.google.*|com.sun.tools.javac.*|.*javatest.*|com.sun.tools.classfile.*|com.beust.*|.*TTShape.*|.*TestHarness.*
+#com.oracle.lambda.log.file=/tmp/agent_log/agent.log
+#com.oracle.lambda.debug=true
+#com.oracle.lambda.serialize.file=$CUSTOM/serialize.list
+com.oracle.lambda.storeStackTraces=true
+#com.oracle.lambda.deserialization.workaround=true
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test-ng/agent/conf/serialize.list	Wed Aug 14 15:53:13 2013 -0700
@@ -0,0 +1,59 @@
+java/lang/invoke/MagicLambdaImpl
+java/util/Optional
+java/util/OptionalDouble
+java/util/OptionalLong
+java/util/OptionalInt
+java/util/Spliterator
+java/util/ArrayList\$SubList
+java/util/SubList
+java/util/RandomAccessSubList
+java/util/HashMap\$.*Spliterator
+java/util/TreeMap\$.*Spliterator
+java/util/function/Function\$\$Lambda.*
+java/util/function/Functions\$\$Lambda.*
+java/util/stream/Collectors.*
+java/util/stream/LambdaTestHelpers\$\$Lambda.*
+java/util/stream/Nodes.*NodeBuilder
+java/util/stream/Nodes\$.*Node
+java/util/stream/AbstractSpinedBuffer
+java/util/stream/SpinedBuffer
+java/util/stream/.*Pipeline
+java/util/stream/AbstractPipeline\$.*
+java/util/stream/IntermediateOp
+java/util/stream/.*StreamTestData\$.*
+java/util/stream/.*NodeTest
+java/util/stream/TestData\$AbstractTestData.*
+org/openjdk/tests/java/util/stream/OpTestCase\$TestData
+org/openjdk/tests/java/util/stream/OpTestCase\$ExerciseDataStreamBuilder
+org/openjdk/tests/java/util/stream/OpTestCase\$ExerciseDataTerminalBuilder
+org/openjdk/tests/java/util/stream/IntNodeTest
+org/openjdk/tests/java/util/stream/UnorderedStreamTest
+org/openjdk/tests/java/util/stream/GroupByOpTest
+org/openjdk/tests/java/util/stream/TabulatorsTest
+org/openjdk/tests/java/util/stream/TabulatorsTest\$.*Assertion
+org/openjdk/tests/java/util/stream/StreamLinkTest
+org.openjdk.tests.java.util.stream.SpliteratorLateBindingFailFastTest\$SpliteratorDataBuilder.*
+org.openjdk.tests.java.util.stream.SpliteratorTraversingAndSplittingTest\$SpliteratorDataBuilder.*
+org.openjdk.tests.java.util.stream.SliceOpTest.*
+org.openjdk.tests.java.util.stream.MatchOpTest.*
+org.openjdk.tests.java.util.stream.InfiniteStreamWithLimitOpTest.*
+java.util.HashMap\$Values
+java.util.LinkedHashMap\$KeyIterator
+java.util.HashMap\$Entry
+java.util.LinkedList\$Node
+java.util.TreeMap\$Entry
+java.util.HashMap\$EntrySet
+java.util.HashMap\$KeySet 
+java.util.IdentityHashMap\$KeySet
+java.util.LinkedHashMap\$ValueIterator
+java.util.TreeMap\$KeySet
+java.util.TreeMap\$EntrySet
+java.util.TreeMap\$Values
+java.util.WeakHashMap
+java.util.WeakHashMap\$EntrySet
+java.util.WeakHashMap\$KeySet
+java.util.WeakHashMap\$Values
+java.util.LinkedHashMap\$EntryIterator
+java.util.IdentityHashMap\$EntrySet
+java.util.IdentityHashMap\$Values
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test-ng/agent/make/build.xml	Wed Aug 14 15:53:13 2013 -0700
@@ -0,0 +1,75 @@
+<project name="SerializationInjectorAgent" default="dist" basedir="..">
+  <!-- Requires ant 1.6.1+ and Lambda (NOT TL)+-->
+
+  <!-- set global properties for this build -->
+  <property name="build.sysclasspath" value="ignore"/>
+  <property name="build.dir" value="../../../build/test-ng/agent" />
+  <property name="src"      value="${basedir}/src"/>
+  <property name="make"     value="${basedir}/make"/>
+  <property name="conf"     value="${basedir}/conf"/>
+  <property name="classes"  value="${build.dir}/classes"/>
+  <property name="dist"     value="${build.dir}/dist"/>
+
+  <target name="init">
+    <!-- Create the time stamp -->
+    <tstamp/>
+    <!-- Create the build directory structure used by compile -->
+    <mkdir dir="${build.dir}"/>
+    <mkdir dir="${dist}"/>
+    <mkdir dir="${classes}"/>
+    <echo message="${java.home}"/>
+  </target>
+
+  <target name="compile" depends="init">
+    <!-- Compile the java code from ${src} into ${build} -->
+    <javac 
+	source="1.7"
+	srcdir="${src}"
+	destdir="${build.dir}/classes"
+	verbose="no"
+	debug="on"
+    >
+    <compilerarg value="-XDignore.symbol.file=true"/>
+    </javac>
+  </target>
+  <target name="dist" depends="compile">
+    <!-- Put everything in jar file -->
+    <jar destfile="${dist}/SerializationInjectorAgent.jar">
+	<manifest>
+	   <attribute name="Main-Class" value="com.oracle.lambda.Main"/>
+           <attribute name="PreMain-Class" value="com.oracle.lambda.Agent"/>
+	</manifest>
+	<fileset dir="${classes}"/>
+    </jar>
+  </target>
+  <target name="run" depends="dist">
+    <condition property="run.arg" value="-o /tmp/ksrini/XX.jar -f /w/ksrini/JDK/hg-lambda/jdk8/jdk/test-ng/serialize.list /tmp/ksrini/rt.jar">
+        <not>
+            <isset property="run.arg"/>
+        </not> 
+    </condition>
+    <java jar="${dist}/SerializationInjectorAgent.jar"
+        dir="."
+        fork="true"  
+    >
+   <jvmarg value="-Dcom.oracle.lambda.debug=true"/>
+   <arg value="${run.arg}"/>
+    </java>
+  </target>
+  <target name="clean">
+    <!-- Delete the ${build} and ${dist} directory trees -->
+    <delete dir="${build}"/>
+    <delete dir="${dist}"/>
+  </target>
+  <target name="bundle" depends="clean, dist">
+      <zip destfile="${dist}/bundle.zip">
+          <zipfileset dir="${src}"/>
+          <zipfileset file="${dist}/SerializationInjectorAgent.jar"/>
+          <zipfileset dir="${make}" excludes="**/netbeans/**"/>
+          <zipfileset dir="${conf}"/>
+          <zipfileset file="Readme"/>
+      </zip>
+      
+  </target>
+
+</project>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test-ng/agent/src/com/oracle/lambda/Agent.java	Wed Aug 14 15:53:13 2013 -0700
@@ -0,0 +1,71 @@
+/*
+ * 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.
+ */
+package com.oracle.lambda;
+
+import java.io.IOException;
+import java.lang.instrument.ClassFileTransformer;
+import java.lang.instrument.IllegalClassFormatException;
+import java.lang.instrument.Instrumentation;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.security.ProtectionDomain;
+import java.util.EnumSet;
+import java.util.HashSet;
+import java.util.TreeSet;
+
+public class Agent {
+    public static void premain(String agentArgs, Instrumentation instrumentation)
+            throws IOException, NoSuchFieldException, IllegalAccessException {
+        // If run without a config file, all we do is set up the shutdown hook
+        if (agentArgs != null) {
+            final SerializationInjector si = new SerializationInjector();
+            instrumentation.addTransformer(new ClassFileTransformer() {
+                @Override
+                public byte[] transform(final ClassLoader cl, String string,
+                                        Class<?> type, ProtectionDomain pd,
+                                        byte[] bytes) throws IllegalClassFormatException {
+                    return si.transformClass(cl, bytes, EnumSet.noneOf(SerializationInjector.Options.class));
+                }
+            });
+        }
+        else {
+            // Horrible horrible hack.
+            // TreeSet/HashSet are based off of HashSet/HashMap, and serializing their spliterators
+            // tries to serialize the underlying map, which uses a non-serializable sentinel object.
+            // This hack swaps that out for a serializable sentinel
+            Field f = HashSet.class.getDeclaredField("PRESENT");
+            f.setAccessible(true);
+            Field modifiersField = Field.class.getDeclaredField("modifiers");
+            modifiersField.setAccessible(true);
+            modifiersField.setInt(f, f.getModifiers() & ~Modifier.FINAL);
+            f.set(null, Boolean.TRUE);
+
+            f = TreeSet.class.getDeclaredField("PRESENT");
+            f.setAccessible(true);
+            modifiersField.setInt(f, f.getModifiers() & ~Modifier.FINAL);
+            f.set(null, Boolean.TRUE);
+
+            TestLambdaSerialization.initializeShutDownHook();
+        }
+    }
+ }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test-ng/agent/src/com/oracle/lambda/Main.java	Wed Aug 14 15:53:13 2013 -0700
@@ -0,0 +1,196 @@
+/*
+ * 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.
+ */
+package com.oracle.lambda;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URI;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.nio.file.DirectoryStream;
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystems;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.attribute.FileAttribute;
+import java.nio.file.attribute.PosixFilePermission;
+import java.nio.file.attribute.PosixFilePermissions;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.regex.Pattern;
+
+import jdk.internal.org.objectweb.asm.ClassReader;
+import static java.nio.file.StandardOpenOption.*;
+import static java.nio.file.StandardCopyOption.*;
+
+/**
+ *
+ * @author kumasrin
+ */
+public class Main {
+
+    static void usage() {
+        System.out.println("usage: -o output_dir path_to/SomeClass.class");
+        System.out.println("usage: -o output_dir path_to_classes");
+        System.out.println("usage: -o output_dir -s path_to_jar");
+        System.exit(1);
+    }
+
+    /*
+     * a standalone tester for this
+     */
+    public static void main(String... inargs) throws Exception {
+        String[] args = inargs;
+        if (inargs != null && inargs.length == 1) {
+            args = inargs[0].split("\\s");
+        }
+        if (args == null || args.length < 3) {
+            usage();
+        }
+        File outDir = null;
+        File inFile = null;
+        boolean serializeOnly = false;
+        for (int i = 0 ; i < args.length ; i++) {
+            switch (args[i]) {
+                case "-o":
+                    i++;
+                    outDir = new File(args[i]);
+                    break;
+                case "-s":
+                    serializeOnly = true;
+                    break;
+                default:
+                    inFile = new File(args[i]);
+            }
+        }
+        if (inFile.isDirectory()) {
+            if (outDir.exists()) {
+                outDir.mkdirs();
+            }
+            URL[] urls = {inFile.toURI().toURL()};
+            ClassLoader cl = new URLClassLoader(urls, ClassLoader.getSystemClassLoader());
+            try (DirectoryStream<Path> paths =
+                    Files.newDirectoryStream(inFile.toPath(), "*")) {
+                for (Path p : paths) {
+                    doFile(inFile, outDir, p.toFile(), cl);
+                }
+            }
+        } else if (inFile.getName().endsWith(".jar")) {
+            if (outDir.exists()) {
+                outDir.mkdirs();
+            }
+            URL[] urls = {inFile.toURI().toURL()};
+            ClassLoader cl = new URLClassLoader(urls, ClassLoader.getSystemClassLoader());
+            Pattern pattern = Pattern.compile(".*");
+            EnumSet<SerializationInjector.Options> options
+                    = serializeOnly ? EnumSet.of(SerializationInjector.Options.SERIALIZE_ONLY) : EnumSet.noneOf(SerializationInjector.Options.class);
+            doJar(inFile, outDir, cl, pattern, options);
+        } else {
+            outDir.mkdirs();
+            URL[] urls = {inFile.getParentFile().toURI().toURL()};
+            ClassLoader cl = new URLClassLoader(urls, ClassLoader.getSystemClassLoader());
+            doFile(null, outDir, inFile, cl);
+        }
+    }
+    static void copyStream(InputStream in, OutputStream out) throws IOException {
+        byte[] buf = new byte[8192];
+        int n = in.read(buf);
+        while (n > 0) {
+            out.write(buf, 0, n);
+            n = in.read(buf);
+        }
+    }
+
+    static byte[] readFully(InputStream is) throws IOException {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        copyStream(is, baos);
+        return baos.toByteArray();
+    }
+
+    static void doJar(File inFile, File outDir, ClassLoader cl, Pattern pattern,
+                      EnumSet<SerializationInjector.Options> options) throws IOException {
+        JarFile jf = new JarFile(inFile);
+        byte[] buffer;
+        SerializationInjector si = new SerializationInjector();
+        FileSystem fs = null;
+        boolean jarOut = outDir.getName().endsWith(".jar");
+        Set<PosixFilePermission> perms = PosixFilePermissions.fromString("rwxrwxrwx");
+        FileAttribute<Set<PosixFilePermission>> attr =
+                PosixFilePermissions.asFileAttribute(perms);
+        Map<String, String> env = new HashMap<>();
+        env.put("create", "true");
+        if (jarOut) {
+            URI uri = URI.create("jar:file:" + outDir.getAbsolutePath());
+            if (outDir.exists())
+                outDir.delete();
+            fs = FileSystems.newFileSystem(uri, env);
+        } else {
+            fs = FileSystems.getDefault();
+        }
+        for (JarEntry je : Collections.list(jf.entries())) {
+            String fname = je.getName();
+            if (fname.endsWith("/")) continue;
+            if (pattern.matcher(fname).matches()) {
+                buffer = readFully(jf.getInputStream(je));
+                if (fname.endsWith(".class"))
+                    buffer = si.transformClass(cl, buffer, options);
+                Path opath = jarOut ? fs.getPath(fname) : fs.getPath(outDir.getAbsolutePath(), fname);
+                Files.createDirectories(opath.getParent(), attr);
+                Files.write(opath, buffer, CREATE, TRUNCATE_EXISTING);
+            }
+        }
+        if (jarOut)
+            fs.close();
+    }
+
+    static String getRelativePath(File baseDir, File inFile) {
+        String bname = baseDir.getAbsolutePath();
+        String fname = inFile.getAbsolutePath();
+        return fname.substring(bname.length() + 1);
+    }
+
+    static void doFile(File inDir, File outDir, File iFile, ClassLoader cl) throws Exception {
+        if (!iFile.getName().endsWith(".class")) {
+            Path p = new File(getRelativePath(inDir, iFile)).toPath();
+            Files.copy(iFile.toPath(), p, COPY_ATTRIBUTES, REPLACE_EXISTING);
+            return;
+        }
+        byte[] classBuffer = Files.readAllBytes(iFile.toPath());
+        ClassReader cr = new ClassReader(classBuffer);
+        File oFile = new File(outDir, cr.getClassName() + ".class");
+        SerializationInjector si = new SerializationInjector();
+        System.err.print("Transforming: " + iFile.getAbsolutePath());
+        System.err.println(" to: " + oFile.getAbsolutePath());
+        oFile.getParentFile().mkdirs();
+        Files.write(oFile.toPath(),
+                si.transformClass(cl, classBuffer, EnumSet.noneOf(SerializationInjector.Options.class)), CREATE, TRUNCATE_EXISTING);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test-ng/agent/src/com/oracle/lambda/SerializationInjector.java	Wed Aug 14 15:53:13 2013 -0700
@@ -0,0 +1,399 @@
+/*
+ * 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.
+ */
+package com.oracle.lambda;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import java.util.regex.Pattern;
+
+import jdk.internal.org.objectweb.asm.ClassReader;
+import jdk.internal.org.objectweb.asm.ClassVisitor;
+import jdk.internal.org.objectweb.asm.ClassWriter;
+import jdk.internal.org.objectweb.asm.Handle;
+import jdk.internal.org.objectweb.asm.MethodVisitor;
+import static jdk.internal.org.objectweb.asm.Opcodes.*;
+import jdk.internal.org.objectweb.asm.Type;
+
+import static java.nio.file.StandardOpenOption.*;
+
+
+public class SerializationInjector {
+    static final String PREFIX = "com.oracle.lambda";
+    static final String INCLUDES = "java.util.*|org.openjdk.tests.java.*"; // also should include java.util...
+    static final String SERIALIZE = "";
+
+    // properties that can be set
+    static final String INCLUDE_FILES  = PREFIX + ".include.files";
+    static final String SERIALIZE_FILE = PREFIX + ".serialize.file";
+    static final String STORE_FRAMES   = PREFIX + ".store.frames";
+    static final String LOGFILE        = PREFIX + ".log.file";
+    static final String DEBUG          = PREFIX + ".debug";
+    static final String NROUNDS        = PREFIX + ".nrounds";
+
+    static boolean storeFrames = true;
+    static boolean deserializationWorkaround;
+
+    final DebugPrint debug;
+    final Pattern includePattern;
+    final Pattern serializePattern;
+    final boolean serializeOnly;
+
+    public enum Options { SERIALIZE_ONLY, FORCE_SERIALIZE }
+
+    public SerializationInjector() throws IOException {
+        includePattern   = propToPattern(INCLUDE_FILES, INCLUDES);
+        serializePattern = fileToPattern(SERIALIZE_FILE, SERIALIZE);
+        debug = new DebugPrint();
+        TestLambdaSerialization.initializeShutDownHook();
+        storeFrames = Boolean.getBoolean(STORE_FRAMES);
+        deserializationWorkaround = false;
+        serializeOnly = false;
+    }
+    final Pattern propToPattern(String propKey, String defValue) {
+        return Pattern.compile(System.getProperty(propKey, defValue));
+    }
+    final Pattern fileToPattern(String propKey, String defValue) throws IOException {
+        String fname = System.getProperty(propKey, null);
+        if (fname != null) {
+            File pFile = new File(fname);
+            if (pFile.canRead()) {
+                return fileToPattern(pFile);
+            }
+        }
+        return Pattern.compile(defValue);
+    }
+    final Pattern fileToPattern(File inFile) throws IOException {
+        List<String> serList = Files.readAllLines(inFile.toPath(),
+                Charset.defaultCharset());
+        String regStr = "";
+        boolean first = true;
+        for (String s : serList) {
+            String x = s.trim();
+            if (x.startsWith("#")) {
+                continue;
+            }
+            regStr = regStr.concat((first ? "" : "|") + x);
+            first = false;
+        }
+        System.out.println("serialization: " + regStr);
+        return Pattern.compile(regStr);
+    }
+
+    byte[] transformClass(ClassLoader cl, byte[] classBuffer, EnumSet<Options> options) {
+        byte[] xBuffer = classBuffer;
+        ClassReader classReader = new ClassReader(xBuffer);
+        String cname = classReader.getClassName();
+
+        if (options.contains(Options.FORCE_SERIALIZE) || serializePattern.matcher(cname).matches()) {
+            debug.println("Implementing Serialization: " + cname);
+            xBuffer = injectSerialization(xBuffer, cl);
+        }
+        if (serializeOnly || options.contains(Options.SERIALIZE_ONLY)) {
+            return xBuffer;
+        }
+        if (!includePattern.matcher(cname).matches()) {
+            debug.println("Excluding SAND: " + cname);
+            return xBuffer;
+        }
+        debug.println("Visiting: " + cname);
+        return injectSAND(xBuffer, cl);
+    }
+
+    byte[] injectSAND(byte[] classBuffer, ClassLoader cl) {
+        Map<String, Integer> locals = getLocals(classBuffer);
+        ClassReader classReader = new ClassReader(classBuffer);
+        ClassWriter classWriter = new ClassWriter(classReader,
+                ClassWriter.COMPUTE_MAXS /*| ClassWriter.COMPUTE_FRAMES*/);
+        classReader.accept(makeSANDVisitor(classWriter, locals), 0);
+        byte[] byteArray = classWriter.toByteArray();
+//        CheckClassAdapter.verify(new ClassReader(byteArray), cl, false,
+//                                 new PrintWriter(System.err));
+        return byteArray;
+    }
+
+    Map<String, Integer> getLocals(byte[] classBuffer) {
+        ClassReader cr = new ClassReader(classBuffer);
+        final Map<String, Integer> locals = new HashMap<>();
+        cr.accept(new ClassVisitor(ASM4, null) {
+            String cname;
+            @Override
+            public void visit(int version, int access, String name,
+                    String signature, String superName,
+                    String[] interfaces) {
+                cname = name;
+                super.visit(version, access, name, signature, superName, interfaces);
+            }
+            @Override
+            public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
+                final String mid = cname + "+" + name + "+" + desc + "+" + signature;
+                return new MethodVisitor(ASM4,
+                        super.visitMethod(access, name, desc, signature, exceptions)) {
+                    @Override
+                    public void visitMaxs(int maxStack, int maxLocals) {
+                        super.visitEnd();
+                        super.visitMaxs(maxStack, maxLocals);
+                        //debug.println("Pre-Visiting:" + mid + ", stack=" + maxLocals);
+                        locals.put(mid, maxLocals);
+                    }
+                };
+            }
+        }, 0);
+
+        return locals;
+    }
+
+    ClassVisitor makeSANDVisitor(ClassWriter cw, final Map<String, Integer>methodLocals) {
+        return new ClassVisitor(ASM4, cw) {
+            String cname = null;
+            @Override
+            public void visit(int version, int access, String name,
+                              String signature, String superName,
+                              String[] interfaces) {
+                cname = name;
+                super.visit(version, access, name, signature, superName, interfaces);
+            }
+            @Override
+            public MethodVisitor visitMethod(int access, final String name,
+                                             final String desc, final String signature,
+                                             String[] exceptions) {
+                if (name.equals("$deserializeLambda$")) {
+                    return super.visitMethod(access, name, desc, signature, exceptions);
+                }
+                return new MethodVisitor(ASM4,
+                        super.visitMethod(access, name, desc, signature, exceptions)) {
+                    final String mid = cname + "+" + name + "+" + desc + "+" + signature;
+                    int locals = methodLocals.containsKey(mid) ? methodLocals.get(mid) : 0;
+
+                    int saveArgs(Type[] types) {
+                        final int n = locals + 1;
+                        final int tlen = types.length;
+                        int count = 0;
+                        // store in LIFO order
+                        for (int i = 0; i < tlen; i++) {
+                            int pos = tlen - 1 - i;
+                            super.visitVarInsn(types[pos].getOpcode(ISTORE), n + pos);
+                        }
+                        // restore back in  FIFO order
+                        for (int i = 0 ; i < tlen; i++) {
+                            if (isNotPrimitive(types[i])) {
+                                count++;
+                            }
+                            super.visitVarInsn(types[i].getOpcode(ILOAD), n + i);
+                        }
+                        return count;
+                    }
+                    boolean isNotPrimitive(Type t) {
+                        int i = t.getSort();
+                        return i == Type.OBJECT || i == Type.ARRAY;
+                    }
+                    void restoreArgs(Type[] types, int count) {
+                        final int n = locals + 1;
+                        final int tlen = types.length;
+                        // create the array
+                        visitIntInsn(BIPUSH, count);
+                        visitTypeInsn(ANEWARRAY, "java/lang/Object");
+                        int ncount = 0;
+                        for (int i = 0 ; i < tlen ; i++ ) {
+                            Type t = types[i];
+                            if (isNotPrimitive(t)) {
+                                debug.println("injecting:" + t);
+                                super.visitInsn(DUP);
+                                super.visitIntInsn(BIPUSH, ncount);
+                                super.visitVarInsn(t.getOpcode(ILOAD), n + i);
+                                super.visitInsn(AASTORE);
+                                ncount++;
+                            }
+                        }
+                    }
+                    @Override
+                    public void visitInvokeDynamicInsn(String callsite,
+                            String sig, Handle handle, Object... bsmArgs) {
+                        // instrument  only! lambda objects
+                        final boolean needsTransform = handle.getName().equals("metafactory");
+                        final boolean injectSand = needsTransform ||
+                                handle.getName().equals("altMetafactory");
+                        if (!injectSand) {
+                            super.visitInvokeDynamicInsn(callsite, sig, handle, bsmArgs);
+                            return;
+                        }
+                        debug.println("indy:" + mid + ", locals = " + locals);
+                        debug.println("  fixing: " + callsite + ":" + sig);
+                        Handle nHandle = handle;
+                        Object[] nbsmArgs = bsmArgs;
+                        if (needsTransform) {
+                            String ndesc = "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;";
+                            nHandle =  new Handle(handle.getTag(), handle.getOwner(),
+                                    "altMetafactory", ndesc);
+
+                            ArrayList<Object> largs = new ArrayList<>(Arrays.asList(bsmArgs));
+                            largs.add(1);
+                            largs.add(Type.getType(java.io.Serializable.class));
+                            nbsmArgs = new Object[largs.size()];
+                            largs.toArray(nbsmArgs);
+                            debug.println("old: " + handle.toString());
+                            debug.println("new: " + nHandle.toString());
+                        }
+                        Type[] types = Type.getArgumentTypes(sig);
+                        int count = saveArgs(types);
+                        super.visitInvokeDynamicInsn(callsite, sig, nHandle, nbsmArgs);
+                        restoreArgs(types, count);
+                        super.visitMethodInsn(INVOKESTATIC,
+                                              "com/oracle/lambda/TestLambdaSerialization",
+                                              (needsTransform && deserializationWorkaround)
+                                                    ? "serializeOnly"
+                                                    : "serializeAndDeserialize",
+                                              "(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;");
+                    }
+                };
+            }
+        };
+    }
+
+    void dumpClass(byte[] array, String prefix) {
+        try {
+            Path f = Files.createTempFile(new File("/tmp").toPath(),
+                                          prefix, ".class");
+            System.out.println("dumping to:" + f.toString());
+            Files.write(f, array, CREATE, TRUNCATE_EXISTING);
+        } catch (IOException ex) {
+            Logger.getLogger(SerializationInjector.class.getName()).log(Level.SEVERE, null, ex);
+        }
+    }
+
+    private byte[] injectSerialization(byte[] classBuffer, ClassLoader cl) {
+        ClassReader classReader = new ClassReader(classBuffer);
+        ClassWriter classWriter = new ClassWriter(classReader,
+                ClassWriter.COMPUTE_MAXS /*| ClassWriter.COMPUTE_FRAMES*/);
+        boolean hasNoArgCtor = hasNoArgCtor(classBuffer);
+        classReader.accept(makeSerializationVisitor(classWriter, !hasNoArgCtor), 0);
+        byte[] byteArray = classWriter.toByteArray();
+        // Needed to comment this out because some classes are actually loaded during this verification
+        // and they fail the package name test (java.*)
+//        CheckClassAdapter.verify(new ClassReader(byteArray), cl, false,
+//                new PrintWriter(System.err));
+
+//        dumpClass(classBuffer, "pre-serialization");
+//        dumpClass(byteArray, "post-serialization");
+        return byteArray;
+    }
+
+    private boolean hasNoArgCtor(byte[] buffer) {
+        final AtomicBoolean foundNoArg = new AtomicBoolean();
+        new ClassReader(buffer).accept(new ClassVisitor(ASM4, null) {
+            @Override
+            public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
+                if (name.equals("<init>") && desc.equals("()V"))
+                    foundNoArg.set(true);
+                return super.visitMethod(access, name, desc, signature, exceptions);
+            }
+        }, 0);
+        return foundNoArg.get();
+    }
+
+    ClassVisitor makeSerializationVisitor(final ClassWriter cw, final boolean injectNoArg) {
+        return new ClassVisitor(ASM4, cw) {
+            @Override
+            public void visit(int version, int access, String name,
+                              String signature, String superName,
+                              String[] interfaces) {
+                String sername = java.io.Serializable.class.getName().replace('.', '/');
+                boolean foundSer = false;
+                for (String x : interfaces) {
+                    foundSer = foundSer || x.contains(sername);
+                }
+                if (!foundSer) {
+                    debug.println("Injecting serialization: " + name);
+                    int n = interfaces.length;
+                    interfaces = Arrays.copyOf(interfaces, n + 1);
+                    interfaces[n] = sername;
+                    if (signature != null)
+                        signature += "L" + sername + ";";
+                }
+                super.visit(version, access, name, signature, superName, interfaces);
+                if (injectNoArg && (access & ACC_INTERFACE) == 0) {
+                    debug.println("Injecting <init>: " + name);
+                    MethodVisitor ctor = visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
+                    ctor.visitCode();
+                    ctor.visitVarInsn(ALOAD, 0);
+                    ctor.visitMethodInsn(INVOKESPECIAL, superName, "<init>", "()V");
+                    ctor.visitInsn(RETURN);
+                    ctor.visitMaxs(-1, -1);
+                    ctor.visitEnd();
+                }
+            }
+        };
+    }
+}
+class DebugPrint {
+    final PrintStream out;
+    final boolean mustPrint;
+    final boolean shouldClose;
+
+    DebugPrint() throws IOException {
+        mustPrint = Boolean.getBoolean(SerializationInjector.DEBUG);
+        String output = System.getProperty(SerializationInjector.LOGFILE, "out");
+        switch (output) {
+            case "out":
+                out = System.out;
+                shouldClose = false;
+                break;
+            case "err":
+                out = System.err;
+                shouldClose = false;
+                break;
+            default:
+                File f = new File(output);
+                if (f.exists()) {
+                    File dir = f.getParentFile();
+                    f = File.createTempFile("agent", ".log", dir);
+                }
+                FileOutputStream fos = new FileOutputStream(f);
+                out = new PrintStream(new BufferedOutputStream(fos));
+                shouldClose = true;
+        }
+    }
+
+    void println(String s) {
+        if (mustPrint)
+            out.println(s);
+    }
+    void print(String s) {
+        if (mustPrint)
+            out.print(s);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test-ng/agent/src/com/oracle/lambda/TestLambdaSerialization.java	Wed Aug 14 15:53:13 2013 -0700
@@ -0,0 +1,253 @@
+/*
+ * 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.
+ */
+package com.oracle.lambda;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class TestLambdaSerialization {
+
+    private static final Map<String, SerializableStatus> nonSerializableClasses =
+            Collections.synchronizedMap(new HashMap<String, SerializableStatus>());
+    private static final Map<String, SerializableStatus> serializableButFailedClasses =
+            Collections.synchronizedMap(new HashMap<String, SerializableStatus>());
+    private static final Map<String, SerializableStatus> deserFailures =
+            Collections.synchronizedMap(new HashMap<String, SerializableStatus>());
+    private static final CounterSet serCounters = new CounterSet();
+    private static final CounterSet deserCounters = new CounterSet();
+    private static final int nRounds =
+            Integer.parseInt(System.getProperty(SerializationInjector.NROUNDS, "1"));
+
+    public static void printStats() {
+        PrintStream rpt = System.out;
+        try {
+            rpt.println("Lambda Serialization Test Status:");
+            rpt.println("  serializations attempted:       " + serCounters.attempted);
+            rpt.println("  serializations succeeded:       " + serCounters.succeeded);
+            rpt.println("  serializations failed:          " + serCounters.failed);
+            rpt.println("  serializations not attempted:   " + serCounters.notAttempted);
+            rpt.println("  deserializations attempted:     " + deserCounters.attempted);
+            rpt.println("  deserializations succeeded:     " + deserCounters.succeeded);
+            rpt.println("  deserializations failed:        " + deserCounters.failed);
+            rpt.println("  deserializations not attempted: " + deserCounters.notAttempted);
+            if (nonSerializableClasses.size() > 0) {
+                rpt.println("Non Serializable Class(es):");
+                for (Entry<String, SerializableStatus> e : nonSerializableClasses.entrySet()) {
+                    rpt.println("  " + e.getValue());
+                }
+            }
+            if (serializableButFailedClasses.size() > 0) {
+                rpt.println("Serializable class(es) but failed serialization:");
+                for (Entry<String, SerializableStatus> e : serializableButFailedClasses.entrySet()) {
+                    rpt.println("  " + e.getValue());
+                }
+            }
+            if (deserFailures.size() > 0) {
+                rpt.println("Failed deserialization:");
+                for (Entry<String, SerializableStatus> e : deserFailures.entrySet()) {
+                    rpt.println("  " + e.getValue());
+                }
+            }
+        } finally {
+            rpt.flush();
+        }
+    }
+
+    public static Object serializeOnly(Object lambdaObj, Object... args) {
+        Object lObj = lambdaObj;
+        for (int i = 0 ; i < nRounds; i++)
+            lObj = serializeAndDeserialize0(true, lObj, args);
+        return lObj;
+    }
+
+    public static Object serializeAndDeserialize(Object lambdaObj, Object... args) {
+        Object lObj = lambdaObj;
+        for (int i = 0; i < nRounds; i++)
+            lObj = serializeAndDeserialize0(false, lObj, args);
+        return lObj;
+    }
+
+    private static Object serializeAndDeserialize0(boolean serializeonly,
+            Object lambdaObj, Object... args) {
+        boolean argsSerializable = true;
+        for (Object a : args) {
+            if (!(a instanceof java.io.Serializable)) {
+                argsSerializable = false;
+                String name = a.getClass().getName();
+                SerializableStatus s = nonSerializableClasses.get(name);
+                if (s == null) {
+                    s = new SerializableStatus("NonSerializableObject", name,
+                            SerializationInjector.storeFrames
+                                ? new Exception(name) : null);
+                    nonSerializableClasses.put(name, s);
+
+                } else {
+                    s.incrementCount();
+                }
+            }
+        }
+
+        byte[] serBytes;
+        if (argsSerializable) {
+            try {
+                serCounters.attempted.incrementAndGet();
+                ByteArrayOutputStream bos = new ByteArrayOutputStream();
+                ObjectOutputStream oos = new ObjectOutputStream(bos);
+                oos.writeObject(lambdaObj);
+                oos.close();
+                serBytes = bos.toByteArray();
+                serCounters.succeeded.incrementAndGet();
+            } catch (java.io.NotSerializableException e) {
+                serCounters.failed.incrementAndGet();
+                String name = e.getMessage();
+                SerializableStatus s = nonSerializableClasses.get(name);
+                if (s == null) {
+                    s = new SerializableStatus("NonSerializableObject", name,
+                                               SerializationInjector.storeFrames ? e : null);
+                    nonSerializableClasses.put(name, s);
+                } else {
+                    s.incrementCount();
+                }
+                return lambdaObj;
+            } catch (RuntimeException | IOException | Error e) {
+                serCounters.failed.incrementAndGet();
+                String cname = lambdaObj.getClass().getName();
+                SerializableStatus s = serializableButFailedClasses.get(cname);
+                if (s == null) {
+                    serializableButFailedClasses.put(cname, new SerializableStatus("LambdaObject",
+                            lambdaObj, SerializationInjector.storeFrames ? e : null));
+                } else {
+                    s.incrementCount();
+                }
+                return lambdaObj;
+            }
+        } else {
+            serCounters.notAttempted.incrementAndGet();
+            return lambdaObj;
+        }
+
+        if (serializeonly) {
+            deserCounters.notAttempted.incrementAndGet();
+            return lambdaObj;
+        }
+
+        deserCounters.attempted.incrementAndGet();
+        try (ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(serBytes))) {
+            Object nlambdaObj = ois.readObject();
+            deserCounters.succeeded.incrementAndGet();
+            return nlambdaObj;
+        } catch (Exception e) {
+            deserCounters.failed.incrementAndGet();
+            String cname = lambdaObj.getClass().getName();
+            SerializableStatus s = deserFailures.get(cname);
+            if (s == null) {
+                deserFailures.put(cname, new SerializableStatus("NonDeserializableObject",
+                        lambdaObj, SerializationInjector.storeFrames ? e : null));
+            } else {
+                s.incrementCount();
+            }
+            return lambdaObj;
+        }
+    }
+
+    /*
+     * a unit tester for this class
+     */
+
+    public static void main(String... args) {
+        String s = "Lambda";
+        Object o = new Object();
+        Object[] array = {
+            "one",
+            "two",
+            "three"
+        };
+        serializeAndDeserialize(s, "Hi", array);
+        serializeAndDeserialize(s, "Bye", array);
+    }
+
+    static AtomicBoolean initialized = new AtomicBoolean();
+    static {
+        initializeShutDownHook();
+    }
+
+    static void initializeShutDownHook() {
+        if (initialized.compareAndSet(false, true)) {
+            Runtime.getRuntime().addShutdownHook(
+                    new Thread() {
+                        @Override
+                        public void run() {
+                            printStats();
+                        }
+                    }
+            );
+        }
+    }
+}
+
+class CounterSet {
+    AtomicInteger notAttempted = new AtomicInteger(0);
+    AtomicInteger attempted = new AtomicInteger(0);
+    AtomicInteger succeeded = new AtomicInteger(0);
+    AtomicInteger failed = new AtomicInteger(0);
+}
+
+class SerializableStatus {
+    String type;
+    Object obj;
+    Throwable exception;
+    AtomicInteger count = new AtomicInteger(1);
+
+    public SerializableStatus(String type, Object obj, Throwable exception) {
+        this.type = type;
+        this.obj = obj;
+        this.exception = exception;
+    }
+
+    public void incrementCount() {
+        count.incrementAndGet();
+    }
+
+    public String toString() {
+        StringWriter sw = new StringWriter();
+        PrintWriter pw = new PrintWriter(sw);
+        pw.printf("%s: %s [ %d ]%n", type, obj, count.get());
+        if (exception != null) {
+            pw.printf("    Throwable: %s", exception);
+            exception.printStackTrace(pw);
+        }
+        return sw.toString();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test-ng/build.xml	Wed Aug 14 15:53:13 2013 -0700
@@ -0,0 +1,289 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+        * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+        * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+        *
+        * This code is free software; you can redistribute it and/or modify it
+        * under the terms of the GNU General Public License version 2 only, as
+        * published by the Free Software Foundation.  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.
+-->
+
+<project name="jdk" default="test">
+
+    <property name="build.dir" value="../../build/test-ng" />
+    <property name="tests.classes.dir" value="${build.dir}/test-classes"/>
+    <property name="mangled.jdk.dir" value="${build.dir}/mangled-jdk"/>
+    <property name="mangled.bootlib.dir" value="${build.dir}/mangled-bootlib"/>
+    <property name="mangled.boottests.dir" value="${build.dir}/mangled-boottests"/>
+    <property name="mangled.tests.dir" value="${build.dir}/mangled-testclasses"/>
+    <property name="boottests.classes.dir" value="${build.dir}/boottest-classes"/>
+    <property name="bootlib.classes.dir" value="${build.dir}/test-bootlib"/>
+    <property name="test.reports.dir" value="${build.dir}/test-reports"/>
+    <property name="lambda.test.dir" value="../test/jdk/lambda" />
+    <property name="spliterator.test.dir" value="../test/java/util/Spliterator" />
+    <property name="tests.src.dir" value="../test/java/util/stream/test"/>
+    <property name="boottests.src.dir" value="../test/java/util/stream/boottest"/>
+    <property name="bootlib.src.dir" value="../test/java/util/stream/bootlib"/>
+    <property name="lib.dir" location="lib" />
+    <property name="test.pattern" value="*" />
+    <property name="lambda.metafactory" value="" />
+    <property name="generated.dir" value="gen-separate"/>
+    <property name="agent.dir"       location="${basedir}/agent"/>
+    <property name="agent.jar"       value="${build.dir}/agent/dist/SerializationInjectorAgent.jar" />
+    <property name="agent.serial.file" value="${agent.dir}/conf/serialize.list" />
+    <property name="agent.rt.jar"    value="${java.home}/lib/rt.jar" />
+    <property name="agent.heap.size" value="-Xmx4g"/>
+    <property name="parallel.mode"    value="classes" />
+    <property name="parallel.suitePool"    value="1" />
+    <property name="parallel.providerPool"    value="1" />
+
+    <property name="lib.testng.jar" value="${lib.dir}/testng.jar"/>
+    <property name="lib.tools.jar" value="${java.home}/../lib/tools.jar"/>
+
+    <path id="compile.class.path">
+        <pathelement location="${bootlib.classes.dir}" />
+        <pathelement location="${tests.classes.dir}" />
+        <pathelement location="${lib.testng.jar}"/>
+        <pathelement location="${lib.tools.jar}"/>
+    </path>
+
+    <path id="test.class.path">
+        <pathelement location="${tests.classes.dir}" />
+        <pathelement location="${lib.testng.jar}"/>
+        <pathelement location="${lib.tools.jar}"/>
+    </path>
+
+    <path id="mangled.class.path">
+        <pathelement location="${mangled.tests.dir}" />
+        <pathelement location="${lib.testng.jar}"/>
+        <pathelement location="${lib.tools.jar}"/>
+    </path>
+
+    <taskdef name="testng" classpathref="test.class.path" classname="org.testng.TestNGAntTask" />
+
+    <target name="prepare">
+        <mkdir dir="${build.dir}"/>
+        <mkdir dir="${mangled.jdk.dir}"/>
+        <mkdir dir="${tests.classes.dir}"/>
+        <mkdir dir="${boottests.classes.dir}"/>
+        <mkdir dir="${bootlib.classes.dir}"/>
+        <mkdir dir="${test.reports.dir}"/>
+    </target>
+
+    <target name="test-compile" depends="prepare">
+        <javac destdir="${bootlib.classes.dir}" debug="on" srcdir="${bootlib.src.dir}" fork="true"
+               classpathref="compile.class.path">
+            <compilerarg value="-Xlint:all"/>
+            <compilerarg value="-XDignore.symbol.file"/>
+        </javac>
+        <javac destdir="${tests.classes.dir}" debug="on" srcdir="${tests.src.dir}:${lambda.test.dir}:${spliterator.test.dir}" fork="true"
+               classpathref="compile.class.path">
+            <compilerarg value="-Xlint:all"/>
+            <compilerarg value="-XDignore.symbol.file"/>
+        </javac>
+        <javac destdir="${boottests.classes.dir}" debug="on" srcdir="${boottests.src.dir}" fork="true"
+               classpathref="compile.class.path">
+            <compilerarg value="-Xlint:all"/>
+            <compilerarg value="-XDignore.symbol.file"/>
+        </javac>
+   </target>
+
+   <target name="test" depends="test-compile" >
+        <echo>Results at: file:${test.reports.dir}/index.html</echo>
+        <testng classpathref="test.class.path" outputdir="${test.reports.dir}"
+                listener="org.testng.reporters.DotTestListener, org.testng.reporters.XMLReporter" useDefaultListeners="false">
+            <classfileset dir="${tests.classes.dir}" includes="**/${test.pattern}.class"/>
+            <classfileset dir="${boottests.classes.dir}" includes="**/${test.pattern}.class"/>
+            <jvmarg value="-Xbootclasspath/p:${boottests.classes.dir}"/>
+            <jvmarg value="-Xbootclasspath/p:${bootlib.classes.dir}"/>
+            <jvmarg value="-Xbootclasspath/p:${lib.testng.jar}"/>
+            <jvmarg value="-ea"/>
+            <jvmarg value="-esa"/>
+            <jvmarg value="-Xverify:all"/>
+            <jvmarg value="-Xmx2g"/>
+            <sysproperty key="org.openjdk.java.util.stream.tripwire" value="true"/>
+        </testng>
+    </target>
+
+    <target name="test-libs" depends="test-compile" >
+        <echo>Results at: file:${test.reports.dir}/index.html</echo>
+        <testng classpathref="test.class.path" outputdir="${test.reports.dir}"
+                listener="org.testng.reporters.XMLReporter" useDefaultListeners="false"
+                parallel="${parallel.mode}" suiteThreadPoolSize="${parallel.suitePool}" dataProviderThreadCount="${parallel.providerPool}">
+            <classfileset dir="${tests.classes.dir}" includes="org/openjdk/tests/java/**/*.class"/>
+            <classfileset dir="${boottests.classes.dir}" includes="java/**/*.class"/>
+            <jvmarg value="-Xbootclasspath/p:${boottests.classes.dir}"/>
+            <jvmarg value="-Xbootclasspath/p:${bootlib.classes.dir}"/>
+            <jvmarg value="-Xbootclasspath/p:${lib.testng.jar}"/>
+            <jvmarg value="-ea" />
+            <jvmarg value="-esa" />
+            <jvmarg value="-Xverify:all" />
+            <jvmarg value="-Xmx2500m" />
+            <sysproperty key="org.openjdk.java.util.stream.tripwire" value="true"/>
+        </testng>
+    </target>
+
+    <target name="test-notlibs" depends="test-compile" >
+        <echo>Results at: file:${test.reports.dir}/index.html</echo>
+        <testng classpathref="test.class.path" outputdir="${test.reports.dir}"
+                listener="org.testng.reporters.XMLReporter" useDefaultListeners="false"
+                parallel="${parallel.mode}" suiteThreadPoolSize="${parallel.suitePool}" dataProviderThreadCount="${parallel.providerPool}" >
+            <classfileset dir="${tests.classes.dir}" excludes="org/openjdk/tests/java/**/*.class"/>
+            <jvmarg value="-Xbootclasspath/p:${boottests.classes.dir}"/>
+            <jvmarg value="-Xbootclasspath/p:${bootlib.classes.dir}"/>
+            <jvmarg value="-Xbootclasspath/p:${lib.testng.jar}"/>
+            <jvmarg value="-ea" />
+            <jvmarg value="-esa" />
+            <jvmarg value="-Xverify:all" />
+            <jvmarg value="-Xmx2500m" />
+            <sysproperty key="org.openjdk.java.util.stream.tripwire" value="true"/>
+        </testng>
+    </target>
+
+    <target name="clean" depends="clean-mangler">
+        <delete includeEmptyDirs="true" failonerror="false">
+            <fileset dir="${build.dir}" />
+            <fileset dir="${generated.dir}" />
+        </delete>
+    </target>
+
+    <!-- mangler related start -->
+    <target name="clean-mangler">
+        <ant antfile="${agent.dir}/make/build.xml" inheritAll="false"
+             target="clean">
+        </ant>
+    </target>
+
+    <target name="build-mangler">
+        <ant antfile="${agent.dir}/make/build.xml" inheritAll="false"
+             target="dist">
+        </ant>
+    </target>
+
+    <target name="mangler-sanity">
+        <condition property="agent.rt.jar.available">
+            <available file="${agent.rt.jar}"/>
+        </condition>
+        <echo message="java.home        : ${java.home}"/>
+        <echo message="agent.rt.jar     : ${agent.rt.jar}"/>
+        <echo message="agent.heap.size  : ${agent.heap.size}"/>
+        <fail message="agent.rt.jar was not found, please set it to a valid rt.jar"
+              unless="agent.rt.jar.available"/>
+    </target>
+
+    <target name="premangle" depends="mangler-sanity, clean, build-mangler, test-compile">
+        <!-- Mangle JDK to mangled.jdk.dir (serialization injection only, no SAND) -->
+        <delete dir="${mangled.jdk.dir}" />
+        <mkdir dir="${mangled.jdk.dir}" />
+        <java jar="${agent.jar}" fork="true" >
+            <jvmarg value="-Dcom.oracle.lambda.serialize.file=${agent.serial.file}"/>
+            <arg value="-s"/>
+            <arg value="-o"/>
+            <arg value="${mangled.jdk.dir}" />
+            <arg value="-s"/>
+            <arg value="${agent.rt.jar}"/>
+        </java>
+        <!-- Mangle boot test classes to mangled.boottests.dir -->
+        <delete dir="${mangled.boottests.dir}" />
+        <mkdir dir="${mangled.boottests.dir}" />
+        <jar destfile="${build.dir}/tmpA.jar" basedir="${boottests.classes.dir}"/>
+        <java jar="${agent.jar}" fork="true" >
+            <jvmarg value="-Dcom.oracle.lambda.serialize.file=${agent.serial.file}"/>
+            <arg value="-o"/>
+            <arg value="${mangled.boottests.dir}" />
+            <arg value="-s"/>
+            <arg value="${build.dir}/tmpA.jar"/>
+        </java>
+        <!-- Mangle boot test classes to mangled.bootlib.dir (serialization injection only, no SAND) -->
+        <delete dir="${mangled.bootlib.dir}" />
+        <mkdir dir="${mangled.bootlib.dir}" />
+        <jar destfile="${build.dir}/tmpB.jar" basedir="${bootlib.classes.dir}"/>
+        <java jar="${agent.jar}" fork="true" >
+            <jvmarg value="-Dcom.oracle.lambda.serialize.file=${agent.serial.file}"/>
+            <arg value="-s"/>
+            <arg value="-o"/>
+            <arg value="${mangled.bootlib.dir}" />
+            <arg value="${build.dir}/tmpB.jar"/>
+        </java>
+        <!-- Mangle test classes to mangled.testdir -->
+        <delete dir="${mangled.tests.dir}" />
+        <mkdir dir="${mangled.tests.dir}" />
+        <jar destfile="${build.dir}/tmpC.jar" basedir="${tests.classes.dir}"/>
+        <java jar="${agent.jar}" fork="true" >
+            <jvmarg value="-Dcom.oracle.lambda.serialize.file=${agent.serial.file}"/>
+            <arg value="-o"/>
+            <arg value="${mangled.tests.dir}" />
+            <arg value="${build.dir}/tmpC.jar"/>
+        </java>
+    </target>
+
+    <!--
+        Some tests are hostile to our serialization testing strategy; these are those where lambdas
+        have side-effects on captured arguments, and then we test properties of the captured arguments
+        separately.  This is because serialization/deserialization severs the aliasing that this test
+        strategy depends on.  So we mark and exclude these classes.
+    -->
+    <target name="test-mangled" depends="mangler-sanity, test-compile, build-mangler" >
+        <testng classpathref="mangled.class.path" outputdir="${test.reports.dir}"
+                excludedgroups="serialization-hostile">
+            <classfileset dir="${mangled.tests.dir}" includes="org/openjdk/tests/java/**/*.class"
+                          excludes="**/SerializedLambdaTest.class"/>
+            <classfileset dir="${mangled.boottests.dir}" includes="**/*.class"/>
+            <jvmarg value="-Xbootclasspath/p:${agent.jar}"/>
+            <jvmarg value="-Xbootclasspath/p:${mangled.jdk.dir}"/>
+            <jvmarg value="-Xbootclasspath/p:${mangled.bootlib.dir}"/>
+            <jvmarg value="-Xbootclasspath/p:${mangled.boottests.dir}"/>
+            <jvmarg value="-Xbootclasspath/p:${lib.testng.jar}"/>
+            <!--<jvmarg value="-Dsun.io.serialization.extendedDebugInfo=true" />-->
+            <jvmarg value="-ea" />
+            <jvmarg value="-esa" />
+            <jvmarg value="-Xverify:none" />
+            <jvmarg value="${agent.heap.size}"/>
+            <sysproperty key="org.openjdk.java.util.stream.tripwire" value="true"/>
+            <sysproperty key="org.openjdk.java.util.stream.sand.mode" value="true"/>
+            <!-- properties specific to agent config -->
+            <jvmarg value="-Dcom.oracle.lambda.store.frames=false"/>
+            <jvmarg value="-Dcom.oracle.lambda.nrounds=1"/>
+            <jvmarg value="-javaagent:${agent.jar}"/>
+        </testng>
+    </target>
+
+    <target name="test-mangledp" depends="test-compile, build-mangler" >
+        <testng classpathref="mangled.class.path" outputdir="${test.reports.dir}"
+                excludedgroups="serialization-hostile">
+            <classfileset dir="${mangled.tests.dir}" includes="**/${test.pattern}.class"/>
+            <classfileset dir="${mangled.boottests.dir}" includes="**/${test.pattern}.class"/>
+            <jvmarg value="-Xbootclasspath/p:${agent.jar}"/>
+            <jvmarg value="-Xbootclasspath/p:${mangled.jdk.dir}"/>
+            <jvmarg value="-Xbootclasspath/p:${mangled.bootlib.dir}"/>
+            <jvmarg value="-Xbootclasspath/p:${mangled.boottests.dir}"/>
+            <jvmarg value="-Xbootclasspath/p:${lib.testng.jar}"/>
+            <!--<jvmarg value="-Dsun.io.serialization.extendedDebugInfo=true" />-->
+            <jvmarg value="-ea" />
+            <jvmarg value="-esa" />
+            <jvmarg value="-Xverify:none" />
+            <jvmarg value="-Xmx2500m" />
+            <sysproperty key="org.openjdk.java.util.stream.tripwire" value="true"/>
+            <sysproperty key="org.openjdk.java.util.stream.sand.mode" value="true"/>
+            <jvmarg value="-javaagent:${agent.jar}"/>
+        </testng>
+    </target>
+    <!-- mangler related,  end -->
+</project>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test-ng/tests/lambda/TestInterfaceBridges.java	Wed Aug 14 15:53:13 2013 -0700
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  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 lambda;
+
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.assertEquals;
+
+/**
+ * TestInterfaceBridges
+ *
+ * @author Brian Goetz
+ */
+@Test
+public class TestInterfaceBridges {
+    public void testCovariantOverrideLambda() {
+        B b = () -> "Foo";
+        assertEquals("Foo", b.make());
+        assertEquals("Foo", ((A) b).make());
+    }
+
+    public void testCovariantOverrideIC() {
+        B b = new B() {
+            @Override
+            public String make() {
+                return "Foo";
+            }
+        };
+        assertEquals("Foo", b.make());
+        assertEquals("Foo", ((A) b).make());
+    }
+
+    public static interface A {
+        Object make();
+    }
+
+    public static interface B extends A {
+        String make();
+    }
+
+    public void testCovariantMerge() {
+        D d = () -> "Foo";
+        assertEquals("Foo", d.make());
+        assertEquals("Foo", ((A) d).make());
+        assertEquals("Foo", ((C) d).make());
+    }
+
+    public static interface C {
+        String make();
+    }
+
+    public static interface D extends A, C {
+    }
+}
--- a/test/ProblemList.txt	Tue Aug 13 10:42:37 2013 -0700
+++ b/test/ProblemList.txt	Wed Aug 14 15:53:13 2013 -0700
@@ -210,6 +210,10 @@
 # 8014719
 sun/net/www/http/HttpClient/ProxyTest.java                       generic-all
 
+# 7150552
+sun/net/www/protocol/http/B6299712.java                         macosx-all
+java/net/CookieHandler/CookieManagerTest.java                   macosx-all
+
 ############################################################################
 
 # jdk_io
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/io/Serializable/defaultSVID/Child.java	Wed Aug 14 15:53:13 2013 -0700
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+class Child implements Parent, java.io.Serializable { }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/io/Serializable/defaultSVID/DefaultSVID.java	Wed Aug 14 15:53:13 2013 -0700
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @summary Test default serial version id creation
+ *
+ * @compile ParentA.java Child.java
+ * @run main DefaultSVID moveParentA
+ * @compile ParentB.java
+ * @run main DefaultSVID
+ */
+
+import java.io.IOException;
+import java.io.ObjectStreamClass;
+import java.nio.file.*;
+import static java.nio.file.StandardCopyOption.*;
+
+public class DefaultSVID {
+
+    static String testClasses = System.getProperty("test.classes");
+
+    public static class MyClassLoader extends ClassLoader {
+        final String suffix;
+
+        public MyClassLoader(String suffix) {
+            super(null);
+            this.suffix = suffix;
+        }
+
+        public Class<?> defineAndResolve(String name) {
+            try {
+                String file;
+                if ("Parent".equals(name)) {
+                    file = name + suffix;
+                } else {
+                    file = name;
+                }
+                byte[] classBytes = Files.readAllBytes(Paths.get(testClasses, file + ".class"));
+                Class<?> ret = defineClass(name, classBytes, 0, classBytes.length);
+                resolveClass(ret);
+                return ret;
+            } catch (IOException ioe) {
+                throw new RuntimeException(ioe);
+            }
+        }
+    }
+
+    public static void main(String args[]) throws Exception {
+        if (args.length > 0) {
+            Files.move(Paths.get(testClasses, "Parent.class"),
+                       Paths.get(testClasses, "ParentA.class"),
+                       REPLACE_EXISTING);
+            return;
+        }
+
+        Files.move(Paths.get(testClasses, "Parent.class"),
+                   Paths.get(testClasses, "ParentB.class"),
+                   REPLACE_EXISTING);
+
+        MyClassLoader cl_nodefault = new MyClassLoader("A");
+        MyClassLoader cl_default = new MyClassLoader("B");
+
+        cl_nodefault.defineAndResolve("Parent");
+        cl_default.defineAndResolve("Parent");
+
+        Class<?> child_nodefault = cl_nodefault.defineAndResolve("Child");
+        Class<?> child_default = cl_default.defineAndResolve("Child");
+
+        ObjectStreamClass osc_child_nodefault = ObjectStreamClass.lookup(child_nodefault);
+        ObjectStreamClass osc_child_default = ObjectStreamClass.lookup(child_default);
+        
+        long svid_nodefault = osc_child_nodefault.getSerialVersionUID();
+        long svid_default = osc_child_default.getSerialVersionUID();
+
+        System.out.printf("svid_nodefault : %016X \n  svid_default : %016X\n",
+                          svid_nodefault, svid_default);
+
+        if (svid_nodefault != svid_default) {
+            throw new AssertionError("serial version IDs differ");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/io/Serializable/defaultSVID/ParentA.java	Wed Aug 14 15:53:13 2013 -0700
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+interface Parent {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/io/Serializable/defaultSVID/ParentB.java	Wed Aug 14 15:53:13 2013 -0700
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+interface Parent {
+    default void parent() { }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/Double/DoubleReducersTest.java	Wed Aug 14 15:53:13 2013 -0700
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @summary
+ * @(#) DoubleReducersTest.java
+ * @author Tristan Yan
+ * @run testng DoubleReducersTest
+ */
+
+import java.util.Random;
+import static org.testng.Assert.*;
+import org.testng.annotations.Test;
+
+public class DoubleReducersTest {
+    private final static int LOOP = 1 << 20;
+
+    private final static Random rand = new Random(System.currentTimeMillis());
+
+    @Test
+    public void testMax() {
+        for(int index = 0; index < LOOP; index++){
+            double d1 = rand.nextDouble();
+            double d2 = rand.nextDouble();
+            double expected = d1 > d2 ? d1 : d2;
+            assertEquals(Double.max(d1, d2), expected);
+        }
+    }
+
+    @Test
+    public void testMin() {
+        for(int index = 0; index < LOOP; index++){
+            double d1 = rand.nextDouble();
+            double d2 = rand.nextDouble();
+            double expected = d1 < d2 ? d1 : d2;
+            assertEquals(Double.min(d1, d2), expected);
+        }
+    }
+
+    @Test
+    public void testSum() {
+        for(int index = 0; index < LOOP; index++){
+            double d1 = rand.nextDouble();
+            double d2 = rand.nextDouble();
+            double expected = d1 + d2;
+            assertEquals(Double.sum(d1, d2), expected);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/Integer/IntegerReducersTest.java	Wed Aug 14 15:53:13 2013 -0700
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @summary
+ * @(#) IntegerReducersTest.java
+ * @author Tristan Yan
+ * @run testng IntegerReducersTest
+ */
+
+import java.util.Random;
+import static org.testng.Assert.*;
+import org.testng.annotations.Test;
+
+public class IntegerReducersTest {
+    private final static int LOOP = 1 << 20;
+
+    private final static Random rand = new Random(System.currentTimeMillis());
+
+    @Test
+    public void testMax() {
+        for(int index = 0; index < LOOP; index++){
+            int i1 = rand.nextInt();
+            int i2 = rand.nextInt();
+            int expected = i1 > i2 ? i1 : i2;
+            assertEquals(Integer.max(i1, i2), expected);
+        }
+    }
+
+    @Test
+    public void testMin() {
+        for(int index = 0; index < LOOP; index++){
+            int i1 = rand.nextInt();
+            int i2 = rand.nextInt();
+            int expected = i1 < i2 ? i1 : i2;
+            assertEquals(Integer.min(i1, i2), expected);
+        }
+    }
+
+    @Test
+    public void testSum() {
+        for(int index = 0; index < LOOP; index++){
+            int i1 = rand.nextInt();
+            int i2 = rand.nextInt();
+            int expected = i1 + i2;
+            assertEquals(Integer.sum(i1, i2), expected);
+        }
+    }
+
+    @Test
+    public void testUnsignedWithoutRadix(){
+        for(int index = 0; index < LOOP; index++){
+            int i = rand.nextInt();
+            assertEquals(Integer.parseUnsignedInt(Integer.toUnsignedString(i)), i);
+            assertEquals(Integer.toUnsignedString(i, 10), Integer.toUnsignedString(i));
+            if(i >= 0)
+                assertEquals(Integer.toUnsignedString(i), Integer.toString(i));
+        }
+    }
+
+    @Test
+    public void testUnsignedWithRadix(){
+        for(int index = 0; index < LOOP; index++){
+            int i = rand.nextInt();
+            int radix = Character.MIN_RADIX + rand.nextInt(Character.MAX_RADIX - Character.MIN_RADIX + 1);
+            assertEquals(Integer.parseUnsignedInt(Integer.toUnsignedString(i, radix), radix), i);
+            if(i >= 0)
+                assertEquals(Integer.toUnsignedString(i, radix), Integer.toString(i, radix));
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/Long/LongReducersTest.java	Wed Aug 14 15:53:13 2013 -0700
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @summary
+ * @author Tristan Yan
+ * @run testng LongReducersTest
+ */
+
+import java.util.Random;
+import static org.testng.Assert.*;
+import org.testng.annotations.Test;
+
+public class LongReducersTest {
+    private final static int LOOP = 1 << 20;
+
+    private final static Random rand = new Random(System.currentTimeMillis());
+
+    @Test
+    public void testMax() {
+        for(int index = 0; index < LOOP; index++){
+            long l1 = rand.nextLong();
+            long l2 = rand.nextLong();
+            long expected = l1 > l2 ? l1 : l2;
+            assertEquals(Long.max(l1, l2), expected);
+        }
+    }
+
+    @Test
+    public void testMin() {
+        for(int index = 0; index < LOOP; index++){
+            long l1 = rand.nextLong();
+            long l2 = rand.nextLong();
+            long expected = l1 < l2 ? l1 : l2;
+            assertEquals(Long.min(l1, l2), expected);
+        }
+    }
+
+    @Test
+    public void testSum() {
+        for(int index = 0; index < LOOP; index++){
+            long l1 = rand.nextLong();
+            long l2 = rand.nextLong();
+            long expected = l1 + l2;
+            assertEquals(Long.sum(l1, l2), expected);
+        }
+    }
+
+    @Test
+    public void testUnsignedWithoutRadix(){
+        for(int index = 0; index < LOOP; index++){
+            long l = rand.nextLong();
+            assertEquals(Long.parseUnsignedLong(Long.toUnsignedString(l)), l);
+            assertEquals(Long.toUnsignedString(l, 10), Long.toUnsignedString(l));
+            if(l >= 0)
+                assertEquals(Long.toUnsignedString(l), Long.toString(l));
+        }
+    }
+
+    @Test
+    public void testUnsignedWithRadix(){
+        for(int index = 0; index < LOOP; index++){
+            long l = rand.nextLong();
+            int radix = Character.MIN_RADIX + rand.nextInt(Character.MAX_RADIX - Character.MIN_RADIX + 1);
+            assertEquals(Long.parseUnsignedLong(Long.toUnsignedString(l, radix), radix), l);
+            if(l >= 0)
+                assertEquals(Long.toUnsignedString(l, radix), Long.toString(l, radix));
+        }
+    }
+
+    @Test
+    public void testCompareUnsigned() {
+        for(int index = 0; index < LOOP; index++){
+            long l1 = rand.nextLong();
+            long l2 = rand.nextLong();
+            assertEquals(Long.compareUnsigned(l1, l2),
+                Long.compare(Long.MAX_VALUE + l1, Long.MAX_VALUE + l2));
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/String/JoinTest.java	Wed Aug 14 15:53:13 2013 -0700
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @summary test for String.join(CharSequence , CharSequence...) and
+ *          String.join(CharSequence , Iterable<? extends CharSequence>).
+ * @(#) JoinTest.java
+ * @author Tristan Yan
+ * @run testng JoinTest
+ */
+
+import java.util.*;
+import static org.testng.Assert.*;
+import org.testng.annotations.Test;
+
+public class JoinTest {
+    private final String[] LANGUAGES = { "ABAP", "ALGOL", "ActionScript",
+        "AppleScript","AspectJ", "Assembly language", "AutoLISP", "AWK", "Bash",
+        "C", "C Shell", "CICS", "COBOL", "Cool", "CSH", "DCL", "Delphi",
+        "Eiffel", "F#", "Formula", "Fortran", "FoxBase", "FoxPro", "Groovy",
+        "Haskell", "J#", "JCL", "JavaScript", "Ksh", "LINC", "Lisp", "Logo",
+        "MASM", "MATLAB", "NASM", "XML", "Objective-C", "Pascal", "Perl",
+        "PL/I", "PostScript", "PowerBuilder", "PowerShell", "Prolog", "Pro*C",
+        "Python", "QBasic", "REBOL", "Ruby", "Scheme", "Sed", "Smalltalk",
+        "SQL", "VBScript" };
+
+
+    private final String[] DELIMETERS = {"`", "~", "!", "@", "#", "$", "%", "^",
+        "&", "*", "(", ")", "-", "_", "+", "=", "\\", "|", ",", ".", "/", ":",
+        ";", "\"", "\"", "\n", "\t", " ", "\t"};
+
+    @Test
+    public void testJoin() {
+        //HashSet sort data with hashCode(), iterator order by hashCode()
+        List<String> lanugageList = Arrays.asList(LANGUAGES);
+        Set<String> lanugageSet = new HashSet<>(lanugageList);
+        Random rnd = new Random();
+        String delimeter = DELIMETERS[rnd.nextInt(DELIMETERS.length)];
+        StringBuilder sb = new StringBuilder();
+        Iterator<String> it = lanugageSet.iterator();
+        int pos = 0;
+        while(it.hasNext()) {
+            sb.append(it.next());
+            if(++pos < lanugageSet.size())
+                sb.append(delimeter);
+        }
+        String result2 = String.join(delimeter, lanugageSet);
+        String result1 = sb.toString();
+        assertEquals(result2, result1);
+
+        Collections.shuffle(lanugageList, new Random(rnd.nextInt()));
+        String[] shuffledArray = new String[lanugageList.size()];
+        lanugageList.toArray(shuffledArray);
+        result1 = String.join(delimeter, shuffledArray);
+        result2 = String.join(delimeter, lanugageList);
+        StringBuilder expectedSB = new StringBuilder();
+        for(int index = 0; index < lanugageList.size() - 1; index++)
+            expectedSB.append(lanugageList.get(index)).append(delimeter);
+        expectedSB.append(lanugageList.get(lanugageList.size() - 1));
+        assertEquals(expectedSB.toString(), result1);
+        assertEquals(result2, result1);
+
+        String single = LANGUAGES[rnd.nextInt(LANGUAGES.length)];
+        assertEquals(String.join(delimeter, new String[]{single}), single);
+        assertEquals(String.join(delimeter, new String[]{single}), single);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/StringBuilder/AddAllTest.java	Wed Aug 14 15:53:13 2013 -0700
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @summary test for StringBuilde/StringBuffer.addAll()
+ * @library /sqeutil
+ * @author Tristan Yan
+ * @run testng AddAllTest
+ */
+
+import java.util.*;
+import java.util.stream.*;
+import static org.testng.Assert.*;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+public class AddAllTest {
+    private final static int LINE_NUM = 1 << 8;
+
+    private final static int LINE_MIN_CHARACTER_LEN = 2;
+
+    private final static int LINE_MAX_CHARACTER_LEN = 80;
+
+    @Test(dataProvider = "generateData")
+    public void builderAddAll(String[] buff){
+        String str = Arrays.stream(buff).collect(Collectors.joining());
+        int start = 0;
+        for(int index = 0; index < buff.length; index++){
+            assert(start + buff[index].length() <= str.length());
+            assertEquals(str.substring(start, start + buff[index].length()), buff[index]);
+            start += buff[index].length();
+        }
+    }
+
+    @Test(dataProvider = "generateData")
+    public void bufferAddAll(String[] buff){
+        StringBuffer sb = Arrays.stream(buff).collect(StringBuffer::new, StringBuffer::append, (s, o) -> s.append(o));
+        String str = sb.toString();
+        int start = 0;
+        for(int index = 0; index < buff.length; index++){
+            assert(start + buff[index].length() <= str.length());
+            assertEquals(str.substring(start, start + buff[index].length()), buff[index]);
+            start += buff[index].length();
+        }
+    }
+
+    @DataProvider
+    public Object[][] generateData(){
+        Object[][] data = new Object[LINE_NUM][];
+        for(int line = 0; line < LINE_NUM; line++) {
+            List<Object> l = new ArrayList<>();
+            String[] buffer = new String[line];
+            for(int row = 0; row < line; row++)
+                buffer[row] = StringUtilities.randomString(LINE_MAX_CHARACTER_LEN,
+                    0);
+            data[line] = new Object[]{buffer};
+        }
+        return data;
+    }
+}
--- a/test/java/lang/ThreadLocal/Basic.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/test/java/lang/ThreadLocal/Basic.java	Wed Aug 14 15:53:13 2013 -0700
@@ -30,6 +30,7 @@
 public class Basic {
     static ThreadLocal n = new ThreadLocal() {
         int i = 0;
+        @Override
         protected synchronized Object initialValue() {
             return new Integer(i++);
         }
@@ -43,11 +44,12 @@
         // Start the threads
         for(int i=0; i<threadCount; i++) {
             th[i] = new Thread() {
+                @Override
                 public void run() {
                     int threadId = ((Integer)(n.get())).intValue();
                     for (int j=0; j<threadId; j++) {
                         x[threadId]++;
-                        Thread.currentThread().yield();
+                        Thread.yield();
                     }
                 }
             };
--- a/test/java/lang/ThreadLocal/ImmutableLocal.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/test/java/lang/ThreadLocal/ImmutableLocal.java	Wed Aug 14 15:53:13 2013 -0700
@@ -33,15 +33,18 @@
      * {@link ThreadLocal} guaranteed to always return the same reference.
      */
     abstract public static class ImmutableThreadLocal extends ThreadLocal {
+        @Override
         public void set(final Object value) {
             throw new RuntimeException("ImmutableThreadLocal set called");
         }
 
         // force override
+        @Override
         abstract protected Object initialValue();
     }
 
     private static final ThreadLocal cache = new ImmutableThreadLocal() {
+        @Override
         public Object initialValue() {
             return Thread.currentThread().getName();
         }
--- a/test/java/lang/ThreadLocal/InitialValue.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/test/java/lang/ThreadLocal/InitialValue.java	Wed Aug 14 15:53:13 2013 -0700
@@ -34,8 +34,9 @@
 
     public class MyLocal extends ThreadLocal<String> {
         String val;
+        @Override
         protected String initialValue() {
-            other = new ThreadLocal<String>();
+            other = new ThreadLocal<>();
             // This should reuse the map that the containing get() created
             // or visa versa (i.e. instead of a second map being created).
             other.set("Other");
@@ -43,6 +44,7 @@
         }
     }
 
+    @Override
     public void run() {
         MyLocal l = new MyLocal();
         // This should pick up the initial value
--- a/test/java/lang/ThreadLocal/TLRemoveTest.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/test/java/lang/ThreadLocal/TLRemoveTest.java	Wed Aug 14 15:53:13 2013 -0700
@@ -32,6 +32,7 @@
     private static final int REMOVE_SET_VALUE = 102;
 
     static ThreadLocal<Integer> n = new ThreadLocal<Integer>() {
+        @Override
         protected synchronized Integer initialValue() {
             return INITIAL_VALUE;
         }
@@ -51,11 +52,12 @@
         for(int i = 0; i<threadCount; i++) {
             final int threadId = i;
             th[i] = new Thread() {
+                @Override
                 public void run() {
                     try{
                         n.set(threadId); // Sets threadId as threadlocal value...
                         for (int j = 0; j<threadId; j++)
-                            Thread.currentThread().yield();
+                            Thread.yield();
 
                         // To remove the ThreadLocal ....
                         for(int removeId  : removeNode)
--- a/test/java/lang/ThreadLocal/TestThreadId.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/test/java/lang/ThreadLocal/TestThreadId.java	Wed Aug 14 15:53:13 2013 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 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
@@ -49,8 +49,9 @@
     }
 
     // Each child thread just publishes its id value for validation
+    @Override
     public void run() {
-        value = id.get();
+        value = ThreadId.get();
     }
 
     public static void main(String args[]) throws Throwable {
--- a/test/java/lang/invoke/lambda/LambdaAccessControlTest.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/test/java/lang/invoke/lambda/LambdaAccessControlTest.java	Wed Aug 14 15:53:13 2013 -0700
@@ -25,11 +25,12 @@
  * @test
  * @bug 8003881
  * @summary tests Lambda expression with a a security manager at top level
- * @compile -XDignore.symbol.file LambdaAccessControlTest.java LUtils.java
+ * @compile -XDignore.symbol.file LambdaAccessControlDoPrivilegedTest.java LambdaAccessControlTest.java
  *
  * @run main/othervm LambdaAccessControlTest
  */
 
+
 public class LambdaAccessControlTest extends LUtils {
     public static void main(String... args) {
         System.setSecurityManager(new SecurityManager());
--- a/test/java/lang/invoke/lambda/LambdaSerialization.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/test/java/lang/invoke/lambda/LambdaSerialization.java	Wed Aug 14 15:53:13 2013 -0700
@@ -25,6 +25,7 @@
 @test
 @bug 8004970
 @summary Lambda serialization
+
 */
 
 import java.io.*;
@@ -65,11 +66,11 @@
         }
         assertTrue(assertionCount == 3);
     }
-
+    
     static void write(ObjectOutput out, LSI lamb) throws IOException {
         out.writeObject(lamb);
     }
-
+    
     static void readAssert(ObjectInputStream in, String expected)  throws IOException, ClassNotFoundException {
         LSI ls = (LSI) in.readObject();
         String result = ls.convert("X");
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/nio/Files/FilesLambdaTest.java	Wed Aug 14 15:53:13 2013 -0700
@@ -0,0 +1,336 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @summary function test for Files.list()/find()/walk()/lines()
+ * @library /sqeutil
+ * @(#) FilesLambdaTest.java
+ * @author Tristan Yan
+ * @run testng/othervm FilesLambdaTest
+ */
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.LinkOption;
+import java.nio.file.NotDirectoryException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Random;
+import java.util.function.Consumer;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import static org.testng.Assert.*;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+public class FilesLambdaTest {
+    private static final Random rand = new Random(System.nanoTime());
+
+    private static final String TEST_SRC = System.getProperty("test.src");
+
+    private static final String ROOT_NAME = "FilesLambdaTest" + System.nanoTime();
+
+    private static final String LINES_TEST_FILE = "lines" +  System.nanoTime();
+
+    private static final int MAX_FILES_NUMBER = 1 << 6;
+
+    private static final Charset UTF8 = Charset.forName("UTF-8");
+
+    private final static int MIN_LEN = 1 << 2;
+
+    private final static int MAX_LEN = 1 << 8;
+
+    private final static int LINES_NUM = 1 << 8;
+
+    private static final String[][] folders = {
+        {"A01"},
+        {"A01", "AA02"},
+        {"A01", "AB02"},
+        {"A01", "AC02"},
+        {"B01"},
+        {"B01", "BA02"},
+        {"B01", "BA02", "BAA03"},
+        {"B01", "BA02", "BAA03", "BAAA04", "BAAAA05", "BAAAAA06", "BAAAAAA07",
+         "BAAAAAAA08", "BAAAAAAAA09", "BAAAAAAAAA10", "BAAAAAAAAAA11"},
+        {"C01"},
+        {"C01", "CA02"},
+        {"C01", "CD02"},
+        {"D01", "DA02", "DAA03", "DAAA04", "DAAAA05", "DAAAAA06", "DAAAAAA07"},
+        {"E01"},
+        {"E01", "EA02"},
+        {"E01", "EB02", "EBB03"},
+        {"E01", "EC02", "ECC03", "ECCC04"},
+        {"E01", "ED02", "EDD03", "EDDD04", "EDDDD05"},
+        {"E01", "EE02", "EEE03", "EEEE04", "EEEEE05", "EEEEEE06"},
+        {"E01", "EF02", "EFF03", "EFFF04", "EFFFF05", "EFFFFF06"},
+        {"E01", "EG02", "EGG03", "EGGG04", "EGGGG05", "EGGGGG06", "EGGGGGG07"},
+        {"E01", "EH02", "EHH03", "EHHH04", "EHHHH05", "EHHHHH06", "EHHHHHH07",
+         "EHHHHHHH08"},
+        {"E01", "EI02", "EII03", "EIII04", "EIIII05", "EIIIII06", "EIIIIII07",
+         "EIIIIIII08", "EIIIIIIII09"},
+        {"E01", "EJ02", "EJJ03", "EJJJ04", "EJJJJ05", "EJJJJJ06", "EJJJJJJ07",
+         "EJJJJJJJ08", "EJJJJJJJJ09", "EJJJJJJJJJ10"},
+        {"E01", "EK02", "EKK03", "EKKK04", "EKKKK05", "EKKKKK06", "EKKKKKK07",
+         "EKKKKKKK08", "EKKKKKKKK09", "EKKKKKKKKK10", "EJJJJJJJJJJ11"}
+    };
+
+    private Path root;
+
+    private Path testFile;
+
+    private Path notExistPath;
+
+    final Consumer<Path> writeReverseWithLink = path -> {
+        int filesCount = rand.nextInt(MAX_FILES_NUMBER);
+        for(int count = 0; count < filesCount; count++) {
+            String fileName = String.valueOf(rand.nextLong());
+            Path file = path.resolve(fileName);
+            String linkName = String.valueOf(rand.nextLong());
+            Path link = path.resolve(linkName);
+            try (BufferedWriter writer
+                    = Files.newBufferedWriter(Files.createFile(file), UTF8)) {
+                writer.write(new StringBuilder(fileName).reverse().toString(),
+                        0, fileName.length());
+                Files.createSymbolicLink(link, file);
+            } catch (IOException ex) {
+                throw new RuntimeException(ex);
+            }
+        }
+    };
+
+    @BeforeClass
+    public void filesSetUp() throws IOException {
+        List<Path> paths = new ArrayList<>();
+        root = Paths.get(TEST_SRC, ROOT_NAME);
+        paths.add(Files.createDirectory(root));
+        for(int i = 0; i < folders.length; i++ ) {
+            String[] toBeCreated = folders[i];
+            Path folder = Paths.get(ROOT_NAME, toBeCreated);
+            paths.add(Files.createDirectories(folder));
+        }
+        paths.forEach(writeReverseWithLink);
+
+        testFile = Paths.get(LINES_TEST_FILE);
+        try (BufferedWriter writer
+                = Files.newBufferedWriter(Files.createFile(testFile), UTF8)) {
+            for(int i = 0; i< LINES_NUM; i++) {
+                String line = StringUtilities.randomString(MAX_LEN, MIN_LEN);
+                writer.write(line, 0, line.length());
+            }
+        } catch (IOException ex) {
+            throw new RuntimeException(ex);
+        }
+
+        String NOT_EXIST = "NOT_EXIST";
+        notExistPath = Paths.get(TEST_SRC, NOT_EXIST);
+    }
+
+    @AfterClass
+    public void filesTearDown() throws IOException {
+        if(root != null) {
+            Files.walkFileTree(root, new SimpleFileVisitor<Path>() {
+                @Override
+                public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
+                    throws IOException {
+                    Files.delete(file);
+                    return FileVisitResult.CONTINUE;
+                }
+                @Override
+                public FileVisitResult postVisitDirectory(Path dir, IOException exc)
+                    throws IOException{
+                    Files.delete(dir);
+                    return FileVisitResult.CONTINUE;
+                }
+            });
+        }
+        if(testFile != null) {
+            Files.delete(testFile);
+        }
+    }
+
+    @Test
+    public void testFilesList() throws IOException {
+        checkFilesList(root);
+    }
+
+    @Test
+    public void testWalk() throws IOException{
+        String[] dir = folders[rand.nextInt(folders.length)];
+        Path walkFolder = Paths.get(ROOT_NAME, dir);
+        final int maxDepth = rand.nextInt(11);
+        List<Path> expectedFullFileList = new ArrayList<>();
+        List<Path> expectedMaxDepthFileList = new ArrayList<>();
+
+        List<Path> expectedFullSymList = new ArrayList<>();
+        List<Path> expectedMaxDepthSymList = new ArrayList<>();
+
+        List<Path> expectedFullDirList = new ArrayList<>();
+        List<Path> expectedMaxDepthDirList = new ArrayList<>();
+
+        Files.walkFileTree(walkFolder, new SimpleFileVisitor<Path>() {
+            @Override
+            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
+                throws IOException {
+                if (walkFolder.relativize(file).getNameCount() <= maxDepth) {
+                    expectedMaxDepthFileList.add(file);
+                    if(Files.isSymbolicLink(file)) {
+                        expectedMaxDepthSymList.add(file);
+                    }
+                }
+                expectedFullFileList.add(file);
+                if(Files.isSymbolicLink(file)) {
+                    expectedFullSymList.add(file);
+                }
+                return FileVisitResult.CONTINUE;
+            }
+            @Override
+            public FileVisitResult postVisitDirectory(Path dir, IOException exc)
+                throws IOException{
+                if (walkFolder.relativize(dir).getNameCount() <= maxDepth
+                        || walkFolder.equals(dir)) {
+                    expectedMaxDepthDirList.add(dir);
+                }
+                expectedFullDirList.add(dir);
+                return FileVisitResult.CONTINUE;
+            }
+        });
+        Collections.sort(expectedFullFileList);
+        Collections.sort(expectedMaxDepthFileList);
+        Collections.sort(expectedFullSymList);
+        Collections.sort(expectedMaxDepthSymList);
+        Collections.sort(expectedFullDirList);
+        Collections.sort(expectedMaxDepthDirList);
+
+        assertEquals(expectedMaxDepthFileList,
+                Files.walk(walkFolder, maxDepth).filter(p -> !Files.isDirectory(p)).
+                sorted().collect(Collectors.toList()));
+        assertEquals(expectedMaxDepthSymList,
+                Files.walk(walkFolder, maxDepth).filter(p -> Files.isSymbolicLink(p)).
+                sorted().collect(Collectors.toList()));
+        assertEquals(expectedMaxDepthDirList,
+                Files.walk(walkFolder, maxDepth).filter(p -> Files.isDirectory(p)).
+                sorted().collect(Collectors.toList()));
+        assertEquals(expectedFullFileList,
+                Files.walk(walkFolder).filter(p -> !Files.isDirectory(p)).
+                sorted().collect(Collectors.toList()));
+        assertEquals(expectedFullSymList,
+                Files.walk(walkFolder).filter(p -> Files.isSymbolicLink(p)).
+                sorted().collect(Collectors.toList()));
+        assertEquals(expectedFullDirList,
+                Files.walk(walkFolder).filter(p -> Files.isDirectory(p)).
+                sorted().collect(Collectors.toList()));
+    }
+
+    @Test
+    public void testFind() throws IOException{
+        String[] dir = folders[rand.nextInt(folders.length)];
+        Path walkFolder = Paths.get(ROOT_NAME, dir);
+        String walkFoderName = dir[dir.length - 1];
+
+        int walkFolderDepth = Integer.parseInt(walkFoderName.substring(walkFoderName.length() - 2));
+        int maxDepth = rand.nextInt(11);
+        Stream<Path> stream
+                = Files.find(walkFolder, maxDepth, (p,bfa) -> Files.isSymbolicLink(p));
+        stream.forEach(p -> {
+            assertTrue(Files.isSymbolicLink(p));
+            assertFalse(Files.isDirectory(p));
+            assertFalse(Files.isRegularFile(p, LinkOption.NOFOLLOW_LINKS));
+            String parentName = p.getParent().toFile().getName();
+            int depth = Integer.parseInt(parentName.substring(parentName.length() - 2));
+            assertTrue(depth - walkFolderDepth < maxDepth);
+        });
+
+        assertEquals(Files.find(walkFolder, maxDepth, (p,bfa) -> Files.isSymbolicLink(p)).toArray(),
+                Files.find(walkFolder, maxDepth, (p,bfa) -> bfa.isSymbolicLink()).toArray());
+    }
+
+    @Test
+    public void testLines() throws IOException{
+        Stream<String> stream = Files.lines(testFile, UTF8);
+        List<String> lines = Files.readAllLines(testFile, UTF8);
+        assertEquals(lines, stream.collect(Collectors.toList()));
+    }
+
+    @Test(expectedExceptions = IOException.class)
+    public void testListNoReadAccess() throws IOException{
+        Files.list(notExistPath);
+    }
+
+    @Test(expectedExceptions = NotDirectoryException.class)
+    public void testListNotDirectory() throws IOException{
+        Files.list(testFile);
+    }
+
+    @Test(expectedExceptions = IOException.class)
+    public void testFindNoExist() throws IOException{
+        Files.find(notExistPath, Integer.MAX_VALUE, (p, bfa) -> true);
+    }
+
+    @Test(expectedExceptions = IOException.class)
+    public void testLinesNoExist() throws IOException{
+        Files.lines(notExistPath, UTF8);
+    }
+
+    @Test(expectedExceptions = IOException.class)
+    public void testWalkNoExist() throws IOException{
+        Files.walk(notExistPath);
+    }
+
+    @Test(expectedExceptions = IOException.class)
+    public void testWalkNoExistWithDepth() throws IOException{
+        Files.walk(notExistPath, Integer.MAX_VALUE);
+    }
+
+    public void checkFilesList(Path checkPath){
+        try {
+            assert(Files.isDirectory(checkPath));
+            Files.list(checkPath).filter(p -> Files.isDirectory(p)).forEach(p -> checkFilesList(p));
+            assertEquals(Files.list(checkPath).filter(p -> Files.isRegularFile(p, LinkOption.NOFOLLOW_LINKS)).count(),
+                    Files.list(checkPath).filter(p -> Files.isSymbolicLink(p)).count());
+            assertTrue(Files.list(checkPath).filter(p -> Files.isRegularFile(p, LinkOption.NOFOLLOW_LINKS)).allMatch(file -> contentRevered(file)));
+        } catch (IOException ex) {
+            throw new RuntimeException(ex);
+        }
+    }
+
+    private boolean contentRevered(Path path) {
+        try (BufferedReader reader = Files.newBufferedReader(path, UTF8)){
+            String fileName = path.getName(path.getNameCount() -1).toString();
+            String reversed = new StringBuilder(reader.readLine()).reverse().toString();
+            return (fileName.equals(reversed));
+        } catch (IOException ex) {
+            throw new RuntimeException(ex);
+        }
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/nio/file/DirectoryStream/StreamTest.java	Wed Aug 14 15:53:13 2013 -0700
@@ -0,0 +1,195 @@
+/*
+ * 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 8006884
+ * @summary Unit test for java.nio.file.DirectoyStream
+ * @library ..
+ * @run testng StreamTest
+ */
+
+import java.nio.file.DirectoryStream;
+import java.nio.file.DirectoryIteratorException;
+import java.nio.file.NotDirectoryException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.io.IOException;
+import java.util.TreeSet;
+import java.util.Comparator;
+import java.util.stream.Stream;
+import java.util.Iterator;
+import org.testng.annotations.Test;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.AfterClass;
+import static org.testng.Assert.*;
+
+@Test(groups = "unit")
+public class StreamTest {
+    /**
+     * Default test folder
+     * testFolder - empty
+     *            - file
+     *            - dir - d1
+     *                  - f1
+     *                  - lnDir2 (../dir2)
+     *            - dir2
+     *            - linkDir (./dir)
+     *            - linkFile(./file)
+     */
+    static Path testFolder;
+    static boolean supportsLinks;
+    static Path[] level1;
+    static Path[] level2;
+
+    @BeforeClass
+    void setupTestFolder() throws IOException {
+        testFolder = TestUtil.createTemporaryDirectory();
+        supportsLinks = TestUtil.supportsLinks(testFolder);
+        TreeSet<Path> set = new TreeSet<>();
+
+        // Level 1
+        Path empty = testFolder.resolve("empty");
+        Path file = testFolder.resolve("file");
+        Path dir = testFolder.resolve("dir");
+        Path dir2 = testFolder.resolve("dir2");
+        Files.createDirectory(empty);
+        Files.createFile(file);
+        Files.createDirectory(dir);
+        Files.createDirectory(dir2);
+        set.add(empty);
+        set.add(file);
+        set.add(dir);
+        set.add(dir2);
+        if (supportsLinks) {
+            Path tmp = testFolder.resolve("linkDir");
+            Files.createSymbolicLink(tmp, dir);
+            set.add(tmp);
+            tmp = testFolder.resolve("linkFile");
+            Files.createSymbolicLink(tmp, file);
+            set.add(tmp);
+        }
+        level1 = set.toArray(new Path[0]);
+
+        set.clear();
+        // Level 2
+        Path tmp = dir.resolve("d1");
+        Files.createDirectory(tmp);
+        set.add(tmp);
+        tmp = dir.resolve("f1");
+        Files.createFile(tmp);
+        set.add(tmp);
+        if (supportsLinks) {
+            tmp = dir.resolve("lnDir2");
+            Files.createSymbolicLink(tmp, dir2);
+            set.add(tmp);
+        }
+        level2 = set.toArray(new Path[0]);
+    }
+
+    @AfterClass
+    void cleanupTestFolder() throws IOException {
+        TestUtil.removeAll(testFolder);
+    }
+
+    public void testEntriesWithoutFilter() throws IOException {
+        try (DirectoryStream<Path> ds = Files.newDirectoryStream(testFolder)) {
+            Path[] actual = ds.stream().sorted(Comparator.naturalOrder()).toArray(Path[]::new);
+            assertEquals(actual, level1);
+        }
+
+        // link to a directory
+        if (supportsLinks) {
+            try (DirectoryStream<Path> ds = Files.newDirectoryStream(testFolder.resolve("linkDir"))) {
+                Path[] actual = ds.stream().sorted(Comparator.naturalOrder()).toArray(Path[]::new);
+                assertEquals(actual.length, level2.length);
+                for (int i = 0; i < actual.length; i++) {
+                    assertEquals(actual[i].getFileName(), level2[i].getFileName());
+                }
+            }
+        }
+    }
+
+    public void testEntriesWithFilter() throws IOException {
+        try (DirectoryStream<Path> ds = Files.newDirectoryStream(testFolder, "f*")) {
+            Path[] actual = ds.stream().toArray(Path[]::new);
+            assertEquals(actual.length, 1);
+            assertEquals(actual[0], testFolder.resolve("file"));
+        }
+
+        try (DirectoryStream<Path> ds = Files.newDirectoryStream(testFolder, "z*")) {
+            int count = ds.stream().mapToInt(p -> 1).reduce(0, Integer::sum);
+            assertEquals(count, 0, "Expect empty stream.");
+        }
+    }
+
+    public void testDirectoryIteratorException() throws IOException {
+        // check that an IOException thrown by a filter is propagated
+        DirectoryStream.Filter<Path> filter = new DirectoryStream.Filter<Path>() {
+            public boolean accept(Path file) throws IOException {
+                throw new java.util.zip.ZipException();
+            }
+        };
+
+        try (DirectoryStream<Path> ds = Files.newDirectoryStream(testFolder, filter)) {
+            Path[] actual = ds.stream().toArray(Path[]::new);
+            throw new RuntimeException("DirectoryIteratorException expected");
+        } catch (DirectoryIteratorException x) {
+            IOException cause = x.getCause();
+            if (!(cause instanceof java.util.zip.ZipException))
+                throw new RuntimeException("Expected IOException not propagated");
+        }
+    }
+
+    public void testEmptyFolder() throws IOException {
+        try (DirectoryStream<Path> ds = Files.newDirectoryStream(testFolder.resolve("empty"))) {
+            int count = ds.stream().mapToInt(p -> 1).reduce(0, Integer::sum);
+            assertEquals(count, 0, "Expect empty stream.");
+        }
+    }
+
+    public void testIllegalStateException() throws IOException {
+        try (DirectoryStream<Path> ds = Files.newDirectoryStream(testFolder)) {
+            Stream<Path> s = ds.stream();
+            try {
+                ds.iterator();
+                fail("Expect IllegalStateException from iterator() call.");
+            } catch (IllegalStateException ise1) {}
+        }
+
+        try (DirectoryStream<Path> ds = Files.newDirectoryStream(testFolder)) {
+            Iterator<Path> it = ds.iterator();
+            try {
+                ds.stream();
+                fail("Expect IllegalStateException from stream() call.");
+            } catch (IllegalStateException ise2) {}
+        }
+    }
+
+    public void testNotDirectoryException() throws IOException {
+        try {
+            Files.newDirectoryStream(testFolder.resolve("file"));
+            throw new RuntimeException("NotDirectoryException not thrown");
+        } catch (NotDirectoryException x) {
+        }
+    }
+}
\ No newline at end of file
--- a/test/java/nio/file/Files/StreamTest.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/test/java/nio/file/Files/StreamTest.java	Wed Aug 14 15:53:13 2013 -0700
@@ -43,14 +43,13 @@
 import java.nio.file.Paths;
 import java.nio.file.attribute.BasicFileAttributes;
 import java.util.Arrays;
-import java.util.Comparator;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Objects;
 import java.util.Set;
 import java.util.TreeSet;
 import java.util.function.BiPredicate;
-import java.util.stream.CloseableStream;
+import java.util.stream.Stream;
 import java.util.stream.Collectors;
 import org.testng.annotations.AfterClass;
 import org.testng.annotations.BeforeClass;
@@ -138,14 +137,14 @@
     }
 
     public void testBasic() {
-        try (CloseableStream<Path> s = Files.list(testFolder)) {
-            Object[] actual = s.sorted(Comparator.naturalOrder()).toArray();
+        try (Stream<Path> s = Files.list(testFolder)) {
+            Object[] actual = s.sorted().toArray();
             assertEquals(actual, level1);
         } catch (IOException ioe) {
             fail("Unexpected IOException");
         }
 
-        try (CloseableStream<Path> s = Files.list(testFolder.resolve("empty"))) {
+        try (Stream<Path> s = Files.list(testFolder.resolve("empty"))) {
             int count = s.mapToInt(p -> 1).reduce(0, Integer::sum);
             assertEquals(count, 0, "Expect empty stream.");
         } catch (IOException ioe) {
@@ -154,8 +153,8 @@
     }
 
     public void testWalk() {
-        try (CloseableStream<Path> s = Files.walk(testFolder)) {
-            Object[] actual = s.sorted(Comparator.naturalOrder()).toArray();
+        try (Stream<Path> s = Files.walk(testFolder)) {
+            Object[] actual = s.sorted().toArray();
             assertEquals(actual, all);
         } catch (IOException ioe) {
             fail("Unexpected IOException");
@@ -163,9 +162,9 @@
     }
 
     public void testWalkOneLevel() {
-        try (CloseableStream<Path> s = Files.walk(testFolder, 1)) {
+        try (Stream<Path> s = Files.walk(testFolder, 1)) {
             Object[] actual = s.filter(path -> ! path.equals(testFolder))
-                               .sorted(Comparator.naturalOrder())
+                               .sorted()
                                .toArray();
             assertEquals(actual, level1);
         } catch (IOException ioe) {
@@ -176,8 +175,8 @@
     public void testWalkFollowLink() {
         // If link is not supported, the directory structure won't have link.
         // We still want to test the behavior with FOLLOW_LINKS option.
-        try (CloseableStream<Path> s = Files.walk(testFolder, FileVisitOption.FOLLOW_LINKS)) {
-            Object[] actual = s.sorted(Comparator.naturalOrder()).toArray();
+        try (Stream<Path> s = Files.walk(testFolder, FileVisitOption.FOLLOW_LINKS)) {
+            Object[] actual = s.sorted().toArray();
             assertEquals(actual, all_folowLinks);
         } catch (IOException ioe) {
             fail("Unexpected IOException");
@@ -185,7 +184,7 @@
     }
 
     private void validateFileSystemLoopException(Path start, Path... causes) {
-        try (CloseableStream<Path> s = Files.walk(start, FileVisitOption.FOLLOW_LINKS)) {
+        try (Stream<Path> s = Files.walk(start, FileVisitOption.FOLLOW_LINKS)) {
             try {
                 int count = s.mapToInt(p -> 1).reduce(0, Integer::sum);
                 fail("Should got FileSystemLoopException, but got " + count + "elements.");
@@ -282,28 +281,28 @@
     public void testFind() throws IOException {
         PathBiPredicate pred = new PathBiPredicate((path, attrs) -> true);
 
-        try (CloseableStream<Path> s = Files.find(testFolder, Integer.MAX_VALUE, pred)) {
+        try (Stream<Path> s = Files.find(testFolder, Integer.MAX_VALUE, pred)) {
             Set<Path> result = s.collect(Collectors.toCollection(TreeSet::new));
             assertEquals(pred.visited(), all);
             assertEquals(result.toArray(new Path[0]), pred.visited());
         }
 
         pred = new PathBiPredicate((path, attrs) -> attrs.isSymbolicLink());
-        try (CloseableStream<Path> s = Files.find(testFolder, Integer.MAX_VALUE, pred)) {
+        try (Stream<Path> s = Files.find(testFolder, Integer.MAX_VALUE, pred)) {
             s.forEach(path -> assertTrue(Files.isSymbolicLink(path)));
             assertEquals(pred.visited(), all);
         }
 
         pred = new PathBiPredicate((path, attrs) ->
             path.getFileName().toString().startsWith("e"));
-        try (CloseableStream<Path> s = Files.find(testFolder, Integer.MAX_VALUE, pred)) {
+        try (Stream<Path> s = Files.find(testFolder, Integer.MAX_VALUE, pred)) {
             s.forEach(path -> assertEquals(path.getFileName().toString(), "empty"));
             assertEquals(pred.visited(), all);
         }
 
         pred = new PathBiPredicate((path, attrs) ->
             path.getFileName().toString().startsWith("l") && attrs.isRegularFile());
-        try (CloseableStream<Path> s = Files.find(testFolder, Integer.MAX_VALUE, pred)) {
+        try (Stream<Path> s = Files.find(testFolder, Integer.MAX_VALUE, pred)) {
             s.forEach(path -> fail("Expect empty stream"));
             assertEquals(pred.visited(), all);
         }
@@ -317,14 +316,14 @@
         try {
             // zero lines
             assertTrue(Files.size(tmpfile) == 0, "File should be empty");
-            try (CloseableStream<String> s = Files.lines(tmpfile, US_ASCII)) {
+            try (Stream<String> s = Files.lines(tmpfile, US_ASCII)) {
                 assertEquals(s.mapToInt(l -> 1).reduce(0, Integer::sum), 0, "No line expected");
             }
 
             // one line
             byte[] hi = { (byte)'h', (byte)'i' };
             Files.write(tmpfile, hi);
-            try (CloseableStream<String> s = Files.lines(tmpfile, US_ASCII)) {
+            try (Stream<String> s = Files.lines(tmpfile, US_ASCII)) {
                 List<String> lines = s.collect(Collectors.toList());
                 assertTrue(lines.size() == 1, "One line expected");
                 assertTrue(lines.get(0).equals("hi"), "'Hi' expected");
@@ -334,7 +333,7 @@
             List<String> expected = Arrays.asList("hi", "there");
             Files.write(tmpfile, expected, US_ASCII);
             assertTrue(Files.size(tmpfile) > 0, "File is empty");
-            try (CloseableStream<String> s = Files.lines(tmpfile, US_ASCII)) {
+            try (Stream<String> s = Files.lines(tmpfile, US_ASCII)) {
                 List<String> lines = s.collect(Collectors.toList());
                 assertTrue(lines.equals(expected), "Unexpected lines");
             }
@@ -342,7 +341,7 @@
             // MalformedInputException
             byte[] bad = { (byte)0xff, (byte)0xff };
             Files.write(tmpfile, bad);
-            try (CloseableStream<String> s = Files.lines(tmpfile, US_ASCII)) {
+            try (Stream<String> s = Files.lines(tmpfile, US_ASCII)) {
                 try {
                     List<String> lines = s.collect(Collectors.toList());
                     throw new RuntimeException("UncheckedIOException expected");
@@ -378,7 +377,7 @@
             fsp.setFaultyMode(false);
             Path fakeRoot = fs.getRoot();
             try {
-                try (CloseableStream<Path> s = Files.list(fakeRoot)) {
+                try (Stream<Path> s = Files.list(fakeRoot)) {
                     s.forEach(path -> assertEquals(path.getFileName().toString(), "DirectoryIteratorException"));
                 }
             } catch (UncheckedIOException uioe) {
@@ -398,7 +397,7 @@
             }
 
             try {
-                try (CloseableStream<Path> s = Files.list(fakeRoot)) {
+                try (Stream<Path> s = Files.list(fakeRoot)) {
                     s.forEach(path -> fail("should not get here"));
                 }
             } catch (UncheckedIOException uioe) {
@@ -427,12 +426,12 @@
         try {
             fsp.setFaultyMode(false);
             Path fakeRoot = fs.getRoot();
-            try (CloseableStream<Path> s = Files.list(fakeRoot.resolve("dir2"))) {
+            try (Stream<Path> s = Files.list(fakeRoot.resolve("dir2"))) {
                 // only one file
                 s.forEach(path -> assertEquals(path.getFileName().toString(), "IOException"));
             }
 
-            try (CloseableStream<Path> s = Files.walk(fakeRoot.resolve("empty"))) {
+            try (Stream<Path> s = Files.walk(fakeRoot.resolve("empty"))) {
                 String[] result = s.map(path -> path.getFileName().toString())
                                    .toArray(String[]::new);
                 // ordered as depth-first
@@ -440,13 +439,13 @@
             }
 
             fsp.setFaultyMode(true);
-            try (CloseableStream<Path> s = Files.list(fakeRoot.resolve("dir2"))) {
+            try (Stream<Path> s = Files.list(fakeRoot.resolve("dir2"))) {
                 s.forEach(path -> fail("should have caused exception"));
             } catch (UncheckedIOException uioe) {
                 assertTrue(uioe.getCause() instanceof FaultyFileSystem.FaultyException);
             }
 
-            try (CloseableStream<Path> s = Files.walk(fakeRoot.resolve("empty"))) {
+            try (Stream<Path> s = Files.walk(fakeRoot.resolve("empty"))) {
                 String[] result = s.map(path -> path.getFileName().toString())
                                    .toArray(String[]::new);
                 fail("should not reach here due to IOException");
@@ -454,7 +453,7 @@
                 assertTrue(uioe.getCause() instanceof FaultyFileSystem.FaultyException);
             }
 
-            try (CloseableStream<Path> s = Files.walk(
+            try (Stream<Path> s = Files.walk(
                 fakeRoot.resolve("empty").resolve("IOException")))
             {
                 String[] result = s.map(path -> path.getFileName().toString())
@@ -502,20 +501,20 @@
             fsp.setFaultyMode(false);
             Path fakeRoot = fs.getRoot();
             // validate setting
-            try (CloseableStream<Path> s = Files.list(fakeRoot.resolve("empty"))) {
+            try (Stream<Path> s = Files.list(fakeRoot.resolve("empty"))) {
                 String[] result = s.map(path -> path.getFileName().toString())
                                    .toArray(String[]::new);
                 assertEqualsNoOrder(result, new String[] { "SecurityException", "sample" });
             }
 
-            try (CloseableStream<Path> s = Files.walk(fakeRoot.resolve("dir2"))) {
+            try (Stream<Path> s = Files.walk(fakeRoot.resolve("dir2"))) {
                 String[] result = s.map(path -> path.getFileName().toString())
                                    .toArray(String[]::new);
                 assertEqualsNoOrder(result, new String[] { "dir2", "SecurityException", "fileInSE", "file" });
             }
 
             if (supportsLinks) {
-                try (CloseableStream<Path> s = Files.list(fakeRoot.resolve("dir"))) {
+                try (Stream<Path> s = Files.list(fakeRoot.resolve("dir"))) {
                     String[] result = s.map(path -> path.getFileName().toString())
                                        .toArray(String[]::new);
                     assertEqualsNoOrder(result, new String[] { "d1", "f1", "lnDir2", "SecurityException", "lnDirSE", "lnFileSE" });
@@ -525,13 +524,13 @@
             // execute test
             fsp.setFaultyMode(true);
             // ignore file cause SecurityException
-            try (CloseableStream<Path> s = Files.walk(fakeRoot.resolve("empty"))) {
+            try (Stream<Path> s = Files.walk(fakeRoot.resolve("empty"))) {
                 String[] result = s.map(path -> path.getFileName().toString())
                                    .toArray(String[]::new);
                 assertEqualsNoOrder(result, new String[] { "empty", "sample" });
             }
             // skip folder cause SecurityException
-            try (CloseableStream<Path> s = Files.walk(fakeRoot.resolve("dir2"))) {
+            try (Stream<Path> s = Files.walk(fakeRoot.resolve("dir2"))) {
                 String[] result = s.map(path -> path.getFileName().toString())
                                    .toArray(String[]::new);
                 assertEqualsNoOrder(result, new String[] { "dir2", "file" });
@@ -539,14 +538,14 @@
 
             if (supportsLinks) {
                 // not following links
-                try (CloseableStream<Path> s = Files.walk(fakeRoot.resolve("dir"))) {
+                try (Stream<Path> s = Files.walk(fakeRoot.resolve("dir"))) {
                     String[] result = s.map(path -> path.getFileName().toString())
                                        .toArray(String[]::new);
                     assertEqualsNoOrder(result, new String[] { "dir", "d1", "f1", "lnDir2", "lnDirSE", "lnFileSE" });
                 }
 
                 // following links
-                try (CloseableStream<Path> s = Files.walk(fakeRoot.resolve("dir"), FileVisitOption.FOLLOW_LINKS)) {
+                try (Stream<Path> s = Files.walk(fakeRoot.resolve("dir"), FileVisitOption.FOLLOW_LINKS)) {
                     String[] result = s.map(path -> path.getFileName().toString())
                                        .toArray(String[]::new);
                     // ?? Should fileInSE show up?
@@ -556,19 +555,19 @@
             }
 
             // list instead of walk
-            try (CloseableStream<Path> s = Files.list(fakeRoot.resolve("empty"))) {
+            try (Stream<Path> s = Files.list(fakeRoot.resolve("empty"))) {
                 String[] result = s.map(path -> path.getFileName().toString())
                                    .toArray(String[]::new);
                 assertEqualsNoOrder(result, new String[] { "sample" });
             }
-            try (CloseableStream<Path> s = Files.list(fakeRoot.resolve("dir2"))) {
+            try (Stream<Path> s = Files.list(fakeRoot.resolve("dir2"))) {
                 String[] result = s.map(path -> path.getFileName().toString())
                                    .toArray(String[]::new);
                 assertEqualsNoOrder(result, new String[] { "file" });
             }
 
             // root cause SecurityException should be reported
-            try (CloseableStream<Path> s = Files.walk(
+            try (Stream<Path> s = Files.walk(
                 fakeRoot.resolve("dir2").resolve("SecurityException")))
             {
                 String[] result = s.map(path -> path.getFileName().toString())
@@ -579,7 +578,7 @@
             }
 
             // Walk a file cause SecurityException, we should get SE
-            try (CloseableStream<Path> s = Files.walk(
+            try (Stream<Path> s = Files.walk(
                 fakeRoot.resolve("dir").resolve("SecurityException")))
             {
                 String[] result = s.map(path -> path.getFileName().toString())
@@ -590,7 +589,7 @@
             }
 
             // List a file cause SecurityException, we should get SE as cannot read attribute
-            try (CloseableStream<Path> s = Files.list(
+            try (Stream<Path> s = Files.list(
                 fakeRoot.resolve("dir2").resolve("SecurityException")))
             {
                 String[] result = s.map(path -> path.getFileName().toString())
@@ -600,7 +599,7 @@
                 assertTrue(se.getCause() instanceof FaultyFileSystem.FaultyException);
             }
 
-            try (CloseableStream<Path> s = Files.list(
+            try (Stream<Path> s = Files.list(
                 fakeRoot.resolve("dir").resolve("SecurityException")))
             {
                 String[] result = s.map(path -> path.getFileName().toString())
@@ -627,7 +626,7 @@
     }
 
     public void testConstructException() {
-        try (CloseableStream<String> s = Files.lines(testFolder.resolve("notExist"), Charset.forName("UTF-8"))) {
+        try (Stream<String> s = Files.lines(testFolder.resolve("notExist"), Charset.forName("UTF-8"))) {
             s.forEach(l -> fail("File is not even exist!"));
         } catch (IOException ioe) {
             assertTrue(ioe instanceof NoSuchFileException);
@@ -635,24 +634,26 @@
     }
 
     public void testClosedStream() throws IOException {
-        try (CloseableStream<Path> s = Files.list(testFolder)) {
+        try (Stream<Path> s = Files.list(testFolder)) {
             s.close();
-            Object[] actual = s.sorted(Comparator.naturalOrder()).toArray();
-            assertTrue(actual.length <= level1.length);
-        }
-
-        try (CloseableStream<Path> s = Files.walk(testFolder)) {
-            s.close();
-            Object[] actual = s.sorted(Comparator.naturalOrder()).toArray();
+            Object[] actual = s.sorted().toArray();
             fail("Operate on closed stream should throw IllegalStateException");
         } catch (IllegalStateException ex) {
             // expected
         }
 
-        try (CloseableStream<Path> s = Files.find(testFolder, Integer.MAX_VALUE,
+        try (Stream<Path> s = Files.walk(testFolder)) {
+            s.close();
+            Object[] actual = s.sorted().toArray();
+            fail("Operate on closed stream should throw IllegalStateException");
+        } catch (IllegalStateException ex) {
+            // expected
+        }
+
+        try (Stream<Path> s = Files.find(testFolder, Integer.MAX_VALUE,
                     (p, attr) -> true)) {
             s.close();
-            Object[] actual = s.sorted(Comparator.naturalOrder()).toArray();
+            Object[] actual = s.sorted().toArray();
             fail("Operate on closed stream should throw IllegalStateException");
         } catch (IllegalStateException ex) {
             // expected
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/Arrays/ArraysLambdaTest.java	Wed Aug 14 15:53:13 2013 -0700
@@ -0,0 +1,221 @@
+/*
+ * 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 Lambda unit test for Arrays.
+ * @library /sqeutil
+ * @(#) ArraysTest.java
+ * @author Tristan Yan
+ * @run testng ArraysLambdaTest
+ */
+
+import java.util.Arrays;
+import java.util.Random;
+import static org.testng.Assert.*;
+import org.testng.annotations.Test;
+
+public class ArraysLambdaTest {
+    private final static int ARRAY_SIZE = 1 << 8;
+
+    private final static int MIN_LEN = 1 << 2;
+
+    private final static int MAX_LEN = 1 << 6;
+
+    private final static Random rand = new Random(System.currentTimeMillis());
+
+    private long[] generateLongData(int size) {
+        long[] array = new long[size];
+        for(int i = 0; i < size; i++) {
+            array[i] = rand.nextLong();
+        }
+        return array;
+    }
+
+    private int[] generateIntData(int size) {
+        int[] array = new int[size];
+        for(int i = 0; i < size; i++) {
+            array[i] = rand.nextInt();
+        }
+        return array;
+    }
+
+    private double[] generateDoubleData(int size) {
+        double[] array = new double[size];
+        //Precision could be changed when do parallel calculation, we only use
+        //integer to test it to prevent precision lost issue
+        for(int i = 0; i < size; i++) {
+            array[i] = rand.nextInt(1024);
+        }
+        return array;
+    }
+
+    private String[] generateStringData(int size) {
+        String[] array = new String[size];
+        for(int i = 0; i < size; i++) {
+            array[i] = StringUtilities.randomString(MAX_LEN, MIN_LEN);
+        }
+        return array;
+    }
+
+    private StringBuilder[] generateSBData(int size) {
+        StringBuilder[] array = new StringBuilder[size];
+        for(int i = 0; i < size; i++) {
+            array[i] = new StringBuilder(StringUtilities.randomString(MAX_LEN, MIN_LEN));
+        }
+        return array;
+    }
+
+    @Test
+    public void testParallelPrefixForInt() {
+        int startIndex = rand.nextInt(ARRAY_SIZE);
+        int endIndex = startIndex + rand.nextInt(ARRAY_SIZE + 1 - startIndex);
+
+        int[] intArr1 = generateIntData(ARRAY_SIZE);
+        int[] intArr2 = Arrays.copyOf(intArr1, ARRAY_SIZE);
+        int[] intBackArr = Arrays.copyOf(intArr1, ARRAY_SIZE);
+        Arrays.parallelPrefix(intArr1, LambdaUtilities.addIntBinaryOperator());
+        assertEquals(intArr1.length, intBackArr.length);
+        int totalInt = 0;
+        for(int i = 0; i < ARRAY_SIZE; i++) {
+            totalInt += intBackArr[i];
+            assertEquals(totalInt, intArr1[i]);
+        }
+        Arrays.parallelPrefix(intArr2, startIndex, endIndex, LambdaUtilities.addIntBinaryOperator());
+        totalInt = 0;
+        for(int i = startIndex; i < endIndex; i++) {
+            totalInt += intBackArr[i];
+            assertEquals(totalInt, intArr2[i]);
+        }
+    }
+
+    @Test
+    public void testParallelPrefixForLong() {
+        int startIndex = rand.nextInt(ARRAY_SIZE);
+        int endIndex = startIndex + rand.nextInt(ARRAY_SIZE + 1 - startIndex);
+        long[] longArr1 = generateLongData(ARRAY_SIZE);
+        long[] longArr2 = Arrays.copyOf(longArr1, ARRAY_SIZE);
+        long[] longBackArr = Arrays.copyOf(longArr1, ARRAY_SIZE);
+        Arrays.parallelPrefix(longArr1, LambdaUtilities.addLongBinaryOperator());
+        assertEquals(longArr1.length, longBackArr.length);
+        long totalLong = 0;
+        for(int i = 0; i < ARRAY_SIZE; i++) {
+            totalLong += longBackArr[i];
+            assertEquals(totalLong, longArr1[i]);
+        }
+        Arrays.parallelPrefix(longArr2, startIndex, endIndex, LambdaUtilities.addLongBinaryOperator());
+        totalLong = 0;
+        for(int i = startIndex; i < endIndex; i++) {
+            totalLong += longBackArr[i];
+            assertEquals(totalLong, longArr2[i]);
+        }
+    }
+
+    @Test
+    public void testParallelPrefixForDouble() {
+        int startIndex = rand.nextInt(ARRAY_SIZE);
+        int endIndex = startIndex + rand.nextInt(ARRAY_SIZE + 1 - startIndex);
+        double[] doubleArr1 = generateDoubleData(ARRAY_SIZE);
+        double[] doubleArr2 = Arrays.copyOf(doubleArr1, ARRAY_SIZE);
+        double[] doubleBackArr = Arrays.copyOf(doubleArr1, ARRAY_SIZE);
+        Arrays.parallelPrefix(doubleArr1, LambdaUtilities.addDoubleBinaryOperator());
+        assertEquals(doubleArr1.length, doubleBackArr.length);
+        double totalDouble = 0;
+        for(int i = 0; i < ARRAY_SIZE; i++) {
+            totalDouble += doubleBackArr[i];
+            assertEquals(totalDouble, doubleArr1[i]);
+        }
+        Arrays.parallelPrefix(doubleArr2, startIndex, endIndex, LambdaUtilities.addDoubleBinaryOperator());
+        totalDouble = 0;
+        for(int i = startIndex; i < endIndex; i++) {
+            totalDouble += doubleBackArr[i];
+            assertEquals(totalDouble, doubleArr2[i]);
+        }
+    }
+
+    @Test
+    public void testParallelPrefix() {
+        int startIndex = rand.nextInt(ARRAY_SIZE);
+        int endIndex = startIndex + rand.nextInt(ARRAY_SIZE + 1 - startIndex);
+        StringBuilder[] sbArr1 = generateSBData(ARRAY_SIZE);
+        StringBuilder[] sbArr2 = Arrays.copyOf(sbArr1, ARRAY_SIZE);
+        StringBuilder[] sbBackArr = Arrays.copyOf(sbArr1, ARRAY_SIZE);
+        Arrays.parallelPrefix(sbArr1, LambdaUtilities.appendSBBinaryOperator());
+        assertEquals(sbArr1.length, sbBackArr.length);
+        StringBuilder sbTotal = new StringBuilder();
+        for(int i = 0; i < ARRAY_SIZE; i++) {
+            sbTotal.append(sbBackArr[i]);
+            assertEquals(sbTotal.toString(), sbArr1[i].toString());
+        }
+        Arrays.parallelPrefix(sbArr2, startIndex, endIndex, LambdaUtilities.appendSBBinaryOperator());
+        sbTotal = new StringBuilder();
+        for(int i = startIndex; i < endIndex; i++) {
+            sbTotal.append(sbBackArr[i]);
+            assertEquals(sbTotal.toString(), sbArr2[i].toString());
+        }
+    }
+
+    @Test
+    public void testSetAll() {
+        boolean[] both = new boolean[]{true, false};
+        for(boolean isParallel:both) {
+            //test Arrays.setAll(double[], IntFunction)
+            int[] iArray = new int[ARRAY_SIZE];
+            if (isParallel)
+                Arrays.parallelSetAll(iArray, i -> 2 * i);
+            else
+                Arrays.setAll(iArray, i -> 2 * i);
+            for(int i = 0; i < iArray.length; i++)
+                assertEquals(iArray[i], 2 * i);
+
+            //test Arrays.setAll(long[], IntFunction)
+            long[] lArray = new long[ARRAY_SIZE];
+            if (isParallel)
+                Arrays.parallelSetAll(lArray, i -> (long)i << 32);
+            else
+                Arrays.setAll(lArray, i -> (long)i << 32);
+            for(int i = 0; i < lArray.length; i++)
+                assertEquals(lArray[i] >> 32, i);
+
+            //test Arrays.setAll(double[], IntToDoubleFunction)
+            double[] dArray = new double[ARRAY_SIZE];
+            if (isParallel)
+                Arrays.parallelSetAll(dArray, i -> Math.sin(i));
+            else
+                Arrays.setAll(dArray, i -> Math.sin(i));
+            for(int i = 0; i < dArray.length; i++)
+                assertEquals(dArray[i], Math.sin(i));
+
+            //test Arrays.setAll(T[], IntFunction<? extends T>)
+            //This is a other version of Arrays.copy()
+            String[] sArrExpected = generateStringData(ARRAY_SIZE);
+            String[] sArr = new String[ARRAY_SIZE];
+            if (isParallel)
+                Arrays.parallelSetAll(sArr, i -> sArrExpected[i]);
+            else
+                Arrays.setAll(sArr, i -> sArrExpected[i]);
+            for(int i = 0; i < sArr.length; i++)
+                assertEquals(sArrExpected[i], sArrExpected[i]); 
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/Arrays/ParallelSet.java	Wed Aug 14 15:53:13 2013 -0700
@@ -0,0 +1,157 @@
+/*
+ * 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 test for Arrays.ParallelSet()/set().
+ * @author Tristan Yan
+ * @run testng ParallelSet
+ */
+
+import java.util.Arrays;
+import java.util.function.IntFunction;
+import java.util.function.IntToDoubleFunction;
+import java.util.function.IntToLongFunction;
+import java.util.function.IntUnaryOperator;
+import static org.testng.Assert.*;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+public class ParallelSet {
+    //Array size less than MIN_PARTITION
+    private final static int SMALL_ARRAY_SIZE = 1 << 3;
+    
+    //Array size equals MIN_PARTITION
+    private final static int THRESHOLD_ARRAY_SIZE = 1 << 4;
+
+    //Array size greater than MIN_PARTITION
+    private final static int MEDIUM_ARRAY_SIZE = 1 << 8;
+
+    //Array size much greater than MIN_PARTITION
+    private final static int LARGE_ARRAY_SIZE = 1 << 12;
+    
+    private final static int[] ARRAY_SIZE_COLLECTION  = new int[]{ 
+        SMALL_ARRAY_SIZE, THRESHOLD_ARRAY_SIZE,MEDIUM_ARRAY_SIZE, LARGE_ARRAY_SIZE};
+
+    @DataProvider
+    public static Object[][] intSet(){
+        return genericData("Arrays.parrallelSetAll/setAll(new int[%d],IntUnaryOperator)",
+                int[]::<Integer>new, new IntUnaryOperator[]{i -> i * 2, i -> i * 2 + 1});
+    }
+
+    @DataProvider
+    public static Object[][] longSet(){
+        return genericData("Arrays.parrallelSetAll/setAll(new long[%d],IntToLongeFunction)",
+                long[]::<Integer>new, new IntToLongFunction[]{ i -> i * 2, i -> i * 2 + 1});
+    }
+
+    @DataProvider
+    public static Object[][] doubleSet(){
+        return genericData("Arrays.parallelSetAll/setAll(new double[%d],IntToDoubleFunction)",
+                double[]::<Integer>new, new IntToDoubleFunction[]{i -> i * 2, i -> i * 2 + 1});
+    }
+    
+    @DataProvider
+    public static Object[][] stringSet(){
+        return genericData("Arrays.parallelSetAll/setAll(new String[%d],IntFunction<String>)",
+                String[]::<Integer>new, new IntFunction[]{Integer::toString});
+    }
+
+    private static <T, OPS> Object[][] genericData(String description, IntFunction<T> generateFunc, OPS[] funcs) {
+        //test arrays which size is equals n-1, n, n+1
+        Object[][] data = new Object[ARRAY_SIZE_COLLECTION.length * 3 * funcs.length][4];
+        for(int n = 0; n < ARRAY_SIZE_COLLECTION.length; n++ ) {
+            for(int testValue = -1 ; testValue <= 1; testValue++) {
+                int array_size = ARRAY_SIZE_COLLECTION[n] + testValue;
+                for(int funcN = 0; funcN < funcs.length; funcN++) {
+                    int index = n * 3 * funcs.length + (testValue + 1) * funcs.length + funcN;
+                    data[index][0] = String.format(description, array_size);
+                    data[index][1] = array_size;
+                    data[index][2] = generateFunc;
+                    data[index][3] = funcs[funcN];
+                }
+            }
+        }
+        return data;
+    }
+
+    @Test(dataProvider="intSet")
+    public void testSetAllForInt(String description,int size, IntFunction<int[]> dataFunc, IntUnaryOperator iuo) {
+        int[] expectedResult = dataFunc.apply(size);
+        for(int i = 0; i < size; i++)
+            expectedResult[i] = iuo.applyAsInt(i);
+                
+        int[] sequentialResult = dataFunc.apply(size);
+        Arrays.setAll(sequentialResult, iuo);
+        assertEquals(sequentialResult, expectedResult);
+
+        int[] parallelResult  = dataFunc.apply(size);
+        Arrays.setAll(parallelResult, iuo);
+        assertEquals(sequentialResult, expectedResult);
+    }
+
+    @Test(dataProvider="longSet")
+    public void testSetAllForLong(String description, int size, IntFunction<long[]> dataFunc,  IntToLongFunction itlf) {
+        long[] expectedResult = dataFunc.apply(size);
+        for(int i = 0; i < size; i++)
+            expectedResult[i] = itlf.applyAsLong(i);
+                
+        long[] sequentialResult = dataFunc.apply(size);
+        Arrays.setAll(sequentialResult, itlf);
+        assertEquals(sequentialResult, expectedResult);
+
+        long[] parallelResult  = dataFunc.apply(size);
+        Arrays.setAll(parallelResult, itlf);
+        assertEquals(sequentialResult, expectedResult);
+    }
+
+    @Test(dataProvider="doubleSet")
+    public void testSetAllForDouble(String description,int size, IntFunction<double[]> dataFunc,  IntToDoubleFunction itdf) {
+        double[] expectedResult = dataFunc.apply(size);
+        for(int i = 0; i < size; i++)
+            expectedResult[i] = itdf.applyAsDouble(i);
+                
+        double[] sequentialResult = dataFunc.apply(size);
+        Arrays.setAll(sequentialResult, itdf);
+        assertEquals(sequentialResult, expectedResult);
+
+        double[] parallelResult  = dataFunc.apply(size);
+        Arrays.setAll(parallelResult, itdf);
+        assertEquals(sequentialResult, expectedResult);
+    }
+
+    @Test(dataProvider="stringSet")
+    public void testSetAllForString(String description,int size, IntFunction<String[]> dataFunc,  IntFunction<String> itsf) {
+        String[] expectedResult = dataFunc.apply(size);
+        for(int i = 0; i < size; i++)
+            expectedResult[i] = itsf.apply(i);
+                
+        String[] sequentialResult = dataFunc.apply(size);
+        Arrays.setAll(sequentialResult, itsf);
+        assertEquals(sequentialResult, expectedResult);
+
+        String[] parallelResult  = dataFunc.apply(size);
+        Arrays.setAll(parallelResult, itsf);
+        assertEquals(sequentialResult, expectedResult);
+    }
+}
--- a/test/java/util/Arrays/SetAllTest.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/test/java/util/Arrays/SetAllTest.java	Wed Aug 14 15:53:13 2013 -0700
@@ -167,13 +167,13 @@
     public void testStringSetNulls() {
         String[] ar = new String[2];
         try {
-            Arrays.setAll(null, i -> "X");
+            Arrays.setAll(null, (IntFunction<String>) i -> "X");
             fail("Arrays.setAll(null, foo) should throw NPE");
         } catch (NullPointerException npe) {
             // expected
         }
         try {
-            Arrays.parallelSetAll(null, i -> "X");
+            Arrays.parallelSetAll(null, (IntFunction<String>) i -> "X");
             fail("Arrays.parallelSetAll(null, foo) should throw NPE");
         } catch (NullPointerException npe) {
             // expected
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/Collection/IntRemovePredicateAllTest.java	Wed Aug 14 15:53:13 2013 -0700
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @summary sanity tests for Collection.removeIf()/forEach()
+ * @library /sqeutil
+ * @(#) IntRemovePredicateAllTest.java
+ * @author Tristan Yan
+ * @run testng IntRemovePredicateAllTest
+ */
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.util.*;
+import java.util.concurrent.*;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Predicate;
+import static org.testng.Assert.*;
+import org.testng.annotations.Factory;
+import org.testng.annotations.Test;
+
+public class IntRemovePredicateAllTest <T extends Collection<Integer>> {
+    private final static Random rand = new Random(System.currentTimeMillis());
+
+    //1K data is best we can optimize for now.
+    private final static int MAX_SIZE = 1 << 10;
+
+    //At least we should have 4 elements in the list
+    private final static int MIN_SIZE = 1 << 2;
+
+    T t;
+
+    public IntRemovePredicateAllTest(T typeObject1){
+        t = typeObject1;
+    }
+
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    private static Collection<Integer>
+        generateData(Class<? extends Collection<Integer>> cls,
+            int... initValue) throws InstantiationException,
+            IllegalAccessException, NoSuchMethodException,
+            IllegalArgumentException, InvocationTargetException{
+        Collection<Integer> c;
+        int t1Size = 0;
+        if(initValue.length == 0) {
+            c = cls.newInstance();
+            t1Size= rand.nextInt(MAX_SIZE);
+            if(t1Size < MIN_SIZE) t1Size = MIN_SIZE;
+        } else {
+            Constructor con = cls.getConstructor(int.class);
+            c = (Collection<Integer>)con.newInstance(initValue[0]);
+            t1Size = initValue.length == 2 ? initValue[1] : initValue[0];
+        }
+        for(int i = 0; i < t1Size; i++)
+            c.add(rand.nextInt());
+        return c;
+    }
+
+    @Factory
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    public static Object[] create() throws Exception{
+        List<IntRemovePredicateAllTest> result = new ArrayList<>();
+        Class[] defaultConstructorClazz = {
+            (Class<ArrayDeque<Integer>>)(Class<?>)(ArrayDeque.class),
+            (Class<ArrayList<Integer>>)(Class<?>)(ArrayList.class),
+            (Class<ConcurrentLinkedDeque<Integer>>)(Class<?>)(ConcurrentLinkedDeque.class),
+            (Class<ConcurrentLinkedQueue<Integer>>)(Class<?>)(ConcurrentLinkedQueue.class),
+            (Class<ConcurrentSkipListSet<Integer>>)(Class<?>)(ConcurrentSkipListSet.class),
+            (Class<HashSet<Integer>>)(Class<?>)(HashSet.class),
+            (Class<LinkedBlockingDeque<Integer>>)(Class<?>)(LinkedBlockingDeque.class),
+            (Class<LinkedBlockingQueue<Integer>>)(Class<?>)(LinkedBlockingQueue.class),
+            (Class<LinkedHashSet<Integer>>)(Class<?>)(LinkedHashSet.class),
+            (Class<LinkedList<Integer>>)(Class<?>)(LinkedList.class),
+            (Class<LinkedTransferQueue<Integer>>)(Class<?>)(LinkedTransferQueue.class),
+            (Class<PriorityBlockingQueue<Integer>>)(Class<?>)(PriorityBlockingQueue.class),
+            (Class<PriorityQueue<Integer>>)(Class<?>)(PriorityQueue.class),
+            (Class<Stack<Integer>>)(Class<?>)(Stack.class),
+            (Class<TreeSet<Integer>>)(Class<?>)(TreeSet.class),
+            (Class<Vector<Integer>>)(Class<?>)(Vector.class)
+        };
+
+        Class[] capacityConstructorClazz = {
+            (Class<ArrayBlockingQueue<Integer>>)(Class<?>)(ArrayBlockingQueue.class),
+            (Class<ArrayDeque<Integer>>)(Class<?>)(ArrayDeque.class),
+            (Class<ArrayList<Integer>>)(Class<?>)(ArrayList.class),
+            (Class<HashSet<Integer>>)(Class<?>)(HashSet.class),
+            (Class<LinkedBlockingDeque<Integer>>)(Class<?>)(LinkedBlockingDeque.class),
+            (Class<LinkedBlockingQueue<Integer>>)(Class<?>)(LinkedBlockingQueue.class),
+            (Class<LinkedHashSet<Integer>>)(Class<?>)(LinkedHashSet.class),
+            (Class<PriorityBlockingQueue<Integer>>)(Class<?>)(PriorityBlockingQueue.class),
+            (Class<PriorityQueue<Integer>>)(Class<?>)(PriorityQueue.class),
+            (Class<Vector<Integer>>)(Class<?>)(Vector.class)
+        };
+
+        for(int i = 0; i < defaultConstructorClazz.length
+                + capacityConstructorClazz.length; i++) {
+            int initSize1 = rand.nextInt(MAX_SIZE);
+            if(initSize1 < MIN_SIZE) initSize1 = MIN_SIZE;
+            Collection<Integer> c = i < defaultConstructorClazz.length ?
+                generateData(defaultConstructorClazz[i]) :
+                generateData(capacityConstructorClazz[i - defaultConstructorClazz.length],
+                    initSize1);
+            result.add(new IntRemovePredicateAllTest(c));
+        }
+        return result.toArray();
+    }
+
+    @Test
+    public void testRemoveIf() {
+        int limit = rand.nextInt();
+        boolean isUP = rand.nextBoolean();
+        Predicate<Integer> p = LambdaUtilities.randomIntegerPredicate(isUP, limit);
+        t.removeIf(p);
+        assertTrue(verifyMatch(t, limit, !isUP, true));
+    }
+
+    @Test
+    public void testForEach() {
+        final AtomicInteger accumulator = new AtomicInteger(0);
+        t.forEach(t -> accumulator.addAndGet(t));
+
+        Optional<Integer> opi = t.stream().reduce((i1, i2) -> i1 + i2);
+        assertTrue(opi.isPresent());
+        assertEquals(accumulator.get(), opi.get().intValue());
+    }
+
+    private boolean verifyMatch(Collection<Integer> c, int limit, boolean isUP,
+            boolean all) {
+        Iterator<Integer> it = c.iterator();
+        while(it.hasNext()) {
+            int current = it.next();
+            if(isUP) {
+                if(all) {
+                    if(current < limit) return false;
+                } else {
+                    if(current >= limit) return true;
+                }
+            } else {
+                if(all) {
+                    if(current >= limit) return false;
+                } else {
+                    if(current < limit) return true;
+                }
+            }
+        }
+        return all;
+    }
+}
--- a/test/java/util/Collection/MOAT.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/test/java/util/Collection/MOAT.java	Wed Aug 14 15:53:13 2013 -0700
@@ -51,10 +51,29 @@
  * simultaneously test all other implementations.
  */
 
-import java.io.*;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.NotSerializableException;
+import java.io.Serializable;
 import java.util.*;
 import java.util.concurrent.*;
-import static java.util.Collections.*;
+import java.util.function.*;
+
+import static java.util.Collections.EMPTY_LIST;
+import static java.util.Collections.EMPTY_MAP;
+import static java.util.Collections.EMPTY_SET;
+import static java.util.Collections.emptyList;
+import static java.util.Collections.emptyMap;
+import static java.util.Collections.emptySet;
+import static java.util.Collections.nCopies;
+import static java.util.Collections.singleton;
+import static java.util.Collections.singletonList;
+import static java.util.Collections.singletonMap;
+import static java.util.Collections.unmodifiableList;
 
 public class MOAT {
     public static void realMain(String[] args) {
@@ -118,9 +137,9 @@
         testCollection(emptyArray);
         testEmptyList(emptyArray);
         THROWS(IndexOutOfBoundsException.class,
-               new Fun(){void f(){ emptyArray.set(0,1); }});
+               new Fun(){public void f(){ emptyArray.set(0,1); }});
         THROWS(UnsupportedOperationException.class,
-               new Fun(){void f(){ emptyArray.add(0,1); }});
+               new Fun(){public void f(){ emptyArray.add(0,1); }});
 
         List<Integer> noOne = nCopies(0,1);
         testCollection(noOne);
@@ -205,11 +224,11 @@
             check(! it.hasNext());
 
         THROWS(NoSuchElementException.class,
-               new Fun(){void f(){ it.next(); }});
+               new Fun(){public void f(){ it.next(); }});
 
         try { it.remove(); }
-        catch (IllegalStateException _) { pass(); }
-        catch (UnsupportedOperationException _) { pass(); }
+        catch (IllegalStateException pass) { pass(); }
+        catch (UnsupportedOperationException pass) { pass(); }
         catch (Throwable t) { unexpected(t); }
 
         if (rnd.nextBoolean())
@@ -232,15 +251,15 @@
 
     private static void testImmutableCollection(final Collection<Integer> c) {
         THROWS(UnsupportedOperationException.class,
-               new Fun(){void f(){ c.add(99); }},
-               new Fun(){void f(){ c.addAll(singleton(99)); }});
+               new Fun(){public void f(){ c.add(99); }},
+               new Fun(){public void f(){ c.addAll(singleton(99)); }});
         if (! c.isEmpty()) {
             final Integer first = c.iterator().next();
             THROWS(UnsupportedOperationException.class,
-                   new Fun(){void f(){ c.clear(); }},
-                   new Fun(){void f(){ c.remove(first); }},
-                   new Fun(){void f(){ c.removeAll(singleton(first)); }},
-                   new Fun(){void f(){ c.retainAll(emptyList()); }}
+                   new Fun(){public void f(){ c.clear(); }},
+                   new Fun(){public void f(){ c.remove(first); }},
+                   new Fun(){public void f(){ c.removeAll(singleton(first)); }},
+                   new Fun(){public void f(){ c.retainAll(emptyList()); }}
                    );
         }
     }
@@ -253,15 +272,15 @@
         testList(c);
         testImmutableCollection(c);
         THROWS(UnsupportedOperationException.class,
-               new Fun(){void f(){ c.set(0,42); }},
-               new Fun(){void f(){ c.add(0,42); }},
-               new Fun(){void f(){ c.addAll(0,singleton(86)); }});
+               new Fun(){public void f(){ c.set(0,42); }},
+               new Fun(){public void f(){ c.add(0,42); }},
+               new Fun(){public void f(){ c.addAll(0,singleton(86)); }});
         if (! c.isEmpty())
             THROWS(UnsupportedOperationException.class,
-                   new Fun(){void f(){
+                   new Fun(){public void f(){
                            Iterator<Integer> it = c.iterator();
                            it.next(); it.remove();}},
-                   new Fun(){void f(){
+                   new Fun(){public void f(){
                            ListIterator<Integer> it = c.listIterator();
                            it.next(); it.remove();}});
     }
@@ -281,28 +300,28 @@
         testEmptyCollection(m.values());
 
         try { check(! m.containsValue(null)); }
-        catch (NullPointerException _) { /* OK */ }
+        catch (NullPointerException pass) { /* OK */ }
         try { check(! m.containsKey(null)); }
-        catch (NullPointerException _) { /* OK */ }
+        catch (NullPointerException pass) { /* OK */ }
         check(! m.containsValue(1));
         check(! m.containsKey(1));
     }
 
     private static void testImmutableMap(final Map<Integer,Integer> m) {
         THROWS(UnsupportedOperationException.class,
-               new Fun(){void f(){ m.put(1,1); }},
-               new Fun(){void f(){ m.putAll(singletonMap(1,1)); }});
+               new Fun(){public void f(){ m.put(1,1); }},
+               new Fun(){public void f(){ m.putAll(singletonMap(1,1)); }});
         if (! m.isEmpty()) {
             final Integer first = m.keySet().iterator().next();
             THROWS(UnsupportedOperationException.class,
-                   new Fun(){void f(){ m.remove(first); }},
-                   new Fun(){void f(){ m.clear(); }});
+                   new Fun(){public void f(){ m.remove(first); }},
+                   new Fun(){public void f(){ m.clear(); }});
             final Map.Entry<Integer,Integer> me
                 = m.entrySet().iterator().next();
             Integer key = me.getKey();
             Integer val = me.getValue();
             THROWS(UnsupportedOperationException.class,
-                   new Fun(){void f(){ me.setValue(3); }});
+                   new Fun(){public void f(){ me.setValue(3); }});
             equal(key, me.getKey());
             equal(val, me.getValue());
         }
@@ -494,9 +513,9 @@
             // insert, query, remove element at head
             if (isEmpty) {
                 THROWS(NoSuchElementException.class,
-                       new Fun(){void f(){ deq.getFirst(); }},
-                       new Fun(){void f(){ deq.element(); }},
-                       new Fun(){void f(){ deq.iterator().next(); }});
+                       new Fun(){public void f(){ deq.getFirst(); }},
+                       new Fun(){public void f(){ deq.element(); }},
+                       new Fun(){public void f(){ deq.iterator().next(); }});
                 check(deq.peekFirst() == null);
                 check(deq.peek() == null);
             } else {
@@ -548,9 +567,9 @@
             }
             if (isEmpty) {
                 THROWS(NoSuchElementException.class,
-                       new Fun(){void f(){ deq.getFirst(); }},
-                       new Fun(){void f(){ deq.element(); }},
-                       new Fun(){void f(){ deq.iterator().next(); }});
+                       new Fun(){public void f(){ deq.getFirst(); }},
+                       new Fun(){public void f(){ deq.element(); }},
+                       new Fun(){public void f(){ deq.iterator().next(); }});
                 check(deq.peekFirst() == null);
                 check(deq.peek() == null);
             } else {
@@ -574,7 +593,7 @@
             if (isEmpty) {
                 check(deq.peekLast() == null);
                 THROWS(NoSuchElementException.class,
-                       new Fun(){void f(){ deq.getLast(); }});
+                       new Fun(){public void f(){ deq.getLast(); }});
             } else {
                 check(deq.peekLast() != e);
                 check(deq.getLast() != e);
@@ -618,7 +637,7 @@
             if (isEmpty) {
                 check(deq.peekLast() == null);
                 THROWS(NoSuchElementException.class,
-                       new Fun(){void f(){ deq.getLast(); }});
+                       new Fun(){public void f(){ deq.getLast(); }});
             } else {
                 check(deq.peekLast() != e);
                 check(deq.getLast() != e);
@@ -651,17 +670,17 @@
             if (isList) {
                 check(!asList.listIterator().hasPrevious());
                 THROWS(NoSuchElementException.class,
-                       new Fun(){void f(){ asList.listIterator().previous(); }});
+                       new Fun(){public void f(){ asList.listIterator().previous(); }});
             }
             THROWS(NoSuchElementException.class,
-                   new Fun(){void f(){ deq.iterator().next(); }},
-                   new Fun(){void f(){ deq.element(); }},
-                   new Fun(){void f(){ deq.getFirst(); }},
-                   new Fun(){void f(){ deq.getLast(); }},
-                   new Fun(){void f(){ deq.pop(); }},
-                   new Fun(){void f(){ deq.remove(); }},
-                   new Fun(){void f(){ deq.removeFirst(); }},
-                   new Fun(){void f(){ deq.removeLast(); }});
+                   new Fun(){public void f(){ deq.iterator().next(); }},
+                   new Fun(){public void f(){ deq.element(); }},
+                   new Fun(){public void f(){ deq.getFirst(); }},
+                   new Fun(){public void f(){ deq.getLast(); }},
+                   new Fun(){public void f(){ deq.pop(); }},
+                   new Fun(){public void f(){ deq.remove(); }},
+                   new Fun(){public void f(){ deq.removeFirst(); }},
+                   new Fun(){public void f(){ deq.removeLast(); }});
 
             check(deq.poll() == null);
             check(deq.pollFirst() == null);
@@ -713,8 +732,8 @@
             l.addAll(-1, Collections.<Integer>emptyList());
             fail("Expected IndexOutOfBoundsException not thrown");
         }
-        catch (UnsupportedOperationException _) {/* OK */}
-        catch (IndexOutOfBoundsException _) {/* OK */}
+        catch (UnsupportedOperationException pass) {/* OK */}
+        catch (IndexOutOfBoundsException pass) {/* OK */}
         catch (Throwable t) { unexpected(t); }
 
 //      equal(l instanceof Serializable,
@@ -789,12 +808,7 @@
             catch (Throwable t) { unexpected(t); }
 
             oneElement(c);
-            try {
-                c.removeAll(null);
-                fail("Expected NullPointerException");
-            }
-            catch (NullPointerException e) { pass(); }
-            catch (Throwable t) { unexpected(t); }
+            THROWS( NullPointerException.class, (Fun) () -> { c.removeAll((Collection<?>)null);});
 
             clear(c);
             try {
@@ -805,28 +819,16 @@
             catch (Throwable t) { unexpected(t); }
 
             oneElement(c);
-            try {
-                c.retainAll(null);
-                fail("Expected NullPointerException");
-            }
-            catch (NullPointerException e) { pass(); }
-            catch (Throwable t) { unexpected(t); }
+            THROWS( NullPointerException.class, (Fun) () -> {c.retainAll((Collection<?>)null);});
 
             oneElement(c);
-            try {
-                c.addAll(null);
-                fail("Expected NullPointerException");
-            }
-            catch (NullPointerException e) { pass(); }
-            catch (Throwable t) { unexpected(t); }
+            THROWS( NullPointerException.class, (Fun) () -> {c.addAll((Collection<Integer>)null);});
 
             oneElement(c);
-            try {
-                c.containsAll(null);
-                fail("Expected NullPointerException");
-            }
-            catch (NullPointerException e) { pass(); }
-            catch (Throwable t) { unexpected(t); }
+            THROWS( NullPointerException.class, (Fun) () -> {c.containsAll((Collection<?>)null);});
+
+            oneElement(c);
+            THROWS( NullPointerException.class, (Fun) () -> {c.removeIf((Predicate<Integer>)null);});
         }
     }
 
@@ -984,22 +986,22 @@
             ? (ConcurrentMap<T,Integer>) m
             : null;
         List<Fun> fs = new ArrayList<Fun>();
-        fs.add(new Fun(){void f(){ check(! m.containsKey(null));}});
-        fs.add(new Fun(){void f(){ equal(m.remove(null), null);}});
-        fs.add(new Fun(){void f(){ equal(m.get(null), null);}});
+        fs.add(() -> { check(! m.containsKey(null));});
+        fs.add(new Fun(){public void f(){ equal(m.remove(null), null);}});
+        fs.add(new Fun(){public void f(){ equal(m.get(null), null);}});
         if (cm != null) {
-            fs.add(new Fun(){void f(){ check(! cm.remove(null,null));}});}
+            fs.add(new Fun(){public void f(){ check(! cm.remove(null,null));}});}
         throwsConsistently(NullPointerException.class, fs);
 
         fs.clear();
         final Map<T,Integer> sm = singletonMap(null,1);
-        fs.add(new Fun(){void f(){ equal(m.put(null,1), null); m.clear();}});
-        fs.add(new Fun(){void f(){ m.putAll(sm); m.clear();}});
+        fs.add(new Fun(){public void f(){ equal(m.put(null,1), null); m.clear();}});
+        fs.add(new Fun(){public void f(){ m.putAll(sm); m.clear();}});
         if (cm != null) {
-            fs.add(new Fun(){void f(){ check(! cm.remove(null,null));}});
-            fs.add(new Fun(){void f(){ equal(cm.putIfAbsent(null,1), 1);}});
-            fs.add(new Fun(){void f(){ equal(cm.replace(null,1), null);}});
-            fs.add(new Fun(){void f(){ equal(cm.replace(null,1, 1), 1);}});
+            fs.add(new Fun(){public void f(){ check(! cm.remove(null,null));}});
+            fs.add(new Fun(){public void f(){ equal(cm.putIfAbsent(null,1), 1);}});
+            fs.add(new Fun(){public void f(){ equal(cm.replace(null,1), null);}});
+            fs.add(new Fun(){public void f(){ equal(cm.replace(null,1, 1), 1);}});
         }
         throwsConsistently(NullPointerException.class, fs);
     }
@@ -1161,7 +1163,7 @@
             equalNext(it, 1);
             check(! it.hasNext());
             THROWS(NoSuchElementException.class,
-                   new Fun(){void f(){it.next();}});
+                   new Fun(){public void f(){it.next();}});
         }
 
         {
@@ -1172,7 +1174,7 @@
             check(it.hasNext()); equal(it.next().getKey(), 1);
             check(! it.hasNext());
             THROWS(NoSuchElementException.class,
-                   new Fun(){void f(){it.next();}});
+                   new Fun(){public void f(){it.next();}});
         }
     }
 
@@ -1206,7 +1208,7 @@
             equalNext(it, 1);
             check(! it.hasNext());
             THROWS(NoSuchElementException.class,
-                   new Fun(){void f(){it.next();}});
+                   new Fun(){public void f(){it.next();}});
         }
     }
 
@@ -1227,7 +1229,7 @@
         System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
         if (failed > 0) throw new Exception("Some tests failed");
     }
-    private static abstract class Fun {abstract void f() throws Throwable;}
+    private interface Fun {void f() throws Throwable;}
     private static void THROWS(Class<? extends Throwable> k, Fun... fs) {
           for (Fun f : fs)
               try { f.f(); fail("Expected " + k.getName() + " not thrown"); }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/Collections/Wrappers.java	Wed Aug 14 15:53:13 2013 -0700
@@ -0,0 +1,132 @@
+/*
+ * 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 Unit tests for wrapping classes should delegate to default methods
+ */
+
+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<Object[]> cases = new ArrayList<>();
+        LinkedList<Integer> seedList = new LinkedList<>();
+        TreeSet<Integer> seedSet = new TreeSet<>();
+        TreeMap<Integer, Integer> seedMap = new TreeMap<>();
+
+        for (int i = 1; i <= 10; i++) {
+            seedList.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.unmodifiableSet(seedSet) });
+        cases.add(new Object[] { Collections.unmodifiableSortedSet(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() });
+
+        // Synchronized
+        cases.add(new Object[] { Collections.synchronizedCollection(seedList) });
+        cases.add(new Object[] { Collections.synchronizedList(seedList) });
+        cases.add(new Object[] { Collections.synchronizedSet(seedSet) });
+        cases.add(new Object[] { Collections.synchronizedSortedSet(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() });
+
+        // Checked
+        cases.add(new Object[] { Collections.checkedCollection(seedList, Integer.class) });
+        cases.add(new Object[] { Collections.checkedList(seedList, 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.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 {
+        ArrayList<Method> 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());
+        }
+    }
+}
+
--- a/test/java/util/Comparator/BasicTest.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/test/java/util/Comparator/BasicTest.java	Wed Aug 14 15:53:13 2013 -0700
@@ -211,8 +211,8 @@
     };
 
     public void testComparatorDefaultMethods() {
-        Comparator<People> cmp = Comparator.comparing((Function<People, String>) People::getFirstName);
-        Comparator<People> cmp2 = Comparator.comparing((Function<People, String>) People::getLastName);
+        Comparator<People> cmp = Comparator.comparing(People::getFirstName);
+        Comparator<People> cmp2 = Comparator.comparing(People::getLastName);
         // reverseOrder
         assertComparison(cmp.reversed(), people[1], people[0]);
         // thenComparing(Comparator)
@@ -235,7 +235,7 @@
 
     public void testNullsFirst() {
         Comparator<String> strcmp = Comparator.nullsFirst(Comparator.naturalOrder());
-        Comparator<People> cmp = Comparator.<People, String>comparing(People::getLastName, strcmp)
+        Comparator<People> 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 @@
         assertComparison(cmp, people[7], people[6]);
 
         // More than one thenComparing
-        strcmp = Comparator.nullsFirst(Comparator.comparing((ToIntFunction<String>) String::length)
+        strcmp = Comparator.nullsFirst(Comparator.comparing(String::length)
                                                  .thenComparing(String.CASE_INSENSITIVE_ORDER));
         assertComparison(strcmp, null, "abc");
         assertComparison(strcmp, "ab", "abc");
@@ -273,7 +273,7 @@
 
     public void testNullsLast() {
         Comparator<String> strcmp = Comparator.nullsLast(Comparator.naturalOrder());
-        Comparator<People> cmp = Comparator.<People, String>comparing(People::getLastName, strcmp)
+        Comparator<People> 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 @@
         assertComparison(cmp, people[7], people[6]);
 
         // More than one thenComparing
-        strcmp = Comparator.nullsLast(Comparator.comparing((ToIntFunction<String>) String::length)
+        strcmp = Comparator.nullsLast(Comparator.comparing(String::length)
                                                 .thenComparing(String.CASE_INSENSITIVE_ORDER));
         assertComparison(strcmp, "abc", null);
         assertComparison(strcmp, "ab", "abc");
@@ -345,7 +345,7 @@
             fail("comparing(null, cmp) should throw NPE");
         } catch (NullPointerException npe) {}
         try {
-            Comparator<People> cmp = Comparator.comparing((Function<People, String>) People::getFirstName, null);
+            Comparator<People> cmp = Comparator.comparing(People::getFirstName, null);
             fail("comparing(f, null) should throw NPE");
         } catch (NullPointerException npe) {}
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/List/ExtensionsTest.java	Wed Aug 14 15:53:13 2013 -0700
@@ -0,0 +1,211 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @summary Basic tests for List's extension methods
+ * @library /sqeutil
+ * @(#) ListTest.java
+ * @author Tristan Yan
+ * @run testng ExtensionsTest
+ */
+
+import java.util.*;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.stream.Stream;
+import static org.testng.Assert.*;
+import org.testng.annotations.*;
+
+public class ExtensionsTest<T extends List<Integer>> {
+    protected Class<T> typeObject;
+
+    protected boolean hasIni;
+
+    protected int initSize;
+
+    protected final static int START = -1 << 6;
+
+    protected final static int END = 1 << 6;
+
+    protected final static Random rand = new Random(System.currentTimeMillis());
+
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    protected static Class[] defaultConstructorClazz = {
+        (Class<ArrayList<Integer>>)(Class<?>)(ArrayList.class),
+        (Class<CopyOnWriteArrayList<Integer>>)(Class<?>)(CopyOnWriteArrayList.class),
+        (Class<LinkedList<Integer>>)(Class<?>)(LinkedList.class),
+        (Class<Stack<Integer>>)(Class<?>)(Stack.class),
+        (Class<Vector<Integer>>)(Class<?>)(Vector.class)
+    };
+
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    protected static Class[] capacityConstructorClazz = {
+        (Class<ArrayList<Integer>>)(Class<?>)(ArrayList.class),
+        (Class<Vector<Integer>>)(Class<?>)(Vector.class)
+    };
+
+    public ExtensionsTest(Class<T> clazz, int... initSizes){
+        this.typeObject = clazz;
+        assert(initSizes.length <= 1);
+        if(initSizes.length == 1) {
+            hasIni = true;
+            this.initSize = initSizes[0];
+        }
+    }
+
+    protected List<Integer> generateList(int start, int end, int size)
+            throws Exception{
+        List<Integer> list =  hasIni ?
+            (List<Integer>)LambdaUtilities.create(typeObject, initSize) :
+            (List<Integer>)LambdaUtilities.create(typeObject);
+        for(int i = 0; i < size; i++) {
+            int element = start + rand.nextInt(end - start);
+            list.add(element);
+        }
+        return list;
+    }
+
+    protected List<Integer> generateList(int start, int end) throws Exception{
+        return generateList(start, end, end - start);
+    }
+
+    @Factory
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    public static Object[] create(){
+        List<ExtensionsTest> result = new ArrayList<>();
+        Stream<Class> stream1 = Arrays.stream(defaultConstructorClazz);
+        Stream<Class> stream2 = Arrays.stream(capacityConstructorClazz);
+        stream1.forEach(clazz -> result.add(new ExtensionsTest(clazz)));
+        stream2.forEach(clazz -> result.add(new ExtensionsTest(clazz,
+                END - START + rand.nextInt(END - START))));
+        return result.toArray();
+    }
+
+    @Test
+    public void testReplaceAll() throws Exception {
+        List<Integer> list = generateList(START, END);
+        List<Integer> listCloned =  hasIni ?
+            (List<Integer>)LambdaUtilities.create(typeObject, initSize) :
+            (List<Integer>)LambdaUtilities.create(typeObject);
+        listCloned.addAll(list);
+        EnumSet<LambdaUtilities.IntOp> set = EnumSet.allOf(LambdaUtilities.IntOp.class);
+        LambdaUtilities.IntOp[] ops = new LambdaUtilities.IntOp[set.size()];
+        set.toArray(ops);
+        LambdaUtilities.IntOp op = ops[rand.nextInt(ops.length)];
+        int value = START + rand.nextInt(END - START);
+        if( op == LambdaUtilities.IntOp.DIVIDE || op == LambdaUtilities.IntOp.MOD)
+            while(value == 0)
+                value = START + rand.nextInt(END - START);
+        list.replaceAll(LambdaUtilities.opIntegerUnaryOperator(op, value));
+        checkReplace(listCloned, list, op, value);
+    }
+
+    @Test
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    public void testSort() throws Exception{
+        Comparator[] cs = { Comparator.<Integer>naturalOrder(),
+            Comparator.<Integer>reverseOrder(),
+            Comparator.comparing(LambdaUtilities.highestPosValueIntFunction() ),
+            Comparator.comparing(LambdaUtilities.lowestPosValueIntFunction() ),
+        };
+
+        Iterator<Comparator> csit = Arrays.stream(cs).iterator();
+        while(csit.hasNext())
+            testComparator((Comparator<Integer>)csit.next());
+    }
+
+    @Test
+    public void testRemoveAll() throws Exception {
+        List<Integer> list = generateList(START, END);
+        int limit = rand.nextInt(2 * (END - START)) + 2 * START;
+        boolean isUP = rand.nextBoolean();
+        list.removeIf(LambdaUtilities.randomIntegerPredicate(isUP, limit));
+        assertTrue(verifyMatch(list, limit, !isUP, true));
+    }
+
+    @Test
+    public void testForEach() throws Exception {
+        List<Integer> list = generateList(START, END);
+        List<Integer> listCloned =  hasIni ?
+            (List<Integer>)LambdaUtilities.create(typeObject, initSize) :
+            (List<Integer>)LambdaUtilities.create(typeObject);
+        list.forEach(LambdaUtilities.copyConsumer(listCloned));
+        assertEquals(list, listCloned);
+    }
+    private void checkReplace(List<Integer> orig, List<Integer> replaced,
+            LambdaUtilities.IntOp op, int value) {
+        assertEquals(orig.size(), replaced.size());
+        for(int index = 0; index < orig.size(); index++)
+            switch(op) {
+                case ADD:
+                    assertTrue(orig.get(index) + value == replaced.get(index));
+                    break;
+                case SUBTRACT:
+                    assertTrue(orig.get(index) - value == replaced.get(index));
+                    break;
+                case MULTIPLY:
+                    assertTrue(orig.get(index) * value == replaced.get(index));
+                    break;
+                case DIVIDE:
+                    assertTrue(orig.get(index) / value == replaced.get(index));
+                    break;
+                default:
+                    assertTrue(orig.get(index) % value == replaced.get(index));
+                    break;
+            }
+    }
+
+    private void testComparator(Comparator<Integer> c) throws Exception {
+        List<Integer> list = generateList(START, END);
+        List<Integer> listCloned =  hasIni ?
+            (List<Integer>)LambdaUtilities.create(typeObject, initSize) :
+            (List<Integer>)LambdaUtilities.create(typeObject);
+        listCloned.addAll(list);
+        list.sort(c);
+        for(int i = 0; i < list.size() - 1; i++)
+            assertTrue(c.compare(list.get(i), list.get(i+1)) <= 0);
+        //assertEquals(list, listCloned);
+    }
+
+    private boolean verifyMatch(Collection<Integer> c, int limit, boolean isUP,
+            boolean all) {
+        Iterator<Integer> it = c.iterator();
+        while(it.hasNext()) {
+            int current = it.next();
+            if(isUP) {
+                if(all) {
+                    if(current < limit) return false;
+                } else {
+                    if(current >= limit) return true;
+                }
+            } else {
+                if(all) {
+                    if(current >= limit) return false;
+                } else {
+                    if(current < limit) return true;
+                }
+            }
+        }
+        return all;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/List/SortAndReplaceAllTest.java	Wed Aug 14 15:53:13 2013 -0700
@@ -0,0 +1,189 @@
+/*
+ * 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 test for List default methods replaceAll() and sort();
+ * @(#) SortAndReplaceAllTest.java
+ * @library /sqeutil
+ * @author Tristan Yan
+ * @run testng SortAndReplaceAllTest
+ */
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.EnumSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Random;
+import java.util.Stack;
+import java.util.Vector;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.function.Function;
+import java.util.stream.Stream;
+import static org.testng.Assert.*;
+import org.testng.annotations.Factory;
+import org.testng.annotations.Test;
+
+public class SortAndReplaceAllTest <T extends List<Integer>>{
+    protected Class<T> typeObject;
+
+    protected boolean hasIni;
+
+    protected int initSize;
+
+    protected final static int START = -1 << 6;
+
+    protected final static int END = 1 << 6;
+
+    protected final static Random rand = new Random(System.currentTimeMillis());
+
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    protected static Class[] defaultConstructorClazz = {
+        (Class<ArrayList<Integer>>)(Class<?>)(ArrayList.class),
+        (Class<CopyOnWriteArrayList<Integer>>)(Class<?>)(CopyOnWriteArrayList.class),
+        (Class<LinkedList<Integer>>)(Class<?>)(LinkedList.class),
+        (Class<Stack<Integer>>)(Class<?>)(Stack.class),
+        (Class<Vector<Integer>>)(Class<?>)(Vector.class)
+    };
+
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    protected static Class[] capacityConstructorClazz = {
+        (Class<ArrayList<Integer>>)(Class<?>)(ArrayList.class),
+        (Class<Vector<Integer>>)(Class<?>)(Vector.class)
+    };
+
+    public SortAndReplaceAllTest(Class<T> clazz, int... initSizes){
+        this.typeObject = clazz;
+        assert(initSizes.length <= 1);
+        if(initSizes.length == 1) {
+            hasIni = true;
+            this.initSize = initSizes[0];
+        }
+    }
+
+    private List<Integer> generateList(int start, int end, int size)
+            throws Exception{
+        List<Integer> list =  hasIni ?
+            (List<Integer>)LambdaUtilities.create(typeObject, initSize) :
+            (List<Integer>)LambdaUtilities.create(typeObject);
+        for(int i = 0; i < size; i++) {
+            int element = start + rand.nextInt(end - start);
+            list.add(element);
+        }
+        return list;
+    }
+
+    protected List<Integer> generateList(int start, int end) throws Exception{
+        return generateList(start, end, end - start);
+    }
+
+    @Factory
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    public static Object[] create(){
+        List<SortAndReplaceAllTest> result = new ArrayList<>();
+        Stream<Class> stream1 = Arrays.stream(defaultConstructorClazz);
+        Stream<Class> stream2 = Arrays.stream(capacityConstructorClazz);
+        stream1.forEach(clazz -> result.add(new SortAndReplaceAllTest(clazz)));
+        stream2.forEach(clazz -> result.add(new SortAndReplaceAllTest(clazz,
+                END - START + rand.nextInt(END - START))));
+        return result.toArray();
+    }
+
+    @Test
+    public void testReplaceAll() throws Exception {
+        List<Integer> list = generateList(START, END);
+        List<Integer> listCloned =  hasIni ?
+            (List<Integer>)LambdaUtilities.create(typeObject, initSize) :
+            (List<Integer>)LambdaUtilities.create(typeObject);
+        listCloned.addAll(list);
+        EnumSet<LambdaUtilities.IntOp> set = EnumSet.allOf(LambdaUtilities.IntOp.class);
+        LambdaUtilities.IntOp[] ops = new LambdaUtilities.IntOp[set.size()];
+        set.toArray(ops);
+        LambdaUtilities.IntOp op = ops[rand.nextInt(ops.length)];
+        int value = START + rand.nextInt(END - START);
+        if( op == LambdaUtilities.IntOp.DIVIDE || op == LambdaUtilities.IntOp.MOD) {
+            while(value == 0) {
+                value = START + rand.nextInt(END - START);
+            }
+        }
+        list.replaceAll(LambdaUtilities.opIntegerUnaryOperator(op, value));
+        checkReplace(listCloned, list, op, value);
+    }
+
+    @Test
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    public void testSort() throws Exception{
+        final Function<Integer, String> i2s = i -> String.valueOf(i);
+        Comparator[] cs = { Comparator.<Integer>naturalOrder(),
+            Comparator.<Integer>reverseOrder(),
+            Comparator.comparing(LambdaUtilities.highestPosValueIntFunction()),
+            Comparator.comparing(LambdaUtilities.lowestPosValueIntFunction()),
+            Comparator.comparing(i2s, Comparator.<String>naturalOrder()),
+            Comparator.comparing(i2s, Comparator.<String>reverseOrder()),
+        };
+
+        Iterator<Comparator> csit = Arrays.stream(cs).iterator();
+        while(csit.hasNext()) {
+            testComparator((Comparator<Integer>)csit.next());
+        }
+    }
+
+    private void checkReplace(List<Integer> orig, List<Integer> replaced,
+            LambdaUtilities.IntOp op, int value) {
+        assertEquals(orig.size(), replaced.size());
+        for(int index = 0; index < orig.size(); index++) {
+            switch(op) {
+                case ADD:
+                    assertTrue(orig.get(index) + value == replaced.get(index));
+                    break;
+                case SUBTRACT:
+                    assertTrue(orig.get(index) - value == replaced.get(index));
+                    break;
+                case MULTIPLY:
+                    assertTrue(orig.get(index) * value == replaced.get(index));
+                    break;
+                case DIVIDE:
+                    assertTrue(orig.get(index) / value == replaced.get(index));
+                    break;
+                default:
+                    assertTrue(orig.get(index) % value == replaced.get(index));
+                    break;
+            }
+        }
+    }
+
+    private void testComparator(Comparator<Integer> c) throws Exception {
+        List<Integer> list = generateList(START, END);
+        List<Integer> listCloned =  hasIni ?
+            (List<Integer>)LambdaUtilities.create(typeObject, initSize) :
+            (List<Integer>)LambdaUtilities.create(typeObject);
+        listCloned.addAll(list);
+        list.sort(c);
+        for(int i = 0; i < list.size() - 1; i++) {
+            assertTrue(c.compare(list.get(i), list.get(i+1)) <= 0);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/Map/LambdaTest.java	Wed Aug 14 15:53:13 2013 -0700
@@ -0,0 +1,225 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @summary sanity test forEach on Map<String,Integer>
+ * @library /sqeutil
+ * @(#)LambdaTest.java
+ * @author Yong Lu/Tristan Yan
+ * @run testng LambdaTest
+ */
+
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentSkipListMap;
+import java.util.stream.Stream;
+import static org.testng.Assert.*;
+import org.testng.ITest;
+import org.testng.annotations.Factory;
+import org.testng.annotations.Test;
+
+@SuppressWarnings({"rawtypes", "unchecked"})
+public class LambdaTest<T extends Map<String, Integer>> implements ITest  {
+    private final static Random rand = new Random(System.currentTimeMillis());
+    private Class<T> typeObject;
+    private boolean hasIni;
+    private int initSize;
+
+    private final static int START = -1 << 6;
+    private final static int END = 1 << 6;
+
+    private static Class[] defaultConstructorClazz = {
+        (Class<ConcurrentHashMap<String, Integer>>) (Class<?>) (ConcurrentHashMap.class),
+        (Class<ConcurrentSkipListMap<String, Integer>>) (Class<?>) (ConcurrentSkipListMap.class),
+        (Class<HashMap<String, Integer>>) (Class<?>) (HashMap.class),
+        (Class<Hashtable<String, Integer>>) (Class<?>) (Hashtable.class),
+        (Class<LinkedHashMap<String, Integer>>) (Class<?>) (LinkedHashMap.class),
+        (Class<IdentityHashMap<String, Integer>>) (Class<?>) (IdentityHashMap.class),
+        (Class<WeakHashMap<String, Integer>>) (Class<?>) (WeakHashMap.class)
+    };
+
+    public LambdaTest(Class<T> clazz, int... initSizes) {
+        this.typeObject = clazz;
+        assert (initSizes.length <= 1);
+        if (initSizes.length == 1) {
+            hasIni = true;
+            this.initSize = initSizes[0];
+        }
+    }
+
+    protected Map<String, Integer> generateData(int start, int end, int size) throws Exception {
+        Map<String, Integer> m = LambdaUtilities.createMap(typeObject);
+        for (int i = 0; i < size; i++) {
+            int element = start + rand.nextInt(end - start);
+            if (element != Integer.SIZE) {
+                m.put(String.valueOf(element), new Integer(element));
+            }
+        }
+        return m;
+    }
+
+    protected Map<String, Integer> generateData(int start, int end) throws Exception {
+        return generateData(start, end, end - start);
+    }
+
+    @Factory
+    public static Object[] create(){
+        List<LambdaTest> result = new ArrayList<>();
+        Stream<Class> stream = Arrays.stream(defaultConstructorClazz);
+        stream.forEach(clazz -> result.add(new LambdaTest(clazz)));
+        return result.toArray();
+    }
+
+    @Test
+    public void testForEach() throws Exception{
+        Map<String, Integer> m1 = generateData(START, END);
+        m1.forEach((x,y) -> assertTrue(m1.get(x).equals(y)));
+
+        Map<String, Integer> m2 = LambdaUtilities.createMap(typeObject);
+        m1.forEach((x,y) -> m2.put(x, y));
+        m2.forEach((x,y) -> assertTrue(m1.get(x).equals(y)));
+
+        m1.forEach((x,y) -> {
+                m1.put(x, Integer.SIZE);
+                assertFalse(m1.containsValue(y));
+        });
+    }
+
+    @Test
+    public void testReplaceAll() throws Exception{
+        //ConcurrentSkipListMap doesn't replaceAll
+        if(typeObject.getName().endsWith("ConcurrentSkipListMap"))
+            return;
+        Map<String, Integer> m = generateData(START, END);
+        Map<String, Integer> mCloned = LambdaUtilities.createMap(typeObject);
+        mCloned.putAll(m);
+        EnumSet<LambdaUtilities.IntOp> set = EnumSet.allOf(LambdaUtilities.IntOp.class);
+        LambdaUtilities.IntOp[] ops = new LambdaUtilities.IntOp[set.size()];
+        set.toArray(ops);
+        LambdaUtilities.IntOp op = ops[rand.nextInt(ops.length)];
+        int value = START + rand.nextInt(END - START);
+        while((value = START + rand.nextInt(END - START)) == 0);
+        m.replaceAll(LambdaUtilities.opBiFunction(op, value));
+        checkReplace(mCloned, m, op, value);
+    }
+
+    @Test
+    public void testCompute() throws Exception{
+        Map<String, Integer> m = generateData(START, END);
+        Map<String, Integer> mCloned = LambdaUtilities.createMap(typeObject);
+        mCloned.putAll(m);
+        final int value = START + rand.nextInt(END - START);
+        EnumSet<LambdaUtilities.IntOp> set = EnumSet.allOf(LambdaUtilities.IntOp.class);
+        LambdaUtilities.IntOp[] ops = new LambdaUtilities.IntOp[set.size()];
+        set.toArray(ops);
+        LambdaUtilities.IntOp op = ops[rand.nextInt(ops.length)];
+        mCloned.keySet().forEach(t -> m.compute(t, LambdaUtilities.opBiFunction(op, value)));
+        checkReplace(mCloned, m, op, value);
+    }
+
+    @Test
+    public void testMerge() throws Exception{
+        Map<String, Integer> m = generateData(START, END);
+        Map<String, Integer> mCloned = LambdaUtilities.createMap(typeObject);
+        mCloned.putAll(m);
+        final int value = START + rand.nextInt(END - START);
+        EnumSet<LambdaUtilities.IntOp> set = EnumSet.allOf(LambdaUtilities.IntOp.class);
+        LambdaUtilities.IntOp[] ops = new LambdaUtilities.IntOp[set.size()];
+        set.toArray(ops);
+        LambdaUtilities.IntOp op = ops[rand.nextInt(ops.length)];
+        mCloned.keySet().forEach(t -> m.merge(t, value, LambdaUtilities.opBiFunction(op)));
+        checkReplace(mCloned, m, op, value);
+    }
+
+    @Test
+    public void testReplace() throws Exception{
+        Map<String, Integer> m = generateData(START, END);
+        Map<String, Integer> mCloned = LambdaUtilities.createMap(typeObject);
+        mCloned.putAll(m);
+        final int value = START + rand.nextInt(END - START);
+        EnumSet<LambdaUtilities.IntOp> set = EnumSet.allOf(LambdaUtilities.IntOp.class);
+        LambdaUtilities.IntOp[] ops = new LambdaUtilities.IntOp[set.size()];
+        set.toArray(ops);
+        LambdaUtilities.IntOp op = ops[rand.nextInt(ops.length)];
+        mCloned.keySet().forEach(t -> m.replace(t, mCloned.get(t), LambdaUtilities.opBiFunction(op).apply(mCloned.get(t), value)));
+        checkReplace(mCloned, m, op, value);
+    }
+
+    private void checkReplace(Map<String, Integer> orig, Map<String, Integer> replaced,
+            LambdaUtilities.IntOp op, int value) {
+        assertEquals(orig.size(), replaced.size());
+        Iterator<String> it = orig.keySet().iterator();
+        while(it.hasNext()) {
+            String k = it.next();
+            if(value == 0){
+                assertEquals(orig.get(k), replaced.get(k));
+                continue;
+            }
+            switch(op) {
+                case ADD:
+                    assertTrue(orig.get(k) + value == replaced.get(k));
+                    break;
+                case SUBTRACT:
+                    assertTrue(orig.get(k) - value == replaced.get(k));
+                    break;
+                case MULTIPLY:
+                    assertTrue(orig.get(k) * value == replaced.get(k));
+                    break;
+                case DIVIDE:
+                    assertTrue(orig.get(k) / value == replaced.get(k));
+                    break;
+                default:
+                    assertTrue(orig.get(k) % value == replaced.get(k));
+                    break;
+            }
+        }
+    }
+
+    @Test
+    public void testRemove() throws Exception {
+        Map<String, Integer> m = generateData(START, END);
+        Map<String, Integer> mCloned = LambdaUtilities.createMap(typeObject);
+        mCloned.putAll(m);
+        mCloned.keySet().forEach(t -> m.remove(t));
+        assertTrue(m.isEmpty());
+    }
+
+    @Test
+    public void testComputeIfAbsent() throws Exception {
+        Map<String, Integer> m = generateData(START, END);
+        Map<String, Integer> mCloned = LambdaUtilities.createMap(typeObject);
+        final int value = START + rand.nextInt(END - START);
+        EnumSet<LambdaUtilities.IntOp> set = EnumSet.allOf(LambdaUtilities.IntOp.class);
+        LambdaUtilities.IntOp[] ops = new LambdaUtilities.IntOp[set.size()];
+        set.toArray(ops);
+        LambdaUtilities.IntOp op = ops[rand.nextInt(ops.length)];
+        m.keySet().forEach(t -> mCloned.computeIfAbsent(t, LambdaUtilities.mappingFunction(m, op, value)));
+        checkReplace(m, mCloned, op, value);
+    }
+
+    @Override
+    public String getTestName() {
+        return typeObject.getName() + "<String,Integer>";
+    }
+}
--- a/test/java/util/Random/RandomStreamTest.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/test/java/util/Random/RandomStreamTest.java	Wed Aug 14 15:53:13 2013 -0700
@@ -82,13 +82,6 @@
         assertEquals(destination.size(), count);
     }
 
-    @Test(dataProvider = "suppliers")
-    public void testRandomGaussianStream(final Random random, final int count) {
-        final List<Double> destination = new ArrayList<>(count);
-        random.gaussians().limit(count).forEach(destination::add);
-        assertEquals(destination.size(), count);
-    }
-
     @Test
     public void testIntStream() {
         final long seed = System.currentTimeMillis();
@@ -132,20 +125,6 @@
     }
 
     @Test
-    public void testGaussianStream() {
-        final long seed = System.currentTimeMillis();
-        final Random r1 = new Random(seed);
-        final double[] a = new double[SIZE];
-        for (int i=0; i < SIZE; i++) {
-            a[i] = r1.nextGaussian();
-        }
-
-        final Random r2 = new Random(seed); // same seed
-        final double[] b = r2.gaussians().limit(SIZE).toArray();
-        assertEquals(a, b);
-    }
-
-    @Test
     public void testThreadLocalIntStream() throws InterruptedException, ExecutionException, TimeoutException {
         ThreadLocalRandom tlr = ThreadLocalRandom.current();
         testRandomResultSupplierConcurrently(() -> tlr.ints().limit(SIZE).boxed().collect(toList()));
@@ -163,12 +142,6 @@
         testRandomResultSupplierConcurrently(() -> tlr.doubles().limit(SIZE).boxed().collect(toList()));
     }
 
-    @Test
-    public void testThreadLocalGaussianStream() throws InterruptedException, ExecutionException, TimeoutException {
-        ThreadLocalRandom tlr = ThreadLocalRandom.current();
-        testRandomResultSupplierConcurrently(() -> tlr.gaussians().limit(SIZE).boxed().collect(toList()));
-    }
-
     <T> void testRandomResultSupplierConcurrently(Supplier<T> s) throws InterruptedException, ExecutionException, TimeoutException {
         // Produce 10 completable future tasks
         final int tasks = 10;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/Random/RandomTest.java	Wed Aug 14 15:53:13 2013 -0700
@@ -0,0 +1,518 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import java.util.Random;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.LongAdder;
+
+import static org.testng.Assert.*;
+
+/**
+ * @test
+ * @run testng RandomTest
+ * @summary test methods on Random
+ */
+@Test
+public class RandomTest {
+
+    // Note: this test was adapted from the 166 TCK ThreadLocalRandomTest test
+    // and modified to be a TestNG test
+
+    /*
+     * Testing coverage notes:
+     *
+     * We don't test randomness properties, but only that repeated
+     * calls, up to NCALLS tries, produce at least one different
+     * result.  For bounded versions, we sample various intervals
+     * across multiples of primes.
+     */
+
+    // max numbers of calls to detect getting stuck on one value
+    static final int NCALLS = 10000;
+
+    // max sampled int bound
+    static final int MAX_INT_BOUND = (1 << 28);
+
+    // max sampled long bound
+    static final long MAX_LONG_BOUND = (1L << 42);
+
+    // Number of replications for other checks
+    static final int REPS = 20;
+
+    /**
+     * Repeated calls to nextInt produce at least two distinct results
+     */
+    public void testNextInt() {
+        Random r = new Random();
+        int f = r.nextInt();
+        int i = 0;
+        while (i < NCALLS && r.nextInt() == f)
+            ++i;
+        assertTrue(i < NCALLS);
+    }
+
+    /**
+     * Repeated calls to nextLong produce at least two distinct results
+     */
+    public void testNextLong() {
+        Random r = new Random();
+        long f = r.nextLong();
+        int i = 0;
+        while (i < NCALLS && r.nextLong() == f)
+            ++i;
+        assertTrue(i < NCALLS);
+    }
+
+    /**
+     * Repeated calls to nextBoolean produce at least two distinct results
+     */
+    public void testNextBoolean() {
+        Random r = new Random();
+        boolean f = r.nextBoolean();
+        int i = 0;
+        while (i < NCALLS && r.nextBoolean() == f)
+            ++i;
+        assertTrue(i < NCALLS);
+    }
+
+    /**
+     * Repeated calls to nextFloat produce at least two distinct results
+     */
+    public void testNextFloat() {
+        Random r = new Random();
+        float f = r.nextFloat();
+        int i = 0;
+        while (i < NCALLS && r.nextFloat() == f)
+            ++i;
+        assertTrue(i < NCALLS);
+    }
+
+    /**
+     * Repeated calls to nextDouble produce at least two distinct results
+     */
+    public void testNextDouble() {
+        Random r = new Random();
+        double f = r.nextDouble();
+        int i = 0;
+        while (i < NCALLS && r.nextDouble() == f)
+            ++i;
+        assertTrue(i < NCALLS);
+    }
+
+    /**
+     * Repeated calls to nextGaussian produce at least two distinct results
+     */
+    public void testNextGaussian() {
+        Random r = new Random();
+        double f = r.nextGaussian();
+        int i = 0;
+        while (i < NCALLS && r.nextGaussian() == f)
+            ++i;
+        assertTrue(i < NCALLS);
+    }
+
+    /**
+     * nextInt(negative) throws IllegalArgumentException
+     */
+    @Test(expectedExceptions = IllegalArgumentException.class)
+    public void testNextIntBoundedNeg() {
+        Random r = new Random();
+        int f = r.nextInt(-17);
+    }
+
+    /**
+     * nextInt(least >= bound) throws IllegalArgumentException
+     */
+    @Test(expectedExceptions = IllegalArgumentException.class)
+    public void testNextIntBadBounds() {
+        Random r = new Random();
+        int f = r.nextInt(17, 2);
+    }
+
+    /**
+     * nextInt(bound) returns 0 <= value < bound; repeated calls produce at
+     * least two distinct results
+     */
+    public void testNextIntBounded() {
+        Random r = new Random();
+        // sample bound space across prime number increments
+        for (int bound = 2; bound < MAX_INT_BOUND; bound += 524959) {
+            int f = r.nextInt(bound);
+            assertTrue(0 <= f && f < bound);
+            int i = 0;
+            int j;
+            while (i < NCALLS &&
+                   (j = r.nextInt(bound)) == f) {
+                assertTrue(0 <= j && j < bound);
+                ++i;
+            }
+            assertTrue(i < NCALLS);
+        }
+    }
+
+    /**
+     * nextInt(least, bound) returns least <= value < bound; repeated calls
+     * produce at least two distinct results
+     */
+    public void testNextIntBounded2() {
+        Random r = new Random(0);
+        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 = r.nextInt(least, bound);
+                assertTrue(least <= f && f < bound, String.format("[%d, %d] %d", least, bound, f));
+                int i = 0;
+                int j;
+                while (i < NCALLS &&
+                       (j = r.nextInt(least, bound)) == f) {
+                    assertTrue(least <= j && j < bound);
+                    ++i;
+                }
+                assertTrue(i < NCALLS);
+            }
+        }
+    }
+
+    /**
+     * nextLong(negative) throws IllegalArgumentException
+     */
+    @Test(expectedExceptions = IllegalArgumentException.class)
+    public void testNextLongBoundedNeg() {
+        Random r = new Random();
+        long f = r.nextLong(-17);
+    }
+
+    /**
+     * nextLong(least >= bound) throws IllegalArgumentException
+     */
+    @Test(expectedExceptions = IllegalArgumentException.class)
+    public void testNextLongBadBounds() {
+        Random r = new Random();
+        long f = r.nextLong(17, 2);
+    }
+
+    /**
+     * nextLong(bound) returns 0 <= value < bound; repeated calls produce at
+     * least two distinct results
+     */
+    public void testNextLongBounded() {
+        Random r = new Random();
+        for (long bound = 2; bound < MAX_LONG_BOUND; bound += 15485863) {
+            long f = r.nextLong(bound);
+            assertTrue(0 <= f && f < bound);
+            int i = 0;
+            long j;
+            while (i < NCALLS &&
+                   (j = r.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() {
+        Random r = new Random();
+        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 = r.nextLong(least, bound);
+                assertTrue(least <= f && f < bound);
+                int i = 0;
+                long j;
+                while (i < NCALLS &&
+                       (j = r.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() {
+        Random r = new Random();
+        for (double least = 0.0001; least < 1.0e20; least *= 8) {
+            for (double bound = least * 1.001; bound < 1.0e20; bound *= 16) {
+                double f = r.nextDouble(least, bound);
+                assertTrue(least <= f && f < bound);
+                int i = 0;
+                double j;
+                while (i < NCALLS &&
+                       (j = r.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() {
+        Random r = new Random();
+        executeAndCatchIAE(() -> r.ints(-1L));
+        executeAndCatchIAE(() -> r.ints(-1L, 2, 3));
+        executeAndCatchIAE(() -> r.longs(-1L));
+        executeAndCatchIAE(() -> r.longs(-1L, -1L, 1L));
+        executeAndCatchIAE(() -> r.doubles(-1L));
+        executeAndCatchIAE(() -> r.doubles(-1L, .5, .6));
+    }
+
+    /**
+     * Invoking bounded ints, long, doubles, with illegal bounds throws
+     * IllegalArgumentException
+     */
+    public void testBadStreamBounds() {
+        Random r = new Random();
+        executeAndCatchIAE(() -> r.ints(2, 1));
+        executeAndCatchIAE(() -> r.ints(10, 42, 42));
+        executeAndCatchIAE(() -> r.longs(-1L, -1L));
+        executeAndCatchIAE(() -> r.longs(10, 1L, -2L));
+        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<? extends Exception> expected, Runnable r) {
+        Exception caught = null;
+        try {
+            r.run();
+        }
+        catch (Exception e) {
+            caught = e;
+        }
+
+        assertNotNull(caught,
+                      String.format("No Exception was thrown, expected an Exception of %s to be thrown",
+                                    expected.getName()));
+        Assert.assertTrue(expected.isInstance(caught),
+                          String.format("Exception thrown %s not an instance of %s",
+                                        caught.getClass().getName(), expected.getName()));
+    }
+
+    /**
+     * A sequential sized stream of ints generates the given number of values
+     */
+    public void testIntsCount() {
+        LongAdder counter = new LongAdder();
+        Random r = new Random();
+        long size = 0;
+        for (int reps = 0; reps < REPS; ++reps) {
+            counter.reset();
+            r.ints(size).forEach(x -> {
+                counter.increment();
+            });
+            assertEquals(counter.sum(), size);
+            size += 524959;
+        }
+    }
+
+    /**
+     * A sequential sized stream of longs generates the given number of values
+     */
+    public void testLongsCount() {
+        LongAdder counter = new LongAdder();
+        Random r = new Random();
+        long size = 0;
+        for (int reps = 0; reps < REPS; ++reps) {
+            counter.reset();
+            r.longs(size).forEach(x -> {
+                counter.increment();
+            });
+            assertEquals(counter.sum(), size);
+            size += 524959;
+        }
+    }
+
+    /**
+     * A sequential sized stream of doubles generates the given number of values
+     */
+    public void testDoublesCount() {
+        LongAdder counter = new LongAdder();
+        Random r = new Random();
+        long size = 0;
+        for (int reps = 0; reps < REPS; ++reps) {
+            counter.reset();
+            r.doubles(size).forEach(x -> {
+                counter.increment();
+            });
+            assertEquals(counter.sum(), size);
+            size += 524959;
+        }
+    }
+
+    /**
+     * Each of a sequential sized stream of bounded ints is within bounds
+     */
+    public void testBoundedInts() {
+        AtomicInteger fails = new AtomicInteger(0);
+        Random r = new Random();
+        long size = 12345L;
+        for (int least = -15485867; least < MAX_INT_BOUND; least += 524959) {
+            for (int bound = least + 2; bound > least && bound < MAX_INT_BOUND; bound += 67867967) {
+                final int lo = least, hi = bound;
+                r.ints(size, lo, hi).
+                        forEach(x -> {
+                            if (x < lo || x >= hi)
+                                fails.getAndIncrement();
+                        });
+            }
+        }
+        assertEquals(fails.get(), 0);
+    }
+
+    /**
+     * Each of a sequential sized stream of bounded longs is within bounds
+     */
+    public void testBoundedLongs() {
+        AtomicInteger fails = new AtomicInteger(0);
+        Random r = new Random();
+        long size = 123L;
+        for (long least = -86028121; least < MAX_LONG_BOUND; least += 1982451653L) {
+            for (long bound = least + 2; bound > least && bound < MAX_LONG_BOUND; bound += Math.abs(bound * 7919)) {
+                final long lo = least, hi = bound;
+                r.longs(size, lo, hi).
+                        forEach(x -> {
+                            if (x < lo || x >= hi)
+                                fails.getAndIncrement();
+                        });
+            }
+        }
+        assertEquals(fails.get(), 0);
+    }
+
+    /**
+     * Each of a sequential sized stream of bounded doubles is within bounds
+     */
+    public void testBoundedDoubles() {
+        AtomicInteger fails = new AtomicInteger(0);
+        Random r = new Random();
+        long size = 456;
+        for (double least = 0.00011; least < 1.0e20; least *= 9) {
+            for (double bound = least * 1.0011; bound < 1.0e20; bound *= 17) {
+                final double lo = least, hi = bound;
+                r.doubles(size, lo, hi).
+                        forEach(x -> {
+                            if (x < lo || x >= hi)
+                                fails.getAndIncrement();
+                        });
+            }
+        }
+        assertEquals(fails.get(), 0);
+    }
+
+    /**
+     * A parallel unsized stream of ints generates at least 100 values
+     */
+    public void testUnsizedIntsCount() {
+        LongAdder counter = new LongAdder();
+        Random r = new Random();
+        long size = 100;
+        r.ints().limit(size).parallel().forEach(x -> {
+            counter.increment();
+        });
+        assertEquals(counter.sum(), size);
+    }
+
+    /**
+     * A parallel unsized stream of longs generates at least 100 values
+     */
+    public void testUnsizedLongsCount() {
+        LongAdder counter = new LongAdder();
+        Random r = new Random();
+        long size = 100;
+        r.longs().limit(size).parallel().forEach(x -> {
+            counter.increment();
+        });
+        assertEquals(counter.sum(), size);
+    }
+
+    /**
+     * A parallel unsized stream of doubles generates at least 100 values
+     */
+    public void testUnsizedDoublesCount() {
+        LongAdder counter = new LongAdder();
+        Random r = new Random();
+        long size = 100;
+        r.doubles().limit(size).parallel().forEach(x -> {
+            counter.increment();
+        });
+        assertEquals(counter.sum(), size);
+    }
+
+    /**
+     * A sequential unsized stream of ints generates at least 100 values
+     */
+    public void testUnsizedIntsCountSeq() {
+        LongAdder counter = new LongAdder();
+        Random r = new Random();
+        long size = 100;
+        r.ints().limit(size).forEach(x -> {
+            counter.increment();
+        });
+        assertEquals(counter.sum(), size);
+    }
+
+    /**
+     * A sequential unsized stream of longs generates at least 100 values
+     */
+    public void testUnsizedLongsCountSeq() {
+        LongAdder counter = new LongAdder();
+        Random r = new Random();
+        long size = 100;
+        r.longs().limit(size).forEach(x -> {
+            counter.increment();
+        });
+        assertEquals(counter.sum(), size);
+    }
+
+    /**
+     * A sequential unsized stream of doubles generates at least 100 values
+     */
+    public void testUnsizedDoublesCountSeq() {
+        LongAdder counter = new LongAdder();
+        Random r = new Random();
+        long size = 100;
+        r.doubles().limit(size).forEach(x -> {
+            counter.increment();
+        });
+        assertEquals(counter.sum(), size);
+    }
+
+}
--- a/test/java/util/Spliterator/SpliteratorCharacteristics.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/test/java/util/Spliterator/SpliteratorCharacteristics.java	Wed Aug 14 15:53:13 2013 -0700
@@ -32,80 +32,134 @@
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Comparator;
+import java.util.Map;
+import java.util.Set;
+import java.util.SortedMap;
+import java.util.SortedSet;
 import java.util.Spliterator;
 import java.util.TreeMap;
 import java.util.TreeSet;
+import java.util.concurrent.ConcurrentSkipListMap;
+import java.util.concurrent.ConcurrentSkipListSet;
 
 import static org.testng.Assert.*;
 
 @Test
 public class SpliteratorCharacteristics {
 
-    public void testTreeMap() {
-        TreeMap<Integer, String> tm = new TreeMap<>();
-        tm.put(1, "4");
-        tm.put(2, "3");
-        tm.put(3, "2");
-        tm.put(4, "1");
+    // TreeMap
 
-        assertCharacteristics(tm.keySet(),
-                              Spliterator.SIZED | Spliterator.DISTINCT |
-                              Spliterator.SORTED | Spliterator.ORDERED);
-        assertNullComparator(tm.keySet());
-
-        assertCharacteristics(tm.values(),
-                              Spliterator.SIZED | Spliterator.ORDERED);
-        assertISEComparator(tm.values());
-
-        assertCharacteristics(tm.entrySet(),
-                              Spliterator.SIZED | Spliterator.DISTINCT |
-                              Spliterator.SORTED | Spliterator.ORDERED);
-        assertNotNullComparator(tm.entrySet());
+    public void testTreeMap() {
+        assertSortedMapCharacteristics(new TreeMap<>(),
+                                       Spliterator.SIZED | Spliterator.DISTINCT |
+                                       Spliterator.SORTED | Spliterator.ORDERED);
     }
 
     public void testTreeMapWithComparator() {
-        TreeMap<Integer, String> tm = new TreeMap<>(Comparator.<Integer>reverseOrder());
-        tm.put(1, "4");
-        tm.put(2, "3");
-        tm.put(3, "2");
-        tm.put(4, "1");
-
-        assertCharacteristics(tm.keySet(),
-                              Spliterator.SIZED | Spliterator.DISTINCT |
-                              Spliterator.SORTED | Spliterator.ORDERED);
-        assertNotNullComparator(tm.keySet());
-
-        assertCharacteristics(tm.values(),
-                              Spliterator.SIZED | Spliterator.ORDERED);
-        assertISEComparator(tm.values());
-
-        assertCharacteristics(tm.entrySet(),
-                              Spliterator.SIZED | Spliterator.DISTINCT |
-                              Spliterator.SORTED | Spliterator.ORDERED);
-        assertNotNullComparator(tm.entrySet());
+        assertSortedMapCharacteristics(new TreeMap<>(Comparator.reverseOrder()),
+                                       Spliterator.SIZED | Spliterator.DISTINCT |
+                                       Spliterator.SORTED | Spliterator.ORDERED);
     }
 
-    public void testTreeSet() {
-        TreeSet<Integer> ts = new TreeSet<>();
-        ts.addAll(Arrays.asList(1, 2, 3, 4));
+
+    // TreeSet
 
-        assertCharacteristics(ts,
-                              Spliterator.SIZED | Spliterator.DISTINCT |
-                              Spliterator.SORTED | Spliterator.ORDERED);
-        assertNullComparator(ts);
+    public void testTreeSet() {
+        assertSortedSetCharacteristics(new TreeSet<>(),
+                                       Spliterator.SIZED | Spliterator.DISTINCT |
+                                       Spliterator.SORTED | Spliterator.ORDERED);
     }
 
     public void testTreeSetWithComparator() {
-        TreeSet<Integer> ts = new TreeSet<>(Comparator.reverseOrder());
-        ts.addAll(Arrays.asList(1, 2, 3, 4));
+        assertSortedSetCharacteristics(new TreeSet<>(Comparator.reverseOrder()),
+                                       Spliterator.SIZED | Spliterator.DISTINCT |
+                                       Spliterator.SORTED | Spliterator.ORDERED);
+    }
+
+
+    // ConcurrentSkipListMap
+
+    public void testConcurrentSkipListMap() {
+        assertSortedMapCharacteristics(new ConcurrentSkipListMap<>(),
+                                       Spliterator.CONCURRENT | Spliterator.NONNULL |
+                                       Spliterator.DISTINCT | Spliterator.SORTED |
+                                       Spliterator.ORDERED);
+    }
 
-        assertCharacteristics(ts,
-                              Spliterator.SIZED | Spliterator.DISTINCT |
-                              Spliterator.SORTED | Spliterator.ORDERED);
-        assertNotNullComparator(ts);
+    public void testConcurrentSkipListMapWithComparator() {
+        assertSortedMapCharacteristics(new ConcurrentSkipListMap<>(Comparator.<Integer>reverseOrder()),
+                                       Spliterator.CONCURRENT | Spliterator.NONNULL |
+                                       Spliterator.DISTINCT | Spliterator.SORTED |
+                                       Spliterator.ORDERED);
+    }
+
+
+    // ConcurrentSkipListSet
+
+    public void testConcurrentSkipListSet() {
+        assertSortedSetCharacteristics(new ConcurrentSkipListSet<>(),
+                                       Spliterator.CONCURRENT | Spliterator.NONNULL |
+                                       Spliterator.DISTINCT | Spliterator.SORTED |
+                                       Spliterator.ORDERED);
+    }
+
+    public void testConcurrentSkipListSetWithComparator() {
+        assertSortedSetCharacteristics(new ConcurrentSkipListSet<>(Comparator.reverseOrder()),
+                                       Spliterator.CONCURRENT | Spliterator.NONNULL |
+                                       Spliterator.DISTINCT | Spliterator.SORTED |
+                                       Spliterator.ORDERED);
     }
 
 
+    //
+
+    void assertSortedMapCharacteristics(SortedMap<Integer, String> m, int keyCharacteristics) {
+        initMap(m);
+
+        boolean hasComparator = m.comparator() != null;
+
+        Set<Integer> keys = m.keySet();
+        assertCharacteristics(keys, keyCharacteristics);
+        if (hasComparator) {
+            assertNotNullComparator(keys);
+        }
+        else {
+            assertNullComparator(keys);
+        }
+
+        assertCharacteristics(m.values(),
+                              keyCharacteristics & ~(Spliterator.DISTINCT | Spliterator.SORTED));
+        assertISEComparator(m.values());
+
+        assertCharacteristics(m.entrySet(), keyCharacteristics);
+        assertNotNullComparator(m.entrySet());
+    }
+
+    void assertSortedSetCharacteristics(SortedSet<Integer> s, int keyCharacteristics) {
+        initSet(s);
+
+        boolean hasComparator = s.comparator() != null;
+
+        assertCharacteristics(s, keyCharacteristics);
+        if (hasComparator) {
+            assertNotNullComparator(s);
+        }
+        else {
+            assertNullComparator(s);
+        }
+    }
+
+    void initMap(Map<Integer, String> m) {
+        m.put(1, "4");
+        m.put(2, "3");
+        m.put(3, "2");
+        m.put(4, "1");
+    }
+
+    void initSet(Set<Integer> s) {
+        s.addAll(Arrays.asList(1, 2, 3, 4));
+    }
+
     void assertCharacteristics(Collection<?> c, int expectedCharacteristics) {
         assertCharacteristics(c.spliterator(), expectedCharacteristics);
     }
--- a/test/java/util/Spliterator/SpliteratorCollisions.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/test/java/util/Spliterator/SpliteratorCollisions.java	Wed Aug 14 15:53:13 2013 -0700
@@ -148,7 +148,6 @@
         List<Object[]> data = new ArrayList<>();
         for (int size : SIZES) {
             List<HashableInteger> exp = listIntRange(size, true);
-            exp.add(0, null);
             SpliteratorDataBuilder<HashableInteger> db = new SpliteratorDataBuilder<>(data, exp);
 
             // Maps
--- a/test/java/util/Spliterator/SpliteratorTraversingAndSplittingTest.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/test/java/util/Spliterator/SpliteratorTraversingAndSplittingTest.java	Wed Aug 14 15:53:13 2013 -0700
@@ -513,6 +513,12 @@
 
     @Test(dataProvider = "Spliterator<Integer>")
     @SuppressWarnings({"unchecked", "rawtypes"})
+    public void testMixedTraverseAndSplit(String description, Collection exp, Supplier<Spliterator> s) {
+        testMixedTraverseAndSplit(exp, s, (Consumer<Object> b) -> b);
+    }
+
+    @Test(dataProvider = "Spliterator<Integer>")
+    @SuppressWarnings({"unchecked", "rawtypes"})
     public void testSplitAfterFullTraversal(String description, Collection exp, Supplier<Spliterator> s) {
         testSplitAfterFullTraversal(s, (Consumer<Object> b) -> b);
     }
@@ -669,6 +675,11 @@
     }
 
     @Test(dataProvider = "Spliterator.OfInt")
+    public void testIntMixedTraverseAndSplit(String description, Collection<Integer> exp, Supplier<Spliterator.OfInt> s) {
+        testMixedTraverseAndSplit(exp, s, intBoxingConsumer());
+    }
+
+    @Test(dataProvider = "Spliterator.OfInt")
     public void testIntSplitAfterFullTraversal(String description, Collection<Integer> exp, Supplier<Spliterator.OfInt> s) {
         testSplitAfterFullTraversal(s, intBoxingConsumer());
     }
@@ -829,6 +840,11 @@
     }
 
     @Test(dataProvider = "Spliterator.OfLong")
+    public void testLongMixedTraverseAndSplit(String description, Collection<Long> exp, Supplier<Spliterator.OfLong> s) {
+        testMixedTraverseAndSplit(exp, s, longBoxingConsumer());
+    }
+
+    @Test(dataProvider = "Spliterator.OfLong")
     public void testLongSplitAfterFullTraversal(String description, Collection<Long> exp, Supplier<Spliterator.OfLong> s) {
         testSplitAfterFullTraversal(s, longBoxingConsumer());
     }
@@ -989,6 +1005,11 @@
     }
 
     @Test(dataProvider = "Spliterator.OfDouble")
+    public void testDoubleMixedTraverseAndSplit(String description, Collection<Double> exp, Supplier<Spliterator.OfDouble> s) {
+        testMixedTraverseAndSplit(exp, s, doubleBoxingConsumer());
+    }
+
+    @Test(dataProvider = "Spliterator.OfDouble")
     public void testDoubleSplitAfterFullTraversal(String description, Collection<Double> exp, Supplier<Spliterator.OfDouble> s) {
         testSplitAfterFullTraversal(s, doubleBoxingConsumer());
     }
@@ -1097,6 +1118,53 @@
         }
     }
 
+    private static <T, S extends Spliterator<T>> void testMixedTraverseAndSplit(
+            Collection<T> exp,
+            Supplier<S> supplier,
+            UnaryOperator<Consumer<T>> boxingAdapter) {
+        S spliterator = supplier.get();
+        long sizeIfKnown = spliterator.getExactSizeIfKnown();
+        boolean isOrdered = spliterator.hasCharacteristics(Spliterator.ORDERED);
+
+        ArrayList<T> dest = new ArrayList<>();
+        spliterator = supplier.get();
+        Consumer<T> b = boxingAdapter.apply(dest::add);
+
+        Spliterator<T> spl1, spl2, spl3;
+        spliterator.tryAdvance(b);
+        spl2 = spliterator.trySplit();
+        if (spl2 != null) {
+            spl2.tryAdvance(b);
+            spl1 = spl2.trySplit();
+            if (spl1 != null) {
+                spl1.tryAdvance(b);
+                spl1.forEachRemaining(b);
+            }
+            spl2.tryAdvance(b);
+            spl2.forEachRemaining(b);
+        }
+        spliterator.tryAdvance(b);
+        spl3 = spliterator.trySplit();
+        if (spl3 != null) {
+            spl3.tryAdvance(b);
+            spl3.forEachRemaining(b);
+        }
+        spliterator.tryAdvance(b);
+        spliterator.forEachRemaining(b);
+
+        if (sizeIfKnown >= 0) {
+            assertEquals(sizeIfKnown, dest.size());
+        }
+        assertEquals(dest.size(), exp.size());
+
+        if (isOrdered) {
+            assertEquals(dest, exp);
+        }
+        else {
+            assertContentsUnordered(dest, exp);
+        }
+    }
+
     private static <T, S extends Spliterator<T>> void testSplitAfterFullTraversal(
             Supplier<S> supplier,
             UnaryOperator<Consumer<T>> boxingAdapter) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/SplittableRandom/SplittableRandomTest.java	Wed Aug 14 15:53:13 2013 -0700
@@ -0,0 +1,510 @@
+/*
+ * 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
+ * @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<? extends Exception> 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);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/StringJoiner/BasicTest.java	Wed Aug 14 15:53:13 2013 -0700
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @summary Sanity Test for StringJoiner
+ * @(#) BasicTest.java
+ * @library /sqeutil
+ * @author Tristan Yan
+ * @run testng BasicTest
+ */
+
+import java.util.*;
+import java.util.stream.Collectors;
+import static org.testng.Assert.*;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+public class BasicTest {
+    protected final static int STRING_ARR_SIIE = 1 << 8;
+
+    protected final static int STRING_LEN = 1 << 10;
+
+    protected final static int TIMES = 1 << 4;
+
+    protected final static Random rnd = new Random(System.currentTimeMillis());
+
+    protected String[] randomStringArray(){
+       String[] arr = new String[STRING_ARR_SIIE];
+       for(int index = 0; index < STRING_ARR_SIIE; index++)
+           arr[index] = StringUtilities.randomAlphabetic(rnd.nextInt(STRING_LEN));
+       return arr;
+    }
+
+    @DataProvider(name = "Connector-Provider")
+    public Object[][] notAlphanumeric(){
+        Object[][] data = new Object[TIMES][3];
+        for(int i = 0; i < TIMES; i++) {
+            List<String> list = new ArrayList<>();
+            for(char c=32; c < 127; c++) {
+                if(!Character.isAlphabetic(c) && !Character.isDigit(c))
+                    list.add(String.valueOf(c));
+            }
+            Collections.shuffle(list);
+            int infixPos = rnd.nextInt(list.size()/2);
+            if(infixPos < 1) infixPos = 1;
+            int prefixPos = infixPos + rnd.nextInt(list.size() - infixPos);
+            if(prefixPos == infixPos) prefixPos = infixPos + 1;
+            data[i] = new String[]{ list.subList(0, infixPos).stream().collect(Collectors.joining("")).toString(),
+                    list.subList(infixPos, prefixPos).stream().collect(Collectors.joining("")).toString(),
+                    list.subList(prefixPos, list.size()).stream().collect(Collectors.joining("")).toString()
+            };
+        }
+        return data;
+    }
+
+    @Test(dataProvider = "Connector-Provider")
+    public void constructorTest(String INFIX, String PREFIX, String SUFFIX) {
+        //Test constructor with only infix
+        //String[] sj = notAlphanumeric();
+        String[] rndStrings = randomStringArray();
+        final StringJoiner nofixsj = new StringJoiner(INFIX);
+        Arrays.stream(rndStrings).forEach(t -> {nofixsj.add(t); });
+        String longStr1 = nofixsj.toString();
+        int index = 0;
+        int pos = 0;
+        while(index < rndStrings.length) {
+            if(index < rndStrings.length - 1) {
+                assertEquals(longStr1.substring(pos, pos + rndStrings[index].length()), rndStrings[index]);
+                pos += rndStrings[index++].length();
+                assertEquals(longStr1.substring(pos, pos + INFIX.length()), INFIX);
+                pos += INFIX.length();
+            } else
+                assertEquals(longStr1.substring(pos, pos + rndStrings[index].length()), rndStrings[index++]);
+        }
+
+        //Test constructor with infix, prefix and suffix
+        final StringJoiner hasfixsj = new StringJoiner(INFIX, PREFIX, SUFFIX);
+        Arrays.stream(rndStrings).forEach(t -> {hasfixsj.add(t); });
+        String longStr2 = hasfixsj.toString();
+        index = 0;
+        pos = 0;
+        assertEquals(longStr2.substring(pos, pos + PREFIX.length()), PREFIX);
+        pos += PREFIX.length();
+        while(index < rndStrings.length) {
+            if(index < rndStrings.length - 1) {
+                assertEquals(longStr2.substring(pos, pos + rndStrings[index].length()), rndStrings[index]);
+                pos += rndStrings[index++].length();
+                assertEquals(longStr2.substring(pos, pos + INFIX.length()), INFIX);
+                pos += INFIX.length();
+            } else {
+                assertEquals(longStr2.substring(pos, pos + rndStrings[index].length()), rndStrings[index]);
+                pos += rndStrings[index++].length();
+            }
+        }
+        assertEquals(longStr2.substring(pos, pos + SUFFIX.length()), SUFFIX);
+    }
+
+    @Test(dataProvider = "Connector-Provider")
+    public void addTest(String INFIX, String PREFIX, String SUFFIX) {
+        StringJoiner nofixsj = new StringJoiner(INFIX);
+        String randAddStr1 = StringUtilities.randomAlphabetic(rnd.nextInt(STRING_LEN));
+        assertEquals(nofixsj.add(randAddStr1).toString(), randAddStr1);
+        String randAddStr2 = StringUtilities.randomAlphabetic(rnd.nextInt(STRING_LEN));
+        assertEquals(nofixsj.add(randAddStr2).toString(), randAddStr1 + INFIX + randAddStr2);
+
+        //Test constructor with infix, prefix and suffix
+        StringJoiner hasfixsj = new StringJoiner(INFIX, PREFIX, SUFFIX);
+        assertEquals(hasfixsj.add(randAddStr1).toString(), PREFIX + randAddStr1 + SUFFIX);
+        assertEquals(hasfixsj.add(randAddStr2).toString(), PREFIX + randAddStr1 + INFIX + randAddStr2 + SUFFIX);
+    }
+
+    @Test(dataProvider = "Connector-Provider")
+    public void testsetEmptyValue(String INFIX, String PREFIX, String SUFFIX) {
+        StringJoiner nofixsj = new StringJoiner(INFIX);
+        String emptyExpectedStr = StringUtilities.randomAlphabetic(rnd.nextInt(STRING_LEN));
+        assertEquals(nofixsj.toString().length(), 0);
+        nofixsj.setEmptyValue(emptyExpectedStr);
+        assertEquals(nofixsj.toString(), emptyExpectedStr);
+        String randAddStr = StringUtilities.randomAlphabetic(rnd.nextInt(STRING_LEN));
+        assertEquals(nofixsj.add(randAddStr).toString(), randAddStr);
+
+        //Test constructor with infix, prefix and suffix
+        StringJoiner hasfixsj = new StringJoiner(INFIX, PREFIX, SUFFIX);
+        assertEquals(hasfixsj.toString(), PREFIX + SUFFIX);
+        hasfixsj.setEmptyValue(emptyExpectedStr);
+        assertEquals(hasfixsj.toString(), emptyExpectedStr);
+
+        assertEquals(hasfixsj.add(randAddStr).toString(), PREFIX + randAddStr + SUFFIX);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/concurrent/AtomicInteger/LambdaTest.java	Wed Aug 14 15:53:13 2013 -0700
@@ -0,0 +1,175 @@
+/*
+ * 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 test for AtomicInteger.updateAndGet()/getAndUpdate() and
+ * AtomicInteger.accumulateAndGet()/getAndAccumulate();
+ * @(#) LambdaTest.java
+ * @library /sqeutil
+ * @author Tristan Yan
+ * @bug 8001666
+ * @run testng LambdaTest
+ */
+
+import java.util.Random;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.FutureTask;
+import java.util.concurrent.atomic.AtomicInteger;
+import static org.testng.Assert.*;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+public class LambdaTest {
+    private static enum Type{updateAndGet, getAndUpdate, accumulateAndGet, getAndAccumulate};
+
+    private static Random rand = new Random(System.currentTimeMillis());
+
+    private final static int MAX_VALUE = 1 << 24;
+
+    private final static int MIN_VALUE = -1 << 24;
+
+    private final static int OP_TIMES = 1 << 10;
+
+    private final static int THREAD_NUM = 1 << 4;
+
+    @DataProvider
+    public Object[][] booleanProvider(){
+        Object[][] providersParam = new Object[Type.values().length][];
+        Object[] a = Type.values();
+        for(int i = 0; i < a.length; i++)
+            providersParam[i] = new Object[]{a[i]};
+        return providersParam;
+    }
+
+    @Test(dataProvider = "booleanProvider")
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    public void test(final Type type) throws InterruptedException,
+            ExecutionException {
+        int initValue = MIN_VALUE + rand.nextInt(MAX_VALUE - MIN_VALUE);
+        final AtomicInteger ai = new AtomicInteger(initValue);
+        final int randPlus = MIN_VALUE + rand.nextInt(MAX_VALUE - MIN_VALUE);
+        final int randMinus = MIN_VALUE + rand.nextInt(MAX_VALUE - MIN_VALUE);
+        switch(type) {
+            case updateAndGet: 
+                assertEquals(ai.updateAndGet(LambdaUtilities.addIntUnaryOperator(randPlus))
+                    , initValue + randPlus);
+                assertEquals(ai.updateAndGet(LambdaUtilities.subIntUnaryOperator(randMinus))
+                    , initValue + randPlus - randMinus);
+                break;
+            case getAndUpdate:
+                assertEquals(ai.getAndUpdate(LambdaUtilities.addIntUnaryOperator(randPlus))
+                    , initValue);
+                assertEquals(ai.getAndUpdate(LambdaUtilities.subIntUnaryOperator(randMinus))
+                    , initValue + randPlus);
+                break;
+            case accumulateAndGet:
+                assertEquals(ai.accumulateAndGet(randPlus,LambdaUtilities.addIntBinaryOperator())
+                    , initValue + randPlus);
+                assertEquals(ai.accumulateAndGet(randMinus,LambdaUtilities.subIntBinaryOperator())
+                    , initValue + randPlus - randMinus);
+                break;
+            case getAndAccumulate:
+                assertEquals(ai.getAndAccumulate(randPlus,LambdaUtilities.addIntBinaryOperator())
+                    , initValue);
+                assertEquals(ai.getAndAccumulate(randMinus,LambdaUtilities.subIntBinaryOperator())
+                    , initValue + randPlus);
+                break;
+        }
+        assertEquals(ai.get(), initValue + randPlus - randMinus);
+
+        ai.set(initValue);
+        Callable<Integer> ac = new Callable<Integer>(){
+            @Override
+            public Integer call() throws Exception {
+                int plusTimes1 = 0;
+                for(int index = 0; index < OP_TIMES; index++) {
+                    boolean plus = rand.nextBoolean();
+                    if(plus) plusTimes1++;
+                    switch(type) {
+                        case updateAndGet:
+                            ai.updateAndGet(plus ?
+                                LambdaUtilities.addIntUnaryOperator(randPlus) :
+                                LambdaUtilities.subIntUnaryOperator(randMinus));
+                            break;
+                        case getAndUpdate:
+                            ai.getAndUpdate(plus ?
+                                LambdaUtilities.addIntUnaryOperator(randPlus) :
+                                LambdaUtilities.subIntUnaryOperator(randMinus));
+                            break;
+                        case accumulateAndGet:
+                            ai.accumulateAndGet(plus ? randPlus : randMinus,
+                                plus ? LambdaUtilities.addIntBinaryOperator() :
+                                    LambdaUtilities.subIntBinaryOperator());
+                            break;
+                        case getAndAccumulate:
+                            ai.getAndAccumulate(plus ? randPlus : randMinus,
+                                plus ? LambdaUtilities.addIntBinaryOperator() :
+                                    LambdaUtilities.subIntBinaryOperator());
+                    }
+                }
+                return plusTimes1;
+            }
+
+        };
+        FutureTask[] futures = new FutureTask[THREAD_NUM -1];
+        for(int i = 0; i < THREAD_NUM -1; i++) {
+            futures[i] = new FutureTask<Integer>(ac);
+            new Thread(futures[i]).start();
+        }
+
+        int plusTimes = 0;
+        for(int index = 0; index < OP_TIMES; index++) {
+            boolean plus = rand.nextBoolean();
+            if(plus) plusTimes++;
+            switch(type) {
+                case updateAndGet:
+                    ai.updateAndGet(plus ?
+                        LambdaUtilities.addIntUnaryOperator(randPlus) :
+                        LambdaUtilities.subIntUnaryOperator(randMinus));
+                    break;
+                case getAndUpdate:
+                    ai.getAndUpdate(plus ?
+                        LambdaUtilities.addIntUnaryOperator(randPlus) :
+                        LambdaUtilities.subIntUnaryOperator(randMinus));
+                    break;
+                case accumulateAndGet:
+                    ai.accumulateAndGet(plus ? randPlus : randMinus,
+                        plus ? LambdaUtilities.addIntBinaryOperator() :
+                            LambdaUtilities.subIntBinaryOperator());
+                    break;
+                case getAndAccumulate:
+                    ai.getAndAccumulate(plus ? randPlus : randMinus,
+                        plus ? LambdaUtilities.addIntBinaryOperator() :
+                            LambdaUtilities.subIntBinaryOperator());
+            }
+        }
+        for(int i = 0; i < THREAD_NUM -1; i++) {
+            plusTimes += ((FutureTask<Integer>)futures[i]).get();
+        }
+        int expected = initValue + plusTimes * randPlus -
+                (THREAD_NUM * OP_TIMES - plusTimes) * randMinus;
+        assertEquals(expected, ai.get());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/concurrent/AtomicIntegerFieldUpdater/LambdaTest.java	Wed Aug 14 15:53:13 2013 -0700
@@ -0,0 +1,182 @@
+/*
+ * 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 test for AtomicIntegerUpdateField.updateAndGet()/getAndUpdate() and 
+ * AtomicIntegerUpdateField.accumulateAndGet()/getAndAccumulate();
+ * @(#) LambdaTest.java
+ * @library /sqeutil
+ * @author Tristan Yan
+ * @run testng LambdaTest
+ * @bug 8001666
+ */
+
+import java.util.Random;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.FutureTask;
+import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
+import static org.testng.Assert.*;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+public class LambdaTest {
+    private static enum Type{updateAndGet, getAndUpdate, accumulateAndGet, getAndAccumulate};
+
+    private static Random rand = new Random(System.currentTimeMillis());
+
+    private final static int MAX_VALUE = 1 << 24;
+
+    private final static int MIN_VALUE = -1 << 24;
+
+    private final static int OP_TIMES = 1 << 10;
+
+    private final static int THREAD_NUM = 1 << 4;
+
+    @DataProvider
+    public Object[][] booleanProvider(){
+        Object[][] providersParam = new Object[Type.values().length][];
+        Object[] a = Type.values();
+        for(int i = 0; i < a.length; i++)
+            providersParam[i] = new Object[]{a[i]};
+        return providersParam;
+    }
+
+    @Test(dataProvider = "booleanProvider")
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    public void test(final Type type) throws InterruptedException,
+            ExecutionException {
+        final Updater u = new Updater();
+        final AtomicIntegerFieldUpdater<Updater> accAIFU = AtomicIntegerFieldUpdater.<Updater>newUpdater((Class<Updater>)(Class<?>)u.getClass(), "accumulation");
+        final int randPlus = MIN_VALUE + rand.nextInt(MAX_VALUE - MIN_VALUE);
+        final int randMinus = MIN_VALUE + rand.nextInt(MAX_VALUE - MIN_VALUE);
+        switch(type) {
+            case updateAndGet: 
+                assertEquals(accAIFU.updateAndGet(u, 
+                        LambdaUtilities.addIntUnaryOperator(randPlus)), randPlus);
+                assertEquals(accAIFU.updateAndGet(u, 
+                        LambdaUtilities.subIntUnaryOperator(randMinus)), randPlus - randMinus);
+                break;
+            case getAndUpdate:
+                assertEquals(accAIFU.getAndUpdate(u, 
+                        LambdaUtilities.addIntUnaryOperator(randPlus)), 0);
+                assertEquals(accAIFU.getAndUpdate(u, 
+                        LambdaUtilities.subIntUnaryOperator(randMinus)), randPlus);
+                break;
+            case accumulateAndGet:
+                assertEquals(accAIFU.accumulateAndGet(u, randPlus, 
+                        LambdaUtilities.addIntBinaryOperator()), randPlus);
+                assertEquals(accAIFU.accumulateAndGet(u, randMinus,
+                        LambdaUtilities.subIntBinaryOperator()), randPlus - randMinus);
+                break;
+            case getAndAccumulate:
+                assertEquals(accAIFU.getAndAccumulate(u, randPlus, 
+                        LambdaUtilities.addIntBinaryOperator()), 0);
+                assertEquals(accAIFU.getAndAccumulate(u, randMinus,
+                        LambdaUtilities.subIntBinaryOperator()), randPlus);
+                break;
+        }
+        assertEquals(u.accumulation, randPlus - randMinus);
+
+        u.accumulation = 0;
+
+        Callable<Integer> ac = new Callable<Integer>(){
+            @Override
+            public Integer call() throws Exception {
+                int plusTimes = 0;
+                for(int index = 0; index < OP_TIMES; index++) {
+                    boolean plus = rand.nextBoolean();
+                    if(plus) plusTimes++;
+                    switch(type) {
+                        case updateAndGet:
+                            accAIFU.updateAndGet(u, plus ?
+                                LambdaUtilities.addIntUnaryOperator(randPlus) :
+                                LambdaUtilities.subIntUnaryOperator(randMinus));
+                            break;
+                        case getAndUpdate:
+                            accAIFU.getAndUpdate(u, plus ?
+                                LambdaUtilities.addIntUnaryOperator(randPlus) :
+                                LambdaUtilities.subIntUnaryOperator(randMinus));
+                            break;
+                        case accumulateAndGet:
+                            accAIFU.accumulateAndGet(u, plus ? randPlus : randMinus,
+                                plus ? LambdaUtilities.addIntBinaryOperator() :
+                                    LambdaUtilities.subIntBinaryOperator());
+                            break;
+                        case getAndAccumulate:
+                            accAIFU.getAndAccumulate(u, plus ? randPlus : randMinus,
+                                plus ? LambdaUtilities.addIntBinaryOperator() :
+                                    LambdaUtilities.subIntBinaryOperator());
+                            break;
+                    }
+                }
+                return plusTimes;
+            }
+        };
+
+        FutureTask[] futures = new FutureTask[THREAD_NUM -1];
+        for(int i = 0; i < THREAD_NUM -1; i++) {
+            futures[i] = new FutureTask<Integer>(ac);
+            new Thread(futures[i]).start();
+        }
+        int plusTimes = 0;
+        for(int index = 0; index < OP_TIMES; index++) {
+            boolean plus = rand.nextBoolean();
+            if(plus) plusTimes++;
+            switch(type) {
+                case updateAndGet:
+                    accAIFU.updateAndGet(u, plus ?
+                        LambdaUtilities.addIntUnaryOperator(randPlus) :
+                        LambdaUtilities.subIntUnaryOperator(randMinus));
+                    break;
+                case getAndUpdate:
+                    accAIFU.getAndUpdate(u, plus ?
+                        LambdaUtilities.addIntUnaryOperator(randPlus) :
+                        LambdaUtilities.subIntUnaryOperator(randMinus));
+                    break;
+                case accumulateAndGet:
+                    accAIFU.accumulateAndGet(u, plus ? randPlus : randMinus,
+                        plus ? LambdaUtilities.addIntBinaryOperator() :
+                            LambdaUtilities.subIntBinaryOperator());
+                    break;
+                case getAndAccumulate:
+                    accAIFU.getAndAccumulate(u, plus ? randPlus : randMinus,
+                        plus ? LambdaUtilities.addIntBinaryOperator() :
+                            LambdaUtilities.subIntBinaryOperator());
+                    break;
+            }
+        }
+        for(int i = 0; i < THREAD_NUM -1; i++) {
+            plusTimes += ((FutureTask<Integer>)futures[i]).get();
+        }
+        int expected = plusTimes * randPlus -
+                (THREAD_NUM * OP_TIMES - plusTimes) * randMinus;
+        assertEquals(expected, u.accumulation);
+    }
+
+    static class Updater{
+        public volatile int accumulation;
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/concurrent/AtomicLong/LambdaTest.java	Wed Aug 14 15:53:13 2013 -0700
@@ -0,0 +1,245 @@
+/*
+ * 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 test AtomicLong.updateAndGet()/getAndUpdate() and
+ * AtomicLong.accumulateAndGet()/getAndAccumulate();
+ * @(#) LambdaTest.java
+ * @library /sqeutil
+ * @author Tristan Yan
+ * @run testng LambdaTest
+ * @bug 8001666
+ */
+
+import java.util.Random;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.atomic.AtomicLong;
+import static org.testng.Assert.*;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+
+public class LambdaTest {
+    private static enum Type{updateAndGet, getAndUpdate, accumulateAndGet, getAndAccumulate};
+
+    private static Random rand = new Random(System.currentTimeMillis());
+
+    private final static int MAX_VALUE = 1 << 24;
+
+    private final static int MIN_VALUE = -1 << 24;
+
+    private final static int OP_TIMES = 1 << 10;
+
+    private final static int THREAD_NUM = 1 << 4;
+
+    @DataProvider
+    public Object[][] booleanProvider(){
+        Object[][] providersParam = new Object[Type.values().length][];
+        Object[] a = Type.values();
+        for(int i = 0; i < a.length; i++)
+            providersParam[i] = new Object[]{a[i]};
+        return providersParam;
+    }
+
+    @Test(dataProvider = "booleanProvider")
+    public void test(final Type type) throws InterruptedException,
+            ExecutionException {
+        long initValue = rand.nextLong();
+        final AtomicLong al = new AtomicLong(initValue);
+        long tl1 = rand.nextLong();
+        if(((byte)(tl1 >> 63) & (byte)(initValue >> 63)) == 0){
+            if(initValue > 0) {
+                if(tl1 > Long.MAX_VALUE - initValue)
+                    tl1 = - tl1;
+            } else {
+                if(tl1 < Long.MIN_VALUE - initValue)
+                    tl1 = - tl1;
+            }
+        }
+        final long randPlus = tl1;
+
+        long tl2 = rand.nextLong();
+        if(((byte)(tl2 >> 63) & (byte)(initValue + randPlus >> 63)) == 1){
+            if(initValue + randPlus > 0) {
+                if(-tl2 > Long.MAX_VALUE - (initValue + randPlus))
+                    tl2 = - tl2;
+            } else {
+                if(tl2 < Long.MIN_VALUE + (initValue + randPlus))
+                    tl2 = - tl2;
+            }
+        }
+        final long randMinus = tl2;
+        switch(type) {
+            case updateAndGet: 
+                assertEquals(al.updateAndGet(LambdaUtilities.addLongUnaryOperator(randPlus))
+                    , initValue + randPlus);
+                assertEquals(al.updateAndGet(LambdaUtilities.subLongUnaryOperator(randMinus))
+                    , initValue + randPlus - randMinus);
+                break;
+            case getAndUpdate:
+                assertEquals(al.getAndUpdate(LambdaUtilities.addLongUnaryOperator(randPlus))
+                    , initValue);
+                assertEquals(al.getAndUpdate(LambdaUtilities.subLongUnaryOperator(randMinus))
+                    , initValue + randPlus);
+                break;
+            case accumulateAndGet: 
+                assertEquals(al.accumulateAndGet(randPlus, LambdaUtilities.addLongBinaryOperator())
+                    , initValue + randPlus);
+                assertEquals(al.accumulateAndGet(randMinus, LambdaUtilities.subLongBinaryOperator())
+                    , initValue + randPlus - randMinus);
+                break;
+            case getAndAccumulate:
+                assertEquals(al.getAndAccumulate(randPlus, LambdaUtilities.addLongBinaryOperator())
+                    , initValue);
+                assertEquals(al.getAndAccumulate(randMinus, LambdaUtilities.subLongBinaryOperator())
+                    , initValue + randPlus);
+                break;
+        }
+        assertEquals(al.get() , initValue + randPlus - randMinus);
+
+        final long randPlus1 = rand.nextBoolean() ? (long)rand.nextInt(MAX_VALUE) : -(long)rand.nextInt(MAX_VALUE);
+        final long randMinus1 = rand.nextBoolean() ? (long)rand.nextInt(MAX_VALUE) : -(long)rand.nextInt(MAX_VALUE);
+        al.set(initValue);
+        final int mainPLusTimes = 0;
+        int minusPLusTimes = 0;
+
+        class UpdateThread  extends Thread{
+            OpTimes ops;
+            CountDownLatch latch;
+            UpdateThread(OpTimes ops, CountDownLatch latch){
+                this.ops = ops;
+                this.latch = latch;
+            }
+            @Override
+            public void run() {
+                int plusTimes = 0;
+                int minusTimes = 0;
+                for(int index = 0; index < OP_TIMES; index++) {
+                    boolean plus = rand.nextBoolean();
+                    if(plus) {
+                        if (randPlus1 > 0 && al.get() > Long.MAX_VALUE - randPlus1
+                                || randPlus1 < 0 && al.get() < Long.MIN_VALUE - randPlus1)
+                            continue;
+                    }
+                    else  {
+                        if (randPlus1 > 0 && al.get() < Long.MIN_VALUE + randPlus1
+                                || randPlus1 > 0 && al.get() > Long.MAX_VALUE - randPlus1)
+                            continue;
+                    }
+                    switch(type) {
+                        case updateAndGet: 
+                            al.updateAndGet(plus ?
+                                LambdaUtilities.addLongUnaryOperator(randPlus1) :
+                                LambdaUtilities.subLongUnaryOperator(randMinus1));
+                            break;
+                        case getAndUpdate:
+                            al.getAndUpdate(plus ?
+                                LambdaUtilities.addLongUnaryOperator(randPlus1) :
+                                LambdaUtilities.subLongUnaryOperator(randMinus1));
+                            break;
+                        case accumulateAndGet: 
+                            al.accumulateAndGet(plus ? randPlus1 : randMinus1,
+                                plus ? LambdaUtilities.addLongBinaryOperator() :
+                                    LambdaUtilities.subLongBinaryOperator());
+                            break;
+                        case getAndAccumulate:
+                            al.getAndAccumulate(plus ? randPlus1 : randMinus1,
+                                plus ? LambdaUtilities.addLongBinaryOperator() :
+                                    LambdaUtilities.subLongBinaryOperator());
+                            break;
+                    }
+                    if(plus)
+                        plusTimes++;
+                    else
+                        minusTimes++;
+                }
+                ops.plus = plusTimes;
+                ops.minus = minusTimes;
+                latch.countDown();
+            }
+
+        };
+        OpTimes[] opts = new OpTimes[THREAD_NUM -1];
+        CountDownLatch latch = new CountDownLatch(THREAD_NUM -1);
+        for(int i = 0; i < THREAD_NUM -1; i++) {
+            opts[i] = new OpTimes();
+            new UpdateThread(opts[i], latch).start();
+        }
+        int plusTimes = 0;
+        int minusTimes = 0;
+        for(int index = 0; index < OP_TIMES; index++) {
+            boolean plus = rand.nextBoolean();
+            if(plus) {
+                if (randPlus1 > 0 && al.get() > Long.MAX_VALUE - randPlus1
+                        || randPlus1 < 0 && al.get() < Long.MIN_VALUE - randPlus1)
+                    continue;
+            }
+            else  {
+                if (randPlus1 > 0 && al.get() < Long.MIN_VALUE + randPlus1
+                        || randPlus1 > 0 && al.get() > Long.MAX_VALUE - randPlus1)
+                    continue;
+            }
+            switch(type) {
+                case updateAndGet: 
+                    al.updateAndGet(plus ?
+                        LambdaUtilities.addLongUnaryOperator(randPlus1) :
+                        LambdaUtilities.subLongUnaryOperator(randMinus1));
+                    break;
+                case getAndUpdate:
+                    al.getAndUpdate(plus ?
+                        LambdaUtilities.addLongUnaryOperator(randPlus1) :
+                        LambdaUtilities.subLongUnaryOperator(randMinus1));
+                    break;
+                case accumulateAndGet: 
+                    al.accumulateAndGet(plus ? randPlus1 : randMinus1,
+                        plus ? LambdaUtilities.addLongBinaryOperator() :
+                            LambdaUtilities.subLongBinaryOperator());
+                    break;
+                case getAndAccumulate:
+                    al.getAndAccumulate(plus ? randPlus1 : randMinus1,
+                        plus ? LambdaUtilities.addLongBinaryOperator() :
+                            LambdaUtilities.subLongBinaryOperator());
+                    break;
+            }
+            if(plus)
+                plusTimes++;
+            else
+                minusTimes++;
+        }
+        latch.await();
+        for(int i = 0; i < THREAD_NUM -1; i++) {
+            plusTimes += opts[i].plus;
+            minusTimes += opts[i].minus;
+        }
+        long expected = initValue + plusTimes * randPlus1 -
+                minusTimes * randMinus1;
+        assertEquals(expected, al.get());
+    }
+}
+class OpTimes{
+    public int plus;
+
+    public int minus;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/concurrent/AtomicLongFieldUpdater/LambdaTest.java	Wed Aug 14 15:53:13 2013 -0700
@@ -0,0 +1,213 @@
+/*
+ * 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 test AtomicLongFieldUpdater.updateAndGet()/getAndUpdate() and
+ * AtomicLongFieldUpdater.accumulateAndGet()/getAndAccumulate();
+ * @(#) LambdaTest.java
+ * @library /sqeutil
+ * @author Tristan Yan
+ * @run testng LambdaTest
+ * @bug 8001666
+ */
+
+import java.util.Random;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.atomic.AtomicLongFieldUpdater;
+import static org.testng.Assert.*;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+public class LambdaTest {
+    private static enum Type{updateAndGet, getAndUpdate, accumulateAndGet, getAndAccumulate};
+
+    private static Random rand = new Random(System.currentTimeMillis());
+
+    private final static int OP_TIMES = 1 << 10;
+
+    private final static int THREAD_NUM = 1 << 4;
+
+    @DataProvider
+    public Object[][] booleanProvider(){
+        Object[][] providersParam = new Object[Type.values().length][];
+        Object[] a = Type.values();
+        for(int i = 0; i < a.length; i++)
+            providersParam[i] = new Object[]{a[i]};
+        return providersParam;
+    }
+
+    @Test(dataProvider = "booleanProvider")
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    public void test(final Type type) throws InterruptedException,
+            ExecutionException {
+        long initValue = rand.nextLong();
+        final Updater u = new Updater();
+        u.accumulation = initValue;
+        final AtomicLongFieldUpdater<Updater> accAIFU
+                = AtomicLongFieldUpdater.<Updater>newUpdater((Class<Updater>)(Class<?>)u.getClass(), "accumulation");
+        final long randPlus = rand.nextLong();
+        final long randMinus = rand.nextLong();
+        switch(type) {
+            case updateAndGet: 
+                assertEquals(accAIFU.updateAndGet(u, 
+                        LambdaUtilities.addLongUnaryOperator(randPlus)), 
+                        initValue + randPlus);
+                assertEquals(accAIFU.updateAndGet(u, 
+                        LambdaUtilities.subLongUnaryOperator(randMinus)), 
+                        initValue + randPlus - randMinus);
+                break;
+            case getAndUpdate:
+                assertEquals(accAIFU.getAndUpdate(u,
+                        LambdaUtilities.addLongUnaryOperator(randPlus)),
+                        initValue);
+                assertEquals(accAIFU.getAndUpdate(u,
+                        LambdaUtilities.subLongUnaryOperator(randMinus)),
+                        initValue + randPlus);
+                break;
+            case accumulateAndGet: 
+                assertEquals(accAIFU.accumulateAndGet(u, randPlus,
+                        LambdaUtilities.addLongBinaryOperator()), 
+                        initValue + randPlus);
+                assertEquals(accAIFU.accumulateAndGet(u, randMinus,
+                        LambdaUtilities.subLongBinaryOperator()), 
+                        initValue + randPlus - randMinus);
+                break;
+            case getAndAccumulate:
+                assertEquals(accAIFU.getAndAccumulate(u, randPlus,
+                        LambdaUtilities.addLongBinaryOperator()),
+                        initValue);
+                assertEquals(accAIFU.getAndAccumulate(u, randMinus,
+                        LambdaUtilities.subLongBinaryOperator()),
+                        initValue + randPlus);
+                break;
+        }
+        assertEquals(u.accumulation, initValue + randPlus - randMinus);
+
+        class UpdateThread  extends Thread{
+            OpTimes ops;
+
+            CountDownLatch latch;
+            UpdateThread(OpTimes ops, CountDownLatch latch){
+                this.ops = ops;
+                this.latch = latch;
+            }
+            @Override
+            public void run() {
+                int plusTimes = 0;
+                int minusTimes = 0;
+                for(int index = 0; index < OP_TIMES; index++) {
+                    boolean plus = rand.nextBoolean();
+                    switch(type) {
+                        case updateAndGet:
+                            accAIFU.updateAndGet(u, plus ?
+                                LambdaUtilities.addLongUnaryOperator(randPlus) :
+                                LambdaUtilities.subLongUnaryOperator(randMinus));
+                            break;
+                        case getAndUpdate:
+                            accAIFU.getAndUpdate(u, plus ?
+                                LambdaUtilities.addLongUnaryOperator(randPlus) :
+                                LambdaUtilities.subLongUnaryOperator(randMinus));
+                            break;
+                        case accumulateAndGet:
+                            accAIFU.accumulateAndGet(u, plus ? randPlus : randMinus,
+                                plus ? LambdaUtilities.addLongBinaryOperator() :
+                                    LambdaUtilities.subLongBinaryOperator());
+                            break;
+                        case getAndAccumulate:
+                            accAIFU.getAndAccumulate(u, plus ? randPlus : randMinus,
+                                plus ? LambdaUtilities.addLongBinaryOperator() :
+                                    LambdaUtilities.subLongBinaryOperator());
+                            break;
+                    }
+                    if(plus)
+                        plusTimes++;
+                    else
+                        minusTimes++;
+                }
+                ops.plus = plusTimes;
+                ops.minus = minusTimes;
+                latch.countDown();
+            }
+        };
+        u.accumulation = initValue;
+
+        int plusTimes = 0;
+        int minusTimes = 0;
+        OpTimes[] opts = new OpTimes[THREAD_NUM -1];
+        CountDownLatch latch = new CountDownLatch(THREAD_NUM -1);
+        for(int i = 0; i < THREAD_NUM -1; i++) {
+            opts[i] = new OpTimes();
+            new UpdateThread(opts[i], latch).start();
+        }
+
+        for(int index = 0; index < OP_TIMES; index++) {
+            boolean plus = rand.nextBoolean();
+            switch(type) {
+                case updateAndGet:
+                    accAIFU.updateAndGet(u, plus ?
+                        LambdaUtilities.addLongUnaryOperator(randPlus) :
+                        LambdaUtilities.subLongUnaryOperator(randMinus));
+                    break;
+                case getAndUpdate:
+                    accAIFU.getAndUpdate(u, plus ?
+                        LambdaUtilities.addLongUnaryOperator(randPlus) :
+                        LambdaUtilities.subLongUnaryOperator(randMinus));
+                    break;
+                case accumulateAndGet:
+                    accAIFU.accumulateAndGet(u, plus ? randPlus : randMinus,
+                        plus ? LambdaUtilities.addLongBinaryOperator() :
+                            LambdaUtilities.subLongBinaryOperator());
+                    break;
+                case getAndAccumulate:
+                    accAIFU.getAndAccumulate(u, plus ? randPlus : randMinus,
+                        plus ? LambdaUtilities.addLongBinaryOperator() :
+                            LambdaUtilities.subLongBinaryOperator());
+                    break;
+            }
+            if(plus)
+                plusTimes++;
+            else
+                minusTimes++;
+        }
+        latch.await();
+        for(int i = 0; i < THREAD_NUM -1; i++) {
+            plusTimes += opts[i].plus;
+            minusTimes += opts[i].minus;
+        }
+        long expected = initValue + plusTimes * randPlus -
+                minusTimes * randMinus;
+        assertEquals(expected, u.accumulation);
+    }
+
+    static class Updater{
+        public volatile long accumulation;
+    }
+
+    static class OpTimes{
+        public int plus;
+
+        public int minus;
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/concurrent/AtomicReference/LambdaTest.java	Wed Aug 14 15:53:13 2013 -0700
@@ -0,0 +1,221 @@
+/*
+ * 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 test for AtomicReference.updateAndGet()/getAndUpdate() and
+ * AtomicReference.accumulateAndGet()/getAndAccumulate();
+ * @(#) LambdaTest.java
+ * @library ../../
+ * @author Tristan Yan
+ * @run testng LambdaTest
+ * @bug 8001666
+ */
+
+import java.util.Random;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.BinaryOperator;
+import java.util.function.UnaryOperator;
+import static org.testng.Assert.*;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+public class LambdaTest {
+    private static enum Type{updateAndGet, getAndUpdate, accumulateAndGet, getAndAccumulate};
+
+    private static Random rand = new Random(System.currentTimeMillis());
+
+    private final static int OP_TIMES = 1 << 10;
+
+    private final static int THREAD_NUM = 1 << 4;
+
+    @DataProvider
+    public Object[][] booleanProvider(){
+        Object[][] providersParam = new Object[Type.values().length][];
+        Object[] a = Type.values();
+        for(int i = 0; i < a.length; i++)
+            providersParam[i] = new Object[]{a[i]};
+        return providersParam;
+    }
+
+    @Test(dataProvider = "booleanProvider")
+    public void test(final Type type) throws InterruptedException{
+        int initPlus = rand.nextInt();
+        int initMinus = rand.nextInt();
+        final AtomicReference<OpValues> ar
+                = new AtomicReference<>(new OpValues(initPlus, initMinus));
+        final int oprnd = rand.nextInt();
+        boolean startFromPlus = rand.nextBoolean();
+        switch(type) {
+            case updateAndGet:
+                assertEquals(ar.updateAndGet(opUnaryOperator(startFromPlus, oprnd))
+                    , startFromPlus ? new OpValues(initPlus + oprnd, initMinus) :
+                    new OpValues(initPlus, initMinus - oprnd));
+                assertEquals(ar.updateAndGet(opUnaryOperator(!startFromPlus, oprnd))
+                    , new OpValues(initPlus + oprnd, initMinus - oprnd));
+                break;
+            case getAndUpdate:
+                assertEquals(ar.getAndUpdate(opUnaryOperator(startFromPlus, oprnd))
+                    , new OpValues(initPlus, initMinus));
+                assertEquals(ar.getAndUpdate(opUnaryOperator(!startFromPlus, oprnd))
+                    ,  startFromPlus ? new OpValues(initPlus + oprnd, initMinus) :
+                    new OpValues(initPlus, initMinus - oprnd));
+                break;
+            case accumulateAndGet:
+                assertEquals(ar.accumulateAndGet(
+                        new OpValues(oprnd, oprnd), 
+                        opBinaryOperator(startFromPlus))
+                    , startFromPlus ? new OpValues(initPlus + oprnd, initMinus) :
+                    new OpValues(initPlus, initMinus - oprnd));
+                assertEquals(ar.accumulateAndGet(
+                        new OpValues(oprnd, oprnd),
+                        opBinaryOperator(!startFromPlus))
+                    ,  new OpValues(initPlus + oprnd, initMinus - oprnd));
+                break;
+            case getAndAccumulate:
+                assertEquals(ar.getAndAccumulate(
+                        new OpValues(oprnd, oprnd), 
+                        opBinaryOperator(startFromPlus))
+                    , new OpValues(initPlus, initMinus));
+                assertEquals(ar.getAndAccumulate(
+                        new OpValues(oprnd, oprnd),
+                        opBinaryOperator(!startFromPlus))
+                    ,  startFromPlus ? new OpValues(initPlus + oprnd, initMinus) :
+                    new OpValues(initPlus, initMinus - oprnd));
+                break;
+        }
+        class UpdateThread  extends Thread{
+            CountDownLatch latch;
+            private int plusTimes = 0;
+            private int minusTimes = 0;
+
+            UpdateThread(CountDownLatch latch){
+                this.latch = latch;
+            }
+            @Override
+            public void run() {
+                for(int index = 0; index < OP_TIMES; index++) {
+                    boolean plus = rand.nextBoolean();
+                    switch(type) {
+                        case updateAndGet:
+                            ar.updateAndGet(opUnaryOperator(plus, oprnd));
+                            break;
+                        case getAndUpdate:
+                            ar.getAndUpdate(opUnaryOperator(plus, oprnd));
+                            break;
+                        case accumulateAndGet:
+                            ar.accumulateAndGet(new OpValues(oprnd, oprnd),
+                                    opBinaryOperator(plus));
+                            break;
+                        case getAndAccumulate:
+                            ar.getAndAccumulate(new OpValues(oprnd, oprnd),
+                                    opBinaryOperator(plus));
+                            break;
+                    }
+                    if(plus)
+                        plusTimes++;
+                    else
+                        minusTimes++;
+                }
+                latch.countDown();
+            }
+            int plusTimes(){ return plusTimes; }
+            int minusTimes(){ return minusTimes; }
+        };
+        UpdateThread[] threads = new UpdateThread[THREAD_NUM -1];
+        CountDownLatch latch = new CountDownLatch(THREAD_NUM -1);
+        for(int i = 0; i < THREAD_NUM -1; i++) {
+            threads[i] = new UpdateThread(latch);
+            threads[i].start();
+        }
+        int plusTimes = 0;
+        int minusTimes = 0;
+        for(int index = 0; index < OP_TIMES; index++) {
+            boolean isPlus = rand.nextBoolean();
+            switch(type) {
+                case updateAndGet:
+                    ar.updateAndGet(opUnaryOperator(isPlus, oprnd));
+                    break;
+                case getAndUpdate:
+                    ar.getAndUpdate(opUnaryOperator(isPlus, oprnd));
+                    break;
+                case accumulateAndGet:
+                    ar.accumulateAndGet(new OpValues(oprnd, oprnd),
+                            opBinaryOperator(isPlus));
+                    break;
+                case getAndAccumulate:
+                    ar.getAndAccumulate(new OpValues(oprnd, oprnd),
+                            opBinaryOperator(isPlus));
+                    break;
+            }
+            if(isPlus)
+                plusTimes++;
+            else
+                minusTimes++;
+        }
+        latch.await();
+        for(int i = 0; i < THREAD_NUM -1; i++) {
+            plusTimes += threads[i].plusTimes();
+            minusTimes += threads[i].minusTimes();
+        }
+        assertEquals(ar.get().getPlusAccumulated(), initPlus + plusTimes * oprnd + oprnd);
+        assertEquals(ar.get().getMinusAccumulated(), initMinus - minusTimes * oprnd - oprnd);
+    }
+
+    static final class OpValues{
+        final int plusAccumulated;
+
+        final int minusAccumulated;
+
+        OpValues(int plusAccumulated, int minusAccumulated){
+            this.plusAccumulated = plusAccumulated;
+            this.minusAccumulated = minusAccumulated;
+        }
+
+        OpValues operate(boolean isPlus, int value) {
+            if(isPlus)
+                return new OpValues(plusAccumulated + value, minusAccumulated);
+            else
+                return new OpValues(plusAccumulated, minusAccumulated - value);
+        }
+
+        int getPlusAccumulated(){    return plusAccumulated;  }
+        int getMinusAccumulated(){    return minusAccumulated;  }
+
+        @Override
+        public boolean equals(Object o){
+            OpValues opv = (OpValues)o;
+            return (opv.plusAccumulated == plusAccumulated)
+                    && (opv.minusAccumulated == minusAccumulated);
+        }
+    }
+
+    public static UnaryOperator<OpValues> opUnaryOperator(boolean isPlus, int value) {
+        return t -> t.operate(isPlus, value);
+    }
+
+    public static BinaryOperator<OpValues> opBinaryOperator(boolean isPlus) {
+        return (t1, t2) -> t1.operate(isPlus, isPlus ? t2.getPlusAccumulated() : t2.getMinusAccumulated());
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/concurrent/AtomicReferenceFieldUpdater/LambdaTest.java	Wed Aug 14 15:53:13 2013 -0700
@@ -0,0 +1,215 @@
+/*
+ * 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 test for AtomicReferenceFieldUpdater.updateAndGet()/getAndUpdate()
+ * and AtomicReferenceFieldUpdater.accumulateAndGet()/getAndAccumulate();
+ * @(#) LambdaTest.java
+ * @library ../../
+ * @author Tristan Yan
+ * @run testng LambdaTest
+ * @bug 8001666
+ */
+
+import java.util.Random;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
+import java.util.function.BinaryOperator;
+import java.util.function.UnaryOperator;
+import static org.testng.Assert.*;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+public class LambdaTest {
+    private static enum Type{updateAndGet, getAndUpdate, accumulateAndGet, getAndAccumulate};
+
+    private static Random rand = new Random(System.currentTimeMillis());
+
+    private final static int OP_TIMES = 1 << 10;
+
+    private final static int THREAD_NUM = 1 << 4;
+
+    @DataProvider
+    public Object[][] booleanProvider(){
+        Object[][] providersParam = new Object[Type.values().length][];
+        Object[] a = Type.values();
+        for(int i = 0; i < a.length; i++)
+            providersParam[i] = new Object[]{a[i]};
+        return providersParam;
+    }
+
+    @Test(dataProvider = "booleanProvider")
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    public void test(final Type type) throws InterruptedException{
+        int initValue = rand.nextInt();
+        final Updater u = new Updater();
+        u.accumulation = new OpValues(initValue);
+        final AtomicReferenceFieldUpdater<Updater, OpValues> accARFU
+                = AtomicReferenceFieldUpdater.<Updater, OpValues>newUpdater((Class<Updater>)(Class<?>)u.getClass(), (Class<OpValues>)(Class<?>)u.accumulation.getClass(),  "accumulation");
+
+        final int oprnd = rand.nextInt();
+        boolean startFromPlus = rand.nextBoolean();
+        switch(type) {
+            case updateAndGet:
+                assertEquals(accARFU.updateAndGet(u,opUnaryOperator(startFromPlus, oprnd))
+                    , new OpValues(startFromPlus ? initValue + oprnd : initValue - oprnd));
+                assertEquals(accARFU.updateAndGet(u,opUnaryOperator(!startFromPlus, oprnd))
+                    , new OpValues(initValue));
+                break;
+            case getAndUpdate:
+                assertEquals(accARFU.getAndUpdate(u,opUnaryOperator(startFromPlus, oprnd))
+                    , new OpValues(initValue));
+                assertEquals(accARFU.getAndUpdate(u,opUnaryOperator(!startFromPlus, oprnd))
+                    , new OpValues(startFromPlus ? initValue + oprnd : initValue - oprnd));
+                break;
+            case accumulateAndGet:
+                assertEquals(accARFU.accumulateAndGet(u, new OpValues(oprnd),
+                        opBinaryOperator(startFromPlus))
+                    , new OpValues(startFromPlus ? initValue + oprnd : initValue - oprnd));
+                assertEquals(accARFU.accumulateAndGet(u, new OpValues(oprnd),
+                        opBinaryOperator(!startFromPlus))
+                    , new OpValues(initValue));
+                break;
+            case getAndAccumulate:
+                assertEquals(accARFU.getAndAccumulate(u, new OpValues(oprnd),
+                        opBinaryOperator(startFromPlus))
+                    , new OpValues(initValue));
+                assertEquals(accARFU.getAndAccumulate(u, new OpValues(oprnd),
+                        opBinaryOperator(!startFromPlus))
+                    , new OpValues(startFromPlus ? initValue + oprnd : initValue - oprnd));
+                break;
+        }
+        class UpdateThread  extends Thread{
+            CountDownLatch latch;
+            private int plusTimes = 0;
+            private int minusTimes = 0;
+
+            UpdateThread(CountDownLatch latch){
+                this.latch = latch;
+            }
+            @Override
+            public void run() {
+                for(int index = 0; index < OP_TIMES; index++) {
+                    boolean plus = rand.nextBoolean();
+                    switch(type) {
+                        case updateAndGet:
+                            accARFU.updateAndGet(u,opUnaryOperator(plus, oprnd));
+                            break;
+                        case getAndUpdate:
+                            accARFU.getAndUpdate(u,opUnaryOperator(plus, oprnd));
+                            break;
+                        case accumulateAndGet:
+                            accARFU.accumulateAndGet(u, new OpValues(oprnd),
+                                    opBinaryOperator(plus));
+                            break;
+                        case getAndAccumulate:
+                            accARFU.getAndAccumulate(u, new OpValues(oprnd),
+                                    opBinaryOperator(plus));
+                            break;
+                    }
+                    if(plus)
+                        plusTimes++;
+                    else
+                        minusTimes++;
+                }
+                latch.countDown();
+            }
+            int plusTimes(){ return plusTimes; }
+            int minusTimes(){ return minusTimes; }
+        };
+        UpdateThread[] threads = new UpdateThread[THREAD_NUM -1];
+        CountDownLatch latch = new CountDownLatch(THREAD_NUM -1);
+        for(int i = 0; i < THREAD_NUM -1; i++) {
+            threads[i] = new UpdateThread(latch);
+            threads[i].start();
+        }
+        int plusTimes = 0;
+        int minusTimes = 0;
+        for(int index = 0; index < OP_TIMES; index++) {
+            boolean isPlus = rand.nextBoolean();
+            switch(type) {
+                case updateAndGet:
+                    accARFU.updateAndGet(u,opUnaryOperator(isPlus, oprnd));
+                    break;
+                case getAndUpdate:
+                    accARFU.getAndUpdate(u,opUnaryOperator(isPlus, oprnd));
+                    break;
+                case accumulateAndGet:
+                    accARFU.accumulateAndGet(u, new OpValues(oprnd),
+                            opBinaryOperator(isPlus));
+                    break;
+                case getAndAccumulate:
+                    accARFU.getAndAccumulate(u, new OpValues(oprnd),
+                            opBinaryOperator(isPlus));
+                    break;
+            }
+            if(isPlus)
+                plusTimes++;
+            else
+                minusTimes++;
+        }
+        latch.await();
+        for(int i = 0; i < THREAD_NUM -1; i++) {
+            plusTimes += threads[i].plusTimes();
+            minusTimes += threads[i].minusTimes();
+        }
+        assertEquals(accARFU.get(u).getAccumulated(), initValue + plusTimes * oprnd - minusTimes * oprnd);
+    }
+
+    static final class OpValues{
+        int accumulated;
+
+        OpValues(int accumulated){
+            this.accumulated = accumulated;
+        }
+
+        OpValues operate(boolean isPlus, int value) {
+            if(isPlus)
+                return new OpValues(accumulated + value);
+            else
+                return new OpValues(accumulated - value);
+        }
+
+        int getAccumulated(){    return accumulated;  }
+
+        @Override
+        public boolean equals(Object o){
+            OpValues opv = (OpValues)o;
+            return (opv.accumulated == accumulated);
+        }
+    }
+
+
+    static class Updater{
+        public volatile OpValues accumulation;
+    }
+
+    public static UnaryOperator<OpValues> opUnaryOperator(boolean isPlus, int value) {
+        return t -> t.operate(isPlus, value);
+    }
+
+    public static BinaryOperator<OpValues> opBinaryOperator(boolean isPlus) {
+        return (t1, t2) -> t1.operate(isPlus, t2.getAccumulated());
+    }
+}
\ No newline at end of file
--- a/test/java/util/concurrent/CompletableFuture/Basic.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/test/java/util/concurrent/CompletableFuture/Basic.java	Wed Aug 14 15:53:13 2013 -0700
@@ -66,6 +66,7 @@
         try { equalAnyOf(cf.get(), values); } catch (Throwable x) { unexpected(x); }
         try { equalAnyOf(cf.get(0L, SECONDS), values); } catch (Throwable x) { unexpected(x); }
         check(cf.isDone(), "Expected isDone to be true, got:" + cf);
+        check(!cf.isCompletedExceptionally(), "Expected isCompletedExceptionally to return false");
         check(!cf.isCancelled(), "Expected isCancelled to be false");
         check(!cf.cancel(true), "Expected cancel to return false");
         check(cf.toString().contains("[Completed normally]"));
@@ -97,6 +98,7 @@
         catch (CancellationException x) { if (cancelled) pass(); else fail(); }
         catch (ExecutionException x) { if (cancelled) check(x.getCause() instanceof CancellationException); else pass(); }
         check(cf.isDone(), "Expected isDone to be true, got:" + cf);
+        check(cf.isCompletedExceptionally(), "Expected isCompletedExceptionally");
         check(cf.isCancelled() == cancelled, "Expected isCancelled: " + cancelled + ", got:"  + cf.isCancelled());
         check(cf.cancel(true) == cancelled, "Expected cancel: " + cancelled + ", got:"  + cf.cancel(true));
         check(cf.toString().contains("[Completed exceptionally]"));  // ## TODO: 'E'xceptionally
@@ -805,6 +807,49 @@
             cf2 = cf1.handle((x,t) -> { check(t.getCause() == ex); return 2;});
             checkCompletedExceptionally(cf1);
             checkCompletedNormally(cf2, 2);
+
+            cf1 = supplyAsync(() -> 1);
+            cf2 = cf1.handleAsync((x,t) -> x+1);
+            checkCompletedNormally(cf1, 1);
+            checkCompletedNormally(cf2, 2);
+
+            cf1 = supplyAsync(() -> { throw ex; });
+            cf2 = cf1.handleAsync((x,t) -> { check(t.getCause() == ex); return 2;});
+            checkCompletedExceptionally(cf1);
+            checkCompletedNormally(cf2, 2);
+        } catch (Throwable t) { unexpected(t); }
+
+        //----------------------------------------------------------------
+        // whenComplete tests
+        //----------------------------------------------------------------
+        try {
+            AtomicInteger count = new AtomicInteger();
+            CompletableFuture<Integer> cf2;
+            CompletableFuture<Integer> cf1 = supplyAsync(() -> 1);
+            cf2 = cf1.whenComplete((x,t) -> count.getAndIncrement());
+            checkCompletedNormally(cf1, 1);
+            checkCompletedNormally(cf2, 1);
+            check(count.get() == 1, "action count should be incremented");
+
+            final RuntimeException ex = new RuntimeException();
+            cf1 = supplyAsync(() -> { throw ex; });
+            cf2 = cf1.whenComplete((x,t) -> count.getAndIncrement());
+            checkCompletedExceptionally(cf1);
+            checkCompletedExceptionally(cf2);
+            check(count.get() == 2, "action count should be incremented");
+
+            cf1 = supplyAsync(() -> 1);
+            cf2 = cf1.whenCompleteAsync((x,t) -> count.getAndIncrement());
+            checkCompletedNormally(cf1, 1);
+            checkCompletedNormally(cf2, 1);
+            check(count.get() == 3, "action count should be incremented");
+
+            cf1 = supplyAsync(() -> { throw ex; });
+            cf2 = cf1.whenCompleteAsync((x,t) -> count.getAndIncrement());
+            checkCompletedExceptionally(cf1);
+            checkCompletedExceptionally(cf2);
+            check(count.get() == 4, "action count should be incremented");
+
         } catch (Throwable t) { unexpected(t); }
 
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/concurrent/ThreadLocalRandom/ThreadLocalRandomTest.java	Wed Aug 14 15:53:13 2013 -0700
@@ -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.concurrent.ThreadLocalRandom;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.LongAdder;
+
+import static org.testng.Assert.*;
+
+/**
+ * @test
+ * @run testng ThreadLocalRandomTest
+ * @summary test methods on ThreadLocalRandom
+ */
+@Test
+public class ThreadLocalRandomTest {
+
+    // Note: this test was copied from the 166 TCK ThreadLocalRandomTest test
+    // and modified to be a TestNG test
+
+    /*
+     * Testing coverage notes:
+     *
+     * We don't test randomness properties, but only that repeated
+     * calls, up to NCALLS tries, produce at least one different
+     * result.  For bounded versions, we sample various intervals
+     * across multiples of primes.
+     */
+
+    // max numbers of calls to detect getting stuck on one value
+    static final int NCALLS = 10000;
+
+    // max sampled int bound
+    static final int MAX_INT_BOUND = (1 << 28);
+
+    // max sampled long bound
+    static final long MAX_LONG_BOUND = (1L << 42);
+
+    // Number of replications for other checks
+    static final int REPS = 20;
+
+    /**
+     * setSeed throws UnsupportedOperationException
+     */
+    @Test(expectedExceptions = UnsupportedOperationException.class)
+    public void testSetSeed() {
+        ThreadLocalRandom.current().setSeed(17);
+    }
+
+    /**
+     * Repeated calls to nextInt produce at least two distinct results
+     */
+    public void testNextInt() {
+        int f = ThreadLocalRandom.current().nextInt();
+        int i = 0;
+        while (i < NCALLS && ThreadLocalRandom.current().nextInt() == f)
+            ++i;
+        assertTrue(i < NCALLS);
+    }
+
+    /**
+     * Repeated calls to nextLong produce at least two distinct results
+     */
+    public void testNextLong() {
+        long f = ThreadLocalRandom.current().nextLong();
+        int i = 0;
+        while (i < NCALLS && ThreadLocalRandom.current().nextLong() == f)
+            ++i;
+        assertTrue(i < NCALLS);
+    }
+
+    /**
+     * Repeated calls to nextBoolean produce at least two distinct results
+     */
+    public void testNextBoolean() {
+        boolean f = ThreadLocalRandom.current().nextBoolean();
+        int i = 0;
+        while (i < NCALLS && ThreadLocalRandom.current().nextBoolean() == f)
+            ++i;
+        assertTrue(i < NCALLS);
+    }
+
+    /**
+     * Repeated calls to nextFloat produce at least two distinct results
+     */
+    public void testNextFloat() {
+        float f = ThreadLocalRandom.current().nextFloat();
+        int i = 0;
+        while (i < NCALLS && ThreadLocalRandom.current().nextFloat() == f)
+            ++i;
+        assertTrue(i < NCALLS);
+    }
+
+    /**
+     * Repeated calls to nextDouble produce at least two distinct results
+     */
+    public void testNextDouble() {
+        double f = ThreadLocalRandom.current().nextDouble();
+        int i = 0;
+        while (i < NCALLS && ThreadLocalRandom.current().nextDouble() == f)
+            ++i;
+        assertTrue(i < NCALLS);
+    }
+
+    /**
+     * Repeated calls to nextGaussian produce at least two distinct results
+     */
+    public void testNextGaussian() {
+        double f = ThreadLocalRandom.current().nextGaussian();
+        int i = 0;
+        while (i < NCALLS && ThreadLocalRandom.current().nextGaussian() == f)
+            ++i;
+        assertTrue(i < NCALLS);
+    }
+
+    /**
+     * nextInt(negative) throws IllegalArgumentException
+     */
+    @Test(expectedExceptions = IllegalArgumentException.class)
+    public void testNextIntBoundedNeg() {
+        int f = ThreadLocalRandom.current().nextInt(-17);
+    }
+
+    /**
+     * nextInt(least >= bound) throws IllegalArgumentException
+     */
+    @Test(expectedExceptions = IllegalArgumentException.class)
+    public void testNextIntBadBounds() {
+        int f = ThreadLocalRandom.current().nextInt(17, 2);
+    }
+
+    /**
+     * nextInt(bound) returns 0 <= value < bound; repeated calls produce at
+     * least two distinct results
+     */
+    public void testNextIntBounded() {
+        // sample bound space across prime number increments
+        for (int bound = 2; bound < MAX_INT_BOUND; bound += 524959) {
+            int f = ThreadLocalRandom.current().nextInt(bound);
+            assertTrue(0 <= f && f < bound);
+            int i = 0;
+            int j;
+            while (i < NCALLS &&
+                   (j = ThreadLocalRandom.current().nextInt(bound)) == f) {
+                assertTrue(0 <= j && j < bound);
+                ++i;
+            }
+            assertTrue(i < NCALLS);
+        }
+    }
+
+    /**
+     * nextInt(least, bound) returns least <= value < bound; repeated calls
+     * produce at least two distinct results
+     */
+    public void testNextIntBounded2() {
+        for (int least = -15485863; least < MAX_INT_BOUND; least += 524959) {
+            for (int bound = least + 2; bound > least && bound < MAX_INT_BOUND; bound += 49979687) {
+                int f = ThreadLocalRandom.current().nextInt(least, bound);
+                assertTrue(least <= f && f < bound);
+                int i = 0;
+                int j;
+                while (i < NCALLS &&
+                       (j = ThreadLocalRandom.current().nextInt(least, bound)) == f) {
+                    assertTrue(least <= j && j < bound);
+                    ++i;
+                }
+                assertTrue(i < NCALLS);
+            }
+        }
+    }
+
+    /**
+     * nextLong(negative) throws IllegalArgumentException
+     */
+    @Test(expectedExceptions = IllegalArgumentException.class)
+    public void testNextLongBoundedNeg() {
+        long f = ThreadLocalRandom.current().nextLong(-17);
+    }
+
+    /**
+     * nextLong(least >= bound) throws IllegalArgumentException
+     */
+    @Test(expectedExceptions = IllegalArgumentException.class)
+    public void testNextLongBadBounds() {
+        long f = ThreadLocalRandom.current().nextLong(17, 2);
+    }
+
+    /**
+     * nextLong(bound) returns 0 <= value < bound; repeated calls produce at
+     * least two distinct results
+     */
+    public void testNextLongBounded() {
+        for (long bound = 2; bound < MAX_LONG_BOUND; bound += 15485863) {
+            long f = ThreadLocalRandom.current().nextLong(bound);
+            assertTrue(0 <= f && f < bound);
+            int i = 0;
+            long j;
+            while (i < NCALLS &&
+                   (j = ThreadLocalRandom.current().nextLong(bound)) == f) {
+                assertTrue(0 <= j && j < bound);
+                ++i;
+            }
+            assertTrue(i < NCALLS);
+        }
+    }
+
+    /**
+     * nextLong(least, bound) returns least <= value < bound; repeated calls
+     * produce at least two distinct results
+     */
+    public void testNextLongBounded2() {
+        for (long least = -86028121; least < MAX_LONG_BOUND; least += 982451653L) {
+            for (long bound = least + 2; bound > least && bound < MAX_LONG_BOUND; bound += Math.abs(bound * 7919)) {
+                long f = ThreadLocalRandom.current().nextLong(least, bound);
+                assertTrue(least <= f && f < bound);
+                int i = 0;
+                long j;
+                while (i < NCALLS &&
+                       (j = ThreadLocalRandom.current().nextLong(least, bound)) == f) {
+                    assertTrue(least <= j && j < bound);
+                    ++i;
+                }
+                assertTrue(i < NCALLS);
+            }
+        }
+    }
+
+    /**
+     * nextDouble(least, bound) returns least <= value < bound; repeated calls
+     * produce at least two distinct results
+     */
+    public void testNextDoubleBounded2() {
+        for (double least = 0.0001; least < 1.0e20; least *= 8) {
+            for (double bound = least * 1.001; bound < 1.0e20; bound *= 16) {
+                double f = ThreadLocalRandom.current().nextDouble(least, bound);
+                assertTrue(least <= f && f < bound);
+                int i = 0;
+                double j;
+                while (i < NCALLS &&
+                       (j = ThreadLocalRandom.current().nextDouble(least, bound)) == f) {
+                    assertTrue(least <= j && j < bound);
+                    ++i;
+                }
+                assertTrue(i < NCALLS);
+            }
+        }
+    }
+
+    /**
+     * Invoking sized ints, long, doubles, with negative sizes throws
+     * IllegalArgumentException
+     */
+    public void testBadStreamSize() {
+        ThreadLocalRandom r = ThreadLocalRandom.current();
+        executeAndCatchIAE(() -> r.ints(-1L));
+        executeAndCatchIAE(() -> r.ints(-1L, 2, 3));
+        executeAndCatchIAE(() -> r.longs(-1L));
+        executeAndCatchIAE(() -> r.longs(-1L, -1L, 1L));
+        executeAndCatchIAE(() -> r.doubles(-1L));
+        executeAndCatchIAE(() -> r.doubles(-1L, .5, .6));
+    }
+
+    /**
+     * Invoking bounded ints, long, doubles, with illegal bounds throws
+     * IllegalArgumentException
+     */
+    public void testBadStreamBounds() {
+        ThreadLocalRandom r = ThreadLocalRandom.current();
+        executeAndCatchIAE(() -> r.ints(2, 1));
+        executeAndCatchIAE(() -> r.ints(10, 42, 42));
+        executeAndCatchIAE(() -> r.longs(-1L, -1L));
+        executeAndCatchIAE(() -> r.longs(10, 1L, -2L));
+        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<? extends Exception> expected, Runnable r) {
+        Exception caught = null;
+        try {
+            r.run();
+        }
+        catch (Exception e) {
+            caught = e;
+        }
+
+        assertNotNull(caught,
+                      String.format("No Exception was thrown, expected an Exception of %s to be thrown",
+                                    expected.getName()));
+        Assert.assertTrue(expected.isInstance(caught),
+                          String.format("Exception thrown %s not an instance of %s",
+                                        caught.getClass().getName(), expected.getName()));
+    }
+
+    /**
+     * A parallel sized stream of ints generates the given number of values
+     */
+    public void testIntsCount() {
+        LongAdder counter = new LongAdder();
+        ThreadLocalRandom r = ThreadLocalRandom.current();
+        long size = 0;
+        for (int reps = 0; reps < REPS; ++reps) {
+            counter.reset();
+            r.ints(size).parallel().forEach(x -> {
+                counter.increment();
+            });
+            assertEquals(counter.sum(), size);
+            size += 524959;
+        }
+    }
+
+    /**
+     * A parallel sized stream of longs generates the given number of values
+     */
+    public void testLongsCount() {
+        LongAdder counter = new LongAdder();
+        ThreadLocalRandom r = ThreadLocalRandom.current();
+        long size = 0;
+        for (int reps = 0; reps < REPS; ++reps) {
+            counter.reset();
+            r.longs(size).parallel().forEach(x -> {
+                counter.increment();
+            });
+            assertEquals(counter.sum(), size);
+            size += 524959;
+        }
+    }
+
+    /**
+     * A parallel sized stream of doubles generates the given number of values
+     */
+    public void testDoublesCount() {
+        LongAdder counter = new LongAdder();
+        ThreadLocalRandom r = ThreadLocalRandom.current();
+        long size = 0;
+        for (int reps = 0; reps < REPS; ++reps) {
+            counter.reset();
+            r.doubles(size).parallel().forEach(x -> {
+                counter.increment();
+            });
+            assertEquals(counter.sum(), size);
+            size += 524959;
+        }
+    }
+
+    /**
+     * Each of a parallel sized stream of bounded ints is within bounds
+     */
+    public void testBoundedInts() {
+        AtomicInteger fails = new AtomicInteger(0);
+        ThreadLocalRandom r = ThreadLocalRandom.current();
+        long size = 12345L;
+        for (int least = -15485867; least < MAX_INT_BOUND; least += 524959) {
+            for (int bound = least + 2; bound > least && bound < MAX_INT_BOUND; bound += 67867967) {
+                final int lo = least, hi = bound;
+                r.ints(size, lo, hi).parallel().
+                        forEach(x -> {
+                            if (x < lo || x >= hi)
+                                fails.getAndIncrement();
+                        });
+            }
+        }
+        assertEquals(fails.get(), 0);
+    }
+
+    /**
+     * Each of a parallel sized stream of bounded longs is within bounds
+     */
+    public void testBoundedLongs() {
+        AtomicInteger fails = new AtomicInteger(0);
+        ThreadLocalRandom r = ThreadLocalRandom.current();
+        long size = 123L;
+        for (long least = -86028121; least < MAX_LONG_BOUND; least += 1982451653L) {
+            for (long bound = least + 2; bound > least && bound < MAX_LONG_BOUND; bound += Math.abs(bound * 7919)) {
+                final long lo = least, hi = bound;
+                r.longs(size, lo, hi).parallel().
+                        forEach(x -> {
+                            if (x < lo || x >= hi)
+                                fails.getAndIncrement();
+                        });
+            }
+        }
+        assertEquals(fails.get(), 0);
+    }
+
+    /**
+     * Each of a parallel sized stream of bounded doubles is within bounds
+     */
+    public void testBoundedDoubles() {
+        AtomicInteger fails = new AtomicInteger(0);
+        ThreadLocalRandom r = ThreadLocalRandom.current();
+        long size = 456;
+        for (double least = 0.00011; least < 1.0e20; least *= 9) {
+            for (double bound = least * 1.0011; bound < 1.0e20; bound *= 17) {
+                final double lo = least, hi = bound;
+                r.doubles(size, lo, hi).parallel().
+                        forEach(x -> {
+                            if (x < lo || x >= hi)
+                                fails.getAndIncrement();
+                        });
+            }
+        }
+        assertEquals(fails.get(), 0);
+    }
+
+    /**
+     * A parallel unsized stream of ints generates at least 100 values
+     */
+    public void testUnsizedIntsCount() {
+        LongAdder counter = new LongAdder();
+        ThreadLocalRandom r = ThreadLocalRandom.current();
+        long size = 100;
+        r.ints().limit(size).parallel().forEach(x -> {
+            counter.increment();
+        });
+        assertEquals(counter.sum(), size);
+    }
+
+    /**
+     * A parallel unsized stream of longs generates at least 100 values
+     */
+    public void testUnsizedLongsCount() {
+        LongAdder counter = new LongAdder();
+        ThreadLocalRandom r = ThreadLocalRandom.current();
+        long size = 100;
+        r.longs().limit(size).parallel().forEach(x -> {
+            counter.increment();
+        });
+        assertEquals(counter.sum(), size);
+    }
+
+    /**
+     * A parallel unsized stream of doubles generates at least 100 values
+     */
+    public void testUnsizedDoublesCount() {
+        LongAdder counter = new LongAdder();
+        ThreadLocalRandom r = ThreadLocalRandom.current();
+        long size = 100;
+        r.doubles().limit(size).parallel().forEach(x -> {
+            counter.increment();
+        });
+        assertEquals(counter.sum(), size);
+    }
+
+    /**
+     * A sequential unsized stream of ints generates at least 100 values
+     */
+    public void testUnsizedIntsCountSeq() {
+        LongAdder counter = new LongAdder();
+        ThreadLocalRandom r = ThreadLocalRandom.current();
+        long size = 100;
+        r.ints().limit(size).forEach(x -> {
+            counter.increment();
+        });
+        assertEquals(counter.sum(), size);
+    }
+
+    /**
+     * A sequential unsized stream of longs generates at least 100 values
+     */
+    public void testUnsizedLongsCountSeq() {
+        LongAdder counter = new LongAdder();
+        ThreadLocalRandom r = ThreadLocalRandom.current();
+        long size = 100;
+        r.longs().limit(size).forEach(x -> {
+            counter.increment();
+        });
+        assertEquals(counter.sum(), size);
+    }
+
+    /**
+     * A sequential unsized stream of doubles generates at least 100 values
+     */
+    public void testUnsizedDoublesCountSeq() {
+        LongAdder counter = new LongAdder();
+        ThreadLocalRandom r = ThreadLocalRandom.current();
+        long size = 100;
+        r.doubles().limit(size).forEach(x -> {
+            counter.increment();
+        });
+        assertEquals(counter.sum(), size);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/concurrent/forkjoin/ParallelSorting.java	Wed Aug 14 15:53:13 2013 -0700
@@ -0,0 +1,2069 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute 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.
+ */
+
+/* Adapted from test/java/util/Arrays/Sorting.java
+ *
+ * Where that test checks Arrays.sort against manual quicksort routines,
+ * this test checks parallelSort against either Arrays.sort or manual
+ * quicksort routines.
+ */
+
+/*
+/*
+ * @test
+ * @summary Exercise ForkJoinUtils.parallelSort (adapted from test Sorting)
+ * @build ParallelSorting
+ * @run main ParallelSorting -shortrun
+ *
+ * @author Vladimir Yaroslavskiy
+ * @author Jon Bentley
+ * @author Josh Bloch
+ *
+ */
+
+import java.util.Arrays;
+import java.util.Random;
+import java.io.PrintStream;
+import java.util.Comparator;
+
+public class ParallelSorting {
+    private static final PrintStream out = System.out;
+    private static final PrintStream err = System.err;
+
+    // Array lengths used in a long run (default)
+    private static final int[] LONG_RUN_LENGTHS = {
+        1, 2, 3, 5, 8, 13, 21, 34, 55, 100, 1000, 10000, 100000, 1000000 };
+
+    // Array lengths used in a short run
+    private static final int[] SHORT_RUN_LENGTHS = {
+        1, 2, 3, 21, 55, 1000, 10000 };
+
+    // Random initial values used in a long run (default)
+    private static final long[] LONG_RUN_RANDOMS = { 666, 0xC0FFEE, 999 };
+
+    // Random initial values used in a short run
+    private static final long[] SHORT_RUN_RANDOMS = { 666 };
+
+    public static void main(String[] args) {
+        boolean shortRun = args.length > 0 && args[0].equals("-shortrun");
+        long start = System.currentTimeMillis();
+
+        if (shortRun) {
+            testAndCheck(SHORT_RUN_LENGTHS, SHORT_RUN_RANDOMS);
+        } else {
+            testAndCheck(LONG_RUN_LENGTHS, LONG_RUN_RANDOMS);
+        }
+        long end = System.currentTimeMillis();
+
+        out.format("PASSED in %d sec.\n", Math.round((end - start) / 1E3));
+    }
+
+    private static void testAndCheck(int[] lengths, long[] randoms) {
+        testEmptyAndNullIntArray();
+	testEmptyAndNullLongArray();
+        testEmptyAndNullShortArray();
+        testEmptyAndNullCharArray();
+        testEmptyAndNullByteArray();
+	testEmptyAndNullFloatArray();
+	testEmptyAndNullDoubleArray();
+
+        for (int length : lengths) {
+            testMergeSort(length);
+            testAndCheckRange(length);
+            testAndCheckSubArray(length);
+        }
+        for (long seed : randoms) {
+            for (int length : lengths) {
+                testAndCheckWithInsertionSort(length, new MyRandom(seed));
+                testAndCheckWithCheckSum(length, new MyRandom(seed));
+                testAndCheckWithScrambling(length, new MyRandom(seed));
+		testAndCheckFloat(length, new MyRandom(seed));
+		testAndCheckDouble(length, new MyRandom(seed));
+                testStable(length, new MyRandom(seed));
+            }
+        }
+    }
+
+    private static void testEmptyAndNullIntArray() {
+        ourDescription = "Check empty and null array";
+        Arrays.parallelSort(new int[]{});
+        Arrays.parallelSort(new int[]{}, 0, 0);
+
+        try {
+            Arrays.parallelSort((int[]) null);
+        } catch (NullPointerException expected) {
+            try {
+                Arrays.parallelSort((int[]) null, 0, 0);
+            } catch (NullPointerException expected2) {
+                return;
+            }
+            failed("ForkJoinUtils.parallelSort(int[],fromIndex,toIndex) shouldn't " +
+                "catch null array");
+        }
+        failed("ForkJoinUtils.parallelSort(int[]) shouldn't catch null array");
+    }
+
+    private static void testEmptyAndNullLongArray() {
+        ourDescription = "Check empty and null array";
+        Arrays.parallelSort(new long[]{});
+        Arrays.parallelSort(new long[]{}, 0, 0);
+
+        try {
+            Arrays.parallelSort((long[]) null);
+        } catch (NullPointerException expected) {
+            try {
+                Arrays.parallelSort((long[]) null, 0, 0);
+            } catch (NullPointerException expected2) {
+                return;
+            }
+            failed("ForkJoinUtils.parallelSort(long[],fromIndex,toIndex) shouldn't " +
+                "catch null array");
+        }
+        failed("ForkJoinUtils.parallelSort(long[]) shouldn't catch null array");
+    }
+
+    private static void testEmptyAndNullShortArray() {
+        ourDescription = "Check empty and null array";
+        Arrays.parallelSort(new short[]{});
+        Arrays.parallelSort(new short[]{}, 0, 0);
+
+        try {
+            Arrays.parallelSort((short[]) null);
+        } catch (NullPointerException expected) {
+            try {
+                Arrays.parallelSort((short[]) null, 0, 0);
+            } catch (NullPointerException expected2) {
+                return;
+            }
+            failed("ForkJoinUtils.parallelSort(short[],fromIndex,toIndex) shouldn't " +
+                "catch null array");
+        }
+        failed("ForkJoinUtils.parallelSort(short[]) shouldn't catch null array");
+    }
+
+    private static void testEmptyAndNullCharArray() {
+        ourDescription = "Check empty and null array";
+        Arrays.parallelSort(new char[]{});
+        Arrays.parallelSort(new char[]{}, 0, 0);
+
+        try {
+            Arrays.parallelSort((char[]) null);
+        } catch (NullPointerException expected) {
+            try {
+                Arrays.parallelSort((char[]) null, 0, 0);
+            } catch (NullPointerException expected2) {
+                return;
+            }
+            failed("ForkJoinUtils.parallelSort(char[],fromIndex,toIndex) shouldn't " +
+                "catch null array");
+        }
+        failed("ForkJoinUtils.parallelSort(char[]) shouldn't catch null array");
+    }
+
+    private static void testEmptyAndNullByteArray() {
+        ourDescription = "Check empty and null array";
+        Arrays.parallelSort(new byte[]{});
+        Arrays.parallelSort(new byte[]{}, 0, 0);
+
+        try {
+            Arrays.parallelSort((byte[]) null);
+        } catch (NullPointerException expected) {
+            try {
+                Arrays.parallelSort((byte[]) null, 0, 0);
+            } catch (NullPointerException expected2) {
+                return;
+            }
+            failed("ForkJoinUtils.parallelSort(byte[],fromIndex,toIndex) shouldn't " +
+                "catch null array");
+        }
+        failed("ForkJoinUtils.parallelSort(byte[]) shouldn't catch null array");
+    }
+
+    private static void testEmptyAndNullFloatArray() {
+        ourDescription = "Check empty and null array";
+        Arrays.parallelSort(new float[]{});
+        Arrays.parallelSort(new float[]{}, 0, 0);
+
+        try {
+            Arrays.parallelSort((float[]) null);
+        } catch (NullPointerException expected) {
+            try {
+                Arrays.parallelSort((float[]) null, 0, 0);
+            } catch (NullPointerException expected2) {
+                return;
+            }
+            failed("ForkJoinUtils.parallelSort(float[],fromIndex,toIndex) shouldn't " +
+                "catch null array");
+        }
+        failed("ForkJoinUtils.parallelSort(float[]) shouldn't catch null array");
+    }
+
+    private static void testEmptyAndNullDoubleArray() {
+        ourDescription = "Check empty and null array";
+        Arrays.parallelSort(new double[]{});
+        Arrays.parallelSort(new double[]{}, 0, 0);
+
+        try {
+            Arrays.parallelSort((double[]) null);
+        } catch (NullPointerException expected) {
+            try {
+                Arrays.parallelSort((double[]) null, 0, 0);
+            } catch (NullPointerException expected2) {
+                return;
+            }
+            failed("ForkJoinUtils.parallelSort(double[],fromIndex,toIndex) shouldn't " +
+                "catch null array");
+        }
+        failed("ForkJoinUtils.parallelSort(double[]) shouldn't catch null array");
+    }
+
+    private static void testAndCheckSubArray(int length) {
+        ourDescription = "Check sorting of subarray";
+        int[] golden = new int[length];
+        boolean newLine = false;
+
+        for (int m = 1; m < length / 2; m *= 2) {
+            newLine = true;
+            int fromIndex = m;
+            int toIndex = length - m;
+
+            prepareSubArray(golden, fromIndex, toIndex, m);
+            int[] test = golden.clone();
+
+            for (TypeConverter converter : TypeConverter.values()) {
+                out.println("Test 'subarray': " + converter +
+                   " length = " + length + ", m = " + m);
+                Object convertedGolden = converter.convert(golden);
+                Object convertedTest = converter.convert(test);
+                sortSubArray(convertedTest, fromIndex, toIndex);
+                checkSubArray(convertedTest, fromIndex, toIndex, m);
+            }
+        }
+        if (newLine) {
+            out.println();
+        }
+    }
+
+    private static void testAndCheckRange(int length) {
+        ourDescription = "Check range check";
+        int[] golden = new int[length];
+
+        for (int m = 1; m < 2 * length; m *= 2) {
+            for (int i = 1; i <= length; i++) {
+                golden[i - 1] = i % m + m % i;
+            }
+            for (TypeConverter converter : TypeConverter.values()) {
+                out.println("Test 'range': " + converter +
+                   ", length = " + length + ", m = " + m);
+                Object convertedGolden = converter.convert(golden);
+                checkRange(convertedGolden, m);
+            }
+        }
+        out.println();
+    }
+
+    private static void testStable(int length, MyRandom random) {
+        ourDescription = "Check if sorting is stable";
+        Pair[] a = build(length, random);
+
+        out.println("Test 'stable': " + "random = " + random.getSeed() +
+            ", length = " + length);
+        Arrays.parallelSort(a);
+        checkSorted(a);
+        checkStable(a);
+        out.println();
+
+	a = build(length, random);
+
+        out.println("Test 'stable' comparator: " + "random = " + random.getSeed() +
+            ", length = " + length);
+        Arrays.parallelSort(a, pairCmp);
+        checkSorted(a);
+        checkStable(a);
+        out.println();
+
+    }
+
+    private static void checkSorted(Pair[] a) {
+        for (int i = 0; i < a.length - 1; i++) {
+            if (a[i].getKey() > a[i + 1].getKey()) {
+                failedSort(i, "" + a[i].getKey(), "" + a[i + 1].getKey());
+            }
+        }
+    }
+
+    private static void checkStable(Pair[] a) {
+        for (int i = 0; i < a.length / 4; ) {
+            int key1 = a[i].getKey();
+            int value1 = a[i++].getValue();
+            int key2 = a[i].getKey();
+            int value2 = a[i++].getValue();
+            int key3 = a[i].getKey();
+            int value3 = a[i++].getValue();
+            int key4 = a[i].getKey();
+            int value4 = a[i++].getValue();
+
+            if (!(key1 == key2 && key2 == key3 && key3 == key4)) {
+                failed("On position " + i + " keys are different " +
+                    key1 + ", " + key2 + ", " + key3 + ", " + key4);
+            }
+            if (!(value1 < value2 && value2 < value3 && value3 < value4)) {
+                failed("Sorting is not stable at position " + i +
+                    ". Second values have been changed: " +  value1 + ", " +
+                    value2 + ", " + value3 + ", " + value4);
+            }
+        }
+    }
+
+    private static Pair[] build(int length, Random random) {
+        Pair[] a = new Pair[length * 4];
+
+        for (int i = 0; i < a.length; ) {
+            int key = random.nextInt();
+            a[i++] = new Pair(key, 1);
+            a[i++] = new Pair(key, 2);
+            a[i++] = new Pair(key, 3);
+            a[i++] = new Pair(key, 4);
+        }
+        return a;
+    }
+
+    private static Comparator<Pair> pairCmp = new Comparator<Pair>() {
+	public int compare(Pair p1, Pair p2) {
+	    return p1.compareTo(p2);
+	}
+    };
+
+    private static final class Pair implements Comparable<Pair> {
+        Pair(int key, int value) {
+            myKey = key;
+            myValue = value;
+        }
+
+        int getKey() {
+            return myKey;
+        }
+
+        int getValue() {
+            return myValue;
+        }
+
+        public int compareTo(Pair pair) {
+            if (myKey < pair.myKey) {
+                return -1;
+            }
+            if (myKey > pair.myKey) {
+                return 1;
+            }
+            return 0;
+        }
+
+        @Override
+        public String toString() {
+            return "(" + myKey + ", " + myValue + ")";
+        }
+
+        private int myKey;
+        private int myValue;
+    }
+
+
+    private static void testAndCheckWithInsertionSort(int length, MyRandom random) {
+        if (length > 1000) {
+            return;
+        }
+        ourDescription = "Check sorting with insertion sort";
+        int[] golden = new int[length];
+
+        for (int m = 1; m < 2 * length; m *= 2) {
+            for (UnsortedBuilder builder : UnsortedBuilder.values()) {
+                builder.build(golden, m, random);
+                int[] test = golden.clone();
+
+                for (TypeConverter converter : TypeConverter.values()) {
+                    out.println("Test 'insertion sort': " + converter +
+                        " " + builder + "random = " + random.getSeed() +
+                        ", length = " + length + ", m = " + m);
+                    Object convertedGolden = converter.convert(golden);
+                    Object convertedTest1 = converter.convert(test);
+                    Object convertedTest2 = converter.convert(test);
+                    sort(convertedTest1);
+                    sortByInsertionSort(convertedTest2);
+                    compare(convertedTest1, convertedTest2);
+                }
+            }
+        }
+        out.println();
+    }
+
+    private static void testMergeSort(int length) {
+        if (length < 1000) {
+            return;
+        }
+        ourDescription = "Check merge sorting";
+        int[] golden = new int[length];
+        int period = 67; // java.util.DualPivotQuicksort.MAX_RUN_COUNT
+
+        for (int m = period - 2; m <= period + 2; m++) {
+            for (MergeBuilder builder : MergeBuilder.values()) {
+                builder.build(golden, m);
+                int[] test = golden.clone();
+
+                for (TypeConverter converter : TypeConverter.values()) {
+                    out.println("Test 'merge sort': " + converter + " " +
+                        builder + "length = " + length + ", m = " + m);
+                    Object convertedGolden = converter.convert(golden);
+                    sort(convertedGolden);
+                    checkSorted(convertedGolden);
+                }
+            }
+        }
+        out.println();
+    }
+
+    private static void testAndCheckWithCheckSum(int length, MyRandom random) {
+        ourDescription = "Check sorting with check sum";
+        int[] golden = new int[length];
+
+        for (int m = 1; m < 2 * length; m *= 2) {
+            for (UnsortedBuilder builder : UnsortedBuilder.values()) {
+                builder.build(golden, m, random);
+                int[] test = golden.clone();
+
+                for (TypeConverter converter : TypeConverter.values()) {
+                    out.println("Test 'check sum': " + converter +
+                        " " + builder + "random = " + random.getSeed() +
+                        ", length = " + length + ", m = " + m);
+                    Object convertedGolden = converter.convert(golden);
+                    Object convertedTest = converter.convert(test);
+                    sort(convertedTest);
+                    checkWithCheckSum(convertedTest, convertedGolden);
+                }
+            }
+        }
+        out.println();
+    }
+
+    private static void testAndCheckWithScrambling(int length, MyRandom random) {
+        ourDescription = "Check sorting with scrambling";
+        int[] golden = new int[length];
+
+        for (int m = 1; m <= 7; m++) {
+            if (m > length) {
+                break;
+            }
+            for (SortedBuilder builder : SortedBuilder.values()) {
+                builder.build(golden, m);
+                int[] test = golden.clone();
+                scramble(test, random);
+
+                for (TypeConverter converter : TypeConverter.values()) {
+                    out.println("Test 'scrambling': " + converter +
+                       " " + builder + "random = " + random.getSeed() +
+                       ", length = " + length + ", m = " + m);
+                    Object convertedGolden = converter.convert(golden);
+                    Object convertedTest = converter.convert(test);
+                    sort(convertedTest);
+                    compare(convertedTest, convertedGolden);
+                }
+            }
+        }
+        out.println();
+    }
+
+    private static void testAndCheckFloat(int length, MyRandom random) {
+        ourDescription = "Check float sorting";
+        float[] golden = new float[length];
+        final int MAX = 10;
+        boolean newLine = false;
+
+        for (int a = 0; a <= MAX; a++) {
+            for (int g = 0; g <= MAX; g++) {
+                for (int z = 0; z <= MAX; z++) {
+                    for (int n = 0; n <= MAX; n++) {
+                        for (int p = 0; p <= MAX; p++) {
+                            if (a + g + z + n + p > length) {
+                                continue;
+                            }
+                            if (a + g + z + n + p < length) {
+                                continue;
+                            }
+                            for (FloatBuilder builder : FloatBuilder.values()) {
+                                out.println("Test 'float': random = " + random.getSeed() +
+                                   ", length = " + length + ", a = " + a + ", g = " +
+                                   g + ", z = " + z + ", n = " + n + ", p = " + p);
+                                builder.build(golden, a, g, z, n, p, random);
+                                float[] test = golden.clone();
+                                scramble(test, random);
+                                sort(test);
+                                compare(test, golden, a, n, g);
+                            }
+                            newLine = true;
+                        }
+                    }
+                }
+            }
+        }
+        if (newLine) {
+            out.println();
+        }
+    }
+
+    private static void testAndCheckDouble(int length, MyRandom random) {
+        ourDescription = "Check double sorting";
+        double[] golden = new double[length];
+        final int MAX = 10;
+        boolean newLine = false;
+
+        for (int a = 0; a <= MAX; a++) {
+            for (int g = 0; g <= MAX; g++) {
+                for (int z = 0; z <= MAX; z++) {
+                    for (int n = 0; n <= MAX; n++) {
+                        for (int p = 0; p <= MAX; p++) {
+                            if (a + g + z + n + p > length) {
+                                continue;
+                            }
+                            if (a + g + z + n + p < length) {
+                                continue;
+                            }
+                            for (DoubleBuilder builder : DoubleBuilder.values()) {
+                                out.println("Test 'double': random = " + random.getSeed() +
+                                   ", length = " + length + ", a = " + a + ", g = " +
+                                   g + ", z = " + z + ", n = " + n + ", p = " + p);
+                                builder.build(golden, a, g, z, n, p, random);
+                                double[] test = golden.clone();
+                                scramble(test, random);
+                                sort(test);
+                                compare(test, golden, a, n, g);
+                            }
+                            newLine = true;
+                        }
+                    }
+                }
+            }
+        }
+        if (newLine) {
+            out.println();
+        }
+    }
+
+    private static void prepareSubArray(int[] a, int fromIndex, int toIndex, int m) {
+        for (int i = 0; i < fromIndex; i++) {
+            a[i] = 0xDEDA;
+        }
+        int middle = (fromIndex + toIndex) >>> 1;
+        int k = 0;
+
+        for (int i = fromIndex; i < middle; i++) {
+            a[i] = k++;
+        }
+        for (int i = middle; i < toIndex; i++) {
+            a[i] = k--;
+        }
+        for (int i = toIndex; i < a.length; i++) {
+            a[i] = 0xBABA;
+        }
+    }
+
+    private static void scramble(int[] a, Random random) {
+        for (int i = 0; i < a.length * 7; i++) {
+            swap(a, random.nextInt(a.length), random.nextInt(a.length));
+        }
+    }
+
+    private static void scramble(float[] a, Random random) {
+        for (int i = 0; i < a.length * 7; i++) {
+            swap(a, random.nextInt(a.length), random.nextInt(a.length));
+        }
+    }
+
+    private static void scramble(double[] a, Random random) {
+        for (int i = 0; i < a.length * 7; i++) {
+            swap(a, random.nextInt(a.length), random.nextInt(a.length));
+        }
+    }
+
+    private static void swap(int[] a, int i, int j) {
+        int t = a[i];
+        a[i] = a[j];
+        a[j] = t;
+    }
+
+    private static void swap(float[] a, int i, int j) {
+        float t = a[i];
+        a[i] = a[j];
+        a[j] = t;
+    }
+
+    private static void swap(double[] a, int i, int j) {
+        double t = a[i];
+        a[i] = a[j];
+        a[j] = t;
+    }
+
+    private static enum TypeConverter {
+        INT {
+            Object convert(int[] a) {
+                return a.clone();
+            }
+        },
+        LONG {
+            Object convert(int[] a) {
+                long[] b = new long[a.length];
+
+                for (int i = 0; i < a.length; i++) {
+                    b[i] = (long) a[i];
+                }
+                return b;
+            }
+        },
+        BYTE {
+            Object convert(int[] a) {
+                byte[] b = new byte[a.length];
+
+                for (int i = 0; i < a.length; i++) {
+                    b[i] = (byte) a[i];
+                }
+                return b;
+            }
+        },
+        SHORT {
+            Object convert(int[] a) {
+                short[] b = new short[a.length];
+
+                for (int i = 0; i < a.length; i++) {
+                    b[i] = (short) a[i];
+                }
+                return b;
+            }
+        },
+        CHAR {
+            Object convert(int[] a) {
+                char[] b = new char[a.length];
+
+                for (int i = 0; i < a.length; i++) {
+                    b[i] = (char) a[i];
+                }
+                return b;
+            }
+        },
+        FLOAT {
+            Object convert(int[] a) {
+                float[] b = new float[a.length];
+
+                for (int i = 0; i < a.length; i++) {
+                    b[i] = (float) a[i];
+                }
+                return b;
+            }
+        },
+        DOUBLE {
+            Object convert(int[] a) {
+                double[] b = new double[a.length];
+
+                for (int i = 0; i < a.length; i++) {
+                    b[i] = (double) a[i];
+                }
+                return b;
+            }
+        },
+        INTEGER {
+            Object convert(int[] a) {
+                Integer[] b = new Integer[a.length];
+
+                for (int i = 0; i < a.length; i++) {
+                    b[i] = new Integer(a[i]);
+                }
+                return b;
+            }
+        };
+
+        abstract Object convert(int[] a);
+
+        @Override public String toString() {
+            String name = name();
+
+            for (int i = name.length(); i < 9; i++) {
+                name += " ";
+            }
+            return name;
+        }
+    }
+
+    private static enum FloatBuilder {
+        SIMPLE {
+            void build(float[] x, int a, int g, int z, int n, int p, Random random) {
+                int fromIndex = 0;
+                float negativeValue = -random.nextFloat();
+                float positiveValue =  random.nextFloat();
+
+                writeValue(x, negativeValue, fromIndex, n);
+                fromIndex += n;
+
+                writeValue(x, -0.0f, fromIndex, g);
+                fromIndex += g;
+
+                writeValue(x, 0.0f, fromIndex, z);
+                fromIndex += z;
+
+                writeValue(x, positiveValue, fromIndex, p);
+                fromIndex += p;
+
+                writeValue(x, Float.NaN, fromIndex, a);
+            }
+        };
+
+        abstract void build(float[] x, int a, int g, int z, int n, int p, Random random);
+    }
+
+    private static enum DoubleBuilder {
+        SIMPLE {
+            void build(double[] x, int a, int g, int z, int n, int p, Random random) {
+                int fromIndex = 0;
+                double negativeValue = -random.nextFloat();
+                double positiveValue =  random.nextFloat();
+
+                writeValue(x, negativeValue, fromIndex, n);
+                fromIndex += n;
+
+                writeValue(x, -0.0d, fromIndex, g);
+                fromIndex += g;
+
+                writeValue(x, 0.0d, fromIndex, z);
+                fromIndex += z;
+
+                writeValue(x, positiveValue, fromIndex, p);
+                fromIndex += p;
+
+                writeValue(x, Double.NaN, fromIndex, a);
+            }
+        };
+
+        abstract void build(double[] x, int a, int g, int z, int n, int p, Random random);
+    }
+
+    private static void writeValue(float[] a, float value, int fromIndex, int count) {
+        for (int i = fromIndex; i < fromIndex + count; i++) {
+            a[i] = value;
+        }
+    }
+
+    private static void compare(float[] a, float[] b, int numNaN, int numNeg, int numNegZero) {
+        for (int i = a.length - numNaN; i < a.length; i++) {
+            if (a[i] == a[i]) {
+                failed("On position " + i + " must be NaN instead of " + a[i]);
+            }
+        }
+        final int NEGATIVE_ZERO = Float.floatToIntBits(-0.0f);
+
+        for (int i = numNeg; i < numNeg + numNegZero; i++) {
+            if (NEGATIVE_ZERO != Float.floatToIntBits(a[i])) {
+                failed("On position " + i + " must be -0.0 instead of " + a[i]);
+            }
+        }
+        for (int i = 0; i < a.length - numNaN; i++) {
+            if (a[i] != b[i]) {
+                failedCompare(i, "" + a[i], "" + b[i]);
+            }
+        }
+    }
+
+    private static void writeValue(double[] a, double value, int fromIndex, int count) {
+        for (int i = fromIndex; i < fromIndex + count; i++) {
+            a[i] = value;
+        }
+    }
+
+    private static void compare(double[] a, double[] b, int numNaN, int numNeg, int numNegZero) {
+        for (int i = a.length - numNaN; i < a.length; i++) {
+            if (a[i] == a[i]) {
+                failed("On position " + i + " must be NaN instead of " + a[i]);
+            }
+        }
+        final long NEGATIVE_ZERO = Double.doubleToLongBits(-0.0d);
+
+        for (int i = numNeg; i < numNeg + numNegZero; i++) {
+            if (NEGATIVE_ZERO != Double.doubleToLongBits(a[i])) {
+                failed("On position " + i + " must be -0.0 instead of " + a[i]);
+            }
+        }
+        for (int i = 0; i < a.length - numNaN; i++) {
+            if (a[i] != b[i]) {
+                failedCompare(i, "" + a[i], "" + b[i]);
+            }
+        }
+    }
+
+    private static enum SortedBuilder {
+        REPEATED {
+            void build(int[] a, int m) {
+                int period = a.length / m;
+                int i = 0;
+                int k = 0;
+
+                while (true) {
+                    for (int t = 1; t <= period; t++) {
+                        if (i >= a.length) {
+                            return;
+                        }
+                        a[i++] = k;
+                    }
+                    if (i >= a.length) {
+                        return;
+                    }
+                    k++;
+                }
+            }
+        },
+        ORGAN_PIPES {
+            void build(int[] a, int m) {
+                int i = 0;
+                int k = m;
+
+                while (true) {
+                    for (int t = 1; t <= m; t++) {
+                        if (i >= a.length) {
+                            return;
+                        }
+                        a[i++] = k;
+                    }
+                }
+            }
+        };
+
+        abstract void build(int[] a, int m);
+
+        @Override public String toString() {
+            String name = name();
+
+            for (int i = name.length(); i < 12; i++) {
+                name += " ";
+            }
+            return name;
+        }
+    }
+
+    private static enum MergeBuilder {
+        ASCENDING {
+            void build(int[] a, int m) {
+                int period = a.length / m;
+                int v = 1, i = 0;
+
+                for (int k = 0; k < m; k++) {
+                    v = 1;
+                    for (int p = 0; p < period; p++) {
+                        a[i++] = v++;
+                    }
+                }
+                for (int j = i; j < a.length - 1; j++) {
+                    a[j] = v++;
+                }
+                a[a.length - 1] = 0;
+            }
+        },
+        DESCENDING {
+            void build(int[] a, int m) {
+                int period = a.length / m;
+                int v = -1, i = 0;
+
+                for (int k = 0; k < m; k++) {
+                    v = -1;
+                    for (int p = 0; p < period; p++) {
+                        a[i++] = v--;
+                    }
+                }
+                for (int j = i; j < a.length - 1; j++) {
+                    a[j] = v--;
+                }
+                a[a.length - 1] = 0;
+            }
+        };
+
+        abstract void build(int[] a, int m);
+
+        @Override public String toString() {
+            String name = name();
+
+            for (int i = name.length(); i < 12; i++) {
+                name += " ";
+            }
+            return name;
+        }
+    }
+
+    private static enum UnsortedBuilder {
+        RANDOM {
+            void build(int[] a, int m, Random random) {
+                for (int i = 0; i < a.length; i++) {
+                    a[i] = random.nextInt();
+                }
+            }
+        },
+        ASCENDING {
+            void build(int[] a, int m, Random random) {
+                for (int i = 0; i < a.length; i++) {
+                    a[i] = m + i;
+                }
+            }
+        },
+        DESCENDING {
+            void build(int[] a, int m, Random random) {
+                for (int i = 0; i < a.length; i++) {
+                    a[i] = a.length - m - i;
+                }
+            }
+        },
+        ALL_EQUAL {
+            void build(int[] a, int m, Random random) {
+                for (int i = 0; i < a.length; i++) {
+                    a[i] = m;
+                }
+            }
+        },
+        SAW {
+            void build(int[] a, int m, Random random) {
+                int incCount = 1;
+                int decCount = a.length;
+                int i = 0;
+                int period = m--;
+
+                while (true) {
+                    for (int k = 1; k <= period; k++) {
+                        if (i >= a.length) {
+                            return;
+                        }
+                        a[i++] = incCount++;
+                    }
+                    period += m;
+
+                    for (int k = 1; k <= period; k++) {
+                        if (i >= a.length) {
+                            return;
+                        }
+                        a[i++] = decCount--;
+                    }
+                    period += m;
+                }
+            }
+        },
+        REPEATED {
+            void build(int[] a, int m, Random random) {
+                for (int i = 0; i < a.length; i++) {
+                    a[i] = i % m;
+                }
+            }
+        },
+        DUPLICATED {
+            void build(int[] a, int m, Random random) {
+                for (int i = 0; i < a.length; i++) {
+                    a[i] = random.nextInt(m);
+                }
+            }
+        },
+        ORGAN_PIPES {
+            void build(int[] a, int m, Random random) {
+                int middle = a.length / (m + 1);
+
+                for (int i = 0; i < middle; i++) {
+                    a[i] = i;
+                }
+                for (int i = middle; i < a.length; i++) {
+                    a[i] = a.length - i - 1;
+                }
+            }
+        },
+        STAGGER {
+            void build(int[] a, int m, Random random) {
+                for (int i = 0; i < a.length; i++) {
+                    a[i] = (i * m + i) % a.length;
+                }
+            }
+        },
+        PLATEAU {
+            void build(int[] a, int m, Random random) {
+                for (int i = 0; i < a.length; i++) {
+                    a[i] = Math.min(i, m);
+                }
+            }
+        },
+        SHUFFLE {
+            void build(int[] a, int m, Random random) {
+                int x = 0, y = 0;
+                for (int i = 0; i < a.length; i++) {
+                    a[i] = random.nextBoolean() ? (x += 2) : (y += 2);
+                }
+            }
+        };
+
+        abstract void build(int[] a, int m, Random random);
+
+        @Override public String toString() {
+            String name = name();
+
+            for (int i = name.length(); i < 12; i++) {
+                name += " ";
+            }
+            return name;
+        }
+    }
+
+    private static void checkWithCheckSum(Object test, Object golden) {
+        checkSorted(test);
+        checkCheckSum(test, golden);
+    }
+
+    private static void failed(String message) {
+        err.format("\n*** TEST FAILED - %s.\n\n%s.\n\n", ourDescription, message);
+        throw new RuntimeException("Test failed - see log file for details");
+    }
+
+    private static void failedSort(int index, String value1, String value2) {
+        failed("Array is not sorted at " + index + "-th position: " +
+            value1 + " and " + value2);
+    }
+
+    private static void failedCompare(int index, String value1, String value2) {
+        failed("On position " + index + " must be " + value2 + " instead of " + value1);
+    }
+
+    private static void compare(Object test, Object golden) {
+        if (test instanceof int[]) {
+            compare((int[]) test, (int[]) golden);
+        } else if (test instanceof long[]) {
+            compare((long[]) test, (long[]) golden);
+        } else if (test instanceof short[]) {
+            compare((short[]) test, (short[]) golden);
+        } else if (test instanceof byte[]) {
+            compare((byte[]) test, (byte[]) golden);
+        } else if (test instanceof char[]) {
+            compare((char[]) test, (char[]) golden);
+        } else if (test instanceof float[]) {
+            compare((float[]) test, (float[]) golden);
+        } else if (test instanceof double[]) {
+            compare((double[]) test, (double[]) golden);
+        } else if (test instanceof Integer[]) {
+            compare((Integer[]) test, (Integer[]) golden);
+        } else {
+            failed("Unknow type of array: " + test + " of class " +
+                test.getClass().getName());
+        }
+    }
+
+    private static void compare(int[] a, int[] b) {
+        for (int i = 0; i < a.length; i++) {
+            if (a[i] != b[i]) {
+                failedCompare(i, "" + a[i], "" + b[i]);
+            }
+        }
+    }
+
+    private static void compare(long[] a, long[] b) {
+        for (int i = 0; i < a.length; i++) {
+            if (a[i] != b[i]) {
+                failedCompare(i, "" + a[i], "" + b[i]);
+            }
+        }
+    }
+
+    private static void compare(short[] a, short[] b) {
+        for (int i = 0; i < a.length; i++) {
+            if (a[i] != b[i]) {
+                failedCompare(i, "" + a[i], "" + b[i]);
+            }
+        }
+    }
+
+    private static void compare(byte[] a, byte[] b) {
+        for (int i = 0; i < a.length; i++) {
+            if (a[i] != b[i]) {
+                failedCompare(i, "" + a[i], "" + b[i]);
+            }
+        }
+    }
+
+    private static void compare(char[] a, char[] b) {
+        for (int i = 0; i < a.length; i++) {
+            if (a[i] != b[i]) {
+                failedCompare(i, "" + a[i], "" + b[i]);
+            }
+        }
+    }
+
+    private static void compare(float[] a, float[] b) {
+        for (int i = 0; i < a.length; i++) {
+            if (a[i] != b[i]) {
+                failedCompare(i, "" + a[i], "" + b[i]);
+            }
+        }
+    }
+
+    private static void compare(double[] a, double[] b) {
+        for (int i = 0; i < a.length; i++) {
+            if (a[i] != b[i]) {
+                failedCompare(i, "" + a[i], "" + b[i]);
+            }
+        }
+    }
+
+    private static void compare(Integer[] a, Integer[] b) {
+        for (int i = 0; i < a.length; i++) {
+            if (a[i].compareTo(b[i]) != 0) {
+                failedCompare(i, "" + a[i], "" + b[i]);
+            }
+        }
+    }
+
+    private static void checkSorted(Object object) {
+        if (object instanceof int[]) {
+            checkSorted((int[]) object);
+        } else if (object instanceof long[]) {
+            checkSorted((long[]) object);
+        } else if (object instanceof short[]) {
+            checkSorted((short[]) object);
+        } else if (object instanceof byte[]) {
+            checkSorted((byte[]) object);
+        } else if (object instanceof char[]) {
+            checkSorted((char[]) object);
+        } else if (object instanceof float[]) {
+            checkSorted((float[]) object);
+        } else if (object instanceof double[]) {
+            checkSorted((double[]) object);
+        } else if (object instanceof Integer[]) {
+            checkSorted((Integer[]) object);
+        } else {
+            failed("Unknow type of array: " + object + " of class " +
+                object.getClass().getName());
+        }
+    }
+
+    private static void checkSorted(int[] a) {
+        for (int i = 0; i < a.length - 1; i++) {
+            if (a[i] > a[i + 1]) {
+                failedSort(i, "" + a[i], "" + a[i + 1]);
+            }
+        }
+    }
+
+    private static void checkSorted(long[] a) {
+        for (int i = 0; i < a.length - 1; i++) {
+            if (a[i] > a[i + 1]) {
+                failedSort(i, "" + a[i], "" + a[i + 1]);
+            }
+        }
+    }
+
+    private static void checkSorted(short[] a) {
+        for (int i = 0; i < a.length - 1; i++) {
+            if (a[i] > a[i + 1]) {
+                failedSort(i, "" + a[i], "" + a[i + 1]);
+            }
+        }
+    }
+
+    private static void checkSorted(byte[] a) {
+        for (int i = 0; i < a.length - 1; i++) {
+            if (a[i] > a[i + 1]) {
+                failedSort(i, "" + a[i], "" + a[i + 1]);
+            }
+        }
+    }
+
+    private static void checkSorted(char[] a) {
+        for (int i = 0; i < a.length - 1; i++) {
+            if (a[i] > a[i + 1]) {
+                failedSort(i, "" + a[i], "" + a[i + 1]);
+            }
+        }
+    }
+
+    private static void checkSorted(float[] a) {
+        for (int i = 0; i < a.length - 1; i++) {
+            if (a[i] > a[i + 1]) {
+                failedSort(i, "" + a[i], "" + a[i + 1]);
+            }
+        }
+    }
+
+    private static void checkSorted(double[] a) {
+        for (int i = 0; i < a.length - 1; i++) {
+            if (a[i] > a[i + 1]) {
+                failedSort(i, "" + a[i], "" + a[i + 1]);
+            }
+        }
+    }
+
+    private static void checkSorted(Integer[] a) {
+        for (int i = 0; i < a.length - 1; i++) {
+            if (a[i].intValue() > a[i + 1].intValue()) {
+                failedSort(i, "" + a[i], "" + a[i + 1]);
+            }
+        }
+    }
+
+    private static void checkCheckSum(Object test, Object golden) {
+        if (checkSumXor(test) != checkSumXor(golden)) {
+            failed("Original and sorted arrays are not identical [xor]");
+        }
+        if (checkSumPlus(test) != checkSumPlus(golden)) {
+            failed("Original and sorted arrays are not identical [plus]");
+        }
+    }
+
+    private static int checkSumXor(Object object) {
+        if (object instanceof int[]) {
+            return checkSumXor((int[]) object);
+        } else if (object instanceof long[]) {
+            return checkSumXor((long[]) object);
+        } else if (object instanceof short[]) {
+            return checkSumXor((short[]) object);
+        } else if (object instanceof byte[]) {
+            return checkSumXor((byte[]) object);
+        } else if (object instanceof char[]) {
+            return checkSumXor((char[]) object);
+        } else if (object instanceof float[]) {
+            return checkSumXor((float[]) object);
+        } else if (object instanceof double[]) {
+            return checkSumXor((double[]) object);
+        } else if (object instanceof Integer[]) {
+            return checkSumXor((Integer[]) object);
+        } else {
+            failed("Unknow type of array: " + object + " of class " +
+                object.getClass().getName());
+            return -1;
+        }
+    }
+
+    private static int checkSumXor(Integer[] a) {
+        int checkSum = 0;
+
+        for (Integer e : a) {
+            checkSum ^= e.intValue();
+        }
+        return checkSum;
+    }
+
+    private static int checkSumXor(int[] a) {
+        int checkSum = 0;
+
+        for (int e : a) {
+            checkSum ^= e;
+        }
+        return checkSum;
+    }
+
+    private static int checkSumXor(long[] a) {
+        long checkSum = 0;
+
+        for (long e : a) {
+            checkSum ^= e;
+        }
+        return (int) checkSum;
+    }
+
+    private static int checkSumXor(short[] a) {
+        short checkSum = 0;
+
+        for (short e : a) {
+            checkSum ^= e;
+        }
+        return (int) checkSum;
+    }
+
+    private static int checkSumXor(byte[] a) {
+        byte checkSum = 0;
+
+        for (byte e : a) {
+            checkSum ^= e;
+        }
+        return (int) checkSum;
+    }
+
+    private static int checkSumXor(char[] a) {
+        char checkSum = 0;
+
+        for (char e : a) {
+            checkSum ^= e;
+        }
+        return (int) checkSum;
+    }
+
+    private static int checkSumXor(float[] a) {
+        int checkSum = 0;
+
+        for (float e : a) {
+            checkSum ^= (int) e;
+        }
+        return checkSum;
+    }
+
+    private static int checkSumXor(double[] a) {
+        int checkSum = 0;
+
+        for (double e : a) {
+            checkSum ^= (int) e;
+        }
+        return checkSum;
+    }
+
+    private static int checkSumPlus(Object object) {
+        if (object instanceof int[]) {
+            return checkSumPlus((int[]) object);
+        } else if (object instanceof long[]) {
+            return checkSumPlus((long[]) object);
+        } else if (object instanceof short[]) {
+            return checkSumPlus((short[]) object);
+        } else if (object instanceof byte[]) {
+            return checkSumPlus((byte[]) object);
+        } else if (object instanceof char[]) {
+            return checkSumPlus((char[]) object);
+        } else if (object instanceof float[]) {
+            return checkSumPlus((float[]) object);
+        } else if (object instanceof double[]) {
+            return checkSumPlus((double[]) object);
+        } else if (object instanceof Integer[]) {
+            return checkSumPlus((Integer[]) object);
+        } else {
+            failed("Unknow type of array: " + object + " of class " +
+                object.getClass().getName());
+            return -1;
+        }
+    }
+
+    private static int checkSumPlus(int[] a) {
+        int checkSum = 0;
+
+        for (int e : a) {
+            checkSum += e;
+        }
+        return checkSum;
+    }
+
+    private static int checkSumPlus(long[] a) {
+        long checkSum = 0;
+
+        for (long e : a) {
+            checkSum += e;
+        }
+        return (int) checkSum;
+    }
+
+    private static int checkSumPlus(short[] a) {
+        short checkSum = 0;
+
+        for (short e : a) {
+            checkSum += e;
+        }
+        return (int) checkSum;
+    }
+
+    private static int checkSumPlus(byte[] a) {
+        byte checkSum = 0;
+
+        for (byte e : a) {
+            checkSum += e;
+        }
+        return (int) checkSum;
+    }
+
+    private static int checkSumPlus(char[] a) {
+        char checkSum = 0;
+
+        for (char e : a) {
+            checkSum += e;
+        }
+        return (int) checkSum;
+    }
+
+    private static int checkSumPlus(float[] a) {
+        int checkSum = 0;
+
+        for (float e : a) {
+            checkSum += (int) e;
+        }
+        return checkSum;
+    }
+
+    private static int checkSumPlus(double[] a) {
+        int checkSum = 0;
+
+        for (double e : a) {
+            checkSum += (int) e;
+        }
+        return checkSum;
+    }
+
+    private static int checkSumPlus(Integer[] a) {
+        int checkSum = 0;
+
+        for (Integer e : a) {
+            checkSum += e.intValue();
+        }
+        return checkSum;
+    }
+
+    private static void sortByInsertionSort(Object object) {
+        if (object instanceof int[]) {
+            sortByInsertionSort((int[]) object);
+        } else if (object instanceof long[]) {
+            sortByInsertionSort((long[]) object);
+        } else if (object instanceof short[]) {
+            sortByInsertionSort((short[]) object);
+        } else if (object instanceof byte[]) {
+            sortByInsertionSort((byte[]) object);
+        } else if (object instanceof char[]) {
+            sortByInsertionSort((char[]) object);
+        } else if (object instanceof float[]) {
+            sortByInsertionSort((float[]) object);
+        } else if (object instanceof double[]) {
+            sortByInsertionSort((double[]) object);
+        } else if (object instanceof Integer[]) {
+            sortByInsertionSort((Integer[]) object);
+        } else {
+            failed("Unknow type of array: " + object + " of class " +
+                object.getClass().getName());
+        }
+    }
+
+    private static void sortByInsertionSort(int[] a) {
+        for (int j, i = 1; i < a.length; i++) {
+            int ai = a[i];
+            for (j = i - 1; j >= 0 && ai < a[j]; j--) {
+                a[j + 1] = a[j];
+            }
+            a[j + 1] = ai;
+        }
+    }
+
+    private static void sortByInsertionSort(long[] a) {
+        for (int j, i = 1; i < a.length; i++) {
+            long ai = a[i];
+            for (j = i - 1; j >= 0 && ai < a[j]; j--) {
+                a[j + 1] = a[j];
+            }
+            a[j + 1] = ai;
+        }
+    }
+
+    private static void sortByInsertionSort(short[] a) {
+        for (int j, i = 1; i < a.length; i++) {
+            short ai = a[i];
+            for (j = i - 1; j >= 0 && ai < a[j]; j--) {
+                a[j + 1] = a[j];
+            }
+            a[j + 1] = ai;
+        }
+    }
+
+    private static void sortByInsertionSort(byte[] a) {
+        for (int j, i = 1; i < a.length; i++) {
+            byte ai = a[i];
+            for (j = i - 1; j >= 0 && ai < a[j]; j--) {
+                a[j + 1] = a[j];
+            }
+            a[j + 1] = ai;
+        }
+    }
+
+    private static void sortByInsertionSort(char[] a) {
+        for (int j, i = 1; i < a.length; i++) {
+            char ai = a[i];
+            for (j = i - 1; j >= 0 && ai < a[j]; j--) {
+                a[j + 1] = a[j];
+            }
+            a[j + 1] = ai;
+        }
+    }
+
+    private static void sortByInsertionSort(float[] a) {
+        for (int j, i = 1; i < a.length; i++) {
+            float ai = a[i];
+            for (j = i - 1; j >= 0 && ai < a[j]; j--) {
+                a[j + 1] = a[j];
+            }
+            a[j + 1] = ai;
+        }
+    }
+
+    private static void sortByInsertionSort(double[] a) {
+        for (int j, i = 1; i < a.length; i++) {
+            double ai = a[i];
+            for (j = i - 1; j >= 0 && ai < a[j]; j--) {
+                a[j + 1] = a[j];
+            }
+            a[j + 1] = ai;
+        }
+    }
+
+    private static void sortByInsertionSort(Integer[] a) {
+        for (int j, i = 1; i < a.length; i++) {
+            Integer ai = a[i];
+            for (j = i - 1; j >= 0 && ai < a[j]; j--) {
+                a[j + 1] = a[j];
+            }
+            a[j + 1] = ai;
+        }
+    }
+
+    private static void sort(Object object) {
+        if (object instanceof int[]) {
+            Arrays.parallelSort((int[]) object);
+        } else if (object instanceof long[]) {
+            Arrays.parallelSort((long[]) object);
+        } else if (object instanceof short[]) {
+            Arrays.parallelSort((short[]) object);
+        } else if (object instanceof byte[]) {
+            Arrays.parallelSort((byte[]) object);
+        } else if (object instanceof char[]) {
+            Arrays.parallelSort((char[]) object);
+        } else if (object instanceof float[]) {
+            Arrays.parallelSort((float[]) object);
+        } else if (object instanceof double[]) {
+            Arrays.parallelSort((double[]) object);
+        } else if (object instanceof Integer[]) {
+            Arrays.parallelSort((Integer[]) object);
+        } else {
+            failed("Unknow type of array: " + object + " of class " +
+                object.getClass().getName());
+        }
+    }
+
+    private static void sortSubArray(Object object, int fromIndex, int toIndex) {
+        if (object instanceof int[]) {
+            Arrays.parallelSort((int[]) object, fromIndex, toIndex);
+        } else if (object instanceof long[]) {
+            Arrays.parallelSort((long[]) object, fromIndex, toIndex);
+        } else if (object instanceof short[]) {
+            Arrays.parallelSort((short[]) object, fromIndex, toIndex);
+        } else if (object instanceof byte[]) {
+            Arrays.parallelSort((byte[]) object, fromIndex, toIndex);
+        } else if (object instanceof char[]) {
+            Arrays.parallelSort((char[]) object, fromIndex, toIndex);
+        } else if (object instanceof float[]) {
+            Arrays.parallelSort((float[]) object, fromIndex, toIndex);
+        } else if (object instanceof double[]) {
+            Arrays.parallelSort((double[]) object, fromIndex, toIndex);
+        } else if (object instanceof Integer[]) {
+            Arrays.parallelSort((Integer[]) object, fromIndex, toIndex);
+        } else {
+            failed("Unknow type of array: " + object + " of class " +
+                object.getClass().getName());
+        }
+    }
+
+    private static void checkSubArray(Object object, int fromIndex, int toIndex, int m) {
+        if (object instanceof int[]) {
+            checkSubArray((int[]) object, fromIndex, toIndex, m);
+        } else if (object instanceof long[]) {
+            checkSubArray((long[]) object, fromIndex, toIndex, m);
+        } else if (object instanceof short[]) {
+            checkSubArray((short[]) object, fromIndex, toIndex, m);
+        } else if (object instanceof byte[]) {
+            checkSubArray((byte[]) object, fromIndex, toIndex, m);
+        } else if (object instanceof char[]) {
+            checkSubArray((char[]) object, fromIndex, toIndex, m);
+        } else if (object instanceof float[]) {
+            checkSubArray((float[]) object, fromIndex, toIndex, m);
+        } else if (object instanceof double[]) {
+            checkSubArray((double[]) object, fromIndex, toIndex, m);
+        } else if (object instanceof Integer[]) {
+            checkSubArray((Integer[]) object, fromIndex, toIndex, m);
+        } else {
+            failed("Unknow type of array: " + object + " of class " +
+                object.getClass().getName());
+        }
+    }
+
+    private static void checkSubArray(Integer[] a, int fromIndex, int toIndex, int m) {
+        for (int i = 0; i < fromIndex; i++) {
+            if (a[i].intValue() != 0xDEDA) {
+                failed("Range sort changes left element on position " + i +
+                    ": " + a[i] + ", must be " + 0xDEDA);
+            }
+        }
+
+        for (int i = fromIndex; i < toIndex - 1; i++) {
+            if (a[i].intValue() > a[i + 1].intValue()) {
+                failedSort(i, "" + a[i], "" + a[i + 1]);
+            }
+        }
+
+        for (int i = toIndex; i < a.length; i++) {
+            if (a[i].intValue() != 0xBABA) {
+                failed("Range sort changes right element on position " + i +
+                    ": " + a[i] + ", must be " + 0xBABA);
+            }
+        }
+    }
+
+    private static void checkSubArray(int[] a, int fromIndex, int toIndex, int m) {
+        for (int i = 0; i < fromIndex; i++) {
+            if (a[i] != 0xDEDA) {
+                failed("Range sort changes left element on position " + i +
+                    ": " + a[i] + ", must be " + 0xDEDA);
+            }
+        }
+
+        for (int i = fromIndex; i < toIndex - 1; i++) {
+            if (a[i] > a[i + 1]) {
+                failedSort(i, "" + a[i], "" + a[i + 1]);
+            }
+        }
+
+        for (int i = toIndex; i < a.length; i++) {
+            if (a[i] != 0xBABA) {
+                failed("Range sort changes right element on position " + i +
+                    ": " + a[i] + ", must be " + 0xBABA);
+            }
+        }
+    }
+
+    private static void checkSubArray(byte[] a, int fromIndex, int toIndex, int m) {
+        for (int i = 0; i < fromIndex; i++) {
+            if (a[i] != (byte) 0xDEDA) {
+                failed("Range sort changes left element on position " + i +
+                    ": " + a[i] + ", must be " + 0xDEDA);
+            }
+        }
+
+        for (int i = fromIndex; i < toIndex - 1; i++) {
+            if (a[i] > a[i + 1]) {
+                failedSort(i, "" + a[i], "" + a[i + 1]);
+            }
+        }
+
+        for (int i = toIndex; i < a.length; i++) {
+            if (a[i] != (byte) 0xBABA) {
+                failed("Range sort changes right element on position " + i +
+                    ": " + a[i] + ", must be " + 0xBABA);
+            }
+        }
+    }
+
+    private static void checkSubArray(long[] a, int fromIndex, int toIndex, int m) {
+        for (int i = 0; i < fromIndex; i++) {
+            if (a[i] != (long) 0xDEDA) {
+                failed("Range sort changes left element on position " + i +
+                    ": " + a[i] + ", must be " + 0xDEDA);
+            }
+        }
+
+        for (int i = fromIndex; i < toIndex - 1; i++) {
+            if (a[i] > a[i + 1]) {
+                failedSort(i, "" + a[i], "" + a[i + 1]);
+            }
+        }
+
+        for (int i = toIndex; i < a.length; i++) {
+            if (a[i] != (long) 0xBABA) {
+                failed("Range sort changes right element on position " + i +
+                    ": " + a[i] + ", must be " + 0xBABA);
+            }
+        }
+    }
+
+    private static void checkSubArray(char[] a, int fromIndex, int toIndex, int m) {
+        for (int i = 0; i < fromIndex; i++) {
+            if (a[i] != (char) 0xDEDA) {
+                failed("Range sort changes left element on position " + i +
+                    ": " + a[i] + ", must be " + 0xDEDA);
+            }
+        }
+
+        for (int i = fromIndex; i < toIndex - 1; i++) {
+            if (a[i] > a[i + 1]) {
+                failedSort(i, "" + a[i], "" + a[i + 1]);
+            }
+        }
+
+        for (int i = toIndex; i < a.length; i++) {
+            if (a[i] != (char) 0xBABA) {
+                failed("Range sort changes right element on position " + i +
+                    ": " + a[i] + ", must be " + 0xBABA);
+            }
+        }
+    }
+
+    private static void checkSubArray(short[] a, int fromIndex, int toIndex, int m) {
+        for (int i = 0; i < fromIndex; i++) {
+            if (a[i] != (short) 0xDEDA) {
+                failed("Range sort changes left element on position " + i +
+                    ": " + a[i] + ", must be " + 0xDEDA);
+            }
+        }
+
+        for (int i = fromIndex; i < toIndex - 1; i++) {
+            if (a[i] > a[i + 1]) {
+                failedSort(i, "" + a[i], "" + a[i + 1]);
+            }
+        }
+
+        for (int i = toIndex; i < a.length; i++) {
+            if (a[i] != (short) 0xBABA) {
+                failed("Range sort changes right element on position " + i +
+                    ": " + a[i] + ", must be " + 0xBABA);
+            }
+        }
+    }
+
+    private static void checkSubArray(float[] a, int fromIndex, int toIndex, int m) {
+        for (int i = 0; i < fromIndex; i++) {
+            if (a[i] != (float) 0xDEDA) {
+                failed("Range sort changes left element on position " + i +
+                    ": " + a[i] + ", must be " + 0xDEDA);
+            }
+        }
+
+        for (int i = fromIndex; i < toIndex - 1; i++) {
+            if (a[i] > a[i + 1]) {
+                failedSort(i, "" + a[i], "" + a[i + 1]);
+            }
+        }
+
+        for (int i = toIndex; i < a.length; i++) {
+            if (a[i] != (float) 0xBABA) {
+                failed("Range sort changes right element on position " + i +
+                    ": " + a[i] + ", must be " + 0xBABA);
+            }
+        }
+    }
+
+    private static void checkSubArray(double[] a, int fromIndex, int toIndex, int m) {
+        for (int i = 0; i < fromIndex; i++) {
+            if (a[i] != (double) 0xDEDA) {
+                failed("Range sort changes left element on position " + i +
+                    ": " + a[i] + ", must be " + 0xDEDA);
+            }
+        }
+
+        for (int i = fromIndex; i < toIndex - 1; i++) {
+            if (a[i] > a[i + 1]) {
+                failedSort(i, "" + a[i], "" + a[i + 1]);
+            }
+        }
+
+        for (int i = toIndex; i < a.length; i++) {
+            if (a[i] != (double) 0xBABA) {
+                failed("Range sort changes right element on position " + i +
+                    ": " + a[i] + ", must be " + 0xBABA);
+            }
+        }
+    }
+
+    private static void checkRange(Object object, int m) {
+        if (object instanceof int[]) {
+            checkRange((int[]) object, m);
+        } else if (object instanceof long[]) {
+            checkRange((long[]) object, m);
+        } else if (object instanceof short[]) {
+            checkRange((short[]) object, m);
+        } else if (object instanceof byte[]) {
+            checkRange((byte[]) object, m);
+        } else if (object instanceof char[]) {
+            checkRange((char[]) object, m);
+        } else if (object instanceof float[]) {
+            checkRange((float[]) object, m);
+        } else if (object instanceof double[]) {
+            checkRange((double[]) object, m);
+        } else if (object instanceof Integer[]) {
+            checkRange((Integer[]) object, m);
+        } else {
+            failed("Unknow type of array: " + object + " of class " +
+                object.getClass().getName());
+        }
+    }
+
+    private static void checkRange(Integer[] a, int m) {
+        try {
+            Arrays.parallelSort(a, m + 1, m);
+
+            failed("ParallelSort does not throw IllegalArgumentException " +
+                " as expected: fromIndex = " + (m + 1) +
+                " toIndex = " + m);
+        }
+        catch (IllegalArgumentException iae) {
+            try {
+                Arrays.parallelSort(a, -m, a.length);
+
+                failed("ParallelSort does not throw ArrayIndexOutOfBoundsException " +
+                    " as expected: fromIndex = " + (-m));
+            }
+            catch (ArrayIndexOutOfBoundsException aoe) {
+                try {
+                    Arrays.parallelSort(a, 0, a.length + m);
+
+                    failed("ParallelSort does not throw ArrayIndexOutOfBoundsException " +
+                        " as expected: toIndex = " + (a.length + m));
+                }
+                catch (ArrayIndexOutOfBoundsException aie) {
+                    return;
+                }
+            }
+        }
+    }
+
+    private static void checkRange(int[] a, int m) {
+        try {
+            Arrays.parallelSort(a, m + 1, m);
+
+            failed("ParallelSort does not throw IllegalArgumentException " +
+                " as expected: fromIndex = " + (m + 1) +
+                " toIndex = " + m);
+        }
+        catch (IllegalArgumentException iae) {
+            try {
+                Arrays.parallelSort(a, -m, a.length);
+
+                failed("ParallelSort does not throw ArrayIndexOutOfBoundsException " +
+                    " as expected: fromIndex = " + (-m));
+            }
+            catch (ArrayIndexOutOfBoundsException aoe) {
+                try {
+                    Arrays.parallelSort(a, 0, a.length + m);
+
+                    failed("ParallelSort does not throw ArrayIndexOutOfBoundsException " +
+                        " as expected: toIndex = " + (a.length + m));
+                }
+                catch (ArrayIndexOutOfBoundsException aie) {
+                    return;
+                }
+            }
+        }
+    }
+
+    private static void checkRange(long[] a, int m) {
+        try {
+            Arrays.parallelSort(a, m + 1, m);
+
+            failed("ParallelSort does not throw IllegalArgumentException " +
+                " as expected: fromIndex = " + (m + 1) +
+                " toIndex = " + m);
+        }
+        catch (IllegalArgumentException iae) {
+            try {
+                Arrays.parallelSort(a, -m, a.length);
+
+                failed("ParallelSort does not throw ArrayIndexOutOfBoundsException " +
+                    " as expected: fromIndex = " + (-m));
+            }
+            catch (ArrayIndexOutOfBoundsException aoe) {
+                try {
+                    Arrays.parallelSort(a, 0, a.length + m);
+
+                    failed("ParallelSort does not throw ArrayIndexOutOfBoundsException " +
+                        " as expected: toIndex = " + (a.length + m));
+                }
+                catch (ArrayIndexOutOfBoundsException aie) {
+                    return;
+                }
+            }
+        }
+    }
+
+    private static void checkRange(byte[] a, int m) {
+        try {
+            Arrays.parallelSort(a, m + 1, m);
+
+            failed("ParallelSort does not throw IllegalArgumentException " +
+                " as expected: fromIndex = " + (m + 1) +
+                " toIndex = " + m);
+        }
+        catch (IllegalArgumentException iae) {
+            try {
+                Arrays.parallelSort(a, -m, a.length);
+
+                failed("ParallelSort does not throw ArrayIndexOutOfBoundsException " +
+                    " as expected: fromIndex = " + (-m));
+            }
+            catch (ArrayIndexOutOfBoundsException aoe) {
+                try {
+                    Arrays.parallelSort(a, 0, a.length + m);
+
+                    failed("ParallelSort does not throw ArrayIndexOutOfBoundsException " +
+                        " as expected: toIndex = " + (a.length + m));
+                }
+                catch (ArrayIndexOutOfBoundsException aie) {
+                    return;
+                }
+            }
+        }
+    }
+
+    private static void checkRange(short[] a, int m) {
+        try {
+            Arrays.parallelSort(a, m + 1, m);
+
+            failed("ParallelSort does not throw IllegalArgumentException " +
+                " as expected: fromIndex = " + (m + 1) +
+                " toIndex = " + m);
+        }
+        catch (IllegalArgumentException iae) {
+            try {
+                Arrays.parallelSort(a, -m, a.length);
+
+                failed("ParallelSort does not throw ArrayIndexOutOfBoundsException " +
+                    " as expected: fromIndex = " + (-m));
+            }
+            catch (ArrayIndexOutOfBoundsException aoe) {
+                try {
+                    Arrays.parallelSort(a, 0, a.length + m);
+
+                    failed("ParallelSort does not throw ArrayIndexOutOfBoundsException " +
+                        " as expected: toIndex = " + (a.length + m));
+                }
+                catch (ArrayIndexOutOfBoundsException aie) {
+                    return;
+                }
+            }
+        }
+    }
+
+    private static void checkRange(char[] a, int m) {
+        try {
+            Arrays.parallelSort(a, m + 1, m);
+
+            failed("ParallelSort does not throw IllegalArgumentException " +
+                " as expected: fromIndex = " + (m + 1) +
+                " toIndex = " + m);
+        }
+        catch (IllegalArgumentException iae) {
+            try {
+                Arrays.parallelSort(a, -m, a.length);
+
+                failed("ParallelSort does not throw ArrayIndexOutOfBoundsException " +
+                    " as expected: fromIndex = " + (-m));
+            }
+            catch (ArrayIndexOutOfBoundsException aoe) {
+                try {
+                    Arrays.parallelSort(a, 0, a.length + m);
+
+                    failed("ParallelSort does not throw ArrayIndexOutOfBoundsException " +
+                        " as expected: toIndex = " + (a.length + m));
+                }
+                catch (ArrayIndexOutOfBoundsException aie) {
+                    return;
+                }
+            }
+        }
+    }
+
+    private static void checkRange(float[] a, int m) {
+        try {
+            Arrays.parallelSort(a, m + 1, m);
+
+            failed("ParallelSort does not throw IllegalArgumentException " +
+                " as expected: fromIndex = " + (m + 1) +
+                " toIndex = " + m);
+        }
+        catch (IllegalArgumentException iae) {
+            try {
+                Arrays.parallelSort(a, -m, a.length);
+
+                failed("ParallelSort does not throw ArrayIndexOutOfBoundsException " +
+                    " as expected: fromIndex = " + (-m));
+            }
+            catch (ArrayIndexOutOfBoundsException aoe) {
+                try {
+                    Arrays.parallelSort(a, 0, a.length + m);
+
+                    failed("ParallelSort does not throw ArrayIndexOutOfBoundsException " +
+                        " as expected: toIndex = " + (a.length + m));
+                }
+                catch (ArrayIndexOutOfBoundsException aie) {
+                    return;
+                }
+            }
+        }
+    }
+
+    private static void checkRange(double[] a, int m) {
+        try {
+            Arrays.parallelSort(a, m + 1, m);
+
+            failed("ParallelSort does not throw IllegalArgumentException " +
+                " as expected: fromIndex = " + (m + 1) +
+                " toIndex = " + m);
+        }
+        catch (IllegalArgumentException iae) {
+            try {
+                Arrays.parallelSort(a, -m, a.length);
+
+                failed("ParallelSort does not throw ArrayIndexOutOfBoundsException " +
+                    " as expected: fromIndex = " + (-m));
+            }
+            catch (ArrayIndexOutOfBoundsException aoe) {
+                try {
+                    Arrays.parallelSort(a, 0, a.length + m);
+
+                    failed("ParallelSort does not throw ArrayIndexOutOfBoundsException " +
+                        " as expected: toIndex = " + (a.length + m));
+                }
+                catch (ArrayIndexOutOfBoundsException aie) {
+                    return;
+                }
+            }
+        }
+    }
+
+    private static void outArray(Object[] a) {
+        for (int i = 0; i < a.length; i++) {
+            out.print(a[i] + " ");
+        }
+        out.println();
+    }
+
+    private static void outArray(int[] a) {
+        for (int i = 0; i < a.length; i++) {
+            out.print(a[i] + " ");
+        }
+        out.println();
+    }
+
+    private static void outArray(float[] a) {
+        for (int i = 0; i < a.length; i++) {
+            out.print(a[i] + " ");
+        }
+        out.println();
+    }
+
+    private static void outArray(double[] a) {
+        for (int i = 0; i < a.length; i++) {
+            out.print(a[i] + " ");
+        }
+        out.println();
+    }
+
+    private static class MyRandom extends Random {
+        MyRandom(long seed) {
+            super(seed);
+            mySeed = seed;
+        }
+
+        long getSeed() {
+            return mySeed;
+        }
+
+        private long mySeed;
+    }
+
+    private static String ourDescription;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/function/PredicateTest.java	Wed Aug 14 15:53:13 2013 -0700
@@ -0,0 +1,208 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8004561
+ * @run testng PredicateTest
+ */
+
+import org.testng.annotations.Test;
+
+import java.util.HashSet;
+import java.util.function.Predicate;
+import java.util.function.DoublePredicate;
+import java.util.function.IntPredicate;
+import java.util.function.LongPredicate;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.assertFalse;
+
+/**
+ * Unit tests for helper methods in Comparators
+ */
+@Test(groups = "unit")
+public class PredicateTest {
+
+    public void testIntPredicate() {
+        IntPredicate pOdd = (t) -> 0 != (t & 1);
+        IntPredicate pEven = (t) -> 0 == (t & 1);
+
+        assertFalse(pOdd.test(0));
+        assertFalse(pOdd.test(Integer.valueOf(0)));
+        assertFalse(pOdd.test(new Integer(0)));
+        assertFalse(pOdd.test(0));
+
+        assertTrue(pOdd.test(1));
+        assertTrue(pOdd.test(Integer.valueOf(1)));
+        assertTrue(pOdd.test(new Integer(1)));
+        assertTrue(pOdd.test(1));
+
+        assertTrue(pEven.test(0));
+        assertTrue(pEven.test(Integer.valueOf(0)));
+        assertTrue(pEven.test(new Integer(0)));
+        assertTrue(pEven.test(0));
+
+        assertFalse(pEven.test(1));
+        assertFalse(pEven.test(Integer.valueOf(1)));
+        assertFalse(pEven.test(new Integer(1)));
+        assertFalse(pEven.test(1));
+
+        int magic[] = { 8675390 };
+        IntPredicate pMagic = (t) -> t == magic[0];
+
+        assertFalse(pMagic.test(3927704 ));
+        assertFalse(pMagic.test(Integer.valueOf(3927704)));
+        assertFalse(pMagic.test(new Integer(3927704)));
+        assertFalse(pMagic.test(3927704));
+
+        assertTrue(pMagic.test(8675390));
+        assertTrue(pMagic.test(Integer.valueOf(8675390)));
+        assertTrue(pMagic.test(new Integer(8675390)));
+        assertTrue(pMagic.test(8675390));
+
+        magic[0] = 3927704;
+
+        assertTrue(pMagic.test(3927704));
+        assertTrue(pMagic.test(Integer.valueOf(3927704)));
+        assertTrue(pMagic.test(new Integer(3927704)));
+        assertTrue(pMagic.test(3927704));
+
+        assertFalse(pMagic.test(8675390));
+        assertFalse(pMagic.test(Integer.valueOf(8675390)));
+        assertFalse(pMagic.test(new Integer(8675390)));
+        assertFalse(pMagic.test(8675390));
+    }
+
+    public void testLongPredicate() {
+        LongPredicate pOdd = (t) -> 0 != (t & 1);
+        LongPredicate pEven = (t) -> 0 == (t & 1);
+
+        assertFalse(pOdd.test(0L));
+        assertFalse(pOdd.test(Long.valueOf(0L)));
+        assertFalse(pOdd.test(new Long(0L)));
+        assertFalse(pOdd.test(0L));
+
+        assertTrue(pOdd.test(1L));
+        assertTrue(pOdd.test(Long.valueOf(1L)));
+        assertTrue(pOdd.test(new Long(1L)));
+        assertTrue(pOdd.test(1L));
+
+        assertTrue(pEven.test(0L));
+        assertTrue(pEven.test(Long.valueOf(0L)));
+        assertTrue(pEven.test(new Long(0L)));
+        assertTrue(pEven.test(0L));
+
+        assertFalse(pEven.test(1L));
+        assertFalse(pEven.test(Long.valueOf(1L)));
+        assertFalse(pEven.test(new Long(1L)));
+        assertFalse(pEven.test(1L));
+
+        long magic[] = { 8675390L };
+        LongPredicate pMagic = (t) -> t == magic[0];
+
+        assertFalse(pMagic.test(3927704L));
+        assertFalse(pMagic.test(Long.valueOf(3927704L)));
+        assertFalse(pMagic.test(new Long(3927704L)));
+        assertFalse(pMagic.test(3927704L));
+
+        assertTrue(pMagic.test(8675390L));
+        assertTrue(pMagic.test(Long.valueOf(8675390L)));
+        assertTrue(pMagic.test(new Long(8675390L)));
+        assertTrue(pMagic.test(8675390L));
+
+        magic[0] = 3927704L;
+
+        assertTrue(pMagic.test(3927704L));
+        assertTrue(pMagic.test(Long.valueOf(3927704L)));
+        assertTrue(pMagic.test(new Long(3927704L)));
+        assertTrue(pMagic.test(3927704L));
+
+        assertFalse(pMagic.test(8675390L));
+        assertFalse(pMagic.test(Long.valueOf(8675390L)));
+        assertFalse(pMagic.test(new Long(8675390L)));
+        assertFalse(pMagic.test(8675390L));
+    }
+
+    public void testDoublePredicate() {
+        DoublePredicate pInfinite = (t) -> Double.isInfinite(t);
+        DoublePredicate pFinite = (t) -> Double.isFinite(t);
+
+        assertFalse(pInfinite.test(0.0));
+        assertFalse(pInfinite.test(Double.valueOf(0.0)));
+        assertFalse(pInfinite.test(new Double(0.0)));
+        assertFalse(pInfinite.test(0.0));
+
+        assertTrue(pInfinite.test(Double.POSITIVE_INFINITY));
+        assertTrue(pInfinite.test(Double.valueOf(Double.POSITIVE_INFINITY)));
+        assertTrue(pInfinite.test(new Double(Double.POSITIVE_INFINITY)));
+        assertTrue(pInfinite.test(Double.POSITIVE_INFINITY));
+
+        assertTrue(pFinite.test(0.0));
+        assertTrue(pFinite.test(Double.valueOf(0.0)));
+        assertTrue(pFinite.test(new Double(0.0)));
+        assertTrue(pFinite.test(0.0));
+
+        assertFalse(pFinite.test(Double.POSITIVE_INFINITY));
+        assertFalse(pFinite.test(Double.valueOf(Double.POSITIVE_INFINITY)));
+        assertFalse(pFinite.test(new Double(Double.POSITIVE_INFINITY)));
+        assertFalse(pFinite.test(Double.POSITIVE_INFINITY));
+
+        double magic[] = { 1.8675390 };
+        DoublePredicate pMagic = (t) -> t == magic[0];
+
+        assertFalse(pMagic.test(1.3927704));
+        assertFalse(pMagic.test(Double.valueOf(1.3927704)));
+        assertFalse(pMagic.test(new Double(1.3927704)));
+        assertFalse(pMagic.test(1.3927704));
+
+        assertTrue(pMagic.test(1.8675390));
+        assertTrue(pMagic.test(Double.valueOf(1.8675390)));
+        assertTrue(pMagic.test(new Double(1.8675390)));
+        assertTrue(pMagic.test(1.8675390));
+
+        magic[0] = 1.3927704;
+
+        assertTrue(pMagic.test(1.3927704));
+        assertTrue(pMagic.test(Double.valueOf(1.3927704)));
+        assertTrue(pMagic.test(new Double(1.3927704)));
+        assertTrue(pMagic.test(1.3927704));
+
+        assertFalse(pMagic.test(1.8675390));
+        assertFalse(pMagic.test(Double.valueOf(1.8675390)));
+        assertFalse(pMagic.test(new Double(1.8675390)));
+        assertFalse(pMagic.test(1.8675390));
+    }
+
+    @Test
+    public void testIsEqual() {
+        HashSet<Long> s1 = new HashSet<>();
+        HashSet<Long> s2 = (HashSet<Long>) s1.clone();
+        assertTrue(Predicate.isEqual(null).test(null));
+        assertTrue(Predicate.isEqual(s2).test(s1));
+    }
+
+}
--- a/test/java/util/regex/RegExTest.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/test/java/util/regex/RegExTest.java	Wed Aug 14 15:53:13 2013 -0700
@@ -40,6 +40,7 @@
 import java.util.Random;
 import java.io.*;
 import java.util.*;
+import java.util.function.Predicate;
 import java.nio.CharBuffer;
 import java.util.function.Predicate;
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/stream/Stream/BaseStreamTest.java	Wed Aug 14 15:53:13 2013 -0700
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+
+public class BaseStreamTest {
+    
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/stream/Stream/EmployeeStreamTest.java	Wed Aug 14 15:53:13 2013 -0700
@@ -0,0 +1,307 @@
+/*
+ * 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 Basic test for Stream<Employee>
+ * @library /sqeutil
+ * @(#) EmployeeStreamTest.java
+ * @author Eric Wang/Tristan Yan
+ * @run testng/othervm -mx1g EmployeeStreamTest
+ */
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.Objects;
+import java.util.function.BiFunction;
+import java.util.function.BinaryOperator;
+import java.util.function.Function;
+import java.util.function.IntFunction;
+import java.util.function.ToIntFunction;
+import org.testng.annotations.Factory;
+
+class Employee implements Comparable<Employee>, Cloneable {
+    static final int ID_LENGTH = 6;
+    static final int MIN_BIRTHDAY = 1900;
+    static final int MAX_BIRTHDAY = 2050;
+    static final int MIN_PAY = 1000;
+    static final int MAX_PAY = 100000;
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    } 
+        
+    public int getBirthday() {
+        return birthday;
+    }
+
+    public boolean isMale() {
+        return male;
+    }
+
+    public double getPay() {
+        return pay;
+    }
+
+    public void setPay(double pay) {
+        this.pay = pay;
+    }  
+
+    public Title getTitle() {
+        return title;
+    }
+
+    public void setTitle(Title title) {
+        this.title = title;
+    }
+    public Employee(String id, int birthday, boolean male, double pay, Title title) {
+        this.id = id;
+        this.birthday = birthday;
+        this.male = male;
+        this.pay = pay;
+        this.title = title;
+    }
+
+    static enum Title {
+        SE, SSE, PSE, CSE, ARCHITECT, M1, M2, M3, M4
+    }
+
+    static enum Rule {
+        ID {
+            @Override
+            Function<Employee, String> empFunc() {
+                return Employee::getId;
+            }
+            @Override
+            String funcName(){
+                return "Employee::getId";
+            }
+        },
+        BIRTHDAY {
+            @Override
+            Function<Employee, Integer> empFunc() {
+                return Employee::getBirthday;
+            }
+            @Override
+            String funcName(){
+                return "Employee::getBirthday";
+            }
+        },
+        MALE {
+            @Override
+            Function<Employee, Boolean> empFunc() {
+                return Employee::isMale;
+            }
+            @Override
+            String funcName(){
+                return "Employee::isMale";
+            }
+        },
+        PAY {
+            @Override
+            Function<Employee, Double> empFunc() {
+                return Employee::getPay;
+            }
+            @Override
+            String funcName(){
+                return "Employee::getPay";
+            }
+        },
+        TITLE {
+            @Override
+            Function<Employee, Title> empFunc(){
+                return Employee::getTitle;
+            }
+
+            @Override
+            String funcName(){
+                return "Employee::getTitle";
+            }
+        };
+
+        Comparator<Employee> getComparator() {
+            return Comparator.comparing(empFunc());
+        }
+
+        Object getValue(Employee e) { return empFunc().apply(e); }
+        
+        abstract String funcName();
+        
+        abstract Function<Employee, ? extends Comparable> empFunc();
+    }
+ 
+    private String id;
+    private final int birthday;
+    private final boolean male;
+    private double pay;
+    private Title title;
+
+    @Override
+    public boolean equals(Object other) {
+        if (other instanceof Employee) {
+            Employee compared = (Employee) other;
+            return id.equals(compared.getId()) && birthday == compared.getBirthday()
+                    && male == compared.isMale() && pay == compared.getPay()
+                    && title == compared.getTitle();
+        } 
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(this.id);
+    }
+
+    @Override
+    public int compareTo(Employee t) {
+        return id.compareTo(t.getId());
+    }
+
+    @Override
+    public Employee clone() {
+        try {
+            return (Employee)super.clone();
+        } catch (CloneNotSupportedException ex) {
+            throw new RuntimeException(ex);
+        }
+    }
+
+    @Override
+    public String toString() {
+        return "id=" + getId() + ", birthday=" + getBirthday() + ". male=" + isMale()
+                + ", pay=" + getPay() + ", title=" + getTitle();
+    }
+}
+
+public class EmployeeStreamTest<T extends Collection<Employee>> extends
+            GenericStreamTest<Employee, Collection<Employee>> {
+    public EmployeeStreamTest(Class clazz, 
+            ParallelType parallelType, int initSize) {
+        super(clazz, parallelType, Comparator.naturalOrder(), initSize);
+    }
+
+    public EmployeeStreamTest(Class clazz, 
+            ParallelType parallelType) {
+        super(clazz, parallelType, Comparator.naturalOrder());
+    }
+
+    @Factory
+    public static Object[] create(){
+      TripleFunction<Class,ParallelType,Integer, EmployeeStreamTest> supplierWithInitSize =
+              EmployeeStreamTest<Collection<Employee>>::<Class,ParallelType,Integer>new;
+      BiFunction<Class,ParallelType,EmployeeStreamTest> supplier =
+              EmployeeStreamTest<Collection<Employee>>::<Class,ParallelType>new;
+      return GenericStreamTest.create(supplierWithInitSize, supplier, true);
+    }
+
+    @Override
+    public String getTestName() {
+        return typeObject.getName() + "<Employee>";
+    }
+
+    @Override
+    protected Object[] predicateAndDesc(int size) {
+        Employee limit = createEmployee();
+        boolean isUp = rand.nextBoolean();
+        Employee.Rule rule = Arrays.stream(Employee.Rule.values()).findAny().get();
+        return new Object[]{ LambdaUtilities.randomGenericPredicate(isUp, limit, rule.getComparator()), 
+                String.format("emp -> Comparator.comparing(%s).compare(emp, %s) %s 0", rule.funcName(), isUp ? ">=" : "<", limit)};
+    }
+    
+    //Function<U, ? extends Comparable>, descrption for Function<? extends Comparable>
+    @Override
+    protected Object[][] functionAndDesc(){
+            return Arrays.stream(Employee.Rule.values()).map(rule -> new Object[]{rule.empFunc(), rule.funcName()})
+                    .toArray(Object[][]::new);   
+    }
+   
+    //BinaryOperator, descrption, stateless
+    @Override
+    protected Object[][] binaryOperatorAndDesc() {
+        BinaryOperator<Employee> maxOp = (e1, e2) -> naturalOrderComparator.compare(e1, e2) < 0 ? e2 : e1;
+        BinaryOperator<Employee> minOp =  (e1, e2) -> naturalOrderComparator.compare(e1, e2) > 0? e2 : e1;
+        return new Object[][]{
+            {maxOp, "(e1, e2) -> naturalOrderComparator.compare(e1, e2) < 0 ? e2 : e1", true},
+            {minOp, "(e1, e2) -> naturalOrderComparator.compare(e1, e2) > 0? e2 : e1", true},
+        }; 
+    }
+    
+    @Override
+   protected Employee[] bases(int size){
+        return new Employee[]{createEmployee()};
+    }
+
+    @Override
+    protected Collection<Employee> generate(int size) {
+        Collection<Employee> col = createEmptyCollection();
+        for (int i = 0; i < size; i++) {
+            col.add(createEmployee(String.valueOf(i + 1)));
+        }
+        return col;
+    }
+    
+    private Employee createEmployee(String id)  {
+        BiFunction<Integer, Integer, Integer> RANDOM_INT_BETWEEN
+            = (start, end) -> start + rand.nextInt(end - start);
+        int birthday = RANDOM_INT_BETWEEN.apply(Employee.MIN_BIRTHDAY, Employee.MAX_BIRTHDAY);
+        Boolean gender = rand.nextBoolean();
+        double pay = RANDOM_INT_BETWEEN.apply(Employee.MIN_PAY, Employee.MAX_PAY);
+        Employee.Title title = Employee.Title.values()[rand.nextInt(Employee.Title.values().length)];
+        return new Employee(id, birthday, gender, pay, title);
+    }
+
+    private Employee createEmployee()  {
+        return this.createEmployee(StringUtilities.randomNumeric(Employee.ID_LENGTH));
+    }
+
+    @Override
+    protected Object[] validArrayGeneratorAndDesc() {
+        return new Object[]{
+            new IntFunction[]{(IntFunction)Employee[]::new, (IntFunction)Object[]::new},
+            "{Employee[]::new, Object[]::new}"
+        };
+    }
+
+    @Override
+    protected Object[][] invalidArrayGeneratorAndDesc() {
+        return new Object[][]{
+            {(IntFunction)Employee.Rule[]::new, "Employee.Rule[]::new"},
+            {(IntFunction)String[]::new, "String[]::new"},
+        };
+    }
+
+    @Override
+    protected IntFunction<Employee> createFunction() {
+        return i -> createEmployee(String.valueOf(i));
+    }
+
+    @Override
+    protected ToIntFunction<Employee> intValueFunction() {
+        return  e -> Integer.parseInt(e.getId()) ;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/stream/Stream/GenericStreamTest.java	Wed Aug 14 15:53:13 2013 -0700
@@ -0,0 +1,854 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.util.*;
+import java.util.concurrent.*;
+import java.util.function.BiFunction;
+import java.util.function.BinaryOperator;
+import java.util.function.Function;
+import java.util.function.IntFunction;
+import java.util.function.Predicate;
+import java.util.function.ToIntFunction;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+import java.util.stream.Stream;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+import org.testng.ITest;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+public abstract class GenericStreamTest<U, V extends Collection<U>> implements ITest{
+    protected enum ParallelType { Parallel, Sequential, Default }
+
+    protected enum Selection { EMPTY, SINGLE, TRIANGLE, COPY_64}
+
+    //Test data size
+    protected final static int VERY_SMALL_DATA_SIZE = 1;
+    
+    protected final static int SMALL_DATA_SIZE = 1 << 2;
+
+    //MIN_PARTITION
+    protected final static int PARTITION_DATA_SIZE = 1 << 4;
+    
+    protected final static int MEDIUM_DATA_SIZE = 1 << 7;
+    
+    protected final static int SIXTY_FOUR = 64;
+    
+    protected final static int DEFAULT_INIT_SIZE = -1;
+    
+    protected final static Random rand = new Random(433494437);
+
+    private final static Class[] defaultConstructorClazz = {
+        ArrayDeque.class,
+        ArrayList.class,
+        ConcurrentLinkedDeque.class,
+        ConcurrentLinkedQueue.class,
+        CopyOnWriteArrayList.class,
+        HashSet.class,
+        LinkedBlockingDeque.class,
+        LinkedBlockingQueue.class,
+        LinkedHashSet.class,
+        LinkedList.class,
+        LinkedTransferQueue.class,
+        Stack.class,
+        Vector.class
+    };
+
+    private final static Class[] capacityConstructorClazz = {
+        ArrayBlockingQueue.class,
+        ArrayDeque.class,
+        ArrayList.class,
+        HashSet.class,
+        LinkedBlockingDeque.class,
+        LinkedBlockingQueue.class,
+        LinkedHashSet.class,
+        Vector.class
+    };
+
+    private final static Class[] defaultComparableConstructorClazz = {
+        //Sorted collection only supports Comparable data type    
+        PriorityBlockingQueue.class,
+        PriorityQueue.class,
+        ConcurrentSkipListSet.class,
+        TreeSet.class,
+    };
+
+    private final static Class[] capacityComparableConstructorClazz = {
+        //Sorted collection only supports Comparable data type
+        PriorityBlockingQueue.class,
+        PriorityQueue.class,
+    };
+
+    protected final Class<V> typeObject;
+
+    private final int initSize;
+
+    protected final ParallelType parallelType;
+    
+    protected final Comparator<U> naturalOrderComparator;
+
+    protected Stream<U> streamFor(Collection<U> c1) {
+        return (parallelType == ParallelType.Parallel) ? 
+                c1.parallelStream(): (parallelType == ParallelType.Sequential)
+                ? c1.parallelStream().sequential() : c1.stream();
+    }
+    protected Collection<U> createEmptyCollection() {
+        try {
+            Collection<U> emptyCol = (initSize == DEFAULT_INIT_SIZE) ? LambdaUtilities.create(typeObject) : 
+                                    LambdaUtilities.create(typeObject, initSize);
+            return emptyCol;
+        } catch ( ReflectiveOperationException roe) {
+            throw new RuntimeException(roe);
+        }
+    }
+
+    @FunctionalInterface
+    public interface TripleFunction<L, M, N, I> { 
+        public I apply(L l, M m, N n);
+    }
+
+    public static Object[] create(TripleFunction<Class, ParallelType, Integer,? extends GenericStreamTest>
+            testCreatorWithInitSize, BiFunction<Class, ParallelType, ? extends GenericStreamTest> testCreator,boolean comparable) {
+        List<GenericStreamTest> result = new ArrayList<>();
+
+        for(final ParallelType parallelType : ParallelType.values()) {
+            Arrays.stream(defaultConstructorClazz).forEach(
+                clazz ->  { result.add(testCreator.apply(clazz, parallelType)); }
+            ); 
+            if(comparable)
+              Arrays.stream(defaultComparableConstructorClazz).forEach(
+                    clazz -> result.add(testCreator.apply(clazz, parallelType)));
+
+            Arrays.stream(capacityConstructorClazz).forEach(
+                clazz -> { result.add(testCreatorWithInitSize.apply(clazz, parallelType, MEDIUM_DATA_SIZE)); }
+            );
+            if(comparable)
+              Arrays.stream(capacityComparableConstructorClazz).forEach(
+                    clazz -> result.add(testCreatorWithInitSize.apply(clazz, parallelType, MEDIUM_DATA_SIZE)));
+        }
+        return result.toArray();
+    }
+
+    protected GenericStreamTest(Class<V> clazz, ParallelType parallelType,
+            Comparator<U> naturalOrderComparator, int initSize) {
+        this.typeObject = clazz;
+        this.parallelType = parallelType;
+        this.naturalOrderComparator = naturalOrderComparator;
+        this.initSize = initSize;
+    }
+    
+    protected GenericStreamTest(Class<V> clazz, ParallelType parallelType,
+            Comparator<U> naturalOrderComparator) {
+        this(clazz, parallelType, naturalOrderComparator, DEFAULT_INIT_SIZE);
+    }
+
+    protected static <T> void assertEqualContents(Collection<T> result1,
+            Collection<T> result2, Comparator<T> comparator) {
+        assertEquals(result1.size(), result2.size());
+        ArrayList<T> a = new ArrayList<>(result1);
+        ArrayList<T> b = new ArrayList<>(result2);
+        Collections.sort(a, comparator);
+        Collections.sort(b, comparator);
+
+        for(int i = 0; i < result1.size(); i++)
+            assertEquals(comparator.compare(a.get(i), b.get(i)), 0);
+    }
+
+    private U getMaxOrMinWithIterator(Collection<U> col, Comparator<U> c, boolean isMax) {
+        assert(!col.isEmpty());
+        Iterator<U> it = col.iterator();
+        U choosen = it.next();
+        while(it.hasNext()) {
+            U next = it.next();
+            if (!(c.compare(choosen, next) < 0 ^ isMax)) choosen = next;
+        }
+        return choosen;
+    }
+
+    private U getMaxOrMinByCollectorBy(Collection<U> col, Comparator<U> c, boolean isMax) {
+        assert(!col.isEmpty());
+        U choosen = isMax ? streamFor(col).collect(Collectors.<U>maxBy(c)).get() :
+                streamFor(col).collect(Collectors.<U>minBy(c)).get();
+        return choosen;
+    }
+    
+    private U getMaxOrMinByReduce(Collection<U> col, Comparator<U> c, boolean isMax) {
+        assert (!col.isEmpty());
+        Optional<U> choosen = col.stream().reduce(isMax ? 
+                LambdaUtilities.maxGenericBinaryOperator(c) :
+                LambdaUtilities.minGenericBinaryOperator(c) );
+        assert(choosen.isPresent());
+        return choosen.get();
+    }
+
+    private U getMaxOrMinReduceWithBase(Collection<U> col, Comparator<U> c, boolean isMax) {
+        assert (!col.isEmpty());
+        U any = col.iterator().next();
+        U choosen = col.stream().reduce(any, 
+                isMax ? LambdaUtilities.maxGenericFunction(c) : LambdaUtilities.minGenericFunction(c),
+                isMax ? LambdaUtilities.maxGenericBinaryOperator(c) : LambdaUtilities.minGenericBinaryOperator(c));
+        return choosen;
+    }
+
+    private U getMaxOrMinCollectWithReducing(Collection<U> col, Comparator<U> c, boolean isMax) {
+        assert (!col.isEmpty());
+        U choosen = col.stream().collect(Collectors.<U>reducing(isMax ? 
+                LambdaUtilities.maxGenericBinaryOperator(c) :
+                LambdaUtilities.minGenericBinaryOperator(c))).get();
+        return choosen;
+    }
+
+    private void verifySlice(Collection<U> col, Collection<U> subL, int skip, int limit, boolean ordered) {
+        int toIndex = skip + limit < col.size() ? skip + limit : col.size();
+        if (ordered) {
+            assertEquals(new ArrayList(col).subList(skip, toIndex), subL);
+        } else {
+            // Unordered: verify that all items from the slice are
+            // present in the original collection
+            assertTrue(col.containsAll(subL));
+            assertEquals(subL.size(), toIndex - skip); 
+        }
+    }
+
+    private Function<U, Stream<U>> genFlatMapper(Selection selection) {
+        switch(selection) {
+            case EMPTY: return e -> Stream.empty();
+            case SINGLE: return e -> Collections.singletonList(e).stream();
+            case TRIANGLE:  
+                return e ->  triangleStream(e);
+            case COPY_64:
+            default:
+                return e ->  Stream.generate(() -> e).limit(SIXTY_FOUR);
+        }
+    } 
+    private void verifyFlatMap(Collection<U> orig, Collection<U> result, Selection selection) {
+        switch (selection) {
+        case EMPTY:
+            assertEquals(result.size(), 0);
+            break;
+        case SINGLE:
+            assertEqualContents(new ArrayList<>(orig), result, naturalOrderComparator);
+            break;
+        case TRIANGLE:
+            List<U> list2 = new ArrayList<>();
+            orig.stream().forEach((current) -> {
+                triangleStream(current).forEach(u -> list2.add(u));
+            });
+            assertEqualContents(list2, result, naturalOrderComparator);
+            break;
+        case COPY_64:
+        default:
+            List<U> list3 = new ArrayList<>();
+            orig.stream().forEach((current) -> {
+                IntStream.range(0, SIXTY_FOUR).forEach(i -> list3.add(current));
+            });
+            assertEquals(list3, result);
+            break;
+        }
+    }
+
+    private boolean verifyMatch(Collection<U> col, Predicate<U> predicate, boolean checkAll) {
+        for(U current : col) {
+            if (checkAll ^ predicate.test(current) )
+                    return !checkAll;
+        }
+        return checkAll;
+    }
+
+    private void verifyAfterMap(Collection<U> origCol, Object[] result, Function<U, ? extends Object> mapFunc) {
+        int index = 0;
+        assertEquals(origCol.size(), result.length);
+        for(U element : origCol) 
+            assertEquals(mapFunc.apply(element), result[index++]);
+    }
+
+    protected abstract  Collection<U> generate(int size);
+    
+    //Predicate<U>, descrption for Predicate<U>
+    protected abstract  Object[] predicateAndDesc(int size);
+    
+    //BinaryOperator<U>, descrption for BinaryOperator<U>, stateless
+    protected abstract  Object[][] binaryOperatorAndDesc();
+
+    //Function<U, ? extends Comparable>, descrption for Function<? extends Comparable>
+    protected abstract  Object[][] functionAndDesc();
+    
+    //IntFunction<W>[], descrption for all IntFunction<W>
+    protected abstract  Object[] validArrayGeneratorAndDesc();
+    
+    //IntFunction<W>[], descrption for IntFunction<W>
+    protected abstract  Object[][] invalidArrayGeneratorAndDesc();
+
+    //IntFunction<U>
+    protected abstract IntFunction<U> createFunction();
+ 
+    //ToIntFunction<U>
+    protected abstract ToIntFunction<U> intValueFunction();
+
+    //base object based on size
+    protected abstract U[] bases(int size);
+
+    protected Object[] builders() {
+        return new Object[]{
+            generate(MEDIUM_DATA_SIZE),
+            generate(SMALL_DATA_SIZE),
+            generate(PARTITION_DATA_SIZE),
+            generate(VERY_SMALL_DATA_SIZE)
+        };
+    }
+
+    protected Object[] smallSizeBuilders() {
+        return new Object[]{
+            generate(SMALL_DATA_SIZE),
+            generate(PARTITION_DATA_SIZE),
+            generate(VERY_SMALL_DATA_SIZE)
+        };
+    }
+
+    //Test only needs Collection<U>
+    @DataProvider
+    protected Iterator<Object[]> collectionData() {    
+        return Arrays.stream(builders()).map(data ->
+                new Object[]{String.format("%s(%d)", typeObject.getName(), ((Collection<U>)data).size()),data}).iterator();
+    }
+    
+    //Test only needs Collection<U>
+    @DataProvider
+    protected Iterator<Object[]> collectionStartEndData() {
+        List<Object[]> dataList= new ArrayList<>();
+        long[][] exceptionStartEnd = new long[][]{
+            {-1, 1},   //startInclusive is negative
+            {1, -1},   //endInclusive is negative
+            {1, 0}    //startInclusive is greater than endExclusive
+        };
+       Arrays.stream(builders()).forEach(data -> {
+           Collection<U> col = (Collection<U>)data;
+           Arrays.stream(exceptionStartEnd).forEach(startEnd -> {
+               dataList.add(new Object[]{String.format("%s(%d), %d, %d", typeObject.getName(), col.size(), startEnd[0], 
+                       startEnd[1]), col, startEnd[0], startEnd[1]});
+           });
+       });    
+       return dataList.iterator();
+    }
+
+    //Test needs Collection<U> and one Predicate
+    @DataProvider
+    protected Iterator<Object[]> collectionPredicateData() {
+        List<Object[]> dataList= new ArrayList<>();
+        Arrays.stream(builders()).forEach(data -> {
+            Collection<U> col = (Collection<U>)data;
+            Object[] predicateAndDesc = predicateAndDesc(col.size());
+            Predicate<U> p = (Predicate<U>)predicateAndDesc[0];
+            String desc = String.format("%s(%d), %s", typeObject.getName(), col.size(), (String)predicateAndDesc[1]);
+            dataList.add(new Object[]{desc, data, p});
+        });
+        return dataList.iterator();
+    }
+    
+    //Test needs Collection<U> and two Predicate
+    @DataProvider
+    protected Iterator<Object[]> collectionDualPredicateData() {
+        List<Object[]> dataList = new ArrayList<>();
+        Arrays.stream(builders()).forEach(data -> {
+            Collection<U> col = (Collection<U>)data;
+            Object[] predicateAndDesc1 = predicateAndDesc(col.size());
+            Object[] predicateAndDesc2 = predicateAndDesc(col.size());
+            Predicate<U> p1 = (Predicate<U>)predicateAndDesc1[0];
+            Predicate<U> p2 = (Predicate<U>)predicateAndDesc2[0];
+            String desc = String.format("%s(%d), %s, %s", typeObject.getName(), col.size(), 
+                    (String)predicateAndDesc1[1], (String)predicateAndDesc2[1]);
+            dataList.add(new Object[]{desc, col, p1, p2});
+        });
+        return dataList.iterator();
+    }
+    
+    //Test needs Collection<U>, U base and and BinaryOperator<U>, stateless
+    @DataProvider
+    protected Iterator<Object[]> collectionBinaryOpeatorData(){
+        List<Object[]> dataList = new ArrayList<>();
+        Arrays.stream(builders()).forEach(data -> {
+            Collection<U> col = (Collection<U>)data;
+            Arrays.stream(binaryOperatorAndDesc()).forEach((Object[] bpDesc) -> {
+                BinaryOperator<U> bo = (BinaryOperator<U>)bpDesc[0];
+                String boDesc = (String)bpDesc[1];
+                boolean stateless =  (Boolean)bpDesc[2];
+                Arrays.stream(bases(col.size())).forEach(base -> {
+                    dataList.add(new Object[]{String.format("%s(%d), %s, %s, %s", typeObject.getName(), col.size(), base, 
+                            boDesc, stateless), col, base, bo, stateless});
+                });
+            });
+        });
+        return dataList.iterator();
+    }
+    
+    //Test needs Collection<U>, Function<U, ? extends Object>
+    @DataProvider
+    protected Iterator<Object[]> collectionFunctionData(){
+         List<Object[]> dataList = new ArrayList<>();
+        Arrays.stream(builders()).forEach(data -> {
+            Collection<Integer> col = (Collection<Integer>)data;
+            Arrays.stream(functionAndDesc()).forEach((Object[] funcDesc) -> {
+                Function<U, Object> func = (Function<U, Object>)funcDesc[0];
+                String desc = (String)funcDesc[1];
+                dataList.add(new Object[]{String.format("%s(%d), %s", typeObject.getName(), col.size(), desc),
+                    col, func});
+            });
+        });
+        return dataList.iterator();
+    }
+    
+    //Test needs Collection<U>, Function<U, K> keyFunc, Function<U, V> valueFunc
+    //toMap need keep key's identical, using Function.identity()
+    @DataProvider
+    protected Iterator<Object[]> collectionKeyValueFunctionData(){
+         List<Object[]> dataList = new ArrayList<>();
+        Arrays.stream(builders()).forEach(data -> {
+            Collection<Integer> col = (Collection<Integer>)data;
+            Arrays.stream(functionAndDesc()).forEach((Object[] valueFuncDesc) -> {
+                Function<U, Object> valueFunc = (Function<U, Object>)valueFuncDesc[0];
+                String valuedesc = (String)valueFuncDesc[1];
+                dataList.add(new Object[]{String.format("%s(%d), %s, %s", typeObject.getName(), col.size(), 
+                        "Function.identity()", valuedesc), col, Function.identity(), valueFunc});
+            });
+        });
+        return dataList.iterator();
+    }
+    
+    //testToArray needs Collection<U>, IntFunction<W>[] 
+    @DataProvider
+    protected Iterator<Object[]> collectionArrayGeneratorData(){
+         List<Object[]> dataList = new ArrayList<>();
+        Arrays.stream(builders()).forEach(data -> {
+            Collection<Integer> col = (Collection<Integer>)data;
+            Object[] validArrayGenerators =  validArrayGeneratorAndDesc();
+            IntFunction[] generators = (IntFunction[])validArrayGenerators[0];
+            String desc = (String)validArrayGenerators[1];
+            dataList.add(new Object[]{String.format("%s(%d), %s", typeObject.getName(), col.size(), desc), col, generators});
+        });
+        return dataList.iterator();
+    }
+    
+    //testToArrayException needs Collection<U>, IntFunction<W>, 
+    //This for test toArray's ArrayStoreException
+    @DataProvider
+    protected Iterator<Object[]> collectionArrayInvalidGeneratorData(){
+         List<Object[]> dataList = new ArrayList<>();
+        Arrays.stream(builders()).forEach(data -> {
+            Collection<Integer> col = (Collection<Integer>)data;
+            Arrays.stream(invalidArrayGeneratorAndDesc()).forEach(invalidArrayGenerators -> {
+                IntFunction generator = (IntFunction)invalidArrayGenerators[0];
+                String desc = (String)invalidArrayGenerators[1];
+                dataList.add(new Object[]{String.format("%s(%d), %s", typeObject.getName(), col.size(), desc), col, generator});
+            });
+        });
+        return dataList.iterator();
+    }
+    
+    //Test needs Collection<U>, Collection<U>
+   @DataProvider
+    protected Iterator<Object[]> concatCollectionData(){
+        List<Object[]> dataList = new ArrayList<>();
+        Arrays.stream(builders()).forEach(data1 ->
+                Arrays.stream(builders()).forEach(data2 -> {
+                    String desc = String.format("%s(%d), %s(%d)", typeObject.getName(), ((Collection<U>)data1).size(), 
+                            typeObject.getName(), ((Collection<U>)data2).size());
+                    dataList.add(new Object[]{desc, data1, data2}); }
+                )
+         );
+        return dataList.iterator();
+    }
+   
+    @DataProvider
+    protected Iterator<Object[]>  exceptionTestData()  throws Exception {
+        Collection<U> col = generate(SMALL_DATA_SIZE);
+        return Arrays.stream(new Object[][]{
+            {String.format("%s(%d)", typeObject.getName(), col.size()), col},
+        }).iterator();
+    }
+
+    @DataProvider
+    protected Iterator<Object[]> smallSizeCollectionData() {
+        List<Object[]> dataList = new ArrayList<>();
+        Arrays.stream(smallSizeBuilders()).forEach(data -> {
+            Collection<U> col = (Collection<U>)data;
+            dataList.add(new Object[]{String.format("%s(%d)", typeObject.getName(), col.size()), col});
+        });
+        return dataList.iterator();
+    }
+    
+    @DataProvider
+    protected Iterator<Object[]> collectionDataWithLimit() {
+        List<Object[]> dataList = new ArrayList<>();
+        Arrays.stream(builders()).forEach(dataCol -> { 
+            Collection<U> col = (Collection<U>)dataCol;
+            int withBoundryLimit = rand.nextInt(col.size());
+            int beyondBoundryLimit = col.size() + rand.nextInt(Integer.MAX_VALUE - col.size());
+            dataList.add(new Object[]{String.format("%s(%d), %s", typeObject.getName(), col.size(), withBoundryLimit, 
+                    beyondBoundryLimit), col, withBoundryLimit, beyondBoundryLimit}); 
+        });
+        return dataList.iterator();
+    }
+
+    @DataProvider
+    protected Iterator<Object[]> collectionDataWithSelection() {
+        List<Object[]> dataList = new ArrayList<>();
+        Arrays.stream(smallSizeBuilders()).forEach(data -> {
+            Collection<U> col = (Collection<U>)data;
+            Arrays.stream(Selection.values()).forEach(selection -> {
+                dataList.add(new Object[]{String.format("%s(%d), %s", typeObject.getName(), col.size(), selection),
+                col, selection});  
+            }); 
+        });
+        return dataList.iterator();
+    }
+
+    @Test(dataProvider="collectionFunctionData")
+    public void testCollectByGroupingBy(String desc, Collection<U> col, Function<U, ? extends Object> mapFunc) {
+        Map<Object, List<U>> result = streamFor(col). collect(Collectors.<U, Object>groupingBy(mapFunc));
+        result.keySet().stream().forEach((key) -> {
+            result.get(key).stream().forEach((u) -> {
+                assertEquals(key, mapFunc.apply(u));
+            });
+        });
+        assertTrue(streamFor(createEmptyCollection()).collect(Collectors.<U, Object>groupingBy(mapFunc)).isEmpty());
+    }
+    
+    @Test(dataProvider="collectionPredicateData")
+    public void testCollectByPartition(String desc, Collection<U> col, Predicate<U> mapFunc) {
+        Map<Boolean, List<U>> result = streamFor(col). collect(Collectors.<U>partitioningBy(mapFunc));
+        for(boolean key : result.keySet()) {
+            result.get(key).stream().forEach((u) -> {
+                assertEquals(mapFunc.test(u), key);
+            });
+        }
+        assertTrue(streamFor(createEmptyCollection()).collect(Collectors.<U>partitioningBy(mapFunc)).get(true).isEmpty());
+        assertTrue(streamFor(createEmptyCollection()).collect(Collectors.<U>partitioningBy(mapFunc)).get(false).isEmpty());
+    }
+
+    @Test(dataProvider="collectionKeyValueFunctionData")
+    public <K, V> void testCollectToMap(String desc, Collection<U> col, Function<U, K> keyFunc, Function<U, V> valueFunc) {
+        Map<K, V> keyToValue = streamFor(col).collect(Collectors.<U, K, V>toMap(keyFunc, valueFunc));
+        assertEquals(keyToValue.size(), streamFor(col).map(keyFunc).distinct().count());
+        col.stream().forEach((u) -> {
+            assertEquals(valueFunc.apply(u), keyToValue.get(keyFunc.apply(u)));
+        });
+    }
+
+    @Test(dataProvider="collectionData")
+    public void testFind(String desc, Collection<U> col) throws Exception{
+        Stream<U> stream = streamFor(col);
+        Optional<U> opAny = stream.findAny();
+        Optional<U> opFirst = streamFor(col).findFirst();
+        if(!stream.isParallel())
+            assertEquals(opAny, opFirst);
+        assertTrue(opAny.isPresent());
+        assertTrue(opFirst.isPresent());
+
+        assertFalse(streamFor(createEmptyCollection()).findAny().isPresent());
+        assertFalse(streamFor(createEmptyCollection()).findFirst().isPresent());
+    }
+       
+    @Test(dataProvider="collectionPredicateData")
+    public void testXxxMatch(String desc, Collection<U> col, Predicate<U> predicate) throws Exception {
+        assertEquals(streamFor(col).allMatch(predicate),
+                verifyMatch(col, predicate, true));
+        assertEquals(streamFor(col).anyMatch(predicate),
+                verifyMatch(col, predicate, false));
+        assertEquals(streamFor(col).noneMatch(predicate),
+                verifyMatch(col, predicate.negate(), true)); 
+
+        assertTrue(streamFor(createEmptyCollection()).allMatch(predicate));
+        assertFalse(streamFor(createEmptyCollection()).anyMatch(predicate));
+        assertTrue(streamFor(createEmptyCollection()).noneMatch(predicate));
+    }
+  
+    @Test(dataProvider="concatCollectionData")
+    public void testConcat(String desc, Collection<U> tobeConcated, Collection<U> concat) throws Exception {
+        //We're using List to store expected result because Set could merge object, 
+        Collection<U> expected = new ArrayList<>(tobeConcated);
+        expected.addAll(concat);
+
+        //test concat with parallel/non-parallel Stream
+        for(ParallelType concatType : ParallelType.values()) {
+            Stream<U> concatStream = (concatType == ParallelType.Parallel) ? 
+                concat.parallelStream(): (concatType == ParallelType.Sequential)
+                ? concat.parallelStream().sequential() : concat.stream();
+            List<U> calculated = Stream.concat(streamFor(tobeConcated), concatStream)
+                    .collect(Collectors.<U>toList());
+            assertEqualContents(calculated, expected, naturalOrderComparator);
+        }
+
+        List<U> result3 = Stream.concat(tobeConcated.stream(), streamFor(createEmptyCollection()))
+                .collect(Collectors.<U>toList());
+        List<U> result4 = Stream.concat(tobeConcated.stream(), Stream.empty())
+                .collect(Collectors.<U>toList());
+        assertEqualContents(tobeConcated, result3, naturalOrderComparator);
+        assertEqualContents(tobeConcated, result4, naturalOrderComparator);
+    }
+
+    @Test(dataProvider="collectionData")
+    public void testCount(String desc, Collection<U> col) throws Exception{
+        assertEquals(streamFor(col).count(), col.size());
+        assertEquals(streamFor(col).count(), streamFor(col).mapToLong(u -> 1).sum());
+        assertEquals(streamFor(createEmptyCollection()).count(), 0);
+    }
+
+    @Test(dataProvider="collectionDualPredicateData")
+    public void testFilter(String desc, Collection<U> col, Predicate<U> p1, Predicate<U> p2) throws Exception {
+        //Filter the data, check if it works as expected.
+        Collection<U> filteredColByP1 = streamFor(col).filter(p1)
+                .collect(Collectors.<U, List<U>>toCollection(LinkedList::new));
+        assertTrue(verifyMatch(filteredColByP1, p1, true));
+
+        //filter on parallel stream can cause IllegalStateException
+        Collection<U>  filteredColByAlwaysTrue = streamFor(col).filter(p1).filter(e -> true)
+                .collect(Collectors.<U, List<U>>toCollection(LinkedList::new));
+        assertTrue(verifyMatch(filteredColByAlwaysTrue, p1, true));
+
+        //filter with false will get nothing
+        Collection<U>  filteredColByAlwaysFalse = streamFor(col).filter(p1).filter(e -> false)
+                .collect(Collectors.<U, List<U>>toCollection(LinkedList::new));
+        assertTrue(filteredColByAlwaysFalse.isEmpty());
+
+        //The reason conver l to sorted is CopyOnWriteArrayList doesn't support
+        //sort, we use ArrayList sort data instead
+        Collection<U> filteredColByP2AfterP1 = streamFor(col).filter(p1).filter(p2)
+                .collect(Collectors.<U, List<U>>toCollection(ArrayList::new));
+
+        List<U> filteredColByrP1AndP2 = streamFor(col).filter(p1.and(p2))
+                .collect(Collectors.<U, List<U>>toCollection(ArrayList::new));
+        assertEqualContents(filteredColByP2AfterP1, filteredColByrP1AndP2, naturalOrderComparator);
+
+        List<U> filteredColByrP1OrP2 = streamFor(col).filter(p1.or(p2))
+                .collect(Collectors.<U, List<U>>toCollection(ArrayList::new));
+
+        List<U> filteredExpected = new ArrayList<>(filteredColByrP1AndP2);
+        filteredExpected.addAll(filteredColByrP1OrP2);
+
+        //concat stream.filter(p1) with stream.filter(p2) should be same as stream.filter(p1 && p2) combine with 
+        //stream.filter(p1 || p2) 
+        List<U> filteredColByP1CancatfilteredColByP2 = Stream.concat(streamFor(col).filter(p1), streamFor(col).filter(p2))
+                .collect(Collectors.<U, List<U>>toCollection(ArrayList::new));
+        assertEqualContents(filteredColByP1CancatfilteredColByP2, filteredExpected, naturalOrderComparator);
+
+        assertEquals(streamFor(createEmptyCollection()).filter(p1).count(), 0); 
+    }
+
+    @Test(dataProvider="collectionData")
+    public void testForEach(String desc, Collection<U> col) throws Exception{
+        List<U> expected= new ArrayList<>(col);
+        //Unordered streams could play parallel executions, which we need a 
+        //thread-safe queue to check the data  
+        ConcurrentLinkedQueue<U> forEachQueue = new ConcurrentLinkedQueue<>();
+        streamFor(col).forEach(forEachQueue::add);
+        assertEqualContents(forEachQueue, expected, naturalOrderComparator);
+
+        List<U> forEachOrderedList = new ArrayList<>();
+        streamFor(col).forEachOrdered(forEachOrderedList::add); 
+        assertEquals(forEachOrderedList, expected);
+        
+        List<U> expectedEmpty = new ArrayList<>();
+        streamFor(createEmptyCollection()).forEach(expectedEmpty::add);
+        assertTrue(expectedEmpty.isEmpty());
+    }
+
+    @Test(dataProvider="collectionDataWithLimit")
+    public void testLimit(String desc, Collection<U> col, int withBoundryLimit, int beyondBoundryLimit) {
+        Collection<U> resultWithBoundary = streamFor(col).limit(withBoundryLimit)
+                .collect(Collectors.<U,List<U>>toCollection(LinkedList::new));
+        assertEquals(resultWithBoundary.size(), withBoundryLimit);
+
+        Collection<U> resultBeyondBoundary = streamFor(col).limit(beyondBoundryLimit)
+                .collect(Collectors.<U,List<U>>toCollection(LinkedList::new));
+        assertEquals(resultBeyondBoundary.size(), resultBeyondBoundary.size());
+
+        assertEquals(streamFor(createEmptyCollection()).limit(withBoundryLimit).count(), 0);
+        assertEquals(streamFor(createEmptyCollection()).limit(beyondBoundryLimit).count(), 0);
+    }
+    
+    @Test(dataProvider="exceptionTestData",expectedExceptions = IllegalArgumentException.class)
+    public void testLimitException(String desc, Collection<U> col){
+        streamFor(col).limit(-1).toArray();
+    }
+
+    @Test(dataProvider="collectionDataWithSelection")
+    public void testFlatMap(String desc, Collection<U> col, Selection selection) {
+        List<U> result = streamFor(col)
+                .flatMap(genFlatMapper(selection))
+                .collect(Collectors.<U>toList());
+        verifyFlatMap(col, result, selection);
+        
+        assertEquals(streamFor(createEmptyCollection()).flatMap(genFlatMapper(selection)).count(), 0);
+    }
+
+    @Test(dataProvider="collectionFunctionData")
+    public void testMaxAndMin(String desc, Collection<U> col, Function<U, ? extends Comparable> mapFunc) {
+        Comparator<U> comp = Comparator.comparing(mapFunc);
+        Optional<U> optionaMax = streamFor(col).max(comp) ;
+        Optional<U> optionaMin = streamFor(col).min(comp) ;
+        assertTrue(optionaMax.isPresent());
+        assertTrue(optionaMin.isPresent());
+
+        assertEquals(comp.compare(optionaMax.get(), getMaxOrMinWithIterator(col, comp, true)), 0);
+        assertEquals(comp.compare(optionaMin.get(), getMaxOrMinWithIterator(col, comp, false)), 0);
+        
+        assertEquals(comp.compare(optionaMax.get(), getMaxOrMinByCollectorBy(col, comp, true)), 0);
+        assertEquals(comp.compare(optionaMin.get(), getMaxOrMinWithIterator(col, comp, false)), 0);
+
+        assertEquals(comp.compare(optionaMax.get(), getMaxOrMinByReduce(col, comp, true)), 0);
+        assertEquals(comp.compare(optionaMin.get(), getMaxOrMinByReduce(col, comp, false)), 0);
+
+        assertEquals(comp.compare(optionaMax.get(), getMaxOrMinReduceWithBase(col, comp, true)), 0);
+        assertEquals(comp.compare(optionaMin.get(), getMaxOrMinReduceWithBase(col, comp, false)), 0);
+
+        assertEquals(comp.compare(optionaMax.get(), getMaxOrMinCollectWithReducing(col, comp, true)), 0);
+        assertEquals(comp.compare(optionaMin.get(), getMaxOrMinCollectWithReducing(col, comp, false)), 0);
+
+        assertFalse(streamFor(createEmptyCollection()).max(comp).isPresent());
+        assertFalse(streamFor(createEmptyCollection()).max(comp).isPresent());
+    }
+   
+    @Test(dataProvider="collectionBinaryOpeatorData")
+    public void testReduce(String desc, Collection<U> col, U base, BinaryOperator<U> op, boolean stateless)  {
+        Optional<U> reduceResult = streamFor(col).reduce( op);
+        assertTrue(reduceResult.isPresent());
+        Iterator<U> iter = col.iterator();
+        U expected = iter.next();
+        while(iter.hasNext())
+            expected = op.apply(expected, iter.next());
+        assertEquals(reduceResult.get(), expected);
+
+        assertEquals(streamFor(createEmptyCollection()).reduce(base,op), base);
+        assertFalse(streamFor(createEmptyCollection()).reduce(op).isPresent());
+
+        if(stateless || !streamFor(col).isParallel()) {
+            U reduceWithBaseResult = streamFor(col).reduce(base, op);
+            U expectedWithBase = base;
+            for(U aCol : col)
+                expectedWithBase = op.apply(expectedWithBase, aCol);
+            assertEquals(reduceWithBaseResult, expectedWithBase);
+        }
+    }
+            
+    @Test(dataProvider="collectionData")
+    public void testSubstream(String desc, Collection<U> col) {
+        BiFunction<Integer,Integer,Integer> bf = LambdaUtilities.randBetweenIntegerFunction();
+        int skip = rand.nextInt(col.size());
+        int limit1 = bf.apply(0, col.size() - skip);
+        Collection<U> sliceCol = streamFor(col).substream(skip, skip + limit1).
+                collect(Collectors.<U>toList());
+        verifySlice(col, sliceCol, skip, limit1, !col.getClass().equals(HashSet.class));
+
+        int limitExceeded = bf.apply(col.size() - skip, Integer.MAX_VALUE);
+        Collection<U> sliceCol2 = streamFor(col).substream(skip, skip + limitExceeded).
+                collect(Collectors.<U>toList());
+        //We couldn't predicate unordered collection exact behavior for substream, only check the length and if data
+        // exists in original collection
+        verifySlice(col, sliceCol2, skip, limitExceeded, !col.getClass().equals(HashSet.class));
+
+        assertEquals(streamFor(col).substream(skip, skip).count(), 0);
+
+        //skip exceed collection size cause empty stream
+        Stream<U> stream3 = streamFor(col);
+        int skipExceeded = bf.apply(col.size(), Integer.MAX_VALUE);
+        assertEquals(stream3.substream(skipExceeded, skipExceeded + 1).count(), 0);
+
+        assertEquals(streamFor(createEmptyCollection()).substream(skip, skip + limit1).count(), 0);
+    }
+    
+    @Test(dataProvider="collectionStartEndData",expectedExceptions = IllegalArgumentException.class)
+    public void  testSubstreamException(String desc, Collection<U> col, long startInclusive, long endExclusive){
+        streamFor(col).substream(startInclusive).count(); 
+        streamFor(col).substream(startInclusive, endExclusive).count();  
+    }
+
+    @Test(dataProvider="collectionFunctionData")
+    public void testSorted(String desc, Collection<U> col, Function<U, ? extends Comparable> mapFunc) {
+        // SortedSet instance's stream can't be reordered, we use ArrayList to do reorder
+        Comparator<U> comp = Comparator.comparing(mapFunc);
+        List<U> sorted = new ArrayList<>(col);
+        List<U> reversed = streamFor(col).sorted(comp).collect(Collectors.<U>toList());
+        Collections.sort(sorted, comp);
+        assertEquals(sorted, reversed);
+
+        assertEquals(streamFor(createEmptyCollection()).sorted(comp).count(), 0);
+    }
+
+    //Note non-Comparable U need override this method
+    @Test(dataProvider="collectionData")
+    public void testSortedSpecial(String desc, Collection<U> col) {
+        // SortedSet instance's stream can't be reordered, we use ArrayList to do reorder
+        List<U> sorted = new ArrayList<>(col);
+        List<U> reversed = streamFor(col).sorted().collect(Collectors.<U>toList());
+        Collections.sort(sorted, naturalOrderComparator);
+        assertEquals(sorted, reversed);
+
+        assertEquals(streamFor(createEmptyCollection()).sorted().count(), 0);
+    }
+
+    @Test(dataProvider="collectionFunctionData")
+    public void testPeek(String desc, Collection<U> col, Function<U, ? extends Object> mapFunc) {
+        //Note ArrayList is not a concurrent data type, if we don't set initial
+        //size, we could get AIOOBE
+        List<U> peekList = new ArrayList<>(col.size());
+        Object[] result = streamFor(col).peek(peekList::add).map(mapFunc).toArray();
+        verifyAfterMap(col, result, mapFunc);
+        
+        List<U> emptyList = new ArrayList<>();
+        assertEquals(streamFor(createEmptyCollection()).peek(emptyList::add).count(), 0);
+        assertTrue(emptyList.isEmpty());
+    }
+
+    @Test(dataProvider="collectionArrayGeneratorData")
+    public void testToArray(String desc, Collection<U> col, IntFunction[] generators) {
+        Object[] expectedArr = col.toArray();
+        assertEquals(streamFor(col).toArray(), expectedArr);
+        assertEquals(streamFor(createEmptyCollection()).toArray().length, 0);
+        
+         Arrays.stream(generators).forEach(generator -> {
+             assertEquals(streamFor(col).toArray(generator), expectedArr);
+             assertEquals(streamFor(createEmptyCollection()).toArray(generator).length, 0);
+         });
+    }
+    
+    @Test(dataProvider="collectionArrayInvalidGeneratorData",expectedExceptions = ArrayStoreException.class)
+    public void testToArrayException(String desc, Collection<U> col, IntFunction generator){
+        streamFor(col).toArray(generator);
+    }
+
+    @Test(dataProvider="smallSizeCollectionData")
+    public void testDistinct(String desc, Collection<U> col)  {
+        Set<U> set = new HashSet<>(col);
+        List<U> list = streamFor(col).flatMap(genFlatMapper(Selection.COPY_64)).distinct().collect(Collectors.<U>toList());
+        assertEqualContents(list, set, naturalOrderComparator); 
+        
+        assertEquals(streamFor(createEmptyCollection()).distinct().count(), 0);
+    }
+
+    private Stream<U> triangleStream(U u) {
+        int e = intValueFunction().applyAsInt(u);
+        return IntStream.range(0, e).mapToObj(i -> createFunction().apply(e * (e - 1) / 2 + i));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/stream/Stream/IntStreamTest.java	Wed Aug 14 15:53:13 2013 -0700
@@ -0,0 +1,497 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @summary Basic test for IntStream
+ * @library /sqeutil
+ * @(#) IntStreamTest.java
+ * @author Tristan Yan
+ * @run testng IntStreamTest
+ */
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.OptionalInt;
+import java.util.Random;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.IntFunction;
+import java.util.function.IntPredicate;
+import java.util.function.IntUnaryOperator;
+import java.util.stream.IntStream;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Factory;
+import org.testng.annotations.Test;
+
+public class IntStreamTest {    
+    private final static int[] ARRAY_SIZES = {1, 1 << 2, 1 << 4, 1 << 7, 1 << 12};
+
+    protected enum Selection { EMPTY, SINGLE, TRIANGLE, COPY_64};
+    
+    private final static int[] EMPTY_ARRAY = new int[0];
+
+    private IntStream streamFor(ParallelType p, int[] array) {
+        return (p == ParallelType.Parallel) ? Arrays.stream(array).parallel()
+                : (p == ParallelType.Sequential) ? Arrays.stream(array).sequential() : Arrays.stream(array);
+    }
+
+    private IntStream streamFor(ParallelType p, int[] array, int startIndex, int endIndex) {
+        return (p == ParallelType.Parallel) ? Arrays.stream(array, startIndex, endIndex).parallel()
+                : (p == ParallelType.Sequential) ? Arrays.stream(array, startIndex, endIndex).sequential() :
+                Arrays.stream(array, startIndex, endIndex);
+    }
+
+    static enum ParallelType { Parallel, Sequential, Default }
+
+    private final static Random rand = new Random(1968721);
+
+    private boolean verifyMatch(int[] array, IntPredicate predicate, boolean checkAll) {
+        for(int element : array) {
+            if(predicate.test(element) != checkAll) 
+                return !checkAll;
+        }
+        return checkAll;
+    }
+    
+    private final ParallelType parallelType;
+    
+    private IntStreamTest(final ParallelType parallelType) {
+        this.parallelType = parallelType;
+    }
+
+    @Factory
+    public static Object[] create(){
+        return Arrays.stream(ParallelType.values()).map(p -> new IntStreamTest(p)).toArray();
+    }
+
+    final static Object[][] arrays = Arrays.stream(ARRAY_SIZES).mapToObj(size -> 
+            new Object[]{IntStream.range(0, size).toArray()}).toArray(Object[][]::new);
+    
+    @DataProvider
+    public static Iterator<Object[]> intArrays(){
+        ArrayList<Object[]> list = new ArrayList<>();
+        String format = "<int[%d]>";
+        Arrays.stream(arrays).forEach(data -> {
+            int[] array = (int[])data[0];
+            list.add(new Object[]{String.format(format, array.length), array});
+        });
+        return list.iterator();
+    }
+
+    @DataProvider
+    public static Iterator<Object[]> intArraysWithSkipLimit(){
+        ArrayList<Object[]> list = new ArrayList<>();
+        String format = "<int[%d], %d, %d>";
+        Arrays.stream(arrays).forEach(data -> {
+            int[] array = (int[])data[0];
+            list.add(new Object[]{String.format(format, array.length, 0, array.length), array, 0, array.length}); 
+            list.add(new Object[]{String.format(format, array.length, array.length / 3, array.length /2), array,  array.length / 3, array.length /2});
+            list.add(new Object[]{String.format(format, array.length,  array.length /2, array.length + 1), array, array.length /2, array.length + 1});
+        });
+        return list.iterator();
+    }
+    
+    @DataProvider
+    public static Iterator<Object[]> intArraysWithLimit(){
+        ArrayList<Object[]> list = new ArrayList<>();
+        String format = "<int[%d], %d>";
+        Arrays.stream(arrays).forEach(data -> {
+            int[] array = (int[])data[0];
+            list.add(new Object[]{String.format(format, array.length, 0), array, 0}); 
+            list.add(new Object[]{String.format(format, array.length, array.length / 3), array, array.length / 3});
+            list.add(new Object[]{String.format(format, array.length, array.length /2), array, array.length /2});
+            list.add(new Object[]{String.format(format, array.length, array.length + 1), array, array.length + 1});
+        });
+        return list.iterator();
+    }
+
+    @DataProvider
+    public static Iterator<Object[]> intArraysWithPredicate(){
+        ArrayList<Object[]> list = new ArrayList<>();
+        String format = "<int[%d], %s>";
+        Arrays.stream(arrays).forEach(data -> {
+            int[] array = (int[])data[0];
+            list.add(new Object[]{String.format(format, array.length, "i -> i < " + array.length / 2), array, (IntPredicate) i -> i < array.length / 2}); 
+            list.add(new Object[]{String.format(format, array.length, "i -> i < 0"), array, (IntPredicate) i -> i < 0});
+            list.add(new Object[]{String.format(format, array.length, "i -> i >= 0"), array, (IntPredicate) i -> i >= 0});
+            list.add(new Object[]{String.format(format, array.length, "i -> i >= " + array.length), array, (IntPredicate) i -> i >= array.length});
+        });
+        return list.iterator();
+    }
+
+    @DataProvider
+    public static Iterator<Object[]> intArraysWithOperator(){
+        ArrayList<Object[]> list = new ArrayList<>();
+        String format = "<int[%d], %s>";
+        Arrays.stream(arrays).forEach(data -> {
+            int[] array = (int[])data[0];
+            list.add(new Object[]{String.format(format, array.length, "i -> i + 1"), array, (IntUnaryOperator)i -> i + 1}); 
+            list.add(new Object[]{String.format(format, array.length, " i -> i << 2"), array, (IntUnaryOperator) i -> i << 2});
+            list.add(new Object[]{String.format(format, array.length, "Math::abs"), array, (IntUnaryOperator)Math::abs});
+        });
+        return list.iterator();
+    }
+
+    @DataProvider
+    public static Iterator<Object[]> intArraysWithSelection(){
+        ArrayList<Object[]> list = new ArrayList<>();
+        String format = "<int[%d], %s>";
+        Arrays.stream(arrays).forEach(data -> {
+            int[] array = (int[])data[0];
+            Arrays.stream(Selection.values()).forEach(selection -> 
+                    list.add(new Object[]{String.format(format, array.length, selection), array, selection}));
+        });
+        return list.iterator();
+    }
+
+    @Test(dataProvider="intArraysWithPredicate")
+    public void testXxxMatch(String desc, int[] array, IntPredicate predicate) {
+        assertEquals(streamFor(parallelType, array) .allMatch(predicate), verifyMatch(array, predicate, true));
+        assertEquals(streamFor(parallelType, array) .anyMatch(predicate),  verifyMatch(array, predicate, false));
+        assertEquals(streamFor(parallelType, array) .noneMatch(predicate), verifyMatch(array, predicate.negate(), true));
+
+        assertEquals(streamFor(parallelType, array, 0, array.length).allMatch(predicate),
+                streamFor(parallelType, array).allMatch(predicate));
+        assertEquals(streamFor(parallelType, array, 0, array.length).anyMatch(predicate),
+                streamFor(parallelType, array).anyMatch(predicate));
+        assertEquals(streamFor(parallelType, array, 0, array.length).noneMatch(predicate), 
+                streamFor(parallelType, array).noneMatch(predicate));
+
+        assertTrue(streamFor(parallelType, EMPTY_ARRAY).allMatch(predicate));
+        assertFalse(streamFor(parallelType, EMPTY_ARRAY).anyMatch(predicate));
+        assertTrue(streamFor(parallelType, EMPTY_ARRAY).noneMatch(predicate));
+    }
+
+    @Test(dataProvider="intArrays")
+    public void testAveargeAndSum(String desc, int[] array) throws Exception {
+        //for calculate average, we need bigger scale data type calculate total, this could prevent int overflow 
+        double total = 0;
+        int intTotal = 0;
+        for(int index = 0; index < array.length; index++) {
+            total += array[index];
+            intTotal += array[index];
+        }
+        assertEquals(streamFor(parallelType, array).average(). getAsDouble(), total / array.length);
+        assertEquals(streamFor(parallelType, array).sum(), intTotal);
+
+        assertEquals(streamFor(parallelType, array).average(), streamFor(parallelType, array, 0, array.length).average());
+        assertEquals(streamFor(parallelType, array).sum(), streamFor(parallelType, array, 0, array.length).sum());
+        
+        assertFalse(streamFor(parallelType, EMPTY_ARRAY).average().isPresent());
+        assertEquals(streamFor(parallelType, EMPTY_ARRAY).sum(), 0);
+    }
+
+    @Test(dataProvider="intArrays")
+    public void testBoxed(String desc, int[] array) throws Exception {
+        Object[] boxedArr1 = streamFor(parallelType, array).boxed().toArray();
+        Object[] boxedArr2 = streamFor(parallelType, array).mapToObj(Integer::new).toArray();
+        assertEquals(boxedArr1, boxedArr2);
+       
+        assertEquals(streamFor(parallelType, EMPTY_ARRAY).boxed().count(), 0);
+    }
+
+    @Test(dataProvider="intArraysWithPredicate")
+    public void testFilter(String desc, int[] array/*, int startIndex, int endIndex*/, IntPredicate predicate) throws Exception{
+        assertTrue(verifyMatch(streamFor(parallelType, array).filter(predicate).toArray(), predicate, true));
+        assertEquals(streamFor(parallelType, array, 0, array.length).filter(predicate).toArray(), 
+                streamFor(parallelType, array).filter(predicate).toArray());
+
+        assertEquals(streamFor(parallelType, EMPTY_ARRAY).filter(predicate).count(), 0);
+    }
+
+    @Test(dataProvider="intArrays")
+    public void testFind(String desc, int[] array) throws Exception{
+        IntStream streamFindAny = streamFor(parallelType, array);
+        OptionalInt opAny = streamFindAny.findAny();
+        OptionalInt opFirst = streamFor(parallelType, array).findFirst();
+        assertTrue(opAny.isPresent());
+        assertTrue(opFirst.isPresent());
+        if(!streamFindAny.isParallel())
+            assertEquals(opAny, opFirst);
+        
+        assertFalse(streamFor(parallelType, EMPTY_ARRAY).findAny().isPresent());
+        assertFalse(streamFor(parallelType, EMPTY_ARRAY).findFirst().isPresent());
+    }
+
+    @Test(dataProvider="intArrays")
+    public void testForEach(String desc, int[] array) throws Exception {
+        IntStream stream = streamFor(parallelType, array);
+        Arrays.parallelSort(array);
+        stream.forEach(t -> { assertTrue(Arrays.binarySearch(array, t) >= 0); });
+
+        ArrayList<Integer> touch = new ArrayList<>();
+        streamFor(parallelType, EMPTY_ARRAY).forEach(t -> { touch.add(t); });
+        assertTrue(touch.isEmpty());
+    }
+
+    @Test(dataProvider="intArraysWithLimit")
+    public void testLimit(String desc, int[] array, int limit) {
+        if(limit > array.length)
+            assertEquals(streamFor(parallelType, array).limit(limit).count(), array.length);
+        else
+            assertEquals(streamFor(parallelType, array).limit(limit).count(), limit);
+    }
+
+    @Test(dataProvider="intArraysWithSelection")
+    public void testFlatMap(String desc, int[] array, Selection selection) {
+        int[] flatArray = streamFor(parallelType, array).flatMap(genIntFlatMapper(selection)).sorted().toArray();
+        verifyMultifunction(array, flatArray, selection);
+
+        assertEquals(streamFor(parallelType, EMPTY_ARRAY).flatMap(genIntFlatMapper(selection)).toArray(),EMPTY_ARRAY);
+    }
+
+    @Test(dataProvider="intArraysWithOperator")
+    public void testMap(String desc, int[] array, IntUnaryOperator mapper)  {
+        int[] mapped = streamFor(parallelType, array).map(mapper).toArray();
+        for(int index = 0; index < array.length; index++) {
+            assertEquals(mapped[index], mapper.applyAsInt(array[index]));
+        }
+
+        IntFunction<Object> objMapper = i -> new Integer(mapper.applyAsInt(i));
+        Object[] objArray1 = streamFor(parallelType, array).map(mapper).boxed().toArray();
+        Object[] objArray2 = streamFor(parallelType, array).mapToObj(objMapper).toArray();
+        assertEquals(objArray1, objArray2);
+    }
+
+    @Test(dataProvider="intArrays")
+    public void testMaxAndMin(String desc, int[] array) {
+        boolean[] maxOrMin = {true, false};
+        for(boolean testMax : maxOrMin) {
+            OptionalInt testOpt = testMax ? streamFor(parallelType, array).max() 
+                    : streamFor(parallelType, array).min();
+            assertEquals(testOpt.getAsInt(), getMaxOrMin(array, testMax));
+            assertEquals(testOpt.getAsInt(), getMaxOrMinWithReduceOp(array, testMax));
+            assertEquals(testOpt.getAsInt(), getMaxOrMinWithReduceOpAndBase(array, testMax));
+
+            assertFalse(testMax ? streamFor(parallelType, EMPTY_ARRAY).max().isPresent()
+                    : streamFor(parallelType, EMPTY_ARRAY).min().isPresent());
+        }
+    }
+
+    @Test(dataProvider="intArrays")
+    public void testSpliterator(String desc, int[] array)  {
+        int[] calArrParallel = StreamSupport.intStream(streamFor(parallelType, array).spliterator(), true).toArray();
+        int[] calArrSequential = StreamSupport.intStream(streamFor(parallelType, array).spliterator(), false).toArray();
+        for(int index = 0; index < array.length; index++) {
+            assertEquals(array[index], calArrParallel[index]);
+            assertEquals(array[index], calArrSequential[index]);
+        }
+    }
+
+    @Test(dataProvider="intArrays")
+    public void testReduceWithBase(String desc, int[] array)  {
+        if(parallelType == ParallelType.Parallel)
+            return;
+        int base = rand.nextInt();
+        int oiPlus = streamFor(parallelType, array).reduce(base, 
+                LambdaUtilities.addIntBinaryOperator());
+        int total = 0;
+        for(int index = 0; index < array.length; index++)
+            total += array[index];
+        assertEquals(oiPlus, total + base);
+
+        int oiSubtract = streamFor(parallelType, array).reduce(base, 
+                LambdaUtilities.subIntBinaryOperator());
+        int subTotal = base;
+        for(int index = 0; index < array.length; index++)
+            subTotal -= array[index];
+        assertEquals(oiSubtract, subTotal);
+
+        int emptyByBase = streamFor(parallelType, EMPTY_ARRAY).reduce(base, rand.nextBoolean() ?
+                LambdaUtilities.addIntBinaryOperator() :
+                LambdaUtilities.subIntBinaryOperator());
+        assertEquals(emptyByBase, base);
+    }
+
+    @Test(dataProvider="intArrays")
+    public void testReduceWithoutBase(String desc, int[] array)  {
+        OptionalInt oiPlus = streamFor(parallelType, array).reduce(Integer::sum);
+        assertTrue(oiPlus.isPresent());
+        int total = 0;
+        for(int index = 0; index < array.length; index++)
+            total += array[index];
+        assertTrue(oiPlus.getAsInt() == total);
+
+        //Can't predict Parallel Substract reduce result, give up testing on
+        //parallel substract test
+        if(parallelType == ParallelType.Parallel)
+            return;
+
+        OptionalInt oiSubtract = streamFor(parallelType, array).
+                reduce(LambdaUtilities.subIntBinaryOperator());
+        assertTrue(oiSubtract.isPresent());
+        int subTotal = array[0];
+        for(int index = 1; index < array.length; index++)
+            subTotal -= array[index];
+        assertEquals(oiSubtract.getAsInt(), subTotal);
+
+        OptionalInt emptyOp = streamFor(parallelType, EMPTY_ARRAY).
+                reduce(rand.nextBoolean() ? LambdaUtilities.addIntBinaryOperator() :
+                LambdaUtilities.subIntBinaryOperator());
+        assertFalse(emptyOp.isPresent());
+    }
+
+    @Test(dataProvider="intArraysWithSkipLimit")
+    public void testSubstream(String desc, int[] array, int skip, int limit) {
+        assert(limit >= skip);
+        int[] toArray = streamFor(parallelType, array).substream(skip, limit).toArray();
+        if(skip < array.length) {
+            if(limit < array.length) {
+                verifySlice(array, toArray, skip, limit);  
+            } else {
+                verifySlice(array, toArray, skip, array.length);
+            }
+        }
+        else {
+            assertEquals(toArray.length, 0);
+        }
+        assertEquals(streamFor(parallelType, EMPTY_ARRAY).substream(skip, limit).count(), 0);    
+        
+    }
+
+    @Test(dataProvider="intArrays")
+    public void testSorted(String desc, int[] array){
+        checkSorted(streamFor(parallelType, array).sorted().toArray(), Comparator.naturalOrder());
+        assertEquals(streamFor(parallelType, array).sorted().toArray(), 
+                streamFor(parallelType, array, 0, array.length).sorted().toArray());
+        assertEquals(streamFor(parallelType, EMPTY_ARRAY).sorted().toArray().length, 0);
+    }
+
+    @Test(dataProvider="intArrays")
+    public void testPeek(String desc, int[] array){
+        AtomicInteger ai1 = new AtomicInteger(0);
+        IntStream stream = streamFor(parallelType, array).peek(LambdaUtilities.addIntConsumer(ai1));
+        //Lazy operation checking
+        assertEquals(ai1.get(), 0);
+        int sum = stream.sum();
+        assertEquals(ai1.get(), sum);
+
+        assertEquals(streamFor(parallelType,EMPTY_ARRAY).peek(LambdaUtilities.addIntConsumer(ai1)).count(), 0);
+    }
+
+    @Test(dataProvider="intArrays")
+    public void testToArray(String desc, int[] array){
+        assertEquals(streamFor(parallelType, array).toArray(), array);
+        assertEquals(streamFor(parallelType, array, 0, array.length).toArray(), array);
+        assertEquals(streamFor(parallelType, EMPTY_ARRAY).toArray().length, 0);
+    }
+
+    @Test(dataProvider="intArrays")
+    public void testDistrinct(String desc, int[] array){
+        int[] toArray = streamFor(parallelType, array).flatMap(genIntFlatMapper(Selection.COPY_64)).distinct().toArray();
+        assertEquals(toArray, array);
+
+        assertEquals(streamFor(parallelType, EMPTY_ARRAY).flatMap(genIntFlatMapper(Selection.COPY_64)).
+                distinct().toArray().length, 0);
+    }
+
+    private void verifyMultifunction(int[] orig, int[] result, Selection selection) {
+        switch(selection) {
+            case EMPTY:
+                assertEquals(result.length, 0);
+                break;
+            case SINGLE:
+                assertEquals(orig, result);
+                break;
+            case TRIANGLE:
+                int expectedSize = orig.length * (orig.length + 1) / 2;
+                int[] expected = IntStream.range(0, expectedSize).toArray();
+                assertEquals(result, expected);
+                break;
+            case COPY_64:
+                Stream<Integer> sToBeConcated = Stream.empty();
+                for(int current : orig) {
+                    sToBeConcated = Stream.concat(sToBeConcated, 
+                            IntStream.generate(() -> current).
+                            limit(1 << 6).boxed());
+                }
+                assertEquals(sToBeConcated.toArray(), result);
+                break;
+            default:
+                throw new RuntimeException("Invalid selection " + selection);
+        }
+    }
+
+    private int getMaxOrMin(int[] array, boolean isMax) {
+        assert(array.length > 0);
+        int pos = 0;
+        int choosen = array[pos++];
+        while(pos < array.length) {
+            int current = array[pos++];
+            if((choosen < current) == isMax) choosen = current;
+        }
+        return choosen;
+    }
+
+    private int getMaxOrMinWithReduceOp(int[] array, boolean isMax) {
+        assert(array.length > 0);
+        OptionalInt choosen = Arrays.stream(array).reduce(isMax ? 
+                LambdaUtilities.maxIntBinaryOperator() :
+                LambdaUtilities.minIntBinaryOperator());
+        return choosen.getAsInt();
+    }
+
+    private int getMaxOrMinWithReduceOpAndBase(int[] array, boolean isMax) {
+        assert(array.length > 0);
+        int choosen = Arrays.stream(array).reduce(array[0], isMax ? 
+                LambdaUtilities.maxIntBinaryOperator() :
+                LambdaUtilities.minIntBinaryOperator());
+        return choosen;
+    }
+
+    private void verifySlice(int[] array, int[] toArray, int skip, int limit){
+        for(int index = skip; index < array.length && index < limit; index++)
+            assertTrue(array[index] <= toArray[index - skip]);
+    }
+
+    private void checkSorted(int[] array, Comparator<Integer> comp){
+        assert(array.length > 0);
+        for(int index = 0; index < array.length - 1; index++)
+            assertTrue(comp.compare(array[index] , array[index + 1]) <= 0);
+    }
+
+    private static IntFunction<IntStream> genIntFlatMapper(Selection selection) {
+        switch (selection) {
+            case EMPTY:
+                //Generate a empty collection
+                return e -> IntStream.empty();
+            case SINGLE:
+                return e -> Arrays.stream(new int[]{ e });
+            case TRIANGLE:
+                //Generate a triangle has different value
+                return e -> IntStream.range(0, e + 1).map(i -> e * (e + 1) / 2 + i);
+            case COPY_64:
+                //Generate 64 folded flat map
+                return e -> IntStream.range(0, 1 << 6).map(i -> e);
+            default:
+                throw new RuntimeException("Invalid selection " + selection);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/stream/Stream/IntegerStreamTest.java	Wed Aug 14 15:53:13 2013 -0700
@@ -0,0 +1,178 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @summary Basic test for Stream<Integer>
+ * @library /sqeutil
+ * @(#) IntegerStreamTest.java
+ * @author Tristan Yan
+ * @run testng IntegerStreamTest
+ */
+
+import java.math.BigDecimal;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.IntSummaryStatistics;
+import java.util.Optional;
+import java.util.function.BiFunction;
+import java.util.function.BinaryOperator;
+import java.util.function.Function;
+import java.util.function.IntFunction;
+import java.util.function.ToIntFunction;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+import java.util.stream.Stream;
+import static org.testng.Assert.assertEquals;
+import org.testng.annotations.Factory;
+import org.testng.annotations.Test;
+
+public class IntegerStreamTest<T extends Collection<Integer>> extends GenericStreamTest<Integer, Collection<Integer>> {
+    private IntegerStreamTest(Class clazz,
+            ParallelType parallelType, int initSize) {
+        super(clazz, parallelType, Comparator.naturalOrder(), initSize);
+    }
+
+   private IntegerStreamTest(Class clazz,
+            ParallelType parallelType) {
+        super(clazz, parallelType, Comparator.naturalOrder());
+    }
+
+    @Factory
+    public static Object[] create(){
+      TripleFunction<Class,ParallelType,Integer, IntegerStreamTest> supplierWithInitSize =
+              IntegerStreamTest<Collection<Integer>>::<Class,ParallelType,Integer>new;
+      BiFunction<Class,ParallelType, IntegerStreamTest> supplier =
+              IntegerStreamTest<Collection<Integer>>::<Class,ParallelType>new;
+      return GenericStreamTest.create(supplierWithInitSize, supplier, true);
+    }
+
+    @Override
+    public String getTestName() {
+        return typeObject.getName() + "<Integer>";
+    }
+
+    @Test(dataProvider="collectionFunctionData")
+    public void testCollectSummarizingInt(String desc, Collection<Integer> col, Function<Integer, ? extends Object> mapFunc) {
+        //test summarizingInt
+        IntSummaryStatistics iss = streamFor(col).collect(Collectors.<Integer>summarizingInt(Integer::intValue));
+        assertEquals(iss.getCount(), col.size());
+        assertEquals(iss.getMax(), streamFor(col).max(naturalOrderComparator).get().intValue());
+        assertEquals(iss.getMin(), streamFor(col).min(naturalOrderComparator).get().intValue());
+        assertEquals(iss.getSum(), streamFor(col).mapToInt(Integer::intValue).sum());
+    }
+
+    @Test(dataProvider="collectionData")
+    public void testReduceIdentitiyWithoutBase(String desc, Collection<Integer> col) throws Exception{
+        Stream<Integer> streamTotal = streamFor(col);
+        Optional<Integer> total = streamTotal.reduce(LambdaUtilities.addIntegerBinaryOperator());
+        double avg = (double) total.get().intValue() / col.size();
+        Stream<Integer> streamStanDeviation = streamFor(col);
+        BigDecimal deviationSquare = streamStanDeviation.reduce(new BigDecimal(0.0),
+                LambdaUtilities.deviationSequareFunction(avg),
+                LambdaUtilities.addBigDecimalBinaryOperator());
+        double stdev = deviationSquare.doubleValue() / col.size();
+
+        int totalExpected = 0;
+        for (Integer aCol : col)
+            totalExpected +=  aCol;
+        assertEquals(totalExpected, total.get().intValue());
+        double avgExpected = (double)totalExpected / col.size();
+        assertEquals(avgExpected, avg);
+
+        BigDecimal deviationSquareExpected = new BigDecimal(0.0);
+        for (Integer aCol : col)
+            deviationSquareExpected = deviationSquareExpected
+                    .add(new BigDecimal(avg - aCol).pow(2));
+        assertEquals(deviationSquare, deviationSquareExpected);
+
+        double stddvExpected = deviationSquareExpected.doubleValue() / col.size();
+        assertEquals(stddvExpected, stdev);
+    }
+
+    @Override
+    protected Collection<Integer> generate(int size) {
+        Collection<Integer> col = createEmptyCollection();
+        IntStream.range(0, size).forEach(i -> col.add(i));
+        return col;
+    }
+    
+    @Override
+    protected Object[] predicateAndDesc(int size){
+            boolean isUp = rand.nextBoolean();
+            int limit = rand.nextInt(size);
+            return new Object[]{ LambdaUtilities.randomIntegerPredicate(isUp, limit), 
+                    String.format("i -> i %s %d", isUp ? ">=" : "<", limit)};
+    }
+
+    //BinaryOperator, descrption, stateless
+    @Override
+    protected Object[][] binaryOperatorAndDesc() {
+        return new Object[][]{
+            {(BinaryOperator<Integer>)Integer::sum, "Integer::sum", false},
+            {(BinaryOperator<Integer>)Integer::max, "Integer::sum", true},
+            {(BinaryOperator<Integer>)Integer::max, "Integer::sum", true},
+        }; 
+    }
+    
+    //Function<U, ? extends Comparable>, descrption for Function<? extends Comparable>
+    @Override
+    protected Object[][] functionAndDesc(){
+        Function<Integer, String> toStr = String::valueOf;
+        return new Object[][]{
+            {(Function<Integer, Integer>)i -> i++, "i -> i++"},
+            {toStr, "String::valueOf"},
+        };
+    }
+    
+    @Override
+    protected Integer[] bases(int size){
+        return new Integer[]{-1, 0, 1, size /2, size - 1, size, size + 1};
+    }
+
+    @Override
+    protected Object[] validArrayGeneratorAndDesc() {
+        return new Object[]{
+            new IntFunction[]{(IntFunction)Integer[]::new, (IntFunction)Number[]::new},
+            "{Integer[]::new, Number[]::new}"
+        };
+    }
+
+    @Override
+    protected Object[][] invalidArrayGeneratorAndDesc() {
+        return new Object[][]{
+            {(IntFunction)Double[]::new, "Double[]::new"},
+            {(IntFunction)String[]::new, "String[]::new"},
+        };
+    }
+
+    @Override
+    protected IntFunction<Integer> createFunction() {
+        return Integer::valueOf;
+    }
+
+    @Override
+    protected ToIntFunction<Integer> intValueFunction() {
+        return Integer::intValue;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/stream/Stream/StringBuilderStreamTest.java	Wed Aug 14 15:53:13 2013 -0700
@@ -0,0 +1,170 @@
+/*
+ * 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 Basic test for Stream<StringBuilder>
+ * @library /sqeutil
+ * @(#) StringBuilderStreamTest.java
+ * @author Eric Wang/Tristan Yan
+ * @run testng/othervm -mx1g StringBuilderStreamTest
+ */
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.function.BiFunction;
+import java.util.function.BinaryOperator;
+import java.util.function.Function;
+import java.util.function.IntFunction;
+import java.util.function.Predicate;
+import java.util.function.ToIntFunction;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+import static org.testng.Assert.assertEquals;
+import org.testng.annotations.Factory;
+import org.testng.annotations.Test;
+
+public class StringBuilderStreamTest<T extends Collection<StringBuilder>> extends
+            GenericStreamTest<StringBuilder, Collection<StringBuilder>> {
+    public StringBuilderStreamTest(Class clazz, 
+            ParallelType parallelType, int initSize) {
+        super(clazz, parallelType, Comparator.comparing((Function<StringBuilder,
+                String>)StringBuilder::toString), initSize);
+    }
+
+    public StringBuilderStreamTest(Class clazz, 
+            ParallelType parallelType) {
+        super(clazz, parallelType, Comparator.comparing((Function<StringBuilder,
+                String>)StringBuilder::toString));
+    }
+
+    @Factory
+    public static Object[] create(){
+      TripleFunction<Class,ParallelType,Integer,StringBuilderStreamTest> supplierWithInitSize =
+              StringBuilderStreamTest<Collection<StringBuilder>>::<Class,ParallelType,Integer>new;
+      BiFunction<Class,ParallelType,StringBuilderStreamTest> supplier =
+              StringBuilderStreamTest<Collection<StringBuilder>>::<Class,ParallelType>new;
+      return GenericStreamTest.create(supplierWithInitSize, supplier, false);
+    }
+
+    @Override
+    public String getTestName() {
+        return typeObject.getName() + "<StringBuilder>";
+    }
+
+    @Test(dataProvider="collectionFunctionData")
+    public void testCollectJoining(String desc, Collection<StringBuilder> col, Function<StringBuilder, ? extends Object> mapFunc) {
+        //test joining
+        String joined = streamFor(col).collect(Collectors.joining());
+        int pos = 0;
+        for(StringBuilder sb : col) {
+            String toString = sb.toString();
+            assertEquals(joined.substring(pos, pos + toString.length()), toString);
+            pos += toString.length();
+        }
+    }
+
+    //StringBuilder is not Comparable
+    //Not single element stream won't throw ClassCastException
+    @Test(dataProvider="exceptionTestData", expectedExceptions = ClassCastException.class)
+    @Override
+    public void testSortedSpecial(String desc, Collection<StringBuilder> col) {
+            streamFor(col).sorted().findFirst();
+            System.out.println(col.size());
+    }
+   
+    @Override
+    protected Object[] predicateAndDesc(int size){
+        LambdaUtilities.CharType charType = Arrays.stream(LambdaUtilities.CharType.values()).findAny().get();
+        Boolean isFirst = rand.nextBoolean();
+       Predicate<StringBuilder> p =(Predicate<StringBuilder>) LambdaUtilities.randomSBPredicate(charType, isFirst);
+       String funcName = "";
+        switch (charType) {
+            case DIGIT: funcName = "isDigit"; break;
+            case LOWERCASE: funcName = "isLowerCase"; break;
+            case UPPERCASE: funcName = "isUpperCase"; break;
+            default: funcName = "isLetterOrDigit"; break;
+        }
+        return new Object[]{ p , String.format("sb -> Character.%s(%s)", funcName, isFirst ? "0" : "sb.toString().length() - 1")};
+
+    }
+
+    //BinaryOperator, descrption, stateless
+    @Override
+    protected Object[][] binaryOperatorAndDesc() {
+        return new Object[][]{
+            {(BinaryOperator<StringBuilder>)StringBuilder::append, "StringBuilder::append", false},
+            {LambdaUtilities.maxGenericBinaryOperator(naturalOrderComparator), "(t1, t2) -> t1 < t2 ? t2 : t1", true},
+            {LambdaUtilities.minGenericBinaryOperator(naturalOrderComparator), " (t1, t2) -> t1 < t2 ? t1 : t2", true},
+        }; 
+    }
+
+    //Function<U, ? extends Comparable>, descrption for Function<? extends Comparable>
+    @Override
+    protected Object[][] functionAndDesc(){
+        return new Object[][]{
+            {(Function<StringBuilder, String>)StringBuilder::toString, "StringBuilder::toString"},
+        };
+    }
+   
+    @Override
+    protected Collection<StringBuilder> generate(int size) {
+        Collection<StringBuilder> col = createEmptyCollection();
+        IntStream.range(0, size).mapToObj(i -> new StringBuilder().append(i) ).forEach(sb -> col.add(sb));
+        return col;
+    }
+    
+    @Override
+    protected StringBuilder[] bases(int size){
+        return new StringBuilder[]{new StringBuilder(), new StringBuilder(rand.nextInt(size)), new StringBuilder(size)};
+    }
+
+    //StringBuilder[] can be converted into StringBuilder[]::new,CharSequence[]::new, Object[]::new
+    @Override
+    protected Object[] validArrayGeneratorAndDesc() {
+        return new Object[]{
+            new IntFunction[]{(IntFunction)StringBuilder[]::new, (IntFunction)CharSequence[]::new, (IntFunction)Object[]::new},
+            "{StringBuilder[]::new, CharSequence[]::new}, Object[]::new}"
+        };
+    }
+
+    //StringBuilder[] can't be converted into StringBuffer[]::new,Integer[]::new
+    @Override
+    protected Object[][] invalidArrayGeneratorAndDesc() {
+        return new Object[][]{
+            {(IntFunction)StringBuffer[]::new, "StringBuffer[]::new"},
+            {(IntFunction)Integer[]::new, "Integer[]::new"},
+        };
+    }
+
+    @Override
+    protected IntFunction<StringBuilder> createFunction() {
+        return  i -> new StringBuilder().append(i);
+    }
+
+    @Override
+    protected ToIntFunction<StringBuilder> intValueFunction() {
+        return sb -> Integer.parseInt(sb.toString()) ;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/stream/Streams/BasicTest.java	Wed Aug 14 15:53:13 2013 -0700
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @summary Basic test for Streams's API
+ * @library /sqeutil
+ * @(#) BasicTest.java
+ * @author Tristan Yan
+ * @run testng BasicTest
+ */
+
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.PrimitiveIterator;
+import java.util.Random;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.IntConsumer;
+import java.util.function.IntUnaryOperator;
+import java.util.stream.IntStream;
+import java.util.stream.Stream;
+import java.util.Spliterators;
+import static org.testng.Assert.*;
+import org.testng.annotations.Test;
+
+public class BasicTest {
+    private final static int ARRAY_SIZE = 1 << 12;
+
+    private final static Random rand = new Random(8675309);
+
+    private final static String HELLO_WORLD = "Hello world";
+
+    @Test
+    public void testEmpty() {
+        final AtomicInteger accumulator = new AtomicInteger(0);
+        IntConsumer ic = i -> {
+            accumulator.getAndIncrement();
+        };
+        Spliterators.emptyIntSpliterator().forEachRemaining(ic);
+        assertEquals(accumulator.get(), 0);
+
+        assertEquals(IntStream.empty().toArray().length, 0);
+
+        assertEquals(Stream.empty().toArray().length, 0);
+
+        assertEquals(Spliterators.emptyIntSpliterator().estimateSize(), 0);
+
+        assertEquals(Spliterators.<String>emptySpliterator().estimateSize(), 0);
+    }
+
+    @Test
+    public void testGenerate() {
+        final int randomValue = rand.nextInt();
+        final int randomSize= rand.nextInt(1 << 8);
+        IntStream is = IntStream.generate(() -> randomValue);
+        assertEquals(is.spliterator().getExactSizeIfKnown(), -1);
+
+        IntStream is1 = IntStream.generate(() -> randomValue);
+        IntStream is2 = IntStream.generate(() -> randomValue);
+        assertEquals(is1.limit(randomSize).max(), is2.limit(randomSize).min());
+
+        Stream<String> ss = Stream.generate(() -> HELLO_WORLD);
+        assertEquals(ss.spliterator().getExactSizeIfKnown(), -1);
+        Stream<String> ss1 = Stream.generate(() -> HELLO_WORLD);
+        Stream<String> ss2 = Stream.generate(() -> HELLO_WORLD);
+        assertEquals(ss1.limit(randomSize).findAny(), ss2.limit(randomSize).findAny());
+
+        LambdaUtilities.IntOp op = LambdaUtilities.IntOp.values()[rand.nextInt(LambdaUtilities.IntOp.values().length)];
+        final int randomInit = rand.nextInt();
+        final int randomOpnd = rand.nextInt();
+        IntUnaryOperator iuo = LambdaUtilities.opIntUnaryOperator(op, randomOpnd);
+        IntStream isi = IntStream.iterate(randomInit, iuo);
+        int limitation = rand.nextInt( 1 << 10 );
+        PrimitiveIterator.OfInt pi = isi.limit(limitation).iterator();
+
+        int next = randomInit;
+
+        while(pi.hasNext()) {
+            assertEquals(pi.nextInt(), next);
+            next = iuo.applyAsInt(next);
+        }
+
+        //below is time-consuming, need watch out if it's gonna affect our test
+        int start = rand.nextInt(1 << 12);
+        int end = rand.nextInt(1 << 12);
+
+        if(start > end) {
+            start = start ^ end;
+            end = end ^ start;
+            start = end ^ start;
+        }
+        PrimitiveIterator.OfInt it1 = IntStream.range(start, end).iterator();
+        while(it1.hasNext())
+            assertEquals(it1.nextInt(), start++);
+        assertEquals(start, end);
+    }
+
+    @Test
+    public void testIterator() {
+        int seed = rand.nextInt();
+        int opRnd = rand.nextInt();
+        int selected = rand.nextInt(LambdaUtilities.IntOp.values().length);
+        LambdaUtilities.IntOp op = LambdaUtilities.IntOp.values()[selected];
+        int limitRnd = rand.nextInt(1 << 20);
+        IntUnaryOperator iuo = LambdaUtilities.opIntUnaryOperator(op, opRnd);
+        int[] arr = IntStream.iterate(seed, iuo).limit(limitRnd).toArray();
+        assertEquals(arr.length, limitRnd);
+    }
+}
--- a/test/java/util/stream/bootlib/java/util/stream/DoubleStreamTestScenario.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/test/java/util/stream/bootlib/java/util/stream/DoubleStreamTestScenario.java	Wed Aug 14 15:53:13 2013 -0700
@@ -40,7 +40,7 @@
 @SuppressWarnings({"rawtypes", "unchecked"})
 public enum DoubleStreamTestScenario implements OpTestCase.BaseStreamTestScenario {
 
-    STREAM_FOR_EACH(false) {
+    STREAM_FOR_EACH_WITH_CLOSE(false) {
         <T, S_IN extends BaseStream<T, S_IN>>
         void _run(TestData<T, S_IN> data, DoubleConsumer b, Function<S_IN, DoubleStream> m) {
             DoubleStream s = m.apply(data.stream());
@@ -48,6 +48,7 @@
                 s = s.sequential();
             }
             s.forEach(b);
+            s.close();
         }
     },
 
--- a/test/java/util/stream/bootlib/java/util/stream/IntStreamTestScenario.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/test/java/util/stream/bootlib/java/util/stream/IntStreamTestScenario.java	Wed Aug 14 15:53:13 2013 -0700
@@ -40,7 +40,7 @@
 @SuppressWarnings({"rawtypes", "unchecked"})
 public enum IntStreamTestScenario implements OpTestCase.BaseStreamTestScenario {
 
-    STREAM_FOR_EACH(false) {
+    STREAM_FOR_EACH_WITH_CLOSE(false) {
         <T, S_IN extends BaseStream<T, S_IN>>
         void _run(TestData<T, S_IN> data, IntConsumer b, Function<S_IN, IntStream> m) {
             IntStream s = m.apply(data.stream());
@@ -48,6 +48,7 @@
                 s = s.sequential();
             }
             s.forEach(b);
+            s.close();
         }
     },
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/stream/bootlib/java/util/stream/LambdaTestMode.java	Wed Aug 14 15:53:13 2013 -0700
@@ -0,0 +1,71 @@
+/*
+ * 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 java.util.stream;
+
+/**
+ * Runtime modes of test execution.
+ */
+public enum LambdaTestMode {
+    /**
+     * Execution mode with no particular runtime constraints.
+     */
+    NORMAL,
+
+    /**
+     * Execution mode where tests are executed for testing lambda serialization
+     * and deserialization.
+     *
+     * <p>This mode may be queried by tests or data supplied by data
+     * providers, which cannot otherwise be assigned to the test group
+     * <em>serialization-hostile</em>, to not execute or declare
+     * serialization-hostile code or data.
+     *
+     * <p>This mode is enabled if the boolean system property
+     * {@code org.openjdk.java.util.stream.sand.mode} is declared with a
+     * {@code true} value.
+     */
+    SERIALIZATION;
+
+    /**
+     * {@code true} if tests are executed in the mode for testing lambda
+     * Serialization ANd Deserialization (SAND).
+     */
+    private static final boolean IS_LAMBDA_SERIALIZATION_MODE =
+            Boolean.getBoolean("org.openjdk.java.util.stream.sand.mode");
+
+    /**
+     *
+     * @return the mode of test execution.
+     */
+    public static LambdaTestMode getMode() {
+        return IS_LAMBDA_SERIALIZATION_MODE ? SERIALIZATION : NORMAL;
+    }
+
+    /**
+     *
+     * @return {@code true} if normal test mode.
+     */
+    public static boolean isNormalMode() {
+        return getMode() == NORMAL;
+    }
+}
--- a/test/java/util/stream/bootlib/java/util/stream/LoggingTestCase.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/test/java/util/stream/bootlib/java/util/stream/LoggingTestCase.java	Wed Aug 14 15:53:13 2013 -0700
@@ -37,6 +37,7 @@
 /**
  * LoggingTestCase
  *
+ * @author Brian Goetz
  */
 @Test
 public class LoggingTestCase extends Assert {
--- a/test/java/util/stream/bootlib/java/util/stream/LongStreamTestScenario.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/test/java/util/stream/bootlib/java/util/stream/LongStreamTestScenario.java	Wed Aug 14 15:53:13 2013 -0700
@@ -40,7 +40,7 @@
 @SuppressWarnings({"rawtypes", "unchecked"})
 public enum LongStreamTestScenario implements OpTestCase.BaseStreamTestScenario {
 
-    STREAM_FOR_EACH(false) {
+    STREAM_FOR_EACH_WITH_CLOSE(false) {
         <T, S_IN extends BaseStream<T, S_IN>>
         void _run(TestData<T, S_IN> data, LongConsumer b, Function<S_IN, LongStream> m) {
             LongStream s = m.apply(data.stream());
@@ -48,6 +48,7 @@
                 s = s.sequential();
             }
             s.forEach(b);
+            s.close();
         }
     },
 
--- a/test/java/util/stream/bootlib/java/util/stream/OpTestCase.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/test/java/util/stream/bootlib/java/util/stream/OpTestCase.java	Wed Aug 14 15:53:13 2013 -0700
@@ -30,7 +30,6 @@
 import java.util.Collections;
 import java.util.EnumMap;
 import java.util.EnumSet;
-import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
@@ -41,7 +40,6 @@
 import java.util.function.Consumer;
 import java.util.function.Function;
 
-import org.testng.Assert;
 import org.testng.annotations.Test;
 
 /**
@@ -397,14 +395,68 @@
 
     // Exercise terminal operations
 
-    static enum TerminalTestScenario {
-        SINGLE_SEQUENTIAL,
-        SINGLE_SEQUENTIAL_SHORT_CIRCUIT,
-        SINGLE_PARALLEL,
-        ALL_SEQUENTIAL,
-        ALL_SEQUENTIAL_SHORT_CIRCUIT,
-        ALL_PARALLEL,
-        ALL_PARALLEL_SEQUENTIAL,
+    interface BaseTerminalTestScenario<U, R, S_OUT extends BaseStream<U, S_OUT>> {
+        boolean requiresSingleStageSource();
+
+        boolean requiresParallelSource();
+
+        default R run(Function<S_OUT, R> terminalF, S_OUT source, StreamShape shape) {
+            return terminalF.apply(source);
+        }
+    }
+
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    static enum TerminalTestScenario implements BaseTerminalTestScenario {
+        SINGLE_SEQUENTIAL(true, false),
+
+        SINGLE_SEQUENTIAL_SHORT_CIRCUIT(true, false) {
+            @Override
+            public Object run(Function terminalF, BaseStream source, StreamShape shape) {
+                source = (BaseStream) chain(source, new ShortCircuitOp(shape));
+                return terminalF.apply(source);
+            }
+        },
+
+        SINGLE_PARALLEL(true, true),
+
+        ALL_SEQUENTIAL(false, false),
+
+        ALL_SEQUENTIAL_SHORT_CIRCUIT(false, false) {
+            @Override
+            public Object run(Function terminalF, BaseStream source, StreamShape shape) {
+                source = (BaseStream) chain(source, new ShortCircuitOp(shape));
+                return terminalF.apply(source);
+            }
+        },
+
+        ALL_PARALLEL(false, true),
+
+        ALL_PARALLEL_SEQUENTIAL(false, false) {
+            @Override
+            public Object run(Function terminalF, BaseStream source, StreamShape shape) {
+                return terminalF.apply(source.sequential());
+            }
+        },
+        ;
+
+        private final boolean requiresSingleStageSource;
+        private final boolean isParallel;
+
+        TerminalTestScenario(boolean requiresSingleStageSource, boolean isParallel) {
+            this.requiresSingleStageSource = requiresSingleStageSource;
+            this.isParallel = isParallel;
+        }
+
+        @Override
+        public boolean requiresSingleStageSource() {
+            return requiresSingleStageSource;
+        }
+
+        @Override
+        public boolean requiresParallelSource() {
+            return isParallel;
+        }
+
     }
 
     @SuppressWarnings({"rawtypes", "unchecked"})
@@ -415,8 +467,6 @@
 
         R refResult;
 
-        Set<TerminalTestScenario> testSet = EnumSet.allOf(TerminalTestScenario.class);
-
         ResultAsserter<R> resultAsserter = (act, exp, ord, par) -> LambdaTestHelpers.assertContentsEqual(act, exp);
 
         private ExerciseDataTerminalBuilder(TestData<T, S_IN> data, Function<S_IN, S_OUT> streamF, Function<S_OUT, R> terminalF) {
@@ -442,27 +492,6 @@
             return this;
         }
 
-        public ExerciseDataTerminalBuilder<T, U, R, S_IN, S_OUT> without(TerminalTestScenario... tests) {
-            return without(Arrays.asList(tests));
-        }
-
-        public ExerciseDataTerminalBuilder<T, U, R, S_IN, S_OUT> without(Collection<TerminalTestScenario> tests) {
-            testSet.removeAll(tests);
-            if (testSet.isEmpty()) {
-                throw new IllegalStateException("Terminal test scenario set is empty");
-            }
-            return this;
-        }
-
-        public ExerciseDataTerminalBuilder<T, U, R, S_IN, S_OUT> with(TerminalTestScenario... tests) {
-            return with(Arrays.asList(tests));
-        }
-
-        public ExerciseDataTerminalBuilder<T, U, R, S_IN, S_OUT> with(Collection<TerminalTestScenario> tests) {
-            testSet.addAll(tests);
-            return this;
-        }
-
         // Build method
 
         public R exercise() {
@@ -471,70 +500,36 @@
             boolean isOrdered = StreamOpFlag.ORDERED.isKnown(ap.getStreamFlags());
             StreamShape shape = ap.getOutputShape();
 
+            EnumSet<TerminalTestScenario> tests = EnumSet.allOf(TerminalTestScenario.class);
+            // Sequentially collect the output that will be input to the terminal op
             Node<U> node = ap.evaluateToArrayNode(size -> (U[]) new Object[size]);
             if (refResult == null) {
-                // Sequentially collect the output that will be input to the terminal op
-                refResult = terminalF.apply((S_OUT) createPipeline(shape, node.spliterator(),
-                                                                   StreamOpFlag.IS_ORDERED | StreamOpFlag.IS_SIZED,
-                                                                   false));
-            } else if (testSet.contains(TerminalTestScenario.SINGLE_SEQUENTIAL)) {
-                S_OUT source = (S_OUT) createPipeline(shape, node.spliterator(),
-                                                      StreamOpFlag.IS_ORDERED | StreamOpFlag.IS_SIZED,
-                                                      false);
-                R result = terminalF.apply(source);
-                LambdaTestHelpers.launderAssertion(() -> resultAsserter.assertResult(result, refResult, isOrdered, false),
-                                                   () -> String.format("Single sequential: %s != %s", refResult, result));
-            }
-
-            if (testSet.contains(TerminalTestScenario.SINGLE_SEQUENTIAL_SHORT_CIRCUIT)) {
+                // Induce the reference result
                 S_OUT source = (S_OUT) createPipeline(shape, node.spliterator(),
                                                       StreamOpFlag.IS_ORDERED | StreamOpFlag.IS_SIZED,
                                                       false);
-                // Force short-circuit
-                source = (S_OUT) chain(source, new ShortCircuitOp<U>(shape));
-                R result = terminalF.apply(source);
-                LambdaTestHelpers.launderAssertion(() -> resultAsserter.assertResult(result, refResult, isOrdered, false),
-                                                   () -> String.format("Single sequential pull: %s != %s", refResult, result));
-            }
 
-            if (testSet.contains(TerminalTestScenario.SINGLE_PARALLEL)) {
-                S_OUT source = (S_OUT) createPipeline(shape, node.spliterator(),
-                                                      StreamOpFlag.IS_ORDERED | StreamOpFlag.IS_SIZED,
-                                                      true);
-                R result = terminalF.apply(source);
-                LambdaTestHelpers.launderAssertion(() -> resultAsserter.assertResult(result, refResult, isOrdered, true),
-                                                   () -> String.format("Single parallel: %s != %s", refResult, result));
+                refResult = (R) TerminalTestScenario.SINGLE_SEQUENTIAL.run(terminalF, source, shape);
+                tests.remove(TerminalTestScenario.SINGLE_SEQUENTIAL);
             }
 
-            if (testSet.contains(TerminalTestScenario.ALL_SEQUENTIAL)) {
-                // This may forEach or tryAdvance depending on the terminal op implementation
-                S_OUT source = streamF.apply(data.stream());
-                R result = terminalF.apply(source);
-                LambdaTestHelpers.launderAssertion(() -> resultAsserter.assertResult(result, refResult, isOrdered, false),
-                                                   () -> String.format("All sequential: %s != %s", refResult, result));
-            }
+            for (BaseTerminalTestScenario test : tests) {
+                S_OUT source;
+                if (test.requiresSingleStageSource()) {
+                    source = (S_OUT) createPipeline(shape, node.spliterator(),
+                                                    StreamOpFlag.IS_ORDERED | StreamOpFlag.IS_SIZED,
+                                                    test.requiresParallelSource());
+                }
+                else {
+                    source = streamF.apply(test.requiresParallelSource()
+                                           ? data.parallelStream() : data.stream());
+                }
 
-            if (testSet.contains(TerminalTestScenario.ALL_SEQUENTIAL_SHORT_CIRCUIT)) {
-                S_OUT source = streamF.apply(data.stream());
-                // Force short-circuit
-                source = (S_OUT) chain(source, new ShortCircuitOp<U>(shape));
-                R result = terminalF.apply(source);
-                LambdaTestHelpers.launderAssertion(() -> resultAsserter.assertResult(result, refResult, isOrdered, false),
-                                                   () -> String.format("All sequential pull: %s != %s", refResult, result));
-            }
+                R result = (R) test.run(terminalF, source, shape);
 
-            if (testSet.contains(TerminalTestScenario.ALL_PARALLEL)) {
-                S_OUT source = streamF.apply(data.parallelStream());
-                R result = terminalF.apply(source);
-                LambdaTestHelpers.launderAssertion(() -> resultAsserter.assertResult(result, refResult, isOrdered, true),
-                                                   () -> String.format("All parallel: %s != %s", refResult, result));
-            }
-
-            if (testSet.contains(TerminalTestScenario.ALL_PARALLEL_SEQUENTIAL)) {
-                S_OUT source = streamF.apply(data.parallelStream());
-                R result = terminalF.apply(source.sequential());
-                LambdaTestHelpers.launderAssertion(() -> resultAsserter.assertResult(result, refResult, isOrdered, false),
-                                                   () -> String.format("All parallel then sequential: %s != %s", refResult, result));
+                LambdaTestHelpers.launderAssertion(
+                        () -> resultAsserter.assertResult(result, refResult, isOrdered, test.requiresParallelSource()),
+                        () -> String.format("%s: %s != %s", test, refResult, result));
             }
 
             return refResult;
@@ -596,10 +591,10 @@
 
     // Test data
 
-    private class ShortCircuitOp<T> implements StatelessTestOp<T,T> {
+    static class ShortCircuitOp<T> implements StatelessTestOp<T,T> {
         private final StreamShape shape;
 
-        private ShortCircuitOp(StreamShape shape) {
+        ShortCircuitOp(StreamShape shape) {
             this.shape = shape;
         }
 
--- a/test/java/util/stream/bootlib/java/util/stream/StreamTestDataProvider.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/test/java/util/stream/bootlib/java/util/stream/StreamTestDataProvider.java	Wed Aug 14 15:53:13 2013 -0700
@@ -96,8 +96,14 @@
                 list.add(streamDataDescr("DelegatingStream(ArrayList):" + name,
                                          () -> new ArrayList<>(intsAsList).stream()));
                 List<Integer> aList = new ArrayList<>(intsAsList);
-                list.add(collectionDataDescr("ArrayList.Sublist:" + name,
-                                             (ints.length) <= 1 ? aList.subList(0, 0) : aList.subList(1, ints.length / 2)));
+                if (LambdaTestMode.isNormalMode()) {
+                    // Only include sub-lists for normal test execution mode
+                    // This data is serialization-hostile since the state of the
+                    // deserialized sub-list will be out of sync with the
+                    // enclosing list.
+                    list.add(collectionDataDescr("ArrayList.Sublist:" + name,
+                                                 (ints.length) <= 1 ? aList.subList(0, 0) : aList.subList(1, ints.length / 2)));
+                }
                 list.add(collectionDataDescr("LinkedList:" + name, new LinkedList<>(intsAsList)));
                 list.add(collectionDataDescr("HashSet:" + name, new HashSet<>(intsAsList)));
                 list.add(collectionDataDescr("LinkedHashSet:" + name, new LinkedHashSet<>(intsAsList)));
--- a/test/java/util/stream/bootlib/java/util/stream/StreamTestScenario.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/test/java/util/stream/bootlib/java/util/stream/StreamTestScenario.java	Wed Aug 14 15:53:13 2013 -0700
@@ -39,7 +39,7 @@
 @SuppressWarnings({"rawtypes", "unchecked"})
 public enum StreamTestScenario implements OpTestCase.BaseStreamTestScenario {
 
-    STREAM_FOR_EACH(false) {
+    STREAM_FOR_EACH_WITH_CLOSE(false) {
         <T, U, S_IN extends BaseStream<T, S_IN>>
         void _run(TestData<T, S_IN> data, Consumer<U> b, Function<S_IN, Stream<U>> m) {
             Stream<U> s = m.apply(data.stream());
@@ -47,6 +47,7 @@
                 s = s.sequential();
             }
             s.forEach(b);
+            s.close();
         }
     },
 
--- a/test/java/util/stream/boottest/java/util/stream/SliceSpliteratorTest.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/test/java/util/stream/boottest/java/util/stream/SliceSpliteratorTest.java	Wed Aug 14 15:53:13 2013 -0700
@@ -131,7 +131,7 @@
 
                 SpliteratorTestHelper.testSpliterator(() -> {
                     Spliterator<Integer> s = Arrays.spliterator(source.stream().toArray(Integer[]::new));
-
+                    
                     return new StreamSpliterators.UnorderedSliceSpliterator.OfRef<>(s, skip, limit);
                 }, uca);
             };
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/stream/test/org/openjdk/tests/java/lang/invoke/GenBadMHTest.java	Wed Aug 14 15:53:13 2013 -0700
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.openjdk.tests.java.lang.invoke;
+
+import jdk.internal.org.objectweb.asm.ClassWriter;
+import jdk.internal.org.objectweb.asm.Handle;
+import jdk.internal.org.objectweb.asm.MethodVisitor;
+import jdk.internal.org.objectweb.asm.Opcodes;
+import org.testng.annotations.Test;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandleInfo;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Supplier;
+
+import static jdk.internal.org.objectweb.asm.Opcodes.*;
+import static jdk.internal.org.objectweb.asm.Opcodes.PUTFIELD;
+import static jdk.internal.org.objectweb.asm.Opcodes.RETURN;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+
+/**
+ * Regression test to ensure that the VM does not report invokevirtual method handles as invokespecial
+ */
+@Test(groups = { "serialization-hostile" })
+public class GenBadMHTest {
+    public void testMHForStringToUpper() throws IOException, ReflectiveOperationException {
+        MethodHandle mh = mhFor(Opcodes.H_INVOKEVIRTUAL, "java/lang/String", "toUpperCase", "()Ljava/lang/String;");
+        MethodHandleInfo mhi = new MethodHandleInfo(mh);
+        assertTrue(mhi.getReferenceKind() == MethodHandleInfo.REF_invokeVirtual);
+    }
+
+    public void testMHForAtomicLong() throws IOException, ReflectiveOperationException {
+        MethodHandle mh = mhFor(Opcodes.H_INVOKEVIRTUAL, "java/util/concurrent/atomic/AtomicLong", "addAndGet", "(J)J");
+        MethodHandleInfo mhi = new MethodHandleInfo(mh);
+        assertTrue(mhi.getReferenceKind() == MethodHandleInfo.REF_invokeVirtual);
+    }
+
+    private MethodHandle mhFor(int kind, String host, String method, String sig) throws IOException, ReflectiveOperationException {
+        ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
+        cw.visit(51, ACC_SUPER + ACC_PUBLIC, "Foo", null, "java/lang/Object", new String[0]);
+
+        // Constructor
+        MethodVisitor ctor = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
+        ctor.visitCode();
+        ctor.visitVarInsn(ALOAD, 0);
+        ctor.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V");
+        ctor.visitInsn(RETURN);
+        ctor.visitMaxs(-1, -1);
+        ctor.visitEnd();
+
+        MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "foo", "()Ljava/lang/Object;", null, null);
+        mv.visitLdcInsn(new Handle(kind, host, method, sig));
+        mv.visitInsn(ARETURN);
+        mv.visitMaxs(-1, -1);
+        mv.visitEnd();
+
+        cw.visitEnd();
+
+        byte[] bytes = cw.toByteArray();
+        File f = new File("Foo.class");
+        try (FileOutputStream fos = new FileOutputStream(f)) {
+            fos.write(bytes);
+        }
+
+        List<URL> list = new ArrayList<>();
+        list.add(new URL("file:" + f.getCanonicalFile().getParent().replace("\\", "/") + "/"));
+        Class<?> clazz = Class.forName("Foo", true, new URLClassLoader(list.toArray(new URL[list.size()])));
+        Method m = clazz.getMethod("foo");
+        return (MethodHandle) m.invoke(clazz.newInstance());
+    }
+
+    public void testPrivateInnerCtorRef() {
+        Supplier<Object> ctor = new Enclosing().foo();
+        Enclosing.Inner inner = (Enclosing.Inner) ctor.get();
+        assertNotNull(inner);
+    }
+
+    static class Enclosing {
+
+        public Supplier<Object> foo() {
+            return Inner::new;
+        }
+
+        private class Inner {
+            private Inner() {}
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/stream/test/org/openjdk/tests/java/util/SplittableRandomTest.java	Wed Aug 14 15:53:13 2013 -0700
@@ -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<T> implements Spliterator<T> {
+        final SplittableRandom rng;
+        long index;
+        final long fence;
+        final Function<SplittableRandom, T> rngF;
+
+        RandomBoxedSpliterator(SplittableRandom rng, long index, long fence, Function<SplittableRandom, T> rngF) {
+            this.rng = rng;
+            this.index = index;
+            this.fence = fence;
+            this.rngF = rngF;
+        }
+
+        public RandomBoxedSpliterator<T> 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<? super T> 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 <T extends Comparable<T>> ResultAsserter<Iterable<T>> randomAsserter(int size, T origin, T bound) {
+        return (act, exp, ord, par) -> {
+            int count = 0;
+            Set<Comparable<T>> values = new HashSet<>();
+            for (Comparable<T> 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<Object[]> data = new ArrayList<>();
+
+        // Function to create a stream using a RandomBoxedSpliterator
+
+        Function<Function<SplittableRandom, Integer>, 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<Iterable<Integer>> 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<Object[]> data = new ArrayList<>();
+
+        // Function to create a stream using a RandomBoxedSpliterator
+
+        Function<Function<SplittableRandom, Long>, 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<Iterable<Long>> 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<Object[]> data = new ArrayList<>();
+
+        // Function to create a stream using a RandomBoxedSpliterator
+
+        Function<Function<SplittableRandom, Double>, 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<Iterable<Double>> ra) {
+        withData(data).
+                stream(s -> s).
+                without(DoubleStreamTestScenario.PAR_STREAM_TO_ARRAY_CLEAR_SIZED).
+                resultAsserter(ra).
+                exercise();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/stream/test/org/openjdk/tests/java/util/regex/PatternTest.java	Wed Aug 14 15:53:13 2013 -0700
@@ -0,0 +1,140 @@
+/*
+ * 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.regex;
+
+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<String>")
+    public static Object[][] makeStreamTestData() {
+        List<Object[]> data = new ArrayList<>();
+
+        String description = "";
+        String input = "awgqwefg1fefw4vssv1vvv1";
+        Pattern pattern = Pattern.compile("4");
+        List<String> 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<String>
+        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<String>")
+    public void testStrings(String description, String input, Pattern pattern, List<String> expected) {
+        Supplier<Stream<String>> ss =  () -> pattern.splitAsStream(input);
+        withData(TestData.Factory.ofSupplier(description, ss))
+                .stream(LambdaTestHelpers.identity())
+                .expectedResult(expected)
+                .exercise();
+    }
+}
--- a/test/java/util/stream/test/org/openjdk/tests/java/util/stream/ExplodeOpTest.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/test/java/util/stream/test/org/openjdk/tests/java/util/stream/ExplodeOpTest.java	Wed Aug 14 15:53:13 2013 -0700
@@ -64,6 +64,9 @@
         result = exerciseOps(data, s -> s.flatMap(mfNull));
         assertEquals(0, result.size());
 
+        result = exerciseOps(data, s-> s.flatMap(e -> Stream.empty()));
+        assertEquals(0, result.size());
+
         exerciseOps(data, s -> s.flatMap(mfLt));
         exerciseOps(data, s -> s.flatMap(integerRangeMapper));
         exerciseOps(data, s -> s.flatMap((Integer e) -> IntStream.range(0, e).boxed().limit(10)));
--- a/test/java/util/stream/test/org/openjdk/tests/java/util/stream/ForEachOpTest.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/test/java/util/stream/test/org/openjdk/tests/java/util/stream/ForEachOpTest.java	Wed Aug 14 15:53:13 2013 -0700
@@ -69,7 +69,7 @@
         };
     }
 
-    @Test
+    @Test(groups = { "serialization-hostile" })
     public void testForEachOrdered() {
         List<Integer> input = countTo(10000);
         TestData.OfRef<Integer> data = TestData.Factory.ofCollection("[1, 10000]", input);
@@ -116,7 +116,7 @@
 
     //
 
-    @Test
+    @Test(groups = { "serialization-hostile" })
     public void testIntForEachOrdered() {
         List<Integer> input = countTo(10000);
         TestData.OfInt data = TestData.Factory.ofIntSupplier("[1, 10000]",
@@ -164,7 +164,7 @@
 
     //
 
-    @Test
+    @Test(groups = { "serialization-hostile" })
     public void testLongForEachOrdered() {
         List<Integer> input = countTo(10000);
         TestData.OfLong data = TestData.Factory.ofLongSupplier("[1, 10000]",
@@ -212,7 +212,7 @@
 
     //
 
-    @Test
+    @Test(groups = { "serialization-hostile" })
     public void testDoubleForEachOrdered() {
         List<Integer> input = countTo(10000);
         TestData.OfDouble data = TestData.Factory.ofDoubleSupplier("[1, 10000]",
--- a/test/java/util/stream/test/org/openjdk/tests/java/util/stream/SliceOpTest.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/test/java/util/stream/test/org/openjdk/tests/java/util/stream/SliceOpTest.java	Wed Aug 14 15:53:13 2013 -0700
@@ -147,7 +147,8 @@
         return Math.max(0, dataSize - skip);
     }
 
-    @Test(dataProvider = "StreamTestData<Integer>", dataProviderClass = StreamTestDataProvider.class)
+    @Test(dataProvider = "StreamTestData<Integer>", dataProviderClass = StreamTestDataProvider.class,
+          groups = { "serialization-hostile" })
     public void testSkipOps(String name, TestData.OfRef<Integer> data) {
         List<Integer> skips = sizes(data.size());
 
@@ -169,7 +170,8 @@
         }
     }
 
-    @Test(dataProvider = "StreamTestData<Integer>", dataProviderClass = StreamTestDataProvider.class)
+    @Test(dataProvider = "StreamTestData<Integer>", dataProviderClass = StreamTestDataProvider.class,
+          groups = { "serialization-hostile" })
     public void testSkipLimitOps(String name, TestData.OfRef<Integer> data) {
         List<Integer> skips = sizes(data.size());
         List<Integer> limits = skips;
@@ -242,7 +244,8 @@
         testSkipLimitOps("testSkipLimitOpsWithNonSplittingSpliterator", data);
     }
 
-    @Test(dataProvider = "StreamTestData<Integer>", dataProviderClass = StreamTestDataProvider.class)
+    @Test(dataProvider = "StreamTestData<Integer>", dataProviderClass = StreamTestDataProvider.class,
+          groups = { "serialization-hostile" })
     public void testLimitOps(String name, TestData.OfRef<Integer> data) {
         List<Integer> limits = sizes(data.size());
 
--- a/test/java/util/stream/test/org/openjdk/tests/java/util/stream/StreamBuilderTest.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/test/java/util/stream/test/org/openjdk/tests/java/util/stream/StreamBuilderTest.java	Wed Aug 14 15:53:13 2013 -0700
@@ -97,7 +97,7 @@
         checkISE(() -> sb.build());
     }
 
-    @Test(dataProvider = "sizes")
+    @Test(dataProvider = "sizes", groups = { "serialization-hostile" })
     public void testStreamBuilder(int size) {
         testStreamBuilder(size, (s) -> {
             Stream.Builder<Integer> sb = Stream.builder();
@@ -159,7 +159,7 @@
         checkISE(() -> sb.build());
     }
 
-    @Test(dataProvider = "sizes")
+    @Test(dataProvider = "sizes", groups = { "serialization-hostile" })
     public void testIntStreamBuilder(int size) {
         testIntStreamBuilder(size, (s) -> {
             IntStream.Builder sb = IntStream.builder();
@@ -221,7 +221,7 @@
         checkISE(() -> sb.build());
     }
 
-    @Test(dataProvider = "sizes")
+    @Test(dataProvider = "sizes", groups = { "serialization-hostile" })
     public void testLongStreamBuilder(int size) {
         testLongStreamBuilder(size, (s) -> {
             LongStream.Builder sb = LongStream.builder();
@@ -282,7 +282,7 @@
         checkISE(() -> sb.build());
     }
 
-    @Test(dataProvider = "sizes")
+    @Test(dataProvider = "sizes", groups = { "serialization-hostile" })
     public void testDoubleStreamBuilder(int size) {
         testDoubleStreamBuilder(size, (s) -> {
             DoubleStream.Builder sb = DoubleStream.builder();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/stream/test/org/openjdk/tests/java/util/stream/StreamCloseTest.java	Wed Aug 14 15:53:13 2013 -0700
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  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 org.openjdk.tests.java.util.stream;
+
+import java.util.Arrays;
+import java.util.stream.OpTestCase;
+import java.util.stream.Stream;
+
+import org.testng.annotations.Test;
+
+import static java.util.stream.LambdaTestHelpers.countTo;
+
+/**
+ * StreamCloseTest
+ *
+ * @author Brian Goetz
+ */
+@Test(groups = { "serialization-hostile" })
+public class StreamCloseTest extends OpTestCase {
+    public void testEmptyCloseHandler() {
+        try (Stream<Integer> ints = countTo(100).stream()) {
+            ints.forEach(i -> {});
+        }
+    }
+
+    public void testOneCloseHandler() {
+        final boolean[] holder = new boolean[1];
+        Runnable closer = () -> { holder[0] = true; };
+
+        try (Stream<Integer> ints = countTo(100).stream()) {
+            ints.onClose(closer);
+            ints.forEach(i -> {});
+        }
+        assertTrue(holder[0]);
+
+        Arrays.fill(holder, false);
+        try (Stream<Integer> ints = countTo(100).stream().onClose(closer)) {
+            ints.forEach(i -> {});
+        }
+        assertTrue(holder[0]);
+
+        Arrays.fill(holder, false);
+        try (Stream<Integer> ints = countTo(100).stream().filter(e -> true).onClose(closer)) {
+            ints.forEach(i -> {});
+        }
+        assertTrue(holder[0]);
+
+        Arrays.fill(holder, false);
+        try (Stream<Integer> ints = countTo(100).stream().filter(e -> true).onClose(closer).filter(e -> true)) {
+            ints.forEach(i -> {});
+        }
+        assertTrue(holder[0]);
+    }
+
+    public void testTwoCloseHandlers() {
+        final boolean[] holder = new boolean[2];
+        Runnable close1 = () -> { holder[0] = true; };
+        Runnable close2 = () -> { holder[1] = true; };
+
+        try (Stream<Integer> ints = countTo(100).stream()) {
+            ints.onClose(close1).onClose(close2);
+            ints.forEach(i -> {});
+        }
+        assertTrue(holder[0] && holder[1]);
+
+        Arrays.fill(holder, false);
+        try (Stream<Integer> ints = countTo(100).stream().onClose(close1).onClose(close2)) {
+            ints.forEach(i -> {});
+        }
+        assertTrue(holder[0] && holder[1]);
+
+        Arrays.fill(holder, false);
+        try (Stream<Integer> ints = countTo(100).stream().filter(e -> true).onClose(close1).onClose(close2)) {
+            ints.forEach(i -> {});
+        }
+        assertTrue(holder[0] && holder[1]);
+
+        Arrays.fill(holder, false);
+        try (Stream<Integer> ints = countTo(100).stream().filter(e -> true).onClose(close1).onClose(close2).filter(e -> true)) {
+            ints.forEach(i -> {});
+        }
+        assertTrue(holder[0] && holder[1]);
+    }
+
+    public void testCascadedExceptions() {
+        final boolean[] holder = new boolean[3];
+        boolean caught = false;
+        Runnable close1 = () -> { holder[0] = true; throw new RuntimeException("1"); };
+        Runnable close2 = () -> { holder[1] = true; throw new RuntimeException("2"); };
+        Runnable close3 = () -> { holder[2] = true; throw new RuntimeException("3"); };
+
+        try (Stream<Integer> ints = countTo(100).stream()) {
+            ints.onClose(close1).onClose(close2).onClose(close3);
+            ints.forEach(i -> {});
+        }
+        catch (RuntimeException e) {
+            assertCascaded(e, 3);
+            assertTrue(holder[0] && holder[1] && holder[2]);
+            caught = true;
+        }
+        assertTrue(caught);
+
+        Arrays.fill(holder, false);
+        caught = false;
+        try (Stream<Integer> ints = countTo(100).stream().onClose(close1).onClose(close2).onClose(close3)) {
+            ints.forEach(i -> {});
+        }
+        catch (RuntimeException e) {
+            assertCascaded(e, 3);
+            assertTrue(holder[0] && holder[1] && holder[2]);
+            caught = true;
+        }
+        assertTrue(caught);
+
+        caught = false;
+        Arrays.fill(holder, false);
+        try (Stream<Integer> ints = countTo(100).stream().filter(e -> true).onClose(close1).onClose(close2).onClose(close3)) {
+            ints.forEach(i -> {});
+        }
+        catch (RuntimeException e) {
+            assertCascaded(e, 3);
+            assertTrue(holder[0] && holder[1] && holder[2]);
+            caught = true;
+        }
+        assertTrue(caught);
+
+        caught = false;
+        Arrays.fill(holder, false);
+        try (Stream<Integer> ints = countTo(100).stream().filter(e -> true).onClose(close1).onClose(close2).filter(e -> true).onClose(close3)) {
+            ints.forEach(i -> {});
+        }
+        catch (RuntimeException e) {
+            assertCascaded(e, 3);
+            assertTrue(holder[0] && holder[1] && holder[2]);
+            caught = true;
+        }
+        assertTrue(caught);
+    }
+
+    private void assertCascaded(RuntimeException e, int n) {
+        assertTrue(e.getMessage().equals("1"));
+        assertTrue(e.getSuppressed().length == n - 1);
+        for (int i=0; i<n-1; i++)
+        assertTrue(e.getSuppressed()[i].getMessage().equals(String.valueOf(i + 2)));
+    }
+}
--- a/test/java/util/stream/test/org/openjdk/tests/java/util/stream/TabulatorsTest.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/test/java/util/stream/test/org/openjdk/tests/java/util/stream/TabulatorsTest.java	Wed Aug 14 15:53:13 2013 -0700
@@ -25,6 +25,7 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -52,6 +53,7 @@
 
 import org.testng.annotations.Test;
 
+import static java.util.stream.Collectors.collectingAndThen;
 import static java.util.stream.Collectors.groupingBy;
 import static java.util.stream.Collectors.groupingByConcurrent;
 import static java.util.stream.Collectors.partitioningBy;
@@ -603,4 +605,17 @@
                               new PartitionAssertion<>(classifier,
                                                        new ReduceAssertion<>(0, LambdaTestHelpers.identity(), Integer::sum)));
     }
+
+    @Test(dataProvider = "StreamTestData<Integer>", dataProviderClass = StreamTestDataProvider.class)
+    public void testComposeFinisher(String name, TestData.OfRef<Integer> data) throws ReflectiveOperationException {
+        List<Integer> asList = exerciseTerminalOps(data, s -> s.collect(toList()));
+        List<Integer> asImmutableList = exerciseTerminalOps(data, s -> s.collect(collectingAndThen(toList(), Collections::unmodifiableList)));
+        assertEquals(asList, asImmutableList);
+        try {
+            asImmutableList.add(0);
+            fail("Expecting immutable result");
+        }
+        catch (UnsupportedOperationException ignored) { }
+    }
+
 }
--- a/test/java/util/stream/test/org/openjdk/tests/java/util/stream/ToArrayOpTest.java	Tue Aug 13 10:42:37 2013 -0700
+++ b/test/java/util/stream/test/org/openjdk/tests/java/util/stream/ToArrayOpTest.java	Wed Aug 14 15:53:13 2013 -0700
@@ -165,7 +165,8 @@
         };
     }
 
-    @Test(dataProvider = "StreamTestData<Integer>", dataProviderClass = StreamTestDataProvider.class)
+    @Test(dataProvider = "StreamTestData<Integer>", dataProviderClass = StreamTestDataProvider.class,
+          groups = { "serialization-hostile" })
     public void testStatefulOpPermutations(String name, TestData.OfRef<Integer> data) {
         for (Function<Stream<Integer>, Stream<Integer>> f : statefulOpPermutations) {
             withData(data).terminal(f, s -> s.toArray())
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/lambda/InvokespecialMethodKindTest.java	Wed Aug 14 15:53:13 2013 -0700
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandleInfo;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+import java.util.function.Function;
+
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.assertEquals;
+
+/**
+ * InvokespecialMethodKindTest
+ */
+@Test
+public class InvokespecialMethodKindTest {
+    public void testStringToUpper() throws ReflectiveOperationException {
+        MethodHandle mh = MethodHandles.lookup().findVirtual(String.class, "toUpperCase",
+                                                             MethodType.methodType(String.class));
+        MethodHandleInfo mhi = new MethodHandleInfo(mh);
+        assertEquals(mhi.getReferenceKind(), MethodHandleInfo.REF_invokeVirtual);
+    }
+
+    public void testSerializeStringToUpper() throws IOException, ClassNotFoundException {
+        Function<String, String> f = (Function<String, String> & Serializable) String::toUpperCase;
+        ByteArrayOutputStream bos = new ByteArrayOutputStream();
+        ObjectOutputStream oos = new ObjectOutputStream(bos);
+        oos.writeObject(f);
+        oos.flush();
+        byte[] bs = bos.toByteArray();
+        ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bs));
+        @SuppressWarnings("unchecked")
+        Function<String, String> ff = (Function<String, String>) ois.readObject();
+        assertEquals("FOO", ff.apply("fOo"));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/lambda/TestInterfaceBridges.java	Wed Aug 14 15:53:13 2013 -0700
@@ -0,0 +1,152 @@
+/*
+ * 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.List;
+
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.assertEquals;
+
+/**
+ * TestInterfaceBridges
+ *
+ * @author Brian Goetz
+ */
+@Test
+public class TestInterfaceBridges {
+    public void testCovariantOverrideLambda() {
+        B b = () -> "Foo";
+        assertEquals("Foo", b.make());
+        assertEquals("Foo", ((A) b).make());
+    }
+
+    public void testCovariantOverrideIC() {
+        B b = new B() {
+            @Override
+            public String make() {
+                return "Foo";
+            }
+        };
+        assertEquals("Foo", b.make());
+        assertEquals("Foo", ((A) b).make());
+    }
+
+    public static interface A {
+        Object make();
+    }
+
+    public static interface B extends A {
+        String make();
+    }
+
+    public void testCovariantMerge() {
+        D d = () -> "Foo";
+        assertEquals("Foo", d.make());
+        assertEquals("Foo", ((A) d).make());
+        assertEquals("Foo", ((C) d).make());
+    }
+
+    public static interface C {
+        String make();
+    }
+
+    public static interface D extends A, C { }
+
+    public void testGenericSpecialization() {
+        F<String, String> fss = x->x;
+        assertEquals("Foo", fss.m("Foo"));
+    }
+
+    interface F<A,B> {
+        B m(A a);
+    }
+
+    public void testGenericFboundSpecialization() {
+        G<String> gs = x->x;
+        assertEquals("Foo", gs.m("Foo"));
+    }
+
+    interface G<X extends Comparable<X>> {
+       X m(X x);
+    }
+
+    public void testGenericSpecializationInSubclass() {
+        F_S_S fss = (s)->s;
+        assertEquals("Foo", fss.m("Foo"));
+        assertEquals("Foo", ((F<String,String>)fss).m("Foo"));
+    }
+
+    interface F_S_S extends F<String,String> {}
+
+    public void testCovariantMultiMerge() {
+        M1234 m1234 = ()->1;
+        assertEquals(1, (int)m1234.m());
+        assertEquals(1, (int)((M1)m1234).m());
+        assertEquals(1, (int)((M2)m1234).m());
+        assertEquals(1, (int)((M3)m1234).m());
+        assertEquals(1, (int)((M4)m1234).m());
+    }
+
+    interface M1 {Number m();}
+    interface M2 {Integer m();}
+    interface M3 {java.io.Serializable m();}
+    interface M4 {Object m();}
+
+    interface M1234 extends M1, M2, M3, M4 {}
+
+    public void testDefaultMerge() {
+        DD12<String> dds = s->1;
+        assertEquals(1, ((DD1<String>)dds).m(""));
+        assertEquals(1, ((DD2)dds).m(""));
+    }
+
+    interface DD1<T> { int m(T arg); }
+    interface DD2 { default int m(String arg) { return 42; } }
+    interface DD12<T> extends DD1<T>, DD2 {}
+
+    public void testDefaultNoMerge() {
+        DD12<Integer> dds = s->1;
+        assertEquals(1, ((DD1<Integer>)dds).m(1));
+        assertEquals(42, ((DD2)dds).m(""));
+    }
+
+    public void testRawMerge() {
+        List<String> ls = null;
+        R12 r12 = l->"Foo";
+        assertEquals("Foo", r12.m(ls));
+        assertEquals("Foo", ((R1)r12).m(ls));
+        assertEquals("Foo", ((R2)r12).m(ls));
+    }
+
+    interface R1 {
+        Object m(List<String> ls);
+    }
+
+    @SuppressWarnings("rawtypes")
+    interface R2 {
+        String m(List l);
+    }
+
+    interface R12 extends R1, R2 {}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/lambda/vm/FDSeparateCompilationTest.java	Wed Aug 14 15:53:13 2013 -0700
@@ -0,0 +1,193 @@
+/*
+ * Copyright (c) 2012 Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package vm;
+
+import java.util.ArrayList;
+import java.util.Set;
+
+import org.testng.ITestResult;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.AfterSuite;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+import separate.TestHarness;
+import separate.Compiler;
+import shapegen.ClassCase;
+import shapegen.Hierarchy;
+import shapegen.HierarchyGenerator;
+
+import static org.testng.Assert.fail;
+import static separate.SourceModel.AbstractMethod;
+import static separate.SourceModel.AccessFlag;
+import static separate.SourceModel.Class;
+import static separate.SourceModel.ConcreteMethod;
+import static separate.SourceModel.DefaultMethod;
+import static separate.SourceModel.Interface;
+import static separate.SourceModel.Method;
+import static separate.SourceModel.Type;
+
+public class FDSeparateCompilationTest extends TestHarness {
+
+    private static String EMPTY = "\"\"";
+
+    public FDSeparateCompilationTest() {
+        super(false, true);
+    }
+
+    @DataProvider(name = "allShapes", parallel = true)
+    public Object[][] hierarchyGenerator() {
+        ArrayList<Object[]> allCases = new ArrayList<>();
+
+        HierarchyGenerator hg = new HierarchyGenerator();
+        hg.getOK().stream().map(x->new Object[]{x}).forEach(allCases::add);
+        hg.getErr().stream().map(x -> new Object[] { x }).forEach(allCases::add);
+        return allCases.toArray(new Object[0][]);
+    }
+
+    // The expected value obtained when invoking the method from the specified 
+    // class.  If returns null, then an AbstractMethodError is expected.
+    private static String getExpectedResult(ClassCase cc) {
+        Set<ClassCase> provs = cc.get_mprov();
+        if (cc.get_mres() != null) {
+            return cc.get_mres().getName();
+        } else if (provs != null && provs.size() == 1) {
+            ClassCase cand = provs.iterator().next();
+            switch (cand.kind) {
+                case CCONCRETE:
+                case IDEFAULT:
+                    return cand.getName();
+                case CNONE:
+                case IVAC:
+                    return getExpectedResult(cand);
+            }
+        } 
+        return null;
+    }
+
+    private static final ConcreteMethod canonicalMethod = new ConcreteMethod(
+            "String", "m", "returns " + EMPTY + ";", AccessFlag.PUBLIC);
+
+    @Test(groups = "vm", dataProvider = "allShapes")
+    public void separateCompilationTest(Hierarchy hs) {
+        ClassCase cc = hs.root;
+        Type type = sourceTypeFrom(hs.root);
+
+        Class specimen = null;
+        if (type instanceof Class) {
+            Class ctype = (Class)type;
+            if (ctype.isAbstract()) {
+                specimen = new Class("Test" + ctype.getName(), ctype);
+            } else {
+                specimen = ctype;
+            }
+        } else {
+            specimen = new Class("Test" + type.getName(), (Interface)type);
+        }
+
+        String value = getExpectedResult(cc);
+        if (value != null) {
+            assertInvokeVirtualEquals(value, specimen, canonicalMethod, EMPTY);
+        } else {
+            assertThrows(AbstractMethodError.class, specimen, 
+                canonicalMethod, EMPTY);
+        }
+    }
+
+    @AfterMethod 
+    public void printCaseError(ITestResult result) {
+        if (result.getStatus() == ITestResult.FAILURE) {
+            Hierarchy hs = (Hierarchy)result.getParameters()[0];
+            System.out.println("Separate compilation case " + hs);
+            printCaseDetails(hs);
+        }
+    }
+
+    @AfterSuite
+    public void cleanupCompilerCache() {
+        Compiler.purgeCache();
+    }
+
+    private void printCaseDetails(Hierarchy hs) {
+        String exp = getExpectedResult(hs.root);
+        hs.getDescription().forEach(
+                x -> System.out.println("    " + x));
+        if (exp != null) { 
+            System.out.println("    Expected \"" + exp + "\"");
+        } else {
+            System.out.println("    Expected AbstractMethodError");
+        }
+    }
+
+    private Type sourceTypeFrom(ClassCase cc) {
+        Type type = null;
+
+        if (cc.isInterface()) {
+            Interface iface = new Interface(cc.getName());
+            for (ClassCase scc : cc.getInterfaces()) {
+                Interface supertype = (Interface)sourceTypeFrom(scc);
+                iface.addSuperType(supertype);
+            }
+            type = iface;
+        } else {
+            Class cls = new Class(cc.getName());
+            if (cc.hasSuperclass()) {
+                Class superc = (Class)sourceTypeFrom(cc.getSuperclass());
+                cls.setSuperClass(superc);
+            }
+            for (ClassCase scc : cc.getInterfaces()) {
+                Interface supertype = (Interface)sourceTypeFrom(scc);
+                cls.addSuperType(supertype);
+            }
+            if (cc.isAbstract()) { 
+                cls.getAccessFlags().add(AccessFlag.ABSTRACT);  
+            }
+            type = cls;
+        }
+        Method method = methodFrom(cc);
+        if (method != null) {
+            type.addMethod(method);
+        }
+        return type;
+    }
+
+    private Method methodFrom(ClassCase cc) {
+        switch (cc.kind) {
+            case IVAC: 
+            case CNONE: return null; 
+            case IPRESENT: 
+            case CABSTRACT:
+                return new AbstractMethod("String", "m", AccessFlag.PUBLIC); 
+            case IDEFAULT:
+                return new DefaultMethod(
+                    "String", "m", "return \"" + cc.getName() + "\";");
+            case CCONCRETE:
+                return new ConcreteMethod(
+                    "String", "m", "return \"" + cc.getName() + "\";", 
+                    AccessFlag.PUBLIC);
+            default:
+                fail("Unknown method type in class");
+                return null;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/lambda/vm/JVMBridgingTest.java	Wed Aug 14 15:53:13 2013 -0700
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2012 Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package vm;
+
+import org.testng.annotations.Test;
+import separate.AttributeInjector;
+import separate.Compiler;
+import separate.TestHarness;
+
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
+import static separate.SourceModel.AbstractMethod;
+import static separate.SourceModel.AccessFlag;
+import static separate.SourceModel.Class;
+import static separate.SourceModel.ConcreteMethod;
+import static separate.SourceModel.Interface;
+import static separate.SourceModel.MethodParameter;
+import static separate.SourceModel.Type;
+import static separate.SourceModel.TypeParameter;
+
+public class JVMBridgingTest extends TestHarness {
+    public JVMBridgingTest() {
+        super(false, false);
+    }
+
+    private static final String STATIC_CLASS = "S";
+    private static final String STATIC_METHOD_NAME = "foo";
+    private static final int SUCCESS_VALUE = 99;
+
+    enum BridgeMode { AUTO_BRIDGE, NO_AUTO_BRIDGE };
+
+    private boolean equalsSuccessValue(
+            BridgeMode mode, Type[] compUnits) {
+        Compiler compiler = new Compiler();
+
+        if (mode == BridgeMode.AUTO_BRIDGE) {
+            compiler.addPostprocessor(
+                new AttributeInjector("RequiresBridges", new byte[0]));
+        }
+
+        ClassLoader cl = compiler.compile(compUnits);
+
+        try {
+            java.lang.Class<?> S_class = 
+                java.lang.Class.forName(STATIC_CLASS, true, cl);
+            assertNotNull(S_class); 
+            java.lang.reflect.Method m = S_class.getMethod(STATIC_METHOD_NAME);
+            assertNotNull(m); 
+            Integer res = (Integer)m.invoke(null);
+            return res.intValue() == SUCCESS_VALUE;
+        } catch (ClassNotFoundException e) {
+            fail("Could not find class");
+        } catch (NoSuchMethodException e) {
+            fail("Could not find method");
+        } catch (IllegalAccessException e) {
+            fail("Unexpected IllegalAccessException");
+        } catch (java.lang.reflect.InvocationTargetException e) {
+            return false; /* A valid situation: the method may not exist */
+        } finally {
+            compiler.cleanup();
+        }
+        fail("Unexpected result");
+        return false; // unreachable
+    }
+
+    public Type[] setupTraditionalBridgeTest() {
+        Interface I = new Interface("I", new TypeParameter("T"), 
+            new AbstractMethod("int", "m", new MethodParameter("T", "t")));
+        Class C = new Class("C", I.with("String"), new ConcreteMethod(
+            "int", "m", "return " + SUCCESS_VALUE + ";", AccessFlag.PUBLIC, 
+            new MethodParameter("String", "s")));
+        ConcreteMethod mStub = new ConcreteMethod(
+            "int", "m", "return 0;", AccessFlag.PUBLIC, 
+            new MethodParameter("Object", "o"));
+        Class Cstub = new Class("C", mStub);
+        Class S = new Class(STATIC_CLASS, new ConcreteMethod(
+            "int", STATIC_METHOD_NAME, "return (new C()).m(\"\");",
+            AccessFlag.PUBLIC, AccessFlag.STATIC));
+        S.addCompilationDependency(Cstub);
+        S.addCompilationDependency(mStub);
+        
+        return new Type[] { S, C, I };
+    }
+
+    private void runTest(Type[] compUnits) {
+        assertFalse(equalsSuccessValue(BridgeMode.NO_AUTO_BRIDGE, compUnits));
+        assertTrue(equalsSuccessValue(BridgeMode.AUTO_BRIDGE, compUnits));
+    }
+
+    @Test(groups = "vm_prototype")
+    public void testTraditionalBridge() {
+        runTest(setupTraditionalBridgeTest());
+    }
+
+    public Type[] setupCovarReturnTest() {
+        ConcreteMethod numberRet = new ConcreteMethod(
+            "Number", "m", "return 0;", AccessFlag.PUBLIC);
+        Class C = new Class("C", numberRet);
+        Class D = new Class("D", C, new ConcreteMethod("Integer", "m", 
+            "return " + SUCCESS_VALUE + ";", AccessFlag.PUBLIC)); 
+
+        Class Dstub = new Class("D", numberRet);
+        Class S = new Class(STATIC_CLASS, 
+            new ConcreteMethod("Integer", STATIC_METHOD_NAME, 
+                "return (Integer)(new D()).m();", 
+                AccessFlag.PUBLIC, AccessFlag.STATIC));
+        S.addCompilationDependency(Dstub);
+        S.addCompilationDependency(numberRet);
+ 
+        return new Type[] { S, D, C };
+    }
+
+    @Test(groups = "vm_prototype")
+    public void testCovarReturn() {
+        runTest(setupCovarReturnTest());
+    }
+
+    @Test(groups = "vm")
+    public void testNoBridgeNeeded() {
+        Interface I = new Interface("I", new TypeParameter("T"), 
+            new AbstractMethod("int", "m", new MethodParameter("T", "t")));
+
+        ConcreteMethod implementing = new ConcreteMethod("int", "m", 
+            "return 0;", AccessFlag.PUBLIC, new MethodParameter("String", "s"));
+        ConcreteMethod matching = new ConcreteMethod("int", "m", "return 99;", 
+            AccessFlag.PUBLIC, new MethodParameter("Object", "o"));
+
+        Class C = new Class("C", I.with("String"), implementing, matching);
+
+        Class S = new Class(STATIC_CLASS, new ConcreteMethod(
+            "int", STATIC_METHOD_NAME, "return (new C()).m(new Object());",
+            AccessFlag.PUBLIC, AccessFlag.STATIC));
+        S.addCompilationDependency(C);
+        S.addCompilationDependency(matching);
+        
+        Type[] compUnits = new Type[] { S, C, I };
+        assertTrue(equalsSuccessValue(BridgeMode.AUTO_BRIDGE, compUnits));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sqeutil/LambdaUtilities.java	Wed Aug 14 15:53:13 2013 -0700
@@ -0,0 +1,674 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @summary This class provide basic support for lambda syntax
+ * @(#) LambdaUtilities.java
+ * @author Tristan Yan
+ */
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.math.BigDecimal;
+import java.nio.file.Path;
+import java.util.*;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.*;
+import java.util.stream.IntStream;
+import java.util.stream.Stream;
+
+public class LambdaUtilities {
+
+    public static enum CharType {
+        DIGIT, LOWERCASE, UPPERCASE, SPECIAL
+    }
+
+    public static enum StringPredicateType {
+        START_WTIH, NOT_START_WITH, MORE_THAN_LEN, LESS_THAN_LEN
+    }
+
+    public static enum IntOp {
+        ADD, SUBTRACT, MULTIPLY, DIVIDE, MOD
+    }
+
+    public static IntPredicate randomIntPredicate(boolean isUP, int limit) {
+        if (isUP) {
+            return i -> i >= limit;
+        } else {
+            return i -> i < limit;
+        }
+    }
+
+    public static Predicate<Integer> randomIntegerPredicate(boolean isUP, int limit) {
+        if (isUP) {
+            return i -> i >= limit;
+        } else {
+            return i -> i < limit;
+        }
+    }
+
+    public static LongPredicate randomLongPredicate(boolean isUP, long limit) {
+        if (isUP) {
+            return i -> i >= limit;
+        } else {
+            return i -> i < limit;
+        }
+    }
+
+    public static Predicate<Path> startPathPredicate(Path start) {
+        return p -> p.startsWith(start);
+    }
+
+    public static <T> Predicate<T> randomGenericPredicate(boolean isUp, T value, Comparator<T> c) {
+        if (isUp) {
+            return emp -> c.compare(emp, value) >= 0;
+        }else {
+            return emp -> c.compare(emp, value) < 0;
+        }
+    }
+
+    public static Predicate<StringBuilder> randomSBPredicate(StringPredicateType type, String value) {
+        switch (type) {
+            case START_WTIH:
+                return sb -> Character.isDigit(sb.charAt(0));
+            case NOT_START_WITH:
+                return sb -> Character.isLowerCase(sb.charAt(0));
+            case MORE_THAN_LEN:
+                return sb -> Character.isUpperCase(sb.charAt(0));
+            default:
+                return sb -> !Character.isLetterOrDigit(sb.charAt(0));
+        }
+    }
+
+    public static Predicate<? extends CharSequence> randomSBPredicate(CharType startType,
+            boolean first) {
+        switch (startType) {
+            case DIGIT:
+                return sb -> Character.isDigit(sb.charAt(first ? 0 : sb.toString().length() - 1));
+            case LOWERCASE:
+                return sb -> Character.isLowerCase(sb.charAt(first ? 0 : sb.toString().length() - 1));
+            case UPPERCASE:
+                return sb -> Character.isUpperCase(sb.charAt(first ? 0 : sb.toString().length() - 1));
+            default:
+                return sb -> !Character.isLetterOrDigit(sb.charAt(first ? 0 : sb.toString().length() - 1));
+        }
+    }
+
+    public static Predicate<Character> isDigitCharacterPredicate() {
+        return c -> Character.isDigit(c);
+    }
+
+    public static Function<Integer, Integer> posIntegerFunction(boolean isHighest) {
+        if (isHighest) {
+            return i -> Integer.valueOf(new StringBuilder().append(i < 0 ? -i : i).reverse().toString()) % 10;
+        } else {
+            return i -> i % 10 < 0 ? -i % 10 : i % 10;
+        }
+    }
+
+    public static Function<StringBuilder, CharType> sbGenericFunction(boolean isFirst) {
+        if (isFirst)
+            return i -> Character.isAlphabetic(i.charAt(0)) ? (Character.isUpperCase(i.charAt(0)) ? CharType.UPPERCASE : CharType.LOWERCASE) : (Character.isDigit(i.charAt(0)) ? CharType.DIGIT : CharType.SPECIAL);
+            else
+            return i -> Character.isAlphabetic(i.charAt(i.length() - 1)) ? (Character.isUpperCase(i.charAt(i.length() - 1)) ? CharType.UPPERCASE : CharType.LOWERCASE) : (Character.isDigit(i.charAt(i.length() - 1)) ? CharType.DIGIT : CharType.SPECIAL);
+    }
+
+    public static Function<String, Integer> mappingFunction(Map<String, Integer> m, IntOp op, int value) {
+        switch (op) {
+            case ADD:
+                return k -> (value != 0) ? m.get(k) + value : m.get(k);
+            case SUBTRACT:
+                return k -> (value != 0) ? m.get(k) - value : m.get(k);
+            case MULTIPLY:
+                return k -> (value != 0) ? m.get(k) * value : m.get(k);
+            case DIVIDE:
+                return k -> (value != 0) ? m.get(k) / value : m.get(k);
+            default:
+                return k -> (value != 0) ? m.get(k) % value : m.get(k);
+        }
+    }
+
+    public static IntFunction<Integer> posIntFunction(boolean isHighest) {
+        if (isHighest) {
+            return i -> Integer.valueOf(new StringBuilder().append(i < 0 ? -i : i).reverse().toString()) % 10;
+        } else {
+            return i -> i % 10 < 0 ? -i % 10 : i % 10;
+        }
+    }
+
+    public static BiFunction<Integer, Integer, Integer> randBetweenIntegerFunction() {
+        return (t1, t2) -> randBetween(t1, t2);
+    }
+
+    public static int randBetween(int low, int up) {
+        assert (low < up && low >= 0);
+        Random rand = new Random();
+        int i = rand.nextInt(up);
+        while (i < low) {
+            i = rand.nextInt();
+        }
+        return i;
+    }
+
+    public static ToIntFunction<Integer> highestPosValueIntFunction() {
+        return i -> Integer.valueOf(new StringBuilder().append(i < 0 ? -i : i).reverse().toString()) % 10;
+    }
+
+    public static ToIntFunction<Integer> lowestPosValueIntFunction() {
+        return i -> i % 10 < 0 ? -i % 10 : i % 10;
+    }
+
+    public static <T> Consumer<T> reverseConsumer(Set<T> set) {
+        return t -> {
+            set.add(t);
+        };
+    }
+
+    public static Consumer<Integer> addIntegerConsumer(AtomicInteger ai) {
+        return t -> {
+            ai.updateAndGet(t1 -> t1 + t);
+        };
+    }
+
+    public static Consumer<StringBuilder> appendSBConsumer(StringBuilder sb) {
+        return t -> {
+            sb.append(t);
+        };
+    }
+
+    public static IntConsumer addIntConsumer(AtomicInteger ai) {
+        return t -> {
+            ai.updateAndGet(t1 -> t1 + t);
+        };
+    }
+
+    public static IntConsumer addLongConsumer(AtomicLong ai) {
+        return t -> {
+            ai.updateAndGet(t1 -> t1 + t);
+        };
+    }
+
+    public static <T> Consumer<T> copyConsumer(List<T> list) {
+        return t -> {
+            list.add(t);
+        };
+    }
+
+    public static <T> Consumer<T> existsConsumer(Collection<T> in, Collection<T> out) {
+        return t -> {
+            if (in.contains(t)) {
+                out.add(t);
+            }
+        };
+    }
+
+    public static Supplier<StringBuilder> sbSupplier(StringBuilder value) {
+        return () -> value;
+    }
+
+    public static Supplier<Integer> integerSupplier(int value) {
+        return () -> value;
+    }
+
+    public static <T> Supplier<T> genericSuppiler(T value) {
+        return () -> value;
+    }
+
+    public static IntSupplier intSupplier(int value) {
+        return () -> value;
+    }
+
+    public static Supplier<Long> longSupplier(long value) {
+        return () -> value;
+    }
+
+    public static Supplier<AtomicInteger> atomicIntegerSupplier(int value) {
+        return () -> new AtomicInteger(value);
+    }
+
+    public static <T> Supplier<AtomicReference<T>> atomicGenericSupplier(T value) {
+        return () -> new AtomicReference<>(value);
+    }
+
+    public static Supplier<AtomicReference<StringBuilder>> atomicSBSupplier(StringBuilder value) {
+        return () -> new AtomicReference<>(value);
+    }
+
+    public static UnaryOperator<Integer> opIntegerUnaryOperator(IntOp op, int value) {
+        switch (op) {
+            case ADD:
+                return t -> t + value;
+            case SUBTRACT:
+                return t -> t - value;
+            case MULTIPLY:
+                return t -> t * value;
+            case DIVIDE:
+                return t -> t / value;
+            default:
+                return t -> t % value;
+        }
+    }
+
+    public static IntUnaryOperator opIntUnaryOperator(IntOp op, int value) {
+        if(value == 0)
+            return t -> t;
+        switch (op) {
+            case ADD:
+                return t -> t + value;
+            case SUBTRACT:
+                return t -> t - value;
+            case MULTIPLY:
+                return t -> t * value;
+            case DIVIDE:
+                return t -> t / value;
+            default:
+                return t -> t % value;
+        }
+    }
+
+    public static Function<Integer, Integer> opIntegerFunction(IntOp op, int value) {
+        if(value == 0)
+            return t -> t;
+        switch (op) {
+            case ADD:
+                return t -> Integer.valueOf(t + value);
+            case SUBTRACT:
+                return t -> Integer.valueOf(t - value);
+            case MULTIPLY:
+                return t -> Integer.valueOf(t * value);
+            case DIVIDE:
+                return t -> Integer.valueOf(t / value);
+            default:
+                return t -> Integer.valueOf(t % value);
+        }
+    }
+
+    public static ToIntFunction<Integer> opToIntFunction(IntOp op, int value) {
+        if(value == 0)
+            return t -> t.intValue();
+        switch (op) {
+            case ADD:
+                return t -> t.intValue() + value;
+            case SUBTRACT:
+                return t -> t.intValue() - value;
+            case MULTIPLY:
+                return t -> t.intValue() * value;
+            case DIVIDE:
+                return t -> t.intValue() / value;
+            default:
+                return t -> t.intValue() % value;
+        }
+    }
+
+    public static IntFunction<Integer> opIntFunction(IntOp op, int value) {
+        if(value == 0)
+            return t -> t;
+        switch (op) {
+            case ADD:
+                return t -> t + value;
+            case SUBTRACT:
+                return t -> t - value;
+            case MULTIPLY:
+                return t -> t * value;
+            case DIVIDE:
+                return t -> t / value;
+            default:
+                return t -> t % value;
+        }
+    }
+
+    public static IntUnaryOperator addIntUnaryOperator(int value) {
+        return t -> t + value;
+    }
+
+    public static IntUnaryOperator subIntUnaryOperator(int value) {
+        return t -> t - value;
+    }
+
+    public static IntUnaryOperator mulIntUnaryOperator(int value) {
+        return t -> t * value;
+    }
+
+    public static IntUnaryOperator divIntUnaryOperator(int value) {
+        return t -> t / value;
+    }
+
+    public static IntBinaryOperator minIntBinaryOperator() {
+        return (t1, t2) -> t1< t2 ? t1 : t2;
+    }
+
+    public static BinaryOperator<Integer> minIntegerBinaryOperator(Comparator<Integer> c) {
+        return (t1, t2) -> c.compare(t1, t2) < 0 ? t1 : t2;
+    }
+
+    public static <T>BinaryOperator<T> minGenericBinaryOperator(Comparator<T> c) {
+        return (t1, t2) -> c.compare(t1, t2) < 0 ? t1 : t2;
+    }
+
+    public static BinaryOperator<StringBuilder> minSBBinaryOperator(Comparator<StringBuilder>  c) {
+        return ( t1, t2 ) -> c.compare(t1, t2) < 0 ? t1 : t2;
+    }
+
+    public static IntBinaryOperator maxIntBinaryOperator() {
+        return ( t1, t2 ) -> (t1< t2) ? t2: t1;
+    }
+
+    public static BinaryOperator<Integer> maxIntegerBinaryOperator(Comparator<Integer>  c) {
+        return (t1, t2) -> c.compare(t1, t2) < 0 ? t2 : t1;
+    }
+
+    public static <T> BinaryOperator<T> maxGenericBinaryOperator(Comparator<T>  c) {
+        return (t1, t2) -> c.compare(t1, t2) < 0 ? t2 : t1;
+    }
+
+    public static IntBinaryOperator maxIntBinaryOperator(Comparator<Integer>  c) {
+        return ( t1, t2 ) -> c.compare(t1, t2) < 0 ? t2 : t1;
+    }
+
+    public static BinaryOperator<StringBuilder> maxSBBinaryOperator(Comparator<StringBuilder>  c) {
+        return ( t1, t2 ) -> c.compare(t1, t2) < 0 ? t2 : t1;
+    }
+
+    public static BinaryOperator<Integer> addIntegerBinaryOperator() {
+        return ( t1 , t2 ) -> t1 + t2;
+    }
+
+    public static IntBinaryOperator addIntBinaryOperator() {
+        return ( t1 , t2 ) -> t1 + t2;
+    }
+
+    public static BinaryOperator<BigDecimal> addBigDecimalBinaryOperator() {
+        return ( t1 , t2 ) -> t1.add(t2);
+    }
+
+    public static DoubleBinaryOperator addDoubleBinaryOperator() {
+        return ( t1 , t2 ) -> t1 + t2;
+    }
+
+    public static BinaryOperator<StringBuilder> appendSBBinaryOperator() {
+        return (t1 , t2) -> new StringBuilder().append(t1).append(t2);
+    }
+
+    public static BinaryOperator<Integer> subIntegerBinaryOperator() {
+        return (t1, t2) -> t1 - t2;
+    }
+
+    public static IntBinaryOperator subIntBinaryOperator() {
+        return (t1, t2) -> t1 - t2;
+    }
+
+    public static BinaryOperator<StringBuilder> deleteSBBinaryOperator() {
+        return (t1, t2) -> {if (t1.length() >= t2.length()) {
+                                int i1 = t1.indexOf(t2.toString());
+                                int i2 = i1 + t2.length();
+                                return new StringBuilder(t1).delete(i1, i2);
+                            }else {
+                                int i1 = t2.indexOf(t1.toString());
+                                int i2 = i1 + t1.length();
+                                return new StringBuilder(t2).delete(i1, i2);
+                            }
+        };
+
+    }
+
+    public static IntBinaryOperator mulIntBinaryOperator() {
+        return (t1, t2) -> t1 * t2;
+    }
+
+    public static IntBinaryOperator divIntBinaryOperator() {
+        return (t1, t2) -> t1 / t2;
+    }
+
+    public static LongUnaryOperator addLongUnaryOperator(long value) {
+        return t -> t + value;
+    }
+
+    public static UnaryOperator<StringBuilder> appendSBUnaryOperator(StringBuilder value) {
+        return t -> t.append(value);
+    }
+
+    public static LongUnaryOperator subLongUnaryOperator(long value) {
+        return t -> t - value;
+    }
+
+    public static LongUnaryOperator mulLongUnaryOperator(long value) {
+        return t -> t * value;
+    }
+
+    public static LongUnaryOperator divLongUnaryOperator(long value) {
+        return t -> t / value;
+    }
+
+    public static LongBinaryOperator addLongBinaryOperator() {
+        return (t1, t2) -> t1 + t2;
+    }
+
+    public static LongBinaryOperator subLongBinaryOperator() {
+        return (t1, t2) -> t1 - t2;
+    }
+
+    public static LongBinaryOperator mulLongBinaryOperator() {
+        return (t1, t2) -> t1 * t2;
+    }
+
+    public static LongBinaryOperator divLongBinaryOperator() {
+        return (t1, t2) -> t1 / t2;
+    }
+
+    public static BiConsumer<AtomicInteger, Integer> addIntegerBiConsumer() {
+        return (t1 , t2 ) -> {  t1.addAndGet(t2); };
+    }
+
+    public static BiConsumer<AtomicInteger, AtomicInteger> addAtomicIntegerBiConsumer() {
+        return (t1 , t2) -> {  t1.addAndGet(t2.get()); };
+    }
+
+    public static BiConsumer<AtomicReference<StringBuilder>, StringBuilder> appendSBBiConsumer() {
+        return (t1, t2) -> {t1.updateAndGet(appendSBUnaryOperator(t2));};
+    }
+
+    public static BiConsumer<AtomicReference<StringBuilder>, AtomicReference<StringBuilder>> appendAtomicSBBiConsumer() {
+        return (t1, t2) -> {t1.updateAndGet(appendSBUnaryOperator(t2.get()));};
+    }
+
+    public static BiConsumer<AtomicInteger, Integer> maxIntegerBiConsumer(Comparator<Integer> c) {
+        return (t1 , t2 ) -> {  t1.getAndUpdate(t -> max(t, t2, c)); };
+    }
+
+    public static <T> BiConsumer<AtomicReference<T>, T> maxGenericBiConsumer(Comparator<T> c) {
+        return (t1 , t2 ) -> {  t1.getAndUpdate(t -> max(t, t2, c)); };
+    }
+
+    public static BiConsumer<AtomicInteger, AtomicInteger> maxAtomicIntegerBiConsumer(Comparator<Integer> c) {
+        return (t1 , t2) -> {  t1.getAndUpdate(t -> max(t, t2.get(), c)); };
+    }
+
+    public static <T> BiConsumer<AtomicReference<T>, AtomicReference<T>> maxAtomicGenericBiConsumer(Comparator<T> c) {
+        return (t1 , t2) -> {  t1.getAndUpdate(t -> max(t, t2.get(), c)); };
+    }
+
+    public static BiConsumer<AtomicInteger, Integer> minIntegerBiConsumer(Comparator<Integer> c) {
+        return (t1 , t2) -> {  t1.getAndUpdate(t -> min(t, t2, c)); };
+    }
+
+    public static <T> BiConsumer<AtomicReference<T>, T> minGenericBiConsumer(Comparator<T> c) {
+        return (t1 , t2) -> {  t1.getAndUpdate(t -> min(t, t2, c)); };
+    }
+
+    public static BiConsumer<AtomicInteger, AtomicInteger> minAtomicIntegerBiConsumer(Comparator<Integer> c) {
+        return (t1, t2) -> {  t1.getAndUpdate(t -> min(t, t2.get(), c)); };
+    }
+
+    public static <T> BiConsumer<AtomicReference<T>, AtomicReference<T>> minAtomicGenericBiConsumer(Comparator<T> c) {
+        return (t1, t2) -> {  t1.getAndUpdate(t -> min(t, t2.get(), c)); };
+    }
+
+    public static BiFunction<Integer, Integer, Integer> maxIntegerFunction(Comparator<Integer> c) {
+        return (t1, t2) -> max(t1, t2, c);
+    }
+
+    public static BiFunction<BigDecimal, Integer, BigDecimal> deviationSequareFunction(double avg) {
+        return (bd, t) -> bd.add(new BigDecimal(avg - t).pow(2));
+    }
+
+    public static <T> BiFunction<T, T, T> maxGenericFunction(Comparator<T> c) {
+        return (t1, t2) -> max(t1, t2, c);
+    }
+
+    public static BiFunction<StringBuilder, StringBuilder, StringBuilder> maxStringBuilderFunction(Comparator<StringBuilder> c) {
+        return (t1, t2) -> max(t1, t2, c);
+    }
+
+    public static BiFunction<Integer, Integer, Integer> minIntegerFunction(Comparator<Integer> c) {
+        return (t1, t2) -> min(t1, t2, c);
+    }
+
+    public static <T> BiFunction<T, T, T> minGenericFunction(Comparator<T> c) {
+        return (t1, t2) -> min(t1, t2, c);
+    }
+
+    public static BiFunction<StringBuilder, StringBuilder, StringBuilder> minStringBuilderFunction(Comparator<StringBuilder> c) {
+        return (t1, t2) -> min(t1, t2, c);
+    }
+
+    public static BiFunction<String, Integer, Integer> opBiFunction(IntOp op, int value) {
+        switch (op) {
+            case ADD:
+                return (k, v) -> (value != 0) ? v + value : v;
+            case SUBTRACT:
+                return (k, v) -> (value != 0) ? v - value : v;
+            case MULTIPLY:
+                return (k, v) -> (value != 0) ? v * value : v;
+            case DIVIDE:
+                return (k, v) -> (value != 0) ? v / value : v;
+            default:
+                return (k, v) -> (value != 0) ? v % value : v;
+        }
+    }
+
+
+    public static BiFunction<Integer, Integer, Integer> opBiFunction(IntOp op) {
+        switch (op) {
+            case ADD:
+                return (oldv, v) -> (v != 0) ? oldv + v : oldv;
+            case SUBTRACT:
+                return (oldv, v) -> (v != 0) ? oldv - v : oldv;
+            case MULTIPLY:
+                return (oldv, v) -> (v != 0) ? oldv * v : oldv;
+            case DIVIDE:
+                return (oldv, v) -> (v != 0) ? oldv / v : oldv;
+            default:
+                return (oldv, v) -> (v != 0) ? oldv % v : oldv;
+        }
+    }
+
+    private static Integer min(Integer i1, Integer i2, Comparator<Integer> c) {
+        return c.compare(i1, i2) < 0 ? i1 : i2;
+    }
+
+    private static <T> T min(T i1, T i2, Comparator<T> c) {
+        return c.compare(i1, i2) < 0 ? i1 : i2;
+    }
+
+    private static StringBuilder min(StringBuilder sb1, StringBuilder sb2, Comparator<StringBuilder> c) {
+        return c.compare(sb1, sb2) < 0 ? sb1 : sb2;
+    }
+
+    private static Integer max(Integer i1, Integer i2, Comparator<Integer> c) {
+        return c.compare(i1, i2) < 0 ? i2 : i1;
+    }
+
+    private static <T> T max(T i1, T i2, Comparator<T> c) {
+        return c.compare(i1, i2) < 0 ? i2 : i1;
+    }
+
+    private static StringBuilder max(StringBuilder sb1, StringBuilder sb2, Comparator<StringBuilder> c) {
+        return c.compare(sb1, sb2) < 0 ? sb2 : sb1;
+    }
+    /*
+     * Construct a Collection C object based on a C object, using generic type
+     * instead of Class type can help preventing type error in compilation
+     */
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    public static <E, C extends Collection<E>>  C create(C c, int... initSize)
+            throws InstantiationException, IllegalAccessException,
+            NoSuchMethodException, IllegalArgumentException,
+            InvocationTargetException {
+        return create((Class<C>) c.getClass(), initSize);
+    }
+
+    /*
+     * Construct a Collection C object based on a C's type, using generic type
+     * instead of Class type can help preventing type error in compilation
+     */
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    public static <E, T extends Collection<E>>  T create(
+            Class<? extends Collection<E>> cls, int... initSize)
+            throws InstantiationException, IllegalAccessException,
+            NoSuchMethodException, IllegalArgumentException,
+            InvocationTargetException {
+        assert (initSize.length <= 1);
+        Collection<E> c;
+        if (initSize.length == 0) {
+            c = cls.newInstance();
+        } else {
+            Constructor con = cls.getConstructor(int.class);
+            c = (Collection<E>) con.newInstance(initSize[0]);
+        }
+        return (T) c;
+    }
+
+    /*
+     * Construct a T object based on T's type, using generic type instead of
+     * Class type can help preventing type error in compilation
+     */
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    public static <K, V, M extends Map<K, V>>  M createMap(M m, int... initSize)
+            throws InstantiationException, IllegalAccessException,
+            NoSuchMethodException, IllegalArgumentException,
+            InvocationTargetException {
+        return createMap((Class<M>) m.getClass(), initSize);
+    }
+
+    /*
+     * Construct a Map M object based on M's type, using generic type instead of
+     * Class type can help preventing type error in compilation
+     */
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    public static <K, V, M extends Map<K, V>>  M createMap(Class<? extends Map<K, V>> cls,
+            int... initSize) throws InstantiationException,
+            IllegalAccessException, NoSuchMethodException,
+            IllegalArgumentException, InvocationTargetException {
+        assert (initSize.length <= 1);
+        Map<K, V> map;
+        if (initSize.length == 0) {
+            map = cls.newInstance();
+        } else {
+            Constructor con = cls.getConstructor(int.class);
+            map = (Map<K, V>) con.newInstance(initSize[0]);
+        }
+        return (M) map;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sqeutil/StringUtilities.java	Wed Aug 14 15:53:13 2013 -0700
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ *
+ * @summary utilities class supporting common operation for tests.
+ * @(#)StringUtilities.java
+ * @author Tristan Yan
+ * @version 1.0
+ */
+
+import java.util.Random;
+
+public class StringUtilities {
+    private final static Random RANDOM =  new Random(System.currentTimeMillis());
+
+    public static String randomString(int max_length, int min_length){
+        return randomAscii(min_length + RANDOM.nextInt(max_length - min_length));
+    }
+
+    public static String random(int count, int start, int end, boolean letters,
+            boolean numbers, char[] chars, Random rnd) {
+        if (count == 0) {
+            return "";
+        } else if (count < 0) {
+            throw new IllegalArgumentException("Requested random string length " + count + " is less than 0.");
+        }
+        if ((start == 0) && (end == 0)) {
+            end = 'z' + 1;
+            start = ' ';
+            if (!letters && !numbers) {
+                start = 0;
+                end = Integer.MAX_VALUE;
+            }
+        }
+
+        char[] buffer = new char[count];
+        int gap = end - start;
+
+        while (count-- != 0) {
+            char ch;
+            if (chars == null) {
+                ch = (char) (rnd.nextInt(gap) + start);
+            } else {
+                ch = chars[rnd.nextInt(gap) + start];
+            }
+            if ((letters && Character.isLetter(ch))
+                || (numbers && Character.isDigit(ch))
+                || (!letters && !numbers))
+            {
+                if(ch >= 56320 && ch <= 57343) {
+                    if(count == 0) {
+                        count++;
+                    } else {
+                        // low surrogate, insert high surrogate after putting it in
+                        buffer[count] = ch;
+                        count--;
+                        buffer[count] = (char) (55296 + rnd.nextInt(128));
+                    }
+                } else if(ch >= 55296 && ch <= 56191) {
+                    if(count == 0) {
+                        count++;
+                    } else {
+                        // high surrogate, insert low surrogate before putting it in
+                        buffer[count] = (char) (56320 + rnd.nextInt(128));
+                        count--;
+                        buffer[count] = ch;
+                    }
+                } else if(ch >= 56192 && ch <= 56319) {
+                    // private high surrogate, no effing clue, so skip it
+                    count++;
+                } else {
+                    buffer[count] = ch;
+                }
+            } else {
+                count++;
+            }
+        }
+        return new String(buffer);
+    }
+    public static String random(int count) {
+        return random(count, false, false);
+    }
+
+    public static String randomAscii(int count) {
+        return random(count, 32, 127, false, false);
+    }
+
+    public static String randomAlphabetic(int count) {
+        return random(count, true, false);
+    }
+
+    public static String randomAlphanumeric(int count) {
+        return random(count, true, true);
+    }
+
+    public static String randomNumeric(int count) {
+        return random(count, false, true);
+    }
+
+    public static String random(int count, boolean letters, boolean numbers) {
+        return random(count, 0, 0, letters, numbers);
+    }
+
+    public static String random(int count, int start, int end, boolean letters, boolean numbers) {
+        return random(count, start, end, letters, numbers, null, RANDOM);
+    }
+
+    public static String random(int count, int start, int end, boolean letters, boolean numbers, char[] chars) {
+        return random(count, start, end, letters, numbers, chars, RANDOM);
+    }
+}