From 65d83871e2a784c12e9edc3f1115991161b6138f Mon Sep 17 00:00:00 2001 From: Yunda Date: Tue, 23 Jul 2013 14:32:37 +0200 Subject: [PATCH 001/218] 8011888: sa.js: TypeError: [object JSAdapter] has no such function "__has__" Reviewed-by: sla, sundar, kmo --- .../sun/jvm/hotspot/utilities/soql/sa.js | 90 +++++++++++++------ 1 file changed, 62 insertions(+), 28 deletions(-) diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/soql/sa.js b/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/soql/sa.js index ec22e35e633..4253740369b 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/soql/sa.js +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/utilities/soql/sa.js @@ -35,8 +35,9 @@ sapkg.c1 = sapkg.hotspot.c1; sapkg.code = sapkg.hotspot.code; sapkg.compiler = sapkg.hotspot.compiler; -// 'debugger' is a JavaScript keyword :-( -// sapkg.debugger = sapkg.hotspot.debugger; +// 'debugger' is a JavaScript keyword, but ES5 relaxes the +// restriction of using keywords as property name +sapkg.debugger = sapkg.hotspot.debugger; sapkg.interpreter = sapkg.hotspot.interpreter; sapkg.jdi = sapkg.hotspot.jdi; @@ -116,27 +117,36 @@ function main(globals, jvmarg) { return args; } + // Handle __has__ specially to avoid metacircularity problems + // when called from __get__. + // Calling + // this.__has__(name) + // will in turn call + // this.__call__('__has__', name) + // which is not handled below + function __has__(name) { + if (typeof(name) == 'number') { + return so["has(int)"](name); + } else { + if (name == '__wrapped__') { + return true; + } else if (so["has(java.lang.String)"](name)) { + return true; + } else if (name.equals('toString')) { + return true; + } else { + return false; + } + } + } + if (so instanceof sapkg.utilities.soql.ScriptObject) { return new JSAdapter() { - __getIds__: function() { - return so.getIds(); + __getIds__: function() { + return so.getIds(); }, - __has__ : function(name) { - if (typeof(name) == 'number') { - return so["has(int)"](name); - } else { - if (name == '__wrapped__') { - return true; - } else if (so["has(java.lang.String)"](name)) { - return true; - } else if (name.equals('toString')) { - return true; - } else { - return false; - } - } - }, + __has__ : __has__, __delete__ : function(name) { if (typeof(name) == 'number') { @@ -147,7 +157,8 @@ function main(globals, jvmarg) { }, __get__ : function(name) { - if (! this.__has__(name)) { + // don't call this.__has__(name); see comments above function __has__ + if (! __has__.call(this, name)) { return undefined; } if (typeof(name) == 'number') { @@ -162,7 +173,7 @@ function main(globals, jvmarg) { var args = prepareArgsArray(arguments); var r; try { - r = value.call(args); + r = value.call(Java.to(args, 'java.lang.Object[]')); } catch (e) { println("call to " + name + " failed!"); throw e; @@ -204,6 +215,18 @@ function main(globals, jvmarg) { } // define "writeln" and "write" if not defined + if (typeof(println) == 'undefined') { + println = function (str) { + java.lang.System.out.println(String(str)); + } + } + + if (typeof(print) == 'undefined') { + print = function (str) { + java.lang.System.out.print(String(str)); + } + } + if (typeof(writeln) == 'undefined') { writeln = println; } @@ -235,7 +258,7 @@ function main(globals, jvmarg) { this.jclasses = function() { forEachKlass(function (clazz) { - writeln(clazz.getName().asString() + " @" + clazz.getHandle().toString()); + writeln(clazz.getName().asString() + " @" + clazz.getAddress().toString()); }); } registerCommand("classes", "classes", "jclasses"); @@ -490,14 +513,14 @@ function systemLoader() { function forEachKlass(callback) { var VisitorClass = sapkg.memory.SystemDictionary.ClassVisitor; var visitor = new VisitorClass() { visit: callback }; - sa.sysDict["classesDo(sun.jvm.hotspot.memory.SystemDictionary$ClassVisitor)"](visitor); + sa.sysDict["classesDo(sun.jvm.hotspot.memory.SystemDictionary.ClassVisitor)"](visitor); } // iterate system dictionary for each 'Klass' and initiating loader function forEachKlassAndLoader(callback) { var VisitorClass = sapkg.memory.SystemDictionary.ClassAndLoaderVisitor; var visitor = new VisitorClass() { visit: callback }; - sa.sysDict["classesDo(sun.jvm.hotspot.memory.SystemDictionary$ClassAndLoaderVisitor)"](visitor); + sa.sysDict["classesDo(sun.jvm.hotspot.memory.SystemDictionary.ClassAndLoaderVisitor)"](visitor); } // iterate system dictionary for each primitive array klass @@ -522,7 +545,12 @@ function obj2oop(obj) { // iterates Java heap for each Oop function forEachOop(callback) { - sa.objHeap.iterate(new sapkg.oops.HeapVisitor() { doObj: callback }); + function empty() { } + sa.objHeap.iterate(new sapkg.oops.HeapVisitor() { + prologue: empty, + doObj: callback, + epilogue: empty + }); } // iterates Java heap for each Oop of given 'klass'. @@ -536,8 +564,14 @@ function forEachOopOfKlass(callback, klass, includeSubtypes) { if (includeSubtypes == undefined) { includeSubtypes = true; } + + function empty() { } sa.objHeap.iterateObjectsOfKlass( - new sapkg.oops.HeapVisitor() { doObj: callback }, + new sapkg.oops.HeapVisitor() { + prologue: empty, + doObj: callback, + epilogue: empty + }, klass, includeSubtypes); } @@ -746,9 +780,9 @@ while (tmp.itr.hasNext()) { // ignore; continue; } else { - // some type names have ':'. replace to make it as a + // some type names have ':', '<', '>', '*', ' '. replace to make it as a // JavaScript identifier - tmp.name = tmp.name.replace(':', '_').replace('<', '_').replace('>', '_').replace('*', '_').replace(' ', '_'); + tmp.name = ("" + tmp.name).replace(/[:<>* ]/g, '_'); eval("function read" + tmp.name + "(addr) {" + " return readVMType('" + tmp.name + "', addr);}"); eval("function print" + tmp.name + "(addr) {" + From 65cc3fdc8a4111fc5617a9ca04d434152d893d15 Mon Sep 17 00:00:00 2001 From: Attila Szegedi Date: Wed, 7 Aug 2013 16:38:44 +0200 Subject: [PATCH 002/218] 8022509: Various Dynalink security enhancements Reviewed-by: jlaskey, hannesw --- .../internal/dynalink/ChainedCallSite.java | 19 +--- .../dynalink/DynamicLinkerFactory.java | 21 +++- .../internal/dynalink/beans/ClassString.java | 4 - .../dynalink/beans/StaticClassLinker.java | 14 +-- .../internal/dynalink/support/Backport.java | 99 ------------------- .../internal/dynalink/support/ClassMap.java | 23 ++--- .../jdk/internal/dynalink/support/Guards.java | 25 ++--- .../jdk/internal/dynalink/support/Lookup.java | 13 +-- .../support/TypeConverterFactory.java | 15 ++- .../internal/runtime/linker/Bootstrap.java | 4 + 10 files changed, 74 insertions(+), 163 deletions(-) delete mode 100644 nashorn/src/jdk/internal/dynalink/support/Backport.java diff --git a/nashorn/src/jdk/internal/dynalink/ChainedCallSite.java b/nashorn/src/jdk/internal/dynalink/ChainedCallSite.java index c242fedfbb9..cdadd1638ba 100644 --- a/nashorn/src/jdk/internal/dynalink/ChainedCallSite.java +++ b/nashorn/src/jdk/internal/dynalink/ChainedCallSite.java @@ -85,12 +85,12 @@ package jdk.internal.dynalink; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; import java.util.Iterator; import java.util.LinkedList; import java.util.concurrent.atomic.AtomicReference; import jdk.internal.dynalink.linker.GuardedInvocation; import jdk.internal.dynalink.support.AbstractRelinkableCallSite; +import jdk.internal.dynalink.support.Lookup; /** * A relinkable call site that maintains a chain of linked method handles. In the default implementation, up to 8 method @@ -103,6 +103,9 @@ import jdk.internal.dynalink.support.AbstractRelinkableCallSite; * handle is always at the start of the chain. */ public class ChainedCallSite extends AbstractRelinkableCallSite { + private static final MethodHandle PRUNE = Lookup.findOwnSpecial(MethodHandles.lookup(), "prune", MethodHandle.class, + MethodHandle.class); + private final AtomicReference> invocations = new AtomicReference<>(); /** @@ -194,18 +197,4 @@ public class ChainedCallSite extends AbstractRelinkableCallSite { private MethodHandle prune(MethodHandle relink) { return relinkInternal(null, relink, false); } - - private static final MethodHandle PRUNE; - static { - try { - PRUNE = MethodHandles.lookup().findSpecial(ChainedCallSite.class, "prune", MethodType.methodType( - MethodHandle.class, MethodHandle.class), ChainedCallSite.class); - // NOTE: using two catch blocks so we don't introduce a reference to 1.7 ReflectiveOperationException, allowing - // Dynalink to be used on 1.6 JVMs with Remi's backport library. - } catch(IllegalAccessException e) { - throw new AssertionError(e.getMessage(), e); // Can not happen - } catch(NoSuchMethodException e) { - throw new AssertionError(e.getMessage(), e); // Can not happen - } - } } diff --git a/nashorn/src/jdk/internal/dynalink/DynamicLinkerFactory.java b/nashorn/src/jdk/internal/dynalink/DynamicLinkerFactory.java index 0f0a347be5a..3cd052003b2 100644 --- a/nashorn/src/jdk/internal/dynalink/DynamicLinkerFactory.java +++ b/nashorn/src/jdk/internal/dynalink/DynamicLinkerFactory.java @@ -84,6 +84,8 @@ package jdk.internal.dynalink; import java.lang.invoke.MutableCallSite; +import java.security.AccessController; +import java.security.PrivilegedAction; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -117,7 +119,9 @@ public class DynamicLinkerFactory { */ public static final int DEFAULT_UNSTABLE_RELINK_THRESHOLD = 8; - private ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); + private boolean classLoaderExplicitlySet = false; + private ClassLoader classLoader; + private List prioritizedLinkers; private List fallbackLinkers; private int runtimeContextArgCount = 0; @@ -126,12 +130,13 @@ public class DynamicLinkerFactory { /** * Sets the class loader for automatic discovery of available linkers. If not set explicitly, then the thread - * context class loader at the time of the constructor invocation will be used. + * context class loader at the time of {@link #createLinker()} invocation will be used. * * @param classLoader the class loader used for the autodiscovery of available linkers. */ public void setClassLoader(ClassLoader classLoader) { this.classLoader = classLoader; + classLoaderExplicitlySet = true; } /** @@ -260,7 +265,8 @@ public class DynamicLinkerFactory { addClasses(knownLinkerClasses, prioritizedLinkers); addClasses(knownLinkerClasses, fallbackLinkers); - final List discovered = AutoDiscovery.loadLinkers(classLoader); + final ClassLoader effectiveClassLoader = classLoaderExplicitlySet ? classLoader : getThreadContextClassLoader(); + final List discovered = AutoDiscovery.loadLinkers(effectiveClassLoader); // Now, concatenate ... final List linkers = new ArrayList<>(prioritizedLinkers.size() + discovered.size() @@ -303,6 +309,15 @@ public class DynamicLinkerFactory { runtimeContextArgCount, syncOnRelink, unstableRelinkThreshold); } + private static ClassLoader getThreadContextClassLoader() { + return AccessController.doPrivileged(new PrivilegedAction() { + @Override + public ClassLoader run() { + return Thread.currentThread().getContextClassLoader(); + } + }); + } + private static void addClasses(Set> knownLinkerClasses, List linkers) { for(GuardingDynamicLinker linker: linkers) { diff --git a/nashorn/src/jdk/internal/dynalink/beans/ClassString.java b/nashorn/src/jdk/internal/dynalink/beans/ClassString.java index 8ab45727de6..2afbdb4f76b 100644 --- a/nashorn/src/jdk/internal/dynalink/beans/ClassString.java +++ b/nashorn/src/jdk/internal/dynalink/beans/ClassString.java @@ -112,10 +112,6 @@ final class ClassString { this(type.parameterArray()); } - Class[] getClasses() { - return classes; - } - @Override public boolean equals(Object other) { if(!(other instanceof ClassString)) { diff --git a/nashorn/src/jdk/internal/dynalink/beans/StaticClassLinker.java b/nashorn/src/jdk/internal/dynalink/beans/StaticClassLinker.java index c473bb4cc73..5f80caea74f 100644 --- a/nashorn/src/jdk/internal/dynalink/beans/StaticClassLinker.java +++ b/nashorn/src/jdk/internal/dynalink/beans/StaticClassLinker.java @@ -189,15 +189,17 @@ class StaticClassLinker implements TypeBasedGuardingDynamicLinker { return type == StaticClass.class; } - /*private*/ static final MethodHandle GET_CLASS = new Lookup(MethodHandles.lookup()).findVirtual(StaticClass.class, - "getRepresentedClass", MethodType.methodType(Class.class)); - - /*private*/ static final MethodHandle IS_CLASS = new Lookup(MethodHandles.lookup()).findStatic(StaticClassLinker.class, - "isClass", MethodType.methodType(Boolean.TYPE, Class.class, Object.class)); - + /*private*/ static final MethodHandle GET_CLASS; + /*private*/ static final MethodHandle IS_CLASS; /*private*/ static final MethodHandle ARRAY_CTOR = Lookup.PUBLIC.findStatic(Array.class, "newInstance", MethodType.methodType(Object.class, Class.class, int.class)); + static { + final Lookup lookup = new Lookup(MethodHandles.lookup()); + GET_CLASS = lookup.findVirtual(StaticClass.class, "getRepresentedClass", MethodType.methodType(Class.class)); + IS_CLASS = lookup.findOwnStatic("isClass", Boolean.TYPE, Class.class, Object.class); + } + @SuppressWarnings("unused") private static boolean isClass(Class clazz, Object obj) { return obj instanceof StaticClass && ((StaticClass)obj).getRepresentedClass() == clazz; diff --git a/nashorn/src/jdk/internal/dynalink/support/Backport.java b/nashorn/src/jdk/internal/dynalink/support/Backport.java deleted file mode 100644 index 1be7dc32acc..00000000000 --- a/nashorn/src/jdk/internal/dynalink/support/Backport.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (c) 2010, 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. - */ - -/* - * 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, and Oracle licenses the original version of this file under the BSD - * license: - */ -/* - Copyright 2009-2013 Attila Szegedi - - Licensed under both the Apache License, Version 2.0 (the "Apache License") - and the BSD License (the "BSD License"), with licensee being free to - choose either of the two at their discretion. - - You may not use this file except in compliance with either the Apache - License or the BSD License. - - If you choose to use this file in compliance with the Apache License, the - following notice applies to you: - - You may obtain a copy of the Apache License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied. See the License for the specific language governing - permissions and limitations under the License. - - If you choose to use this file in compliance with the BSD License, the - following notice applies to you: - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - * Neither the name of the copyright holder nor the names of - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER - BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -package jdk.internal.dynalink.support; - -import java.lang.invoke.MethodHandles; - -/** - * @author Attila Szegedi - */ -public class Backport { - /** - * True if Remi's JSR-292 backport agent is active; false if we're using native OpenJDK JSR-292 support. - */ - public static final boolean inUse = MethodHandles.class.getName().startsWith("jsr292"); - - private Backport() { - } -} diff --git a/nashorn/src/jdk/internal/dynalink/support/ClassMap.java b/nashorn/src/jdk/internal/dynalink/support/ClassMap.java index 7369d2557cf..cf52d2e51c4 100644 --- a/nashorn/src/jdk/internal/dynalink/support/ClassMap.java +++ b/nashorn/src/jdk/internal/dynalink/support/ClassMap.java @@ -85,6 +85,8 @@ package jdk.internal.dynalink.support; import java.lang.ref.Reference; import java.lang.ref.SoftReference; +import java.security.AccessController; +import java.security.PrivilegedAction; import java.util.Map; import java.util.WeakHashMap; import java.util.concurrent.ConcurrentHashMap; @@ -121,22 +123,13 @@ public abstract class ClassMap { */ protected abstract T computeValue(Class clazz); - /** - * Returns the class loader that governs the strong referenceability of this class map. - * - * @return the class loader that governs the strong referenceability of this class map. - */ - public ClassLoader getClassLoader() { - return classLoader; - } - /** * Returns the value associated with the class * * @param clazz the class * @return the value associated with the class */ - public T get(Class clazz) { + public T get(final Class clazz) { // Check in fastest first - objects we're allowed to strongly reference final T v = map.get(clazz); if(v != null) { @@ -156,8 +149,16 @@ public abstract class ClassMap { // Not found in either place; create a new value final T newV = computeValue(clazz); assert newV != null; + + final ClassLoader clazzLoader = AccessController.doPrivileged(new PrivilegedAction() { + @Override + public ClassLoader run() { + return clazz.getClassLoader(); + } + }); + // If allowed to strongly reference, put it in the fast map - if(Guards.canReferenceDirectly(classLoader, clazz.getClassLoader())) { + if(Guards.canReferenceDirectly(classLoader, clazzLoader)) { final T oldV = map.putIfAbsent(clazz, newV); return oldV != null ? oldV : newV; } diff --git a/nashorn/src/jdk/internal/dynalink/support/Guards.java b/nashorn/src/jdk/internal/dynalink/support/Guards.java index bab6e1dc6ca..661cf334b5e 100644 --- a/nashorn/src/jdk/internal/dynalink/support/Guards.java +++ b/nashorn/src/jdk/internal/dynalink/support/Guards.java @@ -258,23 +258,24 @@ public class Guards { type.changeReturnType(Boolean.TYPE), new int[] { pos }); } - private static final MethodHandle IS_OF_CLASS = new Lookup(MethodHandles.lookup()).findStatic(Guards.class, - "isOfClass", MethodType.methodType(Boolean.TYPE, Class.class, Object.class)); - private static final MethodHandle IS_INSTANCE = Lookup.PUBLIC.findVirtual(Class.class, "isInstance", MethodType.methodType(Boolean.TYPE, Object.class)); - private static final MethodHandle IS_ARRAY = new Lookup(MethodHandles.lookup()).findStatic(Guards.class, "isArray", - MethodType.methodType(Boolean.TYPE, Object.class)); + private static final MethodHandle IS_OF_CLASS; + private static final MethodHandle IS_ARRAY; + private static final MethodHandle IS_IDENTICAL; + private static final MethodHandle IS_NULL; + private static final MethodHandle IS_NOT_NULL; - private static final MethodHandle IS_IDENTICAL = new Lookup(MethodHandles.lookup()).findStatic(Guards.class, - "isIdentical", MethodType.methodType(Boolean.TYPE, Object.class, Object.class)); + static { + final Lookup lookup = new Lookup(MethodHandles.lookup()); - private static final MethodHandle IS_NULL = new Lookup(MethodHandles.lookup()).findStatic(Guards.class, - "isNull", MethodType.methodType(Boolean.TYPE, Object.class)); - - private static final MethodHandle IS_NOT_NULL = new Lookup(MethodHandles.lookup()).findStatic(Guards.class, - "isNotNull", MethodType.methodType(Boolean.TYPE, Object.class)); + IS_OF_CLASS = lookup.findOwnStatic("isOfClass", Boolean.TYPE, Class.class, Object.class); + IS_ARRAY = lookup.findOwnStatic("isArray", Boolean.TYPE, Object.class); + IS_IDENTICAL = lookup.findOwnStatic("isIdentical", Boolean.TYPE, Object.class, Object.class); + IS_NULL = lookup.findOwnStatic("isNull", Boolean.TYPE, Object.class); + IS_NOT_NULL = lookup.findOwnStatic("isNotNull", Boolean.TYPE, Object.class); + } /** * Creates a guard method that tests its only argument for being of an exact particular class. diff --git a/nashorn/src/jdk/internal/dynalink/support/Lookup.java b/nashorn/src/jdk/internal/dynalink/support/Lookup.java index 4b21e1c4af4..ba4ff77c6f3 100644 --- a/nashorn/src/jdk/internal/dynalink/support/Lookup.java +++ b/nashorn/src/jdk/internal/dynalink/support/Lookup.java @@ -89,7 +89,6 @@ import java.lang.invoke.MethodType; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; -import java.lang.reflect.Modifier; /** * A wrapper around MethodHandles.Lookup that masks checked exceptions in those cases when you're looking up methods @@ -235,9 +234,8 @@ public class Lookup { } /** - * Performs a findSpecial on the underlying lookup, except for the backport where it rather uses unreflect. Converts - * any encountered {@link IllegalAccessException} into an {@link IllegalAccessError} and a - * {@link NoSuchMethodException} into a {@link NoSuchMethodError}. + * Performs a findSpecial on the underlying lookup. Converts any encountered {@link IllegalAccessException} into an + * {@link IllegalAccessError} and a {@link NoSuchMethodException} into a {@link NoSuchMethodError}. * * @param declaringClass class declaring the method * @param name the name of the method @@ -248,13 +246,6 @@ public class Lookup { */ public MethodHandle findSpecial(Class declaringClass, String name, MethodType type) { try { - if(Backport.inUse) { - final Method m = declaringClass.getDeclaredMethod(name, type.parameterArray()); - if(!Modifier.isPublic(declaringClass.getModifiers()) || !Modifier.isPublic(m.getModifiers())) { - m.setAccessible(true); - } - return unreflect(m); - } return lookup.findSpecial(declaringClass, name, type, declaringClass); } catch(IllegalAccessException e) { final IllegalAccessError ee = new IllegalAccessError("Failed to access special method " + methodDescription( diff --git a/nashorn/src/jdk/internal/dynalink/support/TypeConverterFactory.java b/nashorn/src/jdk/internal/dynalink/support/TypeConverterFactory.java index 71fb4eb7228..245afc126e9 100644 --- a/nashorn/src/jdk/internal/dynalink/support/TypeConverterFactory.java +++ b/nashorn/src/jdk/internal/dynalink/support/TypeConverterFactory.java @@ -87,6 +87,8 @@ import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; import java.lang.invoke.WrongMethodTypeException; +import java.security.AccessController; +import java.security.PrivilegedAction; import java.util.LinkedList; import java.util.List; import jdk.internal.dynalink.linker.ConversionComparator; @@ -110,7 +112,7 @@ public class TypeConverterFactory { private final ClassValue> converterMap = new ClassValue>() { @Override protected ClassMap computeValue(final Class sourceType) { - return new ClassMap(sourceType.getClassLoader()) { + return new ClassMap(getClassLoader(sourceType)) { @Override protected MethodHandle computeValue(Class targetType) { try { @@ -128,7 +130,7 @@ public class TypeConverterFactory { private final ClassValue> converterIdentityMap = new ClassValue>() { @Override protected ClassMap computeValue(final Class sourceType) { - return new ClassMap(sourceType.getClassLoader()) { + return new ClassMap(getClassLoader(sourceType)) { @Override protected MethodHandle computeValue(Class targetType) { if(!canAutoConvert(sourceType, targetType)) { @@ -143,6 +145,15 @@ public class TypeConverterFactory { } }; + private static final ClassLoader getClassLoader(final Class clazz) { + return AccessController.doPrivileged(new PrivilegedAction() { + @Override + public ClassLoader run() { + return clazz.getClassLoader(); + } + }); + } + /** * Creates a new type converter factory from the available {@link GuardingTypeConverterFactory} instances. * diff --git a/nashorn/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java b/nashorn/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java index 421e5f62490..328e15f0230 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java @@ -68,6 +68,10 @@ public final class Bootstrap { if (relinkThreshold > -1) { factory.setUnstableRelinkThreshold(relinkThreshold); } + + // Linkers for any additional language runtimes deployed alongside Nashorn will be picked up by the factory. + factory.setClassLoader(Bootstrap.class.getClassLoader()); + dynamicLinker = factory.createLinker(); } From 3ea9481c2fe6fd9d7c337479bbc24cc46f73c196 Mon Sep 17 00:00:00 2001 From: Erik Helin Date: Wed, 7 Aug 2013 16:47:32 +0200 Subject: [PATCH 003/218] 8014659: NPG: performance counters for compressed klass space Reviewed-by: mgerdin, coleenp, hseigel, jmasa, ctornqvi --- .../g1/g1MonitoringSupport.cpp | 1 + .../parallelScavenge/parallelScavengeHeap.cpp | 1 + .../src/share/vm/memory/genCollectedHeap.cpp | 1 + hotspot/src/share/vm/memory/metaspace.cpp | 30 +- hotspot/src/share/vm/memory/metaspace.hpp | 7 +- .../src/share/vm/memory/metaspaceCounters.cpp | 174 ++++---- .../src/share/vm/memory/metaspaceCounters.hpp | 40 +- hotspot/src/share/vm/memory/universe.cpp | 2 + .../metaspace/TestMetaspacePerfCounters.java | 104 +++++ hotspot/test/testlibrary/AssertsTest.java | 237 +++++++++++ .../com/oracle/java/testlibrary/Asserts.java | 395 ++++++++++++++++++ .../java/testlibrary/ByteCodeLoader.java | 74 ++++ .../testlibrary/InMemoryJavaCompiler.java | 154 +++++++ .../java/testlibrary/InputArguments.java | 51 +++ .../oracle/java/testlibrary/PerfCounter.java | 70 ++++ .../oracle/java/testlibrary/PerfCounters.java | 69 +++ 16 files changed, 1284 insertions(+), 126 deletions(-) create mode 100644 hotspot/test/gc/metaspace/TestMetaspacePerfCounters.java create mode 100644 hotspot/test/testlibrary/AssertsTest.java create mode 100644 hotspot/test/testlibrary/com/oracle/java/testlibrary/Asserts.java create mode 100644 hotspot/test/testlibrary/com/oracle/java/testlibrary/ByteCodeLoader.java create mode 100644 hotspot/test/testlibrary/com/oracle/java/testlibrary/InMemoryJavaCompiler.java create mode 100644 hotspot/test/testlibrary/com/oracle/java/testlibrary/InputArguments.java create mode 100644 hotspot/test/testlibrary/com/oracle/java/testlibrary/PerfCounter.java create mode 100644 hotspot/test/testlibrary/com/oracle/java/testlibrary/PerfCounters.java diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1MonitoringSupport.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1MonitoringSupport.cpp index 16839dcb29a..01bb43bef45 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1MonitoringSupport.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1MonitoringSupport.cpp @@ -262,6 +262,7 @@ void G1MonitoringSupport::update_sizes() { old_collection_counters()->update_all(); young_collection_counters()->update_all(); MetaspaceCounters::update_performance_counters(); + CompressedClassSpaceCounters::update_performance_counters(); } } diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp index d5b6c054005..e5d5229d30c 100644 --- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp +++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp @@ -216,6 +216,7 @@ void ParallelScavengeHeap::update_counters() { young_gen()->update_counters(); old_gen()->update_counters(); MetaspaceCounters::update_performance_counters(); + CompressedClassSpaceCounters::update_performance_counters(); } size_t ParallelScavengeHeap::capacity() const { diff --git a/hotspot/src/share/vm/memory/genCollectedHeap.cpp b/hotspot/src/share/vm/memory/genCollectedHeap.cpp index 2faed4cc818..e0f82c02d86 100644 --- a/hotspot/src/share/vm/memory/genCollectedHeap.cpp +++ b/hotspot/src/share/vm/memory/genCollectedHeap.cpp @@ -1211,6 +1211,7 @@ void GenCollectedHeap::gc_epilogue(bool full) { } MetaspaceCounters::update_performance_counters(); + CompressedClassSpaceCounters::update_performance_counters(); always_do_update_barrier = UseConcMarkSweepGC; }; diff --git a/hotspot/src/share/vm/memory/metaspace.cpp b/hotspot/src/share/vm/memory/metaspace.cpp index e5871ae7a84..f654a13878c 100644 --- a/hotspot/src/share/vm/memory/metaspace.cpp +++ b/hotspot/src/share/vm/memory/metaspace.cpp @@ -2480,16 +2480,13 @@ void SpaceManager::mangle_freed_chunks() { size_t MetaspaceAux::_allocated_capacity_words[] = {0, 0}; size_t MetaspaceAux::_allocated_used_words[] = {0, 0}; +size_t MetaspaceAux::free_bytes(Metaspace::MetadataType mdtype) { + VirtualSpaceList* list = Metaspace::get_space_list(mdtype); + return list == NULL ? 0 : list->free_bytes(); +} + size_t MetaspaceAux::free_bytes() { - size_t result = 0; - if (Metaspace::using_class_space() && - (Metaspace::class_space_list() != NULL)) { - result = result + Metaspace::class_space_list()->free_bytes(); - } - if (Metaspace::space_list() != NULL) { - result = result + Metaspace::space_list()->free_bytes(); - } - return result; + return free_bytes(Metaspace::ClassType) + free_bytes(Metaspace::NonClassType); } void MetaspaceAux::dec_capacity(Metaspace::MetadataType mdtype, size_t words) { @@ -2571,23 +2568,18 @@ size_t MetaspaceAux::capacity_bytes_slow(Metaspace::MetadataType mdtype) { } size_t MetaspaceAux::reserved_in_bytes(Metaspace::MetadataType mdtype) { - if (mdtype == Metaspace::ClassType) { - return Metaspace::using_class_space() ? - Metaspace::class_space_list()->virtual_space_total() * BytesPerWord : 0; - } else { - return Metaspace::space_list()->virtual_space_total() * BytesPerWord; - } + VirtualSpaceList* list = Metaspace::get_space_list(mdtype); + return list == NULL ? 0 : list->virtual_space_total(); } size_t MetaspaceAux::min_chunk_size() { return Metaspace::first_chunk_word_size(); } size_t MetaspaceAux::free_chunks_total(Metaspace::MetadataType mdtype) { - if ((mdtype == Metaspace::ClassType) && !Metaspace::using_class_space()) { + VirtualSpaceList* list = Metaspace::get_space_list(mdtype); + if (list == NULL) { return 0; } - ChunkManager* chunk = (mdtype == Metaspace::ClassType) ? - Metaspace::class_space_list()->chunk_manager() : - Metaspace::space_list()->chunk_manager(); + ChunkManager* chunk = list->chunk_manager(); chunk->slow_verify(); return chunk->free_chunks_total(); } diff --git a/hotspot/src/share/vm/memory/metaspace.hpp b/hotspot/src/share/vm/memory/metaspace.hpp index 3d620357bee..88f089494d3 100644 --- a/hotspot/src/share/vm/memory/metaspace.hpp +++ b/hotspot/src/share/vm/memory/metaspace.hpp @@ -136,6 +136,10 @@ class Metaspace : public CHeapObj { static VirtualSpaceList* space_list() { return _space_list; } static VirtualSpaceList* class_space_list() { return _class_space_list; } + static VirtualSpaceList* get_space_list(MetadataType mdtype) { + assert(mdtype != MetadataTypeCount, "MetadaTypeCount can't be used as mdtype"); + return mdtype == ClassType ? class_space_list() : space_list(); + } // This is used by DumpSharedSpaces only, where only _vsm is used. So we will // maintain a single list for now. @@ -218,7 +222,6 @@ class Metaspace : public CHeapObj { class MetaspaceAux : AllStatic { static size_t free_chunks_total(Metaspace::MetadataType mdtype); - static size_t free_chunks_total_in_bytes(Metaspace::MetadataType mdtype); public: // Statistics for class space and data space in metaspace. @@ -262,6 +265,7 @@ class MetaspaceAux : AllStatic { // Used by MetaspaceCounters static size_t free_chunks_total(); static size_t free_chunks_total_in_bytes(); + static size_t free_chunks_total_in_bytes(Metaspace::MetadataType mdtype); static size_t allocated_capacity_words(Metaspace::MetadataType mdtype) { return _allocated_capacity_words[mdtype]; @@ -294,6 +298,7 @@ class MetaspaceAux : AllStatic { } static size_t free_bytes(); + static size_t free_bytes(Metaspace::MetadataType mdtype); // Total capacity in all Metaspaces static size_t capacity_bytes_slow() { diff --git a/hotspot/src/share/vm/memory/metaspaceCounters.cpp b/hotspot/src/share/vm/memory/metaspaceCounters.cpp index b2be29bca2f..eb7bebd28b6 100644 --- a/hotspot/src/share/vm/memory/metaspaceCounters.cpp +++ b/hotspot/src/share/vm/memory/metaspaceCounters.cpp @@ -25,11 +25,47 @@ #include "precompiled.hpp" #include "memory/metaspaceCounters.hpp" #include "memory/resourceArea.hpp" +#include "runtime/globals.hpp" +#include "runtime/perfData.hpp" #include "utilities/exceptions.hpp" -MetaspaceCounters* MetaspaceCounters::_metaspace_counters = NULL; +class MetaspacePerfCounters: public CHeapObj { + friend class VMStructs; + PerfVariable* _capacity; + PerfVariable* _used; + PerfVariable* _max_capacity; -size_t MetaspaceCounters::calc_total_capacity() { + PerfVariable* create_variable(const char *ns, const char *name, size_t value, TRAPS) { + const char *path = PerfDataManager::counter_name(ns, name); + return PerfDataManager::create_variable(SUN_GC, path, PerfData::U_Bytes, value, THREAD); + } + + void create_constant(const char *ns, const char *name, size_t value, TRAPS) { + const char *path = PerfDataManager::counter_name(ns, name); + PerfDataManager::create_constant(SUN_GC, path, PerfData::U_Bytes, value, THREAD); + } + + public: + MetaspacePerfCounters(const char* ns, size_t min_capacity, size_t curr_capacity, size_t max_capacity, size_t used) { + EXCEPTION_MARK; + ResourceMark rm; + + create_constant(ns, "minCapacity", min_capacity, THREAD); + _capacity = create_variable(ns, "capacity", curr_capacity, THREAD); + _max_capacity = create_variable(ns, "maxCapacity", max_capacity, THREAD); + _used = create_variable(ns, "used", used, THREAD); + } + + void update(size_t capacity, size_t max_capacity, size_t used) { + _capacity->set_value(capacity); + _max_capacity->set_value(max_capacity); + _used->set_value(used); + } +}; + +MetaspacePerfCounters* MetaspaceCounters::_perf_counters = NULL; + +size_t MetaspaceCounters::calculate_capacity() { // The total capacity is the sum of // 1) capacity of Metachunks in use by all Metaspaces // 2) unused space at the end of each Metachunk @@ -39,95 +75,65 @@ size_t MetaspaceCounters::calc_total_capacity() { return total_capacity; } -MetaspaceCounters::MetaspaceCounters() : - _capacity(NULL), - _used(NULL), - _max_capacity(NULL) { - if (UsePerfData) { - size_t min_capacity = MetaspaceAux::min_chunk_size(); - size_t max_capacity = MetaspaceAux::reserved_in_bytes(); - size_t curr_capacity = calc_total_capacity(); - size_t used = MetaspaceAux::allocated_used_bytes(); - - initialize(min_capacity, max_capacity, curr_capacity, used); - } -} - -static PerfVariable* create_ms_variable(const char *ns, - const char *name, - size_t value, - TRAPS) { - const char *path = PerfDataManager::counter_name(ns, name); - PerfVariable *result = - PerfDataManager::create_variable(SUN_GC, path, PerfData::U_Bytes, value, - CHECK_NULL); - return result; -} - -static void create_ms_constant(const char *ns, - const char *name, - size_t value, - TRAPS) { - const char *path = PerfDataManager::counter_name(ns, name); - PerfDataManager::create_constant(SUN_GC, path, PerfData::U_Bytes, value, CHECK); -} - -void MetaspaceCounters::initialize(size_t min_capacity, - size_t max_capacity, - size_t curr_capacity, - size_t used) { - - if (UsePerfData) { - EXCEPTION_MARK; - ResourceMark rm; - - const char *ms = "metaspace"; - - create_ms_constant(ms, "minCapacity", min_capacity, CHECK); - _max_capacity = create_ms_variable(ms, "maxCapacity", max_capacity, CHECK); - _capacity = create_ms_variable(ms, "capacity", curr_capacity, CHECK); - _used = create_ms_variable(ms, "used", used, CHECK); - } -} - -void MetaspaceCounters::update_capacity() { - assert(UsePerfData, "Should not be called unless being used"); - size_t total_capacity = calc_total_capacity(); - _capacity->set_value(total_capacity); -} - -void MetaspaceCounters::update_used() { - assert(UsePerfData, "Should not be called unless being used"); - size_t used_in_bytes = MetaspaceAux::allocated_used_bytes(); - _used->set_value(used_in_bytes); -} - -void MetaspaceCounters::update_max_capacity() { - assert(UsePerfData, "Should not be called unless being used"); - assert(_max_capacity != NULL, "Should be initialized"); - size_t reserved_in_bytes = MetaspaceAux::reserved_in_bytes(); - _max_capacity->set_value(reserved_in_bytes); -} - -void MetaspaceCounters::update_all() { - if (UsePerfData) { - update_used(); - update_capacity(); - update_max_capacity(); - } -} - void MetaspaceCounters::initialize_performance_counters() { if (UsePerfData) { - assert(_metaspace_counters == NULL, "Should only be initialized once"); - _metaspace_counters = new MetaspaceCounters(); + assert(_perf_counters == NULL, "Should only be initialized once"); + + size_t min_capacity = MetaspaceAux::min_chunk_size(); + size_t capacity = calculate_capacity(); + size_t max_capacity = MetaspaceAux::reserved_in_bytes(); + size_t used = MetaspaceAux::allocated_used_bytes(); + + _perf_counters = new MetaspacePerfCounters("metaspace", min_capacity, capacity, max_capacity, used); } } void MetaspaceCounters::update_performance_counters() { if (UsePerfData) { - assert(_metaspace_counters != NULL, "Should be initialized"); - _metaspace_counters->update_all(); + assert(_perf_counters != NULL, "Should be initialized"); + + size_t capacity = calculate_capacity(); + size_t max_capacity = MetaspaceAux::reserved_in_bytes(); + size_t used = MetaspaceAux::allocated_used_bytes(); + + _perf_counters->update(capacity, max_capacity, used); } } +MetaspacePerfCounters* CompressedClassSpaceCounters::_perf_counters = NULL; + +size_t CompressedClassSpaceCounters::calculate_capacity() { + return MetaspaceAux::allocated_capacity_bytes(_class_type) + + MetaspaceAux::free_bytes(_class_type) + + MetaspaceAux::free_chunks_total_in_bytes(_class_type); +} + +void CompressedClassSpaceCounters::update_performance_counters() { + if (UsePerfData && UseCompressedKlassPointers) { + assert(_perf_counters != NULL, "Should be initialized"); + + size_t capacity = calculate_capacity(); + size_t max_capacity = MetaspaceAux::reserved_in_bytes(_class_type); + size_t used = MetaspaceAux::allocated_used_bytes(_class_type); + + _perf_counters->update(capacity, max_capacity, used); + } +} + +void CompressedClassSpaceCounters::initialize_performance_counters() { + if (UsePerfData) { + assert(_perf_counters == NULL, "Should only be initialized once"); + const char* ns = "compressedclassspace"; + + if (UseCompressedKlassPointers) { + size_t min_capacity = MetaspaceAux::min_chunk_size(); + size_t capacity = calculate_capacity(); + size_t max_capacity = MetaspaceAux::reserved_in_bytes(_class_type); + size_t used = MetaspaceAux::allocated_used_bytes(_class_type); + + _perf_counters = new MetaspacePerfCounters(ns, min_capacity, capacity, max_capacity, used); + } else { + _perf_counters = new MetaspacePerfCounters(ns, 0, 0, 0, 0); + } + } +} diff --git a/hotspot/src/share/vm/memory/metaspaceCounters.hpp b/hotspot/src/share/vm/memory/metaspaceCounters.hpp index 46a9308888a..5b481d59b4d 100644 --- a/hotspot/src/share/vm/memory/metaspaceCounters.hpp +++ b/hotspot/src/share/vm/memory/metaspaceCounters.hpp @@ -25,31 +25,27 @@ #ifndef SHARE_VM_MEMORY_METASPACECOUNTERS_HPP #define SHARE_VM_MEMORY_METASPACECOUNTERS_HPP -#include "runtime/perfData.hpp" +#include "memory/metaspace.hpp" + +class MetaspacePerfCounters; + +class MetaspaceCounters: public AllStatic { + static MetaspacePerfCounters* _perf_counters; + static size_t calculate_capacity(); -class MetaspaceCounters: public CHeapObj { - friend class VMStructs; - PerfVariable* _capacity; - PerfVariable* _used; - PerfVariable* _max_capacity; - static MetaspaceCounters* _metaspace_counters; - void initialize(size_t min_capacity, - size_t max_capacity, - size_t curr_capacity, - size_t used); - size_t calc_total_capacity(); public: - MetaspaceCounters(); - ~MetaspaceCounters(); - - void update_capacity(); - void update_used(); - void update_max_capacity(); - - void update_all(); - static void initialize_performance_counters(); static void update_performance_counters(); - }; + +class CompressedClassSpaceCounters: public AllStatic { + static MetaspacePerfCounters* _perf_counters; + static size_t calculate_capacity(); + static const Metaspace::MetadataType _class_type = Metaspace::ClassType; + + public: + static void initialize_performance_counters(); + static void update_performance_counters(); +}; + #endif // SHARE_VM_MEMORY_METASPACECOUNTERS_HPP diff --git a/hotspot/src/share/vm/memory/universe.cpp b/hotspot/src/share/vm/memory/universe.cpp index 1e380ed39f8..d85d23e015b 100644 --- a/hotspot/src/share/vm/memory/universe.cpp +++ b/hotspot/src/share/vm/memory/universe.cpp @@ -1101,6 +1101,8 @@ bool universe_post_init() { // Initialize performance counters for metaspaces MetaspaceCounters::initialize_performance_counters(); + CompressedClassSpaceCounters::initialize_performance_counters(); + MemoryService::add_metaspace_memory_pools(); GC_locker::unlock(); // allow gc after bootstrapping diff --git a/hotspot/test/gc/metaspace/TestMetaspacePerfCounters.java b/hotspot/test/gc/metaspace/TestMetaspacePerfCounters.java new file mode 100644 index 00000000000..26934249a7c --- /dev/null +++ b/hotspot/test/gc/metaspace/TestMetaspacePerfCounters.java @@ -0,0 +1,104 @@ +/* + * 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 java.util.ArrayList; + +import com.oracle.java.testlibrary.*; +import static com.oracle.java.testlibrary.Asserts.*; + +/* @test TestMetaspacePerfCounters + * @bug 8014659 + * @library /testlibrary + * @summary Tests that performance counters for metaspace and compressed class + * space exists and works. + * + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-UseCompressedOops -XX:-UseCompressedKlassPointers -XX:+UsePerfData -XX:+UseSerialGC TestMetaspacePerfCounters + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-UseCompressedOops -XX:-UseCompressedKlassPointers -XX:+UsePerfData -XX:+UseParallelGC -XX:+UseParallelOldGC TestMetaspacePerfCounters + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:-UseCompressedOops -XX:-UseCompressedKlassPointers -XX:+UsePerfData -XX:+UseG1GC TestMetaspacePerfCounters + * + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+UseCompressedOops -XX:+UseCompressedKlassPointers -XX:+UsePerfData -XX:+UseSerialGC TestMetaspacePerfCounters + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+UseCompressedOops -XX:+UseCompressedKlassPointers -XX:+UsePerfData -XX:+UseParallelGC -XX:+UseParallelOldGC TestMetaspacePerfCounters + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+UseCompressedOops -XX:+UseCompressedKlassPointers -XX:+UsePerfData -XX:+UseG1GC TestMetaspacePerfCounters + */ +public class TestMetaspacePerfCounters { + public static Class fooClass = null; + private static final String[] counterNames = {"minCapacity", "maxCapacity", "capacity", "used"}; + + public static void main(String[] args) throws Exception { + String metaspace = "sun.gc.metaspace"; + String ccs = "sun.gc.compressedclassspace"; + + checkPerfCounters(metaspace); + + if (isUsingCompressedClassPointers()) { + checkPerfCounters(ccs); + checkUsedIncreasesWhenLoadingClass(ccs); + } else { + checkEmptyPerfCounters(ccs); + checkUsedIncreasesWhenLoadingClass(metaspace); + } + } + + private static void checkPerfCounters(String ns) throws Exception { + for (PerfCounter counter : countersInNamespace(ns)) { + String msg = "Expected " + counter.getName() + " to be larger than 0"; + assertGT(counter.longValue(), 0L, msg); + } + } + + private static void checkEmptyPerfCounters(String ns) throws Exception { + for (PerfCounter counter : countersInNamespace(ns)) { + String msg = "Expected " + counter.getName() + " to equal 0"; + assertEQ(counter.longValue(), 0L, msg); + } + } + + private static void checkUsedIncreasesWhenLoadingClass(String ns) throws Exception { + PerfCounter used = PerfCounters.findByName(ns + ".used"); + + long before = used.longValue(); + fooClass = compileAndLoad("Foo", "public class Foo { }"); + System.gc(); + long after = used.longValue(); + + assertGT(after, before); + } + + private static List countersInNamespace(String ns) throws Exception { + List counters = new ArrayList<>(); + for (String name : counterNames) { + counters.add(PerfCounters.findByName(ns + "." + name)); + } + return counters; + } + + private static Class compileAndLoad(String name, String source) throws Exception { + byte[] byteCode = InMemoryJavaCompiler.compile(name, source); + return ByteCodeLoader.load(name, byteCode); + } + + private static boolean isUsingCompressedClassPointers() { + return Platform.is64bit() && InputArguments.contains("-XX:+UseCompressedKlassPointers"); + } +} diff --git a/hotspot/test/testlibrary/AssertsTest.java b/hotspot/test/testlibrary/AssertsTest.java new file mode 100644 index 00000000000..9ab62403cd2 --- /dev/null +++ b/hotspot/test/testlibrary/AssertsTest.java @@ -0,0 +1,237 @@ +/* + * 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 static com.oracle.java.testlibrary.Asserts.*; + +/* @test + * @summary Tests the different assertions in the Assert class + * @library /testlibrary + */ +public class AssertsTest { + private static class Foo implements Comparable { + final int id; + public Foo(int id) { + this.id = id; + } + + public int compareTo(Foo f) { + return new Integer(id).compareTo(new Integer(f.id)); + } + } + + public static void main(String[] args) throws Exception { + testLessThan(); + testLessThanOrEqual(); + testEquals(); + testGreaterThanOrEqual(); + testGreaterThan(); + testNotEquals(); + testNull(); + testNotNull(); + testTrue(); + testFalse(); + } + + private static void testLessThan() throws Exception { + expectPass(Assertion.LT, 1, 2); + + expectFail(Assertion.LT, 2, 2); + expectFail(Assertion.LT, 2, 1); + expectFail(Assertion.LT, null, 2); + expectFail(Assertion.LT, 2, null); + } + + private static void testLessThanOrEqual() throws Exception { + expectPass(Assertion.LTE, 1, 2); + expectPass(Assertion.LTE, 2, 2); + + expectFail(Assertion.LTE, 3, 2); + expectFail(Assertion.LTE, null, 2); + expectFail(Assertion.LTE, 2, null); + } + + private static void testEquals() throws Exception { + expectPass(Assertion.EQ, 1, 1); + expectPass(Assertion.EQ, null, null); + + Foo f1 = new Foo(1); + expectPass(Assertion.EQ, f1, f1); + + Foo f2 = new Foo(1); + expectFail(Assertion.EQ, f1, f2); + expectFail(Assertion.LTE, null, 2); + expectFail(Assertion.LTE, 2, null); + } + + private static void testGreaterThanOrEqual() throws Exception { + expectPass(Assertion.GTE, 1, 1); + expectPass(Assertion.GTE, 2, 1); + + expectFail(Assertion.GTE, 1, 2); + expectFail(Assertion.GTE, null, 2); + expectFail(Assertion.GTE, 2, null); + } + + private static void testGreaterThan() throws Exception { + expectPass(Assertion.GT, 2, 1); + + expectFail(Assertion.GT, 1, 1); + expectFail(Assertion.GT, 1, 2); + expectFail(Assertion.GT, null, 2); + expectFail(Assertion.GT, 2, null); + } + + private static void testNotEquals() throws Exception { + expectPass(Assertion.NE, null, 1); + expectPass(Assertion.NE, 1, null); + + Foo f1 = new Foo(1); + Foo f2 = new Foo(1); + expectPass(Assertion.NE, f1, f2); + + expectFail(Assertion.NE, null, null); + expectFail(Assertion.NE, f1, f1); + expectFail(Assertion.NE, 1, 1); + } + + private static void testNull() throws Exception { + expectPass(Assertion.NULL, null); + + expectFail(Assertion.NULL, 1); + } + + private static void testNotNull() throws Exception { + expectPass(Assertion.NOTNULL, 1); + + expectFail(Assertion.NOTNULL, null); + } + + private static void testTrue() throws Exception { + expectPass(Assertion.TRUE, true); + + expectFail(Assertion.TRUE, false); + } + + private static void testFalse() throws Exception { + expectPass(Assertion.FALSE, false); + + expectFail(Assertion.FALSE, true); + } + + private static > void expectPass(Assertion assertion, T ... args) + throws Exception { + Assertion.run(assertion, args); + } + + private static > void expectFail(Assertion assertion, T ... args) + throws Exception { + try { + Assertion.run(assertion, args); + } catch (RuntimeException e) { + return; + } + throw new Exception("Expected " + Assertion.format(assertion, (Object[]) args) + + " to throw a RuntimeException"); + } + +} + +enum Assertion { + LT, LTE, EQ, GTE, GT, NE, NULL, NOTNULL, FALSE, TRUE; + + public static > void run(Assertion assertion, T ... args) { + String msg = "Expected " + format(assertion, args) + " to pass"; + switch (assertion) { + case LT: + assertLessThan(args[0], args[1], msg); + break; + case LTE: + assertLessThanOrEqual(args[0], args[1], msg); + break; + case EQ: + assertEquals(args[0], args[1], msg); + break; + case GTE: + assertGreaterThanOrEqual(args[0], args[1], msg); + break; + case GT: + assertGreaterThan(args[0], args[1], msg); + break; + case NE: + assertNotEquals(args[0], args[1], msg); + break; + case NULL: + assertNull(args == null ? args : args[0], msg); + break; + case NOTNULL: + assertNotNull(args == null ? args : args[0], msg); + break; + case FALSE: + assertFalse((Boolean) args[0], msg); + break; + case TRUE: + assertTrue((Boolean) args[0], msg); + break; + default: + // do nothing + } + } + + public static String format(Assertion assertion, Object ... args) { + switch (assertion) { + case LT: + return asString("assertLessThan", args); + case LTE: + return asString("assertLessThanOrEqual", args); + case EQ: + return asString("assertEquals", args); + case GTE: + return asString("assertGreaterThanOrEquals", args); + case GT: + return asString("assertGreaterThan", args); + case NE: + return asString("assertNotEquals", args); + case NULL: + return asString("assertNull", args); + case NOTNULL: + return asString("assertNotNull", args); + case FALSE: + return asString("assertFalse", args); + case TRUE: + return asString("assertTrue", args); + default: + return ""; + } + } + + private static String asString(String assertion, Object ... args) { + if (args == null) { + return String.format("%s(null)", assertion); + } + if (args.length == 1) { + return String.format("%s(%s)", assertion, args[0]); + } else { + return String.format("%s(%s, %s)", assertion, args[0], args[1]); + } + } +} diff --git a/hotspot/test/testlibrary/com/oracle/java/testlibrary/Asserts.java b/hotspot/test/testlibrary/com/oracle/java/testlibrary/Asserts.java new file mode 100644 index 00000000000..e92e26dd4b5 --- /dev/null +++ b/hotspot/test/testlibrary/com/oracle/java/testlibrary/Asserts.java @@ -0,0 +1,395 @@ +/* + * 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 com.oracle.java.testlibrary; + +/** + * Asserts that can be used for verifying assumptions in tests. + * + * An assertion will throw a {@link RuntimeException} if the assertion isn't + * valid. All the asserts can be imported into a test by using a static + * import: + * + *
+ * {@code
+ * import static com.oracle.java.testlibrary.Asserts.*;
+ * }
+ *
+ * Always provide a message describing the assumption if the line number of the
+ * failing assertion isn't enough to understand why the assumption failed. For
+ * example, if the assertion is in a loop or in a method that is called
+ * multiple times, then the line number won't provide enough context to
+ * understand the failure.
+ * 
+ */ +public class Asserts { + + /** + * Shorthand for {@link #assertLessThan(T, T)}. + * + * @see #assertLessThan(T, T) + */ + public static > void assertLT(T lhs, T rhs) { + assertLessThan(lhs, rhs); + } + + /** + * Shorthand for {@link #assertLessThan(T, T, String)}. + * + * @see #assertLessThan(T, T, String) + */ + public static > void assertLT(T lhs, T rhs, String msg) { + assertLessThan(lhs, rhs, msg); + } + + /** + * Calls {@link #assertLessThan(T, T, String)} with a default message. + * + * @see #assertLessThan(T, T, String) + */ + public static > void assertLessThan(T lhs, T rhs) { + String msg = "Expected that " + format(lhs) + " < " + format(rhs); + assertLessThan(lhs, rhs, msg); + } + + /** + * Asserts that {@code lhs} is less than {@code rhs}. + * + * @param lhs The left hand side of the comparison. + * @param rhs The right hand side of the comparison. + * @param msg A description of the assumption. + * @throws RuntimeException if the assertion isn't valid. + */ + public static >void assertLessThan(T lhs, T rhs, String msg) { + assertTrue(compare(lhs, rhs, msg) < 0, msg); + } + + /** + * Shorthand for {@link #assertLessThanOrEqual(T, T)}. + * + * @see #assertLessThanOrEqual(T, T) + */ + public static > void assertLTE(T lhs, T rhs) { + assertLessThanOrEqual(lhs, rhs); + } + + /** + * Shorthand for {@link #assertLessThanOrEqual(T, T, String)}. + * + * @see #assertLessThanOrEqual(T, T, String) + */ + public static > void assertLTE(T lhs, T rhs, String msg) { + assertLessThanOrEqual(lhs, rhs, msg); + } + + /** + * Calls {@link #assertLessThanOrEqual(T, T, String)} with a default message. + * + * @see #assertLessThanOrEqual(T, T, String) + */ + public static > void assertLessThanOrEqual(T lhs, T rhs) { + String msg = "Expected that " + format(lhs) + " <= " + format(rhs); + assertLessThanOrEqual(lhs, rhs, msg); + } + + /** + * Asserts that {@code lhs} is less than or equal to {@code rhs}. + * + * @param lhs The left hand side of the comparison. + * @param rhs The right hand side of the comparison. + * @param msg A description of the assumption. + * @throws RuntimeException if the assertion isn't valid. + */ + public static > void assertLessThanOrEqual(T lhs, T rhs, String msg) { + assertTrue(compare(lhs, rhs, msg) <= 0, msg); + } + + /** + * Shorthand for {@link #assertEquals(T, T)}. + * + * @see #assertEquals(T, T) + */ + public static void assertEQ(Object lhs, Object rhs) { + assertEquals(lhs, rhs); + } + + /** + * Shorthand for {@link #assertEquals(T, T, String)}. + * + * @see #assertEquals(T, T, String) + */ + public static void assertEQ(Object lhs, Object rhs, String msg) { + assertEquals(lhs, rhs, msg); + } + + /** + * Calls {@link #assertEquals(T, T, String)} with a default message. + * + * @see #assertEquals(T, T, String) + */ + public static void assertEquals(Object lhs, Object rhs) { + String msg = "Expected " + format(lhs) + " to equal " + format(rhs); + assertEquals(lhs, rhs, msg); + } + + /** + * Asserts that {@code lhs} is equal to {@code rhs}. + * + * @param lhs The left hand side of the comparison. + * @param rhs The right hand side of the comparison. + * @param msg A description of the assumption. + * @throws RuntimeException if the assertion isn't valid. + */ + public static void assertEquals(Object lhs, Object rhs, String msg) { + if (lhs == null) { + if (rhs != null) { + error(msg); + } + } else { + assertTrue(lhs.equals(rhs), msg); + } + } + + /** + * Shorthand for {@link #assertGreaterThanOrEqual(T, T)}. + * + * @see #assertGreaterThanOrEqual(T, T) + */ + public static > void assertGTE(T lhs, T rhs) { + assertGreaterThanOrEqual(lhs, rhs); + } + + /** + * Shorthand for {@link #assertGreaterThanOrEqual(T, T, String)}. + * + * @see #assertGreaterThanOrEqual(T, T, String) + */ + public static > void assertGTE(T lhs, T rhs, String msg) { + assertGreaterThanOrEqual(lhs, rhs, msg); + } + + /** + * Calls {@link #assertGreaterThanOrEqual(T, T, String)} with a default message. + * + * @see #assertGreaterThanOrEqual(T, T, String) + */ + public static > void assertGreaterThanOrEqual(T lhs, T rhs) { + String msg = "Expected that " + format(lhs) + " >= " + format(rhs); + assertGreaterThanOrEqual(lhs, rhs, msg); + } + + /** + * Asserts that {@code lhs} is greater than or equal to {@code rhs}. + * + * @param lhs The left hand side of the comparison. + * @param rhs The right hand side of the comparison. + * @param msg A description of the assumption. + * @throws RuntimeException if the assertion isn't valid. + */ + public static > void assertGreaterThanOrEqual(T lhs, T rhs, String msg) { + assertTrue(compare(lhs, rhs, msg) >= 0, msg); + } + + /** + * Shorthand for {@link #assertGreaterThan(T, T)}. + * + * @see #assertGreaterThan(T, T) + */ + public static > void assertGT(T lhs, T rhs) { + assertGreaterThan(lhs, rhs); + } + + /** + * Shorthand for {@link #assertGreaterThan(T, T, String)}. + * + * @see #assertGreaterThan(T, T, String) + */ + public static > void assertGT(T lhs, T rhs, String msg) { + assertGreaterThan(lhs, rhs, msg); + } + + /** + * Calls {@link #assertGreaterThan(T, T, String)} with a default message. + * + * @see #assertGreaterThan(T, T, String) + */ + public static > void assertGreaterThan(T lhs, T rhs) { + String msg = "Expected that " + format(lhs) + " > " + format(rhs); + assertGreaterThan(lhs, rhs, msg); + } + + /** + * Asserts that {@code lhs} is greater than {@code rhs}. + * + * @param lhs The left hand side of the comparison. + * @param rhs The right hand side of the comparison. + * @param msg A description of the assumption. + * @throws RuntimeException if the assertion isn't valid. + */ + public static > void assertGreaterThan(T lhs, T rhs, String msg) { + assertTrue(compare(lhs, rhs, msg) > 0, msg); + } + + /** + * Shorthand for {@link #assertNotEquals(T, T)}. + * + * @see #assertNotEquals(T, T) + */ + public static void assertNE(Object lhs, Object rhs) { + assertNotEquals(lhs, rhs); + } + + /** + * Shorthand for {@link #assertNotEquals(T, T, String)}. + * + * @see #assertNotEquals(T, T, String) + */ + public static void assertNE(Object lhs, Object rhs, String msg) { + assertNotEquals(lhs, rhs, msg); + } + + /** + * Calls {@link #assertNotEquals(T, T, String)} with a default message. + * + * @see #assertNotEquals(T, T, String) + */ + public static void assertNotEquals(Object lhs, Object rhs) { + String msg = "Expected " + format(lhs) + " to not equal " + format(rhs); + assertNotEquals(lhs, rhs, msg); + } + + /** + * Asserts that {@code lhs} is not equal to {@code rhs}. + * + * @param lhs The left hand side of the comparison. + * @param rhs The right hand side of the comparison. + * @param msg A description of the assumption. + * @throws RuntimeException if the assertion isn't valid. + */ + public static void assertNotEquals(Object lhs, Object rhs, String msg) { + if (lhs == null) { + if (rhs == null) { + error(msg); + } + } else { + assertFalse(lhs.equals(rhs), msg); + } + } + + /** + * Calls {@link #assertNull(Object, String)} with a default message. + * + * @see #assertNull(Object, String) + */ + public static void assertNull(Object o) { + assertNull(o, "Expected " + format(o) + " to be null"); + } + + /** + * Asserts that {@code o} is null. + * + * @param o The reference assumed to be null. + * @param msg A description of the assumption. + * @throws RuntimeException if the assertion isn't valid. + */ + public static void assertNull(Object o, String msg) { + assertEquals(o, null, msg); + } + + /** + * Calls {@link #assertNotNull(Object, String)} with a default message. + * + * @see #assertNotNull(Object, String) + */ + public static void assertNotNull(Object o) { + assertNotNull(o, "Expected non null reference"); + } + + /** + * Asserts that {@code o} is not null. + * + * @param o The reference assumed not to be null, + * @param msg A description of the assumption. + * @throws RuntimeException if the assertion isn't valid. + */ + public static void assertNotNull(Object o, String msg) { + assertNotEquals(o, null, msg); + } + + /** + * Calls {@link #assertFalse(boolean, String)} with a default message. + * + * @see #assertFalse(boolean, String) + */ + public static void assertFalse(boolean value) { + assertFalse(value, "Expected value to be false"); + } + + /** + * Asserts that {@code value} is {@code false}. + * + * @param value The value assumed to be false. + * @param msg A description of the assumption. + * @throws RuntimeException if the assertion isn't valid. + */ + public static void assertFalse(boolean value, String msg) { + assertTrue(!value, msg); + } + + /** + * Calls {@link #assertTrue(boolean, String)} with a default message. + * + * @see #assertTrue(boolean, String) + */ + public static void assertTrue(boolean value) { + assertTrue(value, "Expected value to be true"); + } + + /** + * Asserts that {@code value} is {@code true}. + * + * @param value The value assumed to be true. + * @param msg A description of the assumption. + * @throws RuntimeException if the assertion isn't valid. + */ + public static void assertTrue(boolean value, String msg) { + if (!value) { + error(msg); + } + } + + private static > int compare(T lhs, T rhs, String msg) { + assertNotNull(lhs, msg); + assertNotNull(rhs, msg); + return lhs.compareTo(rhs); + } + + private static String format(Object o) { + return o == null? "null" : o.toString(); + } + + private static void error(String msg) { + throw new RuntimeException(msg); + } + +} diff --git a/hotspot/test/testlibrary/com/oracle/java/testlibrary/ByteCodeLoader.java b/hotspot/test/testlibrary/com/oracle/java/testlibrary/ByteCodeLoader.java new file mode 100644 index 00000000000..46309eae0ca --- /dev/null +++ b/hotspot/test/testlibrary/com/oracle/java/testlibrary/ByteCodeLoader.java @@ -0,0 +1,74 @@ +/* + * 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 com.oracle.java.testlibrary; + +import java.security.SecureClassLoader; + +/** + * {@code ByteCodeLoader} can be used for easy loading of byte code already + * present in memory. + * + * {@code InMemoryCompiler} can be used for compiling source code in a string + * into byte code, which then can be loaded with {@code ByteCodeLoader}. + * + * @see InMemoryCompiler + */ +public class ByteCodeLoader extends SecureClassLoader { + private final String className; + private final byte[] byteCode; + + /** + * Creates a new {@code ByteCodeLoader} ready to load a class with the + * given name and the given byte code. + * + * @param className The name of the class + * @param byteCode The byte code of the class + */ + public ByteCodeLoader(String className, byte[] byteCode) { + this.className = className; + this.byteCode = byteCode; + } + + @Override + protected Class findClass(String name) throws ClassNotFoundException { + if (!name.equals(className)) { + throw new ClassNotFoundException(name); + } + + return defineClass(name, byteCode, 0, byteCode.length); + } + + /** + * Utility method for creating a new {@code ByteCodeLoader} and then + * directly load the given byte code. + * + * @param className The name of the class + * @param byteCode The byte code for the class + * @throws ClassNotFoundException if the class can't be loaded + * @return A {@see Class} object representing the class + */ + public static Class load(String className, byte[] byteCode) throws ClassNotFoundException { + return new ByteCodeLoader(className, byteCode).loadClass(className); + } +} diff --git a/hotspot/test/testlibrary/com/oracle/java/testlibrary/InMemoryJavaCompiler.java b/hotspot/test/testlibrary/com/oracle/java/testlibrary/InMemoryJavaCompiler.java new file mode 100644 index 00000000000..9b075e19f3d --- /dev/null +++ b/hotspot/test/testlibrary/com/oracle/java/testlibrary/InMemoryJavaCompiler.java @@ -0,0 +1,154 @@ +/* + * 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 com.oracle.java.testlibrary; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +import java.net.URI; +import java.util.Arrays; + +import javax.tools.ForwardingJavaFileManager; +import javax.tools.ForwardingJavaFileManager; +import javax.tools.FileObject; +import javax.tools.JavaCompiler; +import javax.tools.JavaCompiler.CompilationTask; +import javax.tools.JavaFileManager; +import javax.tools.JavaFileObject; +import javax.tools.JavaFileObject.Kind; +import javax.tools.SimpleJavaFileObject; +import javax.tools.ToolProvider; + +/** + * {@code InMemoryJavaCompiler} can be used for compiling a {@link + * CharSequence} to a {@code byte[]}. + * + * The compiler will not use the file system at all, instead using a {@link + * ByteArrayOutputStream} for storing the byte code. For the source code, any + * kind of {@link CharSequence} can be used, e.g. {@link String}, {@link + * StringBuffer} or {@link StringBuilder}. + * + * The {@code InMemoryCompiler} can easily be used together with a {@code + * ByteClassLoader} to easily compile and load source code in a {@link String}: + * + *
+ * {@code
+ * import com.oracle.java.testlibrary.InMemoryJavaCompiler;
+ * import com.oracle.java.testlibrary.ByteClassLoader;
+ *
+ * class Example {
+ *     public static void main(String[] args) {
+ *         String className = "Foo";
+ *         String sourceCode = "public class " + className + " {" +
+ *                             "    public void bar() {" +
+ *                             "        System.out.println("Hello from bar!");" +
+ *                             "    }" +
+ *                             "}";
+ *         byte[] byteCode = InMemoryJavaCompiler.compile(className, sourceCode);
+ *         Class fooClass = ByteClassLoader.load(className, byteCode);
+ *     }
+ * }
+ * }
+ * 
+ */ +public class InMemoryJavaCompiler { + private static class MemoryJavaFileObject extends SimpleJavaFileObject { + private final String className; + private final CharSequence sourceCode; + private final ByteArrayOutputStream byteCode; + + public MemoryJavaFileObject(String className, CharSequence sourceCode) { + super(URI.create("string:///" + className.replace('.','/') + Kind.SOURCE.extension), Kind.SOURCE); + this.className = className; + this.sourceCode = sourceCode; + this.byteCode = new ByteArrayOutputStream(); + } + + @Override + public CharSequence getCharContent(boolean ignoreEncodingErrors) { + return sourceCode; + } + + @Override + public OutputStream openOutputStream() throws IOException { + return byteCode; + } + + public byte[] getByteCode() { + return byteCode.toByteArray(); + } + + public String getClassName() { + return className; + } + } + + private static class FileManagerWrapper extends ForwardingJavaFileManager { + private MemoryJavaFileObject file; + + public FileManagerWrapper(MemoryJavaFileObject file) { + super(getCompiler().getStandardFileManager(null, null, null)); + this.file = file; + } + + @Override + public JavaFileObject getJavaFileForOutput(Location location, String className, + Kind kind, FileObject sibling) + throws IOException { + if (!file.getClassName().equals(className)) { + throw new IOException("Expected class with name " + file.getClassName() + + ", but got " + className); + } + return file; + } + } + + /** + * Compiles the class with the given name and source code. + * + * @param className The name of the class + * @param sourceCode The source code for the class with name {@code className} + * @throws RuntimeException if the compilation did not succeed + * @return The resulting byte code from the compilation + */ + public static byte[] compile(String className, CharSequence sourceCode) { + MemoryJavaFileObject file = new MemoryJavaFileObject(className, sourceCode); + CompilationTask task = getCompilationTask(file); + + if(!task.call()) { + throw new RuntimeException("Could not compile " + className + " with source code " + sourceCode); + } + + return file.getByteCode(); + } + + private static JavaCompiler getCompiler() { + return ToolProvider.getSystemJavaCompiler(); + } + + private static CompilationTask getCompilationTask(MemoryJavaFileObject file) { + return getCompiler().getTask(null, new FileManagerWrapper(file), null, null, null, Arrays.asList(file)); + } +} diff --git a/hotspot/test/testlibrary/com/oracle/java/testlibrary/InputArguments.java b/hotspot/test/testlibrary/com/oracle/java/testlibrary/InputArguments.java new file mode 100644 index 00000000000..650d6c23390 --- /dev/null +++ b/hotspot/test/testlibrary/com/oracle/java/testlibrary/InputArguments.java @@ -0,0 +1,51 @@ +/* + * 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 com.oracle.java.testlibrary; + +import java.lang.management.RuntimeMXBean; +import java.lang.management.ManagementFactory; +import java.util.List; + +/** + * This class provides access to the input arguments to the VM. + */ +public class InputArguments { + private static final List args; + + static { + RuntimeMXBean runtimeMxBean = ManagementFactory.getRuntimeMXBean(); + args = runtimeMxBean.getInputArguments(); + } + + /** + * Returns true if {@code arg} is an input argument to the VM. + * + * @param arg The name of the argument. + * @return {@code true} if the given argument is an input argument, + * otherwise {@code false}. + */ + public static boolean contains(String arg) { + return args.contains(arg); + } +} diff --git a/hotspot/test/testlibrary/com/oracle/java/testlibrary/PerfCounter.java b/hotspot/test/testlibrary/com/oracle/java/testlibrary/PerfCounter.java new file mode 100644 index 00000000000..1a90f0f1bdf --- /dev/null +++ b/hotspot/test/testlibrary/com/oracle/java/testlibrary/PerfCounter.java @@ -0,0 +1,70 @@ +/* + * 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 com.oracle.java.testlibrary; + +import sun.jvmstat.monitor.Monitor; + +/** + * Represents a performance counter in the JVM. + * + * See http://openjdk.java.net/groups/hotspot/docs/Serviceability.html#bjvmstat + * for more details about performance counters. + */ +public class PerfCounter { + private final Monitor monitor; + private final String name; + + PerfCounter(Monitor monitor, String name) { + this.monitor = monitor; + this.name = name; + } + + /** + * Returns the value of this performance counter as a long. + * + * @return The long value of this performance counter + * @throws RuntimeException If the value of the performance counter isn't a long + */ + public long longValue() { + Object value = monitor.getValue(); + if (value instanceof Long) { + return ((Long) value).longValue(); + } + throw new RuntimeException("Expected " + monitor.getName() + " to have a long value"); + } + + /** + * Returns the name of the performance counter. + * + * @return The name of the performance counter. + */ + public String getName() { + return name; + } + + @Override + public String toString() { + return name; + } +} diff --git a/hotspot/test/testlibrary/com/oracle/java/testlibrary/PerfCounters.java b/hotspot/test/testlibrary/com/oracle/java/testlibrary/PerfCounters.java new file mode 100644 index 00000000000..bfe3d78430a --- /dev/null +++ b/hotspot/test/testlibrary/com/oracle/java/testlibrary/PerfCounters.java @@ -0,0 +1,69 @@ +/* + * 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 com.oracle.java.testlibrary; + +import sun.jvmstat.monitor.Monitor; +import sun.jvmstat.monitor.MonitorException; +import sun.jvmstat.monitor.MonitoredHost; +import sun.jvmstat.monitor.MonitoredVm; +import sun.jvmstat.monitor.VmIdentifier; + +/** + * PerfCounters can be used to get a performance counter from the currently + * executing VM. + * + * Throws a runtime exception if an error occurs while communicating with the + * currently executing VM. + */ +public class PerfCounters { + private final static MonitoredVm vm; + + static { + try { + String pid = Integer.toString(ProcessTools.getProcessId()); + VmIdentifier vmId = new VmIdentifier(pid); + MonitoredHost host = MonitoredHost.getMonitoredHost(vmId); + vm = host.getMonitoredVm(vmId); + } catch (Exception e) { + throw new RuntimeException("Could not connect to the VM"); + } + } + + /** + * Returns the performance counter with the given name. + * + * @param name The name of the performance counter. + * @throws IllegalArgumentException If no counter with the given name exists. + * @throws MonitorException If an error occurs while communicating with the VM. + * @return The performance counter with the given name. + */ + public static PerfCounter findByName(String name) + throws MonitorException, IllegalArgumentException { + Monitor m = vm.findByName(name); + if (m == null) { + throw new IllegalArgumentException("Did not find a performance counter with name " + name); + } + return new PerfCounter(m, name); + } +} From f9cf9e88b8a44407a93a0fffa2b7e60eebc5e2f1 Mon Sep 17 00:00:00 2001 From: Igor Ignatyev Date: Fri, 16 Aug 2013 17:34:37 +0400 Subject: [PATCH 004/218] 8016456: ciReplay test assumes TIERED compilation is available Reviewed-by: vlivanov, kvn, dholmes --- hotspot/test/compiler/ciReplay/common.sh | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/hotspot/test/compiler/ciReplay/common.sh b/hotspot/test/compiler/ciReplay/common.sh index ec3b7fe33cf..df7aa610ba3 100644 --- a/hotspot/test/compiler/ciReplay/common.sh +++ b/hotspot/test/compiler/ciReplay/common.sh @@ -89,7 +89,10 @@ negative_test() { # $1 - initial error_code common_tests() { positive_test $1 "COMMON :: THE SAME FLAGS" - positive_test `expr $1 + 1` "COMMON :: TIERED" -XX:+TieredCompilation + if [ $tiered_available -eq 1 ] + then + positive_test `expr $1 + 1` "COMMON :: TIERED" -XX:+TieredCompilation + fi } # $1 - initial error_code @@ -115,8 +118,11 @@ client_tests() { then negative_test $1 "SERVER :: NON-TIERED" -XX:-TieredCompilation \ -server - positive_test `expr $1 + 1` "SERVER :: TIERED" -XX:+TieredCompilation \ - -server + if [ $tiered_available -eq 1 ] + then + positive_test `expr $1 + 1` "SERVER :: TIERED" -XX:+TieredCompilation \ + -server + fi fi nontiered_tests `expr $1 + 2` $client_level } @@ -167,6 +173,9 @@ client_available=`${JAVA} ${TESTVMOPTS} -client -Xinternalversion 2>&1 | \ grep -c Client` server_available=`${JAVA} ${TESTVMOPTS} -server -Xinternalversion 2>&1 | \ grep -c Server` +tiered_available=`${JAVA} ${TESTVMOPTS} -XX:+TieredCompilation -XX:+PrintFlagsFinal -version | \ + grep TieredCompilation | \ + grep -c true` is_tiered=`${JAVA} ${TESTVMOPTS} -XX:+PrintFlagsFinal -version | \ grep TieredCompilation | \ grep -c true` @@ -177,6 +186,7 @@ server_level=4 echo "client_available=$client_available" echo "server_available=$server_available" +echo "tiered_available=$tiered_available" echo "is_tiered=$is_tiered" # crash vm in compiler thread with generation replay data and 'small' dump-file From caa3d0213010bd361ce2dd4887710c52fa9cacf0 Mon Sep 17 00:00:00 2001 From: Igor Ignatyev Date: Wed, 14 Aug 2013 23:50:23 +0400 Subject: [PATCH 005/218] 8022832: Add WB APIs for OSR compilation Reviewed-by: kvn --- hotspot/src/share/vm/oops/method.cpp | 2 + hotspot/src/share/vm/prims/whitebox.cpp | 81 +++++--- .../share/vm/runtime/compilationPolicy.cpp | 21 +- .../share/vm/runtime/compilationPolicy.hpp | 2 + .../whitebox/ClearMethodStateTest.java | 10 +- .../whitebox/CompilerWhiteBoxTest.java | 196 +++++++++++++++--- .../compiler/whitebox/DeoptimizeAllTest.java | 1 + .../whitebox/DeoptimizeMethodTest.java | 3 +- .../EnqueueMethodForCompilationTest.java | 41 ++-- .../whitebox/IsMethodCompilableTest.java | 20 +- .../whitebox/MakeMethodNotCompilableTest.java | 73 ++++--- .../whitebox/SetDontInlineMethodTest.java | 1 + .../whitebox/SetForceInlineMethodTest.java | 1 + .../whitebox/sun/hotspot/WhiteBox.java | 44 +++- 14 files changed, 371 insertions(+), 125 deletions(-) diff --git a/hotspot/src/share/vm/oops/method.cpp b/hotspot/src/share/vm/oops/method.cpp index ac210e14834..02471f54f86 100644 --- a/hotspot/src/share/vm/oops/method.cpp +++ b/hotspot/src/share/vm/oops/method.cpp @@ -747,6 +747,7 @@ void Method::set_not_compilable(int comp_level, bool report, const char* reason) set_not_c2_compilable(); } CompilationPolicy::policy()->disable_compilation(this); + assert(!CompilationPolicy::can_be_compiled(this, comp_level), "sanity check"); } bool Method::is_not_osr_compilable(int comp_level) const { @@ -773,6 +774,7 @@ void Method::set_not_osr_compilable(int comp_level, bool report, const char* rea set_not_c2_osr_compilable(); } CompilationPolicy::policy()->disable_compilation(this); + assert(!CompilationPolicy::can_be_osr_compiled(this, comp_level), "sanity check"); } // Revert to using the interpreter and clear out the nmethod diff --git a/hotspot/src/share/vm/prims/whitebox.cpp b/hotspot/src/share/vm/prims/whitebox.cpp index 3552ff2062f..6b3051de774 100644 --- a/hotspot/src/share/vm/prims/whitebox.cpp +++ b/hotspot/src/share/vm/prims/whitebox.cpp @@ -196,12 +196,22 @@ WB_ENTRY(void, WB_DeoptimizeAll(JNIEnv* env, jobject o)) VMThread::execute(&op); WB_END -WB_ENTRY(jint, WB_DeoptimizeMethod(JNIEnv* env, jobject o, jobject method)) +WB_ENTRY(jint, WB_DeoptimizeMethod(JNIEnv* env, jobject o, jobject method, jboolean is_osr)) jmethodID jmid = reflected_method_to_jmid(thread, env, method); MutexLockerEx mu(Compile_lock); methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid)); int result = 0; - nmethod* code = mh->code(); + nmethod* code; + if (is_osr) { + int bci = InvocationEntryBci; + while ((code = mh->lookup_osr_nmethod_for(bci, CompLevel_none, false)) != NULL) { + code->mark_for_deoptimization(); + ++result; + bci = code->osr_entry_bci() + 1; + } + } else { + code = mh->code(); + } if (code != NULL) { code->mark_for_deoptimization(); ++result; @@ -214,22 +224,26 @@ WB_ENTRY(jint, WB_DeoptimizeMethod(JNIEnv* env, jobject o, jobject method)) return result; WB_END -WB_ENTRY(jboolean, WB_IsMethodCompiled(JNIEnv* env, jobject o, jobject method)) +WB_ENTRY(jboolean, WB_IsMethodCompiled(JNIEnv* env, jobject o, jobject method, jboolean is_osr)) jmethodID jmid = reflected_method_to_jmid(thread, env, method); MutexLockerEx mu(Compile_lock); methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid)); - nmethod* code = mh->code(); + nmethod* code = is_osr ? mh->lookup_osr_nmethod_for(InvocationEntryBci, CompLevel_none, false) : mh->code(); if (code == NULL) { return JNI_FALSE; } return (code->is_alive() && !code->is_marked_for_deoptimization()); WB_END -WB_ENTRY(jboolean, WB_IsMethodCompilable(JNIEnv* env, jobject o, jobject method, jint comp_level)) +WB_ENTRY(jboolean, WB_IsMethodCompilable(JNIEnv* env, jobject o, jobject method, jint comp_level, jboolean is_osr)) jmethodID jmid = reflected_method_to_jmid(thread, env, method); MutexLockerEx mu(Compile_lock); methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid)); - return CompilationPolicy::can_be_compiled(mh, comp_level); + if (is_osr) { + return CompilationPolicy::can_be_osr_compiled(mh, comp_level); + } else { + return CompilationPolicy::can_be_compiled(mh, comp_level); + } WB_END WB_ENTRY(jboolean, WB_IsMethodQueuedForCompilation(JNIEnv* env, jobject o, jobject method)) @@ -239,18 +253,28 @@ WB_ENTRY(jboolean, WB_IsMethodQueuedForCompilation(JNIEnv* env, jobject o, jobje return mh->queued_for_compilation(); WB_END -WB_ENTRY(jint, WB_GetMethodCompilationLevel(JNIEnv* env, jobject o, jobject method)) +WB_ENTRY(jint, WB_GetMethodCompilationLevel(JNIEnv* env, jobject o, jobject method, jboolean is_osr)) jmethodID jmid = reflected_method_to_jmid(thread, env, method); methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid)); - nmethod* code = mh->code(); + nmethod* code = is_osr ? mh->lookup_osr_nmethod_for(InvocationEntryBci, CompLevel_none, false) : mh->code(); return (code != NULL ? code->comp_level() : CompLevel_none); WB_END - -WB_ENTRY(void, WB_MakeMethodNotCompilable(JNIEnv* env, jobject o, jobject method, jint comp_level)) +WB_ENTRY(void, WB_MakeMethodNotCompilable(JNIEnv* env, jobject o, jobject method, jint comp_level, jboolean is_osr)) jmethodID jmid = reflected_method_to_jmid(thread, env, method); methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid)); - mh->set_not_compilable(comp_level, true /* report */, "WhiteBox"); + if (is_osr) { + mh->set_not_osr_compilable(comp_level, true /* report */, "WhiteBox"); + } else { + mh->set_not_compilable(comp_level, true /* report */, "WhiteBox"); + } +WB_END + +WB_ENTRY(jint, WB_GetMethodEntryBci(JNIEnv* env, jobject o, jobject method)) + jmethodID jmid = reflected_method_to_jmid(thread, env, method); + methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid)); + nmethod* code = mh->lookup_osr_nmethod_for(InvocationEntryBci, CompLevel_none, false); + return (code != NULL && code->is_osr_method() ? code->osr_entry_bci() : InvocationEntryBci); WB_END WB_ENTRY(jboolean, WB_TestSetDontInlineMethod(JNIEnv* env, jobject o, jobject method, jboolean value)) @@ -261,12 +285,15 @@ WB_ENTRY(jboolean, WB_TestSetDontInlineMethod(JNIEnv* env, jobject o, jobject me return result; WB_END -WB_ENTRY(jint, WB_GetCompileQueuesSize(JNIEnv* env, jobject o)) - return CompileBroker::queue_size(CompLevel_full_optimization) /* C2 */ + - CompileBroker::queue_size(CompLevel_full_profile) /* C1 */; +WB_ENTRY(jint, WB_GetCompileQueueSize(JNIEnv* env, jobject o, jint comp_level)) + if (comp_level == CompLevel_any) { + return CompileBroker::queue_size(CompLevel_full_optimization) /* C2 */ + + CompileBroker::queue_size(CompLevel_full_profile) /* C1 */; + } else { + return CompileBroker::queue_size(comp_level); + } WB_END - WB_ENTRY(jboolean, WB_TestSetForceInlineMethod(JNIEnv* env, jobject o, jobject method, jboolean value)) jmethodID jmid = reflected_method_to_jmid(thread, env, method); methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid)); @@ -275,10 +302,10 @@ WB_ENTRY(jboolean, WB_TestSetForceInlineMethod(JNIEnv* env, jobject o, jobject m return result; WB_END -WB_ENTRY(jboolean, WB_EnqueueMethodForCompilation(JNIEnv* env, jobject o, jobject method, jint comp_level)) +WB_ENTRY(jboolean, WB_EnqueueMethodForCompilation(JNIEnv* env, jobject o, jobject method, jint comp_level, jint bci)) jmethodID jmid = reflected_method_to_jmid(thread, env, method); methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid)); - nmethod* nm = CompileBroker::compile_method(mh, InvocationEntryBci, comp_level, mh, mh->invocation_count(), "WhiteBox", THREAD); + nmethod* nm = CompileBroker::compile_method(mh, bci, comp_level, mh, mh->invocation_count(), "WhiteBox", THREAD); MutexLockerEx mu(Compile_lock); return (mh->queued_for_compilation() || nm != NULL); WB_END @@ -324,7 +351,6 @@ WB_ENTRY(jboolean, WB_IsInStringTable(JNIEnv* env, jobject o, jstring javaString return (StringTable::lookup(name, len) != NULL); WB_END - WB_ENTRY(void, WB_FullGC(JNIEnv* env, jobject o)) Universe::heap()->collector_policy()->set_should_clear_all_soft_refs(true); Universe::heap()->collect(GCCause::_last_ditch_collection); @@ -423,31 +449,32 @@ static JNINativeMethod methods[] = { {CC"NMTWaitForDataMerge", CC"()Z", (void*)&WB_NMTWaitForDataMerge}, #endif // INCLUDE_NMT {CC"deoptimizeAll", CC"()V", (void*)&WB_DeoptimizeAll }, - {CC"deoptimizeMethod", CC"(Ljava/lang/reflect/Executable;)I", + {CC"deoptimizeMethod", CC"(Ljava/lang/reflect/Executable;Z)I", (void*)&WB_DeoptimizeMethod }, - {CC"isMethodCompiled", CC"(Ljava/lang/reflect/Executable;)Z", + {CC"isMethodCompiled", CC"(Ljava/lang/reflect/Executable;Z)Z", (void*)&WB_IsMethodCompiled }, - {CC"isMethodCompilable", CC"(Ljava/lang/reflect/Executable;I)Z", + {CC"isMethodCompilable", CC"(Ljava/lang/reflect/Executable;IZ)Z", (void*)&WB_IsMethodCompilable}, {CC"isMethodQueuedForCompilation", CC"(Ljava/lang/reflect/Executable;)Z", (void*)&WB_IsMethodQueuedForCompilation}, {CC"makeMethodNotCompilable", - CC"(Ljava/lang/reflect/Executable;I)V", (void*)&WB_MakeMethodNotCompilable}, + CC"(Ljava/lang/reflect/Executable;IZ)V", (void*)&WB_MakeMethodNotCompilable}, {CC"testSetDontInlineMethod", CC"(Ljava/lang/reflect/Executable;Z)Z", (void*)&WB_TestSetDontInlineMethod}, {CC"getMethodCompilationLevel", - CC"(Ljava/lang/reflect/Executable;)I", (void*)&WB_GetMethodCompilationLevel}, - {CC"getCompileQueuesSize", - CC"()I", (void*)&WB_GetCompileQueuesSize}, + CC"(Ljava/lang/reflect/Executable;Z)I", (void*)&WB_GetMethodCompilationLevel}, + {CC"getMethodEntryBci", + CC"(Ljava/lang/reflect/Executable;)I", (void*)&WB_GetMethodEntryBci}, + {CC"getCompileQueueSize", + CC"(I)I", (void*)&WB_GetCompileQueueSize}, {CC"testSetForceInlineMethod", CC"(Ljava/lang/reflect/Executable;Z)Z", (void*)&WB_TestSetForceInlineMethod}, {CC"enqueueMethodForCompilation", - CC"(Ljava/lang/reflect/Executable;I)Z", (void*)&WB_EnqueueMethodForCompilation}, + CC"(Ljava/lang/reflect/Executable;II)Z", (void*)&WB_EnqueueMethodForCompilation}, {CC"clearMethodState", CC"(Ljava/lang/reflect/Executable;)V", (void*)&WB_ClearMethodState}, {CC"isInStringTable", CC"(Ljava/lang/String;)Z", (void*)&WB_IsInStringTable }, {CC"fullGC", CC"()V", (void*)&WB_FullGC }, - {CC"readReservedMemory", CC"()V", (void*)&WB_ReadReservedMemory }, }; diff --git a/hotspot/src/share/vm/runtime/compilationPolicy.cpp b/hotspot/src/share/vm/runtime/compilationPolicy.cpp index 8fff9586b5b..23fbc87f766 100644 --- a/hotspot/src/share/vm/runtime/compilationPolicy.cpp +++ b/hotspot/src/share/vm/runtime/compilationPolicy.cpp @@ -138,6 +138,23 @@ bool CompilationPolicy::can_be_compiled(methodHandle m, int comp_level) { return false; } +// Returns true if m is allowed to be osr compiled +bool CompilationPolicy::can_be_osr_compiled(methodHandle m, int comp_level) { + bool result = false; + if (comp_level == CompLevel_all) { + if (TieredCompilation) { + // enough to be osr compilable at any level for tiered + result = !m->is_not_osr_compilable(CompLevel_simple) || !m->is_not_osr_compilable(CompLevel_full_optimization); + } else { + // must be osr compilable at available level for non-tiered + result = !m->is_not_osr_compilable(CompLevel_highest_tier); + } + } else if (is_compile(comp_level)) { + result = !m->is_not_osr_compilable(comp_level); + } + return (result && can_be_compiled(m, comp_level)); +} + bool CompilationPolicy::is_compilation_enabled() { // NOTE: CompileBroker::should_compile_new_jobs() checks for UseCompiler return !delay_compilation_during_startup() && CompileBroker::should_compile_new_jobs(); @@ -458,7 +475,7 @@ void SimpleCompPolicy::method_back_branch_event(methodHandle m, int bci, JavaThr const int hot_count = m->backedge_count(); const char* comment = "backedge_count"; - if (is_compilation_enabled() && !m->is_not_osr_compilable(comp_level) && can_be_compiled(m, comp_level)) { + if (is_compilation_enabled() && can_be_osr_compiled(m, comp_level)) { CompileBroker::compile_method(m, bci, comp_level, m, hot_count, comment, thread); NOT_PRODUCT(trace_osr_completion(m->lookup_osr_nmethod_for(bci, comp_level, true));) } @@ -514,7 +531,7 @@ void StackWalkCompPolicy::method_back_branch_event(methodHandle m, int bci, Java const int hot_count = m->backedge_count(); const char* comment = "backedge_count"; - if (is_compilation_enabled() && !m->is_not_osr_compilable(comp_level) && can_be_compiled(m, comp_level)) { + if (is_compilation_enabled() && can_be_osr_compiled(m, comp_level)) { CompileBroker::compile_method(m, bci, comp_level, m, hot_count, comment, thread); NOT_PRODUCT(trace_osr_completion(m->lookup_osr_nmethod_for(bci, comp_level, true));) } diff --git a/hotspot/src/share/vm/runtime/compilationPolicy.hpp b/hotspot/src/share/vm/runtime/compilationPolicy.hpp index 6d90e049e9b..3bba54e5dcd 100644 --- a/hotspot/src/share/vm/runtime/compilationPolicy.hpp +++ b/hotspot/src/share/vm/runtime/compilationPolicy.hpp @@ -52,6 +52,8 @@ public: static bool must_be_compiled(methodHandle m, int comp_level = CompLevel_all); // m is allowed to be compiled static bool can_be_compiled(methodHandle m, int comp_level = CompLevel_all); + // m is allowed to be osr compiled + static bool can_be_osr_compiled(methodHandle m, int comp_level = CompLevel_all); static bool is_compilation_enabled(); static void set_policy(CompilationPolicy* policy) { _policy = policy; } static CompilationPolicy* policy() { return _policy; } diff --git a/hotspot/test/compiler/whitebox/ClearMethodStateTest.java b/hotspot/test/compiler/whitebox/ClearMethodStateTest.java index 6b718ec8851..3f66a5a6966 100644 --- a/hotspot/test/compiler/whitebox/ClearMethodStateTest.java +++ b/hotspot/test/compiler/whitebox/ClearMethodStateTest.java @@ -23,6 +23,7 @@ /* * @test ClearMethodStateTest + * @bug 8006683 8007288 8022832 * @library /testlibrary /testlibrary/whitebox * @build ClearMethodStateTest * @run main ClassFileInstaller sun.hotspot.WhiteBox @@ -59,16 +60,19 @@ public class ClearMethodStateTest extends CompilerWhiteBoxTest { WHITE_BOX.clearMethodState(method); checkCompiled(); WHITE_BOX.clearMethodState(method); - WHITE_BOX.deoptimizeMethod(method); + deoptimize(); checkNotCompiled(); - + if (testCase.isOsr) { + // part test isn't applicable for OSR test case + return; + } if (!TIERED_COMPILATION) { WHITE_BOX.clearMethodState(method); compile(COMPILE_THRESHOLD); checkCompiled(); - WHITE_BOX.deoptimizeMethod(method); + deoptimize(); checkNotCompiled(); WHITE_BOX.clearMethodState(method); diff --git a/hotspot/test/compiler/whitebox/CompilerWhiteBoxTest.java b/hotspot/test/compiler/whitebox/CompilerWhiteBoxTest.java index f09922cec8b..f6c2414f17d 100644 --- a/hotspot/test/compiler/whitebox/CompilerWhiteBoxTest.java +++ b/hotspot/test/compiler/whitebox/CompilerWhiteBoxTest.java @@ -44,8 +44,14 @@ public abstract class CompilerWhiteBoxTest { protected static int COMP_LEVEL_ANY = -1; /** {@code CompLevel::CompLevel_simple} -- C1 */ protected static int COMP_LEVEL_SIMPLE = 1; + /** {@code CompLevel::CompLevel_limited_profile} -- C1, invocation & backedge counters */ + protected static int COMP_LEVEL_LIMITED_PROFILE = 2; + /** {@code CompLevel::CompLevel_full_profile} -- C1, invocation & backedge counters + mdo */ + protected static int COMP_LEVEL_FULL_PROFILE = 3; /** {@code CompLevel::CompLevel_full_optimization} -- C2 or Shark */ protected static int COMP_LEVEL_FULL_OPTIMIZATION = 4; + /** Maximal value for CompLeveL */ + protected static int COMP_LEVEL_MAX = COMP_LEVEL_FULL_OPTIMIZATION; /** Instance of WhiteBox */ protected static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); @@ -64,6 +70,21 @@ public abstract class CompilerWhiteBoxTest { /** Flag for verbose output, true if {@code -Dverbose} specified */ protected static final boolean IS_VERBOSE = System.getProperty("verbose") != null; + /** count of invocation to triger compilation */ + protected static final int THRESHOLD; + /** count of invocation to triger OSR compilation */ + protected static final long BACKEDGE_THRESHOLD; + + static { + if (TIERED_COMPILATION) { + THRESHOLD = 150000; + BACKEDGE_THRESHOLD = 0xFFFFFFFFL; + } else { + THRESHOLD = COMPILE_THRESHOLD; + BACKEDGE_THRESHOLD = COMPILE_THRESHOLD * Long.parseLong(getVMOption( + "OnStackReplacePercentage")); + } + } /** * Returns value of VM option. @@ -112,7 +133,7 @@ public abstract class CompilerWhiteBoxTest { /** tested method */ protected final Executable method; - private final Callable callable; + protected final TestCase testCase; /** * Constructor. @@ -123,7 +144,7 @@ public abstract class CompilerWhiteBoxTest { Objects.requireNonNull(testCase); System.out.println("TEST CASE:" + testCase.name()); method = testCase.executable; - callable = testCase.callable; + this.testCase = testCase; } /** @@ -169,12 +190,18 @@ public abstract class CompilerWhiteBoxTest { if (WHITE_BOX.isMethodQueuedForCompilation(method)) { throw new RuntimeException(method + " must not be in queue"); } - if (WHITE_BOX.isMethodCompiled(method)) { + if (WHITE_BOX.isMethodCompiled(method, false)) { throw new RuntimeException(method + " must be not compiled"); } - if (WHITE_BOX.getMethodCompilationLevel(method) != 0) { + if (WHITE_BOX.getMethodCompilationLevel(method, false) != 0) { throw new RuntimeException(method + " comp_level must be == 0"); } + if (WHITE_BOX.isMethodCompiled(method, true)) { + throw new RuntimeException(method + " must be not osr_compiled"); + } + if (WHITE_BOX.getMethodCompilationLevel(method, true) != 0) { + throw new RuntimeException(method + " osr_comp_level must be == 0"); + } } /** @@ -192,14 +219,46 @@ public abstract class CompilerWhiteBoxTest { method, System.currentTimeMillis() - start); return; } - if (!WHITE_BOX.isMethodCompiled(method)) { - throw new RuntimeException(method + " must be compiled"); + if (!WHITE_BOX.isMethodCompiled(method, testCase.isOsr)) { + throw new RuntimeException(method + " must be " + + (testCase.isOsr ? "osr_" : "") + "compiled"); } - if (WHITE_BOX.getMethodCompilationLevel(method) == 0) { - throw new RuntimeException(method + " comp_level must be != 0"); + if (WHITE_BOX.getMethodCompilationLevel(method, testCase.isOsr) == 0) { + throw new RuntimeException(method + + (testCase.isOsr ? " osr_" : " ") + + "comp_level must be != 0"); } } + protected final void deoptimize() { + WHITE_BOX.deoptimizeMethod(method, testCase.isOsr); + if (testCase.isOsr) { + WHITE_BOX.deoptimizeMethod(method, false); + } + } + + protected final int getCompLevel() { + return WHITE_BOX.getMethodCompilationLevel(method, testCase.isOsr); + } + + protected final boolean isCompilable() { + return WHITE_BOX.isMethodCompilable(method, COMP_LEVEL_ANY, + testCase.isOsr); + } + + protected final boolean isCompilable(int compLevel) { + return WHITE_BOX.isMethodCompilable(method, compLevel, testCase.isOsr); + } + + protected final void makeNotCompilable() { + WHITE_BOX.makeMethodNotCompilable(method, COMP_LEVEL_ANY, + testCase.isOsr); + } + + protected final void makeNotCompilable(int compLevel) { + WHITE_BOX.makeMethodNotCompilable(method, compLevel, testCase.isOsr); + } + /** * Waits for completion of background compilation of {@linkplain #method}. */ @@ -226,12 +285,18 @@ public abstract class CompilerWhiteBoxTest { protected final void printInfo() { System.out.printf("%n%s:%n", method); System.out.printf("\tcompilable:\t%b%n", - WHITE_BOX.isMethodCompilable(method)); + WHITE_BOX.isMethodCompilable(method, COMP_LEVEL_ANY, false)); System.out.printf("\tcompiled:\t%b%n", - WHITE_BOX.isMethodCompiled(method)); + WHITE_BOX.isMethodCompiled(method, false)); System.out.printf("\tcomp_level:\t%d%n", - WHITE_BOX.getMethodCompilationLevel(method)); - System.out.printf("\tin_queue:\t%b%n", + WHITE_BOX.getMethodCompilationLevel(method, false)); + System.out.printf("\tosr_compilable:\t%b%n", + WHITE_BOX.isMethodCompilable(method, COMP_LEVEL_ANY, true)); + System.out.printf("\tosr_compiled:\t%b%n", + WHITE_BOX.isMethodCompiled(method, true)); + System.out.printf("\tosr_comp_level:\t%d%n", + WHITE_BOX.getMethodCompilationLevel(method, true)); + System.out.printf("\tin_queue:\t%b%n", WHITE_BOX.isMethodQueuedForCompilation(method)); System.out.printf("compile_queues_size:\t%d%n%n", WHITE_BOX.getCompileQueuesSize()); @@ -244,18 +309,22 @@ public abstract class CompilerWhiteBoxTest { /** * Tries to trigger compilation of {@linkplain #method} by call - * {@linkplain #callable} enough times. + * {@linkplain #testCase.callable} enough times. * * @return accumulated result * @see #compile(int) */ protected final int compile() { - return compile(Math.max(COMPILE_THRESHOLD, 150000)); + if (testCase.isOsr) { + return compile(1); + } else { + return compile(THRESHOLD); + } } /** * Tries to trigger compilation of {@linkplain #method} by call - * {@linkplain #callable} specified times. + * {@linkplain #testCase.callable} specified times. * * @param count invocation count * @return accumulated result @@ -265,7 +334,7 @@ public abstract class CompilerWhiteBoxTest { Integer tmp; for (int i = 0; i < count; ++i) { try { - tmp = callable.call(); + tmp = testCase.callable.call(); } catch (Exception e) { tmp = null; } @@ -283,23 +352,36 @@ public abstract class CompilerWhiteBoxTest { */ enum TestCase { /** constructor test case */ - CONSTRUCTOR_TEST(Helper.CONSTRUCTOR, Helper.CONSTRUCTOR_CALLABLE), + CONSTRUCTOR_TEST(Helper.CONSTRUCTOR, Helper.CONSTRUCTOR_CALLABLE, false), /** method test case */ - METOD_TEST(Helper.METHOD, Helper.METHOD_CALLABLE), + METOD_TEST(Helper.METHOD, Helper.METHOD_CALLABLE, false), /** static method test case */ - STATIC_TEST(Helper.STATIC, Helper.STATIC_CALLABLE); + STATIC_TEST(Helper.STATIC, Helper.STATIC_CALLABLE, false), + + /** OSR constructor test case */ + OSR_CONSTRUCTOR_TEST(Helper.OSR_CONSTRUCTOR, + Helper.OSR_CONSTRUCTOR_CALLABLE, true), + /** OSR method test case */ + OSR_METOD_TEST(Helper.OSR_METHOD, Helper.OSR_METHOD_CALLABLE, true), + /** OSR static method test case */ + OSR_STATIC_TEST(Helper.OSR_STATIC, Helper.OSR_STATIC_CALLABLE, true); /** tested method */ final Executable executable; /** object to invoke {@linkplain #executable} */ final Callable callable; + /** flag for OSR test case */ + final boolean isOsr; - private TestCase(Executable executable, Callable callable) { + private TestCase(Executable executable, Callable callable, + boolean isOsr) { this.executable = executable; this.callable = callable; + this.isOsr = isOsr; } private static class Helper { + private static final Callable CONSTRUCTOR_CALLABLE = new Callable() { @Override @@ -326,9 +408,39 @@ enum TestCase { } }; + private static final Callable OSR_CONSTRUCTOR_CALLABLE + = new Callable() { + @Override + public Integer call() throws Exception { + return new Helper(null).hashCode(); + } + }; + + private static final Callable OSR_METHOD_CALLABLE + = new Callable() { + private final Helper helper = new Helper(); + + @Override + public Integer call() throws Exception { + return helper.osrMethod(); + } + }; + + private static final Callable OSR_STATIC_CALLABLE + = new Callable() { + @Override + public Integer call() throws Exception { + return osrStaticMethod(); + } + }; + + private static final Constructor CONSTRUCTOR; + private static final Constructor OSR_CONSTRUCTOR; private static final Method METHOD; private static final Method STATIC; + private static final Method OSR_METHOD; + private static final Method OSR_STATIC; static { try { @@ -338,17 +450,26 @@ enum TestCase { "exception on getting method Helper.(int)", e); } try { - METHOD = Helper.class.getDeclaredMethod("method"); + OSR_CONSTRUCTOR = Helper.class.getDeclaredConstructor( + Object.class); } catch (NoSuchMethodException | SecurityException e) { throw new RuntimeException( - "exception on getting method Helper.method()", e); + "exception on getting method Helper.(Object)", e); } + METHOD = getMethod("method"); + STATIC = getMethod("staticMethod"); + OSR_METHOD = getMethod("osrMethod"); + OSR_STATIC = getMethod("osrStaticMethod"); + } + + private static Method getMethod(String name) { try { - STATIC = Helper.class.getDeclaredMethod("staticMethod"); + return Helper.class.getDeclaredMethod(name); } catch (NoSuchMethodException | SecurityException e) { throw new RuntimeException( - "exception on getting method Helper.staticMethod()", e); + "exception on getting method Helper." + name, e); } + } private static int staticMethod() { @@ -359,12 +480,39 @@ enum TestCase { return 42; } + private static int osrStaticMethod() { + int result = 0; + for (long i = 0; i < CompilerWhiteBoxTest.BACKEDGE_THRESHOLD; ++i) { + result += staticMethod(); + } + return result; + } + + private int osrMethod() { + int result = 0; + for (long i = 0; i < CompilerWhiteBoxTest.BACKEDGE_THRESHOLD; ++i) { + result += method(); + } + return result; + } + private final int x; + // for method and OSR method test case public Helper() { x = 0; } + // for OSR constructor test case + private Helper(Object o) { + int result = 0; + for (long i = 0; i < CompilerWhiteBoxTest.BACKEDGE_THRESHOLD; ++i) { + result += method(); + } + x = result; + } + + // for constructor test case private Helper(int x) { this.x = x; } diff --git a/hotspot/test/compiler/whitebox/DeoptimizeAllTest.java b/hotspot/test/compiler/whitebox/DeoptimizeAllTest.java index c659ac164e7..2f49d054a48 100644 --- a/hotspot/test/compiler/whitebox/DeoptimizeAllTest.java +++ b/hotspot/test/compiler/whitebox/DeoptimizeAllTest.java @@ -23,6 +23,7 @@ /* * @test DeoptimizeAllTest + * @bug 8006683 8007288 8022832 * @library /testlibrary /testlibrary/whitebox * @build DeoptimizeAllTest * @run main ClassFileInstaller sun.hotspot.WhiteBox diff --git a/hotspot/test/compiler/whitebox/DeoptimizeMethodTest.java b/hotspot/test/compiler/whitebox/DeoptimizeMethodTest.java index 0fedc3402af..502c9b77fb7 100644 --- a/hotspot/test/compiler/whitebox/DeoptimizeMethodTest.java +++ b/hotspot/test/compiler/whitebox/DeoptimizeMethodTest.java @@ -23,6 +23,7 @@ /* * @test DeoptimizeMethodTest + * @bug 8006683 8007288 8022832 * @library /testlibrary /testlibrary/whitebox * @build DeoptimizeMethodTest * @run main ClassFileInstaller sun.hotspot.WhiteBox @@ -54,7 +55,7 @@ public class DeoptimizeMethodTest extends CompilerWhiteBoxTest { protected void test() throws Exception { compile(); checkCompiled(); - WHITE_BOX.deoptimizeMethod(method); + deoptimize(); checkNotCompiled(); } } diff --git a/hotspot/test/compiler/whitebox/EnqueueMethodForCompilationTest.java b/hotspot/test/compiler/whitebox/EnqueueMethodForCompilationTest.java index b14bd96709f..909a9fda281 100644 --- a/hotspot/test/compiler/whitebox/EnqueueMethodForCompilationTest.java +++ b/hotspot/test/compiler/whitebox/EnqueueMethodForCompilationTest.java @@ -23,10 +23,11 @@ /* * @test EnqueueMethodForCompilationTest + * @bug 8006683 8007288 8022832 * @library /testlibrary /testlibrary/whitebox * @build EnqueueMethodForCompilationTest * @run main ClassFileInstaller sun.hotspot.WhiteBox - * @run main/othervm -Xbootclasspath/a:. -Xmixed -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:CompileCommand=compileonly,TestCase$Helper::* EnqueueMethodForCompilationTest + * @run main/othervm/timeout=600 -Xbootclasspath/a:. -Xmixed -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:CompileCommand=compileonly,TestCase$Helper::* EnqueueMethodForCompilationTest * @summary testing of WB::enqueueMethodForCompilation() * @author igor.ignatyev@oracle.com */ @@ -50,7 +51,7 @@ public class EnqueueMethodForCompilationTest extends CompilerWhiteBoxTest { // method can not be compiled on level 'none' WHITE_BOX.enqueueMethodForCompilation(method, COMP_LEVEL_NONE); - if (WHITE_BOX.isMethodCompilable(method, COMP_LEVEL_NONE)) { + if (isCompilable(COMP_LEVEL_NONE)) { throw new RuntimeException(method + " is compilable at level COMP_LEVEL_NONE"); } @@ -60,27 +61,29 @@ public class EnqueueMethodForCompilationTest extends CompilerWhiteBoxTest { WHITE_BOX.enqueueMethodForCompilation(method, COMP_LEVEL_ANY); checkNotCompiled(); - WHITE_BOX.enqueueMethodForCompilation(method, 5); - if (!WHITE_BOX.isMethodCompilable(method, 5)) { - checkNotCompiled(); - compile(); - checkCompiled(); - } else { - checkCompiled(); - } - - int compLevel = WHITE_BOX.getMethodCompilationLevel(method); - WHITE_BOX.deoptimizeMethod(method); - checkNotCompiled(); - - WHITE_BOX.enqueueMethodForCompilation(method, compLevel); - checkCompiled(); - WHITE_BOX.deoptimizeMethod(method); + // not existing comp level + WHITE_BOX.enqueueMethodForCompilation(method, 42); checkNotCompiled(); compile(); checkCompiled(); - WHITE_BOX.deoptimizeMethod(method); + + int compLevel = getCompLevel(); + int bci = WHITE_BOX.getMethodEntryBci(method); + System.out.println("bci = " + bci); + printInfo(); + deoptimize(); + printInfo(); + checkNotCompiled(); + printInfo(); + WHITE_BOX.enqueueMethodForCompilation(method, compLevel, bci); + checkCompiled(); + deoptimize(); + checkNotCompiled(); + + compile(); + checkCompiled(); + deoptimize(); checkNotCompiled(); } } diff --git a/hotspot/test/compiler/whitebox/IsMethodCompilableTest.java b/hotspot/test/compiler/whitebox/IsMethodCompilableTest.java index bb7da4ab007..e9817deb1d3 100644 --- a/hotspot/test/compiler/whitebox/IsMethodCompilableTest.java +++ b/hotspot/test/compiler/whitebox/IsMethodCompilableTest.java @@ -23,11 +23,11 @@ /* * @test IsMethodCompilableTest - * @bug 8007270 + * @bug 8007270 8006683 8007288 8022832 * @library /testlibrary /testlibrary/whitebox * @build IsMethodCompilableTest * @run main ClassFileInstaller sun.hotspot.WhiteBox - * @run main/othervm/timeout=600 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:CompileCommand=compileonly,TestCase$Helper::* IsMethodCompilableTest + * @run main/othervm/timeout=2400 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:CompileCommand=compileonly,TestCase$Helper::* IsMethodCompilableTest * @summary testing of WB::isMethodCompilable() * @author igor.ignatyev@oracle.com */ @@ -68,7 +68,7 @@ public class IsMethodCompilableTest extends CompilerWhiteBoxTest { */ @Override protected void test() throws Exception { - if (!WHITE_BOX.isMethodCompilable(method)) { + if (!isCompilable()) { throw new RuntimeException(method + " must be compilable"); } System.out.println("PerMethodRecompilationCutoff = " @@ -83,7 +83,8 @@ public class IsMethodCompilableTest extends CompilerWhiteBoxTest { for (long i = 0L, n = PER_METHOD_RECOMPILATION_CUTOFF - 1; i < n; ++i) { compileAndDeoptimize(); } - if (!WHITE_BOX.isMethodCompilable(method)) { + if (!testCase.isOsr && !isCompilable()) { + // in osr test case count of deopt maybe more than iterations throw new RuntimeException(method + " is not compilable after " + (PER_METHOD_RECOMPILATION_CUTOFF - 1) + " iterations"); } @@ -92,15 +93,16 @@ public class IsMethodCompilableTest extends CompilerWhiteBoxTest { // deoptimize 'PerMethodRecompilationCutoff' + 1 times long i; for (i = 0L; i < PER_METHOD_RECOMPILATION_CUTOFF - && WHITE_BOX.isMethodCompilable(method); ++i) { + && isCompilable(); ++i) { compileAndDeoptimize(); } - if (i != PER_METHOD_RECOMPILATION_CUTOFF) { + if (!testCase.isOsr && i != PER_METHOD_RECOMPILATION_CUTOFF) { + // in osr test case count of deopt maybe more than iterations throw new RuntimeException(method + " is not compilable after " + i + " iterations, but must only after " + PER_METHOD_RECOMPILATION_CUTOFF); } - if (WHITE_BOX.isMethodCompilable(method)) { + if (isCompilable()) { throw new RuntimeException(method + " is still compilable after " + PER_METHOD_RECOMPILATION_CUTOFF + " iterations"); } @@ -109,7 +111,7 @@ public class IsMethodCompilableTest extends CompilerWhiteBoxTest { // WB.clearMethodState() must reset no-compilable flags WHITE_BOX.clearMethodState(method); - if (!WHITE_BOX.isMethodCompilable(method)) { + if (!isCompilable()) { throw new RuntimeException(method + " is not compilable after clearMethodState()"); } @@ -120,6 +122,6 @@ public class IsMethodCompilableTest extends CompilerWhiteBoxTest { private void compileAndDeoptimize() throws Exception { compile(); waitBackgroundCompilation(); - WHITE_BOX.deoptimizeMethod(method); + deoptimize(); } } diff --git a/hotspot/test/compiler/whitebox/MakeMethodNotCompilableTest.java b/hotspot/test/compiler/whitebox/MakeMethodNotCompilableTest.java index 8290dcecc3a..3768b3b0191 100644 --- a/hotspot/test/compiler/whitebox/MakeMethodNotCompilableTest.java +++ b/hotspot/test/compiler/whitebox/MakeMethodNotCompilableTest.java @@ -23,16 +23,16 @@ /* * @test MakeMethodNotCompilableTest - * @bug 8012322 + * @bug 8012322 8006683 8007288 8022832 * @library /testlibrary /testlibrary/whitebox * @build MakeMethodNotCompilableTest * @run main ClassFileInstaller sun.hotspot.WhiteBox - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:CompileCommand=compileonly,TestCase$Helper::* MakeMethodNotCompilableTest + * @run main/othervm/timeout=2400 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:CompileCommand=compileonly,TestCase$Helper::* MakeMethodNotCompilableTest * @summary testing of WB::makeMethodNotCompilable() * @author igor.ignatyev@oracle.com */ public class MakeMethodNotCompilableTest extends CompilerWhiteBoxTest { - + private int bci; public static void main(String[] args) throws Exception { if (args.length == 0) { for (TestCase test : TestCase.values()) { @@ -63,25 +63,27 @@ public class MakeMethodNotCompilableTest extends CompilerWhiteBoxTest { @Override protected void test() throws Exception { checkNotCompiled(); - if (!WHITE_BOX.isMethodCompilable(method)) { + if (!isCompilable()) { throw new RuntimeException(method + " must be compilable"); } + bci = getBci(); + if (TIERED_COMPILATION) { final int tierLimit = TIERED_STOP_AT_LEVEL + 1; for (int testedTier = 1; testedTier < tierLimit; ++testedTier) { testTier(testedTier); } for (int testedTier = 1; testedTier < tierLimit; ++testedTier) { - WHITE_BOX.makeMethodNotCompilable(method, testedTier); - if (WHITE_BOX.isMethodCompilable(method, testedTier)) { + makeNotCompilable(testedTier); + if (isCompilable(testedTier)) { throw new RuntimeException(method + " must be not compilable at level" + testedTier); } - WHITE_BOX.enqueueMethodForCompilation(method, testedTier); + WHITE_BOX.enqueueMethodForCompilation(method, testedTier, bci); checkNotCompiled(); - if (!WHITE_BOX.isMethodCompilable(method)) { + if (!isCompilable()) { System.out.println(method + " is not compilable after level " + testedTier); } @@ -89,15 +91,20 @@ public class MakeMethodNotCompilableTest extends CompilerWhiteBoxTest { } else { compile(); checkCompiled(); - int compLevel = WHITE_BOX.getMethodCompilationLevel(method); - WHITE_BOX.deoptimizeMethod(method); - WHITE_BOX.makeMethodNotCompilable(method, compLevel); - if (WHITE_BOX.isMethodCompilable(method, COMP_LEVEL_ANY)) { + int compLevel = getCompLevel(); + deoptimize(); + makeNotCompilable(compLevel); + if (isCompilable(COMP_LEVEL_ANY)) { throw new RuntimeException(method + " must be not compilable at CompLevel::CompLevel_any," + " after it is not compilable at " + compLevel); } + WHITE_BOX.clearMethodState(method); + if (!isCompilable()) { + throw new RuntimeException(method + + " is not compilable after clearMethodState()"); + } // nocompilable at opposite level must make no sense int oppositeLevel; @@ -106,16 +113,16 @@ public class MakeMethodNotCompilableTest extends CompilerWhiteBoxTest { } else { oppositeLevel = COMP_LEVEL_SIMPLE; } - WHITE_BOX.makeMethodNotCompilable(method, oppositeLevel); + makeNotCompilable(oppositeLevel); - if (!WHITE_BOX.isMethodCompilable(method, COMP_LEVEL_ANY)) { + if (!isCompilable(COMP_LEVEL_ANY)) { throw new RuntimeException(method + " must be compilable at CompLevel::CompLevel_any," + " even it is not compilable at opposite level [" + compLevel + "]"); } - if (!WHITE_BOX.isMethodCompilable(method, compLevel)) { + if (!isCompilable(compLevel)) { throw new RuntimeException(method + " must be compilable at level " + compLevel + ", even it is not compilable at opposite level [" @@ -126,24 +133,24 @@ public class MakeMethodNotCompilableTest extends CompilerWhiteBoxTest { // clearing after tiered/non-tiered tests // WB.clearMethodState() must reset no-compilable flags WHITE_BOX.clearMethodState(method); - if (!WHITE_BOX.isMethodCompilable(method)) { + if (!isCompilable()) { throw new RuntimeException(method + " is not compilable after clearMethodState()"); } - WHITE_BOX.makeMethodNotCompilable(method); - if (WHITE_BOX.isMethodCompilable(method)) { + makeNotCompilable(); + if (isCompilable()) { throw new RuntimeException(method + " must be not compilable"); } compile(); checkNotCompiled(); - if (WHITE_BOX.isMethodCompilable(method)) { + if (isCompilable()) { throw new RuntimeException(method + " must be not compilable"); } // WB.clearMethodState() must reset no-compilable flags WHITE_BOX.clearMethodState(method); - if (!WHITE_BOX.isMethodCompilable(method)) { + if (!isCompilable()) { throw new RuntimeException(method + " is not compilable after clearMethodState()"); } @@ -153,24 +160,23 @@ public class MakeMethodNotCompilableTest extends CompilerWhiteBoxTest { // separately tests each tier private void testTier(int testedTier) { - if (!WHITE_BOX.isMethodCompilable(method, testedTier)) { + if (!isCompilable(testedTier)) { throw new RuntimeException(method + " is not compilable on start"); } - WHITE_BOX.makeMethodNotCompilable(method, testedTier); + makeNotCompilable(testedTier); // tests for all other tiers for (int anotherTier = 1, tierLimit = TIERED_STOP_AT_LEVEL + 1; anotherTier < tierLimit; ++anotherTier) { - boolean isCompilable = WHITE_BOX.isMethodCompilable(method, - anotherTier); + boolean isCompilable = isCompilable(anotherTier); if (sameCompile(testedTier, anotherTier)) { if (isCompilable) { throw new RuntimeException(method + " must be not compilable at level " + anotherTier + ", if it is not compilable at " + testedTier); } - WHITE_BOX.enqueueMethodForCompilation(method, anotherTier); + WHITE_BOX.enqueueMethodForCompilation(method, anotherTier, bci); checkNotCompiled(); } else { if (!isCompilable) { @@ -179,12 +185,12 @@ public class MakeMethodNotCompilableTest extends CompilerWhiteBoxTest { + ", even if it is not compilable at " + testedTier); } - WHITE_BOX.enqueueMethodForCompilation(method, anotherTier); + WHITE_BOX.enqueueMethodForCompilation(method, anotherTier, bci); checkCompiled(); - WHITE_BOX.deoptimizeMethod(method); + deoptimize(); } - if (!WHITE_BOX.isMethodCompilable(method, COMP_LEVEL_ANY)) { + if (!isCompilable(COMP_LEVEL_ANY)) { throw new RuntimeException(method + " must be compilable at 'CompLevel::CompLevel_any'" + ", if it is not compilable only at " + testedTier); @@ -193,7 +199,7 @@ public class MakeMethodNotCompilableTest extends CompilerWhiteBoxTest { // clear state after test WHITE_BOX.clearMethodState(method); - if (!WHITE_BOX.isMethodCompilable(method, testedTier)) { + if (!isCompilable(testedTier)) { throw new RuntimeException(method + " is not compilable after clearMethodState()"); } @@ -211,4 +217,13 @@ public class MakeMethodNotCompilableTest extends CompilerWhiteBoxTest { } return false; } + + private int getBci() { + compile(); + checkCompiled(); + int result = WHITE_BOX.getMethodEntryBci(method); + deoptimize(); + WHITE_BOX.clearMethodState(method); + return result; + } } diff --git a/hotspot/test/compiler/whitebox/SetDontInlineMethodTest.java b/hotspot/test/compiler/whitebox/SetDontInlineMethodTest.java index 22912a1058d..e2bff376cd1 100644 --- a/hotspot/test/compiler/whitebox/SetDontInlineMethodTest.java +++ b/hotspot/test/compiler/whitebox/SetDontInlineMethodTest.java @@ -23,6 +23,7 @@ /* * @test SetDontInlineMethodTest + * @bug 8006683 8007288 8022832 * @library /testlibrary /testlibrary/whitebox * @build SetDontInlineMethodTest * @run main ClassFileInstaller sun.hotspot.WhiteBox diff --git a/hotspot/test/compiler/whitebox/SetForceInlineMethodTest.java b/hotspot/test/compiler/whitebox/SetForceInlineMethodTest.java index 609be614a2c..5aa90c3fcd6 100644 --- a/hotspot/test/compiler/whitebox/SetForceInlineMethodTest.java +++ b/hotspot/test/compiler/whitebox/SetForceInlineMethodTest.java @@ -23,6 +23,7 @@ /* * @test SetForceInlineMethodTest + * @bug 8006683 8007288 8022832 * @library /testlibrary /testlibrary/whitebox * @build SetForceInlineMethodTest * @run main ClassFileInstaller sun.hotspot.WhiteBox diff --git a/hotspot/test/testlibrary/whitebox/sun/hotspot/WhiteBox.java b/hotspot/test/testlibrary/whitebox/sun/hotspot/WhiteBox.java index 3e451213311..cd133e5ea47 100644 --- a/hotspot/test/testlibrary/whitebox/sun/hotspot/WhiteBox.java +++ b/hotspot/test/testlibrary/whitebox/sun/hotspot/WhiteBox.java @@ -93,23 +93,45 @@ public class WhiteBox { // Compiler public native void deoptimizeAll(); - public native boolean isMethodCompiled(Executable method); - public boolean isMethodCompilable(Executable method) { - return isMethodCompilable(method, -1 /*any*/); + public boolean isMethodCompiled(Executable method) { + return isMethodCompiled(method, false /*not osr*/); } - public native boolean isMethodCompilable(Executable method, int compLevel); + public native boolean isMethodCompiled(Executable method, boolean isOsr); + public boolean isMethodCompilable(Executable method) { + return isMethodCompilable(method, -1 /*any*/); + } + public boolean isMethodCompilable(Executable method, int compLevel) { + return isMethodCompilable(method, compLevel, false /*not osr*/); + } + public native boolean isMethodCompilable(Executable method, int compLevel, boolean isOsr); public native boolean isMethodQueuedForCompilation(Executable method); - public native int deoptimizeMethod(Executable method); - public void makeMethodNotCompilable(Executable method) { - makeMethodNotCompilable(method, -1 /*any*/); + public int deoptimizeMethod(Executable method) { + return deoptimizeMethod(method, false /*not osr*/); } - public native void makeMethodNotCompilable(Executable method, int compLevel); - public native int getMethodCompilationLevel(Executable method); + public native int deoptimizeMethod(Executable method, boolean isOsr); + public void makeMethodNotCompilable(Executable method) { + makeMethodNotCompilable(method, -1 /*any*/); + } + public void makeMethodNotCompilable(Executable method, int compLevel) { + makeMethodNotCompilable(method, compLevel, false /*not osr*/); + } + public native void makeMethodNotCompilable(Executable method, int compLevel, boolean isOsr); + public int getMethodCompilationLevel(Executable method) { + return getMethodCompilationLevel(method, false /*not ost*/); + } + public native int getMethodCompilationLevel(Executable method, boolean isOsr); public native boolean testSetDontInlineMethod(Executable method, boolean value); - public native int getCompileQueuesSize(); + public int getCompileQueuesSize() { + return getCompileQueueSize(-1 /*any*/); + } + public native int getCompileQueueSize(int compLevel); public native boolean testSetForceInlineMethod(Executable method, boolean value); - public native boolean enqueueMethodForCompilation(Executable method, int compLevel); + public boolean enqueueMethodForCompilation(Executable method, int compLevel) { + return enqueueMethodForCompilation(method, compLevel, -1 /*InvocationEntryBci*/); + } + public native boolean enqueueMethodForCompilation(Executable method, int compLevel, int entry_bci); public native void clearMethodState(Executable method); + public native int getMethodEntryBci(Executable method); // Intered strings public native boolean isInStringTable(String str); From 5467bc74f84a81faee1bf1a29442896e69aae393 Mon Sep 17 00:00:00 2001 From: David Chase Date: Thu, 15 Aug 2013 11:59:19 -0700 Subject: [PATCH 006/218] 8022441: Bad code generated for certain interpreted CRC intrinsics, 2 cases Corrected details Reviewed-by: kvn, twisti, rbackman --- .../cpu/x86/vm/templateInterpreter_x86_64.cpp | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/hotspot/src/cpu/x86/vm/templateInterpreter_x86_64.cpp b/hotspot/src/cpu/x86/vm/templateInterpreter_x86_64.cpp index f0a2258a70e..05938bcedbb 100644 --- a/hotspot/src/cpu/x86/vm/templateInterpreter_x86_64.cpp +++ b/hotspot/src/cpu/x86/vm/templateInterpreter_x86_64.cpp @@ -849,9 +849,9 @@ address InterpreterGenerator::generate_CRC32_update_entry() { address entry = __ pc(); // rbx,: Method* - // rsi: senderSP must preserved for slow path, set SP to it on fast path - // rdx: scratch - // rdi: scratch + // r13: senderSP must preserved for slow path, set SP to it on fast path + // c_rarg0: scratch (rdi on non-Win64, rcx on Win64) + // c_rarg1: scratch (rsi on non-Win64, rdx on Win64) Label slow_path; // If we need a safepoint check, generate full interpreter entry. @@ -865,8 +865,8 @@ address InterpreterGenerator::generate_CRC32_update_entry() { // Load parameters const Register crc = rax; // crc - const Register val = rdx; // source java byte value - const Register tbl = rdi; // scratch + const Register val = c_rarg0; // source java byte value + const Register tbl = c_rarg1; // scratch // Arguments are reversed on java expression stack __ movl(val, Address(rsp, wordSize)); // byte value @@ -880,7 +880,7 @@ address InterpreterGenerator::generate_CRC32_update_entry() { // _areturn __ pop(rdi); // get return address - __ mov(rsp, rsi); // set sp to sender sp + __ mov(rsp, r13); // set sp to sender sp __ jmp(rdi); // generate a vanilla native entry as the slow path @@ -919,20 +919,24 @@ address InterpreterGenerator::generate_CRC32_updateBytes_entry(AbstractInterpret const Register crc = c_rarg0; // crc const Register buf = c_rarg1; // source java byte array address const Register len = c_rarg2; // length + const Register off = len; // offset (never overlaps with 'len') // Arguments are reversed on java expression stack - __ movl(len, Address(rsp, wordSize)); // Length // Calculate address of start element if (kind == Interpreter::java_util_zip_CRC32_updateByteBuffer) { __ movptr(buf, Address(rsp, 3*wordSize)); // long buf - __ addptr(buf, Address(rsp, 2*wordSize)); // + offset + __ movl2ptr(off, Address(rsp, 2*wordSize)); // offset + __ addq(buf, off); // + offset __ movl(crc, Address(rsp, 5*wordSize)); // Initial CRC } else { __ movptr(buf, Address(rsp, 3*wordSize)); // byte[] array __ addptr(buf, arrayOopDesc::base_offset_in_bytes(T_BYTE)); // + header size - __ addptr(buf, Address(rsp, 2*wordSize)); // + offset + __ movl2ptr(off, Address(rsp, 2*wordSize)); // offset + __ addq(buf, off); // + offset __ movl(crc, Address(rsp, 4*wordSize)); // Initial CRC } + // Can now load 'len' since we're finished with 'off' + __ movl(len, Address(rsp, wordSize)); // Length __ super_call_VM_leaf(CAST_FROM_FN_PTR(address, StubRoutines::updateBytesCRC32()), crc, buf, len); // result in rax From a235ecb3449a8d3f0ba311bb3724eae437681276 Mon Sep 17 00:00:00 2001 From: Niclas Adlertz Date: Fri, 16 Aug 2013 10:23:55 +0200 Subject: [PATCH 007/218] 8023003: Cleanup the public interface to PhaseCFG Public methods that don't need to be public should be private. Reviewed-by: kvn, twisti --- hotspot/src/share/vm/opto/block.cpp | 309 ++++++++---------- hotspot/src/share/vm/opto/block.hpp | 196 +++++++---- hotspot/src/share/vm/opto/buildOopMap.cpp | 53 ++- hotspot/src/share/vm/opto/chaitin.cpp | 167 ++++------ hotspot/src/share/vm/opto/coalesce.cpp | 40 +-- hotspot/src/share/vm/opto/compile.cpp | 80 +++-- hotspot/src/share/vm/opto/domgraph.cpp | 63 ++-- hotspot/src/share/vm/opto/gcm.cpp | 292 +++++++++-------- .../src/share/vm/opto/idealGraphPrinter.cpp | 24 +- hotspot/src/share/vm/opto/ifg.cpp | 174 +++++----- hotspot/src/share/vm/opto/lcm.cpp | 6 +- hotspot/src/share/vm/opto/live.cpp | 107 +++--- hotspot/src/share/vm/opto/matcher.cpp | 22 +- hotspot/src/share/vm/opto/matcher.hpp | 26 +- hotspot/src/share/vm/opto/output.cpp | 252 +++++++------- hotspot/src/share/vm/opto/phaseX.cpp | 4 +- hotspot/src/share/vm/opto/postaloc.cpp | 104 +++--- hotspot/src/share/vm/opto/reg_split.cpp | 14 +- hotspot/src/share/vm/runtime/vmStructs.cpp | 4 +- 19 files changed, 965 insertions(+), 972 deletions(-) diff --git a/hotspot/src/share/vm/opto/block.cpp b/hotspot/src/share/vm/opto/block.cpp index 9153d070886..5a6b791b24a 100644 --- a/hotspot/src/share/vm/opto/block.cpp +++ b/hotspot/src/share/vm/opto/block.cpp @@ -35,10 +35,6 @@ #include "opto/rootnode.hpp" #include "utilities/copy.hpp" -// Optimization - Graph Style - - -//----------------------------------------------------------------------------- void Block_Array::grow( uint i ) { assert(i >= Max(), "must be an overflow"); debug_only(_limit = i+1); @@ -54,7 +50,6 @@ void Block_Array::grow( uint i ) { Copy::zero_to_bytes( &_blocks[old], (_size-old)*sizeof(Block*) ); } -//============================================================================= void Block_List::remove(uint i) { assert(i < _cnt, "index out of bounds"); Copy::conjoint_words_to_lower((HeapWord*)&_blocks[i+1], (HeapWord*)&_blocks[i], ((_cnt-i-1)*sizeof(Block*))); @@ -76,8 +71,6 @@ void Block_List::print() { } #endif -//============================================================================= - uint Block::code_alignment() { // Check for Root block if (_pre_order == 0) return CodeEntryAlignment; @@ -113,7 +106,6 @@ uint Block::compute_loop_alignment() { return unit_sz; // no particular alignment } -//----------------------------------------------------------------------------- // Compute the size of first 'inst_cnt' instructions in this block. // Return the number of instructions left to compute if the block has // less then 'inst_cnt' instructions. Stop, and return 0 if sum_size @@ -138,7 +130,6 @@ uint Block::compute_first_inst_size(uint& sum_size, uint inst_cnt, return inst_cnt; } -//----------------------------------------------------------------------------- uint Block::find_node( const Node *n ) const { for( uint i = 0; i < _nodes.size(); i++ ) { if( _nodes[i] == n ) @@ -153,7 +144,6 @@ void Block::find_remove( const Node *n ) { _nodes.remove(find_node(n)); } -//------------------------------is_Empty--------------------------------------- // Return empty status of a block. Empty blocks contain only the head, other // ideal nodes, and an optional trailing goto. int Block::is_Empty() const { @@ -192,7 +182,6 @@ int Block::is_Empty() const { return not_empty; } -//------------------------------has_uncommon_code------------------------------ // Return true if the block's code implies that it is likely to be // executed infrequently. Check to see if the block ends in a Halt or // a low probability call. @@ -218,7 +207,6 @@ bool Block::has_uncommon_code() const { return op == Op_Halt; } -//------------------------------is_uncommon------------------------------------ // True if block is low enough frequency or guarded by a test which // mostly does not go here. bool Block::is_uncommon(PhaseCFG* cfg) const { @@ -271,7 +259,6 @@ bool Block::is_uncommon(PhaseCFG* cfg) const { return false; } -//------------------------------dump------------------------------------------- #ifndef PRODUCT void Block::dump_bidx(const Block* orig, outputStream* st) const { if (_pre_order) st->print("B%d",_pre_order); @@ -364,13 +351,12 @@ void Block::dump(const PhaseCFG* cfg) const { } #endif -//============================================================================= -//------------------------------PhaseCFG--------------------------------------- PhaseCFG::PhaseCFG(Arena* arena, RootNode* root, Matcher& matcher) : Phase(CFG) , _block_arena(arena) -, _node_to_block_mapping(arena) , _root(root) +, _matcher(matcher) +, _node_to_block_mapping(arena) , _node_latency(NULL) #ifndef PRODUCT , _trace_opto_pipelining(TraceOptoPipelining || C->method_has_option("TraceOptoPipelining")) @@ -390,11 +376,10 @@ PhaseCFG::PhaseCFG(Arena* arena, RootNode* root, Matcher& matcher) _goto->set_req(0,_goto); // Build the CFG in Reverse Post Order - _num_blocks = build_cfg(); - _broot = get_block_for_node(_root); + _number_of_blocks = build_cfg(); + _root_block = get_block_for_node(_root); } -//------------------------------build_cfg-------------------------------------- // Build a proper looking CFG. Make every block begin with either a StartNode // or a RegionNode. Make every block end with either a Goto, If or Return. // The RootNode both starts and ends it's own block. Do this with a recursive @@ -496,13 +481,12 @@ uint PhaseCFG::build_cfg() { return sum; } -//------------------------------insert_goto_at--------------------------------- // Inserts a goto & corresponding basic block between // block[block_no] and its succ_no'th successor block void PhaseCFG::insert_goto_at(uint block_no, uint succ_no) { // get block with block_no - assert(block_no < _num_blocks, "illegal block number"); - Block* in = _blocks[block_no]; + assert(block_no < number_of_blocks(), "illegal block number"); + Block* in = get_block(block_no); // get successor block succ_no assert(succ_no < in->_num_succs, "illegal successor number"); Block* out = in->_succs[succ_no]; @@ -537,11 +521,9 @@ void PhaseCFG::insert_goto_at(uint block_no, uint succ_no) { // Set the frequency of the new block block->_freq = freq; // add new basic block to basic block list - _blocks.insert(block_no + 1, block); - _num_blocks++; + add_block_at(block_no + 1, block); } -//------------------------------no_flip_branch--------------------------------- // Does this block end in a multiway branch that cannot have the default case // flipped for another case? static bool no_flip_branch( Block *b ) { @@ -560,7 +542,6 @@ static bool no_flip_branch( Block *b ) { return false; } -//------------------------------convert_NeverBranch_to_Goto-------------------- // Check for NeverBranch at block end. This needs to become a GOTO to the // true target. NeverBranch are treated as a conditional branch that always // goes the same direction for most of the optimizer and are used to give a @@ -598,7 +579,6 @@ void PhaseCFG::convert_NeverBranch_to_Goto(Block *b) { dead->_nodes[k]->del_req(j); } -//------------------------------move_to_next----------------------------------- // Helper function to move block bx to the slot following b_index. Return // true if the move is successful, otherwise false bool PhaseCFG::move_to_next(Block* bx, uint b_index) { @@ -606,20 +586,22 @@ bool PhaseCFG::move_to_next(Block* bx, uint b_index) { // Return false if bx is already scheduled. uint bx_index = bx->_pre_order; - if ((bx_index <= b_index) && (_blocks[bx_index] == bx)) { + if ((bx_index <= b_index) && (get_block(bx_index) == bx)) { return false; } // Find the current index of block bx on the block list bx_index = b_index + 1; - while( bx_index < _num_blocks && _blocks[bx_index] != bx ) bx_index++; - assert(_blocks[bx_index] == bx, "block not found"); + while (bx_index < number_of_blocks() && get_block(bx_index) != bx) { + bx_index++; + } + assert(get_block(bx_index) == bx, "block not found"); // If the previous block conditionally falls into bx, return false, // because moving bx will create an extra jump. for(uint k = 1; k < bx->num_preds(); k++ ) { Block* pred = get_block_for_node(bx->pred(k)); - if (pred == _blocks[bx_index-1]) { + if (pred == get_block(bx_index - 1)) { if (pred->_num_succs != 1) { return false; } @@ -632,7 +614,6 @@ bool PhaseCFG::move_to_next(Block* bx, uint b_index) { return true; } -//------------------------------move_to_end------------------------------------ // Move empty and uncommon blocks to the end. void PhaseCFG::move_to_end(Block *b, uint i) { int e = b->is_Empty(); @@ -650,31 +631,31 @@ void PhaseCFG::move_to_end(Block *b, uint i) { _blocks.push(b); } -//---------------------------set_loop_alignment-------------------------------- // Set loop alignment for every block void PhaseCFG::set_loop_alignment() { - uint last = _num_blocks; - assert( _blocks[0] == _broot, "" ); + uint last = number_of_blocks(); + assert(get_block(0) == get_root_block(), ""); - for (uint i = 1; i < last; i++ ) { - Block *b = _blocks[i]; - if (b->head()->is_Loop()) { - b->set_loop_alignment(b); + for (uint i = 1; i < last; i++) { + Block* block = get_block(i); + if (block->head()->is_Loop()) { + block->set_loop_alignment(block); } } } -//-----------------------------remove_empty------------------------------------ // Make empty basic blocks to be "connector" blocks, Move uncommon blocks // to the end. -void PhaseCFG::remove_empty() { +void PhaseCFG::remove_empty_blocks() { // Move uncommon blocks to the end - uint last = _num_blocks; - assert( _blocks[0] == _broot, "" ); + uint last = number_of_blocks(); + assert(get_block(0) == get_root_block(), ""); for (uint i = 1; i < last; i++) { - Block *b = _blocks[i]; - if (b->is_connector()) break; + Block* block = get_block(i); + if (block->is_connector()) { + break; + } // Check for NeverBranch at block end. This needs to become a GOTO to the // true target. NeverBranch are treated as a conditional branch that @@ -682,124 +663,127 @@ void PhaseCFG::remove_empty() { // to give a fake exit path to infinite loops. At this late stage they // need to turn into Goto's so that when you enter the infinite loop you // indeed hang. - if( b->_nodes[b->end_idx()]->Opcode() == Op_NeverBranch ) - convert_NeverBranch_to_Goto(b); + if (block->_nodes[block->end_idx()]->Opcode() == Op_NeverBranch) { + convert_NeverBranch_to_Goto(block); + } // Look for uncommon blocks and move to end. if (!C->do_freq_based_layout()) { - if (b->is_uncommon(this)) { - move_to_end(b, i); + if (block->is_uncommon(this)) { + move_to_end(block, i); last--; // No longer check for being uncommon! - if( no_flip_branch(b) ) { // Fall-thru case must follow? - b = _blocks[i]; // Find the fall-thru block - move_to_end(b, i); + if (no_flip_branch(block)) { // Fall-thru case must follow? + // Find the fall-thru block + block = get_block(i); + move_to_end(block, i); last--; } - i--; // backup block counter post-increment + // backup block counter post-increment + i--; } } } // Move empty blocks to the end - last = _num_blocks; + last = number_of_blocks(); for (uint i = 1; i < last; i++) { - Block *b = _blocks[i]; - if (b->is_Empty() != Block::not_empty) { - move_to_end(b, i); + Block* block = get_block(i); + if (block->is_Empty() != Block::not_empty) { + move_to_end(block, i); last--; i--; } } // End of for all blocks } -//-----------------------------fixup_flow-------------------------------------- // Fix up the final control flow for basic blocks. void PhaseCFG::fixup_flow() { // Fixup final control flow for the blocks. Remove jump-to-next // block. If neither arm of a IF follows the conditional branch, we // have to add a second jump after the conditional. We place the // TRUE branch target in succs[0] for both GOTOs and IFs. - for (uint i=0; i < _num_blocks; i++) { - Block *b = _blocks[i]; - b->_pre_order = i; // turn pre-order into block-index + for (uint i = 0; i < number_of_blocks(); i++) { + Block* block = get_block(i); + block->_pre_order = i; // turn pre-order into block-index // Connector blocks need no further processing. - if (b->is_connector()) { - assert((i+1) == _num_blocks || _blocks[i+1]->is_connector(), - "All connector blocks should sink to the end"); + if (block->is_connector()) { + assert((i+1) == number_of_blocks() || get_block(i + 1)->is_connector(), "All connector blocks should sink to the end"); continue; } - assert(b->is_Empty() != Block::completely_empty, - "Empty blocks should be connectors"); + assert(block->is_Empty() != Block::completely_empty, "Empty blocks should be connectors"); - Block *bnext = (i < _num_blocks-1) ? _blocks[i+1] : NULL; - Block *bs0 = b->non_connector_successor(0); + Block* bnext = (i < number_of_blocks() - 1) ? get_block(i + 1) : NULL; + Block* bs0 = block->non_connector_successor(0); // Check for multi-way branches where I cannot negate the test to // exchange the true and false targets. - if( no_flip_branch( b ) ) { + if (no_flip_branch(block)) { // Find fall through case - if must fall into its target - int branch_idx = b->_nodes.size() - b->_num_succs; - for (uint j2 = 0; j2 < b->_num_succs; j2++) { - const ProjNode* p = b->_nodes[branch_idx + j2]->as_Proj(); + int branch_idx = block->_nodes.size() - block->_num_succs; + for (uint j2 = 0; j2 < block->_num_succs; j2++) { + const ProjNode* p = block->_nodes[branch_idx + j2]->as_Proj(); if (p->_con == 0) { // successor j2 is fall through case - if (b->non_connector_successor(j2) != bnext) { + if (block->non_connector_successor(j2) != bnext) { // but it is not the next block => insert a goto insert_goto_at(i, j2); } // Put taken branch in slot 0 - if( j2 == 0 && b->_num_succs == 2) { + if (j2 == 0 && block->_num_succs == 2) { // Flip targets in succs map - Block *tbs0 = b->_succs[0]; - Block *tbs1 = b->_succs[1]; - b->_succs.map( 0, tbs1 ); - b->_succs.map( 1, tbs0 ); + Block *tbs0 = block->_succs[0]; + Block *tbs1 = block->_succs[1]; + block->_succs.map(0, tbs1); + block->_succs.map(1, tbs0); } break; } } - // Remove all CatchProjs - for (uint j1 = 0; j1 < b->_num_succs; j1++) b->_nodes.pop(); - } else if (b->_num_succs == 1) { + // Remove all CatchProjs + for (uint j = 0; j < block->_num_succs; j++) { + block->_nodes.pop(); + } + + } else if (block->_num_succs == 1) { // Block ends in a Goto? if (bnext == bs0) { // We fall into next block; remove the Goto - b->_nodes.pop(); + block->_nodes.pop(); } - } else if( b->_num_succs == 2 ) { // Block ends in a If? + } else if(block->_num_succs == 2) { // Block ends in a If? // Get opcode of 1st projection (matches _succs[0]) // Note: Since this basic block has 2 exits, the last 2 nodes must // be projections (in any order), the 3rd last node must be // the IfNode (we have excluded other 2-way exits such as // CatchNodes already). - MachNode *iff = b->_nodes[b->_nodes.size()-3]->as_Mach(); - ProjNode *proj0 = b->_nodes[b->_nodes.size()-2]->as_Proj(); - ProjNode *proj1 = b->_nodes[b->_nodes.size()-1]->as_Proj(); + MachNode* iff = block->_nodes[block->_nodes.size() - 3]->as_Mach(); + ProjNode* proj0 = block->_nodes[block->_nodes.size() - 2]->as_Proj(); + ProjNode* proj1 = block->_nodes[block->_nodes.size() - 1]->as_Proj(); // Assert that proj0 and succs[0] match up. Similarly for proj1 and succs[1]. - assert(proj0->raw_out(0) == b->_succs[0]->head(), "Mismatch successor 0"); - assert(proj1->raw_out(0) == b->_succs[1]->head(), "Mismatch successor 1"); + assert(proj0->raw_out(0) == block->_succs[0]->head(), "Mismatch successor 0"); + assert(proj1->raw_out(0) == block->_succs[1]->head(), "Mismatch successor 1"); - Block *bs1 = b->non_connector_successor(1); + Block* bs1 = block->non_connector_successor(1); // Check for neither successor block following the current // block ending in a conditional. If so, move one of the // successors after the current one, provided that the // successor was previously unscheduled, but moveable // (i.e., all paths to it involve a branch). - if( !C->do_freq_based_layout() && bnext != bs0 && bnext != bs1 ) { + if (!C->do_freq_based_layout() && bnext != bs0 && bnext != bs1) { // Choose the more common successor based on the probability // of the conditional branch. - Block *bx = bs0; - Block *by = bs1; + Block* bx = bs0; + Block* by = bs1; // _prob is the probability of taking the true path. Make // p the probability of taking successor #1. float p = iff->as_MachIf()->_prob; - if( proj0->Opcode() == Op_IfTrue ) { + if (proj0->Opcode() == Op_IfTrue) { p = 1.0 - p; } @@ -826,14 +810,16 @@ void PhaseCFG::fixup_flow() { // succs[1]. if (bnext == bs0) { // Fall-thru case in succs[0], so flip targets in succs map - Block *tbs0 = b->_succs[0]; - Block *tbs1 = b->_succs[1]; - b->_succs.map( 0, tbs1 ); - b->_succs.map( 1, tbs0 ); + Block* tbs0 = block->_succs[0]; + Block* tbs1 = block->_succs[1]; + block->_succs.map(0, tbs1); + block->_succs.map(1, tbs0); // Flip projection for each target - { ProjNode *tmp = proj0; proj0 = proj1; proj1 = tmp; } + ProjNode* tmp = proj0; + proj0 = proj1; + proj1 = tmp; - } else if( bnext != bs1 ) { + } else if(bnext != bs1) { // Need a double-branch // The existing conditional branch need not change. // Add a unconditional branch to the false target. @@ -843,12 +829,12 @@ void PhaseCFG::fixup_flow() { } // Make sure we TRUE branch to the target - if( proj0->Opcode() == Op_IfFalse ) { + if (proj0->Opcode() == Op_IfFalse) { iff->as_MachIf()->negate(); } - b->_nodes.pop(); // Remove IfFalse & IfTrue projections - b->_nodes.pop(); + block->_nodes.pop(); // Remove IfFalse & IfTrue projections + block->_nodes.pop(); } else { // Multi-exit block, e.g. a switch statement @@ -858,7 +844,6 @@ void PhaseCFG::fixup_flow() { } -//------------------------------dump------------------------------------------- #ifndef PRODUCT void PhaseCFG::_dump_cfg( const Node *end, VectorSet &visited ) const { const Node *x = end->is_block_proj(); @@ -884,10 +869,11 @@ void PhaseCFG::_dump_cfg( const Node *end, VectorSet &visited ) const { } void PhaseCFG::dump( ) const { - tty->print("\n--- CFG --- %d BBs\n",_num_blocks); + tty->print("\n--- CFG --- %d BBs\n", number_of_blocks()); if (_blocks.size()) { // Did we do basic-block layout? - for (uint i = 0; i < _num_blocks; i++) { - _blocks[i]->dump(this); + for (uint i = 0; i < number_of_blocks(); i++) { + const Block* block = get_block(i); + block->dump(this); } } else { // Else do it with a DFS VectorSet visited(_block_arena); @@ -896,27 +882,26 @@ void PhaseCFG::dump( ) const { } void PhaseCFG::dump_headers() { - for( uint i = 0; i < _num_blocks; i++ ) { - if (_blocks[i]) { - _blocks[i]->dump_head(this); + for (uint i = 0; i < number_of_blocks(); i++) { + Block* block = get_block(i); + if (block != NULL) { + block->dump_head(this); } } } -void PhaseCFG::verify( ) const { +void PhaseCFG::verify() const { #ifdef ASSERT // Verify sane CFG - for (uint i = 0; i < _num_blocks; i++) { - Block *b = _blocks[i]; - uint cnt = b->_nodes.size(); + for (uint i = 0; i < number_of_blocks(); i++) { + Block* block = get_block(i); + uint cnt = block->_nodes.size(); uint j; for (j = 0; j < cnt; j++) { - Node *n = b->_nodes[j]; - assert(get_block_for_node(n) == b, ""); - if (j >= 1 && n->is_Mach() && - n->as_Mach()->ideal_Opcode() == Op_CreateEx) { - assert(j == 1 || b->_nodes[j-1]->is_Phi(), - "CreateEx must be first instruction in block"); + Node *n = block->_nodes[j]; + assert(get_block_for_node(n) == block, ""); + if (j >= 1 && n->is_Mach() && n->as_Mach()->ideal_Opcode() == Op_CreateEx) { + assert(j == 1 || block->_nodes[j-1]->is_Phi(), "CreateEx must be first instruction in block"); } for (uint k = 0; k < n->req(); k++) { Node *def = n->in(k); @@ -926,8 +911,7 @@ void PhaseCFG::verify( ) const { // Uses must follow their definition if they are at the same block. // Mostly done to check that MachSpillCopy nodes are placed correctly // when CreateEx node is moved in build_ifg_physical(). - if (get_block_for_node(def) == b && - !(b->head()->is_Loop() && n->is_Phi()) && + if (get_block_for_node(def) == block && !(block->head()->is_Loop() && n->is_Phi()) && // See (+++) comment in reg_split.cpp !(n->jvms() != NULL && n->jvms()->is_monitor_use(k))) { bool is_loop = false; @@ -939,29 +923,29 @@ void PhaseCFG::verify( ) const { } } } - assert(is_loop || b->find_node(def) < j, "uses must follow definitions"); + assert(is_loop || block->find_node(def) < j, "uses must follow definitions"); } } } } - j = b->end_idx(); - Node *bp = (Node*)b->_nodes[b->_nodes.size()-1]->is_block_proj(); - assert( bp, "last instruction must be a block proj" ); - assert( bp == b->_nodes[j], "wrong number of successors for this block" ); + j = block->end_idx(); + Node* bp = (Node*)block->_nodes[block->_nodes.size() - 1]->is_block_proj(); + assert(bp, "last instruction must be a block proj"); + assert(bp == block->_nodes[j], "wrong number of successors for this block"); if (bp->is_Catch()) { - while (b->_nodes[--j]->is_MachProj()) ; - assert(b->_nodes[j]->is_MachCall(), "CatchProj must follow call"); + while (block->_nodes[--j]->is_MachProj()) { + ; + } + assert(block->_nodes[j]->is_MachCall(), "CatchProj must follow call"); } else if (bp->is_Mach() && bp->as_Mach()->ideal_Opcode() == Op_If) { - assert(b->_num_succs == 2, "Conditional branch must have two targets"); + assert(block->_num_succs == 2, "Conditional branch must have two targets"); } } #endif } #endif -//============================================================================= -//------------------------------UnionFind-------------------------------------- UnionFind::UnionFind( uint max ) : _cnt(max), _max(max), _indices(NEW_RESOURCE_ARRAY(uint,max)) { Copy::zero_to_bytes( _indices, sizeof(uint)*max ); } @@ -986,7 +970,6 @@ void UnionFind::reset( uint max ) { for( uint i=0; ifreq(); @@ -1087,7 +1065,6 @@ static int edge_order(CFGEdge **e0, CFGEdge **e1) { return dist1 - dist0; } -//------------------------------trace_frequency_order-------------------------- // Comparison function for edges extern "C" int trace_frequency_order(const void *p0, const void *p1) { Trace *tr0 = *(Trace **) p0; @@ -1113,17 +1090,15 @@ extern "C" int trace_frequency_order(const void *p0, const void *p1) { return diff; } -//------------------------------find_edges------------------------------------- // Find edges of interest, i.e, those which can fall through. Presumes that // edges which don't fall through are of low frequency and can be generally // ignored. Initialize the list of traces. -void PhaseBlockLayout::find_edges() -{ +void PhaseBlockLayout::find_edges() { // Walk the blocks, creating edges and Traces uint i; Trace *tr = NULL; - for (i = 0; i < _cfg._num_blocks; i++) { - Block *b = _cfg._blocks[i]; + for (i = 0; i < _cfg.number_of_blocks(); i++) { + Block* b = _cfg.get_block(i); tr = new Trace(b, next, prev); traces[tr->id()] = tr; @@ -1147,7 +1122,7 @@ void PhaseBlockLayout::find_edges() if (n->num_preds() != 1) break; i++; - assert(n = _cfg._blocks[i], "expecting next block"); + assert(n = _cfg.get_block(i), "expecting next block"); tr->append(n); uf->map(n->_pre_order, tr->id()); traces[n->_pre_order] = NULL; @@ -1171,8 +1146,8 @@ void PhaseBlockLayout::find_edges() } // Group connector blocks into one trace - for (i++; i < _cfg._num_blocks; i++) { - Block *b = _cfg._blocks[i]; + for (i++; i < _cfg.number_of_blocks(); i++) { + Block *b = _cfg.get_block(i); assert(b->is_connector(), "connector blocks at the end"); tr->append(b); uf->map(b->_pre_order, tr->id()); @@ -1180,10 +1155,8 @@ void PhaseBlockLayout::find_edges() } } -//------------------------------union_traces---------------------------------- // Union two traces together in uf, and null out the trace in the list -void PhaseBlockLayout::union_traces(Trace* updated_trace, Trace* old_trace) -{ +void PhaseBlockLayout::union_traces(Trace* updated_trace, Trace* old_trace) { uint old_id = old_trace->id(); uint updated_id = updated_trace->id(); @@ -1207,10 +1180,8 @@ void PhaseBlockLayout::union_traces(Trace* updated_trace, Trace* old_trace) traces[hi_id] = NULL; } -//------------------------------grow_traces------------------------------------- // Append traces together via the most frequently executed edges -void PhaseBlockLayout::grow_traces() -{ +void PhaseBlockLayout::grow_traces() { // Order the edges, and drive the growth of Traces via the most // frequently executed edges. edges->sort(edge_order); @@ -1252,11 +1223,9 @@ void PhaseBlockLayout::grow_traces() } } -//------------------------------merge_traces----------------------------------- // Embed one trace into another, if the fork or join points are sufficiently // balanced. -void PhaseBlockLayout::merge_traces(bool fall_thru_only) -{ +void PhaseBlockLayout::merge_traces(bool fall_thru_only) { // Walk the edge list a another time, looking at unprocessed edges. // Fold in diamonds for (int i = 0; i < edges->length(); i++) { @@ -1310,7 +1279,7 @@ void PhaseBlockLayout::merge_traces(bool fall_thru_only) src_trace->insert_after(src_block, targ_trace); union_traces(src_trace, targ_trace); } else if (src_at_tail) { - if (src_trace != trace(_cfg._broot)) { + if (src_trace != trace(_cfg.get_root_block())) { e->set_state(CFGEdge::connected); targ_trace->insert_before(targ_block, src_trace); union_traces(targ_trace, src_trace); @@ -1319,7 +1288,7 @@ void PhaseBlockLayout::merge_traces(bool fall_thru_only) } else if (e->state() == CFGEdge::open) { // Append traces, even without a fall-thru connection. // But leave root entry at the beginning of the block list. - if (targ_trace != trace(_cfg._broot)) { + if (targ_trace != trace(_cfg.get_root_block())) { e->set_state(CFGEdge::connected); src_trace->append(targ_trace); union_traces(src_trace, targ_trace); @@ -1328,11 +1297,9 @@ void PhaseBlockLayout::merge_traces(bool fall_thru_only) } } -//----------------------------reorder_traces----------------------------------- // Order the sequence of the traces in some desirable way, and fixup the // jumps at the end of each block. -void PhaseBlockLayout::reorder_traces(int count) -{ +void PhaseBlockLayout::reorder_traces(int count) { ResourceArea *area = Thread::current()->resource_area(); Trace ** new_traces = NEW_ARENA_ARRAY(area, Trace *, count); Block_List worklist; @@ -1347,15 +1314,14 @@ void PhaseBlockLayout::reorder_traces(int count) } // The entry block should be first on the new trace list. - Trace *tr = trace(_cfg._broot); + Trace *tr = trace(_cfg.get_root_block()); assert(tr == new_traces[0], "entry trace misplaced"); // Sort the new trace list by frequency qsort(new_traces + 1, new_count - 1, sizeof(new_traces[0]), trace_frequency_order); // Patch up the successor blocks - _cfg._blocks.reset(); - _cfg._num_blocks = 0; + _cfg.clear_blocks(); for (int i = 0; i < new_count; i++) { Trace *tr = new_traces[i]; if (tr != NULL) { @@ -1364,17 +1330,15 @@ void PhaseBlockLayout::reorder_traces(int count) } } -//------------------------------PhaseBlockLayout------------------------------- // Order basic blocks based on frequency -PhaseBlockLayout::PhaseBlockLayout(PhaseCFG &cfg) : - Phase(BlockLayout), - _cfg(cfg) -{ +PhaseBlockLayout::PhaseBlockLayout(PhaseCFG &cfg) +: Phase(BlockLayout) +, _cfg(cfg) { ResourceMark rm; ResourceArea *area = Thread::current()->resource_area(); // List of traces - int size = _cfg._num_blocks + 1; + int size = _cfg.number_of_blocks() + 1; traces = NEW_ARENA_ARRAY(area, Trace *, size); memset(traces, 0, size*sizeof(Trace*)); next = NEW_ARENA_ARRAY(area, Block *, size); @@ -1407,11 +1371,10 @@ PhaseBlockLayout::PhaseBlockLayout(PhaseCFG &cfg) : // Re-order all the remaining traces by frequency reorder_traces(size); - assert(_cfg._num_blocks >= (uint) (size - 1), "number of blocks can not shrink"); + assert(_cfg.number_of_blocks() >= (uint) (size - 1), "number of blocks can not shrink"); } -//------------------------------backedge--------------------------------------- // Edge e completes a loop in a trace. If the target block is head of the // loop, rotate the loop block so that the loop ends in a conditional branch. bool Trace::backedge(CFGEdge *e) { @@ -1463,14 +1426,12 @@ bool Trace::backedge(CFGEdge *e) { return loop_rotated; } -//------------------------------fixup_blocks----------------------------------- // push blocks onto the CFG list // ensure that blocks have the correct two-way branch sense void Trace::fixup_blocks(PhaseCFG &cfg) { Block *last = last_block(); for (Block *b = first_block(); b != NULL; b = next(b)) { - cfg._blocks.push(b); - cfg._num_blocks++; + cfg.add_block(b); if (!b->is_connector()) { int nfallthru = b->num_fall_throughs(); if (b != last) { diff --git a/hotspot/src/share/vm/opto/block.hpp b/hotspot/src/share/vm/opto/block.hpp index cb9384de2ee..7cc566cf007 100644 --- a/hotspot/src/share/vm/opto/block.hpp +++ b/hotspot/src/share/vm/opto/block.hpp @@ -348,20 +348,77 @@ class Block : public CFGElement { class PhaseCFG : public Phase { friend class VMStructs; private: + + // Root of whole program + RootNode* _root; + + // The block containing the root node + Block* _root_block; + + // List of basic blocks that are created during CFG creation + Block_List _blocks; + + // Count of basic blocks + uint _number_of_blocks; + // Arena for the blocks to be stored in Arena* _block_arena; + // The matcher for this compilation + Matcher& _matcher; + // Map nodes to owning basic block Block_Array _node_to_block_mapping; + // Loop from the root + CFGLoop* _root_loop; + + // Outmost loop frequency + float _outer_loop_frequency; + + // Per node latency estimation, valid only during GCM + GrowableArray* _node_latency; + // Build a proper looking cfg. Return count of basic blocks uint build_cfg(); - // Perform DFS search. + // Build the dominator tree so that we know where we can move instructions + void build_dominator_tree(); + + // Estimate block frequencies based on IfNode probabilities, so that we know where we want to move instructions + void estimate_block_frequency(); + + // Global Code Motion. See Click's PLDI95 paper. Place Nodes in specific + // basic blocks; i.e. _node_to_block_mapping now maps _idx for all Nodes to some Block. + // Move nodes to ensure correctness from GVN and also try to move nodes out of loops. + void global_code_motion(); + + // Schedule Nodes early in their basic blocks. + bool schedule_early(VectorSet &visited, Node_List &roots); + + // For each node, find the latest block it can be scheduled into + // and then select the cheapest block between the latest and earliest + // block to place the node. + void schedule_late(VectorSet &visited, Node_List &stack); + + // Compute the (backwards) latency of a node from a single use + int latency_from_use(Node *n, const Node *def, Node *use); + + // Compute the (backwards) latency of a node from the uses of this instruction + void partial_latency_of_defs(Node *n); + + // Compute the instruction global latency with a backwards walk + void compute_latencies_backwards(VectorSet &visited, Node_List &stack); + + // Pick a block between early and late that is a cheaper alternative + // to late. Helper for schedule_late. + Block* hoist_to_cheaper_block(Block* LCA, Block* early, Node* self); + + // Perform a Depth First Search (DFS). // Setup 'vertex' as DFS to vertex mapping. // Setup 'semi' as vertex to DFS mapping. // Set 'parent' to DFS parent. - uint DFS( Tarjan *tarjan ); + uint do_DFS(Tarjan* tarjan, uint rpo_counter); // Helper function to insert a node into a block void schedule_node_into_block( Node *n, Block *b ); @@ -372,7 +429,8 @@ class PhaseCFG : public Phase { void schedule_pinned_nodes( VectorSet &visited ); // I'll need a few machine-specific GotoNodes. Clone from this one. - MachNode *_goto; + // Used when building the CFG and creating end nodes for blocks. + MachNode* _goto; Block* insert_anti_dependences(Block* LCA, Node* load, bool verify = false); void verify_anti_dependences(Block* LCA, Node* load) { @@ -380,17 +438,77 @@ class PhaseCFG : public Phase { insert_anti_dependences(LCA, load, true); } + bool move_to_next(Block* bx, uint b_index); + void move_to_end(Block* bx, uint b_index); + + void insert_goto_at(uint block_no, uint succ_no); + + // Check for NeverBranch at block end. This needs to become a GOTO to the + // true target. NeverBranch are treated as a conditional branch that always + // goes the same direction for most of the optimizer and are used to give a + // fake exit path to infinite loops. At this late stage they need to turn + // into Goto's so that when you enter the infinite loop you indeed hang. + void convert_NeverBranch_to_Goto(Block *b); + + CFGLoop* create_loop_tree(); + + #ifndef PRODUCT + bool _trace_opto_pipelining; // tracing flag + #endif + public: PhaseCFG(Arena* arena, RootNode* root, Matcher& matcher); - uint _num_blocks; // Count of basic blocks - Block_List _blocks; // List of basic blocks - RootNode *_root; // Root of whole program - Block *_broot; // Basic block of root - uint _rpo_ctr; - CFGLoop* _root_loop; - float _outer_loop_freq; // Outmost loop frequency + void set_latency_for_node(Node* node, int latency) { + _node_latency->at_put_grow(node->_idx, latency); + } + uint get_latency_for_node(Node* node) { + return _node_latency->at_grow(node->_idx); + } + + // Get the outer most frequency + float get_outer_loop_frequency() const { + return _outer_loop_frequency; + } + + // Get the root node of the CFG + RootNode* get_root_node() const { + return _root; + } + + // Get the block of the root node + Block* get_root_block() const { + return _root_block; + } + + // Add a block at a position and moves the later ones one step + void add_block_at(uint pos, Block* block) { + _blocks.insert(pos, block); + _number_of_blocks++; + } + + // Adds a block to the top of the block list + void add_block(Block* block) { + _blocks.push(block); + _number_of_blocks++; + } + + // Clear the list of blocks + void clear_blocks() { + _blocks.reset(); + _number_of_blocks = 0; + } + + // Get the block at position pos in _blocks + Block* get_block(uint pos) const { + return _blocks[pos]; + } + + // Number of blocks + uint number_of_blocks() const { + return _number_of_blocks; + } // set which block this node should reside in void map_node_to_block(const Node* node, Block* block) { @@ -412,72 +530,26 @@ class PhaseCFG : public Phase { return (_node_to_block_mapping.lookup(node->_idx) != NULL); } - // Per node latency estimation, valid only during GCM - GrowableArray *_node_latency; - -#ifndef PRODUCT - bool _trace_opto_pipelining; // tracing flag -#endif - #ifdef ASSERT Unique_Node_List _raw_oops; #endif - // Build dominators - void Dominators(); - - // Estimate block frequencies based on IfNode probabilities - void Estimate_Block_Frequency(); - - // Global Code Motion. See Click's PLDI95 paper. Place Nodes in specific - // basic blocks; i.e. _node_to_block_mapping now maps _idx for all Nodes to some Block. - void GlobalCodeMotion( Matcher &m, uint unique, Node_List &proj_list ); + // Do global code motion by first building dominator tree and estimate block frequency + // Returns true on success + bool do_global_code_motion(); // Compute the (backwards) latency of a node from the uses void latency_from_uses(Node *n); - // Compute the (backwards) latency of a node from a single use - int latency_from_use(Node *n, const Node *def, Node *use); - - // Compute the (backwards) latency of a node from the uses of this instruction - void partial_latency_of_defs(Node *n); - - // Schedule Nodes early in their basic blocks. - bool schedule_early(VectorSet &visited, Node_List &roots); - - // For each node, find the latest block it can be scheduled into - // and then select the cheapest block between the latest and earliest - // block to place the node. - void schedule_late(VectorSet &visited, Node_List &stack); - - // Pick a block between early and late that is a cheaper alternative - // to late. Helper for schedule_late. - Block* hoist_to_cheaper_block(Block* LCA, Block* early, Node* self); - - // Compute the instruction global latency with a backwards walk - void ComputeLatenciesBackwards(VectorSet &visited, Node_List &stack); - // Set loop alignment void set_loop_alignment(); // Remove empty basic blocks - void remove_empty(); + void remove_empty_blocks(); void fixup_flow(); - bool move_to_next(Block* bx, uint b_index); - void move_to_end(Block* bx, uint b_index); - void insert_goto_at(uint block_no, uint succ_no); - // Check for NeverBranch at block end. This needs to become a GOTO to the - // true target. NeverBranch are treated as a conditional branch that always - // goes the same direction for most of the optimizer and are used to give a - // fake exit path to infinite loops. At this late stage they need to turn - // into Goto's so that when you enter the infinite loop you indeed hang. - void convert_NeverBranch_to_Goto(Block *b); - - CFGLoop* create_loop_tree(); - - // Insert a node into a block, and update the _bbs - void insert( Block *b, uint idx, Node *n ) { + // Insert a node into a block at index and map the node to the block + void insert(Block *b, uint idx, Node *n) { b->_nodes.insert( idx, n ); map_node_to_block(n, b); } diff --git a/hotspot/src/share/vm/opto/buildOopMap.cpp b/hotspot/src/share/vm/opto/buildOopMap.cpp index 884142d57df..746511114a7 100644 --- a/hotspot/src/share/vm/opto/buildOopMap.cpp +++ b/hotspot/src/share/vm/opto/buildOopMap.cpp @@ -87,7 +87,6 @@ // OptoReg::Bad for not-callee-saved. -//------------------------------OopFlow---------------------------------------- // Structure to pass around struct OopFlow : public ResourceObj { short *_callees; // Array mapping register to callee-saved @@ -119,7 +118,6 @@ struct OopFlow : public ResourceObj { OopMap *build_oop_map( Node *n, int max_reg, PhaseRegAlloc *regalloc, int* live ); }; -//------------------------------compute_reach---------------------------------- // Given reaching-defs for this block start, compute it for this block end void OopFlow::compute_reach( PhaseRegAlloc *regalloc, int max_reg, Dict *safehash ) { @@ -177,7 +175,6 @@ void OopFlow::compute_reach( PhaseRegAlloc *regalloc, int max_reg, Dict *safehas } } -//------------------------------merge------------------------------------------ // Merge the given flow into the 'this' flow void OopFlow::merge( OopFlow *flow, int max_reg ) { assert( _b == NULL, "merging into a happy flow" ); @@ -197,14 +194,12 @@ void OopFlow::merge( OopFlow *flow, int max_reg ) { } -//------------------------------clone------------------------------------------ void OopFlow::clone( OopFlow *flow, int max_size ) { _b = flow->_b; memcpy( _callees, flow->_callees, sizeof(short)*max_size); memcpy( _defs , flow->_defs , sizeof(Node*)*max_size); } -//------------------------------make------------------------------------------- OopFlow *OopFlow::make( Arena *A, int max_size, Compile* C ) { short *callees = NEW_ARENA_ARRAY(A,short,max_size+1); Node **defs = NEW_ARENA_ARRAY(A,Node*,max_size+1); @@ -215,7 +210,6 @@ OopFlow *OopFlow::make( Arena *A, int max_size, Compile* C ) { return flow; } -//------------------------------bit twiddlers---------------------------------- static int get_live_bit( int *live, int reg ) { return live[reg>>LogBitsPerInt] & (1<<(reg&(BitsPerInt-1))); } static void set_live_bit( int *live, int reg ) { @@ -223,7 +217,6 @@ static void set_live_bit( int *live, int reg ) { static void clr_live_bit( int *live, int reg ) { live[reg>>LogBitsPerInt] &= ~(1<<(reg&(BitsPerInt-1))); } -//------------------------------build_oop_map---------------------------------- // Build an oopmap from the current flow info OopMap *OopFlow::build_oop_map( Node *n, int max_reg, PhaseRegAlloc *regalloc, int* live ) { int framesize = regalloc->_framesize; @@ -412,19 +405,18 @@ OopMap *OopFlow::build_oop_map( Node *n, int max_reg, PhaseRegAlloc *regalloc, i return omap; } -//------------------------------do_liveness------------------------------------ // Compute backwards liveness on registers -static void do_liveness( PhaseRegAlloc *regalloc, PhaseCFG *cfg, Block_List *worklist, int max_reg_ints, Arena *A, Dict *safehash ) { - int *live = NEW_ARENA_ARRAY(A, int, (cfg->_num_blocks+1) * max_reg_ints); - int *tmp_live = &live[cfg->_num_blocks * max_reg_ints]; - Node *root = cfg->C->root(); +static void do_liveness(PhaseRegAlloc* regalloc, PhaseCFG* cfg, Block_List* worklist, int max_reg_ints, Arena* A, Dict* safehash) { + int* live = NEW_ARENA_ARRAY(A, int, (cfg->number_of_blocks() + 1) * max_reg_ints); + int* tmp_live = &live[cfg->number_of_blocks() * max_reg_ints]; + Node* root = cfg->get_root_node(); // On CISC platforms, get the node representing the stack pointer that regalloc // used for spills Node *fp = NodeSentinel; if (UseCISCSpill && root->req() > 1) { fp = root->in(1)->in(TypeFunc::FramePtr); } - memset( live, 0, cfg->_num_blocks * (max_reg_ints<number_of_blocks() * (max_reg_ints << LogBytesPerInt)); // Push preds onto worklist for (uint i = 1; i < root->req(); i++) { Block* block = cfg->get_block_for_node(root->in(i)); @@ -549,29 +541,32 @@ static void do_liveness( PhaseRegAlloc *regalloc, PhaseCFG *cfg, Block_List *wor // Scan for any missing safepoints. Happens to infinite loops // ala ZKM.jar uint i; - for( i=1; i_num_blocks; i++ ) { - Block *b = cfg->_blocks[i]; + for (i = 1; i < cfg->number_of_blocks(); i++) { + Block* block = cfg->get_block(i); uint j; - for( j=1; j_nodes.size(); j++ ) - if( b->_nodes[j]->jvms() && - (*safehash)[b->_nodes[j]] == NULL ) + for (j = 1; j < block->_nodes.size(); j++) { + if (block->_nodes[j]->jvms() && (*safehash)[block->_nodes[j]] == NULL) { break; - if( j_nodes.size() ) break; + } + } + if (j < block->_nodes.size()) { + break; + } } - if( i == cfg->_num_blocks ) + if (i == cfg->number_of_blocks()) { break; // Got 'em all + } #ifndef PRODUCT if( PrintOpto && Verbose ) tty->print_cr("retripping live calc"); #endif // Force the issue (expensively): recheck everybody - for( i=1; i_num_blocks; i++ ) - worklist->push(cfg->_blocks[i]); + for (i = 1; i < cfg->number_of_blocks(); i++) { + worklist->push(cfg->get_block(i)); + } } - } -//------------------------------BuildOopMaps----------------------------------- // Collect GC mask info - where are all the OOPs? void Compile::BuildOopMaps() { NOT_PRODUCT( TracePhase t3("bldOopMaps", &_t_buildOopMaps, TimeCompiler); ) @@ -592,12 +587,12 @@ void Compile::BuildOopMaps() { OopFlow *free_list = NULL; // Free, unused // Array mapping blocks to completed oopflows - OopFlow **flows = NEW_ARENA_ARRAY(A, OopFlow*, _cfg->_num_blocks); - memset( flows, 0, _cfg->_num_blocks*sizeof(OopFlow*) ); + OopFlow **flows = NEW_ARENA_ARRAY(A, OopFlow*, _cfg->number_of_blocks()); + memset( flows, 0, _cfg->number_of_blocks() * sizeof(OopFlow*) ); // Do the first block 'by hand' to prime the worklist - Block *entry = _cfg->_blocks[1]; + Block *entry = _cfg->get_block(1); OopFlow *rootflow = OopFlow::make(A,max_reg,this); // Initialize to 'bottom' (not 'top') memset( rootflow->_callees, OptoReg::Bad, max_reg*sizeof(short) ); @@ -623,7 +618,9 @@ void Compile::BuildOopMaps() { Block *b = worklist.pop(); // Ignore root block - if( b == _cfg->_broot ) continue; + if (b == _cfg->get_root_block()) { + continue; + } // Block is already done? Happens if block has several predecessors, // he can get on the worklist more than once. if( flows[b->_pre_order] ) continue; diff --git a/hotspot/src/share/vm/opto/chaitin.cpp b/hotspot/src/share/vm/opto/chaitin.cpp index 4fc254f40ca..d19cf1709d7 100644 --- a/hotspot/src/share/vm/opto/chaitin.cpp +++ b/hotspot/src/share/vm/opto/chaitin.cpp @@ -40,10 +40,8 @@ #include "opto/opcodes.hpp" #include "opto/rootnode.hpp" -//============================================================================= - #ifndef PRODUCT -void LRG::dump( ) const { +void LRG::dump() const { ttyLocker ttyl; tty->print("%d ",num_regs()); _mask.dump(); @@ -94,7 +92,6 @@ void LRG::dump( ) const { } #endif -//------------------------------score------------------------------------------ // Compute score from cost and area. Low score is best to spill. static double raw_score( double cost, double area ) { return cost - (area*RegisterCostAreaRatio) * 1.52588e-5; @@ -125,7 +122,6 @@ double LRG::score() const { return score; } -//------------------------------LRG_List--------------------------------------- LRG_List::LRG_List( uint max ) : _cnt(max), _max(max), _lidxs(NEW_RESOURCE_ARRAY(uint,max)) { memset( _lidxs, 0, sizeof(uint)*max ); } @@ -211,7 +207,6 @@ uint LiveRangeMap::find_const(uint lrg) const { return next; } -//------------------------------Chaitin---------------------------------------- PhaseChaitin::PhaseChaitin(uint unique, PhaseCFG &cfg, Matcher &matcher) : PhaseRegAlloc(unique, cfg, matcher, #ifndef PRODUCT @@ -232,31 +227,31 @@ PhaseChaitin::PhaseChaitin(uint unique, PhaseCFG &cfg, Matcher &matcher) { NOT_PRODUCT( Compile::TracePhase t3("ctorChaitin", &_t_ctorChaitin, TimeCompiler); ) - _high_frequency_lrg = MIN2(float(OPTO_LRG_HIGH_FREQ), _cfg._outer_loop_freq); + _high_frequency_lrg = MIN2(float(OPTO_LRG_HIGH_FREQ), _cfg.get_outer_loop_frequency()); // Build a list of basic blocks, sorted by frequency - _blks = NEW_RESOURCE_ARRAY( Block *, _cfg._num_blocks ); + _blks = NEW_RESOURCE_ARRAY(Block *, _cfg.number_of_blocks()); // Experiment with sorting strategies to speed compilation double cutoff = BLOCK_FREQUENCY(1.0); // Cutoff for high frequency bucket Block **buckets[NUMBUCKS]; // Array of buckets uint buckcnt[NUMBUCKS]; // Array of bucket counters double buckval[NUMBUCKS]; // Array of bucket value cutoffs for (uint i = 0; i < NUMBUCKS; i++) { - buckets[i] = NEW_RESOURCE_ARRAY(Block *, _cfg._num_blocks); + buckets[i] = NEW_RESOURCE_ARRAY(Block *, _cfg.number_of_blocks()); buckcnt[i] = 0; // Bump by three orders of magnitude each time cutoff *= 0.001; buckval[i] = cutoff; - for (uint j = 0; j < _cfg._num_blocks; j++) { + for (uint j = 0; j < _cfg.number_of_blocks(); j++) { buckets[i][j] = NULL; } } // Sort blocks into buckets - for (uint i = 0; i < _cfg._num_blocks; i++) { + for (uint i = 0; i < _cfg.number_of_blocks(); i++) { for (uint j = 0; j < NUMBUCKS; j++) { - if ((j == NUMBUCKS - 1) || (_cfg._blocks[i]->_freq > buckval[j])) { + if ((j == NUMBUCKS - 1) || (_cfg.get_block(i)->_freq > buckval[j])) { // Assign block to end of list for appropriate bucket - buckets[j][buckcnt[j]++] = _cfg._blocks[i]; + buckets[j][buckcnt[j]++] = _cfg.get_block(i); break; // kick out of inner loop } } @@ -269,10 +264,9 @@ PhaseChaitin::PhaseChaitin(uint unique, PhaseCFG &cfg, Matcher &matcher) } } - assert(blkcnt == _cfg._num_blocks, "Block array not totally filled"); + assert(blkcnt == _cfg.number_of_blocks(), "Block array not totally filled"); } -//------------------------------Union------------------------------------------ // union 2 sets together. void PhaseChaitin::Union( const Node *src_n, const Node *dst_n ) { uint src = _lrg_map.find(src_n); @@ -285,7 +279,6 @@ void PhaseChaitin::Union( const Node *src_n, const Node *dst_n ) { _lrg_map.uf_map(dst, src); } -//------------------------------new_lrg---------------------------------------- void PhaseChaitin::new_lrg(const Node *x, uint lrg) { // Make the Node->LRG mapping _lrg_map.extend(x->_idx,lrg); @@ -311,7 +304,6 @@ bool PhaseChaitin::clone_projs_shared(Block *b, uint idx, Node *con, Node *copy, return true; } -//------------------------------compact---------------------------------------- // Renumber the live ranges to compact them. Makes the IFG smaller. void PhaseChaitin::compact() { // Current the _uf_map contains a series of short chains which are headed @@ -677,20 +669,19 @@ void PhaseChaitin::Register_Allocate() { C->set_indexSet_arena(NULL); // ResourceArea is at end of scope } -//------------------------------de_ssa----------------------------------------- void PhaseChaitin::de_ssa() { // Set initial Names for all Nodes. Most Nodes get the virtual register // number. A few get the ZERO live range number. These do not // get allocated, but instead rely on correct scheduling to ensure that // only one instance is simultaneously live at a time. uint lr_counter = 1; - for( uint i = 0; i < _cfg._num_blocks; i++ ) { - Block *b = _cfg._blocks[i]; - uint cnt = b->_nodes.size(); + for( uint i = 0; i < _cfg.number_of_blocks(); i++ ) { + Block* block = _cfg.get_block(i); + uint cnt = block->_nodes.size(); // Handle all the normal Nodes in the block for( uint j = 0; j < cnt; j++ ) { - Node *n = b->_nodes[j]; + Node *n = block->_nodes[j]; // Pre-color to the zero live range, or pick virtual register const RegMask &rm = n->out_RegMask(); _lrg_map.map(n->_idx, rm.is_NotEmpty() ? lr_counter++ : 0); @@ -701,52 +692,55 @@ void PhaseChaitin::de_ssa() { } -//------------------------------gather_lrg_masks------------------------------- // Gather LiveRanGe information, including register masks. Modification of // cisc spillable in_RegMasks should not be done before AggressiveCoalesce. void PhaseChaitin::gather_lrg_masks( bool after_aggressive ) { // Nail down the frame pointer live range - uint fp_lrg = _lrg_map.live_range_id(_cfg._root->in(1)->in(TypeFunc::FramePtr)); + uint fp_lrg = _lrg_map.live_range_id(_cfg.get_root_node()->in(1)->in(TypeFunc::FramePtr)); lrgs(fp_lrg)._cost += 1e12; // Cost is infinite // For all blocks - for( uint i = 0; i < _cfg._num_blocks; i++ ) { - Block *b = _cfg._blocks[i]; + for (uint i = 0; i < _cfg.number_of_blocks(); i++) { + Block* block = _cfg.get_block(i); // For all instructions - for( uint j = 1; j < b->_nodes.size(); j++ ) { - Node *n = b->_nodes[j]; + for (uint j = 1; j < block->_nodes.size(); j++) { + Node* n = block->_nodes[j]; uint input_edge_start =1; // Skip control most nodes - if( n->is_Mach() ) input_edge_start = n->as_Mach()->oper_input_base(); + if (n->is_Mach()) { + input_edge_start = n->as_Mach()->oper_input_base(); + } uint idx = n->is_Copy(); // Get virtual register number, same as LiveRanGe index uint vreg = _lrg_map.live_range_id(n); - LRG &lrg = lrgs(vreg); - if( vreg ) { // No vreg means un-allocable (e.g. memory) + LRG& lrg = lrgs(vreg); + if (vreg) { // No vreg means un-allocable (e.g. memory) // Collect has-copy bit - if( idx ) { + if (idx) { lrg._has_copy = 1; uint clidx = _lrg_map.live_range_id(n->in(idx)); - LRG ©_src = lrgs(clidx); + LRG& copy_src = lrgs(clidx); copy_src._has_copy = 1; } // Check for float-vs-int live range (used in register-pressure // calculations) const Type *n_type = n->bottom_type(); - if (n_type->is_floatingpoint()) + if (n_type->is_floatingpoint()) { lrg._is_float = 1; + } // Check for twice prior spilling. Once prior spilling might have // spilled 'soft', 2nd prior spill should have spilled 'hard' and // further spilling is unlikely to make progress. - if( _spilled_once.test(n->_idx) ) { + if (_spilled_once.test(n->_idx)) { lrg._was_spilled1 = 1; - if( _spilled_twice.test(n->_idx) ) + if (_spilled_twice.test(n->_idx)) { lrg._was_spilled2 = 1; + } } #ifndef PRODUCT @@ -783,16 +777,18 @@ void PhaseChaitin::gather_lrg_masks( bool after_aggressive ) { // Check for bound register masks const RegMask &lrgmask = lrg.mask(); - if (lrgmask.is_bound(ireg)) + if (lrgmask.is_bound(ireg)) { lrg._is_bound = 1; + } // Check for maximum frequency value - if (lrg._maxfreq < b->_freq) - lrg._maxfreq = b->_freq; + if (lrg._maxfreq < block->_freq) { + lrg._maxfreq = block->_freq; + } // Check for oop-iness, or long/double // Check for multi-kill projection - switch( ireg ) { + switch (ireg) { case MachProjNode::fat_proj: // Fat projections have size equal to number of registers killed lrg.set_num_regs(rm.Size()); @@ -962,7 +958,7 @@ void PhaseChaitin::gather_lrg_masks( bool after_aggressive ) { // AggressiveCoalesce. This effectively pre-virtual-splits // around uncommon uses of common defs. const RegMask &rm = n->in_RegMask(k); - if (!after_aggressive && _cfg.get_block_for_node(n->in(k))->_freq > 1000 * b->_freq) { + if (!after_aggressive && _cfg.get_block_for_node(n->in(k))->_freq > 1000 * block->_freq) { // Since we are BEFORE aggressive coalesce, leave the register // mask untrimmed by the call. This encourages more coalescing. // Later, AFTER aggressive, this live range will have to spill @@ -1006,8 +1002,9 @@ void PhaseChaitin::gather_lrg_masks( bool after_aggressive ) { } // Check for maximum frequency value - if( lrg._maxfreq < b->_freq ) - lrg._maxfreq = b->_freq; + if (lrg._maxfreq < block->_freq) { + lrg._maxfreq = block->_freq; + } } // End for all allocated inputs } // end for all instructions @@ -1029,7 +1026,6 @@ void PhaseChaitin::gather_lrg_masks( bool after_aggressive ) { } } -//------------------------------set_was_low------------------------------------ // Set the was-lo-degree bit. Conservative coalescing should not change the // colorability of the graph. If any live range was of low-degree before // coalescing, it should Simplify. This call sets the was-lo-degree bit. @@ -1066,7 +1062,6 @@ void PhaseChaitin::set_was_low() { #define REGISTER_CONSTRAINED 16 -//------------------------------cache_lrg_info--------------------------------- // Compute cost/area ratio, in case we spill. Build the lo-degree list. void PhaseChaitin::cache_lrg_info( ) { @@ -1100,7 +1095,6 @@ void PhaseChaitin::cache_lrg_info( ) { } } -//------------------------------Pre-Simplify----------------------------------- // Simplify the IFG by removing LRGs of low degree that have NO copies void PhaseChaitin::Pre_Simplify( ) { @@ -1151,7 +1145,6 @@ void PhaseChaitin::Pre_Simplify( ) { // No more lo-degree no-copy live ranges to simplify } -//------------------------------Simplify--------------------------------------- // Simplify the IFG by removing LRGs of low degree. void PhaseChaitin::Simplify( ) { @@ -1288,7 +1281,6 @@ void PhaseChaitin::Simplify( ) { } -//------------------------------is_legal_reg----------------------------------- // Is 'reg' register legal for 'lrg'? static bool is_legal_reg(LRG &lrg, OptoReg::Name reg, int chunk) { if (reg >= chunk && reg < (chunk + RegMask::CHUNK_SIZE) && @@ -1315,7 +1307,6 @@ static bool is_legal_reg(LRG &lrg, OptoReg::Name reg, int chunk) { return false; } -//------------------------------bias_color------------------------------------- // Choose a color using the biasing heuristic OptoReg::Name PhaseChaitin::bias_color( LRG &lrg, int chunk ) { @@ -1377,7 +1368,6 @@ OptoReg::Name PhaseChaitin::bias_color( LRG &lrg, int chunk ) { return OptoReg::add( reg, chunk ); } -//------------------------------choose_color----------------------------------- // Choose a color in the current chunk OptoReg::Name PhaseChaitin::choose_color( LRG &lrg, int chunk ) { assert( C->in_preserve_stack_slots() == 0 || chunk != 0 || lrg._is_bound || lrg.mask().is_bound1() || !lrg.mask().Member(OptoReg::Name(_matcher._old_SP-1)), "must not allocate stack0 (inside preserve area)"); @@ -1399,7 +1389,6 @@ OptoReg::Name PhaseChaitin::choose_color( LRG &lrg, int chunk ) { return lrg.mask().find_last_elem(); } -//------------------------------Select----------------------------------------- // Select colors by re-inserting LRGs back into the IFG. LRGs are re-inserted // in reverse order of removal. As long as nothing of hi-degree was yanked, // everything going back is guaranteed a color. Select that color. If some @@ -1574,8 +1563,6 @@ uint PhaseChaitin::Select( ) { return spill_reg-LRG::SPILL_REG; // Return number of spills } - -//------------------------------copy_was_spilled------------------------------- // Copy 'was_spilled'-edness from the source Node to the dst Node. void PhaseChaitin::copy_was_spilled( Node *src, Node *dst ) { if( _spilled_once.test(src->_idx) ) { @@ -1588,14 +1575,12 @@ void PhaseChaitin::copy_was_spilled( Node *src, Node *dst ) { } } -//------------------------------set_was_spilled-------------------------------- // Set the 'spilled_once' or 'spilled_twice' flag on a node. void PhaseChaitin::set_was_spilled( Node *n ) { if( _spilled_once.test_set(n->_idx) ) _spilled_twice.set(n->_idx); } -//------------------------------fixup_spills----------------------------------- // Convert Ideal spill instructions into proper FramePtr + offset Loads and // Stores. Use-def chains are NOT preserved, but Node->LRG->reg maps are. void PhaseChaitin::fixup_spills() { @@ -1605,16 +1590,16 @@ void PhaseChaitin::fixup_spills() { NOT_PRODUCT( Compile::TracePhase t3("fixupSpills", &_t_fixupSpills, TimeCompiler); ) // Grab the Frame Pointer - Node *fp = _cfg._broot->head()->in(1)->in(TypeFunc::FramePtr); + Node *fp = _cfg.get_root_block()->head()->in(1)->in(TypeFunc::FramePtr); // For all blocks - for( uint i = 0; i < _cfg._num_blocks; i++ ) { - Block *b = _cfg._blocks[i]; + for (uint i = 0; i < _cfg.number_of_blocks(); i++) { + Block* block = _cfg.get_block(i); // For all instructions in block - uint last_inst = b->end_idx(); - for( uint j = 1; j <= last_inst; j++ ) { - Node *n = b->_nodes[j]; + uint last_inst = block->end_idx(); + for (uint j = 1; j <= last_inst; j++) { + Node* n = block->_nodes[j]; // Dead instruction??? assert( n->outcnt() != 0 ||// Nothing dead after post alloc @@ -1651,7 +1636,7 @@ void PhaseChaitin::fixup_spills() { assert( cisc->oper_input_base() == 2, "Only adding one edge"); cisc->ins_req(1,src); // Requires a memory edge } - b->_nodes.map(j,cisc); // Insert into basic block + block->_nodes.map(j,cisc); // Insert into basic block n->subsume_by(cisc, C); // Correct graph // ++_used_cisc_instructions; @@ -1677,7 +1662,6 @@ void PhaseChaitin::fixup_spills() { } // End of for all blocks } -//------------------------------find_base_for_derived-------------------------- // Helper to stretch above; recursively discover the base Node for a // given derived Node. Easy for AddP-related machine nodes, but needs // to be recursive for derived Phis. @@ -1707,7 +1691,7 @@ Node *PhaseChaitin::find_base_for_derived( Node **derived_base_map, Node *derive // Initialize it once and make it shared: // set control to _root and place it into Start block // (where top() node is placed). - base->init_req(0, _cfg._root); + base->init_req(0, _cfg.get_root_node()); Block *startb = _cfg.get_block_for_node(C->top()); startb->_nodes.insert(startb->find_node(C->top()), base ); _cfg.map_node_to_block(base, startb); @@ -1716,7 +1700,7 @@ Node *PhaseChaitin::find_base_for_derived( Node **derived_base_map, Node *derive if (_lrg_map.live_range_id(base) == 0) { new_lrg(base, maxlrg++); } - assert(base->in(0) == _cfg._root && _cfg.get_block_for_node(base) == _cfg.get_block_for_node(C->top()), "base NULL should be shared"); + assert(base->in(0) == _cfg.get_root_node() && _cfg.get_block_for_node(base) == _cfg.get_block_for_node(C->top()), "base NULL should be shared"); derived_base_map[derived->_idx] = base; return base; } @@ -1779,8 +1763,6 @@ Node *PhaseChaitin::find_base_for_derived( Node **derived_base_map, Node *derive return base; } - -//------------------------------stretch_base_pointer_live_ranges--------------- // At each Safepoint, insert extra debug edges for each pair of derived value/ // base pointer that is live across the Safepoint for oopmap building. The // edge pairs get added in after sfpt->jvmtail()->oopoff(), but are in the @@ -1792,14 +1774,14 @@ bool PhaseChaitin::stretch_base_pointer_live_ranges(ResourceArea *a) { memset( derived_base_map, 0, sizeof(Node*)*C->unique() ); // For all blocks in RPO do... - for( uint i=0; i<_cfg._num_blocks; i++ ) { - Block *b = _cfg._blocks[i]; + for (uint i = 0; i < _cfg.number_of_blocks(); i++) { + Block* block = _cfg.get_block(i); // Note use of deep-copy constructor. I cannot hammer the original // liveout bits, because they are needed by the following coalesce pass. - IndexSet liveout(_live->live(b)); + IndexSet liveout(_live->live(block)); - for( uint j = b->end_idx() + 1; j > 1; j-- ) { - Node *n = b->_nodes[j-1]; + for (uint j = block->end_idx() + 1; j > 1; j--) { + Node* n = block->_nodes[j - 1]; // Pre-split compares of loop-phis. Loop-phis form a cycle we would // like to see in the same register. Compare uses the loop-phi and so @@ -1814,7 +1796,7 @@ bool PhaseChaitin::stretch_base_pointer_live_ranges(ResourceArea *a) { Node *phi = n->in(1); if( phi->is_Phi() && phi->as_Phi()->region()->is_Loop() ) { Block *phi_block = _cfg.get_block_for_node(phi); - if (_cfg.get_block_for_node(phi_block->pred(2)) == b) { + if (_cfg.get_block_for_node(phi_block->pred(2)) == block) { const RegMask *mask = C->matcher()->idealreg2spillmask[Op_RegI]; Node *spill = new (C) MachSpillCopyNode( phi, *mask, *mask ); insert_proj( phi_block, 1, spill, maxlrg++ ); @@ -1868,7 +1850,7 @@ bool PhaseChaitin::stretch_base_pointer_live_ranges(ResourceArea *a) { if ((_lrg_map.live_range_id(base) >= _lrg_map.max_lrg_id() || // (Brand new base (hence not live) or !liveout.member(_lrg_map.live_range_id(base))) && // not live) AND (_lrg_map.live_range_id(base) > 0) && // not a constant - _cfg.get_block_for_node(base) != b) { // base not def'd in blk) + _cfg.get_block_for_node(base) != block) { // base not def'd in blk) // Base pointer is not currently live. Since I stretched // the base pointer to here and it crosses basic-block // boundaries, the global live info is now incorrect. @@ -1903,15 +1885,12 @@ bool PhaseChaitin::stretch_base_pointer_live_ranges(ResourceArea *a) { return must_recompute_live != 0; } - -//------------------------------add_reference---------------------------------- // Extend the node to LRG mapping void PhaseChaitin::add_reference(const Node *node, const Node *old_node) { _lrg_map.extend(node->_idx, _lrg_map.live_range_id(old_node)); } -//------------------------------dump------------------------------------------- #ifndef PRODUCT void PhaseChaitin::dump(const Node *n) const { uint r = (n->_idx < _lrg_map.size()) ? _lrg_map.find_const(n) : 0; @@ -2017,8 +1996,9 @@ void PhaseChaitin::dump() const { _matcher._new_SP, _framesize ); // For all blocks - for( uint i = 0; i < _cfg._num_blocks; i++ ) - dump(_cfg._blocks[i]); + for (uint i = 0; i < _cfg.number_of_blocks(); i++) { + dump(_cfg.get_block(i)); + } // End of per-block dump tty->print("\n"); @@ -2059,7 +2039,6 @@ void PhaseChaitin::dump() const { tty->print_cr(""); } -//------------------------------dump_degree_lists------------------------------ void PhaseChaitin::dump_degree_lists() const { // Dump lo-degree list tty->print("Lo degree: "); @@ -2080,7 +2059,6 @@ void PhaseChaitin::dump_degree_lists() const { tty->print_cr(""); } -//------------------------------dump_simplified-------------------------------- void PhaseChaitin::dump_simplified() const { tty->print("Simplified: "); for( uint i = _simplified; i; i = lrgs(i)._next ) @@ -2099,7 +2077,6 @@ static char *print_reg( OptoReg::Name reg, const PhaseChaitin *pc, char *buf ) { return buf+strlen(buf); } -//------------------------------dump_register---------------------------------- // Dump a register name into a buffer. Be intelligent if we get called // before allocation is complete. char *PhaseChaitin::dump_register( const Node *n, char *buf ) const { @@ -2133,7 +2110,6 @@ char *PhaseChaitin::dump_register( const Node *n, char *buf ) const { return buf+strlen(buf); } -//----------------------dump_for_spill_split_recycle-------------------------- void PhaseChaitin::dump_for_spill_split_recycle() const { if( WizardMode && (PrintCompilation || PrintOpto) ) { // Display which live ranges need to be split and the allocator's state @@ -2149,7 +2125,6 @@ void PhaseChaitin::dump_for_spill_split_recycle() const { } } -//------------------------------dump_frame------------------------------------ void PhaseChaitin::dump_frame() const { const char *fp = OptoReg::regname(OptoReg::c_frame_pointer); const TypeTuple *domain = C->tf()->domain(); @@ -2255,17 +2230,16 @@ void PhaseChaitin::dump_frame() const { tty->print_cr("#"); } -//------------------------------dump_bb---------------------------------------- void PhaseChaitin::dump_bb( uint pre_order ) const { tty->print_cr("---dump of B%d---",pre_order); - for( uint i = 0; i < _cfg._num_blocks; i++ ) { - Block *b = _cfg._blocks[i]; - if( b->_pre_order == pre_order ) - dump(b); + for (uint i = 0; i < _cfg.number_of_blocks(); i++) { + Block* block = _cfg.get_block(i); + if (block->_pre_order == pre_order) { + dump(block); + } } } -//------------------------------dump_lrg--------------------------------------- void PhaseChaitin::dump_lrg( uint lidx, bool defs_only ) const { tty->print_cr("---dump of L%d---",lidx); @@ -2287,17 +2261,17 @@ void PhaseChaitin::dump_lrg( uint lidx, bool defs_only ) const { tty->cr(); } // For all blocks - for( uint i = 0; i < _cfg._num_blocks; i++ ) { - Block *b = _cfg._blocks[i]; + for (uint i = 0; i < _cfg.number_of_blocks(); i++) { + Block* block = _cfg.get_block(i); int dump_once = 0; // For all instructions - for( uint j = 0; j < b->_nodes.size(); j++ ) { - Node *n = b->_nodes[j]; + for( uint j = 0; j < block->_nodes.size(); j++ ) { + Node *n = block->_nodes[j]; if (_lrg_map.find_const(n) == lidx) { if (!dump_once++) { tty->cr(); - b->dump_head(&_cfg); + block->dump_head(&_cfg); } dump(n); continue; @@ -2312,7 +2286,7 @@ void PhaseChaitin::dump_lrg( uint lidx, bool defs_only ) const { if (_lrg_map.find_const(m) == lidx) { if (!dump_once++) { tty->cr(); - b->dump_head(&_cfg); + block->dump_head(&_cfg); } dump(n); } @@ -2324,7 +2298,6 @@ void PhaseChaitin::dump_lrg( uint lidx, bool defs_only ) const { } #endif // not PRODUCT -//------------------------------print_chaitin_statistics------------------------------- int PhaseChaitin::_final_loads = 0; int PhaseChaitin::_final_stores = 0; int PhaseChaitin::_final_memoves= 0; diff --git a/hotspot/src/share/vm/opto/coalesce.cpp b/hotspot/src/share/vm/opto/coalesce.cpp index d1f880a6493..4d84bd42181 100644 --- a/hotspot/src/share/vm/opto/coalesce.cpp +++ b/hotspot/src/share/vm/opto/coalesce.cpp @@ -34,8 +34,6 @@ #include "opto/matcher.hpp" #include "opto/regmask.hpp" -//============================================================================= -//------------------------------Dump------------------------------------------- #ifndef PRODUCT void PhaseCoalesce::dump(Node *n) const { // Being a const function means I cannot use 'Find' @@ -43,12 +41,11 @@ void PhaseCoalesce::dump(Node *n) const { tty->print("L%d/N%d ",r,n->_idx); } -//------------------------------dump------------------------------------------- void PhaseCoalesce::dump() const { // I know I have a block layout now, so I can print blocks in a loop - for( uint i=0; i<_phc._cfg._num_blocks; i++ ) { + for( uint i=0; i<_phc._cfg.number_of_blocks(); i++ ) { uint j; - Block *b = _phc._cfg._blocks[i]; + Block* b = _phc._cfg.get_block(i); // Print a nice block header tty->print("B%d: ",b->_pre_order); for( j=1; jnum_preds(); j++ ) @@ -85,7 +82,6 @@ void PhaseCoalesce::dump() const { } #endif -//------------------------------combine_these_two------------------------------ // Combine the live ranges def'd by these 2 Nodes. N2 is an input to N1. void PhaseCoalesce::combine_these_two(Node *n1, Node *n2) { uint lr1 = _phc._lrg_map.find(n1); @@ -127,18 +123,15 @@ void PhaseCoalesce::combine_these_two(Node *n1, Node *n2) { } } -//------------------------------coalesce_driver-------------------------------- // Copy coalescing -void PhaseCoalesce::coalesce_driver( ) { - +void PhaseCoalesce::coalesce_driver() { verify(); // Coalesce from high frequency to low - for( uint i=0; i<_phc._cfg._num_blocks; i++ ) - coalesce( _phc._blks[i] ); - + for (uint i = 0; i < _phc._cfg.number_of_blocks(); i++) { + coalesce(_phc._blks[i]); + } } -//------------------------------insert_copy_with_overlap----------------------- // I am inserting copies to come out of SSA form. In the general case, I am // doing a parallel renaming. I'm in the Named world now, so I can't do a // general parallel renaming. All the copies now use "names" (live-ranges) @@ -216,7 +209,6 @@ void PhaseAggressiveCoalesce::insert_copy_with_overlap( Block *b, Node *copy, ui b->_nodes.insert(last_use_idx+1,copy); } -//------------------------------insert_copies---------------------------------- void PhaseAggressiveCoalesce::insert_copies( Matcher &matcher ) { // We do LRGs compressing and fix a liveout data only here since the other // place in Split() is guarded by the assert which we never hit. @@ -225,8 +217,8 @@ void PhaseAggressiveCoalesce::insert_copies( Matcher &matcher ) { for (uint lrg = 1; lrg < _phc._lrg_map.max_lrg_id(); lrg++) { uint compressed_lrg = _phc._lrg_map.find(lrg); if (lrg != compressed_lrg) { - for (uint bidx = 0; bidx < _phc._cfg._num_blocks; bidx++) { - IndexSet *liveout = _phc._live->live(_phc._cfg._blocks[bidx]); + for (uint bidx = 0; bidx < _phc._cfg.number_of_blocks(); bidx++) { + IndexSet *liveout = _phc._live->live(_phc._cfg.get_block(bidx)); if (liveout->member(lrg)) { liveout->remove(lrg); liveout->insert(compressed_lrg); @@ -239,10 +231,10 @@ void PhaseAggressiveCoalesce::insert_copies( Matcher &matcher ) { // Nodes with index less than '_unique' are original, non-virtual Nodes. _unique = C->unique(); - for( uint i=0; i<_phc._cfg._num_blocks; i++ ) { + for (uint i = 0; i < _phc._cfg.number_of_blocks(); i++) { C->check_node_count(NodeLimitFudgeFactor, "out of nodes in coalesce"); if (C->failing()) return; - Block *b = _phc._cfg._blocks[i]; + Block *b = _phc._cfg.get_block(i); uint cnt = b->num_preds(); // Number of inputs to the Phi for( uint l = 1; l_nodes.size(); l++ ) { @@ -403,8 +395,7 @@ void PhaseAggressiveCoalesce::insert_copies( Matcher &matcher ) { } // End of for all blocks } -//============================================================================= -//------------------------------coalesce--------------------------------------- + // Aggressive (but pessimistic) copy coalescing of a single block // The following coalesce pass represents a single round of aggressive @@ -464,20 +455,16 @@ void PhaseAggressiveCoalesce::coalesce( Block *b ) { } // End of for all instructions in block } -//============================================================================= -//------------------------------PhaseConservativeCoalesce---------------------- PhaseConservativeCoalesce::PhaseConservativeCoalesce(PhaseChaitin &chaitin) : PhaseCoalesce(chaitin) { _ulr.initialize(_phc._lrg_map.max_lrg_id()); } -//------------------------------verify----------------------------------------- void PhaseConservativeCoalesce::verify() { #ifdef ASSERT _phc.set_was_low(); #endif } -//------------------------------union_helper----------------------------------- void PhaseConservativeCoalesce::union_helper( Node *lr1_node, Node *lr2_node, uint lr1, uint lr2, Node *src_def, Node *dst_copy, Node *src_copy, Block *b, uint bindex ) { // Join live ranges. Merge larger into smaller. Union lr2 into lr1 in the // union-find tree @@ -520,7 +507,6 @@ void PhaseConservativeCoalesce::union_helper( Node *lr1_node, Node *lr2_node, ui } } -//------------------------------compute_separating_interferences--------------- // Factored code from copy_copy that computes extra interferences from // lengthening a live range by double-coalescing. uint PhaseConservativeCoalesce::compute_separating_interferences(Node *dst_copy, Node *src_copy, Block *b, uint bindex, RegMask &rm, uint reg_degree, uint rm_size, uint lr1, uint lr2 ) { @@ -586,7 +572,6 @@ uint PhaseConservativeCoalesce::compute_separating_interferences(Node *dst_copy, return reg_degree; } -//------------------------------update_ifg------------------------------------- void PhaseConservativeCoalesce::update_ifg(uint lr1, uint lr2, IndexSet *n_lr1, IndexSet *n_lr2) { // Some original neighbors of lr1 might have gone away // because the constrained register mask prevented them. @@ -616,7 +601,6 @@ void PhaseConservativeCoalesce::update_ifg(uint lr1, uint lr2, IndexSet *n_lr1, lrgs(neighbor).inc_degree( lrg1.compute_degree(lrgs(neighbor)) ); } -//------------------------------record_bias------------------------------------ static void record_bias( const PhaseIFG *ifg, int lr1, int lr2 ) { // Tag copy bias here if( !ifg->lrgs(lr1)._copy_bias ) @@ -625,7 +609,6 @@ static void record_bias( const PhaseIFG *ifg, int lr1, int lr2 ) { ifg->lrgs(lr2)._copy_bias = lr1; } -//------------------------------copy_copy-------------------------------------- // See if I can coalesce a series of multiple copies together. I need the // final dest copy and the original src copy. They can be the same Node. // Compute the compatible register masks. @@ -785,7 +768,6 @@ bool PhaseConservativeCoalesce::copy_copy(Node *dst_copy, Node *src_copy, Block return true; } -//------------------------------coalesce--------------------------------------- // Conservative (but pessimistic) copy coalescing of a single block void PhaseConservativeCoalesce::coalesce( Block *b ) { // Bail out on infrequent blocks diff --git a/hotspot/src/share/vm/opto/compile.cpp b/hotspot/src/share/vm/opto/compile.cpp index f7cadda849b..39ebf9d0483 100644 --- a/hotspot/src/share/vm/opto/compile.cpp +++ b/hotspot/src/share/vm/opto/compile.cpp @@ -2136,7 +2136,9 @@ void Compile::Optimize() { //------------------------------Code_Gen--------------------------------------- // Given a graph, generate code for it void Compile::Code_Gen() { - if (failing()) return; + if (failing()) { + return; + } // Perform instruction selection. You might think we could reclaim Matcher // memory PDQ, but actually the Matcher is used in generating spill code. @@ -2148,12 +2150,11 @@ void Compile::Code_Gen() { // nodes. Mapping is only valid at the root of each matched subtree. NOT_PRODUCT( verify_graph_edges(); ) - Node_List proj_list; - Matcher m(proj_list); - _matcher = &m; + Matcher matcher; + _matcher = &matcher; { TracePhase t2("matcher", &_t_matcher, true); - m.match(); + matcher.match(); } // In debug mode can dump m._nodes.dump() for mapping of ideal to machine // nodes. Mapping is only valid at the root of each matched subtree. @@ -2161,31 +2162,26 @@ void Compile::Code_Gen() { // If you have too many nodes, or if matching has failed, bail out check_node_count(0, "out of nodes matching instructions"); - if (failing()) return; + if (failing()) { + return; + } // Build a proper-looking CFG - PhaseCFG cfg(node_arena(), root(), m); + PhaseCFG cfg(node_arena(), root(), matcher); _cfg = &cfg; { NOT_PRODUCT( TracePhase t2("scheduler", &_t_scheduler, TimeCompiler); ) - cfg.Dominators(); - if (failing()) return; - - NOT_PRODUCT( verify_graph_edges(); ) - - cfg.Estimate_Block_Frequency(); - cfg.GlobalCodeMotion(m,unique(),proj_list); - if (failing()) return; + bool success = cfg.do_global_code_motion(); + if (!success) { + return; + } print_method(PHASE_GLOBAL_CODE_MOTION, 2); - NOT_PRODUCT( verify_graph_edges(); ) - debug_only( cfg.verify(); ) } - NOT_PRODUCT( verify_graph_edges(); ) - PhaseChaitin regalloc(unique(), cfg, m); + PhaseChaitin regalloc(unique(), cfg, matcher); _regalloc = ®alloc; { TracePhase t2("regalloc", &_t_registerAllocation, true); @@ -2206,7 +2202,7 @@ void Compile::Code_Gen() { // can now safely remove it. { NOT_PRODUCT( TracePhase t2("blockOrdering", &_t_blockOrdering, TimeCompiler); ) - cfg.remove_empty(); + cfg.remove_empty_blocks(); if (do_freq_based_layout()) { PhaseBlockLayout layout(cfg); } else { @@ -2253,38 +2249,50 @@ void Compile::dump_asm(int *pcs, uint pc_limit) { _regalloc->dump_frame(); Node *n = NULL; - for( uint i=0; i<_cfg->_num_blocks; i++ ) { - if (VMThread::should_terminate()) { cut_short = true; break; } - Block *b = _cfg->_blocks[i]; - if (b->is_connector() && !Verbose) continue; - n = b->_nodes[0]; - if (pcs && n->_idx < pc_limit) + for (uint i = 0; i < _cfg->number_of_blocks(); i++) { + if (VMThread::should_terminate()) { + cut_short = true; + break; + } + Block* block = _cfg->get_block(i); + if (block->is_connector() && !Verbose) { + continue; + } + n = block->_nodes[0]; + if (pcs && n->_idx < pc_limit) { tty->print("%3.3x ", pcs[n->_idx]); - else + } else { tty->print(" "); - b->dump_head(_cfg); - if (b->is_connector()) { + } + block->dump_head(_cfg); + if (block->is_connector()) { tty->print_cr(" # Empty connector block"); - } else if (b->num_preds() == 2 && b->pred(1)->is_CatchProj() && b->pred(1)->as_CatchProj()->_con == CatchProjNode::fall_through_index) { + } else if (block->num_preds() == 2 && block->pred(1)->is_CatchProj() && block->pred(1)->as_CatchProj()->_con == CatchProjNode::fall_through_index) { tty->print_cr(" # Block is sole successor of call"); } // For all instructions Node *delay = NULL; - for( uint j = 0; j_nodes.size(); j++ ) { - if (VMThread::should_terminate()) { cut_short = true; break; } - n = b->_nodes[j]; + for (uint j = 0; j < block->_nodes.size(); j++) { + if (VMThread::should_terminate()) { + cut_short = true; + break; + } + n = block->_nodes[j]; if (valid_bundle_info(n)) { - Bundle *bundle = node_bundling(n); + Bundle* bundle = node_bundling(n); if (bundle->used_in_unconditional_delay()) { delay = n; continue; } - if (bundle->starts_bundle()) + if (bundle->starts_bundle()) { starts_bundle = '+'; + } } - if (WizardMode) n->dump(); + if (WizardMode) { + n->dump(); + } if( !n->is_Region() && // Dont print in the Assembly !n->is_Phi() && // a few noisely useless nodes diff --git a/hotspot/src/share/vm/opto/domgraph.cpp b/hotspot/src/share/vm/opto/domgraph.cpp index b64e291e7ca..9a98aef28e9 100644 --- a/hotspot/src/share/vm/opto/domgraph.cpp +++ b/hotspot/src/share/vm/opto/domgraph.cpp @@ -32,9 +32,6 @@ // Portions of code courtesy of Clifford Click -// Optimization - Graph Style - -//------------------------------Tarjan----------------------------------------- // A data structure that holds all the information needed to find dominators. struct Tarjan { Block *_block; // Basic block for this info @@ -60,23 +57,21 @@ struct Tarjan { }; -//------------------------------Dominator-------------------------------------- // Compute the dominator tree of the CFG. The CFG must already have been // constructed. This is the Lengauer & Tarjan O(E-alpha(E,V)) algorithm. -void PhaseCFG::Dominators( ) { +void PhaseCFG::build_dominator_tree() { // Pre-grow the blocks array, prior to the ResourceMark kicking in - _blocks.map(_num_blocks,0); + _blocks.map(number_of_blocks(), 0); ResourceMark rm; // Setup mappings from my Graph to Tarjan's stuff and back // Note: Tarjan uses 1-based arrays - Tarjan *tarjan = NEW_RESOURCE_ARRAY(Tarjan,_num_blocks+1); + Tarjan* tarjan = NEW_RESOURCE_ARRAY(Tarjan, number_of_blocks() + 1); // Tarjan's algorithm, almost verbatim: // Step 1: - _rpo_ctr = _num_blocks; - uint dfsnum = DFS( tarjan ); - if( dfsnum-1 != _num_blocks ) {// Check for unreachable loops! + uint dfsnum = do_DFS(tarjan, number_of_blocks()); + if (dfsnum - 1 != number_of_blocks()) { // Check for unreachable loops! // If the returned dfsnum does not match the number of blocks, then we // must have some unreachable loops. These can be made at any time by // IterGVN. They are cleaned up by CCP or the loop opts, but the last @@ -93,14 +88,13 @@ void PhaseCFG::Dominators( ) { C->record_method_not_compilable("unreachable loop"); return; } - _blocks._cnt = _num_blocks; + _blocks._cnt = number_of_blocks(); // Tarjan is using 1-based arrays, so these are some initialize flags tarjan[0]._size = tarjan[0]._semi = 0; tarjan[0]._label = &tarjan[0]; - uint i; - for( i=_num_blocks; i>=2; i-- ) { // For all vertices in DFS order + for (uint i = number_of_blocks(); i >= 2; i--) { // For all vertices in DFS order Tarjan *w = &tarjan[i]; // Get vertex from DFS // Step 2: @@ -130,19 +124,19 @@ void PhaseCFG::Dominators( ) { } // Step 4: - for( i=2; i <= _num_blocks; i++ ) { + for (uint i = 2; i <= number_of_blocks(); i++) { Tarjan *w = &tarjan[i]; if( w->_dom != &tarjan[w->_semi] ) w->_dom = w->_dom->_dom; w->_dom_next = w->_dom_child = NULL; // Initialize for building tree later } // No immediate dominator for the root - Tarjan *w = &tarjan[_broot->_pre_order]; + Tarjan *w = &tarjan[get_root_block()->_pre_order]; w->_dom = NULL; w->_dom_next = w->_dom_child = NULL; // Initialize for building tree later // Convert the dominator tree array into my kind of graph - for( i=1; i<=_num_blocks;i++){// For all Tarjan vertices + for(uint i = 1; i <= number_of_blocks(); i++){ // For all Tarjan vertices Tarjan *t = &tarjan[i]; // Handy access Tarjan *tdom = t->_dom; // Handy access to immediate dominator if( tdom ) { // Root has no immediate dominator @@ -152,11 +146,10 @@ void PhaseCFG::Dominators( ) { } else t->_block->_idom = NULL; // Root } - w->setdepth( _num_blocks+1 ); // Set depth in dominator tree + w->setdepth(number_of_blocks() + 1); // Set depth in dominator tree } -//----------------------------Block_Stack-------------------------------------- class Block_Stack { private: struct Block_Descr { @@ -214,7 +207,6 @@ class Block_Stack { } }; -//-------------------------most_frequent_successor----------------------------- // Find the index into the b->succs[] array of the most frequent successor. uint Block_Stack::most_frequent_successor( Block *b ) { uint freq_idx = 0; @@ -258,40 +250,38 @@ uint Block_Stack::most_frequent_successor( Block *b ) { return freq_idx; } -//------------------------------DFS-------------------------------------------- // Perform DFS search. Setup 'vertex' as DFS to vertex mapping. Setup // 'semi' as vertex to DFS mapping. Set 'parent' to DFS parent. -uint PhaseCFG::DFS( Tarjan *tarjan ) { - Block *b = _broot; +uint PhaseCFG::do_DFS(Tarjan *tarjan, uint rpo_counter) { + Block* root_block = get_root_block(); uint pre_order = 1; - // Allocate stack of size _num_blocks+1 to avoid frequent realloc - Block_Stack bstack(tarjan, _num_blocks+1); + // Allocate stack of size number_of_blocks() + 1 to avoid frequent realloc + Block_Stack bstack(tarjan, number_of_blocks() + 1); // Push on stack the state for the first block - bstack.push(pre_order, b); + bstack.push(pre_order, root_block); ++pre_order; while (bstack.is_nonempty()) { if (!bstack.last_successor()) { // Walk over all successors in pre-order (DFS). - Block *s = bstack.next_successor(); - if (s->_pre_order == 0) { // Check for no-pre-order, not-visited + Block* next_block = bstack.next_successor(); + if (next_block->_pre_order == 0) { // Check for no-pre-order, not-visited // Push on stack the state of successor - bstack.push(pre_order, s); + bstack.push(pre_order, next_block); ++pre_order; } } else { // Build a reverse post-order in the CFG _blocks array Block *stack_top = bstack.pop(); - stack_top->_rpo = --_rpo_ctr; + stack_top->_rpo = --rpo_counter; _blocks.map(stack_top->_rpo, stack_top); } } return pre_order; } -//------------------------------COMPRESS--------------------------------------- void Tarjan::COMPRESS() { assert( _ancestor != 0, "" ); @@ -303,14 +293,12 @@ void Tarjan::COMPRESS() } } -//------------------------------EVAL------------------------------------------- Tarjan *Tarjan::EVAL() { if( !_ancestor ) return _label; COMPRESS(); return (_ancestor->_label->_semi >= _label->_semi) ? _label : _ancestor->_label; } -//------------------------------LINK------------------------------------------- void Tarjan::LINK( Tarjan *w, Tarjan *tarjan0 ) { Tarjan *s = w; while( w->_label->_semi < s->_child->_label->_semi ) { @@ -333,7 +321,6 @@ void Tarjan::LINK( Tarjan *w, Tarjan *tarjan0 ) { } } -//------------------------------setdepth--------------------------------------- void Tarjan::setdepth( uint stack_size ) { Tarjan **top = NEW_RESOURCE_ARRAY(Tarjan*, stack_size); Tarjan **next = top; @@ -362,8 +349,7 @@ void Tarjan::setdepth( uint stack_size ) { } while (last < top); } -//*********************** DOMINATORS ON THE SEA OF NODES*********************** -//------------------------------NTarjan---------------------------------------- +// Compute dominators on the Sea of Nodes form // A data structure that holds all the information needed to find dominators. struct NTarjan { Node *_control; // Control node associated with this info @@ -396,7 +382,6 @@ struct NTarjan { #endif }; -//------------------------------Dominator-------------------------------------- // Compute the dominator tree of the sea of nodes. This version walks all CFG // nodes (using the is_CFG() call) and places them in a dominator tree. Thus, // it needs a count of the CFG nodes for the mapping table. This is the @@ -517,7 +502,6 @@ void PhaseIdealLoop::Dominators() { } } -//------------------------------DFS-------------------------------------------- // Perform DFS search. Setup 'vertex' as DFS to vertex mapping. Setup // 'semi' as vertex to DFS mapping. Set 'parent' to DFS parent. int NTarjan::DFS( NTarjan *ntarjan, VectorSet &visited, PhaseIdealLoop *pil, uint *dfsorder) { @@ -560,7 +544,6 @@ int NTarjan::DFS( NTarjan *ntarjan, VectorSet &visited, PhaseIdealLoop *pil, uin return dfsnum; } -//------------------------------COMPRESS--------------------------------------- void NTarjan::COMPRESS() { assert( _ancestor != 0, "" ); @@ -572,14 +555,12 @@ void NTarjan::COMPRESS() } } -//------------------------------EVAL------------------------------------------- NTarjan *NTarjan::EVAL() { if( !_ancestor ) return _label; COMPRESS(); return (_ancestor->_label->_semi >= _label->_semi) ? _label : _ancestor->_label; } -//------------------------------LINK------------------------------------------- void NTarjan::LINK( NTarjan *w, NTarjan *ntarjan0 ) { NTarjan *s = w; while( w->_label->_semi < s->_child->_label->_semi ) { @@ -602,7 +583,6 @@ void NTarjan::LINK( NTarjan *w, NTarjan *ntarjan0 ) { } } -//------------------------------setdepth--------------------------------------- void NTarjan::setdepth( uint stack_size, uint *dom_depth ) { NTarjan **top = NEW_RESOURCE_ARRAY(NTarjan*, stack_size); NTarjan **next = top; @@ -631,7 +611,6 @@ void NTarjan::setdepth( uint stack_size, uint *dom_depth ) { } while (last < top); } -//------------------------------dump------------------------------------------- #ifndef PRODUCT void NTarjan::dump(int offset) const { // Dump the data from this node diff --git a/hotspot/src/share/vm/opto/gcm.cpp b/hotspot/src/share/vm/opto/gcm.cpp index 9ded635f65f..3e95535b73e 100644 --- a/hotspot/src/share/vm/opto/gcm.cpp +++ b/hotspot/src/share/vm/opto/gcm.cpp @@ -121,27 +121,30 @@ void PhaseCFG::replace_block_proj_ctrl( Node *n ) { //------------------------------schedule_pinned_nodes-------------------------- // Set the basic block for Nodes pinned into blocks -void PhaseCFG::schedule_pinned_nodes( VectorSet &visited ) { +void PhaseCFG::schedule_pinned_nodes(VectorSet &visited) { // Allocate node stack of size C->unique()+8 to avoid frequent realloc - GrowableArray spstack(C->unique()+8); + GrowableArray spstack(C->unique() + 8); spstack.push(_root); - while ( spstack.is_nonempty() ) { - Node *n = spstack.pop(); - if( !visited.test_set(n->_idx) ) { // Test node and flag it as visited - if( n->pinned() && !has_block(n)) { // Pinned? Nail it down! - assert( n->in(0), "pinned Node must have Control" ); + while (spstack.is_nonempty()) { + Node* node = spstack.pop(); + if (!visited.test_set(node->_idx)) { // Test node and flag it as visited + if (node->pinned() && !has_block(node)) { // Pinned? Nail it down! + assert(node->in(0), "pinned Node must have Control"); // Before setting block replace block_proj control edge - replace_block_proj_ctrl(n); - Node *input = n->in(0); + replace_block_proj_ctrl(node); + Node* input = node->in(0); while (!input->is_block_start()) { input = input->in(0); } - Block *b = get_block_for_node(input); // Basic block of controlling input - schedule_node_into_block(n, b); + Block* block = get_block_for_node(input); // Basic block of controlling input + schedule_node_into_block(node, block); } - for( int i = n->req() - 1; i >= 0; --i ) { // For all inputs - if( n->in(i) != NULL ) - spstack.push(n->in(i)); + + // process all inputs that are non NULL + for (int i = node->req() - 1; i >= 0; --i) { + if (node->in(i) != NULL) { + spstack.push(node->in(i)); + } } } } @@ -205,32 +208,29 @@ static Block* find_deepest_input(Node* n, const PhaseCFG* cfg) { // which all their inputs occur. bool PhaseCFG::schedule_early(VectorSet &visited, Node_List &roots) { // Allocate stack with enough space to avoid frequent realloc - Node_Stack nstack(roots.Size() + 8); // (unique >> 1) + 24 from Java2D stats - // roots.push(_root); _root will be processed among C->top() inputs + Node_Stack nstack(roots.Size() + 8); + // _root will be processed among C->top() inputs roots.push(C->top()); visited.set(C->top()->_idx); while (roots.size() != 0) { // Use local variables nstack_top_n & nstack_top_i to cache values // on stack's top. - Node *nstack_top_n = roots.pop(); - uint nstack_top_i = 0; -//while_nstack_nonempty: - while (true) { - // Get parent node and next input's index from stack's top. - Node *n = nstack_top_n; - uint i = nstack_top_i; + Node* parent_node = roots.pop(); + uint input_index = 0; - if (i == 0) { + while (true) { + if (input_index == 0) { // Fixup some control. Constants without control get attached // to root and nodes that use is_block_proj() nodes should be attached // to the region that starts their block. - const Node *in0 = n->in(0); - if (in0 != NULL) { // Control-dependent? - replace_block_proj_ctrl(n); - } else { // n->in(0) == NULL - if (n->req() == 1) { // This guy is a constant with NO inputs? - n->set_req(0, _root); + const Node* control_input = parent_node->in(0); + if (control_input != NULL) { + replace_block_proj_ctrl(parent_node); + } else { + // Is a constant with NO inputs? + if (parent_node->req() == 1) { + parent_node->set_req(0, _root); } } } @@ -239,37 +239,47 @@ bool PhaseCFG::schedule_early(VectorSet &visited, Node_List &roots) { // input is already in a block we quit following inputs (to avoid // cycles). Instead we put that Node on a worklist to be handled // later (since IT'S inputs may not have a block yet). - bool done = true; // Assume all n's inputs will be processed - while (i < n->len()) { // For all inputs - Node *in = n->in(i); // Get input - ++i; - if (in == NULL) continue; // Ignore NULL, missing inputs + + // Assume all n's inputs will be processed + bool done = true; + + while (input_index < parent_node->len()) { + Node* in = parent_node->in(input_index++); + if (in == NULL) { + continue; + } + int is_visited = visited.test_set(in->_idx); - if (!has_block(in)) { // Missing block selection? + if (!has_block(in)) { if (is_visited) { - // assert( !visited.test(in->_idx), "did not schedule early" ); return false; } - nstack.push(n, i); // Save parent node and next input's index. - nstack_top_n = in; // Process current input now. - nstack_top_i = 0; - done = false; // Not all n's inputs processed. - break; // continue while_nstack_nonempty; - } else if (!is_visited) { // Input not yet visited? - roots.push(in); // Visit this guy later, using worklist + // Save parent node and next input's index. + nstack.push(parent_node, input_index); + // Process current input now. + parent_node = in; + input_index = 0; + // Not all n's inputs processed. + done = false; + break; + } else if (!is_visited) { + // Visit this guy later, using worklist + roots.push(in); } } + if (done) { // All of n's inputs have been processed, complete post-processing. // Some instructions are pinned into a block. These include Region, // Phi, Start, Return, and other control-dependent instructions and // any projections which depend on them. - if (!n->pinned()) { + if (!parent_node->pinned()) { // Set earliest legal block. - map_node_to_block(n, find_deepest_input(n, this)); + Block* earliest_block = find_deepest_input(parent_node, this); + map_node_to_block(parent_node, earliest_block); } else { - assert(get_block_for_node(n) == get_block_for_node(n->in(0)), "Pinned Node should be at the same block as its control edge"); + assert(get_block_for_node(parent_node) == get_block_for_node(parent_node->in(0)), "Pinned Node should be at the same block as its control edge"); } if (nstack.is_empty()) { @@ -278,12 +288,12 @@ bool PhaseCFG::schedule_early(VectorSet &visited, Node_List &roots) { break; } // Get saved parent node and next input's index. - nstack_top_n = nstack.node(); - nstack_top_i = nstack.index(); + parent_node = nstack.node(); + input_index = nstack.index(); nstack.pop(); - } // if (done) - } // while (true) - } // while (roots.size() != 0) + } + } + } return true; } @@ -847,7 +857,7 @@ Node *Node_Backward_Iterator::next() { //------------------------------ComputeLatenciesBackwards---------------------- // Compute the latency of all the instructions. -void PhaseCFG::ComputeLatenciesBackwards(VectorSet &visited, Node_List &stack) { +void PhaseCFG::compute_latencies_backwards(VectorSet &visited, Node_List &stack) { #ifndef PRODUCT if (trace_opto_pipelining()) tty->print("\n#---- ComputeLatenciesBackwards ----\n"); @@ -870,31 +880,34 @@ void PhaseCFG::partial_latency_of_defs(Node *n) { // Set the latency for this instruction #ifndef PRODUCT if (trace_opto_pipelining()) { - tty->print("# latency_to_inputs: node_latency[%d] = %d for node", - n->_idx, _node_latency->at_grow(n->_idx)); + tty->print("# latency_to_inputs: node_latency[%d] = %d for node", n->_idx, get_latency_for_node(n)); dump(); } #endif - if (n->is_Proj()) + if (n->is_Proj()) { n = n->in(0); + } - if (n->is_Root()) + if (n->is_Root()) { return; + } uint nlen = n->len(); - uint use_latency = _node_latency->at_grow(n->_idx); + uint use_latency = get_latency_for_node(n); uint use_pre_order = get_block_for_node(n)->_pre_order; - for ( uint j=0; jin(j); - if (!def || def == n) + if (!def || def == n) { continue; + } // Walk backwards thru projections - if (def->is_Proj()) + if (def->is_Proj()) { def = def->in(0); + } #ifndef PRODUCT if (trace_opto_pipelining()) { @@ -907,22 +920,20 @@ void PhaseCFG::partial_latency_of_defs(Node *n) { Block *def_block = get_block_for_node(def); uint def_pre_order = def_block ? def_block->_pre_order : 0; - if ( (use_pre_order < def_pre_order) || - (use_pre_order == def_pre_order && n->is_Phi()) ) + if ((use_pre_order < def_pre_order) || (use_pre_order == def_pre_order && n->is_Phi())) { continue; + } uint delta_latency = n->latency(j); uint current_latency = delta_latency + use_latency; - if (_node_latency->at_grow(def->_idx) < current_latency) { - _node_latency->at_put_grow(def->_idx, current_latency); + if (get_latency_for_node(def) < current_latency) { + set_latency_for_node(def, current_latency); } #ifndef PRODUCT if (trace_opto_pipelining()) { - tty->print_cr("# %d + edge_latency(%d) == %d -> %d, node_latency[%d] = %d", - use_latency, j, delta_latency, current_latency, def->_idx, - _node_latency->at_grow(def->_idx)); + tty->print_cr("# %d + edge_latency(%d) == %d -> %d, node_latency[%d] = %d", use_latency, j, delta_latency, current_latency, def->_idx, get_latency_for_node(def)); } #endif } @@ -957,7 +968,7 @@ int PhaseCFG::latency_from_use(Node *n, const Node *def, Node *use) { return 0; uint nlen = use->len(); - uint nl = _node_latency->at_grow(use->_idx); + uint nl = get_latency_for_node(use); for ( uint j=0; jin(j) == n) { @@ -992,8 +1003,7 @@ void PhaseCFG::latency_from_uses(Node *n) { // Set the latency for this instruction #ifndef PRODUCT if (trace_opto_pipelining()) { - tty->print("# latency_from_outputs: node_latency[%d] = %d for node", - n->_idx, _node_latency->at_grow(n->_idx)); + tty->print("# latency_from_outputs: node_latency[%d] = %d for node", n->_idx, get_latency_for_node(n)); dump(); } #endif @@ -1006,7 +1016,7 @@ void PhaseCFG::latency_from_uses(Node *n) { if (latency < l) latency = l; } - _node_latency->at_put_grow(n->_idx, latency); + set_latency_for_node(n, latency); } //------------------------------hoist_to_cheaper_block------------------------- @@ -1016,9 +1026,9 @@ Block* PhaseCFG::hoist_to_cheaper_block(Block* LCA, Block* early, Node* self) { const double delta = 1+PROB_UNLIKELY_MAG(4); Block* least = LCA; double least_freq = least->_freq; - uint target = _node_latency->at_grow(self->_idx); - uint start_latency = _node_latency->at_grow(LCA->_nodes[0]->_idx); - uint end_latency = _node_latency->at_grow(LCA->_nodes[LCA->end_idx()]->_idx); + uint target = get_latency_for_node(self); + uint start_latency = get_latency_for_node(LCA->_nodes[0]); + uint end_latency = get_latency_for_node(LCA->_nodes[LCA->end_idx()]); bool in_latency = (target <= start_latency); const Block* root_block = get_block_for_node(_root); @@ -1035,8 +1045,7 @@ Block* PhaseCFG::hoist_to_cheaper_block(Block* LCA, Block* early, Node* self) { #ifndef PRODUCT if (trace_opto_pipelining()) { - tty->print("# Find cheaper block for latency %d: ", - _node_latency->at_grow(self->_idx)); + tty->print("# Find cheaper block for latency %d: ", get_latency_for_node(self)); self->dump(); tty->print_cr("# B%d: start latency for [%4d]=%d, end latency for [%4d]=%d, freq=%g", LCA->_pre_order, @@ -1065,9 +1074,9 @@ Block* PhaseCFG::hoist_to_cheaper_block(Block* LCA, Block* early, Node* self) { if (mach && LCA == root_block) break; - uint start_lat = _node_latency->at_grow(LCA->_nodes[0]->_idx); + uint start_lat = get_latency_for_node(LCA->_nodes[0]); uint end_idx = LCA->end_idx(); - uint end_lat = _node_latency->at_grow(LCA->_nodes[end_idx]->_idx); + uint end_lat = get_latency_for_node(LCA->_nodes[end_idx]); double LCA_freq = LCA->_freq; #ifndef PRODUCT if (trace_opto_pipelining()) { @@ -1109,7 +1118,7 @@ Block* PhaseCFG::hoist_to_cheaper_block(Block* LCA, Block* early, Node* self) { tty->print_cr("# Change latency for [%4d] from %d to %d", self->_idx, target, end_latency); } #endif - _node_latency->at_put_grow(self->_idx, end_latency); + set_latency_for_node(self, end_latency); partial_latency_of_defs(self); } @@ -1255,7 +1264,7 @@ void PhaseCFG::schedule_late(VectorSet &visited, Node_List &stack) { } // end ScheduleLate //------------------------------GlobalCodeMotion------------------------------- -void PhaseCFG::GlobalCodeMotion( Matcher &matcher, uint unique, Node_List &proj_list ) { +void PhaseCFG::global_code_motion() { ResourceMark rm; #ifndef PRODUCT @@ -1265,21 +1274,22 @@ void PhaseCFG::GlobalCodeMotion( Matcher &matcher, uint unique, Node_List &proj_ #endif // Initialize the node to block mapping for things on the proj_list - for (uint i = 0; i < proj_list.size(); i++) { - unmap_node_from_block(proj_list[i]); + for (uint i = 0; i < _matcher.number_of_projections(); i++) { + unmap_node_from_block(_matcher.get_projection(i)); } // Set the basic block for Nodes pinned into blocks - Arena *a = Thread::current()->resource_area(); - VectorSet visited(a); - schedule_pinned_nodes( visited ); + Arena* arena = Thread::current()->resource_area(); + VectorSet visited(arena); + schedule_pinned_nodes(visited); // Find the earliest Block any instruction can be placed in. Some // instructions are pinned into Blocks. Unpinned instructions can // appear in last block in which all their inputs occur. visited.Clear(); - Node_List stack(a); - stack.map( (unique >> 1) + 16, NULL); // Pre-grow the list + Node_List stack(arena); + // Pre-grow the list + stack.map((C->unique() >> 1) + 16, NULL); if (!schedule_early(visited, stack)) { // Bailout without retry C->record_method_not_compilable("early schedule failed"); @@ -1287,29 +1297,25 @@ void PhaseCFG::GlobalCodeMotion( Matcher &matcher, uint unique, Node_List &proj_ } // Build Def-Use edges. - proj_list.push(_root); // Add real root as another root - proj_list.pop(); - // Compute the latency information (via backwards walk) for all the // instructions in the graph _node_latency = new GrowableArray(); // resource_area allocation - if( C->do_scheduling() ) - ComputeLatenciesBackwards(visited, stack); + if (C->do_scheduling()) { + compute_latencies_backwards(visited, stack); + } // Now schedule all codes as LATE as possible. This is the LCA in the // dominator tree of all USES of a value. Pick the block with the least // loop nesting depth that is lowest in the dominator tree. // ( visited.Clear() called in schedule_late()->Node_Backward_Iterator() ) schedule_late(visited, stack); - if( C->failing() ) { + if (C->failing()) { // schedule_late fails only when graph is incorrect. assert(!VerifyGraphEdges, "verification should have failed"); return; } - unique = C->unique(); - #ifndef PRODUCT if (trace_opto_pipelining()) { tty->print("\n---- Detect implicit null checks ----\n"); @@ -1332,10 +1338,11 @@ void PhaseCFG::GlobalCodeMotion( Matcher &matcher, uint unique, Node_List &proj_ // By reversing the loop direction we get a very minor gain on mpegaudio. // Feel free to revert to a forward loop for clarity. // for( int i=0; i < (int)matcher._null_check_tests.size(); i+=2 ) { - for( int i= matcher._null_check_tests.size()-2; i>=0; i-=2 ) { - Node *proj = matcher._null_check_tests[i ]; - Node *val = matcher._null_check_tests[i+1]; - get_block_for_node(proj)->implicit_null_check(this, proj, val, allowed_reasons); + for (int i = _matcher._null_check_tests.size() - 2; i >= 0; i -= 2) { + Node* proj = _matcher._null_check_tests[i]; + Node* val = _matcher._null_check_tests[i + 1]; + Block* block = get_block_for_node(proj); + block->implicit_null_check(this, proj, val, allowed_reasons); // The implicit_null_check will only perform the transformation // if the null branch is truly uncommon, *and* it leads to an // uncommon trap. Combined with the too_many_traps guards @@ -1352,11 +1359,11 @@ void PhaseCFG::GlobalCodeMotion( Matcher &matcher, uint unique, Node_List &proj_ // Schedule locally. Right now a simple topological sort. // Later, do a real latency aware scheduler. - uint max_idx = C->unique(); - GrowableArray ready_cnt(max_idx, max_idx, -1); + GrowableArray ready_cnt(C->unique(), C->unique(), -1); visited.Clear(); - for (uint i = 0; i < _num_blocks; i++) { - if (!_blocks[i]->schedule_local(this, matcher, ready_cnt, visited)) { + for (uint i = 0; i < number_of_blocks(); i++) { + Block* block = get_block(i); + if (!block->schedule_local(this, _matcher, ready_cnt, visited)) { if (!C->failure_reason_is(C2Compiler::retry_no_subsuming_loads())) { C->record_method_not_compilable("local schedule failed"); } @@ -1366,15 +1373,17 @@ void PhaseCFG::GlobalCodeMotion( Matcher &matcher, uint unique, Node_List &proj_ // If we inserted any instructions between a Call and his CatchNode, // clone the instructions on all paths below the Catch. - for (uint i = 0; i < _num_blocks; i++) { - _blocks[i]->call_catch_cleanup(this, C); + for (uint i = 0; i < number_of_blocks(); i++) { + Block* block = get_block(i); + block->call_catch_cleanup(this, C); } #ifndef PRODUCT if (trace_opto_pipelining()) { tty->print("\n---- After GlobalCodeMotion ----\n"); - for (uint i = 0; i < _num_blocks; i++) { - _blocks[i]->dump(); + for (uint i = 0; i < number_of_blocks(); i++) { + Block* block = get_block(i); + block->dump(); } } #endif @@ -1382,10 +1391,29 @@ void PhaseCFG::GlobalCodeMotion( Matcher &matcher, uint unique, Node_List &proj_ _node_latency = (GrowableArray *)0xdeadbeef; } +bool PhaseCFG::do_global_code_motion() { + + build_dominator_tree(); + if (C->failing()) { + return false; + } + + NOT_PRODUCT( C->verify_graph_edges(); ) + + estimate_block_frequency(); + + global_code_motion(); + + if (C->failing()) { + return false; + } + + return true; +} //------------------------------Estimate_Block_Frequency----------------------- // Estimate block frequencies based on IfNode probabilities. -void PhaseCFG::Estimate_Block_Frequency() { +void PhaseCFG::estimate_block_frequency() { // Force conditional branches leading to uncommon traps to be unlikely, // not because we get to the uncommon_trap with less relative frequency, @@ -1393,7 +1421,7 @@ void PhaseCFG::Estimate_Block_Frequency() { // there once. if (C->do_freq_based_layout()) { Block_List worklist; - Block* root_blk = _blocks[0]; + Block* root_blk = get_block(0); for (uint i = 1; i < root_blk->num_preds(); i++) { Block *pb = get_block_for_node(root_blk->pred(i)); if (pb->has_uncommon_code()) { @@ -1402,7 +1430,9 @@ void PhaseCFG::Estimate_Block_Frequency() { } while (worklist.size() > 0) { Block* uct = worklist.pop(); - if (uct == _broot) continue; + if (uct == get_root_block()) { + continue; + } for (uint i = 1; i < uct->num_preds(); i++) { Block *pb = get_block_for_node(uct->pred(i)); if (pb->_num_succs == 1) { @@ -1426,12 +1456,12 @@ void PhaseCFG::Estimate_Block_Frequency() { _root_loop->scale_freq(); // Save outmost loop frequency for LRG frequency threshold - _outer_loop_freq = _root_loop->outer_loop_freq(); + _outer_loop_frequency = _root_loop->outer_loop_freq(); // force paths ending at uncommon traps to be infrequent if (!C->do_freq_based_layout()) { Block_List worklist; - Block* root_blk = _blocks[0]; + Block* root_blk = get_block(0); for (uint i = 1; i < root_blk->num_preds(); i++) { Block *pb = get_block_for_node(root_blk->pred(i)); if (pb->has_uncommon_code()) { @@ -1451,8 +1481,8 @@ void PhaseCFG::Estimate_Block_Frequency() { } #ifdef ASSERT - for (uint i = 0; i < _num_blocks; i++ ) { - Block *b = _blocks[i]; + for (uint i = 0; i < number_of_blocks(); i++) { + Block* b = get_block(i); assert(b->_freq >= MIN_BLOCK_FREQUENCY, "Register Allocator requires meaningful block frequency"); } #endif @@ -1476,16 +1506,16 @@ void PhaseCFG::Estimate_Block_Frequency() { CFGLoop* PhaseCFG::create_loop_tree() { #ifdef ASSERT - assert( _blocks[0] == _broot, "" ); - for (uint i = 0; i < _num_blocks; i++ ) { - Block *b = _blocks[i]; + assert(get_block(0) == get_root_block(), "first block should be root block"); + for (uint i = 0; i < number_of_blocks(); i++) { + Block* block = get_block(i); // Check that _loop field are clear...we could clear them if not. - assert(b->_loop == NULL, "clear _loop expected"); + assert(block->_loop == NULL, "clear _loop expected"); // Sanity check that the RPO numbering is reflected in the _blocks array. // It doesn't have to be for the loop tree to be built, but if it is not, // then the blocks have been reordered since dom graph building...which // may question the RPO numbering - assert(b->_rpo == i, "unexpected reverse post order number"); + assert(block->_rpo == i, "unexpected reverse post order number"); } #endif @@ -1495,11 +1525,11 @@ CFGLoop* PhaseCFG::create_loop_tree() { Block_List worklist; // Assign blocks to loops - for(uint i = _num_blocks - 1; i > 0; i-- ) { // skip Root block - Block *b = _blocks[i]; + for(uint i = number_of_blocks() - 1; i > 0; i-- ) { // skip Root block + Block* block = get_block(i); - if (b->head()->is_Loop()) { - Block* loop_head = b; + if (block->head()->is_Loop()) { + Block* loop_head = block; assert(loop_head->num_preds() - 1 == 2, "loop must have 2 predecessors"); Node* tail_n = loop_head->pred(LoopNode::LoopBackControl); Block* tail = get_block_for_node(tail_n); @@ -1533,23 +1563,23 @@ CFGLoop* PhaseCFG::create_loop_tree() { // Create a member list for each loop consisting // of both blocks and (immediate child) loops. - for (uint i = 0; i < _num_blocks; i++) { - Block *b = _blocks[i]; - CFGLoop* lp = b->_loop; + for (uint i = 0; i < number_of_blocks(); i++) { + Block* block = get_block(i); + CFGLoop* lp = block->_loop; if (lp == NULL) { // Not assigned to a loop. Add it to the method's pseudo loop. - b->_loop = root_loop; + block->_loop = root_loop; lp = root_loop; } - if (lp == root_loop || b != lp->head()) { // loop heads are already members - lp->add_member(b); + if (lp == root_loop || block != lp->head()) { // loop heads are already members + lp->add_member(block); } if (lp != root_loop) { if (lp->parent() == NULL) { // Not a nested loop. Make it a child of the method's pseudo loop. root_loop->add_nested_loop(lp); } - if (b == lp->head()) { + if (block == lp->head()) { // Add nested loop to member list of parent loop. lp->parent()->add_member(lp); } diff --git a/hotspot/src/share/vm/opto/idealGraphPrinter.cpp b/hotspot/src/share/vm/opto/idealGraphPrinter.cpp index 4330643b8b5..06cecaddbdc 100644 --- a/hotspot/src/share/vm/opto/idealGraphPrinter.cpp +++ b/hotspot/src/share/vm/opto/idealGraphPrinter.cpp @@ -416,7 +416,7 @@ void IdealGraphPrinter::visit_node(Node *n, bool edges, VectorSet* temp_set) { if (C->cfg() != NULL) { Block* block = C->cfg()->get_block_for_node(node); if (block == NULL) { - print_prop("block", C->cfg()->_blocks[0]->_pre_order); + print_prop("block", C->cfg()->get_block(0)->_pre_order); } else { print_prop("block", block->_pre_order); } @@ -637,10 +637,10 @@ void IdealGraphPrinter::walk_nodes(Node *start, bool edges, VectorSet* temp_set) if (C->cfg() != NULL) { // once we have a CFG there are some nodes that aren't really // reachable but are in the CFG so add them here. - for (uint i = 0; i < C->cfg()->_blocks.size(); i++) { - Block *b = C->cfg()->_blocks[i]; - for (uint s = 0; s < b->_nodes.size(); s++) { - nodeStack.push(b->_nodes[s]); + for (uint i = 0; i < C->cfg()->number_of_blocks(); i++) { + Block* block = C->cfg()->get_block(i); + for (uint s = 0; s < block->_nodes.size(); s++) { + nodeStack.push(block->_nodes[s]); } } } @@ -698,24 +698,24 @@ void IdealGraphPrinter::print(Compile* compile, const char *name, Node *node, in tail(EDGES_ELEMENT); if (C->cfg() != NULL) { head(CONTROL_FLOW_ELEMENT); - for (uint i = 0; i < C->cfg()->_blocks.size(); i++) { - Block *b = C->cfg()->_blocks[i]; + for (uint i = 0; i < C->cfg()->number_of_blocks(); i++) { + Block* block = C->cfg()->get_block(i); begin_head(BLOCK_ELEMENT); - print_attr(BLOCK_NAME_PROPERTY, b->_pre_order); + print_attr(BLOCK_NAME_PROPERTY, block->_pre_order); end_head(); head(SUCCESSORS_ELEMENT); - for (uint s = 0; s < b->_num_succs; s++) { + for (uint s = 0; s < block->_num_succs; s++) { begin_elem(SUCCESSOR_ELEMENT); - print_attr(BLOCK_NAME_PROPERTY, b->_succs[s]->_pre_order); + print_attr(BLOCK_NAME_PROPERTY, block->_succs[s]->_pre_order); end_elem(); } tail(SUCCESSORS_ELEMENT); head(NODES_ELEMENT); - for (uint s = 0; s < b->_nodes.size(); s++) { + for (uint s = 0; s < block->_nodes.size(); s++) { begin_elem(NODE_ELEMENT); - print_attr(NODE_ID_PROPERTY, get_node_id(b->_nodes[s])); + print_attr(NODE_ID_PROPERTY, get_node_id(block->_nodes[s])); end_elem(); } tail(NODES_ELEMENT); diff --git a/hotspot/src/share/vm/opto/ifg.cpp b/hotspot/src/share/vm/opto/ifg.cpp index 82a8ea893e4..4455cd4571f 100644 --- a/hotspot/src/share/vm/opto/ifg.cpp +++ b/hotspot/src/share/vm/opto/ifg.cpp @@ -37,12 +37,9 @@ #include "opto/memnode.hpp" #include "opto/opcodes.hpp" -//============================================================================= -//------------------------------IFG-------------------------------------------- PhaseIFG::PhaseIFG( Arena *arena ) : Phase(Interference_Graph), _arena(arena) { } -//------------------------------init------------------------------------------- void PhaseIFG::init( uint maxlrg ) { _maxlrg = maxlrg; _yanked = new (_arena) VectorSet(_arena); @@ -59,7 +56,6 @@ void PhaseIFG::init( uint maxlrg ) { } } -//------------------------------add-------------------------------------------- // Add edge between vertices a & b. These are sorted (triangular matrix), // then the smaller number is inserted in the larger numbered array. int PhaseIFG::add_edge( uint a, uint b ) { @@ -71,7 +67,6 @@ int PhaseIFG::add_edge( uint a, uint b ) { return _adjs[a].insert( b ); } -//------------------------------add_vector------------------------------------- // Add an edge between 'a' and everything in the vector. void PhaseIFG::add_vector( uint a, IndexSet *vec ) { // IFG is triangular, so do the inserts where 'a' < 'b'. @@ -86,7 +81,6 @@ void PhaseIFG::add_vector( uint a, IndexSet *vec ) { } } -//------------------------------test------------------------------------------- // Is there an edge between a and b? int PhaseIFG::test_edge( uint a, uint b ) const { // Sort a and b, so that a is larger @@ -95,7 +89,6 @@ int PhaseIFG::test_edge( uint a, uint b ) const { return _adjs[a].member(b); } -//------------------------------SquareUp--------------------------------------- // Convert triangular matrix to square matrix void PhaseIFG::SquareUp() { assert( !_is_square, "only on triangular" ); @@ -111,7 +104,6 @@ void PhaseIFG::SquareUp() { _is_square = true; } -//------------------------------Compute_Effective_Degree----------------------- // Compute effective degree in bulk void PhaseIFG::Compute_Effective_Degree() { assert( _is_square, "only on square" ); @@ -120,7 +112,6 @@ void PhaseIFG::Compute_Effective_Degree() { lrgs(i).set_degree(effective_degree(i)); } -//------------------------------test_edge_sq----------------------------------- int PhaseIFG::test_edge_sq( uint a, uint b ) const { assert( _is_square, "only on square" ); // Swap, so that 'a' has the lesser count. Then binary search is on @@ -130,7 +121,6 @@ int PhaseIFG::test_edge_sq( uint a, uint b ) const { return _adjs[a].member(b); } -//------------------------------Union------------------------------------------ // Union edges of B into A void PhaseIFG::Union( uint a, uint b ) { assert( _is_square, "only on square" ); @@ -146,7 +136,6 @@ void PhaseIFG::Union( uint a, uint b ) { } } -//------------------------------remove_node------------------------------------ // Yank a Node and all connected edges from the IFG. Return a // list of neighbors (edges) yanked. IndexSet *PhaseIFG::remove_node( uint a ) { @@ -165,7 +154,6 @@ IndexSet *PhaseIFG::remove_node( uint a ) { return neighbors(a); } -//------------------------------re_insert-------------------------------------- // Re-insert a yanked Node. void PhaseIFG::re_insert( uint a ) { assert( _is_square, "only on square" ); @@ -180,7 +168,6 @@ void PhaseIFG::re_insert( uint a ) { } } -//------------------------------compute_degree--------------------------------- // Compute the degree between 2 live ranges. If both live ranges are // aligned-adjacent powers-of-2 then we use the MAX size. If either is // mis-aligned (or for Fat-Projections, not-adjacent) then we have to @@ -196,7 +183,6 @@ int LRG::compute_degree( LRG &l ) const { return tmp; } -//------------------------------effective_degree------------------------------- // Compute effective degree for this live range. If both live ranges are // aligned-adjacent powers-of-2 then we use the MAX size. If either is // mis-aligned (or for Fat-Projections, not-adjacent) then we have to @@ -221,7 +207,6 @@ int PhaseIFG::effective_degree( uint lidx ) const { #ifndef PRODUCT -//------------------------------dump------------------------------------------- void PhaseIFG::dump() const { tty->print_cr("-- Interference Graph --%s--", _is_square ? "square" : "triangular" ); @@ -260,7 +245,6 @@ void PhaseIFG::dump() const { tty->print("\n"); } -//------------------------------stats------------------------------------------ void PhaseIFG::stats() const { ResourceMark rm; int *h_cnt = NEW_RESOURCE_ARRAY(int,_maxlrg*2); @@ -276,7 +260,6 @@ void PhaseIFG::stats() const { tty->print_cr(""); } -//------------------------------verify----------------------------------------- void PhaseIFG::verify( const PhaseChaitin *pc ) const { // IFG is square, sorted and no need for Find for( uint i = 0; i < _maxlrg; i++ ) { @@ -298,7 +281,6 @@ void PhaseIFG::verify( const PhaseChaitin *pc ) const { } #endif -//------------------------------interfere_with_live---------------------------- // Interfere this register with everything currently live. Use the RegMasks // to trim the set of possible interferences. Return a count of register-only // interferences as an estimate of register pressure. @@ -315,7 +297,6 @@ void PhaseChaitin::interfere_with_live( uint r, IndexSet *liveout ) { _ifg->add_edge( r, l ); } -//------------------------------build_ifg_virtual------------------------------ // Actually build the interference graph. Uses virtual registers only, no // physical register masks. This allows me to be very aggressive when // coalescing copies. Some of this aggressiveness will have to be undone @@ -325,9 +306,9 @@ void PhaseChaitin::interfere_with_live( uint r, IndexSet *liveout ) { void PhaseChaitin::build_ifg_virtual( ) { // For all blocks (in any order) do... - for( uint i=0; i<_cfg._num_blocks; i++ ) { - Block *b = _cfg._blocks[i]; - IndexSet *liveout = _live->live(b); + for (uint i = 0; i < _cfg.number_of_blocks(); i++) { + Block* block = _cfg.get_block(i); + IndexSet* liveout = _live->live(block); // The IFG is built by a single reverse pass over each basic block. // Starting with the known live-out set, we remove things that get @@ -337,8 +318,8 @@ void PhaseChaitin::build_ifg_virtual( ) { // The defined value interferes with everything currently live. The // value is then removed from the live-ness set and it's inputs are // added to the live-ness set. - for( uint j = b->end_idx() + 1; j > 1; j-- ) { - Node *n = b->_nodes[j-1]; + for (uint j = block->end_idx() + 1; j > 1; j--) { + Node* n = block->_nodes[j - 1]; // Get value being defined uint r = _lrg_map.live_range_id(n); @@ -408,7 +389,6 @@ void PhaseChaitin::build_ifg_virtual( ) { } // End of forall blocks } -//------------------------------count_int_pressure----------------------------- uint PhaseChaitin::count_int_pressure( IndexSet *liveout ) { IndexSetIterator elements(liveout); uint lidx; @@ -424,7 +404,6 @@ uint PhaseChaitin::count_int_pressure( IndexSet *liveout ) { return cnt; } -//------------------------------count_float_pressure--------------------------- uint PhaseChaitin::count_float_pressure( IndexSet *liveout ) { IndexSetIterator elements(liveout); uint lidx; @@ -438,7 +417,6 @@ uint PhaseChaitin::count_float_pressure( IndexSet *liveout ) { return cnt; } -//------------------------------lower_pressure--------------------------------- // Adjust register pressure down by 1. Capture last hi-to-low transition, static void lower_pressure( LRG *lrg, uint where, Block *b, uint *pressure, uint *hrp_index ) { if (lrg->mask().is_UP() && lrg->mask_size()) { @@ -460,40 +438,41 @@ static void lower_pressure( LRG *lrg, uint where, Block *b, uint *pressure, uint } } -//------------------------------build_ifg_physical----------------------------- // Build the interference graph using physical registers when available. // That is, if 2 live ranges are simultaneously alive but in their acceptable // register sets do not overlap, then they do not interfere. uint PhaseChaitin::build_ifg_physical( ResourceArea *a ) { NOT_PRODUCT( Compile::TracePhase t3("buildIFG", &_t_buildIFGphysical, TimeCompiler); ) - uint spill_reg = LRG::SPILL_REG; uint must_spill = 0; // For all blocks (in any order) do... - for( uint i = 0; i < _cfg._num_blocks; i++ ) { - Block *b = _cfg._blocks[i]; + for (uint i = 0; i < _cfg.number_of_blocks(); i++) { + Block* block = _cfg.get_block(i); // Clone (rather than smash in place) the liveout info, so it is alive // for the "collect_gc_info" phase later. - IndexSet liveout(_live->live(b)); - uint last_inst = b->end_idx(); + IndexSet liveout(_live->live(block)); + uint last_inst = block->end_idx(); // Compute first nonphi node index uint first_inst; - for( first_inst = 1; first_inst < last_inst; first_inst++ ) - if( !b->_nodes[first_inst]->is_Phi() ) + for (first_inst = 1; first_inst < last_inst; first_inst++) { + if (!block->_nodes[first_inst]->is_Phi()) { break; + } + } // Spills could be inserted before CreateEx node which should be // first instruction in block after Phis. Move CreateEx up. - for( uint insidx = first_inst; insidx < last_inst; insidx++ ) { - Node *ex = b->_nodes[insidx]; - if( ex->is_SpillCopy() ) continue; - if( insidx > first_inst && ex->is_Mach() && - ex->as_Mach()->ideal_Opcode() == Op_CreateEx ) { + for (uint insidx = first_inst; insidx < last_inst; insidx++) { + Node *ex = block->_nodes[insidx]; + if (ex->is_SpillCopy()) { + continue; + } + if (insidx > first_inst && ex->is_Mach() && ex->as_Mach()->ideal_Opcode() == Op_CreateEx) { // If the CreateEx isn't above all the MachSpillCopies // then move it to the top. - b->_nodes.remove(insidx); - b->_nodes.insert(first_inst, ex); + block->_nodes.remove(insidx); + block->_nodes.insert(first_inst, ex); } // Stop once a CreateEx or any other node is found break; @@ -503,12 +482,12 @@ uint PhaseChaitin::build_ifg_physical( ResourceArea *a ) { uint pressure[2], hrp_index[2]; pressure[0] = pressure[1] = 0; hrp_index[0] = hrp_index[1] = last_inst+1; - b->_reg_pressure = b->_freg_pressure = 0; + block->_reg_pressure = block->_freg_pressure = 0; // Liveout things are presumed live for the whole block. We accumulate // 'area' accordingly. If they get killed in the block, we'll subtract // the unused part of the block from the area. int inst_count = last_inst - first_inst; - double cost = (inst_count <= 0) ? 0.0 : b->_freq * double(inst_count); + double cost = (inst_count <= 0) ? 0.0 : block->_freq * double(inst_count); assert(!(cost < 0.0), "negative spill cost" ); IndexSetIterator elements(&liveout); uint lidx; @@ -519,13 +498,15 @@ uint PhaseChaitin::build_ifg_physical( ResourceArea *a ) { if (lrg.mask().is_UP() && lrg.mask_size()) { if (lrg._is_float || lrg._is_vector) { // Count float pressure pressure[1] += lrg.reg_pressure(); - if( pressure[1] > b->_freg_pressure ) - b->_freg_pressure = pressure[1]; + if (pressure[1] > block->_freg_pressure) { + block->_freg_pressure = pressure[1]; + } // Count int pressure, but do not count the SP, flags - } else if( lrgs(lidx).mask().overlap(*Matcher::idealreg2regmask[Op_RegI]) ) { + } else if(lrgs(lidx).mask().overlap(*Matcher::idealreg2regmask[Op_RegI])) { pressure[0] += lrg.reg_pressure(); - if( pressure[0] > b->_reg_pressure ) - b->_reg_pressure = pressure[0]; + if (pressure[0] > block->_reg_pressure) { + block->_reg_pressure = pressure[0]; + } } } } @@ -541,8 +522,8 @@ uint PhaseChaitin::build_ifg_physical( ResourceArea *a ) { // value is then removed from the live-ness set and it's inputs are added // to the live-ness set. uint j; - for( j = last_inst + 1; j > 1; j-- ) { - Node *n = b->_nodes[j - 1]; + for (j = last_inst + 1; j > 1; j--) { + Node* n = block->_nodes[j - 1]; // Get value being defined uint r = _lrg_map.live_range_id(n); @@ -551,7 +532,7 @@ uint PhaseChaitin::build_ifg_physical( ResourceArea *a ) { if(r) { // A DEF normally costs block frequency; rematerialized values are // removed from the DEF sight, so LOWER costs here. - lrgs(r)._cost += n->rematerialize() ? 0 : b->_freq; + lrgs(r)._cost += n->rematerialize() ? 0 : block->_freq; // If it is not live, then this instruction is dead. Probably caused // by spilling and rematerialization. Who cares why, yank this baby. @@ -560,7 +541,7 @@ uint PhaseChaitin::build_ifg_physical( ResourceArea *a ) { if( !n->is_Proj() || // Could also be a flags-projection of a dead ADD or such. (_lrg_map.live_range_id(def) && !liveout.member(_lrg_map.live_range_id(def)))) { - b->_nodes.remove(j - 1); + block->_nodes.remove(j - 1); if (lrgs(r)._def == n) { lrgs(r)._def = 0; } @@ -580,21 +561,21 @@ uint PhaseChaitin::build_ifg_physical( ResourceArea *a ) { RegMask itmp = lrgs(r).mask(); itmp.AND(*Matcher::idealreg2regmask[Op_RegI]); int iregs = itmp.Size(); - if( pressure[0]+iregs > b->_reg_pressure ) - b->_reg_pressure = pressure[0]+iregs; - if( pressure[0] <= (uint)INTPRESSURE && - pressure[0]+iregs > (uint)INTPRESSURE ) { - hrp_index[0] = j-1; + if (pressure[0]+iregs > block->_reg_pressure) { + block->_reg_pressure = pressure[0] + iregs; + } + if (pressure[0] <= (uint)INTPRESSURE && pressure[0] + iregs > (uint)INTPRESSURE) { + hrp_index[0] = j - 1; } // Count the float-only registers RegMask ftmp = lrgs(r).mask(); ftmp.AND(*Matcher::idealreg2regmask[Op_RegD]); int fregs = ftmp.Size(); - if( pressure[1]+fregs > b->_freg_pressure ) - b->_freg_pressure = pressure[1]+fregs; - if( pressure[1] <= (uint)FLOATPRESSURE && - pressure[1]+fregs > (uint)FLOATPRESSURE ) { - hrp_index[1] = j-1; + if (pressure[1] + fregs > block->_freg_pressure) { + block->_freg_pressure = pressure[1] + fregs; + } + if(pressure[1] <= (uint)FLOATPRESSURE && pressure[1]+fregs > (uint)FLOATPRESSURE) { + hrp_index[1] = j - 1; } } @@ -607,7 +588,7 @@ uint PhaseChaitin::build_ifg_physical( ResourceArea *a ) { if( n->is_SpillCopy() && lrgs(r).is_singledef() // MultiDef live range can still split && n->outcnt() == 1 // and use must be in this block - && _cfg.get_block_for_node(n->unique_out()) == b ) { + && _cfg.get_block_for_node(n->unique_out()) == block) { // All single-use MachSpillCopy(s) that immediately precede their // use must color early. If a longer live range steals their // color, the spill copy will split and may push another spill copy @@ -617,14 +598,16 @@ uint PhaseChaitin::build_ifg_physical( ResourceArea *a ) { // Node *single_use = n->unique_out(); - assert( b->find_node(single_use) >= j, "Use must be later in block"); + assert(block->find_node(single_use) >= j, "Use must be later in block"); // Use can be earlier in block if it is a Phi, but then I should be a MultiDef // Find first non SpillCopy 'm' that follows the current instruction // (j - 1) is index for current instruction 'n' Node *m = n; - for( uint i = j; i <= last_inst && m->is_SpillCopy(); ++i ) { m = b->_nodes[i]; } - if( m == single_use ) { + for (uint i = j; i <= last_inst && m->is_SpillCopy(); ++i) { + m = block->_nodes[i]; + } + if (m == single_use) { lrgs(r)._area = 0.0; } } @@ -633,7 +616,7 @@ uint PhaseChaitin::build_ifg_physical( ResourceArea *a ) { if( liveout.remove(r) ) { // Adjust register pressure. // Capture last hi-to-lo pressure transition - lower_pressure( &lrgs(r), j-1, b, pressure, hrp_index ); + lower_pressure(&lrgs(r), j - 1, block, pressure, hrp_index); assert( pressure[0] == count_int_pressure (&liveout), "" ); assert( pressure[1] == count_float_pressure(&liveout), "" ); } @@ -646,7 +629,7 @@ uint PhaseChaitin::build_ifg_physical( ResourceArea *a ) { if (liveout.remove(x)) { lrgs(x)._area -= cost; // Adjust register pressure. - lower_pressure(&lrgs(x), j-1, b, pressure, hrp_index); + lower_pressure(&lrgs(x), j - 1, block, pressure, hrp_index); assert( pressure[0] == count_int_pressure (&liveout), "" ); assert( pressure[1] == count_float_pressure(&liveout), "" ); } @@ -718,7 +701,7 @@ uint PhaseChaitin::build_ifg_physical( ResourceArea *a ) { // Area remaining in the block inst_count--; - cost = (inst_count <= 0) ? 0.0 : b->_freq * double(inst_count); + cost = (inst_count <= 0) ? 0.0 : block->_freq * double(inst_count); // Make all inputs live if( !n->is_Phi() ) { // Phi function uses come from prior block @@ -743,7 +726,7 @@ uint PhaseChaitin::build_ifg_physical( ResourceArea *a ) { if (k < debug_start) { // A USE costs twice block frequency (once for the Load, once // for a Load-delay). Rematerialized uses only cost once. - lrg._cost += (def->rematerialize() ? b->_freq : (b->_freq + b->_freq)); + lrg._cost += (def->rematerialize() ? block->_freq : (block->_freq + block->_freq)); } // It is live now if (liveout.insert(x)) { @@ -753,12 +736,14 @@ uint PhaseChaitin::build_ifg_physical( ResourceArea *a ) { if (lrg.mask().is_UP() && lrg.mask_size()) { if (lrg._is_float || lrg._is_vector) { pressure[1] += lrg.reg_pressure(); - if( pressure[1] > b->_freg_pressure ) - b->_freg_pressure = pressure[1]; + if (pressure[1] > block->_freg_pressure) { + block->_freg_pressure = pressure[1]; + } } else if( lrg.mask().overlap(*Matcher::idealreg2regmask[Op_RegI]) ) { pressure[0] += lrg.reg_pressure(); - if( pressure[0] > b->_reg_pressure ) - b->_reg_pressure = pressure[0]; + if (pressure[0] > block->_reg_pressure) { + block->_reg_pressure = pressure[0]; + } } } assert( pressure[0] == count_int_pressure (&liveout), "" ); @@ -772,44 +757,47 @@ uint PhaseChaitin::build_ifg_physical( ResourceArea *a ) { // If we run off the top of the block with high pressure and // never see a hi-to-low pressure transition, just record that // the whole block is high pressure. - if( pressure[0] > (uint)INTPRESSURE ) { + if (pressure[0] > (uint)INTPRESSURE) { hrp_index[0] = 0; - if( pressure[0] > b->_reg_pressure ) - b->_reg_pressure = pressure[0]; + if (pressure[0] > block->_reg_pressure) { + block->_reg_pressure = pressure[0]; + } } - if( pressure[1] > (uint)FLOATPRESSURE ) { + if (pressure[1] > (uint)FLOATPRESSURE) { hrp_index[1] = 0; - if( pressure[1] > b->_freg_pressure ) - b->_freg_pressure = pressure[1]; + if (pressure[1] > block->_freg_pressure) { + block->_freg_pressure = pressure[1]; + } } // Compute high pressure indice; avoid landing in the middle of projnodes j = hrp_index[0]; - if( j < b->_nodes.size() && j < b->end_idx()+1 ) { - Node *cur = b->_nodes[j]; - while( cur->is_Proj() || (cur->is_MachNullCheck()) || cur->is_Catch() ) { + if (j < block->_nodes.size() && j < block->end_idx() + 1) { + Node* cur = block->_nodes[j]; + while (cur->is_Proj() || (cur->is_MachNullCheck()) || cur->is_Catch()) { j--; - cur = b->_nodes[j]; + cur = block->_nodes[j]; } } - b->_ihrp_index = j; + block->_ihrp_index = j; j = hrp_index[1]; - if( j < b->_nodes.size() && j < b->end_idx()+1 ) { - Node *cur = b->_nodes[j]; - while( cur->is_Proj() || (cur->is_MachNullCheck()) || cur->is_Catch() ) { + if (j < block->_nodes.size() && j < block->end_idx() + 1) { + Node* cur = block->_nodes[j]; + while (cur->is_Proj() || (cur->is_MachNullCheck()) || cur->is_Catch()) { j--; - cur = b->_nodes[j]; + cur = block->_nodes[j]; } } - b->_fhrp_index = j; + block->_fhrp_index = j; #ifndef PRODUCT // Gather Register Pressure Statistics if( PrintOptoStatistics ) { - if( b->_reg_pressure > (uint)INTPRESSURE || b->_freg_pressure > (uint)FLOATPRESSURE ) + if (block->_reg_pressure > (uint)INTPRESSURE || block->_freg_pressure > (uint)FLOATPRESSURE) { _high_pressure++; - else + } else { _low_pressure++; + } } #endif } // End of for all blocks diff --git a/hotspot/src/share/vm/opto/lcm.cpp b/hotspot/src/share/vm/opto/lcm.cpp index fc05a79b416..8d9daa54b86 100644 --- a/hotspot/src/share/vm/opto/lcm.cpp +++ b/hotspot/src/share/vm/opto/lcm.cpp @@ -501,7 +501,7 @@ Node *Block::select(PhaseCFG *cfg, Node_List &worklist, GrowableArray &read n_choice = 1; } - uint n_latency = cfg->_node_latency->at_grow(n->_idx); + uint n_latency = cfg->get_latency_for_node(n); uint n_score = n->req(); // Many inputs get high score to break ties // Keep best latency found @@ -797,7 +797,7 @@ bool Block::schedule_local(PhaseCFG *cfg, Matcher &matcher, GrowableArray & Node *n = _nodes[j]; int idx = n->_idx; tty->print("# ready cnt:%3d ", ready_cnt.at(idx)); - tty->print("latency:%3d ", cfg->_node_latency->at_grow(idx)); + tty->print("latency:%3d ", cfg->get_latency_for_node(n)); tty->print("%4d: %s\n", idx, n->Name()); } } @@ -825,7 +825,7 @@ bool Block::schedule_local(PhaseCFG *cfg, Matcher &matcher, GrowableArray & #ifndef PRODUCT if (cfg->trace_opto_pipelining()) { tty->print("# select %d: %s", n->_idx, n->Name()); - tty->print(", latency:%d", cfg->_node_latency->at_grow(n->_idx)); + tty->print(", latency:%d", cfg->get_latency_for_node(n)); n->dump(); if (Verbose) { tty->print("# ready list:"); diff --git a/hotspot/src/share/vm/opto/live.cpp b/hotspot/src/share/vm/opto/live.cpp index 846609e8a49..ab7381b639d 100644 --- a/hotspot/src/share/vm/opto/live.cpp +++ b/hotspot/src/share/vm/opto/live.cpp @@ -30,9 +30,6 @@ #include "opto/machnode.hpp" - -//============================================================================= -//------------------------------PhaseLive-------------------------------------- // Compute live-in/live-out. We use a totally incremental algorithm. The LIVE // problem is monotonic. The steady-state solution looks like this: pull a // block from the worklist. It has a set of delta's - values which are newly @@ -53,9 +50,9 @@ void PhaseLive::compute(uint maxlrg) { // Init the sparse live arrays. This data is live on exit from here! // The _live info is the live-out info. - _live = (IndexSet*)_arena->Amalloc(sizeof(IndexSet)*_cfg._num_blocks); + _live = (IndexSet*)_arena->Amalloc(sizeof(IndexSet) * _cfg.number_of_blocks()); uint i; - for( i=0; i<_cfg._num_blocks; i++ ) { + for (i = 0; i < _cfg.number_of_blocks(); i++) { _live[i].initialize(_maxlrg); } @@ -65,14 +62,14 @@ void PhaseLive::compute(uint maxlrg) { // Does the memory used by _defs and _deltas get reclaimed? Does it matter? TT // Array of values defined locally in blocks - _defs = NEW_RESOURCE_ARRAY(IndexSet,_cfg._num_blocks); - for( i=0; i<_cfg._num_blocks; i++ ) { + _defs = NEW_RESOURCE_ARRAY(IndexSet,_cfg.number_of_blocks()); + for (i = 0; i < _cfg.number_of_blocks(); i++) { _defs[i].initialize(_maxlrg); } // Array of delta-set pointers, indexed by block pre_order-1. - _deltas = NEW_RESOURCE_ARRAY(IndexSet*,_cfg._num_blocks); - memset( _deltas, 0, sizeof(IndexSet*)* _cfg._num_blocks); + _deltas = NEW_RESOURCE_ARRAY(IndexSet*,_cfg.number_of_blocks()); + memset( _deltas, 0, sizeof(IndexSet*)* _cfg.number_of_blocks()); _free_IndexSet = NULL; @@ -80,31 +77,32 @@ void PhaseLive::compute(uint maxlrg) { VectorSet first_pass(Thread::current()->resource_area()); // Outer loop: must compute local live-in sets and push into predecessors. - uint iters = _cfg._num_blocks; // stat counters - for( uint j=_cfg._num_blocks; j>0; j-- ) { - Block *b = _cfg._blocks[j-1]; + for (uint j = _cfg.number_of_blocks(); j > 0; j--) { + Block* block = _cfg.get_block(j - 1); // Compute the local live-in set. Start with any new live-out bits. - IndexSet *use = getset( b ); - IndexSet *def = &_defs[b->_pre_order-1]; + IndexSet* use = getset(block); + IndexSet* def = &_defs[block->_pre_order-1]; DEBUG_ONLY(IndexSet *def_outside = getfreeset();) uint i; - for( i=b->_nodes.size(); i>1; i-- ) { - Node *n = b->_nodes[i-1]; - if( n->is_Phi() ) break; + for (i = block->_nodes.size(); i > 1; i--) { + Node* n = block->_nodes[i-1]; + if (n->is_Phi()) { + break; + } uint r = _names[n->_idx]; assert(!def_outside->member(r), "Use of external LRG overlaps the same LRG defined in this block"); def->insert( r ); use->remove( r ); uint cnt = n->req(); - for( uint k=1; kin(k); uint nkidx = nk->_idx; - if (_cfg.get_block_for_node(nk) != b) { + if (_cfg.get_block_for_node(nk) != block) { uint u = _names[nkidx]; - use->insert( u ); - DEBUG_ONLY(def_outside->insert( u );) + use->insert(u); + DEBUG_ONLY(def_outside->insert(u);) } } } @@ -113,41 +111,38 @@ void PhaseLive::compute(uint maxlrg) { _free_IndexSet = def_outside; // Drop onto free list #endif // Remove anything defined by Phis and the block start instruction - for( uint k=i; k>0; k-- ) { - uint r = _names[b->_nodes[k-1]->_idx]; - def->insert( r ); - use->remove( r ); + for (uint k = i; k > 0; k--) { + uint r = _names[block->_nodes[k - 1]->_idx]; + def->insert(r); + use->remove(r); } // Push these live-in things to predecessors - for( uint l=1; lnum_preds(); l++ ) { - Block *p = _cfg.get_block_for_node(b->pred(l)); - add_liveout( p, use, first_pass ); + for (uint l = 1; l < block->num_preds(); l++) { + Block* p = _cfg.get_block_for_node(block->pred(l)); + add_liveout(p, use, first_pass); // PhiNode uses go in the live-out set of prior blocks. - for( uint k=i; k>0; k-- ) - add_liveout( p, _names[b->_nodes[k-1]->in(l)->_idx], first_pass ); + for (uint k = i; k > 0; k--) { + add_liveout(p, _names[block->_nodes[k-1]->in(l)->_idx], first_pass); + } } - freeset( b ); - first_pass.set(b->_pre_order); + freeset(block); + first_pass.set(block->_pre_order); // Inner loop: blocks that picked up new live-out values to be propagated - while( _worklist->size() ) { - // !!!!! -// #ifdef ASSERT - iters++; -// #endif - Block *b = _worklist->pop(); - IndexSet *delta = getset(b); + while (_worklist->size()) { + Block* block = _worklist->pop(); + IndexSet *delta = getset(block); assert( delta->count(), "missing delta set" ); // Add new-live-in to predecessors live-out sets - for (uint l = 1; l < b->num_preds(); l++) { - Block* block = _cfg.get_block_for_node(b->pred(l)); - add_liveout(block, delta, first_pass); + for (uint l = 1; l < block->num_preds(); l++) { + Block* predecessor = _cfg.get_block_for_node(block->pred(l)); + add_liveout(predecessor, delta, first_pass); } - freeset(b); + freeset(block); } // End of while-worklist-not-empty } // End of for-all-blocks-outer-loop @@ -155,7 +150,7 @@ void PhaseLive::compute(uint maxlrg) { // We explicitly clear all of the IndexSets which we are about to release. // This allows us to recycle their internal memory into IndexSet's free list. - for( i=0; i<_cfg._num_blocks; i++ ) { + for (i = 0; i < _cfg.number_of_blocks(); i++) { _defs[i].clear(); if (_deltas[i]) { // Is this always true? @@ -171,13 +166,11 @@ void PhaseLive::compute(uint maxlrg) { } -//------------------------------stats------------------------------------------ #ifndef PRODUCT void PhaseLive::stats(uint iters) const { } #endif -//------------------------------getset----------------------------------------- // Get an IndexSet for a block. Return existing one, if any. Make a new // empty one if a prior one does not exist. IndexSet *PhaseLive::getset( Block *p ) { @@ -188,7 +181,6 @@ IndexSet *PhaseLive::getset( Block *p ) { return delta; // Return set of new live-out items } -//------------------------------getfreeset------------------------------------- // Pull from free list, or allocate. Internal allocation on the returned set // is always from thread local storage. IndexSet *PhaseLive::getfreeset( ) { @@ -207,7 +199,6 @@ IndexSet *PhaseLive::getfreeset( ) { return f; } -//------------------------------freeset---------------------------------------- // Free an IndexSet from a block. void PhaseLive::freeset( const Block *p ) { IndexSet *f = _deltas[p->_pre_order-1]; @@ -216,7 +207,6 @@ void PhaseLive::freeset( const Block *p ) { _deltas[p->_pre_order-1] = NULL; } -//------------------------------add_liveout------------------------------------ // Add a live-out value to a given blocks live-out set. If it is new, then // also add it to the delta set and stick the block on the worklist. void PhaseLive::add_liveout( Block *p, uint r, VectorSet &first_pass ) { @@ -233,8 +223,6 @@ void PhaseLive::add_liveout( Block *p, uint r, VectorSet &first_pass ) { } } - -//------------------------------add_liveout------------------------------------ // Add a vector of live-out values to a given blocks live-out set. void PhaseLive::add_liveout( Block *p, IndexSet *lo, VectorSet &first_pass ) { IndexSet *live = &_live[p->_pre_order-1]; @@ -262,7 +250,6 @@ void PhaseLive::add_liveout( Block *p, IndexSet *lo, VectorSet &first_pass ) { } #ifndef PRODUCT -//------------------------------dump------------------------------------------- // Dump the live-out set for a block void PhaseLive::dump( const Block *b ) const { tty->print("Block %d: ",b->_pre_order); @@ -275,18 +262,19 @@ void PhaseLive::dump( const Block *b ) const { tty->print("\n"); } -//------------------------------verify_base_ptrs------------------------------- // Verify that base pointers and derived pointers are still sane. void PhaseChaitin::verify_base_ptrs( ResourceArea *a ) const { #ifdef ASSERT Unique_Node_List worklist(a); - for( uint i = 0; i < _cfg._num_blocks; i++ ) { - Block *b = _cfg._blocks[i]; - for( uint j = b->end_idx() + 1; j > 1; j-- ) { - Node *n = b->_nodes[j-1]; - if( n->is_Phi() ) break; + for (uint i = 0; i < _cfg.number_of_blocks(); i++) { + Block* block = _cfg.get_block(i); + for (uint j = block->end_idx() + 1; j > 1; j--) { + Node* n = block->_nodes[j-1]; + if (n->is_Phi()) { + break; + } // Found a safepoint? - if( n->is_MachSafePoint() ) { + if (n->is_MachSafePoint()) { MachSafePointNode *sfpt = n->as_MachSafePoint(); JVMState* jvms = sfpt->jvms(); if (jvms != NULL) { @@ -358,7 +346,6 @@ void PhaseChaitin::verify_base_ptrs( ResourceArea *a ) const { #endif } -//------------------------------verify------------------------------------- // Verify that graphs and base pointers are still sane. void PhaseChaitin::verify( ResourceArea *a, bool verify_ifg ) const { #ifdef ASSERT diff --git a/hotspot/src/share/vm/opto/matcher.cpp b/hotspot/src/share/vm/opto/matcher.cpp index 962c3c12894..ae27f6ffa21 100644 --- a/hotspot/src/share/vm/opto/matcher.cpp +++ b/hotspot/src/share/vm/opto/matcher.cpp @@ -67,8 +67,8 @@ const uint Matcher::_begin_rematerialize = _BEGIN_REMATERIALIZE; const uint Matcher::_end_rematerialize = _END_REMATERIALIZE; //---------------------------Matcher------------------------------------------- -Matcher::Matcher( Node_List &proj_list ) : - PhaseTransform( Phase::Ins_Select ), +Matcher::Matcher() +: PhaseTransform( Phase::Ins_Select ), #ifdef ASSERT _old2new_map(C->comp_arena()), _new2old_map(C->comp_arena()), @@ -78,7 +78,7 @@ Matcher::Matcher( Node_List &proj_list ) : _swallowed(swallowed), _begin_inst_chain_rule(_BEGIN_INST_CHAIN_RULE), _end_inst_chain_rule(_END_INST_CHAIN_RULE), - _must_clone(must_clone), _proj_list(proj_list), + _must_clone(must_clone), _register_save_policy(register_save_policy), _c_reg_save_policy(c_reg_save_policy), _register_save_type(register_save_type), @@ -1304,8 +1304,9 @@ MachNode *Matcher::match_sfpt( SafePointNode *sfpt ) { for (int i = begin_out_arg_area; i < out_arg_limit_per_call; i++) proj->_rout.Insert(OptoReg::Name(i)); } - if( proj->_rout.is_NotEmpty() ) - _proj_list.push(proj); + if (proj->_rout.is_NotEmpty()) { + push_projection(proj); + } } // Transfer the safepoint information from the call to the mcall // Move the JVMState list @@ -1685,14 +1686,15 @@ MachNode *Matcher::ReduceInst( State *s, int rule, Node *&mem ) { } // If the _leaf is an AddP, insert the base edge - if( leaf->is_AddP() ) + if (leaf->is_AddP()) { mach->ins_req(AddPNode::Base,leaf->in(AddPNode::Base)); + } - uint num_proj = _proj_list.size(); + uint number_of_projections_prior = number_of_projections(); // Perform any 1-to-many expansions required - MachNode *ex = mach->Expand(s,_proj_list, mem); - if( ex != mach ) { + MachNode *ex = mach->Expand(s, _projection_list, mem); + if (ex != mach) { assert(ex->ideal_reg() == mach->ideal_reg(), "ideal types should match"); if( ex->in(1)->is_Con() ) ex->in(1)->set_req(0, C->root()); @@ -1713,7 +1715,7 @@ MachNode *Matcher::ReduceInst( State *s, int rule, Node *&mem ) { // generated belatedly during spill code generation. if (_allocation_started) { guarantee(ex == mach, "no expand rules during spill generation"); - guarantee(_proj_list.size() == num_proj, "no allocation during spill generation"); + guarantee(number_of_projections_prior == number_of_projections(), "no allocation during spill generation"); } if (leaf->is_Con() || leaf->is_DecodeNarrowPtr()) { diff --git a/hotspot/src/share/vm/opto/matcher.hpp b/hotspot/src/share/vm/opto/matcher.hpp index 280b8ad8865..8435b0f997b 100644 --- a/hotspot/src/share/vm/opto/matcher.hpp +++ b/hotspot/src/share/vm/opto/matcher.hpp @@ -88,7 +88,7 @@ class Matcher : public PhaseTransform { Node *transform( Node *dummy ); - Node_List &_proj_list; // For Machine nodes killing many values + Node_List _projection_list; // For Machine nodes killing many values Node_Array _shared_nodes; @@ -183,10 +183,30 @@ public: void collect_null_checks( Node *proj, Node *orig_proj ); void validate_null_checks( ); - Matcher( Node_List &proj_list ); + Matcher(); + + // Get a projection node at position pos + Node* get_projection(uint pos) { + return _projection_list[pos]; + } + + // Push a projection node onto the projection list + void push_projection(Node* node) { + _projection_list.push(node); + } + + Node* pop_projection() { + return _projection_list.pop(); + } + + // Number of nodes in the projection list + uint number_of_projections() const { + return _projection_list.size(); + } // Select instructions for entire method - void match( ); + void match(); + // Helper for match OptoReg::Name warp_incoming_stk_arg( VMReg reg ); diff --git a/hotspot/src/share/vm/opto/output.cpp b/hotspot/src/share/vm/opto/output.cpp index 24a4497c680..8a06acdc983 100644 --- a/hotspot/src/share/vm/opto/output.cpp +++ b/hotspot/src/share/vm/opto/output.cpp @@ -54,11 +54,10 @@ extern uint size_deopt_handler(); extern int emit_exception_handler(CodeBuffer &cbuf); extern int emit_deopt_handler(CodeBuffer &cbuf); -//------------------------------Output----------------------------------------- // Convert Nodes to instruction bits and pass off to the VM void Compile::Output() { // RootNode goes - assert( _cfg->_broot->_nodes.size() == 0, "" ); + assert( _cfg->get_root_block()->_nodes.size() == 0, "" ); // The number of new nodes (mostly MachNop) is proportional to // the number of java calls and inner loops which are aligned. @@ -68,8 +67,8 @@ void Compile::Output() { return; } // Make sure I can find the Start Node - Block *entry = _cfg->_blocks[1]; - Block *broot = _cfg->_broot; + Block *entry = _cfg->get_block(1); + Block *broot = _cfg->get_root_block(); const StartNode *start = entry->_nodes[0]->as_Start(); @@ -109,40 +108,44 @@ void Compile::Output() { } // Insert epilogs before every return - for( uint i=0; i<_cfg->_num_blocks; i++ ) { - Block *b = _cfg->_blocks[i]; - if( !b->is_connector() && b->non_connector_successor(0) == _cfg->_broot ) { // Found a program exit point? - Node *m = b->end(); - if( m->is_Mach() && m->as_Mach()->ideal_Opcode() != Op_Halt ) { - MachEpilogNode *epilog = new (this) MachEpilogNode(m->as_Mach()->ideal_Opcode() == Op_Return); - b->add_inst( epilog ); - _cfg->map_node_to_block(epilog, b); + for (uint i = 0; i < _cfg->number_of_blocks(); i++) { + Block* block = _cfg->get_block(i); + if (!block->is_connector() && block->non_connector_successor(0) == _cfg->get_root_block()) { // Found a program exit point? + Node* m = block->end(); + if (m->is_Mach() && m->as_Mach()->ideal_Opcode() != Op_Halt) { + MachEpilogNode* epilog = new (this) MachEpilogNode(m->as_Mach()->ideal_Opcode() == Op_Return); + block->add_inst(epilog); + _cfg->map_node_to_block(epilog, block); } } } # ifdef ENABLE_ZAP_DEAD_LOCALS - if ( ZapDeadCompiledLocals ) Insert_zap_nodes(); + if (ZapDeadCompiledLocals) { + Insert_zap_nodes(); + } # endif - uint* blk_starts = NEW_RESOURCE_ARRAY(uint,_cfg->_num_blocks+1); - blk_starts[0] = 0; + uint* blk_starts = NEW_RESOURCE_ARRAY(uint, _cfg->number_of_blocks() + 1); + blk_starts[0] = 0; // Initialize code buffer and process short branches. CodeBuffer* cb = init_buffer(blk_starts); - if (cb == NULL || failing()) return; + if (cb == NULL || failing()) { + return; + } ScheduleAndBundle(); #ifndef PRODUCT if (trace_opto_output()) { tty->print("\n---- After ScheduleAndBundle ----\n"); - for (uint i = 0; i < _cfg->_num_blocks; i++) { + for (uint i = 0; i < _cfg->number_of_blocks(); i++) { tty->print("\nBB#%03d:\n", i); - Block *bb = _cfg->_blocks[i]; - for (uint j = 0; j < bb->_nodes.size(); j++) { - Node *n = bb->_nodes[j]; + Block* block = _cfg->get_block(i); + for (uint j = 0; j < block->_nodes.size(); j++) { + Node* n = block->_nodes[j]; OptoReg::Name reg = _regalloc->get_reg_first(n); tty->print(" %-6s ", reg >= 0 && reg < REG_COUNT ? Matcher::regName[reg] : ""); n->dump(); @@ -151,11 +154,15 @@ void Compile::Output() { } #endif - if (failing()) return; + if (failing()) { + return; + } BuildOopMaps(); - if (failing()) return; + if (failing()) { + return; + } fill_buffer(cb, blk_starts); } @@ -217,8 +224,8 @@ void Compile::Insert_zap_nodes() { return; // no safepoints/oopmaps emitted for calls in stubs,so we don't care // Insert call to zap runtime stub before every node with an oop map - for( uint i=0; i<_cfg->_num_blocks; i++ ) { - Block *b = _cfg->_blocks[i]; + for( uint i=0; i<_cfg->number_of_blocks(); i++ ) { + Block *b = _cfg->get_block(i); for ( uint j = 0; j < b->_nodes.size(); ++j ) { Node *n = b->_nodes[j]; @@ -275,7 +282,6 @@ Node* Compile::call_zap_node(MachSafePointNode* node_to_check, int block_no) { return _matcher->match_sfpt(ideal_node); } -//------------------------------is_node_getting_a_safepoint-------------------- bool Compile::is_node_getting_a_safepoint( Node* n) { // This code duplicates the logic prior to the call of add_safepoint // below in this file. @@ -285,7 +291,6 @@ bool Compile::is_node_getting_a_safepoint( Node* n) { # endif // ENABLE_ZAP_DEAD_LOCALS -//------------------------------compute_loop_first_inst_sizes------------------ // Compute the size of first NumberOfLoopInstrToAlign instructions at the top // of a loop. When aligning a loop we need to provide enough instructions // in cpu's fetch buffer to feed decoders. The loop alignment could be @@ -302,42 +307,39 @@ void Compile::compute_loop_first_inst_sizes() { // or alignment padding is larger then MaxLoopPad. By default, MaxLoopPad // is equal to OptoLoopAlignment-1 except on new Intel cpus, where it is // equal to 11 bytes which is the largest address NOP instruction. - if( MaxLoopPad < OptoLoopAlignment-1 ) { - uint last_block = _cfg->_num_blocks-1; - for( uint i=1; i <= last_block; i++ ) { - Block *b = _cfg->_blocks[i]; + if (MaxLoopPad < OptoLoopAlignment - 1) { + uint last_block = _cfg->number_of_blocks() - 1; + for (uint i = 1; i <= last_block; i++) { + Block* block = _cfg->get_block(i); // Check the first loop's block which requires an alignment. - if( b->loop_alignment() > (uint)relocInfo::addr_unit() ) { + if (block->loop_alignment() > (uint)relocInfo::addr_unit()) { uint sum_size = 0; uint inst_cnt = NumberOfLoopInstrToAlign; - inst_cnt = b->compute_first_inst_size(sum_size, inst_cnt, _regalloc); + inst_cnt = block->compute_first_inst_size(sum_size, inst_cnt, _regalloc); // Check subsequent fallthrough blocks if the loop's first // block(s) does not have enough instructions. - Block *nb = b; - while( inst_cnt > 0 && - i < last_block && - !_cfg->_blocks[i+1]->has_loop_alignment() && - !nb->has_successor(b) ) { + Block *nb = block; + while(inst_cnt > 0 && + i < last_block && + !_cfg->get_block(i + 1)->has_loop_alignment() && + !nb->has_successor(block)) { i++; - nb = _cfg->_blocks[i]; + nb = _cfg->get_block(i); inst_cnt = nb->compute_first_inst_size(sum_size, inst_cnt, _regalloc); } // while( inst_cnt > 0 && i < last_block ) - b->set_first_inst_size(sum_size); + block->set_first_inst_size(sum_size); } // f( b->head()->is_Loop() ) } // for( i <= last_block ) } // if( MaxLoopPad < OptoLoopAlignment-1 ) } -//----------------------shorten_branches--------------------------------------- // The architecture description provides short branch variants for some long // branch instructions. Replace eligible long branches with short branches. void Compile::shorten_branches(uint* blk_starts, int& code_size, int& reloc_size, int& stub_size) { - - // ------------------ // Compute size of each block, method size, and relocation information size - uint nblocks = _cfg->_num_blocks; + uint nblocks = _cfg->number_of_blocks(); uint* jmp_offset = NEW_RESOURCE_ARRAY(uint,nblocks); uint* jmp_size = NEW_RESOURCE_ARRAY(uint,nblocks); @@ -364,7 +366,7 @@ void Compile::shorten_branches(uint* blk_starts, int& code_size, int& reloc_size uint last_avoid_back_to_back_adr = max_uint; uint nop_size = (new (this) MachNopNode())->size(_regalloc); for (uint i = 0; i < nblocks; i++) { // For all blocks - Block *b = _cfg->_blocks[i]; + Block* block = _cfg->get_block(i); // During short branch replacement, we store the relative (to blk_starts) // offset of jump in jmp_offset, rather than the absolute offset of jump. @@ -377,10 +379,10 @@ void Compile::shorten_branches(uint* blk_starts, int& code_size, int& reloc_size DEBUG_ONLY( jmp_rule[i] = 0; ) // Sum all instruction sizes to compute block size - uint last_inst = b->_nodes.size(); + uint last_inst = block->_nodes.size(); uint blk_size = 0; for (uint j = 0; j < last_inst; j++) { - Node* nj = b->_nodes[j]; + Node* nj = block->_nodes[j]; // Handle machine instruction nodes if (nj->is_Mach()) { MachNode *mach = nj->as_Mach(); @@ -441,8 +443,8 @@ void Compile::shorten_branches(uint* blk_starts, int& code_size, int& reloc_size // When the next block starts a loop, we may insert pad NOP // instructions. Since we cannot know our future alignment, // assume the worst. - if (i< nblocks-1) { - Block *nb = _cfg->_blocks[i+1]; + if (i < nblocks - 1) { + Block* nb = _cfg->get_block(i + 1); int max_loop_pad = nb->code_alignment()-relocInfo::addr_unit(); if (max_loop_pad > 0) { assert(is_power_of_2(max_loop_pad+relocInfo::addr_unit()), ""); @@ -473,26 +475,26 @@ void Compile::shorten_branches(uint* blk_starts, int& code_size, int& reloc_size has_short_branch_candidate = false; int adjust_block_start = 0; for (uint i = 0; i < nblocks; i++) { - Block *b = _cfg->_blocks[i]; + Block* block = _cfg->get_block(i); int idx = jmp_nidx[i]; - MachNode* mach = (idx == -1) ? NULL: b->_nodes[idx]->as_Mach(); + MachNode* mach = (idx == -1) ? NULL: block->_nodes[idx]->as_Mach(); if (mach != NULL && mach->may_be_short_branch()) { #ifdef ASSERT assert(jmp_size[i] > 0 && mach->is_MachBranch(), "sanity"); int j; // Find the branch; ignore trailing NOPs. - for (j = b->_nodes.size()-1; j>=0; j--) { - Node* n = b->_nodes[j]; + for (j = block->_nodes.size()-1; j>=0; j--) { + Node* n = block->_nodes[j]; if (!n->is_Mach() || n->as_Mach()->ideal_Opcode() != Op_Con) break; } - assert(j >= 0 && j == idx && b->_nodes[j] == (Node*)mach, "sanity"); + assert(j >= 0 && j == idx && block->_nodes[j] == (Node*)mach, "sanity"); #endif int br_size = jmp_size[i]; int br_offs = blk_starts[i] + jmp_offset[i]; // This requires the TRUE branch target be in succs[0] - uint bnum = b->non_connector_successor(0)->_pre_order; + uint bnum = block->non_connector_successor(0)->_pre_order; int offset = blk_starts[bnum] - br_offs; if (bnum > i) { // adjust following block's offset offset -= adjust_block_start; @@ -520,7 +522,7 @@ void Compile::shorten_branches(uint* blk_starts, int& code_size, int& reloc_size diff -= nop_size; } adjust_block_start += diff; - b->_nodes.map(idx, replacement); + block->_nodes.map(idx, replacement); mach->subsume_by(replacement, C); mach = replacement; progress = true; @@ -1083,8 +1085,8 @@ CodeBuffer* Compile::init_buffer(uint* blk_starts) { if (has_mach_constant_base_node()) { // Fill the constant table. // Note: This must happen before shorten_branches. - for (uint i = 0; i < _cfg->_num_blocks; i++) { - Block* b = _cfg->_blocks[i]; + for (uint i = 0; i < _cfg->number_of_blocks(); i++) { + Block* b = _cfg->get_block(i); for (uint j = 0; j < b->_nodes.size(); j++) { Node* n = b->_nodes[j]; @@ -1170,7 +1172,7 @@ void Compile::fill_buffer(CodeBuffer* cb, uint* blk_starts) { // !!!!! This preserves old handling of oopmaps for now debug_info()->set_oopmaps(_oop_map_set); - uint nblocks = _cfg->_num_blocks; + uint nblocks = _cfg->number_of_blocks(); // Count and start of implicit null check instructions uint inct_cnt = 0; uint *inct_starts = NEW_RESOURCE_ARRAY(uint, nblocks+1); @@ -1218,21 +1220,21 @@ void Compile::fill_buffer(CodeBuffer* cb, uint* blk_starts) { // Now fill in the code buffer Node *delay_slot = NULL; - for (uint i=0; i < nblocks; i++) { - Block *b = _cfg->_blocks[i]; - - Node *head = b->head(); + for (uint i = 0; i < nblocks; i++) { + Block* block = _cfg->get_block(i); + Node* head = block->head(); // If this block needs to start aligned (i.e, can be reached other // than by falling-thru from the previous block), then force the // start of a new bundle. - if (Pipeline::requires_bundling() && starts_bundle(head)) + if (Pipeline::requires_bundling() && starts_bundle(head)) { cb->flush_bundle(true); + } #ifdef ASSERT - if (!b->is_connector()) { + if (!block->is_connector()) { stringStream st; - b->dump_head(_cfg, &st); + block->dump_head(_cfg, &st); MacroAssembler(cb).block_comment(st.as_string()); } jmp_target[i] = 0; @@ -1243,16 +1245,16 @@ void Compile::fill_buffer(CodeBuffer* cb, uint* blk_starts) { int blk_offset = current_offset; // Define the label at the beginning of the basic block - MacroAssembler(cb).bind(blk_labels[b->_pre_order]); + MacroAssembler(cb).bind(blk_labels[block->_pre_order]); - uint last_inst = b->_nodes.size(); + uint last_inst = block->_nodes.size(); // Emit block normally, except for last instruction. // Emit means "dump code bits into code buffer". for (uint j = 0; j_nodes[j]; + Node* n = block->_nodes[j]; // See if delay slots are supported if (valid_bundle_info(n) && @@ -1306,9 +1308,9 @@ void Compile::fill_buffer(CodeBuffer* cb, uint* blk_starts) { assert((padding % nop_size) == 0, "padding is not a multiple of NOP size"); int nops_cnt = padding / nop_size; MachNode *nop = new (this) MachNopNode(nops_cnt); - b->_nodes.insert(j++, nop); + block->_nodes.insert(j++, nop); last_inst++; - _cfg->map_node_to_block(nop, b); + _cfg->map_node_to_block(nop, block); nop->emit(*cb, _regalloc); cb->flush_bundle(true); current_offset = cb->insts_size(); @@ -1322,7 +1324,7 @@ void Compile::fill_buffer(CodeBuffer* cb, uint* blk_starts) { mcall->method_set((intptr_t)mcall->entry_point()); // Save the return address - call_returns[b->_pre_order] = current_offset + mcall->ret_addr_offset(); + call_returns[block->_pre_order] = current_offset + mcall->ret_addr_offset(); if (mcall->is_MachCallLeaf()) { is_mcall = false; @@ -1359,7 +1361,7 @@ void Compile::fill_buffer(CodeBuffer* cb, uint* blk_starts) { // If this is a branch, then fill in the label with the target BB's label else if (mach->is_MachBranch()) { // This requires the TRUE branch target be in succs[0] - uint block_num = b->non_connector_successor(0)->_pre_order; + uint block_num = block->non_connector_successor(0)->_pre_order; // Try to replace long branch if delay slot is not used, // it is mostly for back branches since forward branch's @@ -1392,8 +1394,8 @@ void Compile::fill_buffer(CodeBuffer* cb, uint* blk_starts) { // Insert padding between avoid_back_to_back branches. if (needs_padding && replacement->avoid_back_to_back()) { MachNode *nop = new (this) MachNopNode(); - b->_nodes.insert(j++, nop); - _cfg->map_node_to_block(nop, b); + block->_nodes.insert(j++, nop); + _cfg->map_node_to_block(nop, block); last_inst++; nop->emit(*cb, _regalloc); cb->flush_bundle(true); @@ -1405,7 +1407,7 @@ void Compile::fill_buffer(CodeBuffer* cb, uint* blk_starts) { jmp_size[i] = new_size; jmp_rule[i] = mach->rule(); #endif - b->_nodes.map(j, replacement); + block->_nodes.map(j, replacement); mach->subsume_by(replacement, C); n = replacement; mach = replacement; @@ -1413,8 +1415,8 @@ void Compile::fill_buffer(CodeBuffer* cb, uint* blk_starts) { } mach->as_MachBranch()->label_set( &blk_labels[block_num], block_num ); } else if (mach->ideal_Opcode() == Op_Jump) { - for (uint h = 0; h < b->_num_succs; h++) { - Block* succs_block = b->_succs[h]; + for (uint h = 0; h < block->_num_succs; h++) { + Block* succs_block = block->_succs[h]; for (uint j = 1; j < succs_block->num_preds(); j++) { Node* jpn = succs_block->pred(j); if (jpn->is_JumpProj() && jpn->in(0) == mach) { @@ -1425,7 +1427,6 @@ void Compile::fill_buffer(CodeBuffer* cb, uint* blk_starts) { } } } - #ifdef ASSERT // Check that oop-store precedes the card-mark else if (mach->ideal_Opcode() == Op_StoreCM) { @@ -1436,17 +1437,18 @@ void Compile::fill_buffer(CodeBuffer* cb, uint* blk_starts) { if (oop_store == NULL) continue; count++; uint i4; - for( i4 = 0; i4 < last_inst; ++i4 ) { - if( b->_nodes[i4] == oop_store ) break; + for (i4 = 0; i4 < last_inst; ++i4) { + if (block->_nodes[i4] == oop_store) { + break; + } } // Note: This test can provide a false failure if other precedence // edges have been added to the storeCMNode. - assert( i4 == last_inst || i4 < storeCM_idx, "CM card-mark executes before oop-store"); + assert(i4 == last_inst || i4 < storeCM_idx, "CM card-mark executes before oop-store"); } assert(count > 0, "storeCM expects at least one precedence edge"); } #endif - else if (!n->is_Proj()) { // Remember the beginning of the previous instruction, in case // it's followed by a flag-kill and a null-check. Happens on @@ -1542,12 +1544,12 @@ void Compile::fill_buffer(CodeBuffer* cb, uint* blk_starts) { // If the next block is the top of a loop, pad this block out to align // the loop top a little. Helps prevent pipe stalls at loop back branches. if (i < nblocks-1) { - Block *nb = _cfg->_blocks[i+1]; + Block *nb = _cfg->get_block(i + 1); int padding = nb->alignment_padding(current_offset); if( padding > 0 ) { MachNode *nop = new (this) MachNopNode(padding / nop_size); - b->_nodes.insert( b->_nodes.size(), nop ); - _cfg->map_node_to_block(nop, b); + block->_nodes.insert(block->_nodes.size(), nop); + _cfg->map_node_to_block(nop, block); nop->emit(*cb, _regalloc); current_offset = cb->insts_size(); } @@ -1587,8 +1589,6 @@ void Compile::fill_buffer(CodeBuffer* cb, uint* blk_starts) { } #endif - // ------------------ - #ifndef PRODUCT // Information on the size of the method, without the extraneous code Scheduling::increment_method_size(cb->insts_size()); @@ -1649,52 +1649,55 @@ void Compile::FillExceptionTables(uint cnt, uint *call_returns, uint *inct_start _inc_table.set_size(cnt); uint inct_cnt = 0; - for( uint i=0; i<_cfg->_num_blocks; i++ ) { - Block *b = _cfg->_blocks[i]; + for (uint i = 0; i < _cfg->number_of_blocks(); i++) { + Block* block = _cfg->get_block(i); Node *n = NULL; int j; // Find the branch; ignore trailing NOPs. - for( j = b->_nodes.size()-1; j>=0; j-- ) { - n = b->_nodes[j]; - if( !n->is_Mach() || n->as_Mach()->ideal_Opcode() != Op_Con ) + for (j = block->_nodes.size() - 1; j >= 0; j--) { + n = block->_nodes[j]; + if (!n->is_Mach() || n->as_Mach()->ideal_Opcode() != Op_Con) { break; + } } // If we didn't find anything, continue - if( j < 0 ) continue; + if (j < 0) { + continue; + } // Compute ExceptionHandlerTable subtable entry and add it // (skip empty blocks) - if( n->is_Catch() ) { + if (n->is_Catch()) { // Get the offset of the return from the call - uint call_return = call_returns[b->_pre_order]; + uint call_return = call_returns[block->_pre_order]; #ifdef ASSERT assert( call_return > 0, "no call seen for this basic block" ); - while( b->_nodes[--j]->is_MachProj() ) ; - assert( b->_nodes[j]->is_MachCall(), "CatchProj must follow call" ); + while (block->_nodes[--j]->is_MachProj()) ; + assert(block->_nodes[j]->is_MachCall(), "CatchProj must follow call"); #endif // last instruction is a CatchNode, find it's CatchProjNodes - int nof_succs = b->_num_succs; + int nof_succs = block->_num_succs; // allocate space GrowableArray handler_bcis(nof_succs); GrowableArray handler_pcos(nof_succs); // iterate through all successors for (int j = 0; j < nof_succs; j++) { - Block* s = b->_succs[j]; + Block* s = block->_succs[j]; bool found_p = false; - for( uint k = 1; k < s->num_preds(); k++ ) { - Node *pk = s->pred(k); - if( pk->is_CatchProj() && pk->in(0) == n ) { + for (uint k = 1; k < s->num_preds(); k++) { + Node* pk = s->pred(k); + if (pk->is_CatchProj() && pk->in(0) == n) { const CatchProjNode* p = pk->as_CatchProj(); found_p = true; // add the corresponding handler bci & pco information - if( p->_con != CatchProjNode::fall_through_index ) { + if (p->_con != CatchProjNode::fall_through_index) { // p leads to an exception handler (and is not fall through) - assert(s == _cfg->_blocks[s->_pre_order],"bad numbering"); + assert(s == _cfg->get_block(s->_pre_order), "bad numbering"); // no duplicates, please - if( !handler_bcis.contains(p->handler_bci()) ) { + if (!handler_bcis.contains(p->handler_bci())) { uint block_num = s->non_connector()->_pre_order; handler_bcis.append(p->handler_bci()); handler_pcos.append(blk_labels[block_num].loc_pos()); @@ -1713,9 +1716,9 @@ void Compile::FillExceptionTables(uint cnt, uint *call_returns, uint *inct_start } // Handle implicit null exception table updates - if( n->is_MachNullCheck() ) { - uint block_num = b->non_connector_successor(0)->_pre_order; - _inc_table.append( inct_starts[inct_cnt++], blk_labels[block_num].loc_pos() ); + if (n->is_MachNullCheck()) { + uint block_num = block->non_connector_successor(0)->_pre_order; + _inc_table.append(inct_starts[inct_cnt++], blk_labels[block_num].loc_pos()); continue; } } // End of for all blocks fill in exception table entries @@ -1774,14 +1777,12 @@ Scheduling::Scheduling(Arena *arena, Compile &compile) memset(_current_latency, 0, node_max * sizeof(unsigned short)); // Clear the bundling information - memcpy(_bundle_use_elements, - Pipeline_Use::elaborated_elements, - sizeof(Pipeline_Use::elaborated_elements)); + memcpy(_bundle_use_elements, Pipeline_Use::elaborated_elements, sizeof(Pipeline_Use::elaborated_elements)); // Get the last node - Block *bb = _cfg->_blocks[_cfg->_blocks.size()-1]; + Block* block = _cfg->get_block(_cfg->number_of_blocks() - 1); - _next_node = bb->_nodes[bb->_nodes.size()-1]; + _next_node = block->_nodes[block->_nodes.size() - 1]; } #ifndef PRODUCT @@ -1831,7 +1832,6 @@ void Scheduling::step_and_clear() { sizeof(Pipeline_Use::elaborated_elements)); } -//------------------------------ScheduleAndBundle------------------------------ // Perform instruction scheduling and bundling over the sequence of // instructions in backwards order. void Compile::ScheduleAndBundle() { @@ -1858,7 +1858,6 @@ void Compile::ScheduleAndBundle() { scheduling.DoScheduling(); } -//------------------------------ComputeLocalLatenciesForward------------------- // Compute the latency of all the instructions. This is fairly simple, // because we already have a legal ordering. Walk over the instructions // from first to last, and compute the latency of the instruction based @@ -2028,7 +2027,6 @@ Node * Scheduling::ChooseNodeToBundle() { return _available[0]; } -//------------------------------AddNodeToAvailableList------------------------- void Scheduling::AddNodeToAvailableList(Node *n) { assert( !n->is_Proj(), "projections never directly made available" ); #ifndef PRODUCT @@ -2074,7 +2072,6 @@ void Scheduling::AddNodeToAvailableList(Node *n) { #endif } -//------------------------------DecrementUseCounts----------------------------- void Scheduling::DecrementUseCounts(Node *n, const Block *bb) { for ( uint i=0; i < n->len(); i++ ) { Node *def = n->in(i); @@ -2097,7 +2094,6 @@ void Scheduling::DecrementUseCounts(Node *n, const Block *bb) { } } -//------------------------------AddNodeToBundle-------------------------------- void Scheduling::AddNodeToBundle(Node *n, const Block *bb) { #ifndef PRODUCT if (_cfg->C->trace_opto_output()) { @@ -2312,7 +2308,6 @@ void Scheduling::AddNodeToBundle(Node *n, const Block *bb) { DecrementUseCounts(n,bb); } -//------------------------------ComputeUseCount-------------------------------- // This method sets the use count within a basic block. We will ignore all // uses outside the current basic block. As we are doing a backwards walk, // any node we reach that has a use count of 0 may be scheduled. This also @@ -2397,20 +2392,22 @@ void Scheduling::DoScheduling() { Block *bb; // Walk over all the basic blocks in reverse order - for( int i=_cfg->_num_blocks-1; i >= 0; succ_bb = bb, i-- ) { - bb = _cfg->_blocks[i]; + for (int i = _cfg->number_of_blocks() - 1; i >= 0; succ_bb = bb, i--) { + bb = _cfg->get_block(i); #ifndef PRODUCT if (_cfg->C->trace_opto_output()) { tty->print("# Schedule BB#%03d (initial)\n", i); - for (uint j = 0; j < bb->_nodes.size(); j++) + for (uint j = 0; j < bb->_nodes.size(); j++) { bb->_nodes[j]->dump(); + } } #endif // On the head node, skip processing - if( bb == _cfg->_broot ) + if (bb == _cfg->get_root_block()) { continue; + } // Skip empty, connector blocks if (bb->is_connector()) @@ -2547,7 +2544,6 @@ void Scheduling::DoScheduling() { } // end DoScheduling -//------------------------------verify_good_schedule--------------------------- // Verify that no live-range used in the block is killed in the block by a // wrong DEF. This doesn't verify live-ranges that span blocks. @@ -2560,7 +2556,6 @@ static bool edge_from_to( Node *from, Node *to ) { } #ifdef ASSERT -//------------------------------verify_do_def---------------------------------- void Scheduling::verify_do_def( Node *n, OptoReg::Name def, const char *msg ) { // Check for bad kills if( OptoReg::is_valid(def) ) { // Ignore stores & control flow @@ -2576,7 +2571,6 @@ void Scheduling::verify_do_def( Node *n, OptoReg::Name def, const char *msg ) { } } -//------------------------------verify_good_schedule--------------------------- void Scheduling::verify_good_schedule( Block *b, const char *msg ) { // Zap to something reasonable for the verify code @@ -2636,7 +2630,6 @@ static void add_prec_edge_from_to( Node *from, Node *to ) { from->add_prec(to); } -//------------------------------anti_do_def------------------------------------ void Scheduling::anti_do_def( Block *b, Node *def, OptoReg::Name def_reg, int is_def ) { if( !OptoReg::is_valid(def_reg) ) // Ignore stores & control flow return; @@ -2706,7 +2699,6 @@ void Scheduling::anti_do_def( Block *b, Node *def, OptoReg::Name def_reg, int is add_prec_edge_from_to(kill,pinch); } -//------------------------------anti_do_use------------------------------------ void Scheduling::anti_do_use( Block *b, Node *use, OptoReg::Name use_reg ) { if( !OptoReg::is_valid(use_reg) ) // Ignore stores & control flow return; @@ -2727,7 +2719,6 @@ void Scheduling::anti_do_use( Block *b, Node *use, OptoReg::Name use_reg ) { } } -//------------------------------ComputeRegisterAntidependences----------------- // We insert antidependences between the reads and following write of // allocated registers to prevent illegal code motion. Hopefully, the // number of added references should be fairly small, especially as we @@ -2861,8 +2852,6 @@ void Scheduling::ComputeRegisterAntidependencies(Block *b) { } } -//------------------------------garbage_collect_pinch_nodes------------------------------- - // Garbage collect pinch nodes for reuse by other blocks. // // The block scheduler's insertion of anti-dependence @@ -2937,7 +2926,6 @@ void Scheduling::cleanup_pinch( Node *pinch ) { pinch->set_req(0, NULL); } -//------------------------------print_statistics------------------------------- #ifndef PRODUCT void Scheduling::dump_available() const { diff --git a/hotspot/src/share/vm/opto/phaseX.cpp b/hotspot/src/share/vm/opto/phaseX.cpp index 654c6f724b9..a1d1527127e 100644 --- a/hotspot/src/share/vm/opto/phaseX.cpp +++ b/hotspot/src/share/vm/opto/phaseX.cpp @@ -1643,8 +1643,8 @@ void PhasePeephole::do_transform() { bool method_name_not_printed = true; // Examine each basic block - for( uint block_number = 1; block_number < _cfg._num_blocks; ++block_number ) { - Block *block = _cfg._blocks[block_number]; + for (uint block_number = 1; block_number < _cfg.number_of_blocks(); ++block_number) { + Block* block = _cfg.get_block(block_number); bool block_not_printed = true; // and each instruction within a block diff --git a/hotspot/src/share/vm/opto/postaloc.cpp b/hotspot/src/share/vm/opto/postaloc.cpp index 76c3def2d40..fdb72dd42c6 100644 --- a/hotspot/src/share/vm/opto/postaloc.cpp +++ b/hotspot/src/share/vm/opto/postaloc.cpp @@ -405,28 +405,29 @@ void PhaseChaitin::post_allocate_copy_removal() { // Need a mapping from basic block Node_Lists. We need a Node_List to // map from register number to value-producing Node. - Node_List **blk2value = NEW_RESOURCE_ARRAY( Node_List *, _cfg._num_blocks+1); - memset( blk2value, 0, sizeof(Node_List*)*(_cfg._num_blocks+1) ); + Node_List **blk2value = NEW_RESOURCE_ARRAY( Node_List *, _cfg.number_of_blocks() + 1); + memset(blk2value, 0, sizeof(Node_List*) * (_cfg.number_of_blocks() + 1)); // Need a mapping from basic block Node_Lists. We need a Node_List to // map from register number to register-defining Node. - Node_List **blk2regnd = NEW_RESOURCE_ARRAY( Node_List *, _cfg._num_blocks+1); - memset( blk2regnd, 0, sizeof(Node_List*)*(_cfg._num_blocks+1) ); + Node_List **blk2regnd = NEW_RESOURCE_ARRAY( Node_List *, _cfg.number_of_blocks() + 1); + memset(blk2regnd, 0, sizeof(Node_List*) * (_cfg.number_of_blocks() + 1)); // We keep unused Node_Lists on a free_list to avoid wasting // memory. GrowableArray free_list = GrowableArray(16); // For all blocks - for( uint i = 0; i < _cfg._num_blocks; i++ ) { + for (uint i = 0; i < _cfg.number_of_blocks(); i++) { uint j; - Block *b = _cfg._blocks[i]; + Block* block = _cfg.get_block(i); // Count of Phis in block uint phi_dex; - for( phi_dex = 1; phi_dex < b->_nodes.size(); phi_dex++ ) { - Node *phi = b->_nodes[phi_dex]; - if( !phi->is_Phi() ) + for (phi_dex = 1; phi_dex < block->_nodes.size(); phi_dex++) { + Node* phi = block->_nodes[phi_dex]; + if (!phi->is_Phi()) { break; + } } // If any predecessor has not been visited, we do not know the state @@ -434,21 +435,23 @@ void PhaseChaitin::post_allocate_copy_removal() { // along Phi input edges bool missing_some_inputs = false; Block *freed = NULL; - for( j = 1; j < b->num_preds(); j++ ) { - Block *pb = _cfg.get_block_for_node(b->pred(j)); + for (j = 1; j < block->num_preds(); j++) { + Block* pb = _cfg.get_block_for_node(block->pred(j)); // Remove copies along phi edges - for( uint k=1; k_nodes[k], j, b, *blk2value[pb->_pre_order], *blk2regnd[pb->_pre_order], false ); - if( blk2value[pb->_pre_order] ) { // Have a mapping on this edge? + for (uint k = 1; k < phi_dex; k++) { + elide_copy(block->_nodes[k], j, block, *blk2value[pb->_pre_order], *blk2regnd[pb->_pre_order], false); + } + if (blk2value[pb->_pre_order]) { // Have a mapping on this edge? // See if this predecessor's mappings have been used by everybody // who wants them. If so, free 'em. uint k; - for( k=0; k_num_succs; k++ ) { - Block *pbsucc = pb->_succs[k]; - if( !blk2value[pbsucc->_pre_order] && pbsucc != b ) + for (k = 0; k < pb->_num_succs; k++) { + Block* pbsucc = pb->_succs[k]; + if (!blk2value[pbsucc->_pre_order] && pbsucc != block) { break; // Found a future user + } } - if( k >= pb->_num_succs ) { // No more uses, free! + if (k >= pb->_num_succs) { // No more uses, free! freed = pb; // Record last block freed free_list.push(blk2value[pb->_pre_order]); free_list.push(blk2regnd[pb->_pre_order]); @@ -467,20 +470,20 @@ void PhaseChaitin::post_allocate_copy_removal() { value.map(_max_reg,NULL); regnd.map(_max_reg,NULL); // Set mappings as OUR mappings - blk2value[b->_pre_order] = &value; - blk2regnd[b->_pre_order] = ®nd; + blk2value[block->_pre_order] = &value; + blk2regnd[block->_pre_order] = ®nd; // Initialize value & regnd for this block - if( missing_some_inputs ) { + if (missing_some_inputs) { // Some predecessor has not yet been visited; zap map to empty - for( uint k = 0; k < (uint)_max_reg; k++ ) { + for (uint k = 0; k < (uint)_max_reg; k++) { value.map(k,NULL); regnd.map(k,NULL); } } else { if( !freed ) { // Didn't get a freebie prior block // Must clone some data - freed = _cfg.get_block_for_node(b->pred(1)); + freed = _cfg.get_block_for_node(block->pred(1)); Node_List &f_value = *blk2value[freed->_pre_order]; Node_List &f_regnd = *blk2regnd[freed->_pre_order]; for( uint k = 0; k < (uint)_max_reg; k++ ) { @@ -489,9 +492,11 @@ void PhaseChaitin::post_allocate_copy_removal() { } } // Merge all inputs together, setting to NULL any conflicts. - for( j = 1; j < b->num_preds(); j++ ) { - Block *pb = _cfg.get_block_for_node(b->pred(j)); - if( pb == freed ) continue; // Did self already via freelist + for (j = 1; j < block->num_preds(); j++) { + Block* pb = _cfg.get_block_for_node(block->pred(j)); + if (pb == freed) { + continue; // Did self already via freelist + } Node_List &p_regnd = *blk2regnd[pb->_pre_order]; for( uint k = 0; k < (uint)_max_reg; k++ ) { if( regnd[k] != p_regnd[k] ) { // Conflict on reaching defs? @@ -503,9 +508,9 @@ void PhaseChaitin::post_allocate_copy_removal() { } // For all Phi's - for( j = 1; j < phi_dex; j++ ) { + for (j = 1; j < phi_dex; j++) { uint k; - Node *phi = b->_nodes[j]; + Node *phi = block->_nodes[j]; uint pidx = _lrg_map.live_range_id(phi); OptoReg::Name preg = lrgs(_lrg_map.live_range_id(phi)).reg(); @@ -516,8 +521,8 @@ void PhaseChaitin::post_allocate_copy_removal() { if( phi != x && u != x ) // Found a different input u = u ? NodeSentinel : x; // Capture unique input, or NodeSentinel for 2nd input } - if( u != NodeSentinel ) { // Junk Phi. Remove - b->_nodes.remove(j--); + if (u != NodeSentinel) { // Junk Phi. Remove + block->_nodes.remove(j--); phi_dex--; _cfg.unmap_node_from_block(phi); phi->replace_by(u); @@ -547,13 +552,13 @@ void PhaseChaitin::post_allocate_copy_removal() { } // For all remaining instructions - for( j = phi_dex; j < b->_nodes.size(); j++ ) { - Node *n = b->_nodes[j]; + for (j = phi_dex; j < block->_nodes.size(); j++) { + Node* n = block->_nodes[j]; - if( n->outcnt() == 0 && // Dead? - n != C->top() && // (ignore TOP, it has no du info) - !n->is_Proj() ) { // fat-proj kills - j -= yank_if_dead(n,b,&value,®nd); + if(n->outcnt() == 0 && // Dead? + n != C->top() && // (ignore TOP, it has no du info) + !n->is_Proj() ) { // fat-proj kills + j -= yank_if_dead(n, block, &value, ®nd); continue; } @@ -598,8 +603,9 @@ void PhaseChaitin::post_allocate_copy_removal() { const uint two_adr = n->is_Mach() ? n->as_Mach()->two_adr() : 0; // Remove copies along input edges - for( k = 1; k < n->req(); k++ ) - j -= elide_copy( n, k, b, value, regnd, two_adr!=k ); + for (k = 1; k < n->req(); k++) { + j -= elide_copy(n, k, block, value, regnd, two_adr != k); + } // Unallocated Nodes define no registers uint lidx = _lrg_map.live_range_id(n); @@ -630,8 +636,8 @@ void PhaseChaitin::post_allocate_copy_removal() { // then 'n' is a useless copy. Do not update the register->node // mapping so 'n' will go dead. if( value[nreg] != val ) { - if (eliminate_copy_of_constant(val, n, b, value, regnd, nreg, OptoReg::Bad)) { - j -= replace_and_yank_if_dead(n, nreg, b, value, regnd); + if (eliminate_copy_of_constant(val, n, block, value, regnd, nreg, OptoReg::Bad)) { + j -= replace_and_yank_if_dead(n, nreg, block, value, regnd); } else { // Update the mapping: record new Node defined by the register regnd.map(nreg,n); @@ -640,8 +646,8 @@ void PhaseChaitin::post_allocate_copy_removal() { value.map(nreg,val); } } else if( !may_be_copy_of_callee(n) ) { - assert( n->is_Copy(), "" ); - j -= replace_and_yank_if_dead(n, nreg, b, value, regnd); + assert(n->is_Copy(), ""); + j -= replace_and_yank_if_dead(n, nreg, block, value, regnd); } } else if (RegMask::is_vector(n_ideal_reg)) { // If Node 'n' does not change the value mapped by the register, @@ -660,7 +666,7 @@ void PhaseChaitin::post_allocate_copy_removal() { } } else if (n->is_Copy()) { // Note: vector can't be constant and can't be copy of calee. - j -= replace_and_yank_if_dead(n, nreg, b, value, regnd); + j -= replace_and_yank_if_dead(n, nreg, block, value, regnd); } } else { // If the value occupies a register pair, record same info @@ -674,18 +680,18 @@ void PhaseChaitin::post_allocate_copy_removal() { tmp.Remove(nreg); nreg_lo = tmp.find_first_elem(); } - if( value[nreg] != val || value[nreg_lo] != val ) { - if (eliminate_copy_of_constant(val, n, b, value, regnd, nreg, nreg_lo)) { - j -= replace_and_yank_if_dead(n, nreg, b, value, regnd); + if (value[nreg] != val || value[nreg_lo] != val) { + if (eliminate_copy_of_constant(val, n, block, value, regnd, nreg, nreg_lo)) { + j -= replace_and_yank_if_dead(n, nreg, block, value, regnd); } else { regnd.map(nreg , n ); regnd.map(nreg_lo, n ); value.map(nreg ,val); value.map(nreg_lo,val); } - } else if( !may_be_copy_of_callee(n) ) { - assert( n->is_Copy(), "" ); - j -= replace_and_yank_if_dead(n, nreg, b, value, regnd); + } else if (!may_be_copy_of_callee(n)) { + assert(n->is_Copy(), ""); + j -= replace_and_yank_if_dead(n, nreg, block, value, regnd); } } diff --git a/hotspot/src/share/vm/opto/reg_split.cpp b/hotspot/src/share/vm/opto/reg_split.cpp index 6e4323b406e..d4df3016d8c 100644 --- a/hotspot/src/share/vm/opto/reg_split.cpp +++ b/hotspot/src/share/vm/opto/reg_split.cpp @@ -529,13 +529,13 @@ uint PhaseChaitin::Split(uint maxlrg, ResourceArea* split_arena) { // a Def is UP or DOWN. UP means that it should get a register (ie - // it is always in LRP regions), and DOWN means that it is probably // on the stack (ie - it crosses HRP regions). - Node ***Reaches = NEW_SPLIT_ARRAY( Node**, _cfg._num_blocks+1 ); - bool **UP = NEW_SPLIT_ARRAY( bool*, _cfg._num_blocks+1 ); + Node ***Reaches = NEW_SPLIT_ARRAY( Node**, _cfg.number_of_blocks() + 1); + bool **UP = NEW_SPLIT_ARRAY( bool*, _cfg.number_of_blocks() + 1); Node **debug_defs = NEW_SPLIT_ARRAY( Node*, spill_cnt ); VectorSet **UP_entry= NEW_SPLIT_ARRAY( VectorSet*, spill_cnt ); // Initialize Reaches & UP - for( bidx = 0; bidx < _cfg._num_blocks+1; bidx++ ) { + for (bidx = 0; bidx < _cfg.number_of_blocks() + 1; bidx++) { Reaches[bidx] = NEW_SPLIT_ARRAY( Node*, spill_cnt ); UP[bidx] = NEW_SPLIT_ARRAY( bool, spill_cnt ); Node **Reachblock = Reaches[bidx]; @@ -555,13 +555,13 @@ uint PhaseChaitin::Split(uint maxlrg, ResourceArea* split_arena) { //----------PASS 1---------- //----------Propagation & Node Insertion Code---------- // Walk the Blocks in RPO for DEF & USE info - for( bidx = 0; bidx < _cfg._num_blocks; bidx++ ) { + for( bidx = 0; bidx < _cfg.number_of_blocks(); bidx++ ) { if (C->check_node_count(spill_cnt, out_of_nodes)) { return 0; } - b = _cfg._blocks[bidx]; + b = _cfg.get_block(bidx); // Reaches & UP arrays for this block Reachblock = Reaches[b->_pre_order]; UPblock = UP[b->_pre_order]; @@ -1394,8 +1394,8 @@ uint PhaseChaitin::Split(uint maxlrg, ResourceArea* split_arena) { // DEBUG #ifdef ASSERT // Validate all live range index assignments - for (bidx = 0; bidx < _cfg._num_blocks; bidx++) { - b = _cfg._blocks[bidx]; + for (bidx = 0; bidx < _cfg.number_of_blocks(); bidx++) { + b = _cfg.get_block(bidx); for (insidx = 0; insidx <= b->end_idx(); insidx++) { Node *n = b->_nodes[insidx]; uint defidx = _lrg_map.find(n); diff --git a/hotspot/src/share/vm/runtime/vmStructs.cpp b/hotspot/src/share/vm/runtime/vmStructs.cpp index 163433b524f..47ca1608768 100644 --- a/hotspot/src/share/vm/runtime/vmStructs.cpp +++ b/hotspot/src/share/vm/runtime/vmStructs.cpp @@ -1096,10 +1096,10 @@ typedef BinaryTreeDictionary MetablockTreeDictionary; \ c2_nonstatic_field(MachCallRuntimeNode, _name, const char*) \ \ - c2_nonstatic_field(PhaseCFG, _num_blocks, uint) \ + c2_nonstatic_field(PhaseCFG, _number_of_blocks, uint) \ c2_nonstatic_field(PhaseCFG, _blocks, Block_List) \ c2_nonstatic_field(PhaseCFG, _node_to_block_mapping, Block_Array) \ - c2_nonstatic_field(PhaseCFG, _broot, Block*) \ + c2_nonstatic_field(PhaseCFG, _root_block, Block*) \ \ c2_nonstatic_field(PhaseRegAlloc, _node_regs, OptoRegPair*) \ c2_nonstatic_field(PhaseRegAlloc, _node_regs_max_index, uint) \ From 4ee53ef4e3ec2ef6a94b12cc25e0fbd2ae70f5f3 Mon Sep 17 00:00:00 2001 From: Vladimir Kozlov Date: Fri, 16 Aug 2013 14:11:40 -0700 Subject: [PATCH 008/218] 8021898: Broken JIT compiler optimization for loop unswitching Fix method clone_projs() to clone all related MachProj nodes. Reviewed-by: roland, adlertz --- hotspot/src/share/vm/opto/chaitin.cpp | 33 +++++++++++++--------- hotspot/src/share/vm/opto/chaitin.hpp | 25 +++++----------- hotspot/src/share/vm/opto/coalesce.cpp | 4 +-- hotspot/src/share/vm/opto/reg_split.cpp | 11 ++++++-- hotspot/src/share/vm/runtime/frame.cpp | 12 +++++--- hotspot/src/share/vm/utilities/vmError.cpp | 7 +++++ 6 files changed, 50 insertions(+), 42 deletions(-) diff --git a/hotspot/src/share/vm/opto/chaitin.cpp b/hotspot/src/share/vm/opto/chaitin.cpp index d19cf1709d7..c2f8d40b202 100644 --- a/hotspot/src/share/vm/opto/chaitin.cpp +++ b/hotspot/src/share/vm/opto/chaitin.cpp @@ -287,21 +287,26 @@ void PhaseChaitin::new_lrg(const Node *x, uint lrg) { } -bool PhaseChaitin::clone_projs_shared(Block *b, uint idx, Node *con, Node *copy, uint max_lrg_id) { - Block* bcon = _cfg.get_block_for_node(con); - uint cindex = bcon->find_node(con); - Node *con_next = bcon->_nodes[cindex+1]; - if (con_next->in(0) != con || !con_next->is_MachProj()) { - return false; // No MachProj's follow +int PhaseChaitin::clone_projs(Block* b, uint idx, Node* orig, Node* copy, uint& max_lrg_id) { + assert(b->find_node(copy) == (idx - 1), "incorrect insert index for copy kill projections"); + DEBUG_ONLY( Block* borig = _cfg.get_block_for_node(orig); ) + int found_projs = 0; + uint cnt = orig->outcnt(); + for (uint i = 0; i < cnt; i++) { + Node* proj = orig->raw_out(i); + if (proj->is_MachProj()) { + assert(proj->outcnt() == 0, "only kill projections are expected here"); + assert(_cfg.get_block_for_node(proj) == borig, "incorrect block for kill projections"); + found_projs++; + // Copy kill projections after the cloned node + Node* kills = proj->clone(); + kills->set_req(0, copy); + b->_nodes.insert(idx++, kills); + _cfg.map_node_to_block(kills, b); + new_lrg(kills, max_lrg_id++); + } } - - // Copy kills after the cloned constant - Node *kills = con_next->clone(); - kills->set_req(0, copy); - b->_nodes.insert(idx, kills); - _cfg.map_node_to_block(kills, b); - new_lrg(kills, max_lrg_id); - return true; + return found_projs; } // Renumber the live ranges to compact them. Makes the IFG smaller. diff --git a/hotspot/src/share/vm/opto/chaitin.hpp b/hotspot/src/share/vm/opto/chaitin.hpp index 3455005f330..c951024ee75 100644 --- a/hotspot/src/share/vm/opto/chaitin.hpp +++ b/hotspot/src/share/vm/opto/chaitin.hpp @@ -412,33 +412,22 @@ class PhaseChaitin : public PhaseRegAlloc { uint split_DEF( Node *def, Block *b, int loc, uint max, Node **Reachblock, Node **debug_defs, GrowableArray splits, int slidx ); uint split_USE( Node *def, Block *b, Node *use, uint useidx, uint max, bool def_down, bool cisc_sp, GrowableArray splits, int slidx ); - bool clone_projs(Block *b, uint idx, Node *con, Node *copy, LiveRangeMap &lrg_map) { - bool found_projs = clone_projs_shared(b, idx, con, copy, lrg_map.max_lrg_id()); - - if(found_projs) { - uint max_lrg_id = lrg_map.max_lrg_id(); - lrg_map.set_max_lrg_id(max_lrg_id + 1); - } - - return found_projs; - } - //------------------------------clone_projs------------------------------------ // After cloning some rematerialized instruction, clone any MachProj's that // follow it. Example: Intel zero is XOR, kills flags. Sparc FP constants // use G3 as an address temp. - bool clone_projs(Block *b, uint idx, Node *con, Node *copy, uint &max_lrg_id) { - bool found_projs = clone_projs_shared(b, idx, con, copy, max_lrg_id); + int clone_projs(Block* b, uint idx, Node* orig, Node* copy, uint& max_lrg_id); - if(found_projs) { - max_lrg_id++; + int clone_projs(Block* b, uint idx, Node* orig, Node* copy, LiveRangeMap& lrg_map) { + uint max_lrg_id = lrg_map.max_lrg_id(); + int found_projs = clone_projs(b, idx, orig, copy, max_lrg_id); + if (found_projs > 0) { + // max_lrg_id is updated during call above + lrg_map.set_max_lrg_id(max_lrg_id); } - return found_projs; } - bool clone_projs_shared(Block *b, uint idx, Node *con, Node *copy, uint max_lrg_id); - Node *split_Rematerialize(Node *def, Block *b, uint insidx, uint &maxlrg, GrowableArray splits, int slidx, uint *lrg2reach, Node **Reachblock, bool walkThru); // True if lidx is used before any real register is def'd in the block diff --git a/hotspot/src/share/vm/opto/coalesce.cpp b/hotspot/src/share/vm/opto/coalesce.cpp index 4d84bd42181..66fd988c273 100644 --- a/hotspot/src/share/vm/opto/coalesce.cpp +++ b/hotspot/src/share/vm/opto/coalesce.cpp @@ -322,9 +322,7 @@ void PhaseAggressiveCoalesce::insert_copies( Matcher &matcher ) { copy = m->clone(); // Insert the copy in the basic block, just before us b->_nodes.insert(l++, copy); - if(_phc.clone_projs(b, l, m, copy, _phc._lrg_map)) { - l++; - } + l += _phc.clone_projs(b, l, m, copy, _phc._lrg_map); } else { const RegMask *rm = C->matcher()->idealreg2spillmask[m->ideal_reg()]; copy = new (C) MachSpillCopyNode(m, *rm, *rm); diff --git a/hotspot/src/share/vm/opto/reg_split.cpp b/hotspot/src/share/vm/opto/reg_split.cpp index d4df3016d8c..ac4f8e35824 100644 --- a/hotspot/src/share/vm/opto/reg_split.cpp +++ b/hotspot/src/share/vm/opto/reg_split.cpp @@ -397,10 +397,15 @@ Node *PhaseChaitin::split_Rematerialize( Node *def, Block *b, uint insidx, uint #endif // See if the cloned def kills any flags, and copy those kills as well uint i = insidx+1; - if( clone_projs( b, i, def, spill, maxlrg) ) { + int found_projs = clone_projs( b, i, def, spill, maxlrg); + if (found_projs > 0) { // Adjust the point where we go hi-pressure - if( i <= b->_ihrp_index ) b->_ihrp_index++; - if( i <= b->_fhrp_index ) b->_fhrp_index++; + if (i <= b->_ihrp_index) { + b->_ihrp_index += found_projs; + } + if (i <= b->_fhrp_index) { + b->_fhrp_index += found_projs; + } } return spill; diff --git a/hotspot/src/share/vm/runtime/frame.cpp b/hotspot/src/share/vm/runtime/frame.cpp index 9ea7421cf06..6f5724323cd 100644 --- a/hotspot/src/share/vm/runtime/frame.cpp +++ b/hotspot/src/share/vm/runtime/frame.cpp @@ -23,6 +23,7 @@ */ #include "precompiled.hpp" +#include "compiler/abstractCompiler.hpp" #include "compiler/disassembler.hpp" #include "gc_interface/collectedHeap.inline.hpp" #include "interpreter/interpreter.hpp" @@ -559,7 +560,7 @@ void frame::print_value_on(outputStream* st, JavaThread *thread) const { st->print("%s frame (sp=" INTPTR_FORMAT " unextended sp=" INTPTR_FORMAT, print_name(), sp(), unextended_sp()); if (sp() != NULL) - st->print(", fp=" INTPTR_FORMAT ", pc=" INTPTR_FORMAT, fp(), pc()); + st->print(", fp=" INTPTR_FORMAT ", real_fp=" INTPTR_FORMAT ", pc=" INTPTR_FORMAT, fp(), real_fp(), pc()); if (StubRoutines::contains(pc())) { st->print_cr(")"); @@ -720,11 +721,14 @@ void frame::print_on_error(outputStream* st, char* buf, int buflen, bool verbose } else if (_cb->is_buffer_blob()) { st->print("v ~BufferBlob::%s", ((BufferBlob *)_cb)->name()); } else if (_cb->is_nmethod()) { - Method* m = ((nmethod *)_cb)->method(); + nmethod* nm = (nmethod*)_cb; + Method* m = nm->method(); if (m != NULL) { m->name_and_sig_as_C_string(buf, buflen); - st->print("J %s @ " PTR_FORMAT " [" PTR_FORMAT "+" SIZE_FORMAT "]", - buf, _pc, _cb->code_begin(), _pc - _cb->code_begin()); + st->print("J %d%s %s %s (%d bytes) @ " PTR_FORMAT " [" PTR_FORMAT "+0x%x]", + nm->compile_id(), (nm->is_osr_method() ? "%" : ""), + ((nm->compiler() != NULL) ? nm->compiler()->name() : ""), + buf, m->code_size(), _pc, _cb->code_begin(), _pc - _cb->code_begin()); } else { st->print("J " PTR_FORMAT, pc()); } diff --git a/hotspot/src/share/vm/utilities/vmError.cpp b/hotspot/src/share/vm/utilities/vmError.cpp index 873f479d609..b07404dc9b7 100644 --- a/hotspot/src/share/vm/utilities/vmError.cpp +++ b/hotspot/src/share/vm/utilities/vmError.cpp @@ -586,6 +586,13 @@ void VMError::report(outputStream* st) { while (count++ < StackPrintLimit) { fr.print_on_error(st, buf, sizeof(buf)); st->cr(); + // Compiled code may use EBP register on x86 so it looks like + // non-walkable C frame. Use frame.sender() for java frames. + if (_thread && _thread->is_Java_thread() && fr.is_java_frame()) { + RegisterMap map((JavaThread*)_thread, false); // No update + fr = fr.sender(&map); + continue; + } if (os::is_first_C_frame(&fr)) break; fr = os::get_sender_for_C_frame(&fr); } From 9e056eedc491e9d3af4b98385e200f53e39d5ae5 Mon Sep 17 00:00:00 2001 From: Christian Thalinger Date: Tue, 20 Aug 2013 10:57:50 -0700 Subject: [PATCH 009/218] 8022956: Clang: enable return type warnings on BSD Reviewed-by: coleenp, sla --- hotspot/make/bsd/makefiles/gcc.make | 2 +- hotspot/src/cpu/zero/vm/assembler_zero.cpp | 2 ++ .../src/cpu/zero/vm/cppInterpreter_zero.cpp | 1 + hotspot/src/cpu/zero/vm/frame_zero.cpp | 5 +++-- hotspot/src/cpu/zero/vm/frame_zero.inline.hpp | 6 +++++- hotspot/src/cpu/zero/vm/icBuffer_zero.cpp | 2 ++ hotspot/src/cpu/zero/vm/interp_masm_zero.hpp | 1 + hotspot/src/cpu/zero/vm/interpreter_zero.cpp | 1 + hotspot/src/cpu/zero/vm/nativeInst_zero.hpp | 19 +++++++++++++++++++ hotspot/src/cpu/zero/vm/register_zero.cpp | 2 ++ hotspot/src/cpu/zero/vm/relocInfo_zero.cpp | 2 ++ .../src/cpu/zero/vm/sharedRuntime_zero.cpp | 3 +++ hotspot/src/cpu/zero/vm/vtableStubs_zero.cpp | 4 ++++ hotspot/src/os_cpu/bsd_x86/vm/os_bsd_x86.cpp | 1 + .../src/os_cpu/bsd_zero/vm/os_bsd_zero.cpp | 17 ++++++----------- .../os_cpu/bsd_zero/vm/thread_bsd_zero.hpp | 1 + 16 files changed, 54 insertions(+), 15 deletions(-) diff --git a/hotspot/make/bsd/makefiles/gcc.make b/hotspot/make/bsd/makefiles/gcc.make index 36ba062651c..c2c96f9a18f 100644 --- a/hotspot/make/bsd/makefiles/gcc.make +++ b/hotspot/make/bsd/makefiles/gcc.make @@ -247,7 +247,7 @@ ifeq ($(USE_CLANG), true) # Not yet supported by clang in Xcode 4.6.2 # WARNINGS_ARE_ERRORS += -Wno-tautological-constant-out-of-range-compare WARNINGS_ARE_ERRORS += -Wno-delete-non-virtual-dtor -Wno-deprecated -Wno-format -Wno-dynamic-class-memaccess - WARNINGS_ARE_ERRORS += -Wno-return-type -Wno-empty-body + WARNINGS_ARE_ERRORS += -Wno-empty-body endif WARNING_FLAGS = -Wpointer-arith -Wsign-compare -Wundef diff --git a/hotspot/src/cpu/zero/vm/assembler_zero.cpp b/hotspot/src/cpu/zero/vm/assembler_zero.cpp index ad1107ed12f..5438c9209b6 100644 --- a/hotspot/src/cpu/zero/vm/assembler_zero.cpp +++ b/hotspot/src/cpu/zero/vm/assembler_zero.cpp @@ -50,6 +50,7 @@ int AbstractAssembler::code_fill_byte() { #ifdef ASSERT bool AbstractAssembler::pd_check_instruction_mark() { ShouldNotCallThis(); + return false; } #endif @@ -73,6 +74,7 @@ void MacroAssembler::advance(int bytes) { RegisterOrConstant MacroAssembler::delayed_value_impl( intptr_t* delayed_value_addr, Register tmpl, int offset) { ShouldNotCallThis(); + return RegisterOrConstant(); } void MacroAssembler::store_oop(jobject obj) { diff --git a/hotspot/src/cpu/zero/vm/cppInterpreter_zero.cpp b/hotspot/src/cpu/zero/vm/cppInterpreter_zero.cpp index 9a237998cfd..42e88a7374b 100644 --- a/hotspot/src/cpu/zero/vm/cppInterpreter_zero.cpp +++ b/hotspot/src/cpu/zero/vm/cppInterpreter_zero.cpp @@ -1008,6 +1008,7 @@ void BytecodeInterpreter::layout_interpreterState(interpreterState istate, address CppInterpreter::return_entry(TosState state, int length) { ShouldNotCallThis(); + return NULL; } address CppInterpreter::deopt_entry(TosState state, int length) { diff --git a/hotspot/src/cpu/zero/vm/frame_zero.cpp b/hotspot/src/cpu/zero/vm/frame_zero.cpp index 56f2a7a1c71..c8623f9aade 100644 --- a/hotspot/src/cpu/zero/vm/frame_zero.cpp +++ b/hotspot/src/cpu/zero/vm/frame_zero.cpp @@ -116,6 +116,7 @@ void frame::patch_pc(Thread* thread, address pc) { bool frame::safe_for_sender(JavaThread *thread) { ShouldNotCallThis(); + return false; } void frame::pd_gc_epilog() { @@ -123,6 +124,7 @@ void frame::pd_gc_epilog() { bool frame::is_interpreted_frame_valid(JavaThread *thread) const { ShouldNotCallThis(); + return false; } BasicType frame::interpreter_frame_result(oop* oop_result, @@ -184,9 +186,8 @@ BasicType frame::interpreter_frame_result(oop* oop_result, int frame::frame_size(RegisterMap* map) const { #ifdef PRODUCT ShouldNotCallThis(); -#else - return 0; // make javaVFrame::print_value work #endif // PRODUCT + return 0; // make javaVFrame::print_value work } intptr_t* frame::interpreter_frame_tos_at(jint offset) const { diff --git a/hotspot/src/cpu/zero/vm/frame_zero.inline.hpp b/hotspot/src/cpu/zero/vm/frame_zero.inline.hpp index 971560cd0d8..7f6ca09978c 100644 --- a/hotspot/src/cpu/zero/vm/frame_zero.inline.hpp +++ b/hotspot/src/cpu/zero/vm/frame_zero.inline.hpp @@ -36,7 +36,7 @@ inline frame::frame() { _deopt_state = unknown; } -inline address frame::sender_pc() const { ShouldNotCallThis(); } +inline address frame::sender_pc() const { ShouldNotCallThis(); return NULL; } inline frame::frame(ZeroFrame* zf, intptr_t* sp) { _zeroframe = zf; @@ -89,6 +89,7 @@ inline intptr_t* frame::real_fp() const { inline intptr_t* frame::link() const { ShouldNotCallThis(); + return NULL; } #ifdef CC_INTERP @@ -151,14 +152,17 @@ inline void frame::set_saved_oop_result(RegisterMap* map, oop obj) { inline oop frame::saved_oop_result(RegisterMap* map) const { ShouldNotCallThis(); + return NULL; } inline bool frame::is_older(intptr_t* id) const { ShouldNotCallThis(); + return false; } inline intptr_t* frame::entry_frame_argument_at(int offset) const { ShouldNotCallThis(); + return NULL; } inline intptr_t* frame::unextended_sp() const { diff --git a/hotspot/src/cpu/zero/vm/icBuffer_zero.cpp b/hotspot/src/cpu/zero/vm/icBuffer_zero.cpp index 95d0e115a66..bf2849b6ecc 100644 --- a/hotspot/src/cpu/zero/vm/icBuffer_zero.cpp +++ b/hotspot/src/cpu/zero/vm/icBuffer_zero.cpp @@ -49,8 +49,10 @@ void InlineCacheBuffer::assemble_ic_buffer_code(address code_begin, address InlineCacheBuffer::ic_buffer_entry_point(address code_begin) { // NB ic_stub_code_size() must return the size of the code we generate ShouldNotCallThis(); + return NULL; } void* InlineCacheBuffer::ic_buffer_cached_value(address code_begin) { ShouldNotCallThis(); + return NULL; } diff --git a/hotspot/src/cpu/zero/vm/interp_masm_zero.hpp b/hotspot/src/cpu/zero/vm/interp_masm_zero.hpp index 493f0b7909d..97a105bea80 100644 --- a/hotspot/src/cpu/zero/vm/interp_masm_zero.hpp +++ b/hotspot/src/cpu/zero/vm/interp_masm_zero.hpp @@ -40,6 +40,7 @@ class InterpreterMacroAssembler : public MacroAssembler { Register tmp, int offset) { ShouldNotCallThis(); + return RegisterOrConstant(); } }; diff --git a/hotspot/src/cpu/zero/vm/interpreter_zero.cpp b/hotspot/src/cpu/zero/vm/interpreter_zero.cpp index b838b8bcde5..371d65cf9bb 100644 --- a/hotspot/src/cpu/zero/vm/interpreter_zero.cpp +++ b/hotspot/src/cpu/zero/vm/interpreter_zero.cpp @@ -64,6 +64,7 @@ address InterpreterGenerator::generate_math_entry( return NULL; Unimplemented(); + return NULL; } address InterpreterGenerator::generate_abstract_entry() { diff --git a/hotspot/src/cpu/zero/vm/nativeInst_zero.hpp b/hotspot/src/cpu/zero/vm/nativeInst_zero.hpp index 16d1d3f0dee..00599206126 100644 --- a/hotspot/src/cpu/zero/vm/nativeInst_zero.hpp +++ b/hotspot/src/cpu/zero/vm/nativeInst_zero.hpp @@ -51,15 +51,18 @@ class NativeInstruction VALUE_OBJ_CLASS_SPEC { public: bool is_jump() { ShouldNotCallThis(); + return false; } bool is_safepoint_poll() { ShouldNotCallThis(); + return false; } }; inline NativeInstruction* nativeInstruction_at(address address) { ShouldNotCallThis(); + return NULL; } class NativeCall : public NativeInstruction { @@ -70,18 +73,22 @@ class NativeCall : public NativeInstruction { address instruction_address() const { ShouldNotCallThis(); + return NULL; } address next_instruction_address() const { ShouldNotCallThis(); + return NULL; } address return_address() const { ShouldNotCallThis(); + return NULL; } address destination() const { ShouldNotCallThis(); + return NULL; } void set_destination_mt_safe(address dest) { @@ -98,25 +105,30 @@ class NativeCall : public NativeInstruction { static bool is_call_before(address return_address) { ShouldNotCallThis(); + return false; } }; inline NativeCall* nativeCall_before(address return_address) { ShouldNotCallThis(); + return NULL; } inline NativeCall* nativeCall_at(address address) { ShouldNotCallThis(); + return NULL; } class NativeMovConstReg : public NativeInstruction { public: address next_instruction_address() const { ShouldNotCallThis(); + return NULL; } intptr_t data() const { ShouldNotCallThis(); + return 0; } void set_data(intptr_t x) { @@ -126,12 +138,14 @@ class NativeMovConstReg : public NativeInstruction { inline NativeMovConstReg* nativeMovConstReg_at(address address) { ShouldNotCallThis(); + return NULL; } class NativeMovRegMem : public NativeInstruction { public: int offset() const { ShouldNotCallThis(); + return 0; } void set_offset(intptr_t x) { @@ -145,6 +159,7 @@ class NativeMovRegMem : public NativeInstruction { inline NativeMovRegMem* nativeMovRegMem_at(address address) { ShouldNotCallThis(); + return NULL; } class NativeJump : public NativeInstruction { @@ -155,6 +170,7 @@ class NativeJump : public NativeInstruction { address jump_destination() const { ShouldNotCallThis(); + return NULL; } void set_jump_destination(address dest) { @@ -172,12 +188,14 @@ class NativeJump : public NativeInstruction { inline NativeJump* nativeJump_at(address address) { ShouldNotCallThis(); + return NULL; } class NativeGeneralJump : public NativeInstruction { public: address jump_destination() const { ShouldNotCallThis(); + return NULL; } static void insert_unconditional(address code_pos, address entry) { @@ -191,6 +209,7 @@ class NativeGeneralJump : public NativeInstruction { inline NativeGeneralJump* nativeGeneralJump_at(address address) { ShouldNotCallThis(); + return NULL; } #endif // CPU_ZERO_VM_NATIVEINST_ZERO_HPP diff --git a/hotspot/src/cpu/zero/vm/register_zero.cpp b/hotspot/src/cpu/zero/vm/register_zero.cpp index 31bee7baf78..f11bf829aa6 100644 --- a/hotspot/src/cpu/zero/vm/register_zero.cpp +++ b/hotspot/src/cpu/zero/vm/register_zero.cpp @@ -32,8 +32,10 @@ const int ConcreteRegisterImpl::max_fpr = const char* RegisterImpl::name() const { ShouldNotCallThis(); + return NULL; } const char* FloatRegisterImpl::name() const { ShouldNotCallThis(); + return NULL; } diff --git a/hotspot/src/cpu/zero/vm/relocInfo_zero.cpp b/hotspot/src/cpu/zero/vm/relocInfo_zero.cpp index 5cd6c62a8de..f50190829c0 100644 --- a/hotspot/src/cpu/zero/vm/relocInfo_zero.cpp +++ b/hotspot/src/cpu/zero/vm/relocInfo_zero.cpp @@ -37,6 +37,7 @@ void Relocation::pd_set_data_value(address x, intptr_t o, bool verify_only) { address Relocation::pd_call_destination(address orig_addr) { ShouldNotCallThis(); + return NULL; } void Relocation::pd_set_call_destination(address x) { @@ -45,6 +46,7 @@ void Relocation::pd_set_call_destination(address x) { address Relocation::pd_get_address_from_code() { ShouldNotCallThis(); + return NULL; } address* Relocation::pd_address_in_code() { diff --git a/hotspot/src/cpu/zero/vm/sharedRuntime_zero.cpp b/hotspot/src/cpu/zero/vm/sharedRuntime_zero.cpp index 123d71ec044..2c419b14822 100644 --- a/hotspot/src/cpu/zero/vm/sharedRuntime_zero.cpp +++ b/hotspot/src/cpu/zero/vm/sharedRuntime_zero.cpp @@ -89,6 +89,7 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm, ret_type); #else ShouldNotCallThis(); + return NULL; #endif // SHARK } @@ -99,6 +100,7 @@ int Deoptimization::last_frame_adjust(int callee_parameters, uint SharedRuntime::out_preserve_stack_slots() { ShouldNotCallThis(); + return 0; } JRT_LEAF(void, zero_stub()) @@ -135,4 +137,5 @@ int SharedRuntime::c_calling_convention(const BasicType *sig_bt, VMRegPair *regs, int total_args_passed) { ShouldNotCallThis(); + return 0; } diff --git a/hotspot/src/cpu/zero/vm/vtableStubs_zero.cpp b/hotspot/src/cpu/zero/vm/vtableStubs_zero.cpp index e4ea32e44c1..67f0ea88839 100644 --- a/hotspot/src/cpu/zero/vm/vtableStubs_zero.cpp +++ b/hotspot/src/cpu/zero/vm/vtableStubs_zero.cpp @@ -39,16 +39,20 @@ VtableStub* VtableStubs::create_vtable_stub(int vtable_index) { ShouldNotCallThis(); + return NULL; } VtableStub* VtableStubs::create_itable_stub(int vtable_index) { ShouldNotCallThis(); + return NULL; } int VtableStub::pd_code_size_limit(bool is_vtable_stub) { ShouldNotCallThis(); + return 0; } int VtableStub::pd_code_alignment() { ShouldNotCallThis(); + return 0; } diff --git a/hotspot/src/os_cpu/bsd_x86/vm/os_bsd_x86.cpp b/hotspot/src/os_cpu/bsd_x86/vm/os_bsd_x86.cpp index 24f364e985f..ad3ebb2ead9 100644 --- a/hotspot/src/os_cpu/bsd_x86/vm/os_bsd_x86.cpp +++ b/hotspot/src/os_cpu/bsd_x86/vm/os_bsd_x86.cpp @@ -715,6 +715,7 @@ JVM_handle_bsd_signal(int sig, err.report_and_die(); ShouldNotReachHere(); + return false; } // From solaris_i486.s ported to bsd_i486.s diff --git a/hotspot/src/os_cpu/bsd_zero/vm/os_bsd_zero.cpp b/hotspot/src/os_cpu/bsd_zero/vm/os_bsd_zero.cpp index d2a8c247f0a..7903217291b 100644 --- a/hotspot/src/os_cpu/bsd_zero/vm/os_bsd_zero.cpp +++ b/hotspot/src/os_cpu/bsd_zero/vm/os_bsd_zero.cpp @@ -66,6 +66,7 @@ address os::current_stack_pointer() { frame os::get_sender_for_C_frame(frame* fr) { ShouldNotCallThis(); + return frame(); } frame os::current_frame() { @@ -103,16 +104,19 @@ void os::initialize_thread(Thread* thr) { address os::Bsd::ucontext_get_pc(ucontext_t* uc) { ShouldNotCallThis(); + return NULL; } ExtendedPC os::fetch_frame_from_context(void* ucVoid, intptr_t** ret_sp, intptr_t** ret_fp) { ShouldNotCallThis(); + return ExtendedPC(); } frame os::fetch_frame_from_context(void* ucVoid) { ShouldNotCallThis(); + return frame(); } extern "C" JNIEXPORT int @@ -240,6 +244,7 @@ JVM_handle_bsd_signal(int sig, sprintf(buf, fmt, sig, info->si_addr); fatal(buf); + return false; } void os::Bsd::init_thread_fpu_state(void) { @@ -373,17 +378,7 @@ void os::print_register_info(outputStream *st, void *context) { extern "C" { int SpinPause() { - } - - int SafeFetch32(int *adr, int errValue) { - int value = errValue; - value = *adr; - return value; - } - intptr_t SafeFetchN(intptr_t *adr, intptr_t errValue) { - intptr_t value = errValue; - value = *adr; - return value; + return 1; } void _Copy_conjoint_jshorts_atomic(jshort* from, jshort* to, size_t count) { diff --git a/hotspot/src/os_cpu/bsd_zero/vm/thread_bsd_zero.hpp b/hotspot/src/os_cpu/bsd_zero/vm/thread_bsd_zero.hpp index 12971a6a868..983aea1a2a6 100644 --- a/hotspot/src/os_cpu/bsd_zero/vm/thread_bsd_zero.hpp +++ b/hotspot/src/os_cpu/bsd_zero/vm/thread_bsd_zero.hpp @@ -110,6 +110,7 @@ void* ucontext, bool isInJava) { ShouldNotCallThis(); + return false; } // These routines are only used on cpu architectures that From a231c31f3811a5e9185a0233920b0ea5cfb79a51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rickard=20B=C3=A4ckman?= Date: Thu, 8 Aug 2013 03:16:56 +0200 Subject: [PATCH 010/218] 8022675: Redundant class init check Reviewed-by: kvn, twisti --- hotspot/src/share/vm/opto/library_call.cpp | 39 ++++++++++++++++------ 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/hotspot/src/share/vm/opto/library_call.cpp b/hotspot/src/share/vm/opto/library_call.cpp index df84634832a..22deebb5a83 100644 --- a/hotspot/src/share/vm/opto/library_call.cpp +++ b/hotspot/src/share/vm/opto/library_call.cpp @@ -213,6 +213,7 @@ class LibraryCallKit : public GraphKit { void insert_pre_barrier(Node* base_oop, Node* offset, Node* pre_val, bool need_mem_bar); bool inline_unsafe_access(bool is_native_ptr, bool is_store, BasicType type, bool is_volatile); bool inline_unsafe_prefetch(bool is_native_ptr, bool is_store, bool is_static); + static bool klass_needs_init_guard(Node* kls); bool inline_unsafe_allocate(); bool inline_unsafe_copyMemory(); bool inline_native_currentThread(); @@ -2892,8 +2893,21 @@ bool LibraryCallKit::inline_unsafe_fence(vmIntrinsics::ID id) { } } +bool LibraryCallKit::klass_needs_init_guard(Node* kls) { + if (!kls->is_Con()) { + return true; + } + const TypeKlassPtr* klsptr = kls->bottom_type()->isa_klassptr(); + if (klsptr == NULL) { + return true; + } + ciInstanceKlass* ik = klsptr->klass()->as_instance_klass(); + // don't need a guard for a klass that is already initialized + return !ik->is_initialized(); +} + //----------------------------inline_unsafe_allocate--------------------------- -// public native Object sun.mics.Unsafe.allocateInstance(Class cls); +// public native Object sun.misc.Unsafe.allocateInstance(Class cls); bool LibraryCallKit::inline_unsafe_allocate() { if (callee()->is_static()) return false; // caller must have the capability! @@ -2905,16 +2919,19 @@ bool LibraryCallKit::inline_unsafe_allocate() { kls = null_check(kls); if (stopped()) return true; // argument was like int.class - // Note: The argument might still be an illegal value like - // Serializable.class or Object[].class. The runtime will handle it. - // But we must make an explicit check for initialization. - Node* insp = basic_plus_adr(kls, in_bytes(InstanceKlass::init_state_offset())); - // Use T_BOOLEAN for InstanceKlass::_init_state so the compiler - // can generate code to load it as unsigned byte. - Node* inst = make_load(NULL, insp, TypeInt::UBYTE, T_BOOLEAN); - Node* bits = intcon(InstanceKlass::fully_initialized); - Node* test = _gvn.transform(new (C) SubINode(inst, bits)); - // The 'test' is non-zero if we need to take a slow path. + Node* test = NULL; + if (LibraryCallKit::klass_needs_init_guard(kls)) { + // Note: The argument might still be an illegal value like + // Serializable.class or Object[].class. The runtime will handle it. + // But we must make an explicit check for initialization. + Node* insp = basic_plus_adr(kls, in_bytes(InstanceKlass::init_state_offset())); + // Use T_BOOLEAN for InstanceKlass::_init_state so the compiler + // can generate code to load it as unsigned byte. + Node* inst = make_load(NULL, insp, TypeInt::UBYTE, T_BOOLEAN); + Node* bits = intcon(InstanceKlass::fully_initialized); + test = _gvn.transform(new (C) SubINode(inst, bits)); + // The 'test' is non-zero if we need to take a slow path. + } Node* obj = new_instance(kls, test); set_result(obj); From cecb5cc0ea320f4a0bfa1d4d9ba9763685ee1f04 Mon Sep 17 00:00:00 2001 From: Vicente Romero Date: Thu, 8 Aug 2013 11:49:16 +0100 Subject: [PATCH 011/218] 8019486: javac, generates erroneous LVT for a test case with lambda code Reviewed-by: mcimadamore --- .../sun/tools/javac/comp/LambdaToMethod.java | 2 +- .../javac/T8019486/WrongLVTForLambdaTest.java | 111 ++++++++++++++++++ 2 files changed, 112 insertions(+), 1 deletion(-) create mode 100644 langtools/test/tools/javac/T8019486/WrongLVTForLambdaTest.java diff --git a/langtools/src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java b/langtools/src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java index 21b6791bb7d..577d7cc30a6 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java @@ -473,7 +473,7 @@ public class LambdaToMethod extends TreeTranslator { //non-void to non-void conversion: // return (TYPE)BODY; JCExpression retExpr = transTypes.coerce(attrEnv, expr, restype); - return make.Block(0, List.of(make.Return(retExpr))); + return make.at(retExpr).Block(0, List.of(make.Return(retExpr))); } } diff --git a/langtools/test/tools/javac/T8019486/WrongLVTForLambdaTest.java b/langtools/test/tools/javac/T8019486/WrongLVTForLambdaTest.java new file mode 100644 index 00000000000..9d7d32abb3b --- /dev/null +++ b/langtools/test/tools/javac/T8019486/WrongLVTForLambdaTest.java @@ -0,0 +1,111 @@ +/* + * 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. + */ + +/* + * @test + * @bug 8019486 + * @summary javac, generates erroneous LVT for a test case with lambda code + * @library /tools/javac/lib + * @build ToolBox + * @run main WrongLVTForLambdaTest + */ + +import java.io.File; +import java.nio.file.Paths; + +import com.sun.tools.classfile.ClassFile; +import com.sun.tools.classfile.Code_attribute; +import com.sun.tools.classfile.LineNumberTable_attribute; +import com.sun.tools.classfile.Method; +import com.sun.tools.javac.util.Assert; + +public class WrongLVTForLambdaTest { + + static final String testSource = + /* 01 */ "import java.util.List;\n" + + /* 02 */ "import java.util.Arrays;\n" + + /* 03 */ "import java.util.stream.Collectors;\n" + + /* 04 */ "\n" + + /* 05 */ "public class Foo {\n" + + /* 06 */ " void bar(int value) {\n" + + /* 07 */ " final List numbers = Arrays.asList(1, 2, 3);\n" + + /* 08 */ " final List numbersPlusOne = \n" + + /* 09 */ " numbers.stream().map(number -> number / 1).collect(Collectors.toList());\n" + + /* 10 */ " }\n" + + /* 11 */ "}"; + + static final int[][] expectedLNT = { + // {line-number, start-pc}, + {9, 0}, //number -> number / 1 + }; + + static final String methodToLookFor = "lambda$0"; + + public static void main(String[] args) throws Exception { + new WrongLVTForLambdaTest().run(); + } + + void run() throws Exception { + compileTestClass(); + checkClassFile(new File(Paths.get(System.getProperty("user.dir"), + "Foo.class").toUri()), methodToLookFor); + } + + void compileTestClass() throws Exception { + ToolBox.JavaToolArgs javacSuccessArgs = + new ToolBox.JavaToolArgs().setSources(testSource); + ToolBox.javac(javacSuccessArgs); + } + + void checkClassFile(final File cfile, String methodToFind) throws Exception { + ClassFile classFile = ClassFile.read(cfile); + boolean methodFound = false; + for (Method method : classFile.methods) { + if (method.getName(classFile.constant_pool).equals(methodToFind)) { + methodFound = true; + Code_attribute code = (Code_attribute) method.attributes.get("Code"); + LineNumberTable_attribute lnt = + (LineNumberTable_attribute) code.attributes.get("LineNumberTable"); + Assert.check(lnt.line_number_table_length == expectedLNT.length, + "The LineNumberTable found has a length different to the expected one"); + int i = 0; + for (LineNumberTable_attribute.Entry entry: lnt.line_number_table) { + Assert.check(entry.line_number == expectedLNT[i][0] && + entry.start_pc == expectedLNT[i][1], + "LNT entry at pos " + i + " differ from expected." + + "Found " + entry.line_number + ":" + entry.start_pc + + ". Expected " + expectedLNT[i][0] + ":" + expectedLNT[i][1]); + i++; + } + } + } + Assert.check(methodFound, "The seek method was not found"); + } + + void error(String msg) { + throw new AssertionError(msg); + } + +} From 77e477eaea35cf2a34da7d3c500a4c1d56631235 Mon Sep 17 00:00:00 2001 From: Athijegannathan Sundararajan Date: Thu, 8 Aug 2013 16:38:32 +0530 Subject: [PATCH 012/218] 8022524: Memory leaks in nashorn sources and tests found by jhat analysis Reviewed-by: attila, hannesw --- nashorn/make/project.properties | 4 +- .../nashorn/internal/codegen/CompileUnit.java | 6 +- .../jdk/nashorn/internal/objects/Global.java | 35 ++++- .../nashorn/internal/objects/NativeArray.java | 133 ++++++++++++++---- .../nashorn/internal/objects/NativeDate.java | 19 ++- .../nashorn/internal/objects/NativeJSON.java | 36 ++++- .../internal/objects/NativeObject.java | 19 ++- .../internal/runtime/GlobalObject.java | 18 +++ .../internal/runtime/JSONFunctions.java | 18 ++- .../nashorn/internal/runtime/ListAdapter.java | 112 +++++++++++---- .../RecompilableScriptFunctionData.java | 25 ++-- .../internal/runtime/ScriptFunction.java | 29 ++-- .../runtime/UserAccessorProperty.java | 33 ++++- .../linker/JavaAdapterClassLoader.java | 10 +- .../runtime/linker/JavaAdapterFactory.java | 5 +- nashorn/test/script/basic/JDK-8020357.js | 11 -- .../api/javaaccess/BooleanAccessTest.java | 10 +- .../api/javaaccess/MethodAccessTest.java | 10 +- .../api/javaaccess/NumberAccessTest.java | 10 +- .../api/javaaccess/NumberBoxingTest.java | 10 +- .../api/javaaccess/ObjectAccessTest.java | 10 +- .../api/javaaccess/StringAccessTest.java | 10 +- .../internal/codegen/CompilerTest.java | 11 +- .../nashorn/internal/parser/ParserTest.java | 22 ++- 24 files changed, 473 insertions(+), 133 deletions(-) diff --git a/nashorn/make/project.properties b/nashorn/make/project.properties index 57c99866575..081e27b2f2a 100644 --- a/nashorn/make/project.properties +++ b/nashorn/make/project.properties @@ -223,9 +223,9 @@ run.test.user.language=tr run.test.user.country=TR # -XX:+PrintCompilation -XX:+UnlockDiagnosticVMOptions -XX:+PrintNMethods -run.test.jvmargs.main=-server -Xmx${run.test.xmx} -XX:+TieredCompilation -ea -Dfile.encoding=UTF-8 -Duser.language=${run.test.user.language} -Duser.country=${run.test.user.country} +run.test.jvmargs.main=-server -Xmx${run.test.xmx} -XX:+TieredCompilation -ea -Dfile.encoding=UTF-8 -Duser.language=${run.test.user.language} -Duser.country=${run.test.user.country} -XX:+HeapDumpOnOutOfMemoryError -#-XX:+HeapDumpOnOutOfMemoryError -XX:-UseCompressedKlassPointers -XX:+PrintHeapAtGC -XX:ClassMetaspaceSize=300M +#-XX:-UseCompressedKlassPointers -XX:+PrintHeapAtGC -XX:ClassMetaspaceSize=300M run.test.jvmargs.octane.main=-Xms${run.test.xms} ${run.test.jvmargs.main} run.test.jvmsecurityargs=-Xverify:all -Djava.security.properties=${basedir}/make/java.security.override -Djava.security.manager -Djava.security.policy=${basedir}/build/nashorn.policy diff --git a/nashorn/src/jdk/nashorn/internal/codegen/CompileUnit.java b/nashorn/src/jdk/nashorn/internal/codegen/CompileUnit.java index ff88fa9986a..0156716d9d8 100644 --- a/nashorn/src/jdk/nashorn/internal/codegen/CompileUnit.java +++ b/nashorn/src/jdk/nashorn/internal/codegen/CompileUnit.java @@ -33,7 +33,7 @@ public class CompileUnit { private final String className; /** Current class generator */ - private final ClassEmitter classEmitter; + private ClassEmitter classEmitter; private long weight; @@ -64,7 +64,11 @@ public class CompileUnit { * @param clazz class with code for this compile unit */ void setCode(final Class clazz) { + clazz.getClass(); // null check this.clazz = clazz; + // Revisit this - refactor to avoid null-ed out non-final fields + // null out emitter + this.classEmitter = null; } /** diff --git a/nashorn/src/jdk/nashorn/internal/objects/Global.java b/nashorn/src/jdk/nashorn/internal/objects/Global.java index 62288414f6f..891e0d7ced5 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/Global.java +++ b/nashorn/src/jdk/nashorn/internal/objects/Global.java @@ -41,6 +41,8 @@ import java.util.Arrays; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.concurrent.Callable; +import java.util.concurrent.ConcurrentHashMap; import jdk.internal.dynalink.linker.GuardedInvocation; import jdk.internal.dynalink.linker.LinkRequest; import jdk.nashorn.internal.objects.annotations.Attribute; @@ -72,8 +74,8 @@ import jdk.nashorn.internal.scripts.JO; */ @ScriptClass("Global") public final class Global extends ScriptObject implements GlobalObject, Scope { - private static final InvokeByName TO_STRING = new InvokeByName("toString", ScriptObject.class); - private static final InvokeByName VALUE_OF = new InvokeByName("valueOf", ScriptObject.class); + private final InvokeByName TO_STRING = new InvokeByName("toString", ScriptObject.class); + private final InvokeByName VALUE_OF = new InvokeByName("valueOf", ScriptObject.class); /** ECMA 15.1.2.2 parseInt (string , radix) */ @Property(attributes = Attribute.NOT_ENUMERABLE) @@ -709,6 +711,35 @@ public final class Global extends ScriptObject implements GlobalObject, Scope { classCache.put(source, new SoftReference>(clazz)); } + private static T getLazilyCreatedValue(final Object key, final Callable creator, final Map map) { + final T obj = map.get(key); + if (obj != null) { + return obj; + } + + try { + final T newObj = creator.call(); + final T existingObj = map.putIfAbsent(key, newObj); + return existingObj != null ? existingObj : newObj; + } catch (final Exception exp) { + throw new RuntimeException(exp); + } + } + + private final Map namedInvokers = new ConcurrentHashMap<>(); + + @Override + public InvokeByName getInvokeByName(final Object key, final Callable creator) { + return getLazilyCreatedValue(key, creator, namedInvokers); + } + + private final Map dynamicInvokers = new ConcurrentHashMap<>(); + + @Override + public MethodHandle getDynamicInvoker(final Object key, final Callable creator) { + return getLazilyCreatedValue(key, creator, dynamicInvokers); + } + /** * This is the eval used when 'indirect' eval call is made. * diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeArray.java b/nashorn/src/jdk/nashorn/internal/objects/NativeArray.java index 5572cb14522..e03cd8dde85 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeArray.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeArray.java @@ -39,6 +39,7 @@ import java.util.Collections; import java.util.Comparator; import java.util.Iterator; import java.util.List; +import java.util.concurrent.Callable; import jdk.nashorn.api.scripting.ScriptObjectMirror; import jdk.nashorn.internal.objects.annotations.Attribute; import jdk.nashorn.internal.objects.annotations.Constructor; @@ -68,20 +69,88 @@ import jdk.nashorn.internal.runtime.linker.InvokeByName; */ @ScriptClass("Array") public final class NativeArray extends ScriptObject { - private static final InvokeByName JOIN = new InvokeByName("join", ScriptObject.class); + private static final Object JOIN = new Object(); + private static final Object EVERY_CALLBACK_INVOKER = new Object(); + private static final Object SOME_CALLBACK_INVOKER = new Object(); + private static final Object FOREACH_CALLBACK_INVOKER = new Object(); + private static final Object MAP_CALLBACK_INVOKER = new Object(); + private static final Object FILTER_CALLBACK_INVOKER = new Object(); + private static final Object REDUCE_CALLBACK_INVOKER = new Object(); + private static final Object CALL_CMP = new Object(); + private static final Object TO_LOCALE_STRING = new Object(); - private static final MethodHandle EVERY_CALLBACK_INVOKER = createIteratorCallbackInvoker(boolean.class); - private static final MethodHandle SOME_CALLBACK_INVOKER = createIteratorCallbackInvoker(boolean.class); - private static final MethodHandle FOREACH_CALLBACK_INVOKER = createIteratorCallbackInvoker(void.class); - private static final MethodHandle MAP_CALLBACK_INVOKER = createIteratorCallbackInvoker(Object.class); - private static final MethodHandle FILTER_CALLBACK_INVOKER = createIteratorCallbackInvoker(boolean.class); + private static InvokeByName getJOIN() { + return Global.instance().getInvokeByName(JOIN, + new Callable() { + @Override + public InvokeByName call() { + return new InvokeByName("join", ScriptObject.class); + } + }); + } - private static final MethodHandle REDUCE_CALLBACK_INVOKER = Bootstrap.createDynamicInvoker("dyn:call", Object.class, - Object.class, Undefined.class, Object.class, Object.class, long.class, Object.class); - private static final MethodHandle CALL_CMP = Bootstrap.createDynamicInvoker("dyn:call", double.class, - ScriptFunction.class, Object.class, Object.class, Object.class); + private static MethodHandle createIteratorCallbackInvoker(final Object key, final Class rtype) { + return Global.instance().getDynamicInvoker(key, + new Callable() { + @Override + public MethodHandle call() { + return Bootstrap.createDynamicInvoker("dyn:call", rtype, Object.class, Object.class, Object.class, + long.class, Object.class); + } + }); + } - private static final InvokeByName TO_LOCALE_STRING = new InvokeByName("toLocaleString", ScriptObject.class, String.class); + private static MethodHandle getEVERY_CALLBACK_INVOKER() { + return createIteratorCallbackInvoker(EVERY_CALLBACK_INVOKER, boolean.class); + } + + private static MethodHandle getSOME_CALLBACK_INVOKER() { + return createIteratorCallbackInvoker(SOME_CALLBACK_INVOKER, boolean.class); + } + + private static MethodHandle getFOREACH_CALLBACK_INVOKER() { + return createIteratorCallbackInvoker(FOREACH_CALLBACK_INVOKER, void.class); + } + + private static MethodHandle getMAP_CALLBACK_INVOKER() { + return createIteratorCallbackInvoker(MAP_CALLBACK_INVOKER, Object.class); + } + + private static MethodHandle getFILTER_CALLBACK_INVOKER() { + return createIteratorCallbackInvoker(FILTER_CALLBACK_INVOKER, boolean.class); + } + + private static MethodHandle getREDUCE_CALLBACK_INVOKER() { + return Global.instance().getDynamicInvoker(REDUCE_CALLBACK_INVOKER, + new Callable() { + @Override + public MethodHandle call() { + return Bootstrap.createDynamicInvoker("dyn:call", Object.class, Object.class, + Undefined.class, Object.class, Object.class, long.class, Object.class); + } + }); + } + + private static MethodHandle getCALL_CMP() { + return Global.instance().getDynamicInvoker(CALL_CMP, + new Callable() { + @Override + public MethodHandle call() { + return Bootstrap.createDynamicInvoker("dyn:call", double.class, + ScriptFunction.class, Object.class, Object.class, Object.class); + } + }); + } + + private static InvokeByName getTO_LOCALE_STRING() { + return Global.instance().getInvokeByName(TO_LOCALE_STRING, + new Callable() { + @Override + public InvokeByName call() { + return new InvokeByName("toLocaleString", ScriptObject.class, String.class); + } + }); + } // initialized by nasgen private static PropertyMap $nasgenmap$; @@ -357,11 +426,12 @@ public final class NativeArray extends ScriptObject { public static Object toString(final Object self) { final Object obj = Global.toObject(self); if (obj instanceof ScriptObject) { + final InvokeByName joinInvoker = getJOIN(); final ScriptObject sobj = (ScriptObject)obj; try { - final Object join = JOIN.getGetter().invokeExact(sobj); + final Object join = joinInvoker.getGetter().invokeExact(sobj); if (Bootstrap.isCallable(join)) { - return JOIN.getInvoker().invokeExact(join, sobj); + return joinInvoker.getInvoker().invokeExact(join, sobj); } } catch (final RuntimeException | Error e) { throw e; @@ -393,11 +463,12 @@ public final class NativeArray extends ScriptObject { try { if (val instanceof ScriptObject) { + final InvokeByName localeInvoker = getTO_LOCALE_STRING(); final ScriptObject sobj = (ScriptObject)val; - final Object toLocaleString = TO_LOCALE_STRING.getGetter().invokeExact(sobj); + final Object toLocaleString = localeInvoker.getGetter().invokeExact(sobj); if (Bootstrap.isCallable(toLocaleString)) { - sb.append((String)TO_LOCALE_STRING.getInvoker().invokeExact(toLocaleString, sobj)); + sb.append((String)localeInvoker.getInvoker().invokeExact(toLocaleString, sobj)); } else { throw typeError("not.a.function", "toLocaleString"); } @@ -814,6 +885,7 @@ public final class NativeArray extends ScriptObject { final Object cmpThis = cmp == null || cmp.isStrict() ? ScriptRuntime.UNDEFINED : Global.instance(); Collections.sort(list, new Comparator() { + private final MethodHandle call_cmp = getCALL_CMP(); @Override public int compare(final Object x, final Object y) { if (x == ScriptRuntime.UNDEFINED && y == ScriptRuntime.UNDEFINED) { @@ -826,7 +898,7 @@ public final class NativeArray extends ScriptObject { if (cmp != null) { try { - return (int)Math.signum((double)CALL_CMP.invokeExact(cmp, cmpThis, x, y)); + return (int)Math.signum((double)call_cmp.invokeExact(cmp, cmpThis, x, y)); } catch (final RuntimeException | Error e) { throw e; } catch (final Throwable t) { @@ -1103,9 +1175,11 @@ public final class NativeArray extends ScriptObject { private static boolean applyEvery(final Object self, final Object callbackfn, final Object thisArg) { return new IteratorAction(Global.toObject(self), callbackfn, thisArg, true) { + private final MethodHandle everyInvoker = getEVERY_CALLBACK_INVOKER(); + @Override protected boolean forEach(final Object val, final long i) throws Throwable { - return (result = (boolean)EVERY_CALLBACK_INVOKER.invokeExact(callbackfn, thisArg, val, i, self)); + return (result = (boolean)everyInvoker.invokeExact(callbackfn, thisArg, val, i, self)); } }.apply(); } @@ -1121,9 +1195,11 @@ public final class NativeArray extends ScriptObject { @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1) public static Object some(final Object self, final Object callbackfn, final Object thisArg) { return new IteratorAction(Global.toObject(self), callbackfn, thisArg, false) { + private final MethodHandle someInvoker = getSOME_CALLBACK_INVOKER(); + @Override protected boolean forEach(final Object val, final long i) throws Throwable { - return !(result = (boolean)SOME_CALLBACK_INVOKER.invokeExact(callbackfn, thisArg, val, i, self)); + return !(result = (boolean)someInvoker.invokeExact(callbackfn, thisArg, val, i, self)); } }.apply(); } @@ -1139,9 +1215,11 @@ public final class NativeArray extends ScriptObject { @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1) public static Object forEach(final Object self, final Object callbackfn, final Object thisArg) { return new IteratorAction(Global.toObject(self), callbackfn, thisArg, ScriptRuntime.UNDEFINED) { + private final MethodHandle forEachInvoker = getFOREACH_CALLBACK_INVOKER(); + @Override protected boolean forEach(final Object val, final long i) throws Throwable { - FOREACH_CALLBACK_INVOKER.invokeExact(callbackfn, thisArg, val, i, self); + forEachInvoker.invokeExact(callbackfn, thisArg, val, i, self); return true; } }.apply(); @@ -1158,9 +1236,11 @@ public final class NativeArray extends ScriptObject { @Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1) public static Object map(final Object self, final Object callbackfn, final Object thisArg) { return new IteratorAction(Global.toObject(self), callbackfn, thisArg, null) { + private final MethodHandle mapInvoker = getMAP_CALLBACK_INVOKER(); + @Override protected boolean forEach(final Object val, final long i) throws Throwable { - final Object r = MAP_CALLBACK_INVOKER.invokeExact(callbackfn, thisArg, val, i, self); + final Object r = mapInvoker.invokeExact(callbackfn, thisArg, val, i, self); result.defineOwnProperty(ArrayIndex.getArrayIndex(index), r); return true; } @@ -1186,10 +1266,11 @@ public final class NativeArray extends ScriptObject { public static Object filter(final Object self, final Object callbackfn, final Object thisArg) { return new IteratorAction(Global.toObject(self), callbackfn, thisArg, new NativeArray()) { private long to = 0; + private final MethodHandle filterInvoker = getFILTER_CALLBACK_INVOKER(); @Override protected boolean forEach(final Object val, final long i) throws Throwable { - if ((boolean)FILTER_CALLBACK_INVOKER.invokeExact(callbackfn, thisArg, val, i, self)) { + if ((boolean)filterInvoker.invokeExact(callbackfn, thisArg, val, i, self)) { result.defineOwnProperty(ArrayIndex.getArrayIndex(to++), val); } return true; @@ -1217,10 +1298,12 @@ public final class NativeArray extends ScriptObject { //if initial value is ScriptRuntime.UNDEFINED - step forward once. return new IteratorAction(Global.toObject(self), callbackfn, ScriptRuntime.UNDEFINED, initialValue, iter) { + private final MethodHandle reduceInvoker = getREDUCE_CALLBACK_INVOKER(); + @Override protected boolean forEach(final Object val, final long i) throws Throwable { // TODO: why can't I declare the second arg as Undefined.class? - result = REDUCE_CALLBACK_INVOKER.invokeExact(callbackfn, ScriptRuntime.UNDEFINED, result, val, i, self); + result = reduceInvoker.invokeExact(callbackfn, ScriptRuntime.UNDEFINED, result, val, i, self); return true; } }.apply(); @@ -1273,10 +1356,4 @@ public final class NativeArray extends ScriptObject { return false; } - - private static MethodHandle createIteratorCallbackInvoker(final Class rtype) { - return Bootstrap.createDynamicInvoker("dyn:call", rtype, Object.class, Object.class, Object.class, - long.class, Object.class); - - } } diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeDate.java b/nashorn/src/jdk/nashorn/internal/objects/NativeDate.java index e12b022ec34..859745f3dca 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeDate.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeDate.java @@ -33,6 +33,7 @@ import static jdk.nashorn.internal.runtime.ECMAErrors.typeError; import java.util.Locale; import java.util.TimeZone; +import java.util.concurrent.Callable; import jdk.nashorn.internal.objects.annotations.Attribute; import jdk.nashorn.internal.objects.annotations.Constructor; import jdk.nashorn.internal.objects.annotations.Function; @@ -95,8 +96,17 @@ public final class NativeDate extends ScriptObject { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; - private static final InvokeByName TO_ISO_STRING = new InvokeByName("toISOString", ScriptObject.class, Object.class, - Object.class); + private static final Object TO_ISO_STRING = new Object(); + + private static InvokeByName getTO_ISO_STRING() { + return Global.instance().getInvokeByName(TO_ISO_STRING, + new Callable() { + @Override + public InvokeByName call() { + return new InvokeByName("toISOString", ScriptObject.class, Object.class, Object.class); + } + }); + } private double time; private final TimeZone timezone; @@ -861,9 +871,10 @@ public final class NativeDate extends ScriptObject { } try { - final Object func = TO_ISO_STRING.getGetter().invokeExact(sobj); + final InvokeByName toIsoString = getTO_ISO_STRING(); + final Object func = toIsoString.getGetter().invokeExact(sobj); if (Bootstrap.isCallable(func)) { - return TO_ISO_STRING.getInvoker().invokeExact(func, sobj, key); + return toIsoString.getInvoker().invokeExact(func, sobj, key); } throw typeError("not.a.function", ScriptRuntime.safeToString(func)); } catch (final RuntimeException | Error e) { diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeJSON.java b/nashorn/src/jdk/nashorn/internal/objects/NativeJSON.java index c7e9f1c0fcc..b2fa46d2b52 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeJSON.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeJSON.java @@ -35,6 +35,7 @@ import java.util.IdentityHashMap; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.concurrent.Callable; import jdk.nashorn.internal.objects.annotations.Attribute; import jdk.nashorn.internal.objects.annotations.Function; import jdk.nashorn.internal.objects.annotations.ScriptClass; @@ -55,9 +56,31 @@ import jdk.nashorn.internal.runtime.linker.InvokeByName; */ @ScriptClass("JSON") public final class NativeJSON extends ScriptObject { - private static final InvokeByName TO_JSON = new InvokeByName("toJSON", ScriptObject.class, Object.class, Object.class); - private static final MethodHandle REPLACER_INVOKER = Bootstrap.createDynamicInvoker("dyn:call", Object.class, - ScriptFunction.class, ScriptObject.class, Object.class, Object.class); + private static final Object TO_JSON = new Object(); + + private static InvokeByName getTO_JSON() { + return Global.instance().getInvokeByName(TO_JSON, + new Callable() { + @Override + public InvokeByName call() { + return new InvokeByName("toJSON", ScriptObject.class, Object.class, Object.class); + } + }); + } + + + private static final Object REPLACER_INVOKER = new Object(); + + private static MethodHandle getREPLACER_INVOKER() { + return Global.instance().getDynamicInvoker(REPLACER_INVOKER, + new Callable() { + @Override + public MethodHandle call() { + return Bootstrap.createDynamicInvoker("dyn:call", Object.class, + ScriptFunction.class, ScriptObject.class, Object.class, Object.class); + } + }); + } // initialized by nasgen @SuppressWarnings("unused") @@ -187,15 +210,16 @@ public final class NativeJSON extends ScriptObject { try { if (value instanceof ScriptObject) { + final InvokeByName toJSONInvoker = getTO_JSON(); final ScriptObject svalue = (ScriptObject)value; - final Object toJSON = TO_JSON.getGetter().invokeExact(svalue); + final Object toJSON = toJSONInvoker.getGetter().invokeExact(svalue); if (Bootstrap.isCallable(toJSON)) { - value = TO_JSON.getInvoker().invokeExact(toJSON, svalue, key); + value = toJSONInvoker.getInvoker().invokeExact(toJSON, svalue, key); } } if (state.replacerFunction != null) { - value = REPLACER_INVOKER.invokeExact(state.replacerFunction, holder, key, value); + value = getREPLACER_INVOKER().invokeExact(state.replacerFunction, holder, key, value); } } catch(Error|RuntimeException t) { throw t; diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeObject.java b/nashorn/src/jdk/nashorn/internal/objects/NativeObject.java index 659040534d4..ff72ce5cd97 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeObject.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeObject.java @@ -36,6 +36,7 @@ import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Set; +import java.util.concurrent.Callable; import jdk.internal.dynalink.beans.BeansLinker; import jdk.internal.dynalink.beans.StaticClass; import jdk.internal.dynalink.linker.GuardedInvocation; @@ -70,7 +71,18 @@ import jdk.nashorn.internal.runtime.linker.InvokeByName; */ @ScriptClass("Object") public final class NativeObject { - private static final InvokeByName TO_STRING = new InvokeByName("toString", ScriptObject.class); + private static final Object TO_STRING = new Object(); + + private static InvokeByName getTO_STRING() { + return Global.instance().getInvokeByName(TO_STRING, + new Callable() { + @Override + public InvokeByName call() { + return new InvokeByName("toString", ScriptObject.class); + } + }); + } + private static final MethodType MIRROR_GETTER_TYPE = MethodType.methodType(Object.class, ScriptObjectMirror.class); private static final MethodType MIRROR_SETTER_TYPE = MethodType.methodType(Object.class, ScriptObjectMirror.class, Object.class); @@ -402,12 +414,13 @@ public final class NativeObject { public static Object toLocaleString(final Object self) { final Object obj = JSType.toScriptObject(self); if (obj instanceof ScriptObject) { + final InvokeByName toStringInvoker = getTO_STRING(); final ScriptObject sobj = (ScriptObject)self; try { - final Object toString = TO_STRING.getGetter().invokeExact(sobj); + final Object toString = toStringInvoker.getGetter().invokeExact(sobj); if (Bootstrap.isCallable(toString)) { - return TO_STRING.getInvoker().invokeExact(toString, sobj); + return toStringInvoker.getInvoker().invokeExact(toString, sobj); } } catch (final RuntimeException | Error e) { throw e; diff --git a/nashorn/src/jdk/nashorn/internal/runtime/GlobalObject.java b/nashorn/src/jdk/nashorn/internal/runtime/GlobalObject.java index 7a118290c71..087b34554bc 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/GlobalObject.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/GlobalObject.java @@ -26,8 +26,10 @@ package jdk.nashorn.internal.runtime; import java.lang.invoke.MethodHandle; +import java.util.concurrent.Callable; import jdk.internal.dynalink.linker.GuardedInvocation; import jdk.internal.dynalink.linker.LinkRequest; +import jdk.nashorn.internal.runtime.linker.InvokeByName; /** * Runtime interface to the global scope objects. @@ -210,4 +212,20 @@ public interface GlobalObject { * @param clazz compiled Class object for the source */ public void cacheClass(Source source, Class clazz); + + /** + * Get cached InvokeByName object for the given key + * @param key key to be associated with InvokeByName object + * @param creator if InvokeByName is absent 'creator' is called to make one (lazy init) + * @return InvokeByName object associated with the key. + */ + public InvokeByName getInvokeByName(final Object key, final Callable creator); + + /** + * Get cached dynamic method handle for the given key + * @param key key to be associated with dynamic method handle + * @param creator if method handle is absent 'creator' is called to make one (lazy init) + * @return dynamic method handle associated with the key. + */ + public MethodHandle getDynamicInvoker(final Object key, final Callable creator); } diff --git a/nashorn/src/jdk/nashorn/internal/runtime/JSONFunctions.java b/nashorn/src/jdk/nashorn/internal/runtime/JSONFunctions.java index 2895cb85644..73552cb10df 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/JSONFunctions.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/JSONFunctions.java @@ -27,6 +27,7 @@ package jdk.nashorn.internal.runtime; import java.lang.invoke.MethodHandle; import java.util.Iterator; +import java.util.concurrent.Callable; import jdk.nashorn.internal.ir.LiteralNode; import jdk.nashorn.internal.ir.Node; import jdk.nashorn.internal.ir.ObjectNode; @@ -42,8 +43,19 @@ import jdk.nashorn.internal.runtime.linker.Bootstrap; */ public final class JSONFunctions { private JSONFunctions() {} - private static final MethodHandle REVIVER_INVOKER = Bootstrap.createDynamicInvoker("dyn:call", Object.class, - ScriptFunction.class, ScriptObject.class, String.class, Object.class); + + private static final Object REVIVER_INVOKER = new Object(); + + private static MethodHandle getREVIVER_INVOKER() { + return ((GlobalObject)Context.getGlobal()).getDynamicInvoker(REVIVER_INVOKER, + new Callable() { + @Override + public MethodHandle call() { + return Bootstrap.createDynamicInvoker("dyn:call", Object.class, + ScriptFunction.class, ScriptObject.class, String.class, Object.class); + } + }); + } /** * Returns JSON-compatible quoted version of the given string. @@ -117,7 +129,7 @@ public final class JSONFunctions { try { // Object.class, ScriptFunction.class, ScriptObject.class, String.class, Object.class); - return REVIVER_INVOKER.invokeExact(reviver, holder, JSType.toString(name), val); + return getREVIVER_INVOKER().invokeExact(reviver, holder, JSType.toString(name), val); } catch(Error|RuntimeException t) { throw t; } catch(final Throwable t) { diff --git a/nashorn/src/jdk/nashorn/internal/runtime/ListAdapter.java b/nashorn/src/jdk/nashorn/internal/runtime/ListAdapter.java index 1d5603f6818..ae6d74461a1 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/ListAdapter.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/ListAdapter.java @@ -31,6 +31,7 @@ import java.util.Iterator; import java.util.ListIterator; import java.util.NoSuchElementException; import java.util.RandomAccess; +import java.util.concurrent.Callable; import jdk.nashorn.internal.runtime.linker.Bootstrap; import jdk.nashorn.internal.runtime.linker.InvokeByName; @@ -49,16 +50,73 @@ import jdk.nashorn.internal.runtime.linker.InvokeByName; */ public final class ListAdapter extends AbstractList implements RandomAccess, Deque { // These add to the back and front of the list - private static final InvokeByName PUSH = new InvokeByName("push", ScriptObject.class, void.class, Object.class); - private static final InvokeByName UNSHIFT = new InvokeByName("unshift", ScriptObject.class, void.class, Object.class); + private static final Object PUSH = new Object(); + private static InvokeByName getPUSH() { + return ((GlobalObject)Context.getGlobal()).getInvokeByName(PUSH, + new Callable() { + @Override + public InvokeByName call() { + return new InvokeByName("push", ScriptObject.class, void.class, Object.class); + } + }); + } + + private static final Object UNSHIFT = new Object(); + private static InvokeByName getUNSHIFT() { + return ((GlobalObject)Context.getGlobal()).getInvokeByName(UNSHIFT, + new Callable() { + @Override + public InvokeByName call() { + return new InvokeByName("unshift", ScriptObject.class, void.class, Object.class); + } + }); + } // These remove from the back and front of the list - private static final InvokeByName POP = new InvokeByName("pop", ScriptObject.class, Object.class); - private static final InvokeByName SHIFT = new InvokeByName("shift", ScriptObject.class, Object.class); + private static final Object POP = new Object(); + private static InvokeByName getPOP() { + return ((GlobalObject)Context.getGlobal()).getInvokeByName(POP, + new Callable() { + @Override + public InvokeByName call() { + return new InvokeByName("pop", ScriptObject.class, Object.class); + } + }); + } + + private static final Object SHIFT = new Object(); + private static InvokeByName getSHIFT() { + return ((GlobalObject)Context.getGlobal()).getInvokeByName(SHIFT, + new Callable() { + @Override + public InvokeByName call() { + return new InvokeByName("shift", ScriptObject.class, Object.class); + } + }); + } // These insert and remove in the middle of the list - private static final InvokeByName SPLICE_ADD = new InvokeByName("splice", ScriptObject.class, void.class, int.class, int.class, Object.class); - private static final InvokeByName SPLICE_REMOVE = new InvokeByName("splice", ScriptObject.class, void.class, int.class, int.class); + private static final Object SPLICE_ADD = new Object(); + private static InvokeByName getSPLICE_ADD() { + return ((GlobalObject)Context.getGlobal()).getInvokeByName(SPLICE_ADD, + new Callable() { + @Override + public InvokeByName call() { + return new InvokeByName("splice", ScriptObject.class, void.class, int.class, int.class, Object.class); + } + }); + } + + private static final Object SPLICE_REMOVE = new Object(); + private static InvokeByName getSPLICE_REMOVE() { + return ((GlobalObject)Context.getGlobal()).getInvokeByName(SPLICE_REMOVE, + new Callable() { + @Override + public InvokeByName call() { + return new InvokeByName("splice", ScriptObject.class, void.class, int.class, int.class); + } + }); + } private final ScriptObject obj; @@ -109,9 +167,10 @@ public final class ListAdapter extends AbstractList implements RandomAcc @Override public void addFirst(Object e) { try { - final Object fn = UNSHIFT.getGetter().invokeExact(obj); - checkFunction(fn, UNSHIFT); - UNSHIFT.getInvoker().invokeExact(fn, obj, e); + final InvokeByName unshiftInvoker = getUNSHIFT(); + final Object fn = unshiftInvoker.getGetter().invokeExact(obj); + checkFunction(fn, unshiftInvoker); + unshiftInvoker.getInvoker().invokeExact(fn, obj, e); } catch(RuntimeException | Error ex) { throw ex; } catch(Throwable t) { @@ -122,9 +181,10 @@ public final class ListAdapter extends AbstractList implements RandomAcc @Override public void addLast(Object e) { try { - final Object fn = PUSH.getGetter().invokeExact(obj); - checkFunction(fn, PUSH); - PUSH.getInvoker().invokeExact(fn, obj, e); + final InvokeByName pushInvoker = getPUSH(); + final Object fn = pushInvoker.getGetter().invokeExact(obj); + checkFunction(fn, pushInvoker); + pushInvoker.getInvoker().invokeExact(fn, obj, e); } catch(RuntimeException | Error ex) { throw ex; } catch(Throwable t) { @@ -142,9 +202,10 @@ public final class ListAdapter extends AbstractList implements RandomAcc } else { final int size = size(); if(index < size) { - final Object fn = SPLICE_ADD.getGetter().invokeExact(obj); - checkFunction(fn, SPLICE_ADD); - SPLICE_ADD.getInvoker().invokeExact(fn, obj, index, 0, e); + final InvokeByName spliceAddInvoker = getSPLICE_ADD(); + final Object fn = spliceAddInvoker.getGetter().invokeExact(obj); + checkFunction(fn, spliceAddInvoker); + spliceAddInvoker.getInvoker().invokeExact(fn, obj, index, 0, e); } else if(index == size) { addLast(e); } else { @@ -234,9 +295,10 @@ public final class ListAdapter extends AbstractList implements RandomAcc private Object invokeShift() { try { - final Object fn = SHIFT.getGetter().invokeExact(obj); - checkFunction(fn, SHIFT); - return SHIFT.getInvoker().invokeExact(fn, obj); + final InvokeByName shiftInvoker = getSHIFT(); + final Object fn = shiftInvoker.getGetter().invokeExact(obj); + checkFunction(fn, shiftInvoker); + return shiftInvoker.getInvoker().invokeExact(fn, obj); } catch(RuntimeException | Error ex) { throw ex; } catch(Throwable t) { @@ -246,9 +308,10 @@ public final class ListAdapter extends AbstractList implements RandomAcc private Object invokePop() { try { - final Object fn = POP.getGetter().invokeExact(obj); - checkFunction(fn, POP); - return POP.getInvoker().invokeExact(fn, obj); + final InvokeByName popInvoker = getPOP(); + final Object fn = popInvoker.getGetter().invokeExact(obj); + checkFunction(fn, popInvoker); + return popInvoker.getInvoker().invokeExact(fn, obj); } catch(RuntimeException | Error ex) { throw ex; } catch(Throwable t) { @@ -263,9 +326,10 @@ public final class ListAdapter extends AbstractList implements RandomAcc private void invokeSpliceRemove(int fromIndex, int count) { try { - final Object fn = SPLICE_REMOVE.getGetter().invokeExact(obj); - checkFunction(fn, SPLICE_REMOVE); - SPLICE_REMOVE.getInvoker().invokeExact(fn, obj, fromIndex, count); + final InvokeByName spliceRemoveInvoker = getSPLICE_REMOVE(); + final Object fn = spliceRemoveInvoker.getGetter().invokeExact(obj); + checkFunction(fn, spliceRemoveInvoker); + spliceRemoveInvoker.getInvoker().invokeExact(fn, obj, fromIndex, count); } catch(RuntimeException | Error ex) { throw ex; } catch(Throwable t) { diff --git a/nashorn/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java b/nashorn/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java index 226d83d1b76..859a688c1ba 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java @@ -52,13 +52,19 @@ import jdk.nashorn.internal.parser.TokenType; public final class RecompilableScriptFunctionData extends ScriptFunctionData { /** FunctionNode with the code for this ScriptFunction */ - private FunctionNode functionNode; + private volatile FunctionNode functionNode; + + /** Source from which FunctionNode was parsed. */ + private final Source source; + + /** Token of this function within the source. */ + private final long token; /** Allocator map from makeMap() */ private final PropertyMap allocatorMap; /** Code installer used for all further recompilation/specialization of this ScriptFunction */ - private final CodeInstaller installer; + private volatile CodeInstaller installer; /** Name of class where allocator function resides */ private final String allocatorClassName; @@ -103,6 +109,8 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData { true); this.functionNode = functionNode; + this.source = functionNode.getSource(); + this.token = tokenFor(functionNode); this.installer = installer; this.allocatorClassName = allocatorClassName; this.allocatorMap = allocatorMap; @@ -110,9 +118,6 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData { @Override String toSource() { - final Source source = functionNode.getSource(); - final long token = tokenFor(functionNode); - if (source != null && token != 0) { return source.getString(Token.descPosition(token), Token.descLength(token)); } @@ -123,8 +128,6 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData { @Override public String toString() { final StringBuilder sb = new StringBuilder(); - final Source source = functionNode.getSource(); - final long token = tokenFor(functionNode); if (source != null) { sb.append(source.getName()) @@ -190,6 +193,12 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData { // code exists - look it up and add it into the automatically sorted invoker list addCode(functionNode); + + if (! functionNode.canSpecialize()) { + // allow GC to claim IR stuff that is not needed anymore + functionNode = null; + installer = null; + } } private MethodHandle addCode(final FunctionNode fn) { @@ -325,7 +334,7 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData { * footprint too large to store a parse snapshot, or if it is meaningless * to do so, such as e.g. for runScript */ - if (!functionNode.canSpecialize()) { + if (functionNode == null || !functionNode.canSpecialize()) { return mh; } diff --git a/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunction.java b/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunction.java index 50f2b074c45..564f1946810 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunction.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunction.java @@ -496,32 +496,24 @@ public abstract class ScriptFunction extends ScriptObject { MethodHandle boundHandle; MethodHandle guard = null; + final boolean scopeCall = NashornCallSiteDescriptor.isScope(desc); + if (data.needsCallee()) { final MethodHandle callHandle = getBestInvoker(type, request.getArguments()); - if (NashornCallSiteDescriptor.isScope(desc)) { + if (scopeCall) { // Make a handle that drops the passed "this" argument and substitutes either Global or Undefined // (callee, this, args...) => (callee, args...) boundHandle = MH.insertArguments(callHandle, 1, needsWrappedThis() ? Context.getGlobalTrusted() : ScriptRuntime.UNDEFINED); // (callee, args...) => (callee, [this], args...) boundHandle = MH.dropArguments(boundHandle, 1, Object.class); + } else { // It's already (callee, this, args...), just what we need boundHandle = callHandle; - - // For non-strict functions, check whether this-object is primitive type. - // If so add a to-object-wrapper argument filter. - // Else install a guard that will trigger a relink when the argument becomes primitive. - if (needsWrappedThis()) { - if (ScriptFunctionData.isPrimitiveThis(request.getArguments()[1])) { - boundHandle = MH.filterArguments(boundHandle, 1, WRAPFILTER); - } else { - guard = getNonStrictFunctionGuard(this); - } - } } } else { final MethodHandle callHandle = getBestInvoker(type.dropParameterTypes(0, 1), request.getArguments()); - if (NashornCallSiteDescriptor.isScope(desc)) { + if (scopeCall) { // Make a handle that drops the passed "this" argument and substitutes either Global or Undefined // (this, args...) => (args...) boundHandle = MH.bindTo(callHandle, needsWrappedThis() ? Context.getGlobalTrusted() : ScriptRuntime.UNDEFINED); @@ -533,6 +525,17 @@ public abstract class ScriptFunction extends ScriptObject { } } + // For non-strict functions, check whether this-object is primitive type. + // If so add a to-object-wrapper argument filter. + // Else install a guard that will trigger a relink when the argument becomes primitive. + if (!scopeCall && needsWrappedThis()) { + if (ScriptFunctionData.isPrimitiveThis(request.getArguments()[1])) { + boundHandle = MH.filterArguments(boundHandle, 1, WRAPFILTER); + } else { + guard = getNonStrictFunctionGuard(this); + } + } + boundHandle = pairArguments(boundHandle, type); return new GuardedInvocation(boundHandle, guard == null ? getFunctionGuard(this) : guard); diff --git a/nashorn/src/jdk/nashorn/internal/runtime/UserAccessorProperty.java b/nashorn/src/jdk/nashorn/internal/runtime/UserAccessorProperty.java index 7f4659c00ce..931d712b9aa 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/UserAccessorProperty.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/UserAccessorProperty.java @@ -27,6 +27,7 @@ package jdk.nashorn.internal.runtime; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; +import java.util.concurrent.Callable; import jdk.nashorn.internal.codegen.CompilerConstants; import jdk.nashorn.internal.lookup.Lookup; @@ -68,12 +69,32 @@ public final class UserAccessorProperty extends Property { "userAccessorSetter", void.class, ScriptObject.class, int.class, String.class, Object.class, Object.class); /** Dynamic invoker for getter */ - private static final MethodHandle INVOKE_UA_GETTER = Bootstrap.createDynamicInvoker("dyn:call", Object.class, - Object.class, Object.class); + private static final Object INVOKE_UA_GETTER = new Object(); + + private static MethodHandle getINVOKE_UA_GETTER() { + + return ((GlobalObject)Context.getGlobal()).getDynamicInvoker(INVOKE_UA_GETTER, + new Callable() { + @Override + public MethodHandle call() { + return Bootstrap.createDynamicInvoker("dyn:call", Object.class, + Object.class, Object.class); + } + }); + } /** Dynamic invoker for setter */ - private static final MethodHandle INVOKE_UA_SETTER = Bootstrap.createDynamicInvoker("dyn:call", void.class, - Object.class, Object.class, Object.class); + private static Object INVOKE_UA_SETTER = new Object(); + private static MethodHandle getINVOKE_UA_SETTER() { + return ((GlobalObject)Context.getGlobal()).getDynamicInvoker(INVOKE_UA_SETTER, + new Callable() { + @Override + public MethodHandle call() { + return Bootstrap.createDynamicInvoker("dyn:call", void.class, + Object.class, Object.class, Object.class); + } + }); + } /** * Constructor @@ -191,7 +212,7 @@ public final class UserAccessorProperty extends Property { if (func instanceof ScriptFunction) { try { - return INVOKE_UA_GETTER.invokeExact(func, self); + return getINVOKE_UA_GETTER().invokeExact(func, self); } catch(final Error|RuntimeException t) { throw t; } catch(final Throwable t) { @@ -208,7 +229,7 @@ public final class UserAccessorProperty extends Property { if (func instanceof ScriptFunction) { try { - INVOKE_UA_SETTER.invokeExact(func, self, value); + getINVOKE_UA_SETTER().invokeExact(func, self, value); } catch(final Error|RuntimeException t) { throw t; } catch(final Throwable t) { diff --git a/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterClassLoader.java b/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterClassLoader.java index 73c0563631d..059ed552a64 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterClassLoader.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterClassLoader.java @@ -48,13 +48,20 @@ final class JavaAdapterClassLoader { private static final ProtectionDomain GENERATED_PROTECTION_DOMAIN = createGeneratedProtectionDomain(); private final String className; - private final byte[] classBytes; + private volatile byte[] classBytes; JavaAdapterClassLoader(String className, byte[] classBytes) { this.className = className.replace('/', '.'); this.classBytes = classBytes; } + /** + * clear classBytes after loading class. + */ + void clearClassBytes() { + this.classBytes = null; + } + /** * Loads the generated adapter class into the JVM. * @param parentLoader the parent class loader for the generated class loader @@ -103,6 +110,7 @@ final class JavaAdapterClassLoader { @Override protected Class findClass(final String name) throws ClassNotFoundException { if(name.equals(className)) { + assert classBytes != null : "what? already cleared .class bytes!!"; return defineClass(name, classBytes, 0, classBytes.length, GENERATED_PROTECTION_DOMAIN); } else { throw new ClassNotFoundException(name); diff --git a/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterFactory.java b/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterFactory.java index 93c2dd391a0..4c005a273e8 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterFactory.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterFactory.java @@ -224,7 +224,10 @@ public final class JavaAdapterFactory { this.commonLoader = findCommonLoader(definingLoader); final JavaAdapterBytecodeGenerator gen = new JavaAdapterBytecodeGenerator(superClass, interfaces, commonLoader, false); this.autoConvertibleFromFunction = gen.isAutoConvertibleFromFunction(); - this.instanceAdapterClass = gen.createAdapterClassLoader().generateClass(commonLoader); + final JavaAdapterClassLoader jacl = gen.createAdapterClassLoader(); + this.instanceAdapterClass = jacl.generateClass(commonLoader); + // loaded Class - no need to keep class bytes around + jacl.clearClassBytes(); this.adapterGenerator = new JavaAdapterBytecodeGenerator(superClass, interfaces, commonLoader, true).createAdapterClassLoader(); this.adaptationResult = AdaptationResult.SUCCESSFUL_RESULT; } diff --git a/nashorn/test/script/basic/JDK-8020357.js b/nashorn/test/script/basic/JDK-8020357.js index e74bca8ab0e..694063713bf 100644 --- a/nashorn/test/script/basic/JDK-8020357.js +++ b/nashorn/test/script/basic/JDK-8020357.js @@ -33,17 +33,6 @@ var BYTES_PER_INT_32 = 4 var limit = Math.pow(2, UNSIGNED_INT_BITS)/BYTES_PER_INT_32 -try { - // A value at or under the limit should either succeed if we have - // enough heap, or throw an OutOfMemoryError if we don't. - Int32Array(limit - 1) -} catch(e) { - if(!(e instanceof java.lang.OutOfMemoryError)) { - // Only print an unexpected result; OutOfMemoryError is expected - print(e) - } -} - // A value over the limit should throw a RangeError. try { Int32Array(limit) diff --git a/nashorn/test/src/jdk/nashorn/api/javaaccess/BooleanAccessTest.java b/nashorn/test/src/jdk/nashorn/api/javaaccess/BooleanAccessTest.java index 030bb1e522c..198735648ff 100644 --- a/nashorn/test/src/jdk/nashorn/api/javaaccess/BooleanAccessTest.java +++ b/nashorn/test/src/jdk/nashorn/api/javaaccess/BooleanAccessTest.java @@ -33,6 +33,7 @@ import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; import javax.script.ScriptException; import org.testng.TestNG; +import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; @@ -44,7 +45,7 @@ import org.testng.annotations.Test; public class BooleanAccessTest { private static ScriptEngine e = null; - private static SharedObject o = new SharedObject(); + private static SharedObject o = null; public static void main(final String[] args) { TestNG.main(args); @@ -54,10 +55,17 @@ public class BooleanAccessTest { public static void setUpClass() throws ScriptException { final ScriptEngineManager m = new ScriptEngineManager(); e = m.getEngineByName("nashorn"); + o = new SharedObject(); e.put("o", o); e.eval("var SharedObject = Packages.jdk.nashorn.api.javaaccess.SharedObject;"); } + @AfterClass + public static void tearDownClass() { + e = null; + o = null; + } + @Test public void accessFieldBoolean() throws ScriptException { e.eval("var p_boolean = o.publicBoolean;"); diff --git a/nashorn/test/src/jdk/nashorn/api/javaaccess/MethodAccessTest.java b/nashorn/test/src/jdk/nashorn/api/javaaccess/MethodAccessTest.java index 6de10a54783..14207b7df47 100644 --- a/nashorn/test/src/jdk/nashorn/api/javaaccess/MethodAccessTest.java +++ b/nashorn/test/src/jdk/nashorn/api/javaaccess/MethodAccessTest.java @@ -36,6 +36,7 @@ import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; import javax.script.ScriptException; import org.testng.TestNG; +import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; @@ -47,7 +48,7 @@ import org.testng.annotations.Test; public class MethodAccessTest { private static ScriptEngine e = null; - private static SharedObject o = new SharedObject(); + private static SharedObject o = null; public static void main(final String[] args) { TestNG.main(args); @@ -57,12 +58,19 @@ public class MethodAccessTest { public static void setUpClass() throws ScriptException { final ScriptEngineManager m = new ScriptEngineManager(); e = m.getEngineByName("nashorn"); + o = new SharedObject(); o.setEngine(e); e.put("o", o); e.eval("var SharedObject = Packages.jdk.nashorn.api.javaaccess.SharedObject;"); e.eval("var Person = Packages.jdk.nashorn.api.javaaccess.Person;"); } + @AfterClass + public static void tearDownClass() { + e = null; + o = null; + } + @Test public void accessMethodthrowsCheckedException() throws ScriptException { e.eval("try {" + diff --git a/nashorn/test/src/jdk/nashorn/api/javaaccess/NumberAccessTest.java b/nashorn/test/src/jdk/nashorn/api/javaaccess/NumberAccessTest.java index 49f193e91bc..116d1cf4667 100644 --- a/nashorn/test/src/jdk/nashorn/api/javaaccess/NumberAccessTest.java +++ b/nashorn/test/src/jdk/nashorn/api/javaaccess/NumberAccessTest.java @@ -33,6 +33,7 @@ import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; import javax.script.ScriptException; import org.testng.TestNG; +import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; @@ -44,7 +45,7 @@ import org.testng.annotations.Test; public class NumberAccessTest { private static ScriptEngine e = null; - private static SharedObject o = new SharedObject(); + private static SharedObject o = null; public static void main(final String[] args) { TestNG.main(args); @@ -54,10 +55,17 @@ public class NumberAccessTest { public static void setUpClass() throws ScriptException { final ScriptEngineManager m = new ScriptEngineManager(); e = m.getEngineByName("nashorn"); + o = new SharedObject(); e.put("o", o); e.eval("var SharedObject = Packages.jdk.nashorn.api.javaaccess.SharedObject;"); } + @AfterClass + public static void tearDownClass() { + e = null; + o = null; + } + // --------------------------------long // tests------------------------------------ @Test diff --git a/nashorn/test/src/jdk/nashorn/api/javaaccess/NumberBoxingTest.java b/nashorn/test/src/jdk/nashorn/api/javaaccess/NumberBoxingTest.java index 0302259e95b..03e30752a7f 100644 --- a/nashorn/test/src/jdk/nashorn/api/javaaccess/NumberBoxingTest.java +++ b/nashorn/test/src/jdk/nashorn/api/javaaccess/NumberBoxingTest.java @@ -32,6 +32,7 @@ import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; import javax.script.ScriptException; import org.testng.TestNG; +import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; @@ -43,7 +44,7 @@ import org.testng.annotations.Test; public class NumberBoxingTest { private static ScriptEngine e = null; - private static SharedObject o = new SharedObject(); + private static SharedObject o = null; public static void main(final String[] args) { TestNG.main(args); @@ -53,10 +54,17 @@ public class NumberBoxingTest { public static void setUpClass() throws ScriptException { final ScriptEngineManager m = new ScriptEngineManager(); e = m.getEngineByName("nashorn"); + o = new SharedObject(); e.put("o", o); e.eval("var SharedObject = Packages.jdk.nashorn.api.javaaccess.SharedObject;"); } + @AfterClass + public static void tearDownClass() { + e = null; + o = null; + } + // --------------------------------long // tests------------------------------------ @Test diff --git a/nashorn/test/src/jdk/nashorn/api/javaaccess/ObjectAccessTest.java b/nashorn/test/src/jdk/nashorn/api/javaaccess/ObjectAccessTest.java index de0fd8ee152..9c1fa114aea 100644 --- a/nashorn/test/src/jdk/nashorn/api/javaaccess/ObjectAccessTest.java +++ b/nashorn/test/src/jdk/nashorn/api/javaaccess/ObjectAccessTest.java @@ -32,6 +32,7 @@ import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; import javax.script.ScriptException; import org.testng.TestNG; +import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; @@ -43,7 +44,7 @@ import org.testng.annotations.Test; public class ObjectAccessTest { private static ScriptEngine e = null; - private static SharedObject o = new SharedObject(); + private static SharedObject o = null; public static void main(final String[] args) { TestNG.main(args); @@ -53,11 +54,18 @@ public class ObjectAccessTest { public static void setUpClass() throws ScriptException { final ScriptEngineManager m = new ScriptEngineManager(); e = m.getEngineByName("nashorn"); + o = new SharedObject(); e.put("o", o); e.eval("var SharedObject = Packages.jdk.nashorn.api.javaaccess.SharedObject;"); e.eval("var Person = Packages.jdk.nashorn.api.javaaccess.Person;"); } + @AfterClass + public static void tearDownClass() { + e = null; + o = null; + } + @Test public void accessFieldObject() throws ScriptException { e.eval("var p_object = o.publicObject;"); diff --git a/nashorn/test/src/jdk/nashorn/api/javaaccess/StringAccessTest.java b/nashorn/test/src/jdk/nashorn/api/javaaccess/StringAccessTest.java index 55624360824..7b6a11f14a3 100644 --- a/nashorn/test/src/jdk/nashorn/api/javaaccess/StringAccessTest.java +++ b/nashorn/test/src/jdk/nashorn/api/javaaccess/StringAccessTest.java @@ -32,6 +32,7 @@ import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; import javax.script.ScriptException; import org.testng.TestNG; +import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; @@ -43,7 +44,7 @@ import org.testng.annotations.Test; public class StringAccessTest { private static ScriptEngine e = null; - private static SharedObject o = new SharedObject(); + private static SharedObject o = null; public static void main(final String[] args) { TestNG.main(args); @@ -53,10 +54,17 @@ public class StringAccessTest { public static void setUpClass() throws ScriptException { final ScriptEngineManager m = new ScriptEngineManager(); e = m.getEngineByName("nashorn"); + o = new SharedObject(); e.put("o", o); e.eval("var SharedObject = Packages.jdk.nashorn.api.javaaccess.SharedObject;"); } + @AfterClass + public static void tearDownClass() { + e = null; + o = null; + } + @Test public void accessFieldString() throws ScriptException { e.eval("var p_string = o.publicString;"); diff --git a/nashorn/test/src/jdk/nashorn/internal/codegen/CompilerTest.java b/nashorn/test/src/jdk/nashorn/internal/codegen/CompilerTest.java index 3cbe1ed4152..00d79acbda9 100644 --- a/nashorn/test/src/jdk/nashorn/internal/codegen/CompilerTest.java +++ b/nashorn/test/src/jdk/nashorn/internal/codegen/CompilerTest.java @@ -35,6 +35,8 @@ import jdk.nashorn.internal.runtime.ScriptObject; import jdk.nashorn.internal.runtime.Source; import jdk.nashorn.internal.runtime.options.Options; import org.testng.Assert; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; /** @@ -58,7 +60,8 @@ public class CompilerTest { private Context context; private ScriptObject global; - public CompilerTest() { + @BeforeClass + public void setupTest() { final Options options = new Options("nashorn"); options.set("anon.functions", true); options.set("compile.only", true); @@ -79,6 +82,12 @@ public class CompilerTest { this.global = context.createGlobal(); } + @AfterClass + public void tearDownTest() { + this.context = null; + this.global = null; + } + @Test public void compileAllTests() { if (TEST262) { diff --git a/nashorn/test/src/jdk/nashorn/internal/parser/ParserTest.java b/nashorn/test/src/jdk/nashorn/internal/parser/ParserTest.java index afffe0516d8..3e10a89e857 100644 --- a/nashorn/test/src/jdk/nashorn/internal/parser/ParserTest.java +++ b/nashorn/test/src/jdk/nashorn/internal/parser/ParserTest.java @@ -28,10 +28,11 @@ package jdk.nashorn.internal.parser; import java.io.File; import jdk.nashorn.internal.runtime.Context; import jdk.nashorn.internal.runtime.ErrorManager; -import jdk.nashorn.internal.runtime.ScriptObject; import jdk.nashorn.internal.runtime.Source; import jdk.nashorn.internal.runtime.options.Options; import org.testng.Assert; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; /** @@ -54,9 +55,9 @@ public class ParserTest { } private Context context; - private ScriptObject global; - public ParserTest() { + @BeforeClass + public void setupTest() { final Options options = new Options("nashorn"); options.set("anon.functions", true); options.set("parse.only", true); @@ -64,7 +65,11 @@ public class ParserTest { ErrorManager errors = new ErrorManager(); this.context = new Context(options, errors, Thread.currentThread().getContextClassLoader()); - this.global = context.createGlobal(); + } + + @AfterClass + public void tearDownTest() { + this.context = null; } @Test @@ -125,8 +130,6 @@ public class ParserTest { log("Begin parsing " + file.getAbsolutePath()); } - final ScriptObject oldGlobal = Context.getGlobal(); - final boolean globalChanged = (oldGlobal != global); try { final char[] buffer = Source.readFully(file); boolean excluded = false; @@ -150,9 +153,6 @@ public class ParserTest { } }; errors.setLimit(0); - if (globalChanged) { - Context.setGlobal(global); - } final Source source = new Source(file.getAbsolutePath(), buffer); new Parser(context.getEnv(), source, errors).parse(); if (errors.getNumberOfErrors() > 0) { @@ -167,10 +167,6 @@ public class ParserTest { exp.printStackTrace(System.out); } failed++; - } finally { - if (globalChanged) { - Context.setGlobal(oldGlobal); - } } if (VERBOSE) { From 8ee7468a8c75b503078396d5f71f6f967104fbef Mon Sep 17 00:00:00 2001 From: Athijegannathan Sundararajan Date: Fri, 9 Aug 2013 20:48:44 +0530 Subject: [PATCH 013/218] 8022707: Revisit all doPrivileged blocks Reviewed-by: jlaskey, hannesw --- nashorn/make/project.properties | 11 +++- .../api/scripting/NashornScriptEngine.java | 33 ++++++----- .../scripting/NashornScriptEngineFactory.java | 12 +++- .../api/scripting/ScriptObjectMirror.java | 15 ++++- .../jdk/nashorn/internal/objects/Global.java | 22 +++---- .../nashorn/internal/objects/NativeDebug.java | 2 +- .../jdk/nashorn/internal/runtime/Context.java | 57 ++++++++++++++++--- .../nashorn/internal/runtime/ECMAErrors.java | 11 +--- .../jdk/nashorn/internal/runtime/Logging.java | 24 ++++++-- .../runtime/linker/ClassAndLoader.java | 15 ++++- .../linker/JavaAdapterBytecodeGenerator.java | 5 +- .../linker/JavaAdapterClassLoader.java | 4 +- .../runtime/linker/JavaAdapterFactory.java | 33 ++++++----- .../runtime/linker/ReflectionCheckLinker.java | 2 +- .../internal/runtime/options/Options.java | 29 ++++++---- nashorn/src/jdk/nashorn/tools/Shell.java | 15 +---- 16 files changed, 185 insertions(+), 105 deletions(-) diff --git a/nashorn/make/project.properties b/nashorn/make/project.properties index 081e27b2f2a..5523f6cbab8 100644 --- a/nashorn/make/project.properties +++ b/nashorn/make/project.properties @@ -222,11 +222,16 @@ run.test.xms=2G run.test.user.language=tr run.test.user.country=TR -# -XX:+PrintCompilation -XX:+UnlockDiagnosticVMOptions -XX:+PrintNMethods -run.test.jvmargs.main=-server -Xmx${run.test.xmx} -XX:+TieredCompilation -ea -Dfile.encoding=UTF-8 -Duser.language=${run.test.user.language} -Duser.country=${run.test.user.country} -XX:+HeapDumpOnOutOfMemoryError +run.test.jvmargs.common=-server -Xmx${run.test.xmx} -XX:+TieredCompilation -Dfile.encoding=UTF-8 -Duser.language=${run.test.user.language} -Duser.country=${run.test.user.country} -XX:+HeapDumpOnOutOfMemoryError + +#-XX:-UseCompressedKlassPointers -XX:+PrintHeapAtGC -XX:ClassMetaspaceSize=300M +# -XX:+PrintCompilation -XX:+UnlockDiagnosticVMOptions -XX:+PrintNMethods + +# turn on assertions for tests +run.test.jvmargs.main=${run.test.jvmargs.common} -ea #-XX:-UseCompressedKlassPointers -XX:+PrintHeapAtGC -XX:ClassMetaspaceSize=300M -run.test.jvmargs.octane.main=-Xms${run.test.xms} ${run.test.jvmargs.main} +run.test.jvmargs.octane.main=-Xms${run.test.xms} ${run.test.jvmargs.common} run.test.jvmsecurityargs=-Xverify:all -Djava.security.properties=${basedir}/make/java.security.override -Djava.security.manager -Djava.security.policy=${basedir}/build/nashorn.policy diff --git a/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngine.java b/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngine.java index 5b79846b011..063bc08fd70 100644 --- a/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngine.java +++ b/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngine.java @@ -36,10 +36,13 @@ import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.net.URL; import java.nio.charset.Charset; +import java.security.AccessControlContext; import java.security.AccessController; +import java.security.Permissions; import java.security.PrivilegedAction; import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; +import java.security.ProtectionDomain; import java.text.MessageFormat; import java.util.Locale; import java.util.ResourceBundle; @@ -71,6 +74,14 @@ import jdk.nashorn.internal.runtime.options.Options; */ public final class NashornScriptEngine extends AbstractScriptEngine implements Compilable, Invocable { + private static AccessControlContext createPermAccCtxt(final String permName) { + final Permissions perms = new Permissions(); + perms.add(new RuntimePermission(permName)); + return new AccessControlContext(new ProtectionDomain[] { new ProtectionDomain(null, perms) }); + } + + private static final AccessControlContext CREATE_CONTEXT_ACC_CTXT = createPermAccCtxt(Context.NASHORN_CREATE_CONTEXT); + private static final AccessControlContext CREATE_GLOBAL_ACC_CTXT = createPermAccCtxt(Context.NASHORN_CREATE_GLOBAL); private final ScriptEngineFactory factory; private final Context nashornContext; @@ -84,16 +95,9 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C private static final String MESSAGES_RESOURCE = "jdk.nashorn.api.scripting.resources.Messages"; - // Without do privileged, under security manager messages can not be loaded. private static final ResourceBundle MESSAGES_BUNDLE; static { - MESSAGES_BUNDLE = AccessController.doPrivileged( - new PrivilegedAction() { - @Override - public ResourceBundle run() { - return ResourceBundle.getBundle(MESSAGES_RESOURCE, Locale.getDefault()); - } - }); + MESSAGES_BUNDLE = ResourceBundle.getBundle(MESSAGES_RESOURCE, Locale.getDefault()); } private static String getMessage(final String msgId, final String... args) { @@ -128,7 +132,7 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C throw e; } } - }); + }, CREATE_CONTEXT_ACC_CTXT); // create new global object this.global = createNashornGlobal(); @@ -340,7 +344,7 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C throw e; } } - }); + }, CREATE_GLOBAL_ACC_CTXT); nashornContext.initGlobal(newGlobal); @@ -362,10 +366,8 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C } private void evalEngineScript() throws ScriptException { - evalSupportScript("resources/engine.js", NashornException.ENGINE_SCRIPT_SOURCE_NAME); - } - - private void evalSupportScript(final String script, final String name) throws ScriptException { + final String script = "resources/engine.js"; + final String name = NashornException.ENGINE_SCRIPT_SOURCE_NAME; try { final InputStream is = AccessController.doPrivileged( new PrivilegedExceptionAction() { @@ -380,6 +382,9 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C eval(isr); } } catch (final PrivilegedActionException | IOException e) { + if (Context.DEBUG) { + e.printStackTrace(); + } throw new ScriptException(e); } finally { put(ScriptEngine.FILENAME, null); diff --git a/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngineFactory.java b/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngineFactory.java index c10054158fe..beb0c2a0fef 100644 --- a/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngineFactory.java +++ b/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngineFactory.java @@ -30,6 +30,7 @@ import java.util.Collections; import java.util.List; import javax.script.ScriptEngine; import javax.script.ScriptEngineFactory; +import jdk.nashorn.internal.runtime.Context; import jdk.nashorn.internal.runtime.Version; /** @@ -136,7 +137,14 @@ public final class NashornScriptEngineFactory implements ScriptEngineFactory { @Override public ScriptEngine getScriptEngine() { - return new NashornScriptEngine(this, getAppClassLoader()); + try { + return new NashornScriptEngine(this, getAppClassLoader()); + } catch (final RuntimeException e) { + if (Context.DEBUG) { + e.printStackTrace(); + } + throw e; + } } /** @@ -178,7 +186,7 @@ public final class NashornScriptEngineFactory implements ScriptEngineFactory { private static void checkConfigPermission() { final SecurityManager sm = System.getSecurityManager(); if (sm != null) { - sm.checkPermission(new RuntimePermission("nashorn.setConfig")); + sm.checkPermission(new RuntimePermission(Context.NASHORN_SET_CONFIG)); } } diff --git a/nashorn/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java b/nashorn/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java index 7abf142c9b8..fd2ef88a199 100644 --- a/nashorn/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java +++ b/nashorn/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java @@ -25,14 +25,17 @@ package jdk.nashorn.api.scripting; +import java.security.AccessControlContext; import java.security.AccessController; +import java.security.Permissions; import java.security.PrivilegedAction; +import java.security.ProtectionDomain; import java.util.AbstractMap; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; -import java.util.LinkedHashSet; import java.util.Iterator; +import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; @@ -49,6 +52,14 @@ import jdk.nashorn.internal.runtime.ScriptRuntime; * netscape.javascript.JSObject interface. */ public final class ScriptObjectMirror extends JSObject implements Bindings { + private static AccessControlContext getContextAccCtxt() { + final Permissions perms = new Permissions(); + perms.add(new RuntimePermission(Context.NASHORN_GET_CONTEXT)); + return new AccessControlContext(new ProtectionDomain[] { new ProtectionDomain(null, perms) }); + } + + private static final AccessControlContext GET_CONTEXT_ACC_CTXT = getContextAccCtxt(); + private final ScriptObject sobj; private final ScriptObject global; @@ -144,7 +155,7 @@ public final class ScriptObjectMirror extends JSObject implements Bindings { public Context run() { return Context.getContext(); } - }); + }, GET_CONTEXT_ACC_CTXT); return wrap(context.eval(global, s, null, null, false), global); } }); diff --git a/nashorn/src/jdk/nashorn/internal/objects/Global.java b/nashorn/src/jdk/nashorn/internal/objects/Global.java index 891e0d7ced5..6d7be378be6 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/Global.java +++ b/nashorn/src/jdk/nashorn/internal/objects/Global.java @@ -35,8 +35,6 @@ import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.ref.SoftReference; import java.lang.reflect.Field; -import java.security.AccessController; -import java.security.PrivilegedAction; import java.util.Arrays; import java.util.LinkedHashMap; import java.util.List; @@ -420,7 +418,7 @@ public final class Global extends ScriptObject implements GlobalObject, Scope { // security check first final SecurityManager sm = System.getSecurityManager(); if (sm != null) { - sm.checkPermission(new RuntimePermission("nashorn.newGlobal")); + sm.checkPermission(new RuntimePermission(Context.NASHORN_CREATE_GLOBAL)); } // null check on context @@ -1780,19 +1778,13 @@ public final class Global extends ScriptObject implements GlobalObject, Scope { } private static void copyOptions(final ScriptObject options, final ScriptEnvironment scriptEnv) { - AccessController.doPrivileged(new PrivilegedAction() { - @Override - public Void run() { - for (Field f : scriptEnv.getClass().getFields()) { - try { - options.set(f.getName(), f.get(scriptEnv), false); - } catch (final IllegalArgumentException | IllegalAccessException exp) { - throw new RuntimeException(exp); - } - } - return null; + for (Field f : scriptEnv.getClass().getFields()) { + try { + options.set(f.getName(), f.get(scriptEnv), false); + } catch (final IllegalArgumentException | IllegalAccessException exp) { + throw new RuntimeException(exp); } - }); + } } private void initTypedArray() { diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeDebug.java b/nashorn/src/jdk/nashorn/internal/objects/NativeDebug.java index 82757cbae51..9ee7c99a7f7 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeDebug.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeDebug.java @@ -72,7 +72,7 @@ public final class NativeDebug extends ScriptObject { public static Object getContext(final Object self) { final SecurityManager sm = System.getSecurityManager(); if (sm != null) { - sm.checkPermission(new RuntimePermission("nashorn.getContext")); + sm.checkPermission(new RuntimePermission(Context.NASHORN_GET_CONTEXT)); } return Global.getThisContext(); } diff --git a/nashorn/src/jdk/nashorn/internal/runtime/Context.java b/nashorn/src/jdk/nashorn/internal/runtime/Context.java index b0e2f15fb66..8ff85b93be3 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/Context.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/Context.java @@ -64,6 +64,31 @@ import jdk.nashorn.internal.runtime.options.Options; * This class manages the global state of execution. Context is immutable. */ public final class Context { + // nashorn specific security runtime access permission names + /** + * Permission needed to pass arbitrary nashorn command line options when creating Context. + */ + public static final String NASHORN_SET_CONFIG = "nashorn.setConfig"; + + /** + * Permission needed to create Nashorn Context instance. + */ + public static final String NASHORN_CREATE_CONTEXT = "nashorn.createContext"; + + /** + * Permission needed to create Nashorn Global instance. + */ + public static final String NASHORN_CREATE_GLOBAL = "nashorn.createGlobal"; + + /** + * Permission to get current Nashorn Context from thread local storage. + */ + public static final String NASHORN_GET_CONTEXT = "nashorn.getContext"; + + /** + * Permission to use Java reflection/jsr292 from script code. + */ + public static final String NASHORN_JAVA_REFLECTION = "nashorn.JavaReflection"; /** * ContextCodeInstaller that has the privilege of installing classes in the Context. @@ -139,7 +164,7 @@ public final class Context { public static Context getContext() { final SecurityManager sm = System.getSecurityManager(); if (sm != null) { - sm.checkPermission(new RuntimePermission("nashorn.getContext")); + sm.checkPermission(new RuntimePermission(NASHORN_GET_CONTEXT)); } return getContextTrusted(); } @@ -204,7 +229,20 @@ public final class Context { private static final ClassLoader myLoader = Context.class.getClassLoader(); private static final StructureLoader sharedLoader; - private static final AccessControlContext NO_PERMISSIONS_CONTEXT; + + private static AccessControlContext createNoPermAccCtxt() { + return new AccessControlContext(new ProtectionDomain[] { new ProtectionDomain(null, new Permissions()) }); + } + + private static AccessControlContext createPermAccCtxt(final String permName) { + final Permissions perms = new Permissions(); + perms.add(new RuntimePermission(permName)); + return new AccessControlContext(new ProtectionDomain[] { new ProtectionDomain(null, perms) }); + } + + private static final AccessControlContext NO_PERMISSIONS_ACC_CTXT = createNoPermAccCtxt(); + private static final AccessControlContext CREATE_LOADER_ACC_CTXT = createPermAccCtxt("createClassLoader"); + private static final AccessControlContext CREATE_GLOBAL_ACC_CTXT = createPermAccCtxt(NASHORN_CREATE_GLOBAL); static { sharedLoader = AccessController.doPrivileged(new PrivilegedAction() { @@ -212,8 +250,7 @@ public final class Context { public StructureLoader run() { return new StructureLoader(myLoader, null); } - }); - NO_PERMISSIONS_CONTEXT = new AccessControlContext(new ProtectionDomain[] { new ProtectionDomain(null, new Permissions()) }); + }, CREATE_LOADER_ACC_CTXT); } /** @@ -254,7 +291,7 @@ public final class Context { public Context(final Options options, final ErrorManager errors, final PrintWriter out, final PrintWriter err, final ClassLoader appLoader) { final SecurityManager sm = System.getSecurityManager(); if (sm != null) { - sm.checkPermission(new RuntimePermission("nashorn.createContext")); + sm.checkPermission(new RuntimePermission(NASHORN_CREATE_CONTEXT)); } this.env = new ScriptEnvironment(options, out, err); @@ -516,7 +553,7 @@ public final class Context { @Override public ScriptObject run() { try { - return createGlobal(); + return newGlobal(); } catch (final RuntimeException e) { if (Context.DEBUG) { e.printStackTrace(); @@ -524,7 +561,9 @@ public final class Context { throw e; } } - }); + }, CREATE_GLOBAL_ACC_CTXT); + // initialize newly created Global instance + initGlobal(newGlobal); setGlobalTrusted(newGlobal); final Object[] wrapped = args == null? ScriptRuntime.EMPTY_ARRAY : ScriptObjectMirror.wrapArray(args, oldGlobal); @@ -577,7 +616,7 @@ public final class Context { sm.checkPackageAccess(fullName.substring(0, index)); return null; } - }, NO_PERMISSIONS_CONTEXT); + }, NO_PERMISSIONS_ACC_CTXT); } } } @@ -856,7 +895,7 @@ public final class Context { public ScriptLoader run() { return new ScriptLoader(sharedLoader, Context.this); } - }); + }, CREATE_LOADER_ACC_CTXT); } private long getUniqueScriptId() { diff --git a/nashorn/src/jdk/nashorn/internal/runtime/ECMAErrors.java b/nashorn/src/jdk/nashorn/internal/runtime/ECMAErrors.java index 35a0f2f48f9..5b608f4b37b 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/ECMAErrors.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/ECMAErrors.java @@ -25,8 +25,6 @@ package jdk.nashorn.internal.runtime; -import java.security.AccessController; -import java.security.PrivilegedAction; import java.text.MessageFormat; import java.util.Locale; import java.util.ResourceBundle; @@ -40,16 +38,9 @@ import jdk.nashorn.internal.scripts.JS; public final class ECMAErrors { private static final String MESSAGES_RESOURCE = "jdk.nashorn.internal.runtime.resources.Messages"; - // Without do privileged, under security manager messages can not be loaded. private static final ResourceBundle MESSAGES_BUNDLE; static { - MESSAGES_BUNDLE = AccessController.doPrivileged( - new PrivilegedAction() { - @Override - public ResourceBundle run() { - return ResourceBundle.getBundle(MESSAGES_RESOURCE, Locale.getDefault()); - } - }); + MESSAGES_BUNDLE = ResourceBundle.getBundle(MESSAGES_RESOURCE, Locale.getDefault()); } /** We assume that compiler generates script classes into the known package. */ diff --git a/nashorn/src/jdk/nashorn/internal/runtime/Logging.java b/nashorn/src/jdk/nashorn/internal/runtime/Logging.java index 39740dd2e34..54d83b79233 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/Logging.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/Logging.java @@ -25,6 +25,11 @@ package jdk.nashorn.internal.runtime; +import java.security.AccessControlContext; +import java.security.AccessController; +import java.security.Permissions; +import java.security.PrivilegedAction; +import java.security.ProtectionDomain; import java.util.HashMap; import java.util.Locale; import java.util.Map; @@ -35,6 +40,7 @@ import java.util.logging.Handler; import java.util.logging.Level; import java.util.logging.LogRecord; import java.util.logging.Logger; +import java.util.logging.LoggingPermission; /** * Logging system for getting loggers for arbitrary subsystems as @@ -50,12 +56,20 @@ public final class Logging { private static final Logger disabledLogger = Logger.getLogger("disabled"); + private static AccessControlContext createLoggerControlAccCtxt() { + final Permissions perms = new Permissions(); + perms.add(new LoggingPermission("control", null)); + return new AccessControlContext(new ProtectionDomain[] { new ProtectionDomain(null, perms) }); + } + static { - try { - Logging.disabledLogger.setLevel(Level.OFF); - } catch (final SecurityException e) { - //ignored - } + AccessController.doPrivileged(new PrivilegedAction() { + @Override + public Void run() { + Logging.disabledLogger.setLevel(Level.OFF); + return null; + } + }, createLoggerControlAccCtxt()); } /** Maps logger name to loggers. Names are typically per package */ diff --git a/nashorn/src/jdk/nashorn/internal/runtime/linker/ClassAndLoader.java b/nashorn/src/jdk/nashorn/internal/runtime/linker/ClassAndLoader.java index d12df47ad46..b139da1cfea 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/linker/ClassAndLoader.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/ClassAndLoader.java @@ -27,8 +27,11 @@ package jdk.nashorn.internal.runtime.linker; import static jdk.nashorn.internal.runtime.ECMAErrors.typeError; +import java.security.AccessControlContext; import java.security.AccessController; +import java.security.Permissions; import java.security.PrivilegedAction; +import java.security.ProtectionDomain; import java.util.Collection; import java.util.Iterator; import java.util.LinkedHashMap; @@ -43,6 +46,16 @@ import java.util.Map; * used to determine if one loader can see the other loader's classes. */ final class ClassAndLoader { + static AccessControlContext createPermAccCtxt(final String... permNames) { + final Permissions perms = new Permissions(); + for (final String permName : permNames) { + perms.add(new RuntimePermission(permName)); + } + return new AccessControlContext(new ProtectionDomain[] { new ProtectionDomain(null, perms) }); + } + + private static final AccessControlContext GET_LOADER_ACC_CTXT = createPermAccCtxt("getClassLoader"); + private final Class representativeClass; // Don't access this directly; most of the time, use getRetrievedLoader(), or if you know what you're doing, // getLoader(). @@ -116,7 +129,7 @@ final class ClassAndLoader { public ClassAndLoader run() { return getDefiningClassAndLoaderPrivileged(types); } - }); + }, GET_LOADER_ACC_CTXT); } static ClassAndLoader getDefiningClassAndLoaderPrivileged(final Class[] types) { diff --git a/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterBytecodeGenerator.java b/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterBytecodeGenerator.java index 2264cae50fd..efbf7cf623e 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterBytecodeGenerator.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterBytecodeGenerator.java @@ -49,6 +49,7 @@ import java.lang.reflect.AccessibleObject; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.lang.reflect.Modifier; +import java.security.AccessControlContext; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.Arrays; @@ -868,6 +869,8 @@ final class JavaAdapterBytecodeGenerator { } } + private static final AccessControlContext GET_DECLARED_MEMBERS_ACC_CTXT = ClassAndLoader.createPermAccCtxt("accessDeclaredMembers"); + /** * Creates a collection of methods that are not final, but we still never allow them to be overridden in adapters, * as explicitly declaring them automatically is a bad idea. Currently, this means {@code Object.finalize()} and @@ -886,7 +889,7 @@ final class JavaAdapterBytecodeGenerator { throw new AssertionError(e); } } - }); + }, GET_DECLARED_MEMBERS_ACC_CTXT); } private String getCommonSuperClass(final String type1, final String type2) { diff --git a/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterClassLoader.java b/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterClassLoader.java index 059ed552a64..291e4d2ff20 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterClassLoader.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterClassLoader.java @@ -25,6 +25,7 @@ package jdk.nashorn.internal.runtime.linker; +import java.security.AccessControlContext; import java.security.AccessController; import java.security.AllPermission; import java.security.CodeSigner; @@ -46,6 +47,7 @@ import jdk.internal.dynalink.beans.StaticClass; @SuppressWarnings("javadoc") final class JavaAdapterClassLoader { private static final ProtectionDomain GENERATED_PROTECTION_DOMAIN = createGeneratedProtectionDomain(); + private static final AccessControlContext CREATE_LOADER_ACC_CTXT = ClassAndLoader.createPermAccCtxt("createClassLoader"); private final String className; private volatile byte[] classBytes; @@ -77,7 +79,7 @@ final class JavaAdapterClassLoader { throw new AssertionError(e); // cannot happen } } - }); + }, CREATE_LOADER_ACC_CTXT); } // Note that the adapter class is created in the protection domain of the class/interface being diff --git a/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterFactory.java b/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterFactory.java index 4c005a273e8..5130f3d69ec 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterFactory.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterFactory.java @@ -31,9 +31,9 @@ import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; import java.lang.reflect.Modifier; +import java.security.AccessControlContext; import java.security.AccessController; import java.security.PrivilegedAction; -import java.security.PrivilegedExceptionAction; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -70,6 +70,11 @@ import jdk.nashorn.internal.runtime.ScriptObject; @SuppressWarnings("javadoc") public final class JavaAdapterFactory { + // context with permissions needs for AdapterInfo creation + private static final AccessControlContext CREATE_ADAPTER_INFO_ACC_CTXT = + ClassAndLoader.createPermAccCtxt("createClassLoader", "getClassLoader", + "accessDeclaredMembers", "accessClassInPackage.jdk.nashorn.internal.runtime"); + /** * A mapping from an original Class object to AdapterInfo representing the adapter for the class it represents. */ @@ -124,17 +129,10 @@ public final class JavaAdapterFactory { */ public static MethodHandle getConstructor(final Class sourceType, final Class targetType) throws Exception { final StaticClass adapterClass = getAdapterClassFor(new Class[] { targetType }, null); - return AccessController.doPrivileged(new PrivilegedExceptionAction() { - @Override - public MethodHandle run() throws Exception { - // NOTE: we use publicLookup(), but none of our adapter constructors are caller sensitive, so this is - // okay, we won't artificially limit access. - return MH.bindTo(Bootstrap.getLinkerServices().getGuardedInvocation(new LinkRequestImpl( - NashornCallSiteDescriptor.get(MethodHandles.publicLookup(), "dyn:new", - MethodType.methodType(targetType, StaticClass.class, sourceType), 0), false, - adapterClass, null)).getInvocation(), adapterClass); - } - }); + return MH.bindTo(Bootstrap.getLinkerServices().getGuardedInvocation(new LinkRequestImpl( + NashornCallSiteDescriptor.get(MethodHandles.publicLookup(), "dyn:new", + MethodType.methodType(targetType, StaticClass.class, sourceType), 0), false, + adapterClass, null)).getInvocation(), adapterClass); } /** @@ -171,7 +169,7 @@ public final class JavaAdapterFactory { return (List)Collections.singletonList(clazz); } - /** + /** * For a given class, create its adapter class and associated info. * @param type the class for which the adapter is created * @return the adapter info for the class. @@ -190,12 +188,19 @@ public final class JavaAdapterFactory { } superClass = t; } else { + if (interfaces.size() > 65535) { + throw new IllegalArgumentException("interface limit exceeded"); + } + interfaces.add(t); } + if(!Modifier.isPublic(mod)) { return new AdapterInfo(AdaptationResult.Outcome.ERROR_NON_PUBLIC_CLASS, t.getCanonicalName()); } } + + final Class effectiveSuperClass = superClass == null ? Object.class : superClass; return AccessController.doPrivileged(new PrivilegedAction() { @Override @@ -206,7 +211,7 @@ public final class JavaAdapterFactory { return new AdapterInfo(e.getAdaptationResult()); } } - }); + }, CREATE_ADAPTER_INFO_ACC_CTXT); } private static class AdapterInfo { diff --git a/nashorn/src/jdk/nashorn/internal/runtime/linker/ReflectionCheckLinker.java b/nashorn/src/jdk/nashorn/internal/runtime/linker/ReflectionCheckLinker.java index 1e540231f24..39f9364233d 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/linker/ReflectionCheckLinker.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/ReflectionCheckLinker.java @@ -88,6 +88,6 @@ final class ReflectionCheckLinker implements TypeBasedGuardingDynamicLinker{ } private static void checkReflectionPermission(final SecurityManager sm) { - sm.checkPermission(new RuntimePermission("nashorn.JavaReflection")); + sm.checkPermission(new RuntimePermission(Context.NASHORN_JAVA_REFLECTION)); } } diff --git a/nashorn/src/jdk/nashorn/internal/runtime/options/Options.java b/nashorn/src/jdk/nashorn/internal/runtime/options/Options.java index 737c56b4b1a..900d9dd4e8c 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/options/Options.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/options/Options.java @@ -26,8 +26,11 @@ package jdk.nashorn.internal.runtime.options; import java.io.PrintWriter; +import java.security.AccessControlContext; import java.security.AccessController; +import java.security.Permissions; import java.security.PrivilegedAction; +import java.security.ProtectionDomain; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Collection; @@ -39,6 +42,7 @@ import java.util.List; import java.util.Locale; import java.util.Map; import java.util.MissingResourceException; +import java.util.PropertyPermission; import java.util.ResourceBundle; import java.util.StringTokenizer; import java.util.TimeZone; @@ -51,6 +55,15 @@ import jdk.nashorn.internal.runtime.QuotedStringTokenizer; * Manages global runtime options. */ public final class Options { + // permission to just read nashorn.* System properties + private static AccessControlContext createPropertyReadAccCtxt() { + final Permissions perms = new Permissions(); + perms.add(new PropertyPermission("nashorn.*", "read")); + return new AccessControlContext(new ProtectionDomain[] { new ProtectionDomain(null, perms) }); + } + + private static final AccessControlContext READ_PROPERTY_ACC_CTXT = createPropertyReadAccCtxt(); + /** Resource tag. */ private final String resource; @@ -144,7 +157,7 @@ public final class Options { return false; } } - }); + }, READ_PROPERTY_ACC_CTXT); } /** @@ -171,7 +184,7 @@ public final class Options { return defValue; } } - }); + }, READ_PROPERTY_ACC_CTXT); } /** @@ -198,7 +211,7 @@ public final class Options { return defValue; } } - }); + }, READ_PROPERTY_ACC_CTXT); } /** @@ -567,15 +580,7 @@ public final class Options { private static String definePropPrefix; static { - // Without do privileged, under security manager messages can not be - // loaded. - Options.bundle = AccessController.doPrivileged(new PrivilegedAction() { - @Override - public ResourceBundle run() { - return ResourceBundle.getBundle(Options.MESSAGES_RESOURCE, Locale.getDefault()); - } - }); - + Options.bundle = ResourceBundle.getBundle(Options.MESSAGES_RESOURCE, Locale.getDefault()); Options.validOptions = new TreeSet<>(); Options.usage = new HashMap<>(); diff --git a/nashorn/src/jdk/nashorn/tools/Shell.java b/nashorn/src/jdk/nashorn/tools/Shell.java index 55840078e64..08b576fb9fa 100644 --- a/nashorn/src/jdk/nashorn/tools/Shell.java +++ b/nashorn/src/jdk/nashorn/tools/Shell.java @@ -34,8 +34,6 @@ import java.io.InputStreamReader; import java.io.OutputStream; import java.io.PrintStream; import java.io.PrintWriter; -import java.security.AccessController; -import java.security.PrivilegedAction; import java.util.List; import java.util.Locale; import java.util.ResourceBundle; @@ -68,18 +66,7 @@ public class Shell { /** * Shell message bundle. */ - private static ResourceBundle bundle; - - static { - // Without do privileged, under security manager messages can not be - // loaded. - bundle = AccessController.doPrivileged(new PrivilegedAction() { - @Override - public ResourceBundle run() { - return ResourceBundle.getBundle(MESSAGE_RESOURCE, Locale.getDefault()); - } - }); - } + private static final ResourceBundle bundle = ResourceBundle.getBundle(MESSAGE_RESOURCE, Locale.getDefault()); /** * Exit code for command line tool - successful From 86ec979f23be493f44a21694fa6a3d355fd86a50 Mon Sep 17 00:00:00 2001 From: Joe Wang Date: Fri, 9 Aug 2013 12:10:41 -0700 Subject: [PATCH 014/218] 8022548: SPECJVM2008 has errors introduced in 7u40-b34 Reviewed-by: chegar, lancea --- .../xerces/internal/parsers/DTDConfiguration.java | 9 ++++++++- .../internal/parsers/NonValidatingConfiguration.java | 9 ++++++++- .../apache/xerces/internal/parsers/SAXParser.java | 12 ++++++++---- 3 files changed, 24 insertions(+), 6 deletions(-) diff --git a/jaxp/src/com/sun/org/apache/xerces/internal/parsers/DTDConfiguration.java b/jaxp/src/com/sun/org/apache/xerces/internal/parsers/DTDConfiguration.java index 0cdfd654b78..c63ae43923e 100644 --- a/jaxp/src/com/sun/org/apache/xerces/internal/parsers/DTDConfiguration.java +++ b/jaxp/src/com/sun/org/apache/xerces/internal/parsers/DTDConfiguration.java @@ -38,6 +38,7 @@ import com.sun.org.apache.xerces.internal.util.FeatureState; import com.sun.org.apache.xerces.internal.util.PropertyState; import com.sun.org.apache.xerces.internal.util.Status; import com.sun.org.apache.xerces.internal.util.SymbolTable; +import com.sun.org.apache.xerces.internal.utils.XMLSecurityPropertyManager; import com.sun.org.apache.xerces.internal.xni.XMLLocator; import com.sun.org.apache.xerces.internal.xni.XNIException; import com.sun.org.apache.xerces.internal.xni.grammars.XMLGrammarPool; @@ -184,6 +185,10 @@ public class DTDConfiguration protected static final String LOCALE = Constants.XERCES_PROPERTY_PREFIX + Constants.LOCALE_PROPERTY; + /** Property identifier: Security property manager. */ + protected static final String XML_SECURITY_PROPERTY_MANAGER = + Constants.XML_SECURITY_PROPERTY_MANAGER; + // debugging /** Set to true and recompile to print exception stack trace. */ @@ -328,7 +333,8 @@ public class DTDConfiguration VALIDATION_MANAGER, JAXP_SCHEMA_SOURCE, JAXP_SCHEMA_LANGUAGE, - LOCALE + LOCALE, + XML_SECURITY_PROPERTY_MANAGER }; addRecognizedProperties(recognizedProperties); @@ -406,6 +412,7 @@ public class DTDConfiguration // REVISIT: What is the right thing to do? -Ac } + setProperty(XML_SECURITY_PROPERTY_MANAGER, new XMLSecurityPropertyManager()); } // (SymbolTable,XMLGrammarPool) // diff --git a/jaxp/src/com/sun/org/apache/xerces/internal/parsers/NonValidatingConfiguration.java b/jaxp/src/com/sun/org/apache/xerces/internal/parsers/NonValidatingConfiguration.java index 55339157c90..481eda6f21e 100644 --- a/jaxp/src/com/sun/org/apache/xerces/internal/parsers/NonValidatingConfiguration.java +++ b/jaxp/src/com/sun/org/apache/xerces/internal/parsers/NonValidatingConfiguration.java @@ -36,6 +36,7 @@ import com.sun.org.apache.xerces.internal.util.FeatureState; import com.sun.org.apache.xerces.internal.util.PropertyState; import com.sun.org.apache.xerces.internal.util.Status; import com.sun.org.apache.xerces.internal.util.SymbolTable; +import com.sun.org.apache.xerces.internal.utils.XMLSecurityPropertyManager; import com.sun.org.apache.xerces.internal.xni.XMLLocator; import com.sun.org.apache.xerces.internal.xni.XNIException; import com.sun.org.apache.xerces.internal.xni.grammars.XMLGrammarPool; @@ -157,6 +158,10 @@ public class NonValidatingConfiguration protected static final String LOCALE = Constants.XERCES_PROPERTY_PREFIX + Constants.LOCALE_PROPERTY; + /** Property identifier: Security property manager. */ + protected static final String XML_SECURITY_PROPERTY_MANAGER = + Constants.XML_SECURITY_PROPERTY_MANAGER; + // debugging /** Set to true and recompile to print exception stack trace. */ @@ -310,7 +315,8 @@ public class NonValidatingConfiguration XMLGRAMMAR_POOL, DATATYPE_VALIDATOR_FACTORY, VALIDATION_MANAGER, - LOCALE + LOCALE, + XML_SECURITY_PROPERTY_MANAGER }; addRecognizedProperties(recognizedProperties); @@ -367,6 +373,7 @@ public class NonValidatingConfiguration // REVISIT: What is the right thing to do? -Ac } + setProperty(XML_SECURITY_PROPERTY_MANAGER, new XMLSecurityPropertyManager()); } // (SymbolTable,XMLGrammarPool) // diff --git a/jaxp/src/com/sun/org/apache/xerces/internal/parsers/SAXParser.java b/jaxp/src/com/sun/org/apache/xerces/internal/parsers/SAXParser.java index cf9e9a79f92..1ba84aff710 100644 --- a/jaxp/src/com/sun/org/apache/xerces/internal/parsers/SAXParser.java +++ b/jaxp/src/com/sun/org/apache/xerces/internal/parsers/SAXParser.java @@ -76,6 +76,7 @@ public class SAXParser XMLGRAMMAR_POOL, }; + XMLSecurityPropertyManager securityPropertyManager; // // Constructors // @@ -129,16 +130,19 @@ public class SAXParser */ public void setProperty(String name, Object value) throws SAXNotRecognizedException, SAXNotSupportedException { - XMLSecurityPropertyManager spm = new XMLSecurityPropertyManager(); - int index = spm.getIndex(name); + if (securityPropertyManager == null) { + securityPropertyManager = new XMLSecurityPropertyManager(); + } + int index = securityPropertyManager.getIndex(name); + if (index > -1) { /** * this is a direct call to this parser, not a subclass since * internally the support of this property is done through * XMLSecurityPropertyManager */ - spm.setValue(index, XMLSecurityPropertyManager.State.APIPROPERTY, (String)value); - super.setProperty(Constants.XML_SECURITY_PROPERTY_MANAGER, spm); + securityPropertyManager.setValue(index, XMLSecurityPropertyManager.State.APIPROPERTY, (String)value); + super.setProperty(Constants.XML_SECURITY_PROPERTY_MANAGER, securityPropertyManager); } else { super.setProperty(name, value); } From 35e27fd5945d4dd0e130d56efb09e23073476a4d Mon Sep 17 00:00:00 2001 From: Kumar Srinivasan Date: Fri, 9 Aug 2013 15:01:33 -0700 Subject: [PATCH 015/218] 8022161: javac Null Pointer Exception in Enter.visitTopLevel Reviewed-by: jjg, vromero, jlahoda --- .../com/sun/tools/javac/comp/Enter.java | 2 +- langtools/test/tools/javac/TestPkgInfo.java | 47 +++++++++++++++---- 2 files changed, 40 insertions(+), 9 deletions(-) diff --git a/langtools/src/share/classes/com/sun/tools/javac/comp/Enter.java b/langtools/src/share/classes/com/sun/tools/javac/comp/Enter.java index e1094b6f9d1..41c0792acf2 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/comp/Enter.java +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Enter.java @@ -291,7 +291,7 @@ public class Enter extends JCTree.Visitor { if (tree.packageAnnotations.nonEmpty() || pkginfoOpt == PkgInfo.ALWAYS) { if (isPkgInfo) { addEnv = true; - } else { + } else if (tree.packageAnnotations.nonEmpty()){ log.error(tree.packageAnnotations.head.pos(), "pkg.annotations.sb.in.package-info.java"); } diff --git a/langtools/test/tools/javac/TestPkgInfo.java b/langtools/test/tools/javac/TestPkgInfo.java index 15adff341d9..7c12ecedc6c 100644 --- a/langtools/test/tools/javac/TestPkgInfo.java +++ b/langtools/test/tools/javac/TestPkgInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,8 +23,10 @@ /* * @test - * @bug 6960424 - * @summary new option -Xpkginfo for better control of when package-info.class is generated + * @bug 6960424 8022161 + * @summary new option -Xpkginfo for better control of when package-info.class + * is generated, also ensures no failures if package-info.java is + * not available. */ import java.io.*; @@ -43,8 +45,11 @@ public class TestPkgInfo { public static void main(String... args) throws Exception { new TestPkgInfo().run(args); } - public void run(String... args) throws Exception { + testPositive(); + testNoExceptions(); + } + public void testPositive(String... args) throws Exception { boolean[] booleanValues = { false, true }; for (OptKind ok: OptKind.values()) { for (boolean sr: booleanValues) { @@ -65,6 +70,32 @@ public class TestPkgInfo { throw new Exception(errors + " errors occurred"); } + /** this should throw no exceptions **/ + void testNoExceptions() throws Exception { + count++; + System.err.println("Test " + count + ": ALWAYS nofile"); + + StringBuilder sb = new StringBuilder(); + sb.append("package test; class Hello{}"); + + // test specific tmp directory + File tmpDir = new File("tmp.test" + count); + File classesDir = new File(tmpDir, "classes"); + classesDir.mkdirs(); + File javafile = new File(new File(tmpDir, "src"), "Hello.java"); + writeFile(javafile, sb.toString()); + // build up list of options and files to be compiled + List opts = new ArrayList<>(); + List files = new ArrayList<>(); + + opts.add("-d"); + opts.add(classesDir.getPath()); + opts.add("-Xpkginfo:always"); + files.add(javafile); + + compile(opts, files); + } + void test(OptKind ok, boolean sr, boolean cr, boolean rr) throws Exception { count++; System.err.println("Test " + count + ": ok:" + ok + " sr:" + sr + " cr:" + cr + " rr:" + rr); @@ -91,15 +122,15 @@ public class TestPkgInfo { writeFile(pkginfo_java, sb.toString()); // build up list of options and files to be compiled - List opts = new ArrayList(); - List files = new ArrayList(); + List opts = new ArrayList<>(); + List files = new ArrayList<>(); opts.add("-d"); opts.add(classesDir.getPath()); if (ok.opt != null) opts.add(ok.opt); //opts.add("-verbose"); - files.add(pkginfo_java); + files.add(pkginfo_java); compile(opts, files); @@ -134,7 +165,7 @@ public class TestPkgInfo { /** Compile files with options provided. */ void compile(List opts, List files) throws Exception { System.err.println("javac: " + opts + " " + files); - List args = new ArrayList(); + List args = new ArrayList<>(); args.addAll(opts); for (File f: files) args.add(f.getPath()); From cee3c2853b8a080c459755475faab4494b3a3de6 Mon Sep 17 00:00:00 2001 From: Vicente Romero Date: Sat, 10 Aug 2013 13:27:38 +0100 Subject: [PATCH 016/218] 8009640: -profile does not work when -bootclasspath specified Reviewed-by: jjg --- .../com/sun/tools/javac/main/Main.java | 5 ++ .../tools/javac/resources/javac.properties | 2 + ...ctProfileBCPOptionsIfUsedTogetherTest.java | 66 +++++++++++++++++++ 3 files changed, 73 insertions(+) create mode 100644 langtools/test/tools/javac/T8009640/CheckRejectProfileBCPOptionsIfUsedTogetherTest.java diff --git a/langtools/src/share/classes/com/sun/tools/javac/main/Main.java b/langtools/src/share/classes/com/sun/tools/javac/main/Main.java index 72a279d7173..2842487b4a7 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/main/Main.java +++ b/langtools/src/share/classes/com/sun/tools/javac/main/Main.java @@ -262,6 +262,11 @@ public class Main { } } + if (options.get(PROFILE) != null && options.get(BOOTCLASSPATH) != null) { + error("err.profile.bootclasspath.conflict"); + return null; + } + if (this.classnames != null && classNames != null) { this.classnames.addAll(Arrays.asList(classNames)); } diff --git a/langtools/src/share/classes/com/sun/tools/javac/resources/javac.properties b/langtools/src/share/classes/com/sun/tools/javac/resources/javac.properties index f32c2291748..328d9fbf76b 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/resources/javac.properties +++ b/langtools/src/share/classes/com/sun/tools/javac/resources/javac.properties @@ -185,6 +185,8 @@ javac.err.invalid.A.key=\ key in annotation processor option ''{0}'' is not a dot-separated sequence of identifiers javac.err.invalid.flag=\ invalid flag: {0} +javac.err.profile.bootclasspath.conflict=\ + profile and bootclasspath options cannot be used together javac.err.invalid.profile=\ invalid profile: {0} javac.err.invalid.target=\ diff --git a/langtools/test/tools/javac/T8009640/CheckRejectProfileBCPOptionsIfUsedTogetherTest.java b/langtools/test/tools/javac/T8009640/CheckRejectProfileBCPOptionsIfUsedTogetherTest.java new file mode 100644 index 00000000000..186774a63be --- /dev/null +++ b/langtools/test/tools/javac/T8009640/CheckRejectProfileBCPOptionsIfUsedTogetherTest.java @@ -0,0 +1,66 @@ +/* + * 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. + */ + +/* + * @test + * @bug 8009640 + * @summary -profile does not work when -bootclasspath specified + * @library /tools/javac/lib + * @build ToolBox + * @run main CheckRejectProfileBCPOptionsIfUsedTogetherTest + */ + +import com.sun.tools.javac.util.Assert; +import java.util.ArrayList; +import java.util.List; + +public class CheckRejectProfileBCPOptionsIfUsedTogetherTest { + + private static final String TestSrc = + "public class Test {\n" + + " javax.swing.JButton b;\n" + + "}"; + + public static void main(String args[]) throws Exception { + List errOutput = new ArrayList<>(); + String testJDK = ToolBox.jdkUnderTest; + ToolBox.createJavaFileFromSource(TestSrc); + + ToolBox.AnyToolArgs javacParams = + new ToolBox.AnyToolArgs(ToolBox.Expect.FAIL) + .appendArgs(ToolBox.javacBinary) + .appendArgs(ToolBox.testToolVMOpts) + .appendArgs("-profile", "compact1", "-bootclasspath", + testJDK + "/jre/lib/rt.jar", "Test.java") + .setErrOutput(errOutput); + + ToolBox.executeCommand(javacParams); + + Assert.check(errOutput.get(0).startsWith( + "javac: profile and bootclasspath options cannot be used together"), + "Incorrect javac error output"); + } + +} From 22652f53542fcc37ffac24127cda023af2481715 Mon Sep 17 00:00:00 2001 From: Vicente Romero Date: Sat, 10 Aug 2013 16:26:50 +0100 Subject: [PATCH 017/218] 8022622: javac, two tests are failing with compile time error after class Collector was modified Reviewed-by: mcimadamore --- langtools/test/tools/javac/lambda/TargetType59.java | 6 +++--- langtools/test/tools/javac/lambda/TargetType62.java | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/langtools/test/tools/javac/lambda/TargetType59.java b/langtools/test/tools/javac/lambda/TargetType59.java index f366179f0c9..d2bdb83cd6c 100644 --- a/langtools/test/tools/javac/lambda/TargetType59.java +++ b/langtools/test/tools/javac/lambda/TargetType59.java @@ -34,15 +34,15 @@ import java.util.stream.*; class TargetType59 { - Collector m(Supplier supplier, BiConsumer accumulator) { + Collector m(Supplier supplier, BiConsumer accumulator) { return null; } - > Collector test1(Supplier collectionFactory) { + > Collector test1(Supplier collectionFactory) { return m(collectionFactory, Collection::add); } - Collector test2(Supplier sb) { + Collector test2(Supplier sb) { return m(sb, StringBuilder::append); } } diff --git a/langtools/test/tools/javac/lambda/TargetType62.java b/langtools/test/tools/javac/lambda/TargetType62.java index 9bf79bbc699..30ffa0277af 100644 --- a/langtools/test/tools/javac/lambda/TargetType62.java +++ b/langtools/test/tools/javac/lambda/TargetType62.java @@ -38,8 +38,8 @@ class TargetType61 { return g(classifier, TreeMap::new, m(HashSet::new)); } - Collector m(Supplier s) { return null; } + Collector m(Supplier s) { return null; } > - Collector g(Function classifier, Supplier mapFactory, Collector downstream) { return null; } + Collector g(Function classifier, Supplier mapFactory, Collector downstream) { return null; } } From 190f9337b13159b987ceb44852fe456e8019aac7 Mon Sep 17 00:00:00 2001 From: Vicente Romero Date: Sat, 10 Aug 2013 16:29:26 +0100 Subject: [PATCH 018/218] 6983297: methods missing from NewArrayTree Reviewed-by: jjg --- .../classes/com/sun/source/tree/NewArrayTree.java | 4 +++- .../share/classes/com/sun/source/util/TreeScanner.java | 4 ++++ .../share/classes/com/sun/tools/javac/tree/JCTree.java | 10 ++++++++++ .../test/tools/javac/tree/SourceTreeScannerTest.java | 7 ------- 4 files changed, 17 insertions(+), 8 deletions(-) diff --git a/langtools/src/share/classes/com/sun/source/tree/NewArrayTree.java b/langtools/src/share/classes/com/sun/source/tree/NewArrayTree.java index b9f1bddf487..3cd2f6283bf 100644 --- a/langtools/src/share/classes/com/sun/source/tree/NewArrayTree.java +++ b/langtools/src/share/classes/com/sun/source/tree/NewArrayTree.java @@ -25,7 +25,7 @@ package com.sun.source.tree; -import java.util.List; +import com.sun.tools.javac.util.List; /** * A tree node for an expression to create a new instance of an array. @@ -48,4 +48,6 @@ public interface NewArrayTree extends ExpressionTree { Tree getType(); List getDimensions(); List getInitializers(); + List getAnnotations(); + List> getDimAnnotations(); } diff --git a/langtools/src/share/classes/com/sun/source/util/TreeScanner.java b/langtools/src/share/classes/com/sun/source/util/TreeScanner.java index a6d0466a729..38ba501d190 100644 --- a/langtools/src/share/classes/com/sun/source/util/TreeScanner.java +++ b/langtools/src/share/classes/com/sun/source/util/TreeScanner.java @@ -285,6 +285,10 @@ public class TreeScanner implements TreeVisitor { R r = scan(node.getType(), p); r = scanAndReduce(node.getDimensions(), p, r); r = scanAndReduce(node.getInitializers(), p, r); + r = scanAndReduce(node.getAnnotations(), p, r); + for (Iterable< ? extends Tree> dimAnno : node.getDimAnnotations()) { + r = scanAndReduce(dimAnno, p, r); + } return r; } diff --git a/langtools/src/share/classes/com/sun/tools/javac/tree/JCTree.java b/langtools/src/share/classes/com/sun/tools/javac/tree/JCTree.java index 846a4a2e2aa..313596a3362 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/tree/JCTree.java +++ b/langtools/src/share/classes/com/sun/tools/javac/tree/JCTree.java @@ -1571,6 +1571,16 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition { public Tag getTag() { return NEWARRAY; } + + @Override + public List getAnnotations() { + return annotations; + } + + @Override + public List> getDimAnnotations() { + return dimAnnotations; + } } /** diff --git a/langtools/test/tools/javac/tree/SourceTreeScannerTest.java b/langtools/test/tools/javac/tree/SourceTreeScannerTest.java index e4cc3f851bd..0043f6668a6 100644 --- a/langtools/test/tools/javac/tree/SourceTreeScannerTest.java +++ b/langtools/test/tools/javac/tree/SourceTreeScannerTest.java @@ -140,13 +140,6 @@ public class SourceTreeScannerTest extends AbstractTreeScannerTest { // not part of public API continue; } - if (JCTree.JCNewArray.class.isAssignableFrom(tree.getClass()) - && (f.getName().equals("annotations") - || f.getName().equals("dimAnnotations"))) { - // these fields are incorrectly missing from the public API - // (CR 6983297) - continue; - } try { //System.err.println("FIELD: " + f.getName()); reflectiveScan(f.get(tree)); From ec9506c0fe8761acf2354aa13b7e3d39f000c767 Mon Sep 17 00:00:00 2001 From: Athijegannathan Sundararajan Date: Mon, 12 Aug 2013 14:43:53 +0530 Subject: [PATCH 019/218] 8022782: publicLookup access failures in ScriptObject, ScriptFunction and ScriptFunction Reviewed-by: lagergren, attila, hannesw --- .../internal/codegen/CompilerConstants.java | 28 ----------------- .../jdk/nashorn/internal/runtime/JSType.java | 31 ++++++++++--------- .../internal/runtime/ScriptObject.java | 6 ++-- .../internal/runtime/ScriptRuntime.java | 3 +- 4 files changed, 22 insertions(+), 46 deletions(-) diff --git a/nashorn/src/jdk/nashorn/internal/codegen/CompilerConstants.java b/nashorn/src/jdk/nashorn/internal/codegen/CompilerConstants.java index c8ccc1cedc1..5207fbce636 100644 --- a/nashorn/src/jdk/nashorn/internal/codegen/CompilerConstants.java +++ b/nashorn/src/jdk/nashorn/internal/codegen/CompilerConstants.java @@ -488,20 +488,6 @@ public enum CompilerConstants { return staticField(className(clazz), name, typeDescriptor(type)); } - /** - * Create a static call, looking up the method handle for it at the same time - * - * @param clazz the class - * @param name the name of the method - * @param rtype the return type of the method - * @param ptypes the parameter types of the method - * - * @return the call object representing the static call - */ - public static Call staticCall(final Class clazz, final String name, final Class rtype, final Class... ptypes) { - return staticCall(MethodHandles.publicLookup(), clazz, name, rtype, ptypes); - } - /** * Create a static call, given an explicit lookup, looking up the method handle for it at the same time * @@ -522,20 +508,6 @@ public enum CompilerConstants { }; } - /** - * Create a virtual call, looking up the method handle for it at the same time - * - * @param clazz the class - * @param name the name of the method - * @param rtype the return type of the method - * @param ptypes the parameter types of the method - * - * @return the call object representing the virtual call - */ - public static Call virtualCall(final Class clazz, final String name, final Class rtype, final Class... ptypes) { - return virtualCall(MethodHandles.publicLookup(), clazz, name, rtype, ptypes); - } - /** * Create a virtual call, given an explicit lookup, looking up the method handle for it at the same time * diff --git a/nashorn/src/jdk/nashorn/internal/runtime/JSType.java b/nashorn/src/jdk/nashorn/internal/runtime/JSType.java index 4d1d825c852..f532762149d 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/JSType.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/JSType.java @@ -28,6 +28,7 @@ package jdk.nashorn.internal.runtime; import static jdk.nashorn.internal.codegen.CompilerConstants.staticCall; import static jdk.nashorn.internal.runtime.ECMAErrors.typeError; +import java.lang.invoke.MethodHandles; import java.util.Locale; import jdk.internal.dynalink.beans.BeansLinker; import jdk.internal.dynalink.beans.StaticClass; @@ -63,47 +64,49 @@ public enum JSType { /** Max value for an uint32 in JavaScript */ public static final long MAX_UINT = 0xFFFF_FFFFL; + private static final MethodHandles.Lookup myLookup = MethodHandles.lookup(); + /** JavaScript compliant conversion function from Object to boolean */ - public static final Call TO_BOOLEAN = staticCall(JSType.class, "toBoolean", boolean.class, Object.class); + public static final Call TO_BOOLEAN = staticCall(myLookup, JSType.class, "toBoolean", boolean.class, Object.class); /** JavaScript compliant conversion function from number to boolean */ - public static final Call TO_BOOLEAN_D = staticCall(JSType.class, "toBoolean", boolean.class, double.class); + public static final Call TO_BOOLEAN_D = staticCall(myLookup, JSType.class, "toBoolean", boolean.class, double.class); /** JavaScript compliant conversion function from Object to integer */ - public static final Call TO_INTEGER = staticCall(JSType.class, "toInteger", int.class, Object.class); + public static final Call TO_INTEGER = staticCall(myLookup, JSType.class, "toInteger", int.class, Object.class); /** JavaScript compliant conversion function from Object to long */ - public static final Call TO_LONG = staticCall(JSType.class, "toLong", long.class, Object.class); + public static final Call TO_LONG = staticCall(myLookup, JSType.class, "toLong", long.class, Object.class); /** JavaScript compliant conversion function from Object to number */ - public static final Call TO_NUMBER = staticCall(JSType.class, "toNumber", double.class, Object.class); + public static final Call TO_NUMBER = staticCall(myLookup, JSType.class, "toNumber", double.class, Object.class); /** JavaScript compliant conversion function from Object to int32 */ - public static final Call TO_INT32 = staticCall(JSType.class, "toInt32", int.class, Object.class); + public static final Call TO_INT32 = staticCall(myLookup, JSType.class, "toInt32", int.class, Object.class); /** JavaScript compliant conversion function from double to int32 */ - public static final Call TO_INT32_D = staticCall(JSType.class, "toInt32", int.class, double.class); + public static final Call TO_INT32_D = staticCall(myLookup, JSType.class, "toInt32", int.class, double.class); /** JavaScript compliant conversion function from Object to uint32 */ - public static final Call TO_UINT32 = staticCall(JSType.class, "toUint32", long.class, Object.class); + public static final Call TO_UINT32 = staticCall(myLookup, JSType.class, "toUint32", long.class, Object.class); /** JavaScript compliant conversion function from number to uint32 */ - public static final Call TO_UINT32_D = staticCall(JSType.class, "toUint32", long.class, double.class); + public static final Call TO_UINT32_D = staticCall(myLookup, JSType.class, "toUint32", long.class, double.class); /** JavaScript compliant conversion function from Object to int64 */ - public static final Call TO_INT64 = staticCall(JSType.class, "toInt64", long.class, Object.class); + public static final Call TO_INT64 = staticCall(myLookup, JSType.class, "toInt64", long.class, Object.class); /** JavaScript compliant conversion function from number to int64 */ - public static final Call TO_INT64_D = staticCall(JSType.class, "toInt64", long.class, double.class); + public static final Call TO_INT64_D = staticCall(myLookup, JSType.class, "toInt64", long.class, double.class); /** JavaScript compliant conversion function from Object to String */ - public static final Call TO_STRING = staticCall(JSType.class, "toString", String.class, Object.class); + public static final Call TO_STRING = staticCall(myLookup, JSType.class, "toString", String.class, Object.class); /** JavaScript compliant conversion function from number to String */ - public static final Call TO_STRING_D = staticCall(JSType.class, "toString", String.class, double.class); + public static final Call TO_STRING_D = staticCall(myLookup, JSType.class, "toString", String.class, double.class); /** JavaScript compliant conversion function from Object to primitive */ - public static final Call TO_PRIMITIVE = staticCall(JSType.class, "toPrimitive", Object.class, Object.class); + public static final Call TO_PRIMITIVE = staticCall(myLookup, JSType.class, "toPrimitive", Object.class, Object.class); private static final double INT32_LIMIT = 4294967296.0; diff --git a/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java b/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java index 099aad5511c..f26e30f00e8 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java @@ -138,10 +138,10 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr private static final MethodHandle KNOWNFUNCPROPGUARD = findOwnMH("knownFunctionPropertyGuard", boolean.class, Object.class, PropertyMap.class, MethodHandle.class, Object.class, ScriptFunction.class); /** Method handle for getting a function argument at a given index. Used from MapCreator */ - public static final Call GET_ARGUMENT = virtualCall(ScriptObject.class, "getArgument", Object.class, int.class); + public static final Call GET_ARGUMENT = virtualCall(MethodHandles.lookup(), ScriptObject.class, "getArgument", Object.class, int.class); /** Method handle for setting a function argument at a given index. Used from MapCreator */ - public static final Call SET_ARGUMENT = virtualCall(ScriptObject.class, "setArgument", void.class, int.class, Object.class); + public static final Call SET_ARGUMENT = virtualCall(MethodHandles.lookup(), ScriptObject.class, "setArgument", void.class, int.class, Object.class); /** Method handle for getting the proto of a ScriptObject */ public static final Call GET_PROTO = virtualCallNoLookup(ScriptObject.class, "getProto", ScriptObject.class); @@ -150,7 +150,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr public static final Call SET_PROTO = virtualCallNoLookup(ScriptObject.class, "setProto", void.class, ScriptObject.class); /** Method handle for setting the user accessors of a ScriptObject */ - public static final Call SET_USER_ACCESSORS = virtualCall(ScriptObject.class, "setUserAccessors", void.class, String.class, ScriptFunction.class, ScriptFunction.class); + public static final Call SET_USER_ACCESSORS = virtualCall(MethodHandles.lookup(), ScriptObject.class, "setUserAccessors", void.class, String.class, ScriptFunction.class, ScriptFunction.class); /** * Constructor diff --git a/nashorn/src/jdk/nashorn/internal/runtime/ScriptRuntime.java b/nashorn/src/jdk/nashorn/internal/runtime/ScriptRuntime.java index dbeee76ad8c..53c4d4fee78 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptRuntime.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptRuntime.java @@ -33,6 +33,7 @@ import static jdk.nashorn.internal.runtime.ECMAErrors.typeError; import static jdk.nashorn.internal.runtime.JSType.isRepresentableAsInt; import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; import java.lang.reflect.Array; import java.util.Collections; import java.util.Iterator; @@ -100,7 +101,7 @@ public final class ScriptRuntime { * call sites that are known to be megamorphic. Using an invoke dynamic here would * lead to the JVM deoptimizing itself to death */ - public static final Call APPLY = staticCall(ScriptRuntime.class, "apply", Object.class, ScriptFunction.class, Object.class, Object[].class); + public static final Call APPLY = staticCall(MethodHandles.lookup(), ScriptRuntime.class, "apply", Object.class, ScriptFunction.class, Object.class, Object[].class); /** * Converts a switch tag value to a simple integer. deflt value if it can't. From cd65f6f9739f4bf09fa9e14433acc203ec3c907f Mon Sep 17 00:00:00 2001 From: Xue-Lei Andrew Fan Date: Thu, 29 Aug 2013 18:58:18 -0700 Subject: [PATCH 020/218] 8023881: IDN.USE_STD3_ASCII_RULES option is too strict to use Unicode in IDN.toASCII Reviewed-by: michaelm --- jdk/src/share/classes/java/net/IDN.java | 40 +++++----- jdk/test/java/net/IDN/UseSTD3ASCIIRules.java | 80 ++++++++++++++++++++ 2 files changed, 99 insertions(+), 21 deletions(-) create mode 100644 jdk/test/java/net/IDN/UseSTD3ASCIIRules.java diff --git a/jdk/src/share/classes/java/net/IDN.java b/jdk/src/share/classes/java/net/IDN.java index ed2f3a38159..34642b9824c 100644 --- a/jdk/src/share/classes/java/net/IDN.java +++ b/jdk/src/share/classes/java/net/IDN.java @@ -292,13 +292,17 @@ public final class IDN { if (useSTD3ASCIIRules) { for (int i = 0; i < dest.length(); i++) { int c = dest.charAt(i); - if (!isLDHChar(c)) { - throw new IllegalArgumentException("Contains non-LDH characters"); + if (isNonLDHAsciiCodePoint(c)) { + throw new IllegalArgumentException( + "Contains non-LDH ASCII characters"); } } - if (dest.charAt(0) == '-' || dest.charAt(dest.length() - 1) == '-') { - throw new IllegalArgumentException("Has leading or trailing hyphen"); + if (dest.charAt(0) == '-' || + dest.charAt(dest.length() - 1) == '-') { + + throw new IllegalArgumentException( + "Has leading or trailing hyphen"); } } @@ -401,26 +405,20 @@ public final class IDN { // // LDH stands for "letter/digit/hyphen", with characters restricted to the // 26-letter Latin alphabet , the digits <0-9>, and the hyphen - // <-> - // non-LDH = 0..0x2C, 0x2E..0x2F, 0x3A..0x40, 0x56..0x60, 0x7B..0x7F + // <->. + // Non LDH refers to characters in the ASCII range, but which are not + // letters, digits or the hypen. // - private static boolean isLDHChar(int ch){ - // high runner case - if(ch > 0x007A){ - return false; - } - //['-' '0'..'9' 'A'..'Z' 'a'..'z'] - if((ch == 0x002D) || - (0x0030 <= ch && ch <= 0x0039) || - (0x0041 <= ch && ch <= 0x005A) || - (0x0061 <= ch && ch <= 0x007A) - ){ - return true; - } - return false; + // non-LDH = 0..0x2C, 0x2E..0x2F, 0x3A..0x40, 0x5B..0x60, 0x7B..0x7F + // + private static boolean isNonLDHAsciiCodePoint(int ch){ + return (0x0000 <= ch && ch <= 0x002C) || + (0x002E <= ch && ch <= 0x002F) || + (0x003A <= ch && ch <= 0x0040) || + (0x005B <= ch && ch <= 0x0060) || + (0x007B <= ch && ch <= 0x007F); } - // // search dots in a string and return the index of that character; // or if there is no dots, return the length of input string diff --git a/jdk/test/java/net/IDN/UseSTD3ASCIIRules.java b/jdk/test/java/net/IDN/UseSTD3ASCIIRules.java new file mode 100644 index 00000000000..0afc4a912ca --- /dev/null +++ b/jdk/test/java/net/IDN/UseSTD3ASCIIRules.java @@ -0,0 +1,80 @@ +/* + * 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 8023881 + * @summary IDN.USE_STD3_ASCII_RULES option is too strict to use Unicode + * in IDN.toASCII + */ + +import java.net.*; + +public class UseSTD3ASCIIRules { + + public static void main(String[] args) throws Exception { + // Per Section 4.1, RFC 3490, if the UseSTD3ASCIIRules flag is set, + // then perform these checks: + // + // (a) Verify the absence of non-LDH ASCII code points; that is, the + // absence of 0..2C, 2E..2F, 3A..40, 5B..60, and 7B..7F. + // + // (b) Verify the absence of leading and trailing hyphen-minus; that + // is, the absence of U+002D at the beginning and end of the + // sequence. + String[] illegalNames = { + "www.example.com-", + "-www.example.com", + "-www.example.com-", + "www.ex\u002Cmple.com", + "www.ex\u007Bmple.com", + "www.ex\u007Fmple.com" + }; + + String[] legalNames = { + "www.ex-ample.com", + "www.ex\u002Dmple.com", // www.ex-mple.com + "www.ex\u007Ample.com", // www.exzmple.com + "www.ex\u3042mple.com", // www.xn--exmple-j43e.com + "www.\u3042\u3044\u3046.com", // www.xn--l8jeg.com + "www.\u793A\u4F8B.com" // www.xn--fsq092h.com + }; + + for (String name : illegalNames) { + try { + System.out.println("Convering illegal IDN: " + name); + IDN.toASCII(name, IDN.USE_STD3_ASCII_RULES); + throw new Exception( + "Expected to get IllegalArgumentException for " + name); + } catch (IllegalArgumentException iae) { + // That's the right behavior. + } + } + + for (String name : legalNames) { + System.out.println("Convering legal IDN: " + name); + System.out.println("\tThe ACE form is: " + + IDN.toASCII(name, IDN.USE_STD3_ASCII_RULES)); + } + } +} From dbca0a2b8590e59b65e4bb9adfff1d92d96f3757 Mon Sep 17 00:00:00 2001 From: Shanliang Jiang Date: Fri, 30 Aug 2013 12:49:41 +0200 Subject: [PATCH 021/218] 6566891: RMIConnector: map value referencing map key in WeakHashMap prevents map entry to be removed Reviewed-by: egahlin, jbachorik, dfuchs, dholmes --- .../management/remote/rmi/RMIConnector.java | 33 +++-- .../RMIConnectorInternalMapTest.java | 122 ++++++++++++++++++ .../RMIConnectorNullSubjectConnTest.java | 105 +++++++++++++++ 3 files changed, 250 insertions(+), 10 deletions(-) create mode 100644 jdk/test/javax/management/remote/mandatory/connection/RMIConnectorInternalMapTest.java create mode 100644 jdk/test/javax/management/remote/mandatory/connection/RMIConnectorNullSubjectConnTest.java diff --git a/jdk/src/share/classes/javax/management/remote/rmi/RMIConnector.java b/jdk/src/share/classes/javax/management/remote/rmi/RMIConnector.java index 53e6754e6ed..4868b94b2ff 100644 --- a/jdk/src/share/classes/javax/management/remote/rmi/RMIConnector.java +++ b/jdk/src/share/classes/javax/management/remote/rmi/RMIConnector.java @@ -405,14 +405,7 @@ public class RMIConnector implements JMXConnector, Serializable, JMXAddressable throw new IOException("Not connected"); } - MBeanServerConnection rmbsc = rmbscMap.get(delegationSubject); - if (rmbsc != null) { - return rmbsc; - } - - rmbsc = new RemoteMBeanServerConnection(delegationSubject); - rmbscMap.put(delegationSubject, rmbsc); - return rmbsc; + return getConnectionWithSubject(delegationSubject); } public void @@ -1831,7 +1824,7 @@ public class RMIConnector implements JMXConnector, Serializable, JMXAddressable // Initialization of transient variables. private void initTransients() { - rmbscMap = new WeakHashMap(); + rmbscMap = new WeakHashMap>(); connected = false; terminated = false; @@ -2011,6 +2004,25 @@ public class RMIConnector implements JMXConnector, Serializable, JMXAddressable private final ClassLoader loader; } + private MBeanServerConnection getConnectionWithSubject(Subject delegationSubject) { + MBeanServerConnection conn = null; + + if (delegationSubject == null) { + if (nullSubjectConnRef == null + || (conn = nullSubjectConnRef.get()) == null) { + conn = new RemoteMBeanServerConnection(null); + nullSubjectConnRef = new WeakReference(conn); + } + } else { + WeakReference wr = rmbscMap.get(delegationSubject); + if (wr == null || (conn = wr.get()) == null) { + conn = new RemoteMBeanServerConnection(delegationSubject); + rmbscMap.put(delegationSubject, new WeakReference(conn)); + } + } + return conn; + } + /* The following section of code avoids a class loading problem with RMI. The problem is that an RMI stub, when deserializing @@ -2551,7 +2563,8 @@ public class RMIConnector implements JMXConnector, Serializable, JMXAddressable private transient long clientNotifSeqNo = 0; - private transient WeakHashMap rmbscMap; + private transient WeakHashMap> rmbscMap; + private transient WeakReference nullSubjectConnRef = null; private transient RMINotifClient rmiNotifClient; // = new RMINotifClient(new Integer(0)); diff --git a/jdk/test/javax/management/remote/mandatory/connection/RMIConnectorInternalMapTest.java b/jdk/test/javax/management/remote/mandatory/connection/RMIConnectorInternalMapTest.java new file mode 100644 index 00000000000..86efed134f3 --- /dev/null +++ b/jdk/test/javax/management/remote/mandatory/connection/RMIConnectorInternalMapTest.java @@ -0,0 +1,122 @@ +/* + * 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.lang.management.ManagementFactory; +import java.lang.ref.WeakReference; +import java.lang.reflect.Field; +import java.util.Collections; +import java.util.Map; +import javax.management.MBeanServer; +import javax.management.MBeanServerConnection; +import javax.management.remote.JMXConnector; +import javax.management.remote.JMXConnectorFactory; +import javax.management.remote.JMXConnectorServer; +import javax.management.remote.JMXConnectorServerFactory; +import javax.management.remote.JMXPrincipal; +import javax.management.remote.JMXServiceURL; +import javax.management.remote.rmi.RMIConnector; +import javax.security.auth.Subject; + +/* + * @test + * @bug 6566891 + * @summary Check no memory leak on RMIConnector's rmbscMap + * @author Shanliang JIANG + * @run clean RMIConnectorInternalMapTest + * @run build RMIConnectorInternalMapTest + * @run main RMIConnectorInternalMapTest + */ + +public class RMIConnectorInternalMapTest { + public static void main(String[] args) throws Exception { + System.out.println("---RMIConnectorInternalMapTest starting..."); + + JMXConnectorServer connectorServer = null; + JMXConnector connectorClient = null; + + try { + MBeanServer mserver = ManagementFactory.getPlatformMBeanServer(); + JMXServiceURL serverURL = new JMXServiceURL("rmi", "localhost", 0); + connectorServer = JMXConnectorServerFactory.newJMXConnectorServer(serverURL, null, mserver); + connectorServer.start(); + + JMXServiceURL serverAddr = connectorServer.getAddress(); + connectorClient = JMXConnectorFactory.connect(serverAddr, null); + connectorClient.connect(); + + Field rmbscMapField = RMIConnector.class.getDeclaredField("rmbscMap"); + rmbscMapField.setAccessible(true); + Map> map = + (Map>) rmbscMapField.get(connectorClient); + if (map != null && !map.isEmpty()) { // failed + throw new RuntimeException("RMIConnector's rmbscMap must be empty at the initial time."); + } + + Subject delegationSubject = + new Subject(true, + Collections.singleton(new JMXPrincipal("delegate")), + Collections.EMPTY_SET, + Collections.EMPTY_SET); + MBeanServerConnection mbsc1 = + connectorClient.getMBeanServerConnection(delegationSubject); + MBeanServerConnection mbsc2 = + connectorClient.getMBeanServerConnection(delegationSubject); + + if (mbsc1 == null) { + throw new RuntimeException("Got null connection."); + } + if (mbsc1 != mbsc2) { + throw new RuntimeException("Not got same connection with a same subject."); + } + + map = (Map>) rmbscMapField.get(connectorClient); + if (map == null || map.isEmpty()) { // failed + throw new RuntimeException("RMIConnector's rmbscMap has wrong size " + + "after creating a delegated connection."); + } + + delegationSubject = null; + mbsc1 = null; + mbsc2 = null; + + int i = 0; + while (!map.isEmpty() && i++ < 60) { + System.gc(); + Thread.sleep(100); + } + System.out.println("---GC times: " + i); + + if (!map.isEmpty()) { + throw new RuntimeException("Failed to clean RMIConnector's rmbscMap"); + } else { + System.out.println("---RMIConnectorInternalMapTest: PASSED!"); + } + } finally { + try { + connectorClient.close(); + connectorServer.stop(); + } catch (Exception e) { + } + } + } +} diff --git a/jdk/test/javax/management/remote/mandatory/connection/RMIConnectorNullSubjectConnTest.java b/jdk/test/javax/management/remote/mandatory/connection/RMIConnectorNullSubjectConnTest.java new file mode 100644 index 00000000000..7b5224e9b92 --- /dev/null +++ b/jdk/test/javax/management/remote/mandatory/connection/RMIConnectorNullSubjectConnTest.java @@ -0,0 +1,105 @@ +/* + * 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.lang.management.ManagementFactory; +import java.lang.ref.WeakReference; +import java.lang.reflect.Field; +import javax.management.MBeanServer; +import javax.management.MBeanServerConnection; +import javax.management.remote.JMXConnector; +import javax.management.remote.JMXConnectorFactory; +import javax.management.remote.JMXConnectorServer; +import javax.management.remote.JMXConnectorServerFactory; +import javax.management.remote.JMXServiceURL; +import javax.management.remote.rmi.RMIConnector; + +/* + * @test + * @bug 6566891 + * @summary Check no memory leak on RMIConnector's nullSubjectConn + * @author Shanliang JIANG + * @run clean RMIConnectorNullSubjectConnTest + * @run build RMIConnectorNullSubjectConnTest + * @run main RMIConnectorNullSubjectConnTest + */ + +public class RMIConnectorNullSubjectConnTest { + public static void main(String[] args) throws Exception { + System.out.println("---RMIConnectorNullSubjectConnTest starting..."); + + JMXConnectorServer connectorServer = null; + JMXConnector connectorClient = null; + + try { + MBeanServer mserver = ManagementFactory.getPlatformMBeanServer(); + JMXServiceURL serverURL = new JMXServiceURL("rmi", "localhost", 0); + connectorServer = JMXConnectorServerFactory.newJMXConnectorServer(serverURL, null, mserver); + connectorServer.start(); + + JMXServiceURL serverAddr = connectorServer.getAddress(); + connectorClient = JMXConnectorFactory.connect(serverAddr, null); + connectorClient.connect(); + + Field nullSubjectConnField = RMIConnector.class.getDeclaredField("nullSubjectConnRef"); + nullSubjectConnField.setAccessible(true); + + WeakReference weak = + (WeakReference)nullSubjectConnField.get(connectorClient); + + if (weak != null && weak.get() != null) { + throw new RuntimeException("nullSubjectConnRef must be null at initial time."); + } + + MBeanServerConnection conn1 = connectorClient.getMBeanServerConnection(null); + MBeanServerConnection conn2 = connectorClient.getMBeanServerConnection(null); + if (conn1 == null) { + throw new RuntimeException("A connection with null subject should not be null."); + } else if (conn1 != conn2) { + throw new RuntimeException("The 2 connections with null subject are not equal."); + } + + conn1 = null; + conn2 = null; + int i = 1; + do { + System.gc(); + Thread.sleep(100); + weak = (WeakReference)nullSubjectConnField.get(connectorClient); + } while ((weak != null && weak.get() != null) && i++ < 60); + + System.out.println("---GC times: " + i); + + if (weak != null && weak.get() != null) { + throw new RuntimeException("Failed to clean RMIConnector's nullSubjectConn"); + } else { + System.out.println("---RMIConnectorNullSubjectConnTest: PASSED!"); + } + } finally { + try { + connectorClient.close(); + connectorServer.stop(); + } catch (Exception e) { + } + } + } +} From d6854baa4e31c6d02fa25ca51e6d8dd1b539e6ea Mon Sep 17 00:00:00 2001 From: Dan Xu Date: Fri, 30 Aug 2013 16:45:45 -0700 Subject: [PATCH 022/218] 8023765: Improve MaxPathLength.java testcase and reduce its test load 7160013: java/io/File/MaxPathLength.java fails Reviewed-by: alanb --- jdk/test/ProblemList.txt | 7 --- jdk/test/java/io/File/MaxPathLength.java | 67 ++++++++++++++---------- 2 files changed, 39 insertions(+), 35 deletions(-) diff --git a/jdk/test/ProblemList.txt b/jdk/test/ProblemList.txt index 1f594fe3d3b..26c4eb54a55 100644 --- a/jdk/test/ProblemList.txt +++ b/jdk/test/ProblemList.txt @@ -205,13 +205,6 @@ sun/net/www/http/HttpClient/ProxyTest.java generic-all ############################################################################ -# jdk_io - -# 7160013 -#java/io/File/MaxPathLength.java windows-all - -############################################################################ - # jdk_nio # 6963118 diff --git a/jdk/test/java/io/File/MaxPathLength.java b/jdk/test/java/io/File/MaxPathLength.java index 7ec379cf1d1..9fd6183f36d 100644 --- a/jdk/test/java/io/File/MaxPathLength.java +++ b/jdk/test/java/io/File/MaxPathLength.java @@ -22,7 +22,7 @@ */ /* @test - @bug 4759207 4403166 4165006 4403166 6182812 6274272 + @bug 4759207 4403166 4165006 4403166 6182812 6274272 7160013 @summary Test to see if win32 path length can be greater than 260 */ @@ -37,6 +37,10 @@ public class MaxPathLength { "areallylongfilenamethatsforsur"; private static boolean isWindows = false; + private final static int MAX_LENGTH = 256; + + private static int counter = 0; + public static void main(String[] args) throws Exception { String osName = System.getProperty("os.name"); if (osName.startsWith("Windows")) { @@ -45,33 +49,39 @@ public class MaxPathLength { for (int i = 4; i < 7; i++) { String name = fileName; - while (name.length() < 256) { + while (name.length() < MAX_LENGTH) { testLongPath (i, name, false); testLongPath (i, name, true); - name += "A"; + name = getNextName(name); } } // test long paths on windows + // And these long pathes cannot be handled on Solaris and Mac platforms if (isWindows) { String name = fileName; - while (name.length() < 256) { + while (name.length() < MAX_LENGTH) { testLongPath (20, name, false); testLongPath (20, name, true); - name += "A"; + name = getNextName(name); } } } + private static String getNextName(String fName) { + return (fName.length() < MAX_LENGTH/2) ? fName + fName + : fName + "A"; + } + static void testLongPath(int max, String fn, boolean tryAbsolute) throws Exception { String[] created = new String[max]; String pathString = "."; for (int i = 0; i < max -1; i++) { - pathString = pathString + pathComponent; + pathString = pathString + pathComponent + (counter++); created[max - 1 -i] = pathString; - } + File dirFile = new File(pathString); File f = new File(pathString + sep + fn); @@ -88,9 +98,10 @@ public class MaxPathLength { System.err.println("Warning: Test directory structure exists already!"); return; } - Files.createDirectories(dirFile.toPath()); try { + Files.createDirectories(dirFile.toPath()); + if (tryAbsolute) dirFile = new File(dirFile.getCanonicalPath()); if (!dirFile.isDirectory()) @@ -99,6 +110,7 @@ public class MaxPathLength { if (!f.createNewFile()) { throw new RuntimeException ("File.createNewFile() failed"); } + if (!f.exists()) throw new RuntimeException ("File.exists() failed"); if (!f.isFile()) @@ -107,11 +119,14 @@ public class MaxPathLength { throw new RuntimeException ("File.canRead() failed"); if (!f.canWrite()) throw new RuntimeException ("File.canWrite() failed"); + if (!f.delete()) throw new RuntimeException ("File.delete() failed"); + FileOutputStream fos = new FileOutputStream(f); fos.write(1); fos.close(); + if (f.length() != 1) throw new RuntimeException ("File.length() failed"); long time = System.currentTimeMillis(); @@ -148,30 +163,26 @@ public class MaxPathLength { throw new RuntimeException ("File.renameTo() failed for lenth=" + abPath.length()); } - return; + } else { + if (!nf.canRead()) + throw new RuntimeException ("Renamed file is not readable"); + if (!nf.canWrite()) + throw new RuntimeException ("Renamed file is not writable"); + if (nf.length() != 1) + throw new RuntimeException ("Renamed file's size is not correct"); + if (!nf.renameTo(f)) { + created[0] = nf.getPath(); + } + /* add a script to test these two if we got a regression later + if (!f.setReadOnly()) + throw new RuntimeException ("File.setReadOnly() failed"); + f.deleteOnExit(); + */ } - if (!nf.canRead()) - throw new RuntimeException ("Renamed file is not readable"); - if (!nf.canWrite()) - throw new RuntimeException ("Renamed file is not writable"); - if (nf.length() != 1) - throw new RuntimeException ("Renamed file's size is not correct"); - nf.renameTo(f); - /* add a script to test these two if we got a regression later - if (!f.setReadOnly()) - throw new RuntimeException ("File.setReadOnly() failed"); - f.deleteOnExit(); - */ } finally { // Clean up for (int i = 0; i < max; i++) { - pathString = created[i]; - // Only works with completex canonical paths - File df = new File(pathString); - pathString = df.getCanonicalPath(); - df = new File(pathString); - if (!df.delete()) - System.out.printf("Delete failed->%s\n", pathString); + Files.deleteIfExists((new File(created[i])).toPath()); } } } From 1cff90b3353b16370bd7784ab1f2dd52367d3d1f Mon Sep 17 00:00:00 2001 From: Xue-Lei Andrew Fan Date: Sun, 1 Sep 2013 20:00:03 -0700 Subject: [PATCH 023/218] 8024068: sun/security/ssl/javax/net/ssl/ServerName/IllegalSNIName.java fails Reviewed-by: weijun --- .../security/ssl/javax/net/ssl/ServerName/IllegalSNIName.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jdk/test/sun/security/ssl/javax/net/ssl/ServerName/IllegalSNIName.java b/jdk/test/sun/security/ssl/javax/net/ssl/ServerName/IllegalSNIName.java index 4d5460739cd..a6a6912c0aa 100644 --- a/jdk/test/sun/security/ssl/javax/net/ssl/ServerName/IllegalSNIName.java +++ b/jdk/test/sun/security/ssl/javax/net/ssl/ServerName/IllegalSNIName.java @@ -34,7 +34,7 @@ public class IllegalSNIName { public static void main(String[] args) throws Exception { String[] illegalNames = { - "example\u3003\u3002com", + "example\u3002\u3002com", "example..com", "com\u3002", "com.", From ff0317b09805c47be8bf6a09cc07150c2dcea4e6 Mon Sep 17 00:00:00 2001 From: Chris Hegarty Date: Mon, 2 Sep 2013 14:02:35 +0100 Subject: [PATCH 024/218] 8024103: AtomicLongArray getAndAccumulate/accumulateAndGet have int type for new value arg Reviewed-by: alanb, psandoz --- .../classes/java/util/concurrent/atomic/AtomicLongArray.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jdk/src/share/classes/java/util/concurrent/atomic/AtomicLongArray.java b/jdk/src/share/classes/java/util/concurrent/atomic/AtomicLongArray.java index bf7aa6ecca8..28174a586ff 100644 --- a/jdk/src/share/classes/java/util/concurrent/atomic/AtomicLongArray.java +++ b/jdk/src/share/classes/java/util/concurrent/atomic/AtomicLongArray.java @@ -303,7 +303,7 @@ public class AtomicLongArray implements java.io.Serializable { * @return the previous value * @since 1.8 */ - public final long getAndAccumulate(int i, int x, + public final long getAndAccumulate(int i, long x, LongBinaryOperator accumulatorFunction) { long offset = checkedByteOffset(i); long prev, next; @@ -329,7 +329,7 @@ public class AtomicLongArray implements java.io.Serializable { * @return the updated value * @since 1.8 */ - public final long accumulateAndGet(int i, int x, + public final long accumulateAndGet(int i, long x, LongBinaryOperator accumulatorFunction) { long offset = checkedByteOffset(i); long prev, next; From b81e7785d1fd24ed0833d7b14b04a9383734cfcd Mon Sep 17 00:00:00 2001 From: Daniel Fuchs Date: Mon, 2 Sep 2013 18:28:50 +0200 Subject: [PATCH 025/218] 8016127: NLS: logging.properties translatability recommendation 8024131: Issues with cached localizedLevelName in java.util.logging.Level This fix updates logging.properties resource bundles to follow internationalization guidelines. It also fixes a caching issue with localizedLevelName. The regression test that was added needs both fixes to pass. Reviewed-by: mchung, alanb --- .../classes/java/util/logging/Level.java | 72 +++++++++++- .../util/logging/resources/logging.properties | 18 +-- .../logging/resources/logging_de.properties | 18 +-- .../logging/resources/logging_es.properties | 18 +-- .../logging/resources/logging_fr.properties | 18 +-- .../logging/resources/logging_it.properties | 18 +-- .../logging/resources/logging_ja.properties | 12 +- .../logging/resources/logging_ko.properties | 18 +-- .../resources/logging_pt_BR.properties | 18 +-- .../logging/resources/logging_sv.properties | 18 +-- .../resources/logging_zh_CN.properties | 18 +-- .../resources/logging_zh_TW.properties | 12 +- .../java/util/logging/LocalizedLevelName.java | 103 ++++++++++++++++++ 13 files changed, 262 insertions(+), 99 deletions(-) create mode 100644 jdk/test/java/util/logging/LocalizedLevelName.java diff --git a/jdk/src/share/classes/java/util/logging/Level.java b/jdk/src/share/classes/java/util/logging/Level.java index 6847518ce02..936925624e4 100644 --- a/jdk/src/share/classes/java/util/logging/Level.java +++ b/jdk/src/share/classes/java/util/logging/Level.java @@ -27,6 +27,7 @@ package java.util.logging; import java.util.ArrayList; import java.util.HashMap; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.ResourceBundle; @@ -63,7 +64,7 @@ import java.util.ResourceBundle; */ public class Level implements java.io.Serializable { - private static String defaultBundle = "sun.util.logging.resources.logging"; + private static final String defaultBundle = "sun.util.logging.resources.logging"; /** * @serial The non-localized name of the level. @@ -81,7 +82,8 @@ public class Level implements java.io.Serializable { private final String resourceBundleName; // localized level name - private String localizedLevelName; + private transient String localizedLevelName; + private transient Locale cachedLocale; /** * OFF is a special level that can be used to turn off logging. @@ -209,6 +211,7 @@ public class Level implements java.io.Serializable { this.value = value; this.resourceBundleName = resourceBundleName; this.localizedLevelName = resourceBundleName == null ? name : null; + this.cachedLocale = null; KnownLevel.add(this); } @@ -250,17 +253,71 @@ public class Level implements java.io.Serializable { return this.name; } - final synchronized String getLocalizedLevelName() { + private String computeLocalizedLevelName(Locale newLocale) { + ResourceBundle rb = ResourceBundle.getBundle(resourceBundleName, newLocale); + final String localizedName = rb.getString(name); + + final boolean isDefaultBundle = defaultBundle.equals(resourceBundleName); + if (!isDefaultBundle) return localizedName; + + // This is a trick to determine whether the name has been translated + // or not. If it has not been translated, we need to use Locale.ROOT + // when calling toUpperCase(). + final Locale rbLocale = rb.getLocale(); + final Locale locale = + Locale.ROOT.equals(rbLocale) + || name.equals(localizedName.toUpperCase(Locale.ROOT)) + ? Locale.ROOT : rbLocale; + + // ALL CAPS in a resource bundle's message indicates no translation + // needed per Oracle translation guideline. To workaround this + // in Oracle JDK implementation, convert the localized level name + // to uppercase for compatibility reason. + return Locale.ROOT.equals(locale) ? name : localizedName.toUpperCase(locale); + } + + // Avoid looking up the localizedLevelName twice if we already + // have it. + final String getCachedLocalizedLevelName() { + if (localizedLevelName != null) { - return localizedLevelName; + if (cachedLocale != null) { + if (cachedLocale.equals(Locale.getDefault())) { + // OK: our cached value was looked up with the same + // locale. We can use it. + return localizedLevelName; + } + } } + if (resourceBundleName == null) { + // No resource bundle: just use the name. + return name; + } + + // We need to compute the localized name. + // Either because it's the first time, or because our cached + // value is for a different locale. Just return null. + return null; + } + + final synchronized String getLocalizedLevelName() { + + // See if we have a cached localized name + final String cachedLocalizedName = getCachedLocalizedLevelName(); + if (cachedLocalizedName != null) { + return cachedLocalizedName; + } + + // No cached localized name or cache invalid. + // Need to compute the localized name. + final Locale newLocale = Locale.getDefault(); try { - ResourceBundle rb = ResourceBundle.getBundle(resourceBundleName); - localizedLevelName = rb.getString(name); + localizedLevelName = computeLocalizedLevelName(newLocale); } catch (Exception ex) { localizedLevelName = name; } + cachedLocale = newLocale; return localizedLevelName; } @@ -318,6 +375,7 @@ public class Level implements java.io.Serializable { * * @return the non-localized name of the Level, for example "INFO". */ + @Override public final String toString() { return name; } @@ -420,6 +478,7 @@ public class Level implements java.io.Serializable { * Compare two objects for value equality. * @return true if and only if the two objects have the same level value. */ + @Override public boolean equals(Object ox) { try { Level lx = (Level)ox; @@ -433,6 +492,7 @@ public class Level implements java.io.Serializable { * Generate a hashcode. * @return a hashcode based on the level value */ + @Override public int hashCode() { return this.value; } diff --git a/jdk/src/share/classes/sun/util/logging/resources/logging.properties b/jdk/src/share/classes/sun/util/logging/resources/logging.properties index da17c47f8fd..248b4d7fcbe 100644 --- a/jdk/src/share/classes/sun/util/logging/resources/logging.properties +++ b/jdk/src/share/classes/sun/util/logging/resources/logging.properties @@ -27,20 +27,20 @@ # these are the same as the non-localized level name. # The following ALL CAPS words should be translated. -ALL=ALL +ALL=All # The following ALL CAPS words should be translated. -SEVERE=SEVERE +SEVERE=Severe # The following ALL CAPS words should be translated. -WARNING=WARNING +WARNING=Warning # The following ALL CAPS words should be translated. -INFO=INFO +INFO=Info # The following ALL CAPS words should be translated. -CONFIG= CONFIG +CONFIG= Config # The following ALL CAPS words should be translated. -FINE=FINE +FINE=Fine # The following ALL CAPS words should be translated. -FINER=FINER +FINER=Finer # The following ALL CAPS words should be translated. -FINEST=FINEST +FINEST=Finest # The following ALL CAPS words should be translated. -OFF=OFF +OFF=Off diff --git a/jdk/src/share/classes/sun/util/logging/resources/logging_de.properties b/jdk/src/share/classes/sun/util/logging/resources/logging_de.properties index da17c47f8fd..1aa8ef4e22c 100644 --- a/jdk/src/share/classes/sun/util/logging/resources/logging_de.properties +++ b/jdk/src/share/classes/sun/util/logging/resources/logging_de.properties @@ -27,20 +27,20 @@ # these are the same as the non-localized level name. # The following ALL CAPS words should be translated. -ALL=ALL +ALL=Alle # The following ALL CAPS words should be translated. -SEVERE=SEVERE +SEVERE=Schwerwiegend # The following ALL CAPS words should be translated. -WARNING=WARNING +WARNING=Warnung # The following ALL CAPS words should be translated. -INFO=INFO +INFO=Information # The following ALL CAPS words should be translated. -CONFIG= CONFIG +CONFIG= Konfiguration # The following ALL CAPS words should be translated. -FINE=FINE +FINE=Fein # The following ALL CAPS words should be translated. -FINER=FINER +FINER=Feiner # The following ALL CAPS words should be translated. -FINEST=FINEST +FINEST=Am feinsten # The following ALL CAPS words should be translated. -OFF=OFF +OFF=Deaktiviert diff --git a/jdk/src/share/classes/sun/util/logging/resources/logging_es.properties b/jdk/src/share/classes/sun/util/logging/resources/logging_es.properties index da17c47f8fd..90de2e88238 100644 --- a/jdk/src/share/classes/sun/util/logging/resources/logging_es.properties +++ b/jdk/src/share/classes/sun/util/logging/resources/logging_es.properties @@ -27,20 +27,20 @@ # these are the same as the non-localized level name. # The following ALL CAPS words should be translated. -ALL=ALL +ALL=Todo # The following ALL CAPS words should be translated. -SEVERE=SEVERE +SEVERE=Grave # The following ALL CAPS words should be translated. -WARNING=WARNING +WARNING=Advertencia # The following ALL CAPS words should be translated. -INFO=INFO +INFO=Informaci\u00F3n # The following ALL CAPS words should be translated. -CONFIG= CONFIG +CONFIG= Configurar # The following ALL CAPS words should be translated. -FINE=FINE +FINE=Detallado # The following ALL CAPS words should be translated. -FINER=FINER +FINER=Muy Detallado # The following ALL CAPS words should be translated. -FINEST=FINEST +FINEST=M\u00E1s Detallado # The following ALL CAPS words should be translated. -OFF=OFF +OFF=Desactivado diff --git a/jdk/src/share/classes/sun/util/logging/resources/logging_fr.properties b/jdk/src/share/classes/sun/util/logging/resources/logging_fr.properties index da17c47f8fd..af34d6fa414 100644 --- a/jdk/src/share/classes/sun/util/logging/resources/logging_fr.properties +++ b/jdk/src/share/classes/sun/util/logging/resources/logging_fr.properties @@ -27,20 +27,20 @@ # these are the same as the non-localized level name. # The following ALL CAPS words should be translated. -ALL=ALL +ALL=Tout # The following ALL CAPS words should be translated. -SEVERE=SEVERE +SEVERE=Grave # The following ALL CAPS words should be translated. -WARNING=WARNING +WARNING=Avertissement # The following ALL CAPS words should be translated. -INFO=INFO +INFO=Infos # The following ALL CAPS words should be translated. -CONFIG= CONFIG +CONFIG= Config # The following ALL CAPS words should be translated. -FINE=FINE +FINE=Pr\u00E9cis # The following ALL CAPS words should be translated. -FINER=FINER +FINER=Plus pr\u00E9cis # The following ALL CAPS words should be translated. -FINEST=FINEST +FINEST=Le plus pr\u00E9cis # The following ALL CAPS words should be translated. -OFF=OFF +OFF=D\u00E9sactiv\u00E9 diff --git a/jdk/src/share/classes/sun/util/logging/resources/logging_it.properties b/jdk/src/share/classes/sun/util/logging/resources/logging_it.properties index da17c47f8fd..73a3b5c59cf 100644 --- a/jdk/src/share/classes/sun/util/logging/resources/logging_it.properties +++ b/jdk/src/share/classes/sun/util/logging/resources/logging_it.properties @@ -27,20 +27,20 @@ # these are the same as the non-localized level name. # The following ALL CAPS words should be translated. -ALL=ALL +ALL=Tutto # The following ALL CAPS words should be translated. -SEVERE=SEVERE +SEVERE=Grave # The following ALL CAPS words should be translated. -WARNING=WARNING +WARNING=Avvertenza # The following ALL CAPS words should be translated. -INFO=INFO +INFO=Informazioni # The following ALL CAPS words should be translated. -CONFIG= CONFIG +CONFIG= Configurazione # The following ALL CAPS words should be translated. -FINE=FINE +FINE=Buono # The following ALL CAPS words should be translated. -FINER=FINER +FINER=Migliore # The following ALL CAPS words should be translated. -FINEST=FINEST +FINEST=Ottimale # The following ALL CAPS words should be translated. -OFF=OFF +OFF=Non attivo diff --git a/jdk/src/share/classes/sun/util/logging/resources/logging_ja.properties b/jdk/src/share/classes/sun/util/logging/resources/logging_ja.properties index 980c33549c5..60358d1c86e 100644 --- a/jdk/src/share/classes/sun/util/logging/resources/logging_ja.properties +++ b/jdk/src/share/classes/sun/util/logging/resources/logging_ja.properties @@ -29,18 +29,18 @@ # The following ALL CAPS words should be translated. ALL=\u3059\u3079\u3066 # The following ALL CAPS words should be translated. -SEVERE=SEVERE +SEVERE=\u91CD\u5927 # The following ALL CAPS words should be translated. -WARNING=WARNING +WARNING=\u8B66\u544A # The following ALL CAPS words should be translated. INFO=\u60C5\u5831 # The following ALL CAPS words should be translated. -CONFIG= CONFIG +CONFIG= \u69CB\u6210 # The following ALL CAPS words should be translated. -FINE=\u8A73\u7D30\u30EC\u30D9\u30EB(\u4F4E) +FINE=\u666E\u901A # The following ALL CAPS words should be translated. -FINER=FINER +FINER=\u8A73\u7D30 # The following ALL CAPS words should be translated. -FINEST=FINEST +FINEST=\u6700\u3082\u8A73\u7D30 # The following ALL CAPS words should be translated. OFF=\u30AA\u30D5 diff --git a/jdk/src/share/classes/sun/util/logging/resources/logging_ko.properties b/jdk/src/share/classes/sun/util/logging/resources/logging_ko.properties index da17c47f8fd..6d5dc551e67 100644 --- a/jdk/src/share/classes/sun/util/logging/resources/logging_ko.properties +++ b/jdk/src/share/classes/sun/util/logging/resources/logging_ko.properties @@ -27,20 +27,20 @@ # these are the same as the non-localized level name. # The following ALL CAPS words should be translated. -ALL=ALL +ALL=\uBAA8\uB450 # The following ALL CAPS words should be translated. -SEVERE=SEVERE +SEVERE=\uC2EC\uAC01 # The following ALL CAPS words should be translated. -WARNING=WARNING +WARNING=\uACBD\uACE0 # The following ALL CAPS words should be translated. -INFO=INFO +INFO=\uC815\uBCF4 # The following ALL CAPS words should be translated. -CONFIG= CONFIG +CONFIG= \uAD6C\uC131 # The following ALL CAPS words should be translated. -FINE=FINE +FINE=\uBBF8\uC138 # The following ALL CAPS words should be translated. -FINER=FINER +FINER=\uBCF4\uB2E4 \uBBF8\uC138 # The following ALL CAPS words should be translated. -FINEST=FINEST +FINEST=\uAC00\uC7A5 \uBBF8\uC138 # The following ALL CAPS words should be translated. -OFF=OFF +OFF=\uD574\uC81C diff --git a/jdk/src/share/classes/sun/util/logging/resources/logging_pt_BR.properties b/jdk/src/share/classes/sun/util/logging/resources/logging_pt_BR.properties index da17c47f8fd..29229f2c7c1 100644 --- a/jdk/src/share/classes/sun/util/logging/resources/logging_pt_BR.properties +++ b/jdk/src/share/classes/sun/util/logging/resources/logging_pt_BR.properties @@ -27,20 +27,20 @@ # these are the same as the non-localized level name. # The following ALL CAPS words should be translated. -ALL=ALL +ALL=Tudo # The following ALL CAPS words should be translated. -SEVERE=SEVERE +SEVERE=Grave # The following ALL CAPS words should be translated. -WARNING=WARNING +WARNING=Advert\u00EAncia # The following ALL CAPS words should be translated. -INFO=INFO +INFO=Informa\u00E7\u00F5es # The following ALL CAPS words should be translated. -CONFIG= CONFIG +CONFIG= Configura\u00E7\u00E3o # The following ALL CAPS words should be translated. -FINE=FINE +FINE=Detalhado # The following ALL CAPS words should be translated. -FINER=FINER +FINER=Mais Detalhado # The following ALL CAPS words should be translated. -FINEST=FINEST +FINEST=O Mais Detalhado # The following ALL CAPS words should be translated. -OFF=OFF +OFF=Desativado diff --git a/jdk/src/share/classes/sun/util/logging/resources/logging_sv.properties b/jdk/src/share/classes/sun/util/logging/resources/logging_sv.properties index 4c8dd1d2dcb..b7607863ffb 100644 --- a/jdk/src/share/classes/sun/util/logging/resources/logging_sv.properties +++ b/jdk/src/share/classes/sun/util/logging/resources/logging_sv.properties @@ -27,20 +27,20 @@ # these are the same as the non-localized level name. # The following ALL CAPS words should be translated. -ALL=ALLA +ALL=Alla # The following ALL CAPS words should be translated. -SEVERE=SEVERE +SEVERE=Allvarlig # The following ALL CAPS words should be translated. -WARNING=WARNING +WARNING=Varning # The following ALL CAPS words should be translated. -INFO=INFO +INFO=Info # The following ALL CAPS words should be translated. -CONFIG= CONFIG +CONFIG= Konfig # The following ALL CAPS words should be translated. -FINE=FINE +FINE=Fin # The following ALL CAPS words should be translated. -FINER=FINER +FINER=Finare # The following ALL CAPS words should be translated. -FINEST=FINEST +FINEST=Finaste # The following ALL CAPS words should be translated. -OFF=OFF +OFF=Av diff --git a/jdk/src/share/classes/sun/util/logging/resources/logging_zh_CN.properties b/jdk/src/share/classes/sun/util/logging/resources/logging_zh_CN.properties index da17c47f8fd..67dd2b8b50a 100644 --- a/jdk/src/share/classes/sun/util/logging/resources/logging_zh_CN.properties +++ b/jdk/src/share/classes/sun/util/logging/resources/logging_zh_CN.properties @@ -27,20 +27,20 @@ # these are the same as the non-localized level name. # The following ALL CAPS words should be translated. -ALL=ALL +ALL=\u5168\u90E8 # The following ALL CAPS words should be translated. -SEVERE=SEVERE +SEVERE=\u4E25\u91CD # The following ALL CAPS words should be translated. -WARNING=WARNING +WARNING=\u8B66\u544A # The following ALL CAPS words should be translated. -INFO=INFO +INFO=\u4FE1\u606F # The following ALL CAPS words should be translated. -CONFIG= CONFIG +CONFIG= \u914D\u7F6E # The following ALL CAPS words should be translated. -FINE=FINE +FINE=\u8BE6\u7EC6 # The following ALL CAPS words should be translated. -FINER=FINER +FINER=\u8F83\u8BE6\u7EC6 # The following ALL CAPS words should be translated. -FINEST=FINEST +FINEST=\u975E\u5E38\u8BE6\u7EC6 # The following ALL CAPS words should be translated. -OFF=OFF +OFF=\u7981\u7528 diff --git a/jdk/src/share/classes/sun/util/logging/resources/logging_zh_TW.properties b/jdk/src/share/classes/sun/util/logging/resources/logging_zh_TW.properties index d7ad070a69e..4875bc825c1 100644 --- a/jdk/src/share/classes/sun/util/logging/resources/logging_zh_TW.properties +++ b/jdk/src/share/classes/sun/util/logging/resources/logging_zh_TW.properties @@ -27,20 +27,20 @@ # these are the same as the non-localized level name. # The following ALL CAPS words should be translated. -ALL=\u6240\u6709 +ALL=\u5168\u90E8 # The following ALL CAPS words should be translated. -SEVERE=SEVERE +SEVERE=\u56B4\u91CD # The following ALL CAPS words should be translated. -WARNING=WARNING +WARNING=\u8B66\u544A # The following ALL CAPS words should be translated. INFO=\u8CC7\u8A0A # The following ALL CAPS words should be translated. -CONFIG= CONFIG +CONFIG= \u7D44\u614B # The following ALL CAPS words should be translated. FINE=\u8A73\u7D30 # The following ALL CAPS words should be translated. -FINER=FINER +FINER=\u8F03\u8A73\u7D30 # The following ALL CAPS words should be translated. -FINEST=FINEST +FINEST=\u6700\u8A73\u7D30 # The following ALL CAPS words should be translated. OFF=\u95DC\u9589 diff --git a/jdk/test/java/util/logging/LocalizedLevelName.java b/jdk/test/java/util/logging/LocalizedLevelName.java new file mode 100644 index 00000000000..cdb425a294f --- /dev/null +++ b/jdk/test/java/util/logging/LocalizedLevelName.java @@ -0,0 +1,103 @@ +/* + * 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.*; +import java.util.logging.*; + +/* + * @test + * @bug 8016127 8024131 + * @summary test logging.properties localized + * @run main/othervm LocalizedLevelName + */ + +public class LocalizedLevelName { + private static Object[] namesMap = { + "SEVERE", Locale.ENGLISH, "Severe", Level.SEVERE, + "WARNING", Locale.FRENCH, "Avertissement", Level.WARNING, + "INFO", Locale.ITALIAN, "Informazioni", Level.INFO, + "SEVERE", Locale.FRENCH, "Grave", Level.SEVERE, + "CONFIG", Locale.GERMAN, "Konfiguration", Level.CONFIG, + "ALL", Locale.ROOT, "All", Level.ALL, + "SEVERE", Locale.ROOT, "Severe", Level.SEVERE, + "WARNING", Locale.ROOT, "Warning", Level.WARNING, + "CONFIG", Locale.ROOT, "Config", Level.CONFIG, + "INFO", Locale.ROOT, "Info", Level.INFO, + "FINE", Locale.ROOT, "Fine", Level.FINE, + "FINER", Locale.ROOT, "Finer", Level.FINER, + "FINEST", Locale.ROOT, "Finest", Level.FINEST + }; + + public static void main(String args[]) throws Exception { + Locale defaultLocale = Locale.getDefault(); + for (int i=0; i localized(" + Locale.ENGLISH + ", " + + key + ")=" + en); + System.out.println(" => localized(" + locale + ", " + key + + ")=" + other); + if (!key.equals(en.toUpperCase(Locale.ROOT))) { + throw new RuntimeException("Expect " + key + + " equals upperCase(" + en + ")"); + } + if (!Locale.ENGLISH.equals(locale) && !Locale.ROOT.equals(locale) + && key.equals(other.toUpperCase(Locale.ROOT))) { + throw new RuntimeException("Expect " + key + + " not equals upperCase(" + other +")"); + } + if ((Locale.ENGLISH.equals(locale) || Locale.ROOT.equals(locale)) + && !key.equals(other.toUpperCase(Locale.ROOT))) { + throw new RuntimeException("Expect " + key + + " equals upperCase(" + other +")"); + } + if (!other.equals(expectedTranslation)) { + throw new RuntimeException("Expected \"" + expectedTranslation + + "\" for '" + locale + "' but got \"" + other + "\""); + } + Locale.setDefault(locale); + final String levelName = level.getLocalizedName(); + System.out.println("Level.getLocalizedName() is: " + levelName); + if (!levelName.equals(other.toUpperCase(locale))) { + throw new RuntimeException("Expected \"" + + other.toUpperCase(locale) + "\" for '" + + locale + "' but got \"" + levelName + "\""); + } + Locale.setDefault(defaultLocale); + } + } + + private static final String RBNAME = "sun.util.logging.resources.logging"; + private static String getLocalizedMessage(Locale locale, String key) { + ResourceBundle rb = ResourceBundle.getBundle(RBNAME, locale); + return rb.getString(key); + } +} From f4dda09731a2ceb1a6a633589f14a7a68828eeeb Mon Sep 17 00:00:00 2001 From: Erik Gahlin Date: Mon, 2 Sep 2013 16:03:34 +0200 Subject: [PATCH 026/218] 7172176: java/jconsole test/sun/tools/jconsole/ImmutableResourceTest.sh failing Reviewed-by: mchung, mfang --- .../classes/sun/tools/jconsole/Resources.java | 6 +- jdk/test/ProblemList.txt | 4 - .../tools/jconsole/ImmutableResourceTest.java | 60 --- .../tools/jconsole/ImmutableResourceTest.sh | 111 ----- .../sun/tools/jconsole/ResourceCheckTest.java | 469 +++++------------- .../sun/tools/jconsole/ResourceCheckTest.sh | 4 +- 6 files changed, 118 insertions(+), 536 deletions(-) delete mode 100644 jdk/test/sun/tools/jconsole/ImmutableResourceTest.java delete mode 100644 jdk/test/sun/tools/jconsole/ImmutableResourceTest.sh diff --git a/jdk/src/share/classes/sun/tools/jconsole/Resources.java b/jdk/src/share/classes/sun/tools/jconsole/Resources.java index 785be24d2e6..20af2e9f9e9 100644 --- a/jdk/src/share/classes/sun/tools/jconsole/Resources.java +++ b/jdk/src/share/classes/sun/tools/jconsole/Resources.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,7 +30,7 @@ import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.text.MessageFormat; import java.util.Collections; -import java.util.HashMap; +import java.util.IdentityHashMap; import java.util.Map; import java.util.MissingResourceException; import java.util.ResourceBundle; @@ -40,7 +40,7 @@ import java.util.ResourceBundle; */ public final class Resources { private static Map MNEMONIC_LOOKUP = Collections - .synchronizedMap(new HashMap()); + .synchronizedMap(new IdentityHashMap()); private Resources() { throw new AssertionError(); diff --git a/jdk/test/ProblemList.txt b/jdk/test/ProblemList.txt index 26c4eb54a55..1ac61aa2c3f 100644 --- a/jdk/test/ProblemList.txt +++ b/jdk/test/ProblemList.txt @@ -305,10 +305,6 @@ sun/security/krb5/auto/BadKdc4.java solaris-sparcv9 # 6461635 com/sun/tools/attach/BasicTests.sh generic-all -# 7172176 -sun/tools/jconsole/ResourceCheckTest.sh generic-all -sun/tools/jconsole/ImmutableResourceTest.sh generic-all - # 7132203 sun/jvmstat/monitor/MonitoredVm/CR6672135.java generic-all diff --git a/jdk/test/sun/tools/jconsole/ImmutableResourceTest.java b/jdk/test/sun/tools/jconsole/ImmutableResourceTest.java deleted file mode 100644 index 082776667a4..00000000000 --- a/jdk/test/sun/tools/jconsole/ImmutableResourceTest.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (c) 2005, 2007, 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. - */ - -/** - * - * - * This isn't the test case: ImmutableResourceTest.sh is. - * Refer to ImmutableResourceTest.sh when running this test. - * - * @bug 6287579 - * @summary SubClasses of ListResourceBundle should fix getContents() - */ -import java.util.ResourceBundle; - -public class ImmutableResourceTest { - - public static void main(String[] args) throws Exception { - - /* Reach under the covers and get the message strings */ - sun.tools.jconsole.resources.JConsoleResources jcr = - new sun.tools.jconsole.resources.JConsoleResources (); - Object [][] testData = jcr.getContents(); - - /* Shred our copy of the message strings */ - for (int ii = 0; ii < testData.length; ii++) { - testData[ii][0] = "xxx"; - testData[ii][1] = "yyy"; - } - - /* - * Try a lookup for the shredded key. - * If this is successful we have a problem. - */ - String ss = sun.tools.jconsole.Resources.getText("xxx"); - if ("yyy".equals(ss)) { - throw new Exception ("SubClasses of ListResourceBundle should fix getContents()"); - } - System.out.println("...Finished."); - } -} diff --git a/jdk/test/sun/tools/jconsole/ImmutableResourceTest.sh b/jdk/test/sun/tools/jconsole/ImmutableResourceTest.sh deleted file mode 100644 index dedf21271b0..00000000000 --- a/jdk/test/sun/tools/jconsole/ImmutableResourceTest.sh +++ /dev/null @@ -1,111 +0,0 @@ -# -# Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -# or visit www.oracle.com if you need additional information or have any -# questions. -# - -# @test -# @bug 6287579 -# @summary SubClasses of ListResourceBundle should fix getContents() -# -# @run shell ImmutableResourceTest.sh - -# Beginning of subroutines: -status=1 - -#Call this from anywhere to fail the test with an error message -# usage: fail "reason why the test failed" -fail() - { echo "The test failed :-(" - echo "$*" 1>&2 - echo "exit status was $status" - exit $status - } #end of fail() - -#Call this from anywhere to pass the test with a message -# usage: pass "reason why the test passed if applicable" -pass() - { echo "The test passed!!!" - echo "$*" 1>&2 - exit 0 - } #end of pass() - -# end of subroutines - -# The beginning of the script proper - -OS=`uname -s` -case "$OS" in - SunOS | Linux | Darwin ) - PATHSEP=":" - ;; - - Windows* | CYGWIN*) - PATHSEP=";" - ;; - - # catch all other OSs - * ) - echo "Unrecognized system! $OS" - fail "Unrecognized system! $OS" - ;; -esac - -TARGETCLASS="ImmutableResourceTest" -if [ -z "${TESTJAVA}" ] ; then - # TESTJAVA is not set, so the test is running stand-alone. - # TESTJAVA holds the path to the root directory of the build of the JDK - # to be tested. That is, any java files run explicitly in this shell - # should use TESTJAVA in the path to the java interpreter. - # So, we'll set this to the JDK spec'd on the command line. If none - # is given on the command line, tell the user that and use a default. - # THIS IS THE JDK BEING TESTED. - if [ -n "$1" ] ; then - TESTJAVA=$1 - else - TESTJAVA=$JAVA_HOME - fi - TESTSRC=. - TESTCLASSES=. - #Deal with .class files: -fi -# -echo "JDK under test is: $TESTJAVA" -# -CP="-classpath ${TESTCLASSES}${PATHSEP}${TESTJAVA}/lib/jconsole.jar" -# Compile the test class using the classpath we need: -# -env -# -set -vx -# -#Compile. jconsole.jar is required on the classpath. -${TESTJAVA}/bin/javac -d "${TESTCLASSES}" ${CP} -g \ - "${TESTSRC}"/"${TARGETCLASS}".java -# -#Run the test class, again with the classpath we need: -${TESTJAVA}/bin/java ${CP} ${TARGETCLASS} -status=$? -echo "test status was: $status" -if [ $status -eq "0" ]; - then pass "" - - else fail "unspecified test failure" -fi diff --git a/jdk/test/sun/tools/jconsole/ResourceCheckTest.java b/jdk/test/sun/tools/jconsole/ResourceCheckTest.java index 6d4e27be860..1ed5bb642c7 100644 --- a/jdk/test/sun/tools/jconsole/ResourceCheckTest.java +++ b/jdk/test/sun/tools/jconsole/ResourceCheckTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,377 +27,134 @@ * This isn't the test case: ResourceCheckTest.sh is. * Refer to ResourceCheckTest.sh when running this test. * - * @bug 5008856 5023573 5024917 5062569 + * @bug 5008856 5023573 5024917 5062569 7172176 * @summary 'missing resource key' error for key = "Operating system" */ -import java.awt.event.KeyEvent; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Locale; +import java.util.ResourceBundle; +import sun.tools.jconsole.Messages; import sun.tools.jconsole.Resources; +/* + * Ensures that there is a one-to-one mapping between constants in the + * Message class and the keys in the sun.tools.jconsole.resources.messages + * bundle. + * + * An error will be thrown if there is a: + * + * - key in the resource bundle that doesn't have a public static field with + * the same name in the Message class. + * + * - public static field in the Message class that doesn't have a key with + * the same name in the resource bundle. + * + * - message with a mnemonic identifier(&) for which a mnemonic can't + * be looked up using Resources#getMnemonicInt(). + * + */ public class ResourceCheckTest { + private static final String MISSING_RESOURCE_KEY_PREFIX = "missing message for"; + private static final String RESOURCE_BUNDLE = "sun.tools.jconsole.resources.messages"; + private static final String NEW_LINE = String.format("%n"); - public static void main(String[] args){ - Object [][] testData = { - {"<", "", "", "", ""}, - {"<<", "", "", "", ""}, - {">", "", "", "", ""}, - {" 1 day", "", "", "", ""}, - {" 1 hour", "", "", "", ""}, - {" 1 min", "", "", "", ""}, - {" 1 month", "", "", "", ""}, - {" 1 year", "", "", "", ""}, - {" 2 hours", "", "", "", ""}, - {" 3 hours", "", "", "", ""}, - {" 3 months", "", "", "", ""}, - {" 5 min", "", "", "", ""}, - {" 6 hours", "", "", "", ""}, - {" 6 months", "", "", "", ""}, - {" 7 days", "", "", "", ""}, - {"10 min", "", "", "", ""}, - {"12 hours", "", "", "", ""}, - {"30 min", "", "", "", ""}, - {"ACTION", "", "", "", ""}, - {"ACTION_INFO", "", "", "", ""}, - {"All", "", "", "", ""}, - {"Architecture", "", "", "", ""}, - {"Attribute", "", "", "", ""}, - {"Attribute value", "", "", "", ""}, - {"Attribute values", "", "", "", ""}, - {"Attributes", "", "", "", ""}, - {"Blank", "", "", "", ""}, - {"BlockedCount WaitedCount", "BlockedCount", "WaitedCount", "", ""}, - {"Boot class path", "", "", "", ""}, - {"BorderedComponent.moreOrLessButton.toolTip", "", "", "", ""}, - {"Close", "", "", "", ""}, - {"CPU Usage", "", "", "", ""}, - {"CPUUsageFormat","PhonyPercentage", "", "", ""}, - {"Cancel", "", "", "", ""}, - {"Cascade", "", "", "", ""}, - {"Cascade.mnemonic", "", "", "", ""}, - {"Chart:", "", "", "", ""}, - {"Chart:.mnemonic", "", "", "", ""}, - {"ClassTab.infoLabelFormat", "LoadedCount", "UnloadedCount", "TotalCount", ""}, - {"ClassTab.loadedClassesPlotter.accessibleName", "", "", "", ""}, - {"Class path", "", "", "", ""}, - {"Classes", "", "", "", ""}, - {"ClassName", "", "", "", ""}, - {"Column.Name", "", "", "", ""}, - {"Column.PID", "", "", "", ""}, - {"Committed", "", "", "", ""}, - {"Committed memory", "", "", "", ""}, - {"Committed virtual memory", "", "", "", ""}, - {"Compiler", "", "", "", ""}, - {"Connect...", "", "", "", ""}, - {"Connect", "", "", "", ""}, - {"Connect.mnemonic", "", "", "", ""}, - {"ConnectDialog.connectButton.toolTip", "", "", "", ""}, - {"ConnectDialog.accessibleDescription", "", "", "", ""}, - {"ConnectDialog.masthead.accessibleName", "", "", "", ""}, - {"ConnectDialog.masthead.title", "", "", "", ""}, - {"ConnectDialog.statusBar.accessibleName", "", "", "", ""}, - {"ConnectDialog.title", "", "", "", ""}, - {"Connected. Click to disconnect.", "", "", "", ""}, - {"connectingTo1", "PhonyConnectionName", "", "", ""}, - {"connectingTo2", "PhonyConnectionName", "", "", ""}, - {"connectionFailed1", "", "", "", ""}, - {"connectionFailed2", "PhonyConnectionName", "", "", ""}, - {"connectionLost1", "", "", "", ""}, - {"connectionLost2", "PhonyConnectionName", "", "", ""}, - {"Connection failed", "", "", "", ""}, - {"Connection", "", "", "", ""}, - {"Connection.mnemonic", "", "", "", ""}, - {"Connection name", "", "", "", ""}, - {"ConnectionName (disconnected)", "Phony", "Phony", "", ""}, - {"Constructor", "", "", "", ""}, - {"Create", "Phony", "Phony", "", ""}, - {"Current classes loaded", "", "", "", ""}, - {"Current heap size", "", "", "", ""}, - {"Current value", "PhonyValue", "", "", ""}, - {"Daemon threads", "", "", "", ""}, - {"deadlockAllTab", "", "", "", ""}, - {"deadlockTab", "", "", "", ""}, - {"deadlockTabN", "PhonyInt", "", "", ""}, - {"Description", "", "", "", ""}, - {"Descriptor", "", "", "", ""}, - {"Details", "", "", "", ""}, - {"Detect Deadlock", "", "", "", ""}, - {"Detect Deadlock.mnemonic", "", "", "", ""}, - {"Detect Deadlock.toolTip", "", "", "", ""}, - {"Dimension is not supported:", "", "", "", ""}, - {"Discard chart", "", "", "", ""}, - {"Disconnected. Click to connect.", "", "", "", ""}, - {"Double click to expand/collapse", "", "", "", ""}, - {"Double click to visualize", "", "", "", ""}, - {"DurationDaysHoursMinutes", 0, 13, 54, ""}, - {"DurationDaysHoursMinutes", 1, 13, 54, ""}, - {"DurationDaysHoursMinutes", 2, 13, 54, ""}, - {"DurationDaysHoursMinutes", 1024, 13, 45, ""}, - {"DurationHoursMinutes", 0, 13, "", ""}, - {"DurationHoursMinutes", 1, 0, "", ""}, - {"DurationHoursMinutes", 1, 1, "", ""}, - {"DurationHoursMinutes", 2, 42, "", ""}, - {"DurationMinutes", 0, "", "", ""}, - {"DurationMinutes", 1, "", "", ""}, - {"DurationMinutes", 2, "", "", ""}, - {"DurationSeconds", 0, "", "", ""}, - {"DurationSeconds", 1, "", "", ""}, - {"DurationSeconds", 2, "", "", ""}, - {"Empty array", "", "", "", ""}, - {"Error", "", "", "", ""}, - {"Error: MBeans already exist", "", "", "", ""}, - {"Error: MBeans do not exist", "", "", "", ""}, - {"Event", "", "", "", ""}, - {"Exit", "", "", "", ""}, - {"Exit.mnemonic", "", "", "", ""}, - {"expand", "", "", "", ""}, - {"Fail to load plugin", "", "", "", ""}, - {"FileChooser.fileExists.cancelOption", "", "", "", ""}, - {"FileChooser.fileExists.message", "PhonyFileName", "", "", ""}, - {"FileChooser.fileExists.okOption", "", "", "", ""}, - {"FileChooser.fileExists.title", "", "", "", ""}, - {"FileChooser.savedFile", "PhonyFilePath", "PhonyFileSize", "", ""}, - {"FileChooser.saveFailed.message", "PhonyFilePath", "PhonyMessage", "", ""}, - {"FileChooser.saveFailed.title", "", "", "", ""}, - {"Free physical memory", "", "", "", ""}, - {"Free swap space", "", "", "", ""}, - {"Garbage collector", "", "", "", ""}, - {"GC time", "", "", "", ""}, - {"GC time details", 54, "Phony", 11, ""}, - {"GcInfo", "Phony", -1, 768, ""}, - {"GcInfo", "Phony", 0, 768, ""}, - {"GcInfo", "Phony", 1, 768, ""}, - {"Heap", "", "", "", ""}, - {"Heap Memory Usage", "", "", "", ""}, - {"Help.AboutDialog.accessibleDescription", "", "", "", ""}, - {"Help.AboutDialog.jConsoleVersion", "DummyVersion", "", "", ""}, - {"Help.AboutDialog.javaVersion", "DummyVersion", "", "", ""}, - {"Help.AboutDialog.masthead.accessibleName", "", "", "", ""}, - {"Help.AboutDialog.masthead.title", "", "", "", ""}, - {"Help.AboutDialog.title", "", "", "", ""}, - {"Help.AboutDialog.userGuideLink", "DummyMessage", "", "", ""}, - {"Help.AboutDialog.userGuideLink.mnemonic", "", "", "", ""}, - {"Help.AboutDialog.userGuideLink.url", "DummyURL", "", "", ""}, - {"HelpMenu.About.title", "", "", "", ""}, - {"HelpMenu.About.title.mnemonic", "", "", "", ""}, - {"HelpMenu.UserGuide.title", "", "", "", ""}, - {"HelpMenu.UserGuide.title.mnemonic", "", "", "", ""}, - {"HelpMenu.title", "", "", "", ""}, - {"HelpMenu.title.mnemonic", "", "", "", ""}, - {"Hotspot MBeans...", "", "", "", ""}, - {"Hotspot MBeans....mnemonic", "", "", "", ""}, - {"Hotspot MBeans.dialog.accessibleDescription", "", "", "", ""}, - {"Impact", "", "", "", ""}, - {"Info", "", "", "", ""}, - {"INFO", "", "", "", ""}, - {"Invalid plugin path", "", "", "", ""}, - {"Invalid URL", "", "", "", ""}, - {"Is", "", "", "", ""}, - {"Java Monitoring & Management Console", "", "", "", ""}, - {"Java Virtual Machine", "", "", "", ""}, - {"JConsole: ", "", "", "", ""}, - {"JConsole.accessibleDescription", "", "", "", ""}, - {"JConsole version", "PhonyVersion", "", "", ""}, - {"JIT compiler", "", "", "", ""}, - {"Library path", "", "", "", ""}, - {"Live Threads", "", "", "", ""}, - {"Loaded", "", "", "", ""}, - {"Local Process:", "", "", "", ""}, - {"Local Process:.mnemonic", "", "", "", ""}, - {"Manage Hotspot MBeans in: ", "", "", "", ""}, - {"Management Not Enabled", "", "", "", ""}, - {"Management Will Be Enabled", "", "", "", ""}, - {"Masthead.font", "", "", "", ""}, - {"Max", "", "", "", ""}, - {"Max", "", "", "", ""}, - {"Maximum heap size", "", "", "", ""}, - {"MBeanAttributeInfo", "", "", "", ""}, - {"MBeanInfo", "", "", "", ""}, - {"MBeanNotificationInfo", "", "", "", ""}, - {"MBeanOperationInfo", "", "", "", ""}, - {"MBeans", "", "", "", ""}, - {"MBeansTab.clearNotificationsButton", "", "", "", ""}, - {"MBeansTab.clearNotificationsButton.mnemonic", "", "", "", ""}, - {"MBeansTab.clearNotificationsButton.toolTip", "", "", "", ""}, - {"MBeansTab.compositeNavigationMultiple", 0, 0, "", ""}, - {"MBeansTab.compositeNavigationSingle", "", "", "", ""}, - {"MBeansTab.refreshAttributesButton", "", "", "", ""}, - {"MBeansTab.refreshAttributesButton.mnemonic", "", "", "", ""}, - {"MBeansTab.refreshAttributesButton.toolTip", "", "", "", ""}, - {"MBeansTab.subscribeNotificationsButton", "", "", "", ""}, - {"MBeansTab.subscribeNotificationsButton.mnemonic", "", "", "", ""}, - {"MBeansTab.subscribeNotificationsButton.toolTip", "", "", "", ""}, - {"MBeansTab.tabularNavigationMultiple", 0, 0, "", ""}, - {"MBeansTab.tabularNavigationSingle", "", "", "", ""}, - {"MBeansTab.unsubscribeNotificationsButton", "", "", "", ""}, - {"MBeansTab.unsubscribeNotificationsButton.mnemonic", "", "", "", ""}, - {"MBeansTab.unsubscribeNotificationsButton.toolTip", "", "", "", ""}, - {"Memory", "", "", "", ""}, - {"MemoryPoolLabel", "PhonyMemoryPool", "", "", ""}, - {"MemoryTab.heapPlotter.accessibleName", "", "", "", ""}, - {"MemoryTab.infoLabelFormat", "UsedCount", "CommittedCount", "MaxCount", ""}, - {"MemoryTab.nonHeapPlotter.accessibleName", "", "", "", ""}, - {"MemoryTab.poolChart.aboveThreshold", "Threshold", "", "", ""}, - {"MemoryTab.poolChart.accessibleName", "", "", "", ""}, - {"MemoryTab.poolChart.belowThreshold", "Threshold", "", "", ""}, - {"MemoryTab.poolPlotter.accessibleName", "PhonyMemoryPool", "", "", ""}, - {"Message", "", "", "", ""}, - {"Method successfully invoked", "", "", "", ""}, - {"Monitor locked", "", "", "", ""}, - {"Minimize All", "", "", "", ""}, - {"Minimize All.mnemonic", "", "", "", ""}, - {"Name", "", "", "", ""}, - {"Name and Build", "PhonyName", "PhonyBuild", "", ""}, - {"Name Build and Mode", "PhonyName", "PhonyBuild", "PhonyMode", ""}, - {"Name State", "PhonyName", "PhonyState", "", ""}, - {"Name State LockName", "PhonyName", "PhonyState", "PhonyLock", ""}, - {"Name State LockName LockOwner", "PhonyName", "PhonyState", "PhonyLock", "PhonyOwner"}, - {"New Connection...", "", "", "", ""}, - {"New Connection....mnemonic", "", "", "", ""}, - {"No deadlock detected", "", "", "", ""}, - {"Non-Heap", "", "", "", ""}, - {"Non-Heap Memory Usage", "", "", "", ""}, - {"Notification", "", "", "", ""}, - {"Notification buffer", "", "", "", ""}, - {"Notifications", "", "", "", ""}, - {"NotifTypes", "", "", "", ""}, - {"Number of Loaded Classes", "", "", "", ""}, - {"Number of processors", "", "", "", ""}, - {"Number of Threads", "", "", "", ""}, - {"ObjectName", "", "", "", ""}, - {"Operating System", "", "", "", ""}, - {"Operation", "", "", "", ""}, - {"Operation invocation", "", "", "", ""}, - {"Operation return value", "", "", "", ""}, - {"Operations", "", "", "", ""}, - {"Overview", "", "", "", ""}, - {"OverviewPanel.plotter.accessibleName", "PhonyPlotter", "", "", ""}, - {"Parameter", "", "", "", ""}, - {"Password: ", "", "", "", ""}, - {"Password: .mnemonic", "", "", "", ""}, - {"Password.accessibleName", "", "", "", ""}, - {"Peak", "", "", "", ""}, - {"Perform GC", "", "", "", ""}, - {"Perform GC.mnemonic", "", "", "", ""}, - {"Perform GC.toolTip", "", "", "", ""}, - {"Plotter.accessibleName", "", "", "", ""}, - {"Plotter.accessibleName.keyAndValue", "Key", "Value", "", ""}, - {"Plotter.accessibleName.noData", "", "", "", ""}, - {"Plotter.saveAsMenuItem", "", "", "", ""}, - {"Plotter.saveAsMenuItem.mnemonic", "", "", "", ""}, - {"Plotter.timeRangeMenu", "", "", "", ""}, - {"Plotter.timeRangeMenu.mnemonic", "", "", "", ""}, - {"plot", "", "", "", ""}, - {"Problem adding listener", "", "", "", ""}, - {"Problem displaying MBean", "", "", "", ""}, - {"Problem invoking", "", "", "", ""}, - {"Problem removing listener", "", "", "", ""}, - {"Problem setting attribute", "", "", "", ""}, - {"Process CPU time", "", "", "", ""}, - {"Readable", "", "", "", ""}, - {"Reconnect", "", "", "", ""}, - {"Remote Process:", "", "", "", ""}, - {"Remote Process:.mnemonic", "", "", "", ""}, - {"Remote Process.textField.accessibleName", "", "", "", ""}, - {"remoteTF.usage", "", "", "", ""}, - {"Restore All", "", "", "", ""}, - {"Restore All.mnemonic", "", "", "", ""}, - {"ReturnType", "", "", "", ""}, - {"SeqNum", "", "", "", ""}, - {"Size Bytes", 512, "", "", ""}, - {"Size Gb", 512, "", "", ""}, - {"Size Kb", 512, "", "", ""}, - {"Size Mb", 512, "", "", ""}, - {"Source", "", "", "", ""}, - {"Stack trace", "", "", "", ""}, - {"SummaryTab.headerDateTimeFormat", "", "", "", ""}, - {"SummaryTab.pendingFinalization.label", "", "", "", ""}, - {"SummaryTab.pendingFinalization.value", "ObjectCount", "", "", ""}, - {"SummaryTab.tabName", "", "", "", ""}, - {"SummaryTab.vmVersion", "VMName", "VMVersion", "", ""}, - {"ThreadTab.infoLabelFormat", "LiveCount", "PeakCount", "TotalCount", ""}, - {"ThreadTab.threadInfo.accessibleName", "", "", "", ""}, - {"ThreadTab.threadPlotter.accessibleName", "", "", "", ""}, - {"Threads", "", "", "", ""}, - {"Threshold", "", "", "", ""}, - {"Tile", "", "", "", ""}, - {"Tile.mnemonic", "", "", "", ""}, - {"Time", "", "", "", ""}, - {"Time Range:", "", "", "", ""}, - {"Time Range:.mnemonic", "", "", "", ""}, - {"TimeStamp", "", "", "", ""}, - {"Total classes loaded", "", "", "", ""}, - {"Total classes unloaded", "", "", "", ""}, - {"Total compile time", "", "", "", ""}, - {"Total Loaded", "", "", "", ""}, - {"Total physical memory", "", "", "", ""}, - {"Total swap space", "", "", "", ""}, - {"Total threads started", "", "", "", ""}, - {"Type", "", "", "", ""}, - {"Unavailable", "", "", "", ""}, - {"UNKNOWN", "", "", "", ""}, - {"Unregister", "", "", "", ""}, - {"Uptime", "", "", "", ""}, - {"Usage Threshold", "", "", "", ""}, - {"Used", "", "", "", ""}, - {"Username: ", "", "", "", ""}, - {"Username: .mnemonic", "", "", "", ""}, - {"Username.accessibleName", "", "", "", ""}, - {"UserData", "", "", "", ""}, - {"Value", "", "", "", ""}, - {"Vendor", "", "", "", ""}, - {"Verbose Output", "", "", "", ""}, - {"Verbose Output.toolTip", "", "", "", ""}, - {"visualize", "", "", "", ""}, - {"VM", "", "", "", ""}, - {"VMInternalFrame.accessibleDescription", "", "", "", ""}, - {"VM arguments", "", "", "", ""}, - {"Virtual Machine", "", "", "", ""}, - {"Window", "", "", "", ""}, - {"Window.mnemonic", "", "", "", ""}, - {"Writable", "", "", "", ""}, - {"zz usage text", "PhonyName", "", "", ""}, - }; - //boolean verbose = false; - boolean verbose = true; - - long badLookups = 0; - System.out.println("Start..."); - for (int ii = 0; ii < testData.length; ii++) { - String key = (String)testData[ii][0]; - - if (key.endsWith(".mnemonic")) { - String baseKey = key.substring(0, key.length() - ".mnemonic".length()); - int mnemonic = Resources.getMnemonicInt(baseKey); - if (mnemonic == 0) { - badLookups++; - System.out.println("****lookup failed for key = " + key); + public static void main(String... args) { + List errors = new ArrayList<>(); + // Ensure that all Message fields have a corresponding key/value + // in the resource bundle and that mnemonics can be looked + // up where applicable. + ResourceBundle rb = ResourceBundle.getBundle(RESOURCE_BUNDLE); + for (Field field : Messages.class.getFields()) { + if (isResourceKeyField(field)) { + String resourceKey = field.getName(); + String message = readField(field); + if (message.startsWith(MISSING_RESOURCE_KEY_PREFIX)) { + errors.add("Can't find message (and perhaps mnemonic) for " + + Messages.class.getSimpleName() + "." + + resourceKey + " in resource bundle."); } else { - if (verbose) { - System.out.println(" mnemonic: " + KeyEvent.getKeyText(mnemonic)); + String resourceMessage = rb.getString(resourceKey); + if (hasMnemonicIdentifier(resourceMessage)) { + int mi = Resources.getMnemonicInt(message); + if (mi == 0) { + errors.add("Could not look up mnemonic for message '" + + message + "'."); + } } } - continue; } + } - String ss = Resources.getText(key, - testData[ii][1], - testData[ii][2], - testData[ii][3], - testData[ii][4]); - if (ss.startsWith("missing resource key")) { - badLookups++; - System.out.println("****lookup failed for key = " + key); - } else { - if (verbose) { - System.out.println(" " + ss); + // Ensure that there is Message class field for every resource key. + for (String key : Collections.list(rb.getKeys())) { + try { + Messages.class.getField(key); + } catch (NoSuchFieldException nfe) { + errors.add("Can't find static field (" + + Messages.class.getSimpleName() + "." + key + + ") matching '" + key + + "' in resource bundle. Unused message?"); + } + } + + if (errors.size() > 0) { + throwError(errors); + } + } + + private static String readField(Field field) { + try { + return (String) field.get(null); + } catch (IllegalArgumentException | IllegalAccessException e) { + throw new Error("Could not access field " + field.getName() + + " when trying to read resource message."); + } + } + + private static boolean isResourceKeyField(Field field) { + int modifiers = field.getModifiers(); + return Modifier.isPublic(modifiers) && Modifier.isStatic(modifiers); + } + + private static boolean hasMnemonicIdentifier(String s) { + for (int i = 0; i < s.length() - 1; i++) { + if (s.charAt(i) == '&') { + if (s.charAt(i + 1) != '&') { + return true; + } else { + i++; } } } - if (badLookups > 0) { - throw new Error ("Resource lookup failed " + badLookups + - " time(s); Test failed"); + return false; + } + + private static void throwError(List errors) { + StringBuffer buffer = new StringBuffer(); + buffer.append("Found "); + buffer.append(errors.size()); + buffer.append(" error(s) when checking one-to-one mapping "); + buffer.append("between Message and resource bundle keys in "); + buffer.append(RESOURCE_BUNDLE); + buffer.append(" with "); + buffer.append(Locale.getDefault()); + buffer.append(" locale."); + buffer.append(NEW_LINE); + int errorIndex = 1; + for (String error : errors) { + buffer.append("Error "); + buffer.append(errorIndex); + buffer.append(": "); + buffer.append(error); + buffer.append(NEW_LINE); + errorIndex++; } - System.out.println("...Finished."); + throw new Error(buffer.toString()); } } diff --git a/jdk/test/sun/tools/jconsole/ResourceCheckTest.sh b/jdk/test/sun/tools/jconsole/ResourceCheckTest.sh index bec63a7992f..01c2e4b6f01 100644 --- a/jdk/test/sun/tools/jconsole/ResourceCheckTest.sh +++ b/jdk/test/sun/tools/jconsole/ResourceCheckTest.sh @@ -1,5 +1,5 @@ # -# Copyright (c) 2004, 2007, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -54,7 +54,7 @@ pass() OS=`uname -s` case "$OS" in - SunOS | Linux ) + SunOS | Linux | Darwin) PATHSEP=":" ;; From 9b5513a8e8d82a40dacc910ddfa3d88bdecb6887 Mon Sep 17 00:00:00 2001 From: Mike Duigou Date: Tue, 3 Sep 2013 11:29:12 -0700 Subject: [PATCH 027/218] 8024015: TEST.groups: move jdk/lambda tests from jdk_other to jdk_lang Reviewed-by: alanb, mchung --- jdk/test/TEST.groups | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jdk/test/TEST.groups b/jdk/test/TEST.groups index 0674bdc1d91..ed70cbf6704 100644 --- a/jdk/test/TEST.groups +++ b/jdk/test/TEST.groups @@ -27,6 +27,7 @@ jdk_lang = \ sun/invoke \ sun/misc \ sun/reflect \ + jdk/lambda \ vm jdk_util = \ @@ -133,7 +134,6 @@ jdk_other = \ javax/xml \ -javax/xml/crypto \ jdk/asm \ - jdk/lambda \ com/sun/jndi \ com/sun/corba \ lib/testlibrary \ From f7b61b93f1d44b921df005f950e5836fad15c8cc Mon Sep 17 00:00:00 2001 From: Brian Goetz Date: Wed, 28 Aug 2013 14:13:03 -0700 Subject: [PATCH 028/218] 8022176: Weaken contract of java.lang.AutoCloseable Reviewed-by: alanb, martin, mduigou, psandoz --- .../classes/java/lang/AutoCloseable.java | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/jdk/src/share/classes/java/lang/AutoCloseable.java b/jdk/src/share/classes/java/lang/AutoCloseable.java index ce0fffe5939..be47cd0835f 100644 --- a/jdk/src/share/classes/java/lang/AutoCloseable.java +++ b/jdk/src/share/classes/java/lang/AutoCloseable.java @@ -26,7 +26,24 @@ package java.lang; /** - * A resource that must be closed when it is no longer needed. + * An object that may hold resources (such as file or socket handles) + * until it is closed. The {@link #close()} method of an {@code AutoCloseable} + * object is called automatically when exiting a {@code + * try}-with-resources block for which the object has been declared in + * the resource specification header. This construction ensures prompt + * release, avoiding resource exhaustion exceptions and errors that + * may otherwise occur. + * + * @apiNote + *

It is possible, and in fact common, for a base class to + * implement AutoCloseable even though not all of its subclasses or + * instances will hold releasable resources. For code that must operate + * in complete generality, or when it is known that the {@code AutoCloseable} + * instance requires resource release, it is recommended to use {@code + * try}-with-resources constructions. However, when using facilities such as + * {@link java.util.stream.Stream} that support both I/O-based and + * non-I/O-based forms, {@code try}-with-resources blocks are in + * general unnecessary when using non-I/O-based forms. * * @author Josh Bloch * @since 1.7 From 45d26c95711c9e57c51394ceeb10fd69d320c62a Mon Sep 17 00:00:00 2001 From: Henry Jen Date: Tue, 3 Sep 2013 11:44:34 -0700 Subject: [PATCH 029/218] 8024178: Difference in Stream.collect(Collector) methods located in jdk8 and jdk8-lambda repos Reviewed-by: mduigou --- jdk/src/share/classes/java/util/stream/DelegatingStream.java | 2 +- jdk/src/share/classes/java/util/stream/ReferencePipeline.java | 2 +- jdk/src/share/classes/java/util/stream/Stream.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/jdk/src/share/classes/java/util/stream/DelegatingStream.java b/jdk/src/share/classes/java/util/stream/DelegatingStream.java index 2dab1a4430c..fbe7735a515 100644 --- a/jdk/src/share/classes/java/util/stream/DelegatingStream.java +++ b/jdk/src/share/classes/java/util/stream/DelegatingStream.java @@ -209,7 +209,7 @@ public class DelegatingStream implements Stream { } @Override - public R collect(Collector collector) { + public R collect(Collector collector) { return delegate.collect(collector); } diff --git a/jdk/src/share/classes/java/util/stream/ReferencePipeline.java b/jdk/src/share/classes/java/util/stream/ReferencePipeline.java index 1fffff48b18..6c6fe647ee9 100644 --- a/jdk/src/share/classes/java/util/stream/ReferencePipeline.java +++ b/jdk/src/share/classes/java/util/stream/ReferencePipeline.java @@ -493,7 +493,7 @@ abstract class ReferencePipeline @Override @SuppressWarnings("unchecked") - public final R collect(Collector collector) { + public final R collect(Collector collector) { A container; if (isParallel() && (collector.characteristics().contains(Collector.Characteristics.CONCURRENT)) diff --git a/jdk/src/share/classes/java/util/stream/Stream.java b/jdk/src/share/classes/java/util/stream/Stream.java index 59d703b118e..1071b20110e 100644 --- a/jdk/src/share/classes/java/util/stream/Stream.java +++ b/jdk/src/share/classes/java/util/stream/Stream.java @@ -657,7 +657,7 @@ public interface Stream extends BaseStream> { * @see #collect(Supplier, BiConsumer, BiConsumer) * @see Collectors */ - R collect(Collector collector); + R collect(Collector collector); /** * Returns the minimum element of this stream according to the provided From 7bc062de1deb8ae4c5cca937970e1fb5794946d0 Mon Sep 17 00:00:00 2001 From: Brian Goetz Date: Tue, 3 Sep 2013 12:16:01 -0700 Subject: [PATCH 030/218] 8017513: Support for closeable streams 8022237: j.u.s.BaseStream.onClose() has an issue in implementation or requires spec clarification 8022572: Same exception instances thrown from j.u.stream.Stream.onClose() handlers are not listed as suppressed BaseStream implements AutoCloseable; Remove CloseableStream and DelegatingStream Reviewed-by: alanb, mduigou, psandoz --- .../share/classes/java/nio/file/Files.java | 298 +++++++++++------- .../java/util/stream/AbstractPipeline.java | 44 ++- .../classes/java/util/stream/BaseStream.java | 32 +- .../java/util/stream/CloseableStream.java | 57 ---- .../java/util/stream/DelegatingStream.java | 270 ---------------- .../java/util/stream/DoublePipeline.java | 9 +- .../java/util/stream/DoubleStream.java | 6 +- .../classes/java/util/stream/IntPipeline.java | 9 +- .../classes/java/util/stream/IntStream.java | 6 +- .../java/util/stream/LongPipeline.java | 9 +- .../classes/java/util/stream/LongStream.java | 6 +- .../java/util/stream/ReferencePipeline.java | 36 ++- .../classes/java/util/stream/Stream.java | 6 +- .../classes/java/util/stream/Streams.java | 57 ++++ jdk/test/java/nio/file/Files/StreamTest.java | 103 +++--- .../util/stream/DoubleStreamTestScenario.java | 3 +- .../util/stream/IntStreamTestScenario.java | 3 +- .../util/stream/LongStreamTestScenario.java | 3 +- .../java/util/stream/StreamTestScenario.java | 3 +- .../java/util/stream/StreamCloseTest.java | 166 ++++++++++ 20 files changed, 578 insertions(+), 548 deletions(-) delete mode 100644 jdk/src/share/classes/java/util/stream/CloseableStream.java delete mode 100644 jdk/src/share/classes/java/util/stream/DelegatingStream.java create mode 100644 jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/StreamCloseTest.java diff --git a/jdk/src/share/classes/java/nio/file/Files.java b/jdk/src/share/classes/java/nio/file/Files.java index 721184c1533..f084040c179 100644 --- a/jdk/src/share/classes/java/nio/file/Files.java +++ b/jdk/src/share/classes/java/nio/file/Files.java @@ -25,34 +25,56 @@ package java.nio.file; -import java.nio.file.attribute.*; -import java.nio.file.spi.FileSystemProvider; -import java.nio.file.spi.FileTypeDetector; +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.channels.Channels; 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.util.function.BiPredicate; -import java.util.stream.CloseableStream; -import java.util.stream.DelegatingStream; -import java.util.stream.Stream; -import java.util.stream.StreamSupport; -import java.security.AccessController; -import java.security.PrivilegedAction; 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.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.Stream; +import java.util.stream.StreamSupport; /** * This class consists exclusively of static methods that operate on files, @@ -74,6 +96,21 @@ public final class Files { 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 +3265,7 @@ public final class Files { // -- Stream APIs -- /** - * Implementation of CloseableStream - */ - private static class DelegatingCloseableStream extends DelegatingStream - implements CloseableStream - { - private final Closeable closeable; - - DelegatingCloseableStream(Closeable c, Stream 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. * *

The elements of the stream are {@link Path} objects that are @@ -3264,10 +3279,13 @@ public final class Files { * reflect updates to the directory that occur after returning from this * method. * - *

When not using the try-with-resources construct, then the stream's - * {@link CloseableStream#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 + *

The returned stream encapsulates a {@link DirectoryStream}. + * If timely disposal of file system resources is required, the + * {@code try}-with-resources construct should be used to ensure that the + * stream's {@link Stream#close close} method is invoked after the stream + * operations are completed. + * + *

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 * returned after the stream has been closed. * @@ -3278,7 +3296,7 @@ public final class Files { * * @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 +3312,54 @@ public final class Files { * @see #newDirectoryStream(Path) * @since 1.8 */ - public static CloseableStream list(Path dir) throws IOException { + public static Stream list(Path dir) throws IOException { DirectoryStream ds = Files.newDirectoryStream(dir); - final Iterator delegate = ds.iterator(); + try { + final Iterator delegate = ds.iterator(); - // Re-wrap DirectoryIteratorException to UncheckedIOException - Iterator it = new Iterator() { - public boolean hasNext() { - try { - return delegate.hasNext(); - } catch (DirectoryIteratorException e) { - throw new UncheckedIOException(e.getCause()); + // Re-wrap DirectoryIteratorException to UncheckedIOException + Iterator it = new Iterator() { + @Override + 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()); + @Override + public Path next() { + try { + return delegate.next(); + } catch (DirectoryIteratorException e) { + throw new UncheckedIOException(e.getCause()); + } } - } - }; + }; - Stream 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) { + try { + ds.close(); + } catch (IOException ex) { + try { + e.addSuppressed(ex); + } catch (Throwable ignore) {} + } + 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 depth-first, 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}. * *

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 @@ -3370,10 +3399,11 @@ public final class Files { *

When a security manager is installed and it denies access to a file * (or directory), then it is ignored and not included in the stream. * - *

When not using the try-with-resources construct, then the stream's - * {@link CloseableStream#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 + *

The returned stream encapsulates one or more {@link DirectoryStream}s. + * If timely disposal of file system resources is required, the + * {@code try}-with-resources construct should be used to ensure that the + * stream's {@link Stream#close close} method is invoked after the stream + * operations are completed. Operating on a closed stream will result in an * {@link java.lang.IllegalStateException}. * *

If an {@link IOException} is thrown when accessing the directory @@ -3388,7 +3418,7 @@ public final class Files { * @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 +3431,22 @@ public final class Files { * if an I/O error is thrown when accessing the starting file. * @since 1.8 */ - public static CloseableStream walk(Path start, int maxDepth, - FileVisitOption... options) - throws IOException - { + public static Stream walk(Path start, int maxDepth, + FileVisitOption... options) + throws IOException { FileTreeIterator iterator = new FileTreeIterator(start, maxDepth, options); - - Stream 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 depth-first, the elements in the stream * are {@link Path} objects that are obtained as if by {@link @@ -3428,12 +3459,19 @@ public final class Files { * * In other words, it visits all levels of the file tree. * + *

The returned stream encapsulates one or more {@link DirectoryStream}s. + * If timely disposal of file system resources is required, the + * {@code try}-with-resources construct should be used to ensure that the + * stream's {@link Stream#close close} method is invoked after the stream + * operations are completed. Operating on a closed stream will result in an + * {@link java.lang.IllegalStateException}. + * * @param start * the starting file * @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 +3484,14 @@ public final class Files { * @see #walk(Path, int, FileVisitOption...) * @since 1.8 */ - public static CloseableStream walk(Path start, - FileVisitOption... options) - throws IOException - { + public static Stream 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,12 +3500,19 @@ public final class Files { * {@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 * avoiding redundant retrieval of the {@code BasicFileAttributes}. * + *

The returned stream encapsulates one or more {@link DirectoryStream}s. + * If timely disposal of file system resources is required, the + * {@code try}-with-resources construct should be used to ensure that the + * stream's {@link Stream#close close} method is invoked after the stream + * operations are completed. Operating on a closed stream will result in an + * {@link java.lang.IllegalStateException}. + * *

If an {@link IOException} is thrown when accessing the directory * after returned from this method, it is wrapped in an {@link * UncheckedIOException} which will be thrown from the method that caused @@ -3484,7 +3528,7 @@ public final class Files { * @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 +3543,25 @@ public final class Files { * @see #walk(Path, int, FileVisitOption...) * @since 1.8 */ - public static CloseableStream find(Path start, - int maxDepth, - BiPredicate matcher, - FileVisitOption... options) - throws IOException - { + public static Stream find(Path start, + int maxDepth, + BiPredicate matcher, + FileVisitOption... options) + throws IOException { FileTreeIterator iterator = new FileTreeIterator(start, maxDepth, options); - - Stream 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. @@ -3528,22 +3573,24 @@ public final class Files { *

After this method returns, then any subsequent I/O exception that * occurs while reading from the file or when a malformed or unmappable byte * sequence is read, is wrapped in an {@link UncheckedIOException} that will - * be thrown form the + * be thrown from the * {@link java.util.stream.Stream} method that caused the read to take * place. In case an {@code IOException} is thrown when closing the file, * it is also wrapped as an {@code UncheckedIOException}. * - *

When not using the try-with-resources construct, then stream's - * {@link CloseableStream#close close} method should be invoked after - * operation is completed so as to free any resources held for the open - * file. + *

The returned stream encapsulates a {@link Reader}. If timely + * disposal of file system resources is required, the try-with-resources + * construct should be used to ensure that the stream's + * {@link Stream#close close} method is invoked after the stream operations + * are completed. + * * * @param path * the path to the file * @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 +3604,19 @@ public final class Files { * @see java.io.BufferedReader#lines() * @since 1.8 */ - public static CloseableStream lines(Path path, Charset cs) - throws IOException - { + public static Stream 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) { + try { + br.close(); + } catch (IOException ex) { + try { + e.addSuppressed(ex); + } catch (Throwable ignore) {} + } + throw e; + } } } diff --git a/jdk/src/share/classes/java/util/stream/AbstractPipeline.java b/jdk/src/share/classes/java/util/stream/AbstractPipeline.java index 3b2f5bdc5f7..dd60c2520e4 100644 --- a/jdk/src/share/classes/java/util/stream/AbstractPipeline.java +++ b/jdk/src/share/classes/java/util/stream/AbstractPipeline.java @@ -71,6 +71,9 @@ import java.util.function.Supplier; */ abstract class AbstractPipeline> extends PipelineHelper implements BaseStream { + 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 @@ abstract class AbstractPipeline> */ 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 @@ abstract class AbstractPipeline> */ AbstractPipeline(AbstractPipeline 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 @@ abstract class AbstractPipeline> final R evaluate(TerminalOp 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 @@ abstract class AbstractPipeline> @SuppressWarnings("unchecked") final Node evaluateToArrayNode(IntFunction 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 @@ abstract class AbstractPipeline> 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 @@ abstract class AbstractPipeline> return s; } else { - throw new IllegalStateException("source already consumed"); + throw new IllegalStateException(MSG_CONSUMED); } } @@ -302,12 +307,35 @@ abstract class AbstractPipeline> return (S) this; } + @Override + public void close() { + linkedOrConsumed = true; + sourceSupplier = null; + sourceSpliterator = null; + if (sourceStage.sourceCloseAction != null) { + Runnable closeAction = sourceStage.sourceCloseAction; + sourceStage.sourceCloseAction = null; + closeAction.run(); + } + } + + @Override + @SuppressWarnings("unchecked") + 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 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 +352,7 @@ abstract class AbstractPipeline> return lazySpliterator(s); } else { - throw new IllegalStateException("source already consumed"); + throw new IllegalStateException(MSG_CONSUMED); } } else { @@ -424,7 +452,7 @@ abstract class AbstractPipeline> sourceStage.sourceSupplier = null; } else { - throw new IllegalStateException("source already consumed"); + throw new IllegalStateException(MSG_CONSUMED); } if (isParallel()) { diff --git a/jdk/src/share/classes/java/util/stream/BaseStream.java b/jdk/src/share/classes/java/util/stream/BaseStream.java index 94dbc7de73f..9c87a309098 100644 --- a/jdk/src/share/classes/java/util/stream/BaseStream.java +++ b/jdk/src/share/classes/java/util/stream/BaseStream.java @@ -35,7 +35,8 @@ import java.util.Spliterator; * @param type of stream implementing {@code BaseStream} * @since 1.8 */ -public interface BaseStream> { +public interface BaseStream> + extends AutoCloseable { /** * Returns an iterator for the elements of this stream. * @@ -103,4 +104,33 @@ public interface BaseStream> { * @return an unordered stream */ S unordered(); + + /** + * Returns an equivalent stream with an additional close handler. Close + * handlers are run when the {@link #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 + * (unless one of the remaining exceptions is the same exception as the + * first exception, since an exception cannot suppress itself.) May + * return itself. + * + *

This is an intermediate + * operation. + * + * @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); + + /** + * Closes this stream, causing all close handlers for this stream pipeline + * to be called. + * + * @see AutoCloseable#close() + */ + @Override + void close(); } diff --git a/jdk/src/share/classes/java/util/stream/CloseableStream.java b/jdk/src/share/classes/java/util/stream/CloseableStream.java deleted file mode 100644 index bbcce516f99..00000000000 --- a/jdk/src/share/classes/java/util/stream/CloseableStream.java +++ /dev/null @@ -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 The type of stream elements - * @since 1.8 - */ -public interface CloseableStream extends Stream, 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 mark 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(); -} diff --git a/jdk/src/share/classes/java/util/stream/DelegatingStream.java b/jdk/src/share/classes/java/util/stream/DelegatingStream.java deleted file mode 100644 index fbe7735a515..00000000000 --- a/jdk/src/share/classes/java/util/stream/DelegatingStream.java +++ /dev/null @@ -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 type of stream elements for this stream and underlying delegate - * stream - * - * @since 1.8 - */ -public class DelegatingStream implements Stream { - final private Stream 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 delegate) { - this.delegate = Objects.requireNonNull(delegate); - } - - // -- BaseStream methods -- - - @Override - public Spliterator spliterator() { - return delegate.spliterator(); - } - - @Override - public boolean isParallel() { - return delegate.isParallel(); - } - - @Override - public Iterator iterator() { - return delegate.iterator(); - } - - // -- Stream methods -- - - @Override - public Stream filter(Predicate predicate) { - return delegate.filter(predicate); - } - - @Override - public Stream map(Function mapper) { - return delegate.map(mapper); - } - - @Override - public IntStream mapToInt(ToIntFunction mapper) { - return delegate.mapToInt(mapper); - } - - @Override - public LongStream mapToLong(ToLongFunction mapper) { - return delegate.mapToLong(mapper); - } - - @Override - public DoubleStream mapToDouble(ToDoubleFunction mapper) { - return delegate.mapToDouble(mapper); - } - - @Override - public Stream flatMap(Function> mapper) { - return delegate.flatMap(mapper); - } - - @Override - public IntStream flatMapToInt(Function mapper) { - return delegate.flatMapToInt(mapper); - } - - @Override - public LongStream flatMapToLong(Function mapper) { - return delegate.flatMapToLong(mapper); - } - - @Override - public DoubleStream flatMapToDouble(Function mapper) { - return delegate.flatMapToDouble(mapper); - } - - @Override - public Stream distinct() { - return delegate.distinct(); - } - - @Override - public Stream sorted() { - return delegate.sorted(); - } - - @Override - public Stream sorted(Comparator comparator) { - return delegate.sorted(comparator); - } - - @Override - public void forEach(Consumer action) { - delegate.forEach(action); - } - - @Override - public void forEachOrdered(Consumer action) { - delegate.forEachOrdered(action); - } - - @Override - public Stream peek(Consumer consumer) { - return delegate.peek(consumer); - } - - @Override - public Stream limit(long maxSize) { - return delegate.limit(maxSize); - } - - @Override - public Stream substream(long startingOffset) { - return delegate.substream(startingOffset); - } - - @Override - public Stream substream(long startingOffset, long endingOffset) { - return delegate.substream(startingOffset, endingOffset); - } - - @Override - public A[] toArray(IntFunction generator) { - return delegate.toArray(generator); - } - - @Override - public Object[] toArray() { - return delegate.toArray(); - } - - @Override - public T reduce(T identity, BinaryOperator accumulator) { - return delegate.reduce(identity, accumulator); - } - - @Override - public Optional reduce(BinaryOperator accumulator) { - return delegate.reduce(accumulator); - } - - @Override - public U reduce(U identity, BiFunction accumulator, - BinaryOperator combiner) { - return delegate.reduce(identity, accumulator, combiner); - } - - @Override - public R collect(Supplier resultFactory, - BiConsumer accumulator, - BiConsumer combiner) { - return delegate.collect(resultFactory, accumulator, combiner); - } - - @Override - public R collect(Collector collector) { - return delegate.collect(collector); - } - - @Override - public Optional max(Comparator comparator) { - return delegate.max(comparator); - } - - @Override - public Optional min(Comparator comparator) { - return delegate.min(comparator); - } - - @Override - public long count() { - return delegate.count(); - } - - @Override - public boolean anyMatch(Predicate predicate) { - return delegate.anyMatch(predicate); - } - - @Override - public boolean allMatch(Predicate predicate) { - return delegate.allMatch(predicate); - } - - @Override - public boolean noneMatch(Predicate predicate) { - return delegate.noneMatch(predicate); - } - - @Override - public Optional findFirst() { - return delegate.findFirst(); - } - - @Override - public Optional findAny() { - return delegate.findAny(); - } - - @Override - public Stream unordered() { - return delegate.unordered(); - } - - @Override - public Stream sequential() { - return delegate.sequential(); - } - - @Override - public Stream parallel() { - return delegate.parallel(); - } -} diff --git a/jdk/src/share/classes/java/util/stream/DoublePipeline.java b/jdk/src/share/classes/java/util/stream/DoublePipeline.java index f894fa0abb9..75981d5801f 100644 --- a/jdk/src/share/classes/java/util/stream/DoublePipeline.java +++ b/jdk/src/share/classes/java/util/stream/DoublePipeline.java @@ -266,10 +266,11 @@ abstract class DoublePipeline @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)); + } } }; } diff --git a/jdk/src/share/classes/java/util/stream/DoubleStream.java b/jdk/src/share/classes/java/util/stream/DoubleStream.java index 93a83991e0b..bf356926154 100644 --- a/jdk/src/share/classes/java/util/stream/DoubleStream.java +++ b/jdk/src/share/classes/java/util/stream/DoubleStream.java @@ -752,7 +752,8 @@ public interface DoubleStream extends BaseStream { * elements of a first {@code DoubleStream} succeeded by all the elements of the * second {@code DoubleStream}. 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 @@ -764,7 +765,8 @@ public interface DoubleStream extends BaseStream { 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)); } /** diff --git a/jdk/src/share/classes/java/util/stream/IntPipeline.java b/jdk/src/share/classes/java/util/stream/IntPipeline.java index f7dc79317d3..f35bc1d7a8e 100644 --- a/jdk/src/share/classes/java/util/stream/IntPipeline.java +++ b/jdk/src/share/classes/java/util/stream/IntPipeline.java @@ -302,10 +302,11 @@ abstract class IntPipeline @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)); + } } }; } diff --git a/jdk/src/share/classes/java/util/stream/IntStream.java b/jdk/src/share/classes/java/util/stream/IntStream.java index 883b03cbd3d..c107ca46de9 100644 --- a/jdk/src/share/classes/java/util/stream/IntStream.java +++ b/jdk/src/share/classes/java/util/stream/IntStream.java @@ -806,7 +806,8 @@ public interface IntStream extends BaseStream { * elements of a first {@code IntStream} succeeded by all the elements of the * second {@code IntStream}. 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 @@ -818,7 +819,8 @@ public interface IntStream extends BaseStream { 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)); } /** diff --git a/jdk/src/share/classes/java/util/stream/LongPipeline.java b/jdk/src/share/classes/java/util/stream/LongPipeline.java index 3c199feab59..a59ec3f5f00 100644 --- a/jdk/src/share/classes/java/util/stream/LongPipeline.java +++ b/jdk/src/share/classes/java/util/stream/LongPipeline.java @@ -283,10 +283,11 @@ abstract class LongPipeline @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)); + } } }; } diff --git a/jdk/src/share/classes/java/util/stream/LongStream.java b/jdk/src/share/classes/java/util/stream/LongStream.java index 8fce0d68d65..e64c67204dc 100644 --- a/jdk/src/share/classes/java/util/stream/LongStream.java +++ b/jdk/src/share/classes/java/util/stream/LongStream.java @@ -812,7 +812,8 @@ public interface LongStream extends BaseStream { * elements of a first {@code LongStream} succeeded by all the elements of the * second {@code LongStream}. 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 @@ -824,7 +825,8 @@ public interface LongStream extends BaseStream { 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)); } /** diff --git a/jdk/src/share/classes/java/util/stream/ReferencePipeline.java b/jdk/src/share/classes/java/util/stream/ReferencePipeline.java index 6c6fe647ee9..42d711f4b2b 100644 --- a/jdk/src/share/classes/java/util/stream/ReferencePipeline.java +++ b/jdk/src/share/classes/java/util/stream/ReferencePipeline.java @@ -264,10 +264,11 @@ abstract class ReferencePipeline @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 - Stream result = mapper.apply(u); - if (result != null) - result.sequential().forEach(downstream); + try (Stream 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); + } } }; } @@ -291,10 +292,11 @@ abstract class ReferencePipeline @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); + } } }; } @@ -318,10 +320,11 @@ abstract class ReferencePipeline @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); + } } }; } @@ -345,10 +348,11 @@ abstract class ReferencePipeline @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); + } } }; } diff --git a/jdk/src/share/classes/java/util/stream/Stream.java b/jdk/src/share/classes/java/util/stream/Stream.java index 1071b20110e..715729f24a7 100644 --- a/jdk/src/share/classes/java/util/stream/Stream.java +++ b/jdk/src/share/classes/java/util/stream/Stream.java @@ -891,7 +891,8 @@ public interface Stream extends BaseStream> { * elements of a first {@code Stream} succeeded by all the elements of the * second {@code 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 The type of stream elements * @param a the first stream @@ -906,7 +907,8 @@ public interface Stream extends BaseStream> { @SuppressWarnings("unchecked") Spliterator split = new Streams.ConcatSpliterator.OfRef<>( (Spliterator) a.spliterator(), (Spliterator) b.spliterator()); - return StreamSupport.stream(split, a.isParallel() || b.isParallel()); + Stream stream = StreamSupport.stream(split, a.isParallel() || b.isParallel()); + return stream.onClose(Streams.composedClose(a, b)); } /** diff --git a/jdk/src/share/classes/java/util/stream/Streams.java b/jdk/src/share/classes/java/util/stream/Streams.java index 15c3dcae497..8af33f2b3c2 100644 --- a/jdk/src/share/classes/java/util/stream/Streams.java +++ b/jdk/src/share/classes/java/util/stream/Streams.java @@ -833,4 +833,61 @@ final class Streams { } } } + + /** + * 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 (Throwable e1) { + try { + b.run(); + } + catch (Throwable e2) { + try { + e1.addSuppressed(e2); + } catch (Throwable ignore) {} + } + throw e1; + } + b.run(); + } + }; + } + + /** + * Given two streams, return a Runnable that + * executes both of their {@link BaseStream#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(BaseStream a, BaseStream b) { + return new Runnable() { + @Override + public void run() { + try { + a.close(); + } + catch (Throwable e1) { + try { + b.close(); + } + catch (Throwable e2) { + try { + e1.addSuppressed(e2); + } catch (Throwable ignore) {} + } + throw e1; + } + b.close(); + } + }; + } } diff --git a/jdk/test/java/nio/file/Files/StreamTest.java b/jdk/test/java/nio/file/Files/StreamTest.java index b5ff2977257..5304492f1db 100644 --- a/jdk/test/java/nio/file/Files/StreamTest.java +++ b/jdk/test/java/nio/file/Files/StreamTest.java @@ -43,14 +43,13 @@ import java.nio.file.Path; 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 class StreamTest { } public void testBasic() { - try (CloseableStream s = Files.list(testFolder)) { - Object[] actual = s.sorted(Comparator.naturalOrder()).toArray(); + try (Stream s = Files.list(testFolder)) { + Object[] actual = s.sorted().toArray(); assertEquals(actual, level1); } catch (IOException ioe) { fail("Unexpected IOException"); } - try (CloseableStream s = Files.list(testFolder.resolve("empty"))) { + try (Stream 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 class StreamTest { } public void testWalk() { - try (CloseableStream s = Files.walk(testFolder)) { - Object[] actual = s.sorted(Comparator.naturalOrder()).toArray(); + try (Stream s = Files.walk(testFolder)) { + Object[] actual = s.sorted().toArray(); assertEquals(actual, all); } catch (IOException ioe) { fail("Unexpected IOException"); @@ -163,9 +162,9 @@ public class StreamTest { } public void testWalkOneLevel() { - try (CloseableStream s = Files.walk(testFolder, 1)) { + try (Stream 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 class StreamTest { 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 s = Files.walk(testFolder, FileVisitOption.FOLLOW_LINKS)) { - Object[] actual = s.sorted(Comparator.naturalOrder()).toArray(); + try (Stream 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 @@ public class StreamTest { } private void validateFileSystemLoopException(Path start, Path... causes) { - try (CloseableStream s = Files.walk(start, FileVisitOption.FOLLOW_LINKS)) { + try (Stream 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 class StreamTest { public void testFind() throws IOException { PathBiPredicate pred = new PathBiPredicate((path, attrs) -> true); - try (CloseableStream s = Files.find(testFolder, Integer.MAX_VALUE, pred)) { + try (Stream s = Files.find(testFolder, Integer.MAX_VALUE, pred)) { Set 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 s = Files.find(testFolder, Integer.MAX_VALUE, pred)) { + try (Stream 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 s = Files.find(testFolder, Integer.MAX_VALUE, pred)) { + try (Stream 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 s = Files.find(testFolder, Integer.MAX_VALUE, pred)) { + try (Stream s = Files.find(testFolder, Integer.MAX_VALUE, pred)) { s.forEach(path -> fail("Expect empty stream")); assertEquals(pred.visited(), all); } @@ -317,14 +316,14 @@ public class StreamTest { try { // zero lines assertTrue(Files.size(tmpfile) == 0, "File should be empty"); - try (CloseableStream s = Files.lines(tmpfile, US_ASCII)) { + try (Stream 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 s = Files.lines(tmpfile, US_ASCII)) { + try (Stream s = Files.lines(tmpfile, US_ASCII)) { List lines = s.collect(Collectors.toList()); assertTrue(lines.size() == 1, "One line expected"); assertTrue(lines.get(0).equals("hi"), "'Hi' expected"); @@ -334,7 +333,7 @@ public class StreamTest { List expected = Arrays.asList("hi", "there"); Files.write(tmpfile, expected, US_ASCII); assertTrue(Files.size(tmpfile) > 0, "File is empty"); - try (CloseableStream s = Files.lines(tmpfile, US_ASCII)) { + try (Stream s = Files.lines(tmpfile, US_ASCII)) { List lines = s.collect(Collectors.toList()); assertTrue(lines.equals(expected), "Unexpected lines"); } @@ -342,7 +341,7 @@ public class StreamTest { // MalformedInputException byte[] bad = { (byte)0xff, (byte)0xff }; Files.write(tmpfile, bad); - try (CloseableStream s = Files.lines(tmpfile, US_ASCII)) { + try (Stream s = Files.lines(tmpfile, US_ASCII)) { try { List lines = s.collect(Collectors.toList()); throw new RuntimeException("UncheckedIOException expected"); @@ -378,7 +377,7 @@ public class StreamTest { fsp.setFaultyMode(false); Path fakeRoot = fs.getRoot(); try { - try (CloseableStream s = Files.list(fakeRoot)) { + try (Stream s = Files.list(fakeRoot)) { s.forEach(path -> assertEquals(path.getFileName().toString(), "DirectoryIteratorException")); } } catch (UncheckedIOException uioe) { @@ -398,7 +397,7 @@ public class StreamTest { } try { - try (CloseableStream s = Files.list(fakeRoot)) { + try (Stream s = Files.list(fakeRoot)) { s.forEach(path -> fail("should not get here")); } } catch (UncheckedIOException uioe) { @@ -427,12 +426,12 @@ public class StreamTest { try { fsp.setFaultyMode(false); Path fakeRoot = fs.getRoot(); - try (CloseableStream s = Files.list(fakeRoot.resolve("dir2"))) { + try (Stream s = Files.list(fakeRoot.resolve("dir2"))) { // only one file s.forEach(path -> assertEquals(path.getFileName().toString(), "IOException")); } - try (CloseableStream s = Files.walk(fakeRoot.resolve("empty"))) { + try (Stream 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 @@ public class StreamTest { } fsp.setFaultyMode(true); - try (CloseableStream s = Files.list(fakeRoot.resolve("dir2"))) { + try (Stream 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 s = Files.walk(fakeRoot.resolve("empty"))) { + try (Stream 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 @@ public class StreamTest { assertTrue(uioe.getCause() instanceof FaultyFileSystem.FaultyException); } - try (CloseableStream s = Files.walk( + try (Stream s = Files.walk( fakeRoot.resolve("empty").resolve("IOException"))) { String[] result = s.map(path -> path.getFileName().toString()) @@ -502,20 +501,20 @@ public class StreamTest { fsp.setFaultyMode(false); Path fakeRoot = fs.getRoot(); // validate setting - try (CloseableStream s = Files.list(fakeRoot.resolve("empty"))) { + try (Stream 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 s = Files.walk(fakeRoot.resolve("dir2"))) { + try (Stream 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 s = Files.list(fakeRoot.resolve("dir"))) { + try (Stream 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 @@ public class StreamTest { // execute test fsp.setFaultyMode(true); // ignore file cause SecurityException - try (CloseableStream s = Files.walk(fakeRoot.resolve("empty"))) { + try (Stream 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 s = Files.walk(fakeRoot.resolve("dir2"))) { + try (Stream 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 @@ public class StreamTest { if (supportsLinks) { // not following links - try (CloseableStream s = Files.walk(fakeRoot.resolve("dir"))) { + try (Stream 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 s = Files.walk(fakeRoot.resolve("dir"), FileVisitOption.FOLLOW_LINKS)) { + try (Stream 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 @@ public class StreamTest { } // list instead of walk - try (CloseableStream s = Files.list(fakeRoot.resolve("empty"))) { + try (Stream s = Files.list(fakeRoot.resolve("empty"))) { String[] result = s.map(path -> path.getFileName().toString()) .toArray(String[]::new); assertEqualsNoOrder(result, new String[] { "sample" }); } - try (CloseableStream s = Files.list(fakeRoot.resolve("dir2"))) { + try (Stream 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 s = Files.walk( + try (Stream s = Files.walk( fakeRoot.resolve("dir2").resolve("SecurityException"))) { String[] result = s.map(path -> path.getFileName().toString()) @@ -579,7 +578,7 @@ public class StreamTest { } // Walk a file cause SecurityException, we should get SE - try (CloseableStream s = Files.walk( + try (Stream s = Files.walk( fakeRoot.resolve("dir").resolve("SecurityException"))) { String[] result = s.map(path -> path.getFileName().toString()) @@ -590,7 +589,7 @@ public class StreamTest { } // List a file cause SecurityException, we should get SE as cannot read attribute - try (CloseableStream s = Files.list( + try (Stream s = Files.list( fakeRoot.resolve("dir2").resolve("SecurityException"))) { String[] result = s.map(path -> path.getFileName().toString()) @@ -600,7 +599,7 @@ public class StreamTest { assertTrue(se.getCause() instanceof FaultyFileSystem.FaultyException); } - try (CloseableStream s = Files.list( + try (Stream s = Files.list( fakeRoot.resolve("dir").resolve("SecurityException"))) { String[] result = s.map(path -> path.getFileName().toString()) @@ -627,7 +626,7 @@ public class StreamTest { } public void testConstructException() { - try (CloseableStream s = Files.lines(testFolder.resolve("notExist"), Charset.forName("UTF-8"))) { + try (Stream 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 class StreamTest { } public void testClosedStream() throws IOException { - try (CloseableStream s = Files.list(testFolder)) { + try (Stream s = Files.list(testFolder)) { s.close(); - Object[] actual = s.sorted(Comparator.naturalOrder()).toArray(); - assertTrue(actual.length <= level1.length); - } - - try (CloseableStream 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 s = Files.find(testFolder, Integer.MAX_VALUE, + try (Stream 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 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 diff --git a/jdk/test/java/util/stream/bootlib/java/util/stream/DoubleStreamTestScenario.java b/jdk/test/java/util/stream/bootlib/java/util/stream/DoubleStreamTestScenario.java index d4459cf0c9b..43b99973dd2 100644 --- a/jdk/test/java/util/stream/bootlib/java/util/stream/DoubleStreamTestScenario.java +++ b/jdk/test/java/util/stream/bootlib/java/util/stream/DoubleStreamTestScenario.java @@ -40,7 +40,7 @@ import java.util.function.Function; @SuppressWarnings({"rawtypes", "unchecked"}) public enum DoubleStreamTestScenario implements OpTestCase.BaseStreamTestScenario { - STREAM_FOR_EACH(false) { + STREAM_FOR_EACH_WITH_CLOSE(false) { > void _run(TestData data, DoubleConsumer b, Function m) { DoubleStream s = m.apply(data.stream()); @@ -48,6 +48,7 @@ public enum DoubleStreamTestScenario implements OpTestCase.BaseStreamTestScenari s = s.sequential(); } s.forEach(b); + s.close(); } }, diff --git a/jdk/test/java/util/stream/bootlib/java/util/stream/IntStreamTestScenario.java b/jdk/test/java/util/stream/bootlib/java/util/stream/IntStreamTestScenario.java index f399cdeef25..4127a7b5a81 100644 --- a/jdk/test/java/util/stream/bootlib/java/util/stream/IntStreamTestScenario.java +++ b/jdk/test/java/util/stream/bootlib/java/util/stream/IntStreamTestScenario.java @@ -40,7 +40,7 @@ import java.util.function.IntConsumer; @SuppressWarnings({"rawtypes", "unchecked"}) public enum IntStreamTestScenario implements OpTestCase.BaseStreamTestScenario { - STREAM_FOR_EACH(false) { + STREAM_FOR_EACH_WITH_CLOSE(false) { > void _run(TestData data, IntConsumer b, Function m) { IntStream s = m.apply(data.stream()); @@ -48,6 +48,7 @@ public enum IntStreamTestScenario implements OpTestCase.BaseStreamTestScenario { s = s.sequential(); } s.forEach(b); + s.close(); } }, diff --git a/jdk/test/java/util/stream/bootlib/java/util/stream/LongStreamTestScenario.java b/jdk/test/java/util/stream/bootlib/java/util/stream/LongStreamTestScenario.java index 3010745a55d..0a334bc0261 100644 --- a/jdk/test/java/util/stream/bootlib/java/util/stream/LongStreamTestScenario.java +++ b/jdk/test/java/util/stream/bootlib/java/util/stream/LongStreamTestScenario.java @@ -40,7 +40,7 @@ import java.util.function.LongConsumer; @SuppressWarnings({"rawtypes", "unchecked"}) public enum LongStreamTestScenario implements OpTestCase.BaseStreamTestScenario { - STREAM_FOR_EACH(false) { + STREAM_FOR_EACH_WITH_CLOSE(false) { > void _run(TestData data, LongConsumer b, Function m) { LongStream s = m.apply(data.stream()); @@ -48,6 +48,7 @@ public enum LongStreamTestScenario implements OpTestCase.BaseStreamTestScenario s = s.sequential(); } s.forEach(b); + s.close(); } }, diff --git a/jdk/test/java/util/stream/bootlib/java/util/stream/StreamTestScenario.java b/jdk/test/java/util/stream/bootlib/java/util/stream/StreamTestScenario.java index b1abd4320db..d1a446234a7 100644 --- a/jdk/test/java/util/stream/bootlib/java/util/stream/StreamTestScenario.java +++ b/jdk/test/java/util/stream/bootlib/java/util/stream/StreamTestScenario.java @@ -39,7 +39,7 @@ import java.util.function.Function; @SuppressWarnings({"rawtypes", "unchecked"}) public enum StreamTestScenario implements OpTestCase.BaseStreamTestScenario { - STREAM_FOR_EACH(false) { + STREAM_FOR_EACH_WITH_CLOSE(false) { > void _run(TestData data, Consumer b, Function> m) { Stream s = m.apply(data.stream()); @@ -47,6 +47,7 @@ public enum StreamTestScenario implements OpTestCase.BaseStreamTestScenario { s = s.sequential(); } s.forEach(b); + s.close(); } }, diff --git a/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/StreamCloseTest.java b/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/StreamCloseTest.java new file mode 100644 index 00000000000..51ffd4b9010 --- /dev/null +++ b/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/StreamCloseTest.java @@ -0,0 +1,166 @@ +/* + * 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.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 ints = countTo(100).stream()) { + ints.forEach(i -> {}); + } + } + + public void testOneCloseHandler() { + final boolean[] holder = new boolean[1]; + Runnable closer = () -> { holder[0] = true; }; + + try (Stream ints = countTo(100).stream()) { + ints.onClose(closer); + ints.forEach(i -> {}); + } + assertTrue(holder[0]); + + Arrays.fill(holder, false); + try (Stream ints = countTo(100).stream().onClose(closer)) { + ints.forEach(i -> {}); + } + assertTrue(holder[0]); + + Arrays.fill(holder, false); + try (Stream ints = countTo(100).stream().filter(e -> true).onClose(closer)) { + ints.forEach(i -> {}); + } + assertTrue(holder[0]); + + Arrays.fill(holder, false); + try (Stream 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 ints = countTo(100).stream()) { + ints.onClose(close1).onClose(close2); + ints.forEach(i -> {}); + } + assertTrue(holder[0] && holder[1]); + + Arrays.fill(holder, false); + try (Stream ints = countTo(100).stream().onClose(close1).onClose(close2)) { + ints.forEach(i -> {}); + } + assertTrue(holder[0] && holder[1]); + + Arrays.fill(holder, false); + try (Stream 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 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 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 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 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 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 Date: Tue, 3 Sep 2013 22:37:07 +0100 Subject: [PATCH 031/218] 8017195: Introduce option to setKeepAlive parameter on CORBA sockets Reviewed-by: chegar, msheppar --- .../sun/corba/transport/KeepAliveSockets.java | 68 +++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 jdk/test/com/sun/corba/transport/KeepAliveSockets.java diff --git a/jdk/test/com/sun/corba/transport/KeepAliveSockets.java b/jdk/test/com/sun/corba/transport/KeepAliveSockets.java new file mode 100644 index 00000000000..4d9b9d97855 --- /dev/null +++ b/jdk/test/com/sun/corba/transport/KeepAliveSockets.java @@ -0,0 +1,68 @@ +/* + * 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 8017195 + * @summary Introduce option to setKeepAlive parameter on CORBA sockets + * + * @run main/othervm KeepAliveSockets + * @run main/othervm -Dcom.sun.CORBA.transport.enableTcpKeepAlive KeepAliveSockets + * @run main/othervm -Dcom.sun.CORBA.transport.enableTcpKeepAlive=true KeepAliveSockets + * @run main/othervm -Dcom.sun.CORBA.transport.enableTcpKeepAlive=false KeepAliveSockets + */ + +import java.lang.*; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.nio.channels.ServerSocketChannel; +import java.util.*; +import com.sun.corba.se.impl.orb.*; + +import com.sun.corba.se.impl.transport.*; + +public class KeepAliveSockets { + + public static void main(String[] args) throws Exception { + + boolean keepAlive = false; + String prop = System.getProperty("com.sun.CORBA.transport.enableTcpKeepAlive"); + if (prop != null) + keepAlive = !"false".equalsIgnoreCase(prop); + + DefaultSocketFactoryImpl sfImpl = new DefaultSocketFactoryImpl(); + ORBImpl orb = new ORBImpl(); + orb.set_parameters(null); + sfImpl.setORB(orb); + + ServerSocketChannel ssc = ServerSocketChannel.open(); + ssc.socket().bind(new InetSocketAddress(0)); + + InetSocketAddress isa = new InetSocketAddress("localhost", ssc.socket().getLocalPort()); + Socket s = sfImpl.createSocket("ignore", isa); + System.out.println("Received factory socket" + s); + if (keepAlive != s.getKeepAlive()) + throw new RuntimeException("KeepAlive value not honoured in CORBA socket"); + } + +} From 25af2121aa224df049dbf1dbc50dc869523bdeed Mon Sep 17 00:00:00 2001 From: Henry Jen Date: Tue, 3 Sep 2013 16:05:45 -0700 Subject: [PATCH 032/218] 8023997: j.l.String.join(java.lang.CharSequence, java.lang.Iterable) sample doesn't compile and is incorrect Reviewed-by: alanb --- jdk/src/share/classes/java/lang/String.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jdk/src/share/classes/java/lang/String.java b/jdk/src/share/classes/java/lang/String.java index 651a85017ed..e9d75afbbce 100644 --- a/jdk/src/share/classes/java/lang/String.java +++ b/jdk/src/share/classes/java/lang/String.java @@ -2457,8 +2457,8 @@ public final class String * String message = String.join(" ", strings); * //message returned is: "Java is cool" * - * Set strings = new HashSet<>(); - * Strings.add("Java"); strings.add("is"); + * Set strings = new LinkedHashSet<>(); + * strings.add("Java"); strings.add("is"); * strings.add("very"); strings.add("cool"); * String message = String.join("-", strings); * //message returned is: "Java-is-very-cool" From 7fc1c28757b950e48af2058b2bb7c45f7c9979b2 Mon Sep 17 00:00:00 2001 From: David Holmes Date: Tue, 3 Sep 2013 23:47:27 -0400 Subject: [PATCH 033/218] 8024140: [TESTBUG] Profile based regression test groups for jdk repo Reviewed-by: alanb, chegar --- jdk/test/TEST.groups | 338 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 338 insertions(+) diff --git a/jdk/test/TEST.groups b/jdk/test/TEST.groups index ed70cbf6704..a59b38853ff 100644 --- a/jdk/test/TEST.groups +++ b/jdk/test/TEST.groups @@ -212,3 +212,341 @@ jdk_desktop = \ :jdk_swing \ :jdk_sound \ :jdk_imageio + +############################################################################### +# Profile-based Test Group Definitions +# +# These groups define the tests that cover the different possible runtimes: +# - compact1, compact2, compact3, full JRE, JDK +# +# In addition they support testing of the minimal VM on compact1 and compact2. +# Essentially this defines groups based around the specified API's and VM +# services available in the runtime. +# +# The groups are defined hierarchically in two forms: +# - The need_xxx groups list all the tests that have a dependency on +# a specific profile. This is either because it tests a feature in +# that profile, or the test infrastructure uses a feature in that +# profile. +# - The primary groups are defined in terms of the other primary groups +# combined with the needs_xxx groups (including and excluding them as +# appropriate). For example the jre can run all tests from compact3, plus +# those from needs_jre, but excluding those from need_jdk. +# +# The bottom group defines all the actual tests to be considered, simply +# by listing the top-level test directories. + +# Full JDK can run all tests +# +jdk = \ + :jre \ + :needs_jdk + +# Tests that require a full JDK to execute. Either they test a feature +# only in the JDK or they use tools that are only in the JDK. The latter +# can be resolved in some cases by using tools from the compile-jdk. +# +needs_jdk = \ + :jdk_jdi \ + com/sun/tools \ + demo \ + sun/security/tools/jarsigner \ + sun/rmi/rmic \ + sun/tools \ + sun/jvmstat \ + tools \ + com/sun/jmx/remote/NotificationMarshalVersions/TestSerializationMismatch.java \ + java/io/Serializable/serialver \ + java/lang/invoke/lambda/LambdaAccessControlDoPrivilegedTest.java \ + java/lang/invoke/lambda/LambdaAccessControlTest.java \ + java/lang/System/MacEncoding/TestFileEncoding.java \ + java/net/URLClassLoader/closetest/GetResourceAsStream.java \ + java/util/Collections/EmptyIterator.java \ + java/util/concurrent/locks/Lock/TimedAcquireLeak.java \ + java/util/jar/Manifest/CreateManifest.java \ + java/util/jar/JarInputStream/ExtraFileInMetaInf.java \ + java/util/logging/AnonLoggerWeakRefLeak.sh \ + java/util/logging/LoggerWeakRefLeak.sh \ + java/util/zip/3GBZipFiles.sh \ + jdk/lambda/FDTest.java \ + jdk/lambda/separate/Compiler.java \ + sun/management/jdp/JdpTest.sh \ + sun/management/jmxremote/bootstrap/JvmstatCountersTest.java \ + sun/management/jmxremote/bootstrap/LocalManagementTest.sh \ + sun/misc/JarIndex/metaInfFilenames/Basic.java \ + sun/misc/JarIndex/JarIndexMergeForClassLoaderTest.java \ + sun/reflect/CallerSensitive/CallerSensitiveFinder.java \ + sun/reflect/CallerSensitive/MissingCallerSensitive.java \ + sun/security/util/Resources/NewNamesFormat.java \ + vm/verifier/defaultMethods/DefaultMethodRegressionTestsRun.java + +# JRE adds further tests to compact3 +# +jre = \ + :compact3 \ + :needs_jre \ + -:needs_jdk + +# Tests that require the full JRE +# +needs_jre = \ + :needs_charsets \ + :jdk_desktop \ + com/sun/corba \ + com/sun/jndi/cosnaming \ + sun/net/ftp \ + sun/net/www/protocol/ftp \ + sun/security/tools/policytool \ + java/net/URI/URItoURLTest.java \ + java/net/URL/URIToURLTest.java \ + java/net/URLConnection/HandleContentTypeWithAttrs.java \ + java/security/Security/ClassLoaderDeadlock/ClassLoaderDeadlock.sh \ + java/security/Security/ClassLoaderDeadlock/Deadlock.sh \ + java/util/logging/Listeners.java \ + java/util/logging/ListenersWithSM.java \ + java/util/ResourceBundle/Control/Bug6530694.java \ + java/text/Bidi/BidiConformance.java \ + java/text/Bidi/BidiEmbeddingTest.java \ + java/text/Bidi/Bug6665028.java \ + java/text/Bidi/Bug7042148.java \ + java/text/Bidi/Bug7051769.java \ + javax/crypto/Cipher/CipherStreamClose.java \ + javax/management/monitor/AttributeArbitraryDataTypeTest.java \ + jdk/lambda/vm/InterfaceAccessFlagsTest.java \ + sun/misc/URLClassPath/ClassnameCharTest.java + +# Tests dependent on the optional charsets.jar +# These are isolated for easy exclusions +# +needs_charsets = \ + java/io/OutputStreamWriter/TestWrite.java \ + java/nio/charset/RemovingSunIO/SunioAlias.java \ + java/nio/charset/coders/Check.java \ + java/nio/charset/Charset/CharsetContainmentTest.java \ + java/nio/charset/Charset/Contains.java \ + java/nio/charset/Charset/NIOCharsetAvailabilityTest.java \ + java/nio/charset/Charset/RegisteredCharsets.java \ + java/nio/charset/CharsetEncoder/Flush.java \ + java/nio/charset/coders/CheckSJISMappingProp.sh \ + java/nio/charset/coders/ResetISO2022JP.java \ + java/util/Locale/InternationalBAT.java \ + java/util/Locale/LocaleProviders.sh \ + java/util/Calendar/CldrFormatNamesTest.java \ + java/util/TimeZone/CLDRDisplayNamesTest.java \ + java/util/zip/ZipCoding.java \ + sun/nio/cs/EucJpLinux0212.java \ + sun/nio/cs/EUCJPUnderflowDecodeTest.java \ + sun/nio/cs/EuroConverter.java \ + sun/nio/cs/JISAutoDetectTest.java \ + sun/nio/cs/OLD/TestIBMDB.java \ + sun/nio/cs/SJISCanEncode.java \ + sun/nio/cs/Test6254467.java \ + sun/nio/cs/TestCompoundTest.java \ + sun/nio/cs/TestCp834_SBCS.java \ + sun/nio/cs/TestEUC_TW.java \ + sun/nio/cs/TestISO2022CNDecoder.java \ + sun/nio/cs/TestISO2022JPEncoder.java \ + sun/nio/cs/TestISO2022JPSubBytes.java \ + sun/nio/cs/TestIllegalSJIS.java \ + sun/nio/cs/TestJIS0208Decoder.java \ + sun/nio/cs/TestJIS0212Decoder.java \ + sun/nio/cs/TestMiscEUC_JP.java \ + sun/nio/cs/TestSJIS0213_SM.java \ + sun/nio/cs/BufferUnderflowEUCTWTest.java \ + sun/nio/cs/CheckCaseInsensitiveEncAliases.java \ + sun/nio/cs/CheckHistoricalNames.java \ + sun/nio/cs/EucJpLinuxDecoderRecoveryTest.java \ + sun/nio/cs/HWKatakanaMS932EncodeTest.java \ + sun/nio/cs/ISCIITest.java \ + sun/nio/cs/LatinCharReplacementTWTest.java \ + sun/nio/cs/NIOJISAutoDetectTest.java \ + sun/nio/cs/StreamEncoderClose.java \ + sun/nio/cs/SurrogateGB18030Test.java \ + sun/nio/cs/SurrogateTestEUCTW.java \ + sun/nio/cs/SurrogateTestHKSCS.java \ + sun/nio/cs/TestConverterDroppedCharacters.java \ + sun/nio/cs/TestCp93xSISO.java \ + sun/nio/cs/TestIBM1364.java \ + sun/nio/cs/TestIBMBugs.java \ + sun/nio/cs/TestIllegalISO2022Esc.java \ + sun/nio/cs/TestISO2022JP.java \ + sun/nio/cs/TestMS5022X.java \ + sun/nio/cs/TestSJIS0213.java \ + sun/nio/cs/TestTrailingEscapesISO2022JP.java \ + sun/nio/cs/TestUni2HKSCS.java \ + sun/nio/cs/ZeroedByteArrayEUCTWTest.java + +# Compact 3 adds further tests to compact2 +# +compact3 = \ + :compact2 \ + :needs_compact3 \ + -:needs_jre \ + -:needs_jdk + + +# Tests that require compact3 API's +# +needs_compact3 = \ + :jdk_instrument \ + :jdk_jmx \ + :jdk_management \ + :jdk_sctp \ + com/sun/jndi \ + com/sun/org/apache/xml/internal/security \ + com/sun/security/auth \ + com/sun/security/sasl \ + com/sun/security/jgss \ + com/sun/tracing \ + java/util/prefs \ + javax/naming \ + javax/security \ + javax/smartcardio \ + javax/sql/rowset \ + javax/xml/crypto \ + sun/security/acl \ + sun/security/jgss \ + sun/security/krb5 \ + java/lang/System/MacEncoding/TestFileEncoding.java \ + java/nio/channels/AsynchronousSocketChannel/Leaky.java \ + java/security/PermissionCollection/Concurrent.java \ + java/security/Principal/Implies.java \ + java/security/cert/GetInstance.java \ + java/util/logging/DrainFindDeadlockTest.java \ + java/util/logging/LoggingMXBeanTest.java \ + sun/net/www/http/KeepAliveCache/B5045306.java \ + sun/security/provider/PolicyFile/Alias.java \ + sun/security/provider/PolicyFile/Comparator.java \ + sun/security/provider/PolicyFile/SelfWildcard.java \ + sun/security/ssl/com/sun/net/ssl/internal/ssl/SSLEngineImpl/SSLEngineDeadlock.java \ + sun/security/util/Oid/OidFormat.java \ + sun/security/util/Resources/Format.java \ + sun/security/util/Resources/NewNamesFormat.java + +# Compact 2 adds full VM tests +compact2 = \ + :compact2_minimal \ + :compact1 \ + :needs_full_vm_compact2 \ + -:needs_compact3 \ + -:needs_jre \ + -:needs_jdk + +# Tests that require compact2 API's and a full VM +# +needs_full_vm_compact2 = + +# Minimal VM on Compact 2 adds in some compact2 tests +# +compact2_minimal = \ + :compact1_minimal \ + :needs_compact2 \ + -:needs_compact3 \ + -:needs_jre \ + -:needs_jdk + +# Tests that require compact2 API's +# +needs_compact2 = \ + :jdk_rmi \ + :jdk_time \ + com/sun/org/apache \ + com/sun/net/httpserver \ + java/sql \ + javax/sql \ + javax/xml \ + jdk/lambda \ + sun/net/www/http \ + sun/net/www/protocol/http \ + java/io/BufferedReader/Lines.java \ + java/lang/reflect/DefaultStaticTest/DefaultStaticInvokeTest.java \ + java/lang/CharSequence/DefaultTest.java \ + java/lang/IntegralPrimitiveToString.java \ + java/lang/PrimitiveSumMinMaxTest.java \ + java/lang/String/StringJoinTest.java \ + java/lang/Thread/StopThrowable.java \ + java/net/Authenticator/Deadlock.java \ + java/net/CookieHandler/LocalHostCookie.java \ + java/net/CookieHandler/CookieManagerTest.java \ + java/net/CookieHandler/EmptyCookieHeader.java \ + java/net/HttpCookie/IllegalCookieNameTest.java \ + java/net/HttpURLConnection/UnmodifiableMaps.java \ + java/net/HttpURLPermission/URLTest.java \ + java/net/ResponseCache/Test.java \ + java/net/URLClassLoader/ClassLoad.java \ + java/net/URLClassLoader/closetest/CloseTest.java \ + java/nio/Buffer/Chars.java \ + java/nio/file/Files/StreamTest.java \ + java/security/BasicPermission/Wildcard.java \ + java/util/Arrays/ParallelPrefix.java \ + java/util/Arrays/SetAllTest.java \ + java/util/BitSet/BitSetStreamTest.java \ + java/util/Collection/CollectionDefaults.java \ + java/util/Collection/ListDefaults.java \ + java/util/Collections/CheckedIdentityMap.java \ + java/util/Collections/CheckedMapBash.java \ + java/util/Collections/CheckedSetBash.java \ + java/util/Collections/EmptyCollectionSerialization.java \ + java/util/Collections/EmptyNavigableMap.java \ + java/util/Collections/EmptyNavigableSet.java \ + java/util/Collections/UnmodifiableMapEntrySet.java \ + java/util/Comparator/BasicTest.java \ + java/util/Comparator/TypeTest.java \ + java/util/Iterator/IteratorDefaults.java \ + java/util/Iterator/PrimitiveIteratorDefaults.java \ + java/util/Map/BasicSerialization.java \ + java/util/Map/Defaults.java \ + java/util/Map/EntryComparators.java \ + java/util/Optional/Basic.java \ + java/util/Optional/BasicDouble.java \ + java/util/Optional/BasicInt.java \ + java/util/Optional/BasicLong.java \ + java/util/Random/RandomStreamTest.java \ + java/util/ResourceBundle/Bug6359330.java \ + java/util/Spliterator/SpliteratorCharacteristics.java \ + java/util/Spliterator/SpliteratorCollisions.java \ + java/util/Spliterator/SpliteratorLateBindingFailFastTest.java \ + java/util/Spliterator/SpliteratorTraversingAndSplittingTest.java \ + java/util/StringJoiner/MergeTest.java \ + java/util/StringJoiner/StringJoinerTest.java \ + java/util/concurrent/atomic/AtomicReferenceTest.java \ + java/util/function/BinaryOperator/BasicTest.java \ + java/util/logging/LoggerSupplierAPIsTest.java \ + java/util/zip/ZipFile/StreamZipEntriesTest.java \ + java/util/zip/ZipFile/DeleteTempJar.java \ + javax/crypto/Cipher/CipherStreamClose.java \ + sun/misc/URLClassPath/ClassnameCharTest.java \ + sun/security/ssl/sun/net/www/protocol/https/HttpsURLConnection/HttpsCreateSockTest.java \ + sun/security/ssl/sun/net/www/protocol/https/HttpsURLConnection/HttpsSocketFacTest.java + +# Compact 1 adds full VM tests +# +compact1 = \ + :compact1_minimal \ + :needs_full_vm_compact1 \ + -:needs_compact2 \ + -:needs_full_vm_compact2 \ + -:needs_compact3 \ + -:needs_jre \ + -:needs_jdk + +# Tests that require compact1 API's and a full VM +# +needs_full_vm_compact1 = + +# All tests that run on the most minimal configuration: Minimal VM on Compact 1 +compact1_minimal = \ + com \ + java \ + javax \ + jdk \ + lib \ + sample \ + sun \ + vm \ + -:needs_full_vm_compact1 \ + -:needs_full_vm_compact2 \ + -:needs_compact2 \ + -:needs_compact3 \ + -:needs_jre \ + -:needs_jdk From 59440ee0bef7cce9a5f528e7840d098b89e9fc43 Mon Sep 17 00:00:00 2001 From: John Rose Date: Tue, 3 Sep 2013 21:42:56 -0700 Subject: [PATCH 034/218] 8008688: Make MethodHandleInfo public A major overhaul to MethodHandleInfo and method handles in general. Reviewed-by: vlivanov, twisti --- .../AbstractValidatingLambdaMetafactory.java | 2 +- .../java/lang/invoke/InfoFromMemberName.java | 145 ++++ .../classes/java/lang/invoke/Invokers.java | 2 + .../classes/java/lang/invoke/MemberName.java | 41 +- .../java/lang/invoke/MethodHandle.java | 40 +- .../java/lang/invoke/MethodHandleImpl.java | 75 +- .../java/lang/invoke/MethodHandleInfo.java | 286 +++++-- .../java/lang/invoke/MethodHandleNatives.java | 63 +- .../java/lang/invoke/MethodHandles.java | 93 ++- .../java/lang/invoke/SerializedLambda.java | 2 +- .../java/lang/invoke/7087570/Test7087570.java | 130 +-- .../java/lang/invoke/RevealDirectTest.java | 753 ++++++++++++++++++ .../java/lang/invoke/jtreg.security.policy | 9 + 13 files changed, 1437 insertions(+), 204 deletions(-) create mode 100644 jdk/src/share/classes/java/lang/invoke/InfoFromMemberName.java create mode 100644 jdk/test/java/lang/invoke/RevealDirectTest.java create mode 100644 jdk/test/java/lang/invoke/jtreg.security.policy diff --git a/jdk/src/share/classes/java/lang/invoke/AbstractValidatingLambdaMetafactory.java b/jdk/src/share/classes/java/lang/invoke/AbstractValidatingLambdaMetafactory.java index 79b3b69fcf3..92a44a048f3 100644 --- a/jdk/src/share/classes/java/lang/invoke/AbstractValidatingLambdaMetafactory.java +++ b/jdk/src/share/classes/java/lang/invoke/AbstractValidatingLambdaMetafactory.java @@ -124,7 +124,7 @@ import static sun.invoke.util.Wrapper.isWrapperType; this.samMethodType = samMethodType; this.implMethod = implMethod; - this.implInfo = new MethodHandleInfo(implMethod); + this.implInfo = caller.revealDirect(implMethod); // @@@ Temporary work-around pending resolution of 8005119 this.implKind = (implInfo.getReferenceKind() == MethodHandleInfo.REF_invokeSpecial) ? MethodHandleInfo.REF_invokeVirtual diff --git a/jdk/src/share/classes/java/lang/invoke/InfoFromMemberName.java b/jdk/src/share/classes/java/lang/invoke/InfoFromMemberName.java new file mode 100644 index 00000000000..0ecd005a8d3 --- /dev/null +++ b/jdk/src/share/classes/java/lang/invoke/InfoFromMemberName.java @@ -0,0 +1,145 @@ +/* + * 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. 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.lang.invoke; + +import java.security.*; +import java.lang.reflect.*; +import java.lang.invoke.MethodHandleNatives.Constants; +import java.lang.invoke.MethodHandles.Lookup; +import static java.lang.invoke.MethodHandleStatics.*; + +/* + * Auxiliary to MethodHandleInfo, wants to nest in MethodHandleInfo but must be non-public. + */ +/*non-public*/ +final +class InfoFromMemberName implements MethodHandleInfo { + private final MemberName member; + private final int referenceKind; + + InfoFromMemberName(Lookup lookup, MemberName member, byte referenceKind) { + assert(member.isResolved() || member.isMethodHandleInvoke()); + assert(member.referenceKindIsConsistentWith(referenceKind)); + this.member = member; + this.referenceKind = referenceKind; + } + + @Override + public Class getDeclaringClass() { + return member.getDeclaringClass(); + } + + @Override + public String getName() { + return member.getName(); + } + + @Override + public MethodType getMethodType() { + return member.getMethodOrFieldType(); + } + + @Override + public int getModifiers() { + return member.getModifiers(); + } + + @Override + public int getReferenceKind() { + return referenceKind; + } + + @Override + public String toString() { + return MethodHandleInfo.toString(getReferenceKind(), getDeclaringClass(), getName(), getMethodType()); + } + + @Override + public T reflectAs(Class expected, Lookup lookup) { + if (member.isMethodHandleInvoke() && !member.isVarargs()) { + // This member is an instance of a signature-polymorphic method, which cannot be reflected + // A method handle invoker can come in either of two forms: + // A generic placeholder (present in the source code, and varargs) + // and a signature-polymorphic instance (synthetic and not varargs). + // For more information see comments on {@link MethodHandleNatives#linkMethod}. + throw new IllegalArgumentException("cannot reflect signature polymorphic method"); + } + Member mem = AccessController.doPrivileged(new PrivilegedAction() { + public Member run() { + try { + return reflectUnchecked(); + } catch (ReflectiveOperationException ex) { + throw new IllegalArgumentException(ex); + } + } + }); + try { + Class defc = getDeclaringClass(); + byte refKind = (byte) getReferenceKind(); + lookup.checkAccess(refKind, defc, convertToMemberName(refKind, mem)); + } catch (IllegalAccessException ex) { + throw new IllegalArgumentException(ex); + } + return expected.cast(mem); + } + + private Member reflectUnchecked() throws ReflectiveOperationException { + byte refKind = (byte) getReferenceKind(); + Class defc = getDeclaringClass(); + boolean isPublic = Modifier.isPublic(getModifiers()); + if (MethodHandleNatives.refKindIsMethod(refKind)) { + if (isPublic) + return defc.getMethod(getName(), getMethodType().parameterArray()); + else + return defc.getDeclaredMethod(getName(), getMethodType().parameterArray()); + } else if (MethodHandleNatives.refKindIsConstructor(refKind)) { + if (isPublic) + return defc.getConstructor(getMethodType().parameterArray()); + else + return defc.getDeclaredConstructor(getMethodType().parameterArray()); + } else if (MethodHandleNatives.refKindIsField(refKind)) { + if (isPublic) + return defc.getField(getName()); + else + return defc.getDeclaredField(getName()); + } else { + throw new IllegalArgumentException("referenceKind="+refKind); + } + } + + private static MemberName convertToMemberName(byte refKind, Member mem) throws IllegalAccessException { + if (mem instanceof Method) { + boolean wantSpecial = (refKind == REF_invokeSpecial); + return new MemberName((Method) mem, wantSpecial); + } else if (mem instanceof Constructor) { + return new MemberName((Constructor) mem); + } else if (mem instanceof Field) { + boolean isSetter = (refKind == REF_putField || refKind == REF_putStatic); + return new MemberName((Field) mem, isSetter); + } + throw new InternalError(mem.getClass().getName()); + } +} diff --git a/jdk/src/share/classes/java/lang/invoke/Invokers.java b/jdk/src/share/classes/java/lang/invoke/Invokers.java index 8d8e019d722..0ef6078b6b5 100644 --- a/jdk/src/share/classes/java/lang/invoke/Invokers.java +++ b/jdk/src/share/classes/java/lang/invoke/Invokers.java @@ -87,6 +87,7 @@ class Invokers { lform = invokeForm(mtype, true, MethodTypeForm.LF_EX_INVOKER); invoker = SimpleMethodHandle.make(invokerType, lform); } + invoker = invoker.withInternalMemberName(MemberName.makeMethodHandleInvoke("invokeExact", mtype)); assert(checkInvoker(invoker)); exactInvoker = invoker; return invoker; @@ -110,6 +111,7 @@ class Invokers { lform = invokeForm(mtype, true, MethodTypeForm.LF_GEN_INVOKER); invoker = SimpleMethodHandle.make(invokerType, lform); } + invoker = invoker.withInternalMemberName(MemberName.makeMethodHandleInvoke("invoke", mtype)); assert(checkInvoker(invoker)); generalInvoker = invoker; return invoker; diff --git a/jdk/src/share/classes/java/lang/invoke/MemberName.java b/jdk/src/share/classes/java/lang/invoke/MemberName.java index dfb468417d6..910574befe7 100644 --- a/jdk/src/share/classes/java/lang/invoke/MemberName.java +++ b/jdk/src/share/classes/java/lang/invoke/MemberName.java @@ -320,14 +320,18 @@ import java.util.Objects; /** Utility method to query if this member is a method handle invocation (invoke or invokeExact). */ public boolean isMethodHandleInvoke() { - final int bits = Modifier.NATIVE | Modifier.FINAL; + final int bits = MH_INVOKE_MODS; final int negs = Modifier.STATIC; if (testFlags(bits | negs, bits) && clazz == MethodHandle.class) { - return name.equals("invoke") || name.equals("invokeExact"); + return isMethodHandleInvokeName(name); } return false; } + public static boolean isMethodHandleInvokeName(String name) { + return name.equals("invoke") || name.equals("invokeExact"); + } + private static final int MH_INVOKE_MODS = Modifier.NATIVE | Modifier.FINAL | Modifier.PUBLIC; /** Utility method to query the modifier flags of this member. */ public boolean isStatic() { @@ -482,12 +486,27 @@ import java.util.Objects; m.getClass(); // NPE check // fill in vmtarget, vmindex while we have m in hand: MethodHandleNatives.init(this, m); + if (clazz == null) { // MHN.init failed + if (m.getDeclaringClass() == MethodHandle.class && + isMethodHandleInvokeName(m.getName())) { + // The JVM did not reify this signature-polymorphic instance. + // Need a special case here. + // See comments on MethodHandleNatives.linkMethod. + MethodType type = MethodType.methodType(m.getReturnType(), m.getParameterTypes()); + int flags = flagsMods(IS_METHOD, m.getModifiers(), REF_invokeVirtual); + init(MethodHandle.class, m.getName(), type, flags); + if (isMethodHandleInvoke()) + return; + } + throw new LinkageError(m.toString()); + } assert(isResolved() && this.clazz != null); this.name = m.getName(); if (this.type == null) this.type = new Object[] { m.getReturnType(), m.getParameterTypes() }; if (wantSpecial) { - assert(!isAbstract()) : this; + if (isAbstract()) + throw new AbstractMethodError(this.toString()); if (getReferenceKind() == REF_invokeVirtual) changeReferenceKind(REF_invokeSpecial, REF_invokeVirtual); else if (getReferenceKind() == REF_invokeInterface) @@ -562,6 +581,22 @@ import java.util.Objects; initResolved(true); } + /** + * Create a name for a signature-polymorphic invoker. + * This is a placeholder for a signature-polymorphic instance + * (of MH.invokeExact, etc.) that the JVM does not reify. + * See comments on {@link MethodHandleNatives#linkMethod}. + */ + static MemberName makeMethodHandleInvoke(String name, MethodType type) { + return makeMethodHandleInvoke(name, type, MH_INVOKE_MODS | SYNTHETIC); + } + static MemberName makeMethodHandleInvoke(String name, MethodType type, int mods) { + MemberName mem = new MemberName(MethodHandle.class, name, type, REF_invokeVirtual); + mem.flags |= mods; // it's not resolved, but add these modifiers anyway + assert(mem.isMethodHandleInvoke()) : mem; + return mem; + } + // bare-bones constructor; the JVM will fill it in MemberName() { } diff --git a/jdk/src/share/classes/java/lang/invoke/MethodHandle.java b/jdk/src/share/classes/java/lang/invoke/MethodHandle.java index df784d35e5b..408cbd08abc 100644 --- a/jdk/src/share/classes/java/lang/invoke/MethodHandle.java +++ b/jdk/src/share/classes/java/lang/invoke/MethodHandle.java @@ -1284,6 +1284,11 @@ assertEquals("[three, thee, tee]", asListFix.invoke((Object)argv).toString()); return null; // DMH returns DMH.member } + /*non-public*/ + MethodHandle withInternalMemberName(MemberName member) { + return MethodHandleImpl.makeWrappedMember(this, member); + } + /*non-public*/ boolean isInvokeSpecial() { return false; // DMH.Special returns true @@ -1356,7 +1361,7 @@ assertEquals("[three, thee, tee]", asListFix.invoke((Object)argv).toString()); MethodHandle rebind() { // Bind 'this' into a new invoker, of the known class BMH. MethodType type2 = type(); - LambdaForm form2 = reinvokerForm(type2.basicType()); + LambdaForm form2 = reinvokerForm(this); // form2 = lambda (bmh, arg*) { thismh = bmh[0]; invokeBasic(thismh, arg*) } return BoundMethodHandle.bindSingle(type2, form2, this); } @@ -1369,23 +1374,38 @@ assertEquals("[three, thee, tee]", asListFix.invoke((Object)argv).toString()); /** Create a LF which simply reinvokes a target of the given basic type. * The target MH must override {@link #reinvokerTarget} to provide the target. */ - static LambdaForm reinvokerForm(MethodType mtype) { - mtype = mtype.basicType(); + static LambdaForm reinvokerForm(MethodHandle target) { + MethodType mtype = target.type().basicType(); LambdaForm reinvoker = mtype.form().cachedLambdaForm(MethodTypeForm.LF_REINVOKE); if (reinvoker != null) return reinvoker; - MethodHandle MH_invokeBasic = MethodHandles.basicInvoker(mtype); + if (mtype.parameterSlotCount() >= MethodType.MAX_MH_ARITY) + return makeReinvokerForm(target.type(), target); // cannot cache this + reinvoker = makeReinvokerForm(mtype, null); + return mtype.form().setCachedLambdaForm(MethodTypeForm.LF_REINVOKE, reinvoker); + } + private static LambdaForm makeReinvokerForm(MethodType mtype, MethodHandle customTargetOrNull) { + boolean customized = (customTargetOrNull != null); + MethodHandle MH_invokeBasic = customized ? null : MethodHandles.basicInvoker(mtype); final int THIS_BMH = 0; final int ARG_BASE = 1; final int ARG_LIMIT = ARG_BASE + mtype.parameterCount(); int nameCursor = ARG_LIMIT; - final int NEXT_MH = nameCursor++; + final int NEXT_MH = customized ? -1 : nameCursor++; final int REINVOKE = nameCursor++; LambdaForm.Name[] names = LambdaForm.arguments(nameCursor - ARG_LIMIT, mtype.invokerType()); - names[NEXT_MH] = new LambdaForm.Name(NF_reinvokerTarget, names[THIS_BMH]); - Object[] targetArgs = Arrays.copyOfRange(names, THIS_BMH, ARG_LIMIT, Object[].class); - targetArgs[0] = names[NEXT_MH]; // overwrite this MH with next MH - names[REINVOKE] = new LambdaForm.Name(MH_invokeBasic, targetArgs); - return mtype.form().setCachedLambdaForm(MethodTypeForm.LF_REINVOKE, new LambdaForm("BMH.reinvoke", ARG_LIMIT, names)); + Object[] targetArgs; + MethodHandle targetMH; + if (customized) { + targetArgs = Arrays.copyOfRange(names, ARG_BASE, ARG_LIMIT, Object[].class); + targetMH = customTargetOrNull; + } else { + names[NEXT_MH] = new LambdaForm.Name(NF_reinvokerTarget, names[THIS_BMH]); + targetArgs = Arrays.copyOfRange(names, THIS_BMH, ARG_LIMIT, Object[].class); + targetArgs[0] = names[NEXT_MH]; // overwrite this MH with next MH + targetMH = MethodHandles.basicInvoker(mtype); + } + names[REINVOKE] = new LambdaForm.Name(targetMH, targetArgs); + return new LambdaForm("BMH.reinvoke", ARG_LIMIT, names); } private static final LambdaForm.NamedFunction NF_reinvokerTarget; diff --git a/jdk/src/share/classes/java/lang/invoke/MethodHandleImpl.java b/jdk/src/share/classes/java/lang/invoke/MethodHandleImpl.java index 04eda964966..5ab7f7adb7b 100644 --- a/jdk/src/share/classes/java/lang/invoke/MethodHandleImpl.java +++ b/jdk/src/share/classes/java/lang/invoke/MethodHandleImpl.java @@ -317,7 +317,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; private MethodHandle cache; AsVarargsCollector(MethodHandle target, MethodType type, Class arrayType) { - super(type, reinvokerForm(type)); + super(type, reinvokerForm(target)); this.target = target; this.arrayType = arrayType; this.cache = target.asCollector(arrayType, 0); @@ -778,16 +778,27 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; } static Empty throwException(T t) throws T { throw t; } - static MethodHandle FAKE_METHOD_HANDLE_INVOKE; - static - MethodHandle fakeMethodHandleInvoke(MemberName method) { - MethodType type = method.getInvocationType(); - assert(type.equals(MethodType.methodType(Object.class, Object[].class))); - MethodHandle mh = FAKE_METHOD_HANDLE_INVOKE; + static MethodHandle[] FAKE_METHOD_HANDLE_INVOKE = new MethodHandle[2]; + static MethodHandle fakeMethodHandleInvoke(MemberName method) { + int idx; + assert(method.isMethodHandleInvoke()); + switch (method.getName()) { + case "invoke": idx = 0; break; + case "invokeExact": idx = 1; break; + default: throw new InternalError(method.getName()); + } + MethodHandle mh = FAKE_METHOD_HANDLE_INVOKE[idx]; if (mh != null) return mh; - mh = throwException(type.insertParameterTypes(0, UnsupportedOperationException.class)); + MethodType type = MethodType.methodType(Object.class, UnsupportedOperationException.class, + MethodHandle.class, Object[].class); + mh = throwException(type); mh = mh.bindTo(new UnsupportedOperationException("cannot reflectively invoke MethodHandle")); - FAKE_METHOD_HANDLE_INVOKE = mh; + if (!method.getInvocationType().equals(mh.type())) + throw new InternalError(method.toString()); + mh = mh.withInternalMemberName(method); + mh = mh.asVarargsCollector(Object[].class); + assert(method.isVarargs()); + FAKE_METHOD_HANDLE_INVOKE[idx] = mh; return mh; } @@ -821,7 +832,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; MethodHandle vamh = prepareForInvoker(mh); // Cache the result of makeInjectedInvoker once per argument class. MethodHandle bccInvoker = CV_makeInjectedInvoker.get(hostClass); - return restoreToType(bccInvoker.bindTo(vamh), mh.type()); + return restoreToType(bccInvoker.bindTo(vamh), mh.type(), mh.internalMemberName()); } private static MethodHandle makeInjectedInvoker(Class hostClass) { @@ -876,8 +887,11 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; } // Undo the adapter effect of prepareForInvoker: - private static MethodHandle restoreToType(MethodHandle vamh, MethodType type) { - return vamh.asCollector(Object[].class, type.parameterCount()).asType(type); + private static MethodHandle restoreToType(MethodHandle vamh, MethodType type, MemberName member) { + MethodHandle mh = vamh.asCollector(Object[].class, type.parameterCount()); + mh = mh.asType(type); + mh = mh.withInternalMemberName(member); + return mh; } private static final MethodHandle MH_checkCallerClass; @@ -939,4 +953,41 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; } } } + + + /** This subclass allows a wrapped method handle to be re-associated with an arbitrary member name. */ + static class WrappedMember extends MethodHandle { + private final MethodHandle target; + private final MemberName member; + + private WrappedMember(MethodHandle target, MethodType type, MemberName member) { + super(type, reinvokerForm(target)); + this.target = target; + this.member = member; + } + + @Override + MethodHandle reinvokerTarget() { + return target; + } + @Override + MemberName internalMemberName() { + return member; + } + @Override + boolean isInvokeSpecial() { + return target.isInvokeSpecial(); + } + @Override + MethodHandle viewAsType(MethodType newType) { + return new WrappedMember(target, newType, member); + } + } + + static MethodHandle makeWrappedMember(MethodHandle target, MemberName member) { + if (member.equals(target.internalMemberName())) + return target; + return new WrappedMember(target, target.type(), member); + } + } diff --git a/jdk/src/share/classes/java/lang/invoke/MethodHandleInfo.java b/jdk/src/share/classes/java/lang/invoke/MethodHandleInfo.java index 380ca59b6e1..72fd8e91035 100644 --- a/jdk/src/share/classes/java/lang/invoke/MethodHandleInfo.java +++ b/jdk/src/share/classes/java/lang/invoke/MethodHandleInfo.java @@ -24,80 +24,246 @@ */ package java.lang.invoke; + +import java.lang.reflect.*; +import java.util.*; import java.lang.invoke.MethodHandleNatives.Constants; +import java.lang.invoke.MethodHandles.Lookup; +import static java.lang.invoke.MethodHandleStatics.*; /** - * Cracking (reflecting) method handles back into their constituent symbolic parts. + * A symbolic reference obtained by cracking a method handle into its consitutent symbolic parts. + * To crack a direct method handle, call {@link Lookup#revealDirect Lookup.revealDirect}. + *

+ * A direct method handle represents a method, constructor, or field without + * any intervening argument bindings or other transformations. + * The method, constructor, or field referred to by a direct method handle is called + * its underlying member. + * Direct method handles may be obtained in any of these ways: + *

+ * In all of these cases, it is possible to crack the resulting direct method handle + * to recover a symbolic reference for the underlying method, constructor, or field. + * Cracking must be done via a {@code Lookup} object equivalent to that which created + * the target method handle, or which has enough access permissions to recreate + * an equivalent method handle. * + *

Reference kinds

+ * The Lookup Factory Methods + * correspond to all major use cases for methods, constructors, and fields. + * These use cases may be distinguished using small integers as follows: + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
reference kinddescriptive namescopememberbehavior
{@code 1}{@code REF_getField}{@code class}{@code FT f;}{@code (T) this.f;}
{@code 2}{@code REF_getStatic}{@code class} or {@code interface}{@code static}
{@code FT f;}
{@code (T) C.f;}
{@code 3}{@code REF_putField}{@code class}{@code FT f;}{@code this.f = x;}
{@code 4}{@code REF_putStatic}{@code class}{@code static}
{@code FT f;}
{@code C.f = arg;}
{@code 5}{@code REF_invokeVirtual}{@code class}{@code T m(A*);}{@code (T) this.m(arg*);}
{@code 6}{@code REF_invokeStatic}{@code class} or {@code interface}{@code static}
{@code T m(A*);}
{@code (T) C.m(arg*);}
{@code 7}{@code REF_invokeSpecial}{@code class} or {@code interface}{@code T m(A*);}{@code (T) super.m(arg*);}
{@code 8}{@code REF_newInvokeSpecial}{@code class}{@code C(A*);}{@code new C(arg*);}
{@code 9}{@code REF_invokeInterface}{@code interface}{@code T m(A*);}{@code (T) this.m(arg*);}
+ * @since 1.8 */ -final class MethodHandleInfo { - public static final int - REF_getField = Constants.REF_getField, - REF_getStatic = Constants.REF_getStatic, - REF_putField = Constants.REF_putField, - REF_putStatic = Constants.REF_putStatic, - REF_invokeVirtual = Constants.REF_invokeVirtual, - REF_invokeStatic = Constants.REF_invokeStatic, - REF_invokeSpecial = Constants.REF_invokeSpecial, - REF_newInvokeSpecial = Constants.REF_newInvokeSpecial, - REF_invokeInterface = Constants.REF_invokeInterface; +public +interface MethodHandleInfo { + /** + * A direct method handle reference kind, + * as defined in the table above. + */ + public static final int + REF_getField = Constants.REF_getField, + REF_getStatic = Constants.REF_getStatic, + REF_putField = Constants.REF_putField, + REF_putStatic = Constants.REF_putStatic, + REF_invokeVirtual = Constants.REF_invokeVirtual, + REF_invokeStatic = Constants.REF_invokeStatic, + REF_invokeSpecial = Constants.REF_invokeSpecial, + REF_newInvokeSpecial = Constants.REF_newInvokeSpecial, + REF_invokeInterface = Constants.REF_invokeInterface; - private final Class declaringClass; - private final String name; - private final MethodType methodType; - private final int referenceKind; + /** + * Returns the reference kind of the cracked method handle, which in turn + * determines whether the method handle's underlying member was a constructor, method, or field. + * See the table above for definitions. + * @return the integer code for the kind of reference used to access the underlying member + */ + public int getReferenceKind(); - public MethodHandleInfo(MethodHandle mh) { - MemberName mn = mh.internalMemberName(); - if (mn == null) throw new IllegalArgumentException("not a direct method handle"); - this.declaringClass = mn.getDeclaringClass(); - this.name = mn.getName(); - this.methodType = mn.getMethodOrFieldType(); - byte refKind = mn.getReferenceKind(); - if (refKind == REF_invokeSpecial && !mh.isInvokeSpecial()) - // Devirtualized method invocation is usually formally virtual. - refKind = REF_invokeVirtual; - this.referenceKind = refKind; - } + /** + * Returns the class in which the cracked method handle's underlying member was defined. + * @return the declaring class of the underlying member + */ + public Class getDeclaringClass(); - public Class getDeclaringClass() { - return declaringClass; - } + /** + * Returns the name of the cracked method handle's underlying member. + * This is {@code "<init>"} if the underlying member was a constructor, + * else it is a simple method name or field name. + * @return the simple name of the underlying member + */ + public String getName(); - public String getName() { - return name; - } + /** + * Returns the nominal type of the cracked symbolic reference, expressed as a method type. + * If the reference is to a constructor, the return type will be {@code void}. + * If it is to a non-static method, the method type will not mention the {@code this} parameter. + * If it is to a field and the requested access is to read the field, + * the method type will have no parameters and return the field type. + * If it is to a field and the requested access is to write the field, + * the method type will have one parameter of the field type and return {@code void}. + *

+ * Note that original direct method handle may include a leading {@code this} parameter, + * or (in the case of a constructor) will replace the {@code void} return type + * with the constructed class. + * The nominal type does not include any {@code this} parameter, + * and (in the case of a constructor) will return {@code void}. + * @return the type of the underlying member, expressed as a method type + */ + public MethodType getMethodType(); - public MethodType getMethodType() { - return methodType; - } + // Utility methods. + // NOTE: class/name/type and reference kind constitute a symbolic reference + // member and modifiers are an add-on, derived from Core Reflection (or the equivalent) - public int getModifiers() { - return -1; //TODO - } + /** + * Reflects the underlying member as a method, constructor, or field object. + * If the underlying member is public, it is reflected as if by + * {@code getMethod}, {@code getConstructor}, or {@code getField}. + * Otherwise, it is reflected as if by + * {@code getDeclaredMethod}, {@code getDeclaredConstructor}, or {@code getDeclaredField}. + * The underlying member must be accessible to the given lookup object. + * @param the desired type of the result, either {@link Member} or a subtype + * @param expected a class object representing the desired result type {@code T} + * @param lookup the lookup object that created this MethodHandleInfo, or one with equivalent access privileges + * @return a reference to the method, constructor, or field object + * @exception ClassCastException if the member is not of the expected type + * @exception NullPointerException if either argument is {@code null} + * @exception IllegalArgumentException if the underlying member is not accessible to the given lookup object + */ + public T reflectAs(Class expected, Lookup lookup); - public int getReferenceKind() { - return referenceKind; - } + /** + * Returns the access modifiers of the underlying member. + * @return the Java language modifiers for underlying member, + * or -1 if the member cannot be accessed + * @see Modifier + * @see reflectAs + */ + public int getModifiers(); - static String getReferenceKindString(int referenceKind) { - switch (referenceKind) { - case REF_getField: return "getfield"; - case REF_getStatic: return "getstatic"; - case REF_putField: return "putfield"; - case REF_putStatic: return "putstatic"; - case REF_invokeVirtual: return "invokevirtual"; - case REF_invokeStatic: return "invokestatic"; - case REF_invokeSpecial: return "invokespecial"; - case REF_newInvokeSpecial: return "newinvokespecial"; - case REF_invokeInterface: return "invokeinterface"; - default: return "UNKNOWN_REFENCE_KIND" + "[" + referenceKind + "]"; - } + /** + * Determines if the underlying member was a variable arity method or constructor. + * Such members are represented by method handles that are varargs collectors. + * @implSpec + * This produces a result equivalent to: + *

{@code
+     *     getReferenceKind() >= REF_invokeVirtual && Modifier.isTransient(getModifiers())
+     * }
+ * + * + * @return {@code true} if and only if the underlying member was declared with variable arity. + */ + // spelling derived from java.lang.reflect.Executable, not MethodHandle.isVarargsCollector + public default boolean isVarArgs() { + // fields are never varargs: + if (MethodHandleNatives.refKindIsField((byte) getReferenceKind())) + return false; + // not in the public API: Modifier.VARARGS + final int ACC_VARARGS = 0x00000080; // from JVMS 4.6 (Table 4.20) + assert(ACC_VARARGS == Modifier.TRANSIENT); + return Modifier.isTransient(getModifiers()); } - @Override - public String toString() { - return String.format("%s %s.%s:%s", getReferenceKindString(referenceKind), - declaringClass.getName(), name, methodType); + /** + * Returns the descriptive name of the given reference kind, + * as defined in the table above. + * The conventional prefix "REF_" is omitted. + * @param referenceKind an integer code for a kind of reference used to access a class member + * @return a mixed-case string such as {@code "getField"} + * @exception IllegalArgumentException if the argument is not a valid + * reference kind number + */ + public static String referenceKindToString(int referenceKind) { + if (!MethodHandleNatives.refKindIsValid(referenceKind)) + throw newIllegalArgumentException("invalid reference kind", referenceKind); + return MethodHandleNatives.refKindName((byte)referenceKind); + } + + /** + * Returns a string representation for a {@code MethodHandleInfo}, + * given the four parts of its symbolic reference. + * This is defined to be of the form {@code "RK C.N:MT"}, where {@code RK} is the + * {@linkplain #referenceKindToString reference kind string} for {@code kind}, + * {@code C} is the {@linkplain java.lang.Class#getName name} of {@code defc} + * {@code N} is the {@code name}, and + * {@code MT} is the {@code type}. + * These four values may be obtained from the + * {@linkplain #getReferenceKind reference kind}, + * {@linkplain #getDeclaringClass declaring class}, + * {@linkplain #getName member name}, + * and {@linkplain #getMethodType method type} + * of a {@code MethodHandleInfo} object. + * + * @implSpec + * This produces a result equivalent to: + *
{@code
+     *     String.format("%s %s.%s:%s", referenceKindToString(kind), defc.getName(), name, type)
+     * }
+ * + * @param kind the {@linkplain #getReferenceKind reference kind} part of the symbolic reference + * @param defc the {@linkplain #getDeclaringClass declaring class} part of the symbolic reference + * @param name the {@linkplain #getName member name} part of the symbolic reference + * @param type the {@linkplain #getMethodType method type} part of the symbolic reference + * @return a string of the form {@code "RK C.N:MT"} + * @exception IllegalArgumentException if the first argument is not a valid + * reference kind number + * @exception NullPointerException if any reference argument is {@code null} + */ + public static String toString(int kind, Class defc, String name, MethodType type) { + Objects.requireNonNull(name); Objects.requireNonNull(type); + return String.format("%s %s.%s:%s", referenceKindToString(kind), defc.getName(), name, type); } } diff --git a/jdk/src/share/classes/java/lang/invoke/MethodHandleNatives.java b/jdk/src/share/classes/java/lang/invoke/MethodHandleNatives.java index 06e61a7dd8b..4f83e82158c 100644 --- a/jdk/src/share/classes/java/lang/invoke/MethodHandleNatives.java +++ b/jdk/src/share/classes/java/lang/invoke/MethodHandleNatives.java @@ -205,6 +205,9 @@ class MethodHandleNatives { static boolean refKindIsMethod(byte refKind) { return !refKindIsField(refKind) && (refKind != REF_newInvokeSpecial); } + static boolean refKindIsConstructor(byte refKind) { + return (refKind == REF_newInvokeSpecial); + } static boolean refKindHasReceiver(byte refKind) { assert(refKindIsValid(refKind)); return (refKind & 1) != 0; @@ -313,7 +316,65 @@ class MethodHandleNatives { * The method assumes the following arguments on the stack: * 0: the method handle being invoked * 1-N: the arguments to the method handle invocation - * N+1: an implicitly added type argument (the given MethodType) + * N+1: an optional, implicitly added argument (typically the given MethodType) + *

+ * The nominal method at such a call site is an instance of + * a signature-polymorphic method (see @PolymorphicSignature). + * Such method instances are user-visible entities which are + * "split" from the generic placeholder method in {@code MethodHandle}. + * (Note that the placeholder method is not identical with any of + * its instances. If invoked reflectively, is guaranteed to throw an + * {@code UnsupportedOperationException}.) + * If the signature-polymorphic method instance is ever reified, + * it appears as a "copy" of the original placeholder + * (a native final member of {@code MethodHandle}) except + * that its type descriptor has shape required by the instance, + * and the method instance is not varargs. + * The method instance is also marked synthetic, since the + * method (by definition) does not appear in Java source code. + *

+ * The JVM is allowed to reify this method as instance metadata. + * For example, {@code invokeBasic} is always reified. + * But the JVM may instead call {@code linkMethod}. + * If the result is an * ordered pair of a {@code (method, appendix)}, + * the method gets all the arguments (0..N inclusive) + * plus the appendix (N+1), and uses the appendix to complete the call. + * In this way, one reusable method (called a "linker method") + * can perform the function of any number of polymorphic instance + * methods. + *

+ * Linker methods are allowed to be weakly typed, with any or + * all references rewritten to {@code Object} and any primitives + * (except {@code long}/{@code float}/{@code double}) + * rewritten to {@code int}. + * A linker method is trusted to return a strongly typed result, + * according to the specific method type descriptor of the + * signature-polymorphic instance it is emulating. + * This can involve (as necessary) a dynamic check using + * data extracted from the appendix argument. + *

+ * The JVM does not inspect the appendix, other than to pass + * it verbatim to the linker method at every call. + * This means that the JDK runtime has wide latitude + * for choosing the shape of each linker method and its + * corresponding appendix. + * Linker methods should be generated from {@code LambdaForm}s + * so that they do not become visible on stack traces. + *

+ * The {@code linkMethod} call is free to omit the appendix + * (returning null) and instead emulate the required function + * completely in the linker method. + * As a corner case, if N==255, no appendix is possible. + * In this case, the method returned must be custom-generated to + * to perform any needed type checking. + *

+ * If the JVM does not reify a method at a call site, but instead + * calls {@code linkMethod}, the corresponding call represented + * in the bytecodes may mention a valid method which is not + * representable with a {@code MemberName}. + * Therefore, use cases for {@code linkMethod} tend to correspond to + * special cases in reflective code such as {@code findVirtual} + * or {@code revealDirect}. */ static MemberName linkMethod(Class callerClass, int refKind, Class defc, String name, Object type, diff --git a/jdk/src/share/classes/java/lang/invoke/MethodHandles.java b/jdk/src/share/classes/java/lang/invoke/MethodHandles.java index 78b01215636..f0f9447e001 100644 --- a/jdk/src/share/classes/java/lang/invoke/MethodHandles.java +++ b/jdk/src/share/classes/java/lang/invoke/MethodHandles.java @@ -26,8 +26,6 @@ package java.lang.invoke; import java.lang.reflect.*; -import java.security.AccessController; -import java.security.PrivilegedAction; import java.util.List; import java.util.ArrayList; import java.util.Arrays; @@ -54,6 +52,7 @@ import sun.security.util.SecurityConstants; * *

* @author John Rose, JSR 292 EG + * @since 1.7 */ public class MethodHandles { @@ -96,6 +95,38 @@ public class MethodHandles { return Lookup.PUBLIC_LOOKUP; } + /** + * Performs an unchecked "crack" of a direct method handle. + * The result is as if the user had obtained a lookup object capable enough + * to crack the target method handle, called + * {@link java.lang.invoke.MethodHandles.Lookup#revealDirect Lookup.revealDirect} + * on the target to obtain its symbolic reference, and then called + * {@link java.lang.invoke.MethodHandleInfo#reflectAs MethodHandleInfo.reflectAs} + * to resolve the symbolic reference to a member. + *

+ * If there is a security manager, its {@code checkPermission} method + * is called with a {@code ReflectPermission("suppressAccessChecks")} permission. + * @param the desired type of the result, either {@link Member} or a subtype + * @param target a direct method handle to crack into symbolic reference components + * @param expected a class object representing the desired result type {@code T} + * @return a reference to the method, constructor, or field object + * @exception SecurityException if the caller is not privileged to call {@code setAccessible} + * @exception NullPointerException if either argument is {@code null} + * @exception IllegalArgumentException if the target is not a direct method handle + * @exception ClassCastException if the member is not of the expected type + * @since 1.8 + */ + public static T + reflectAs(Class expected, MethodHandle target) { + SecurityManager smgr = System.getSecurityManager(); + if (smgr != null) smgr.checkPermission(ACCESS_PERMISSION); + Lookup lookup = Lookup.IMPL_LOOKUP; // use maximally privileged lookup + return lookup.revealDirect(target).reflectAs(expected, lookup); + } + // Copied from AccessibleObject, as used by Method.setAccessible, etc.: + static final private java.security.Permission ACCESS_PERMISSION = + new ReflectPermission("suppressAccessChecks"); + /** * A lookup object is a factory for creating method handles, * when the creation requires access checking. @@ -647,6 +678,7 @@ public class MethodHandles { return invoker(type); if ("invokeExact".equals(name)) return exactInvoker(type); + assert(!MemberName.isMethodHandleInvokeName(name)); return null; } @@ -892,6 +924,10 @@ return mh1; * @throws NullPointerException if the argument is null */ public MethodHandle unreflect(Method m) throws IllegalAccessException { + if (m.getDeclaringClass() == MethodHandle.class) { + MethodHandle mh = unreflectForMH(m); + if (mh != null) return mh; + } MemberName method = new MemberName(m); byte refKind = method.getReferenceKind(); if (refKind == REF_invokeSpecial) @@ -900,6 +936,12 @@ return mh1; Lookup lookup = m.isAccessible() ? IMPL_LOOKUP : this; return lookup.getDirectMethod(refKind, method.getDeclaringClass(), method, findBoundCallerClass(method)); } + private MethodHandle unreflectForMH(Method m) { + // these names require special lookups because they throw UnsupportedOperationException + if (MemberName.isMethodHandleInvokeName(m.getName())) + return MethodHandleImpl.fakeMethodHandleInvoke(new MemberName(m)); + return null; + } /** * Produces a method handle for a reflected method. @@ -1004,6 +1046,46 @@ return mh1; return unreflectField(f, true); } + /** + * Cracks a direct method handle created by this lookup object or a similar one. + * Security and access checks are performed to ensure that this lookup object + * is capable of reproducing the target method handle. + * This means that the cracking may fail if target is a direct method handle + * but was created by an unrelated lookup object. + * @param target a direct method handle to crack into symbolic reference components + * @return a symbolic reference which can be used to reconstruct this method handle from this lookup object + * @exception SecurityException if a security manager is present and it + * refuses access + * @throws IllegalArgumentException if the target is not a direct method handle or if access checking fails + * @exception NullPointerException if the target is {@code null} + * @since 1.8 + */ + public MethodHandleInfo revealDirect(MethodHandle target) { + MemberName member = target.internalMemberName(); + if (member == null || (!member.isResolved() && !member.isMethodHandleInvoke())) + throw newIllegalArgumentException("not a direct method handle"); + Class defc = member.getDeclaringClass(); + byte refKind = member.getReferenceKind(); + assert(MethodHandleNatives.refKindIsValid(refKind)); + if (refKind == REF_invokeSpecial && !target.isInvokeSpecial()) + // Devirtualized method invocation is usually formally virtual. + // To avoid creating extra MemberName objects for this common case, + // we encode this extra degree of freedom using MH.isInvokeSpecial. + refKind = REF_invokeVirtual; + if (refKind == REF_invokeVirtual && defc.isInterface()) + // Symbolic reference is through interface but resolves to Object method (toString, etc.) + refKind = REF_invokeInterface; + // Check SM permissions and member access before cracking. + try { + checkSecurityManager(defc, member); + checkAccess(refKind, defc, member); + } catch (IllegalAccessException ex) { + throw new IllegalArgumentException(ex); + } + // Produce the handle to the results. + return new InfoFromMemberName(this, member, refKind); + } + /// Helper methods, all package-private. MemberName resolveOrFail(byte refKind, Class refc, String name, Class type) throws NoSuchFieldException, IllegalAccessException { @@ -1201,12 +1283,12 @@ return mh1; private MethodHandle getDirectMethodCommon(byte refKind, Class refc, MemberName method, boolean doRestrict, Class callerClass) throws IllegalAccessException { checkMethod(refKind, refc, method); - if (method.isMethodHandleInvoke()) - return fakeMethodHandleInvoke(method); + assert(!method.isMethodHandleInvoke()); Class refcAsSuper; if (refKind == REF_invokeSpecial && refc != lookupClass() && + !refc.isInterface() && refc != (refcAsSuper = lookupClass().getSuperclass()) && refc.isAssignableFrom(lookupClass())) { assert(!method.getName().equals("")); // not this code path @@ -1234,9 +1316,6 @@ return mh1; mh = restrictReceiver(method, mh, lookupClass()); return mh; } - private MethodHandle fakeMethodHandleInvoke(MemberName method) { - return throwException(method.getReturnType(), UnsupportedOperationException.class); - } private MethodHandle maybeBindCaller(MemberName method, MethodHandle mh, Class callerClass) throws IllegalAccessException { diff --git a/jdk/src/share/classes/java/lang/invoke/SerializedLambda.java b/jdk/src/share/classes/java/lang/invoke/SerializedLambda.java index a775fc43e34..9be96ff685b 100644 --- a/jdk/src/share/classes/java/lang/invoke/SerializedLambda.java +++ b/jdk/src/share/classes/java/lang/invoke/SerializedLambda.java @@ -225,7 +225,7 @@ public final class SerializedLambda implements Serializable { @Override public String toString() { - String implKind=MethodHandleInfo.getReferenceKindString(implMethodKind); + String implKind=MethodHandleInfo.referenceKindToString(implMethodKind); return String.format("SerializedLambda[%s=%s, %s=%s.%s:%s, " + "%s=%s %s.%s:%s, %s=%s, %s=%d]", "capturingClass", capturingClass, diff --git a/jdk/test/java/lang/invoke/7087570/Test7087570.java b/jdk/test/java/lang/invoke/7087570/Test7087570.java index 572faccdf5a..732467b8c62 100644 --- a/jdk/test/java/lang/invoke/7087570/Test7087570.java +++ b/jdk/test/java/lang/invoke/7087570/Test7087570.java @@ -35,20 +35,9 @@ import java.util.*; import static java.lang.invoke.MethodHandles.*; import static java.lang.invoke.MethodType.*; +import static java.lang.invoke.MethodHandleInfo.*; public class Test7087570 { - // XXX may remove the following constant declarations when MethodHandleInfo is made public - private static final int - REF_getField = 1, - REF_getStatic = 2, - REF_putField = 3, - REF_putStatic = 4, - REF_invokeVirtual = 5, - REF_invokeStatic = 6, - REF_invokeSpecial = 7, - REF_newInvokeSpecial = 8, - REF_invokeInterface = 9, - REF_LIMIT = 10; private static final TestMethodData[] TESTS = new TestMethodData[] { // field accessors @@ -87,17 +76,17 @@ public class Test7087570 { } private static void doTest(MethodHandle mh, TestMethodData testMethod) { - Object mhi = newMethodHandleInfo(mh); + MethodHandleInfo mhi = LOOKUP.revealDirect(mh); System.out.printf("%s.%s: %s, nominal refKind: %s, actual refKind: %s\n", testMethod.clazz.getName(), testMethod.name, testMethod.methodType, - REF_KIND_NAMES[testMethod.referenceKind], - REF_KIND_NAMES[getReferenceKind(mhi)]); - assertEquals(testMethod.name, getName(mhi)); - assertEquals(testMethod.methodType, getMethodType(mhi)); - assertEquals(testMethod.declaringClass, getDeclaringClass(mhi)); + referenceKindToString(testMethod.referenceKind), + referenceKindToString(mhi.getReferenceKind())); + assertEquals(testMethod.name, mhi.getName()); + assertEquals(testMethod.methodType, mhi.getMethodType()); + assertEquals(testMethod.declaringClass, mhi.getDeclaringClass()); assertEquals(testMethod.referenceKind == REF_invokeSpecial, isInvokeSpecial(mh)); - assertRefKindEquals(testMethod.referenceKind, getReferenceKind(mhi)); + assertRefKindEquals(testMethod.referenceKind, mhi.getReferenceKind()); } private static void testWithLookup() throws Throwable { @@ -122,50 +111,8 @@ public class Test7087570 { return methodType(void.class, clazz); } - private static final String[] REF_KIND_NAMES = { - "MH::invokeBasic", - "REF_getField", "REF_getStatic", "REF_putField", "REF_putStatic", - "REF_invokeVirtual", "REF_invokeStatic", "REF_invokeSpecial", - "REF_newInvokeSpecial", "REF_invokeInterface" - }; - private static final Lookup LOOKUP = lookup(); - // XXX may remove the following reflective logic when MethodHandleInfo is made public - private static final MethodHandle MH_IS_INVOKESPECIAL; - private static final MethodHandle MHI_CONSTRUCTOR; - private static final MethodHandle MHI_GET_NAME; - private static final MethodHandle MHI_GET_METHOD_TYPE; - private static final MethodHandle MHI_GET_DECLARING_CLASS; - private static final MethodHandle MHI_GET_REFERENCE_KIND; - - static { - try { - // This is white box testing. Use reflection to grab private implementation bits. - String magicName = "IMPL_LOOKUP"; - Field magicLookup = MethodHandles.Lookup.class.getDeclaredField(magicName); - // This unit test will fail if a security manager is installed. - magicLookup.setAccessible(true); - // Forbidden fruit... - Lookup directInvokeLookup = (Lookup) magicLookup.get(null); - Class mhiClass = Class.forName("java.lang.invoke.MethodHandleInfo", false, MethodHandle.class.getClassLoader()); - MH_IS_INVOKESPECIAL = directInvokeLookup - .findVirtual(MethodHandle.class, "isInvokeSpecial", methodType(boolean.class)); - MHI_CONSTRUCTOR = directInvokeLookup - .findConstructor(mhiClass, methodType(void.class, MethodHandle.class)); - MHI_GET_NAME = directInvokeLookup - .findVirtual(mhiClass, "getName", methodType(String.class)); - MHI_GET_METHOD_TYPE = directInvokeLookup - .findVirtual(mhiClass, "getMethodType", methodType(MethodType.class)); - MHI_GET_DECLARING_CLASS = directInvokeLookup - .findVirtual(mhiClass, "getDeclaringClass", methodType(Class.class)); - MHI_GET_REFERENCE_KIND = directInvokeLookup - .findVirtual(mhiClass, "getReferenceKind", methodType(int.class)); - } catch (ReflectiveOperationException ex) { - throw new Error(ex); - } - } - private static class TestMethodData { final Class clazz; final String name; @@ -208,7 +155,9 @@ public class Test7087570 { return LOOKUP.findStatic(testMethod.clazz, testMethod.name, testMethod.methodType); case REF_invokeSpecial: Class thisClass = LOOKUP.lookupClass(); - return LOOKUP.findSpecial(testMethod.clazz, testMethod.name, testMethod.methodType, thisClass); + MethodHandle smh = LOOKUP.findSpecial(testMethod.clazz, testMethod.name, testMethod.methodType, thisClass); + noteInvokeSpecial(smh); + return smh; case REF_newInvokeSpecial: return LOOKUP.findConstructor(testMethod.clazz, testMethod.methodType); default: @@ -238,7 +187,9 @@ public class Test7087570 { case REF_invokeSpecial: { Method m = testMethod.clazz.getDeclaredMethod(testMethod.name, testMethod.methodType.parameterArray()); Class thisClass = LOOKUP.lookupClass(); - return LOOKUP.unreflectSpecial(m, thisClass); + MethodHandle smh = LOOKUP.unreflectSpecial(m, thisClass); + noteInvokeSpecial(smh); + return smh; } case REF_newInvokeSpecial: { Constructor c = testMethod.clazz.getDeclaredConstructor(testMethod.methodType.parameterArray()); @@ -249,59 +200,20 @@ public class Test7087570 { } } - private static Object newMethodHandleInfo(MethodHandle mh) { - try { - return MHI_CONSTRUCTOR.invoke(mh); - } catch (Throwable ex) { - throw new Error(ex); - } + private static List specialMethodHandles = new ArrayList<>(); + private static void noteInvokeSpecial(MethodHandle mh) { + specialMethodHandles.add(mh); + assert(isInvokeSpecial(mh)); } - private static boolean isInvokeSpecial(MethodHandle mh) { - try { - return (boolean) MH_IS_INVOKESPECIAL.invokeExact(mh); - } catch (Throwable ex) { - throw new Error(ex); - } - } - - private static String getName(Object mhi) { - try { - return (String) MHI_GET_NAME.invoke(mhi); - } catch (Throwable ex) { - throw new Error(ex); - } - } - - private static MethodType getMethodType(Object mhi) { - try { - return (MethodType) MHI_GET_METHOD_TYPE.invoke(mhi); - } catch (Throwable ex) { - throw new Error(ex); - } - } - - private static Class getDeclaringClass(Object mhi) { - try { - return (Class) MHI_GET_DECLARING_CLASS.invoke(mhi); - } catch (Throwable ex) { - throw new Error(ex); - } - } - - private static int getReferenceKind(Object mhi) { - try { - return (int) MHI_GET_REFERENCE_KIND.invoke(mhi); - } catch (Throwable ex) { - throw new Error(ex); - } + return specialMethodHandles.contains(mh); } private static void assertRefKindEquals(int expect, int observed) { if (expect == observed) return; - String msg = "expected " + REF_KIND_NAMES[(int) expect] + - " but observed " + REF_KIND_NAMES[(int) observed]; + String msg = "expected " + referenceKindToString(expect) + + " but observed " + referenceKindToString(observed); System.out.println("FAILED: " + msg); throw new AssertionError(msg); } diff --git a/jdk/test/java/lang/invoke/RevealDirectTest.java b/jdk/test/java/lang/invoke/RevealDirectTest.java new file mode 100644 index 00000000000..f05b19077c1 --- /dev/null +++ b/jdk/test/java/lang/invoke/RevealDirectTest.java @@ -0,0 +1,753 @@ +/* + * 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. + */ + +/* + * @test + * @summary verify Lookup.revealDirect on a variety of input handles + * @compile -XDignore.symbol.file RevealDirectTest.java + * @run junit/othervm -ea -esa test.java.lang.invoke.RevealDirectTest + * + * @test + * @summary verify Lookup.revealDirect on a variety of input handles, with security manager + * @run main/othervm/policy=jtreg.security.policy/secure=java.lang.SecurityManager -ea -esa test.java.lang.invoke.RevealDirectTest + */ + +/* To run manually: + * $ $JAVA8X_HOME/bin/javac -cp $JUNIT4_JAR -d ../../../.. -XDignore.symbol.file RevealDirectTest.java + * $ $JAVA8X_HOME/bin/java -cp $JUNIT4_JAR:../../../.. -ea -esa org.junit.runner.JUnitCore test.java.lang.invoke.RevealDirectTest + * $ $JAVA8X_HOME/bin/java -cp $JUNIT4_JAR:../../../.. -ea -esa -Djava.security.manager test.java.lang.invoke.RevealDirectTest + */ + +package test.java.lang.invoke; + +import java.lang.reflect.*; +import java.lang.invoke.*; +import static java.lang.invoke.MethodHandles.*; +import static java.lang.invoke.MethodType.*; +import static java.lang.invoke.MethodHandleInfo.*; +import java.util.*; +import static org.junit.Assert.*; +import org.junit.*; + +public class RevealDirectTest { + public static void main(String... av) throws Throwable { + // Run the @Test methods explicitly, in case we don't want to use the JUnitCore driver. + // This appears to be necessary when running with a security manager. + Throwable fail = null; + for (Method test : RevealDirectTest.class.getDeclaredMethods()) { + if (!test.isAnnotationPresent(Test.class)) continue; + try { + test.invoke(new RevealDirectTest()); + } catch (Throwable ex) { + if (ex instanceof InvocationTargetException) + ex = ex.getCause(); + if (fail == null) fail = ex; + System.out.println("Testcase: "+test.getName() + +"("+test.getDeclaringClass().getName() + +"):\tCaused an ERROR"); + System.out.println(ex); + ex.printStackTrace(System.out); + } + } + if (fail != null) throw fail; + } + + public interface SimpleSuperInterface { + public abstract int getInt(); + public static void printAll(String... args) { + System.out.println(Arrays.toString(args)); + } + public int NICE_CONSTANT = 42; + } + public interface SimpleInterface extends SimpleSuperInterface { + default float getFloat() { return getInt(); } + public static void printAll(String[] args) { + System.out.println(Arrays.toString(args)); + } + } + public static class Simple implements SimpleInterface, Cloneable { + public int intField; + public final int finalField; + private static String stringField; + public int getInt() { return NICE_CONSTANT; } + private static Number getNum() { return 804; } + public Simple clone() { + try { + return (Simple) super.clone(); + } catch (CloneNotSupportedException ex) { + throw new RuntimeException(ex); + } + } + Simple() { finalField = -NICE_CONSTANT; } + private static Lookup localLookup() { return lookup(); } + private static List members() { return getMembers(lookup().lookupClass()); }; + } + + static boolean VERBOSE = false; + + @Test public void testSimple() throws Throwable { + if (VERBOSE) System.out.println("@Test testSimple"); + testOnMembers("testSimple", Simple.members(), Simple.localLookup()); + } + @Test public void testPublicLookup() throws Throwable { + if (VERBOSE) System.out.println("@Test testPublicLookup"); + List mems = publicOnly(Simple.members()); + Lookup pubLookup = publicLookup(), privLookup = Simple.localLookup(); + testOnMembers("testPublicLookup/1", mems, pubLookup); + // reveal using publicLookup: + testOnMembers("testPublicLookup/2", mems, privLookup, pubLookup); + // lookup using publicLookup, but reveal using private: + testOnMembers("testPublicLookup/3", mems, pubLookup, privLookup); + } + @Test public void testPublicLookupNegative() throws Throwable { + if (VERBOSE) System.out.println("@Test testPublicLookupNegative"); + List mems = nonPublicOnly(Simple.members()); + Lookup pubLookup = publicLookup(), privLookup = Simple.localLookup(); + testOnMembersNoLookup("testPublicLookupNegative/1", mems, pubLookup); + testOnMembersNoReveal("testPublicLookupNegative/2", mems, privLookup, pubLookup); + testOnMembersNoReflect("testPublicLookupNegative/3", mems, privLookup, pubLookup); + } + @Test public void testJavaLangClass() throws Throwable { + if (VERBOSE) System.out.println("@Test testJavaLangClass"); + List mems = callerSensitive(false, publicOnly(getMembers(Class.class))); + mems = limit(20, mems); + testOnMembers("testJavaLangClass", mems, Simple.localLookup()); + } + @Test public void testCallerSensitive() throws Throwable { + if (VERBOSE) System.out.println("@Test testCallerSensitive"); + List mems = union(getMembers(MethodHandles.class, "lookup"), + getMembers(Method.class, "invoke"), + getMembers(Field.class, "get", "set", "getLong"), + getMembers(Class.class)); + mems = callerSensitive(true, publicOnly(mems)); + mems = limit(10, mems); + testOnMembers("testCallerSensitive", mems, Simple.localLookup()); + } + @Test public void testCallerSensitiveNegative() throws Throwable { + if (VERBOSE) System.out.println("@Test testCallerSensitiveNegative"); + List mems = union(getMembers(MethodHandles.class, "lookup"), + getMembers(Class.class, "forName"), + getMembers(Method.class, "invoke")); + mems = callerSensitive(true, publicOnly(mems)); + // CS methods cannot be looked up with publicLookup + testOnMembersNoLookup("testCallerSensitiveNegative", mems, publicLookup()); + } + @Test public void testMethodHandleNatives() throws Throwable { + if (VERBOSE) System.out.println("@Test testMethodHandleNatives"); + List mems = getMembers(MethodHandle.class, "invoke", "invokeExact"); + testOnMembers("testMethodHandleNatives", mems, Simple.localLookup()); + } + @Test public void testMethodHandleInvokes() throws Throwable { + if (VERBOSE) System.out.println("@Test testMethodHandleInvokes"); + List types = new ArrayList<>(); + Class[] someParamTypes = { void.class, int.class, Object.class, Object[].class }; + for (Class rt : someParamTypes) { + for (Class p0 : someParamTypes) { + if (p0 == void.class) { types.add(methodType(rt)); continue; } + for (Class p1 : someParamTypes) { + if (p1 == void.class) { types.add(methodType(rt, p0)); continue; } + for (Class p2 : someParamTypes) { + if (p2 == void.class) { types.add(methodType(rt, p0, p1)); continue; } + types.add(methodType(rt, p0, p1, p2)); + } + } + } + } + List mems = union(getPolyMembers(MethodHandle.class, "invoke", types), + getPolyMembers(MethodHandle.class, "invokeExact", types)); + testOnMembers("testMethodHandleInvokes/1", mems, Simple.localLookup()); + testOnMembers("testMethodHandleInvokes/2", mems, publicLookup()); + } + + static List getPolyMembers(Class cls, String name, List types) { + assert(cls == MethodHandle.class); + ArrayList mems = new ArrayList<>(); + for (MethodType type : types) { + mems.add(new SignaturePolymorphicMethod(name, type)); + } + return mems; + } + static List getMembers(Class cls) { + return getMembers(cls, (String[]) null); + } + static List getMembers(Class cls, String... onlyNames) { + List names = (onlyNames == null || onlyNames.length == 0 ? null : Arrays.asList(onlyNames)); + ArrayList res = new ArrayList<>(); + for (Class sup : getSupers(cls)) { + res.addAll(getDeclaredMembers(sup, "getDeclaredFields")); + res.addAll(getDeclaredMembers(sup, "getDeclaredMethods")); + res.addAll(getDeclaredMembers(sup, "getDeclaredConstructors")); + } + res = new ArrayList<>(new LinkedHashSet<>(res)); + for (int i = 0; i < res.size(); i++) { + Member mem = res.get(i); + if (!canBeReached(mem, cls) || + res.indexOf(mem) != i || + mem.isSynthetic() || + (names != null && !names.contains(mem.getName())) + ) { + res.remove(i--); + } + } + return res; + } + static List> getSupers(Class cls) { + ArrayList> res = new ArrayList<>(); + ArrayList> intfs = new ArrayList<>(); + for (Class sup = cls; sup != null; sup = sup.getSuperclass()) { + res.add(sup); + for (Class intf : cls.getInterfaces()) { + if (!intfs.contains(intf)) + intfs.add(intf); + } + } + for (int i = 0; i < intfs.size(); i++) { + for (Class intf : intfs.get(i).getInterfaces()) { + if (!intfs.contains(intf)) + intfs.add(intf); + } + } + res.addAll(intfs); + //System.out.println("getSupers => "+res); + return res; + } + static boolean hasSM() { + return (System.getSecurityManager() != null); + } + static List getDeclaredMembers(Class cls, String accessor) { + Member[] mems = {}; + Method getter = getMethod(Class.class, accessor); + if (hasSM()) { + try { + mems = (Member[]) invokeMethod(getter, cls); + } catch (SecurityException ex) { + //if (VERBOSE) ex.printStackTrace(); + accessor = accessor.replace("Declared", ""); + getter = getMethod(Class.class, accessor); + if (VERBOSE) System.out.println("replaced accessor: "+getter); + } + } + if (mems.length == 0) { + try { + mems = (Member[]) invokeMethod(getter, cls); + } catch (SecurityException ex) { + ex.printStackTrace(); + } + } + if (VERBOSE) System.out.println(accessor+" "+cls.getName()+" => "+mems.length+" members"); + return Arrays.asList(mems); + } + static Method getMethod(Class cls, String name) { + try { + return cls.getMethod(name); + } catch (ReflectiveOperationException ex) { + throw new AssertionError(ex); + } + } + static Object invokeMethod(Method m, Object recv, Object... args) { + try { + return m.invoke(recv, args); + } catch (InvocationTargetException ex) { + Throwable ex2 = ex.getCause(); + if (ex2 instanceof RuntimeException) throw (RuntimeException) ex2; + if (ex2 instanceof Error) throw (Error) ex2; + throw new AssertionError(ex); + } catch (ReflectiveOperationException ex) { + throw new AssertionError(ex); + } + } + + static List limit(int len, List mems) { + if (mems.size() <= len) return mems; + return mems.subList(0, len); + } + @SafeVarargs + static List union(List mems, List... mem2s) { + for (List mem2 : mem2s) { + for (Member m : mem2) { + if (!mems.contains(m)) + mems.add(m); + } + } + return mems; + } + static List callerSensitive(boolean cond, List members) { + for (Iterator i = members.iterator(); i.hasNext(); ) { + Member mem = i.next(); + if (isCallerSensitive(mem) != cond) + i.remove(); + } + if (members.isEmpty()) throw new AssertionError("trivial result"); + return members; + } + static boolean isCallerSensitive(Member mem) { + if (!(mem instanceof AnnotatedElement)) return false; + AnnotatedElement ae = (AnnotatedElement) mem; + if (CS_CLASS != null) + return ae.isAnnotationPresent(sun.reflect.CallerSensitive.class); + for (java.lang.annotation.Annotation a : ae.getDeclaredAnnotations()) { + if (a.toString().contains(".CallerSensitive")) + return true; + } + return false; + } + static final Class CS_CLASS; + static { + Class c = null; + try { + c = sun.reflect.CallerSensitive.class; + } catch (SecurityException | LinkageError ex) { + } + CS_CLASS = c; + } + static List publicOnly(List members) { + return removeMods(members, Modifier.PUBLIC, 0); + } + static List nonPublicOnly(List members) { + return removeMods(members, Modifier.PUBLIC, -1); + } + static List removeMods(List members, int mask, int bits) { + int publicMods = (mask & Modifier.PUBLIC); + members = new ArrayList<>(members); + for (Iterator i = members.iterator(); i.hasNext(); ) { + Member mem = i.next(); + int mods = mem.getModifiers(); + if ((publicMods & mods) != 0 && + (publicMods & mem.getDeclaringClass().getModifiers()) == 0) + mods -= publicMods; + if ((mods & mask) == (bits & mask)) + i.remove(); + } + return members; + } + + void testOnMembers(String tname, List mems, Lookup lookup, Lookup... lookups) throws Throwable { + if (VERBOSE) System.out.println("testOnMembers "+mems); + Lookup revLookup = (lookups.length > 0) ? lookups[0] : null; + if (revLookup == null) revLookup = lookup; + Lookup refLookup = (lookups.length > 1) ? lookups[1] : null; + if (refLookup == null) refLookup = lookup; + assert(lookups.length <= 2); + testOnMembersImpl(tname, mems, lookup, revLookup, refLookup, NO_FAIL); + } + void testOnMembersNoLookup(String tname, List mems, Lookup lookup) throws Throwable { + if (VERBOSE) System.out.println("testOnMembersNoLookup "+mems); + testOnMembersImpl(tname, mems, lookup, null, null, FAIL_LOOKUP); + } + void testOnMembersNoReveal(String tname, List mems, + Lookup lookup, Lookup negLookup) throws Throwable { + if (VERBOSE) System.out.println("testOnMembersNoReveal "+mems); + testOnMembersImpl(tname, mems, lookup, negLookup, null, FAIL_REVEAL); + } + void testOnMembersNoReflect(String tname, List mems, + Lookup lookup, Lookup negLookup) throws Throwable { + if (VERBOSE) System.out.println("testOnMembersNoReflect "+mems); + testOnMembersImpl(tname, mems, lookup, lookup, negLookup, FAIL_REFLECT); + } + void testOnMembersImpl(String tname, List mems, + Lookup lookup, + Lookup revLookup, + Lookup refLookup, + int failureMode) throws Throwable { + Throwable fail = null; + int failCount = 0; + failureModeCounts = new int[FAIL_MODE_COUNT]; + long tm0 = System.currentTimeMillis(); + for (Member mem : mems) { + try { + testWithMember(mem, lookup, revLookup, refLookup, failureMode); + } catch (Throwable ex) { + if (fail == null) fail = ex; + if (++failCount > 10) { System.out.println("*** FAIL: too many failures"); break; } + System.out.println("*** FAIL: "+mem+" => "+ex); + if (VERBOSE) ex.printStackTrace(System.out); + } + } + long tm1 = System.currentTimeMillis(); + System.out.printf("@Test %s executed %s tests in %d ms", + tname, testKinds(failureModeCounts), (tm1-tm0)).println(); + if (fail != null) throw fail; + } + static String testKinds(int[] modes) { + int pos = modes[0], neg = -pos; + for (int n : modes) neg += n; + if (neg == 0) return pos + " positive"; + String negs = ""; + for (int n : modes) negs += "/"+n; + negs = negs.replaceFirst("/"+pos+"/", ""); + negs += " negative"; + if (pos == 0) return negs; + return pos + " positive, " + negs; + } + static class SignaturePolymorphicMethod implements Member { // non-reflected instance of MH.invoke* + final String name; + final MethodType type; + SignaturePolymorphicMethod(String name, MethodType type) { + this.name = name; + this.type = type; + } + public String toString() { + String typeStr = type.toString(); + if (isVarArgs()) typeStr = typeStr.replaceFirst("\\[\\])$", "...)"); + return (Modifier.toString(getModifiers()) + +typeStr.substring(0, typeStr.indexOf('('))+" " + +getDeclaringClass().getTypeName()+"." + +getName()+typeStr.substring(typeStr.indexOf('('))); + } + public boolean equals(Object x) { + return (x instanceof SignaturePolymorphicMethod && equals((SignaturePolymorphicMethod)x)); + } + public boolean equals(SignaturePolymorphicMethod that) { + return this.name.equals(that.name) && this.type.equals(that.type); + } + public int hashCode() { + return name.hashCode() * 31 + type.hashCode(); + } + public Class getDeclaringClass() { return MethodHandle.class; } + public String getName() { return name; } + public MethodType getMethodType() { return type; } + public int getModifiers() { return Modifier.PUBLIC | Modifier.FINAL | Modifier.NATIVE | SYNTHETIC; } + public boolean isVarArgs() { return Modifier.isTransient(getModifiers()); } + public boolean isSynthetic() { return true; } + public Class getReturnType() { return type.returnType(); } + public Class[] getParameterTypes() { return type.parameterArray(); } + static final int SYNTHETIC = 0x00001000; + } + static class UnreflectResult { // a tuple + final MethodHandle mh; + final Throwable ex; + final byte kind; + final Member mem; + final int var; + UnreflectResult(MethodHandle mh, byte kind, Member mem, int var) { + this.mh = mh; + this.ex = null; + this.kind = kind; + this.mem = mem; + this.var = var; + } + UnreflectResult(Throwable ex, byte kind, Member mem, int var) { + this.mh = null; + this.ex = ex; + this.kind = kind; + this.mem = mem; + this.var = var; + } + public String toString() { + return toInfoString()+"/v"+var; + } + public String toInfoString() { + return String.format("%s %s.%s:%s", MethodHandleInfo.referenceKindToString(kind), + mem.getDeclaringClass().getName(), name(mem), type(mem, kind)); + } + static String name(Member mem) { + if (mem instanceof Constructor) return ""; + return mem.getName(); + } + static MethodType type(Member mem, byte kind) { + if (mem instanceof Field) { + Class type = ((Field)mem).getType(); + if (kind == REF_putStatic || kind == REF_putField) + return methodType(void.class, type); + return methodType(type); + } else if (mem instanceof SignaturePolymorphicMethod) { + return ((SignaturePolymorphicMethod)mem).getMethodType(); + } + Class[] params = ((Executable)mem).getParameterTypes(); + if (mem instanceof Constructor) + return methodType(void.class, params); + Class type = ((Method)mem).getReturnType(); + return methodType(type, params); + } + } + static UnreflectResult unreflectMember(Lookup lookup, Member mem, int variation) { + byte[] refKind = {0}; + try { + return unreflectMemberOrThrow(lookup, mem, variation, refKind); + } catch (ReflectiveOperationException|SecurityException ex) { + return new UnreflectResult(ex, refKind[0], mem, variation); + } + } + static UnreflectResult unreflectMemberOrThrow(Lookup lookup, Member mem, int variation, + byte[] refKind) throws ReflectiveOperationException { + Class cls = lookup.lookupClass(); + Class defc = mem.getDeclaringClass(); + String name = mem.getName(); + int mods = mem.getModifiers(); + boolean isStatic = Modifier.isStatic(mods); + MethodHandle mh = null; + byte kind = 0; + if (mem instanceof Method) { + Method m = (Method) mem; + MethodType type = methodType(m.getReturnType(), m.getParameterTypes()); + boolean canBeSpecial = (!isStatic && + (lookup.lookupModes() & Modifier.PRIVATE) != 0 && + defc.isAssignableFrom(cls) && + (!defc.isInterface() || Arrays.asList(cls.getInterfaces()).contains(defc))); + if (variation >= 2) + kind = REF_invokeSpecial; + else if (isStatic) + kind = REF_invokeStatic; + else if (defc.isInterface()) + kind = REF_invokeInterface; + else + kind = REF_invokeVirtual; + refKind[0] = kind; + switch (variation) { + case 0: + mh = lookup.unreflect(m); + break; + case 1: + if (defc == MethodHandle.class && + !isStatic && + m.isVarArgs() && + Modifier.isFinal(mods) && + Modifier.isNative(mods)) { + break; + } + if (isStatic) + mh = lookup.findStatic(defc, name, type); + else + mh = lookup.findVirtual(defc, name, type); + break; + case 2: + if (!canBeSpecial) + break; + mh = lookup.unreflectSpecial(m, lookup.lookupClass()); + break; + case 3: + if (!canBeSpecial) + break; + mh = lookup.findSpecial(defc, name, type, lookup.lookupClass()); + break; + } + } else if (mem instanceof SignaturePolymorphicMethod) { + SignaturePolymorphicMethod m = (SignaturePolymorphicMethod) mem; + MethodType type = methodType(m.getReturnType(), m.getParameterTypes()); + kind = REF_invokeVirtual; + refKind[0] = kind; + switch (variation) { + case 0: + mh = lookup.findVirtual(defc, name, type); + break; + } + } else if (mem instanceof Constructor) { + name = ""; // not used + Constructor m = (Constructor) mem; + MethodType type = methodType(void.class, m.getParameterTypes()); + kind = REF_newInvokeSpecial; + refKind[0] = kind; + switch (variation) { + case 0: + mh = lookup.unreflectConstructor(m); + break; + case 1: + mh = lookup.findConstructor(defc, type); + break; + } + } else if (mem instanceof Field) { + Field m = (Field) mem; + Class type = m.getType(); + boolean canHaveSetter = !Modifier.isFinal(mods); + if (variation >= 2) + kind = (byte)(isStatic ? REF_putStatic : REF_putField); + else + kind = (byte)(isStatic ? REF_getStatic : REF_getField); + refKind[0] = kind; + switch (variation) { + case 0: + mh = lookup.unreflectGetter(m); + break; + case 1: + if (isStatic) + mh = lookup.findStaticGetter(defc, name, type); + else + mh = lookup.findGetter(defc, name, type); + break; + case 3: + if (!canHaveSetter) + break; + mh = lookup.unreflectSetter(m); + break; + case 2: + if (!canHaveSetter) + break; + if (isStatic) + mh = lookup.findStaticSetter(defc, name, type); + else + mh = lookup.findSetter(defc, name, type); + break; + } + } else { + throw new IllegalArgumentException(String.valueOf(mem)); + } + if (mh == null) + // ran out of valid variations; return null to caller + return null; + return new UnreflectResult(mh, kind, mem, variation); + } + static boolean canBeReached(Member mem, Class cls) { + Class defc = mem.getDeclaringClass(); + String name = mem.getName(); + int mods = mem.getModifiers(); + if (mem instanceof Constructor) { + name = ""; // according to 292 spec. + } + if (defc == cls) + return true; + if (name.startsWith("<")) + return false; // only my own constructors + if (Modifier.isPrivate(mods)) + return false; // only my own constructors + if (defc.getPackage() == cls.getPackage()) + return true; // package access or greater OK + if (Modifier.isPublic(mods)) + return true; // publics always OK + if (Modifier.isProtected(mods) && defc.isAssignableFrom(cls)) + return true; // protected OK + return false; + } + static boolean consistent(UnreflectResult res, MethodHandleInfo info) { + assert(res.mh != null); + assertEquals(res.kind, info.getReferenceKind()); + assertEquals(res.mem.getModifiers(), info.getModifiers()); + assertEquals(res.mem.getDeclaringClass(), info.getDeclaringClass()); + String expectName = res.mem.getName(); + if (res.kind == REF_newInvokeSpecial) + expectName = ""; + assertEquals(expectName, info.getName()); + MethodType expectType = res.mh.type(); + if ((res.kind & 1) == (REF_getField & 1)) + expectType = expectType.dropParameterTypes(0, 1); + if (res.kind == REF_newInvokeSpecial) + expectType = expectType.changeReturnType(void.class); + assertEquals(expectType, info.getMethodType()); + assertEquals(res.mh.isVarargsCollector(), isVarArgs(info)); + assertEquals(res.toInfoString(), info.toString()); + assertEquals(res.toInfoString(), MethodHandleInfo.toString(info.getReferenceKind(), info.getDeclaringClass(), info.getName(), info.getMethodType())); + return true; + } + static boolean isVarArgs(MethodHandleInfo info) { + return info.isVarArgs(); + } + static boolean consistent(Member mem, Member mem2) { + assertEquals(mem, mem2); + return true; + } + static boolean consistent(MethodHandleInfo info, MethodHandleInfo info2) { + assertEquals(info.getReferenceKind(), info2.getReferenceKind()); + assertEquals(info.getModifiers(), info2.getModifiers()); + assertEquals(info.getDeclaringClass(), info2.getDeclaringClass()); + assertEquals(info.getName(), info2.getName()); + assertEquals(info.getMethodType(), info2.getMethodType()); + assertEquals(isVarArgs(info), isVarArgs(info)); + return true; + } + static boolean consistent(MethodHandle mh, MethodHandle mh2) { + assertEquals(mh.type(), mh2.type()); + assertEquals(mh.isVarargsCollector(), mh2.isVarargsCollector()); + return true; + } + int[] failureModeCounts; + static final int NO_FAIL=0, FAIL_LOOKUP=1, FAIL_REVEAL=2, FAIL_REFLECT=3, FAIL_MODE_COUNT=4; + void testWithMember(Member mem, + Lookup lookup, // initial lookup of member => MH + Lookup revLookup, // reveal MH => info + Lookup refLookup, // reflect info => member + int failureMode) throws Throwable { + boolean expectEx1 = (failureMode == FAIL_LOOKUP); // testOnMembersNoLookup + boolean expectEx2 = (failureMode == FAIL_REVEAL); // testOnMembersNoReveal + boolean expectEx3 = (failureMode == FAIL_REFLECT); // testOnMembersNoReflect + for (int variation = 0; ; variation++) { + UnreflectResult res = unreflectMember(lookup, mem, variation); + failureModeCounts[failureMode] += 1; + if (variation == 0) assert(res != null); + if (res == null) break; + if (VERBOSE && variation == 0) + System.out.println("from "+mem.getDeclaringClass().getSimpleName()); + MethodHandle mh = res.mh; + Throwable ex1 = res.ex; + if (VERBOSE) System.out.println(" "+variation+": "+res+" << "+(mh != null ? mh : ex1)); + if (expectEx1 && ex1 != null) + continue; // this is OK; we expected that lookup to fail + if (expectEx1) + throw new AssertionError("unexpected lookup for negative test"); + if (ex1 != null && !expectEx1) { + if (failureMode != NO_FAIL) + throw new AssertionError("unexpected lookup failure for negative test", ex1); + throw ex1; + } + MethodHandleInfo info; + try { + info = revLookup.revealDirect(mh); + if (expectEx2) throw new AssertionError("unexpected revelation for negative test"); + } catch (Throwable ex2) { + if (VERBOSE) System.out.println(" "+variation+": "+res+" => "+mh.getClass().getName()+" => (EX2)"+ex2); + if (expectEx2) + continue; // this is OK; we expected the reflect to fail + if (failureMode != NO_FAIL) + throw new AssertionError("unexpected revelation failure for negative test", ex2); + throw ex2; + } + assert(consistent(res, info)); + Member mem2; + try { + mem2 = info.reflectAs(Member.class, refLookup); + if (expectEx3) throw new AssertionError("unexpected reflection for negative test"); + assert(!(mem instanceof SignaturePolymorphicMethod)); + } catch (IllegalArgumentException ex3) { + if (VERBOSE) System.out.println(" "+variation+": "+info+" => (EX3)"+ex3); + if (expectEx3) + continue; // this is OK; we expected the reflect to fail + if (mem instanceof SignaturePolymorphicMethod) + continue; // this is OK; we cannot reflect MH.invokeExact(a,b,c) + if (failureMode != NO_FAIL) + throw new AssertionError("unexpected reflection failure for negative test", ex3); + throw ex3; + } + assert(consistent(mem, mem2)); + UnreflectResult res2 = unreflectMember(lookup, mem2, variation); + MethodHandle mh2 = res2.mh; + assert(consistent(mh, mh2)); + MethodHandleInfo info2 = lookup.revealDirect(mh2); + assert(consistent(info, info2)); + assert(consistent(res, info2)); + Member mem3; + if (hasSM()) + mem3 = info2.reflectAs(Member.class, lookup); + else + mem3 = MethodHandles.reflectAs(Member.class, mh2); + assert(consistent(mem2, mem3)); + if (hasSM()) { + try { + MethodHandles.reflectAs(Member.class, mh2); + throw new AssertionError("failed to throw on "+mem3); + } catch (SecurityException ex3) { + // OK... + } + } + } + } +} diff --git a/jdk/test/java/lang/invoke/jtreg.security.policy b/jdk/test/java/lang/invoke/jtreg.security.policy new file mode 100644 index 00000000000..d32c7af9b3f --- /dev/null +++ b/jdk/test/java/lang/invoke/jtreg.security.policy @@ -0,0 +1,9 @@ +/* + * security policy used by the test process + * must allow file reads so that jtreg itself can run + */ + +grant { + // standard test activation permissions + permission java.io.FilePermission "*", "read"; +}; From 1f2ba9f2286e0de55a160f5d15a9db64e7024f06 Mon Sep 17 00:00:00 2001 From: Paul Sandoz Date: Mon, 12 Aug 2013 12:22:10 +0200 Subject: [PATCH 035/218] 8024182: test/java/util/Arrays/SetAllTest.java fails to compile due to recent compiler changes Use explicit lambda due to javac simplfying rules for overload resolution with implicit lambdas Reviewed-by: alanb, mduigou --- jdk/test/java/util/Arrays/SetAllTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jdk/test/java/util/Arrays/SetAllTest.java b/jdk/test/java/util/Arrays/SetAllTest.java index 2388a7bfd55..528d3c57b54 100644 --- a/jdk/test/java/util/Arrays/SetAllTest.java +++ b/jdk/test/java/util/Arrays/SetAllTest.java @@ -167,13 +167,13 @@ public class SetAllTest { public void testStringSetNulls() { String[] ar = new String[2]; try { - Arrays.setAll(null, i -> "X"); + Arrays.setAll(null, (IntFunction) i -> "X"); fail("Arrays.setAll(null, foo) should throw NPE"); } catch (NullPointerException npe) { // expected } try { - Arrays.parallelSetAll(null, i -> "X"); + Arrays.parallelSetAll(null, (IntFunction) i -> "X"); fail("Arrays.parallelSetAll(null, foo) should throw NPE"); } catch (NullPointerException npe) { // expected From 71bd48d8e790d0c86728eb808a4a9c7dd5e8b318 Mon Sep 17 00:00:00 2001 From: Attila Szegedi Date: Mon, 12 Aug 2013 12:46:01 +0200 Subject: [PATCH 036/218] 8022789: Revisit doPrivileged blocks in Dynalink Reviewed-by: lagergren, sundar --- .../dynalink/DynamicLinkerFactory.java | 3 +- .../ClassLoaderGetterContextProvider.java | 107 ++++++++++++++++++ .../internal/dynalink/support/ClassMap.java | 2 +- .../support/TypeConverterFactory.java | 2 +- 4 files changed, 111 insertions(+), 3 deletions(-) create mode 100644 nashorn/src/jdk/internal/dynalink/support/ClassLoaderGetterContextProvider.java diff --git a/nashorn/src/jdk/internal/dynalink/DynamicLinkerFactory.java b/nashorn/src/jdk/internal/dynalink/DynamicLinkerFactory.java index 3cd052003b2..72fbebe33be 100644 --- a/nashorn/src/jdk/internal/dynalink/DynamicLinkerFactory.java +++ b/nashorn/src/jdk/internal/dynalink/DynamicLinkerFactory.java @@ -99,6 +99,7 @@ import jdk.internal.dynalink.linker.GuardingTypeConverterFactory; import jdk.internal.dynalink.linker.LinkRequest; import jdk.internal.dynalink.support.AutoDiscovery; import jdk.internal.dynalink.support.BottomGuardingDynamicLinker; +import jdk.internal.dynalink.support.ClassLoaderGetterContextProvider; import jdk.internal.dynalink.support.CompositeGuardingDynamicLinker; import jdk.internal.dynalink.support.CompositeTypeBasedGuardingDynamicLinker; import jdk.internal.dynalink.support.LinkerServicesImpl; @@ -315,7 +316,7 @@ public class DynamicLinkerFactory { public ClassLoader run() { return Thread.currentThread().getContextClassLoader(); } - }); + }, ClassLoaderGetterContextProvider.GET_CLASS_LOADER_CONTEXT); } private static void addClasses(Set> knownLinkerClasses, diff --git a/nashorn/src/jdk/internal/dynalink/support/ClassLoaderGetterContextProvider.java b/nashorn/src/jdk/internal/dynalink/support/ClassLoaderGetterContextProvider.java new file mode 100644 index 00000000000..f9470215409 --- /dev/null +++ b/nashorn/src/jdk/internal/dynalink/support/ClassLoaderGetterContextProvider.java @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2010, 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. + */ + +/* + * 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, and Oracle licenses the original version of this file under the BSD + * license: + */ +/* + Copyright 2009-2013 Attila Szegedi + + Licensed under both the Apache License, Version 2.0 (the "Apache License") + and the BSD License (the "BSD License"), with licensee being free to + choose either of the two at their discretion. + + You may not use this file except in compliance with either the Apache + License or the BSD License. + + If you choose to use this file in compliance with the Apache License, the + following notice applies to you: + + You may obtain a copy of the Apache License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied. See the License for the specific language governing + permissions and limitations under the License. + + If you choose to use this file in compliance with the BSD License, the + following notice applies to you: + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the copyright holder nor the names of + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER + BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +package jdk.internal.dynalink.support; + +import java.security.AccessControlContext; +import java.security.Permissions; +import java.security.ProtectionDomain; + +/** + * This class exposes a canonical {@link AccessControlContext} with a single {@link RuntimePermission} for + * {@code "getClassLoader"} permission that is used by other parts of the code to narrow their set of permissions when + * they're retrieving class loaders in privileged blocks. + */ +public class ClassLoaderGetterContextProvider { + /** + * Canonical instance of {@link AccessControlContext} with a single {@link RuntimePermission} for + * {@code "getClassLoader"} permission. + */ + public static final AccessControlContext GET_CLASS_LOADER_CONTEXT; + static { + final Permissions perms = new Permissions(); + perms.add(new RuntimePermission("getClassLoader")); + GET_CLASS_LOADER_CONTEXT = new AccessControlContext( + new ProtectionDomain[] { new ProtectionDomain(null, perms) }); + } +} diff --git a/nashorn/src/jdk/internal/dynalink/support/ClassMap.java b/nashorn/src/jdk/internal/dynalink/support/ClassMap.java index cf52d2e51c4..d85b21d0033 100644 --- a/nashorn/src/jdk/internal/dynalink/support/ClassMap.java +++ b/nashorn/src/jdk/internal/dynalink/support/ClassMap.java @@ -155,7 +155,7 @@ public abstract class ClassMap { public ClassLoader run() { return clazz.getClassLoader(); } - }); + }, ClassLoaderGetterContextProvider.GET_CLASS_LOADER_CONTEXT); // If allowed to strongly reference, put it in the fast map if(Guards.canReferenceDirectly(classLoader, clazzLoader)) { diff --git a/nashorn/src/jdk/internal/dynalink/support/TypeConverterFactory.java b/nashorn/src/jdk/internal/dynalink/support/TypeConverterFactory.java index 245afc126e9..5ab541f33f9 100644 --- a/nashorn/src/jdk/internal/dynalink/support/TypeConverterFactory.java +++ b/nashorn/src/jdk/internal/dynalink/support/TypeConverterFactory.java @@ -151,7 +151,7 @@ public class TypeConverterFactory { public ClassLoader run() { return clazz.getClassLoader(); } - }); + }, ClassLoaderGetterContextProvider.GET_CLASS_LOADER_CONTEXT); } /** From 42d8f2818115201e38144b4909343337f86d6cf1 Mon Sep 17 00:00:00 2001 From: Athijegannathan Sundararajan Date: Mon, 12 Aug 2013 16:52:32 +0530 Subject: [PATCH 037/218] 8022614: Please exclude test test/script/trusted/JDK-8020809.js from Nashorn code coverage run Reviewed-by: jlaskey, lagergren --- nashorn/exclude/exclude_list_cc.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/nashorn/exclude/exclude_list_cc.txt b/nashorn/exclude/exclude_list_cc.txt index a66476b8e16..79b6303eb16 100644 --- a/nashorn/exclude/exclude_list_cc.txt +++ b/nashorn/exclude/exclude_list_cc.txt @@ -3,4 +3,5 @@ + From 76e9329e16bb22d1b663a6eb4b8bd8d0bdd292d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hannes=20Walln=C3=B6fer?= Date: Mon, 12 Aug 2013 13:31:43 +0200 Subject: [PATCH 038/218] 8022731: NativeArguments has wrong implementation of isMapped() Reviewed-by: lagergren, jlaskey --- .../internal/objects/NativeArguments.java | 452 ++++-------------- nashorn/test/script/basic/JDK-8022731.js | 93 ++++ .../test/script/basic/JDK-8022731.js.EXPECTED | 16 + 3 files changed, 189 insertions(+), 372 deletions(-) create mode 100644 nashorn/test/script/basic/JDK-8022731.js create mode 100644 nashorn/test/script/basic/JDK-8022731.js.EXPECTED diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeArguments.java b/nashorn/src/jdk/nashorn/internal/objects/NativeArguments.java index 3bd74d523d8..55c79da94d0 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeArguments.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeArguments.java @@ -76,36 +76,21 @@ public final class NativeArguments extends ScriptObject { private Object length; private Object callee; - private ArrayData namedArgs; - // This is lazily initialized - only when delete is invoked at all + private final int numMapped; + private final int numParams; + + // These are lazily initialized when delete is invoked on a mapped arg or an unmapped argument is set. + private ArrayData unmappedArgs; private BitSet deleted; NativeArguments(final Object[] arguments, final Object callee, final int numParams, final ScriptObject proto, final PropertyMap map) { super(proto, map); setIsArguments(); - setArray(ArrayData.allocate(arguments)); this.length = arguments.length; this.callee = callee; - - /** - * Declared number of parameters may be more or less than the actual passed - * runtime arguments count. We need to truncate or extend with undefined values. - * - * Example: - * - * // less declared params - * (function (x) { print(arguments); })(20, 44); - * - * // more declared params - * (function (x, y) { print(arguments); })(3); - */ - final Object[] newValues = new Object[numParams]; - if (numParams > arguments.length) { - Arrays.fill(newValues, UNDEFINED); - } - System.arraycopy(arguments, 0, newValues, 0, Math.min(newValues.length, arguments.length)); - this.namedArgs = ArrayData.allocate(newValues); + this.numMapped = Math.min(numParams, arguments.length); + this.numParams = numParams; } @Override @@ -118,7 +103,8 @@ public final class NativeArguments extends ScriptObject { */ @Override public Object getArgument(final int key) { - return namedArgs.has(key) ? namedArgs.getObject(key) : UNDEFINED; + assert key >= 0 && key < numParams : "invalid argument index"; + return isMapped(key) ? getArray().getObject(key) : getUnmappedArg(key); } /** @@ -126,353 +112,36 @@ public final class NativeArguments extends ScriptObject { */ @Override public void setArgument(final int key, final Object value) { - if (namedArgs.has(key)) { - namedArgs = namedArgs.set(key, value, false); - } - } - - @Override - public int getInt(final Object key) { - final int index = ArrayIndex.getArrayIndex(key); - return isMapped(index) ? namedArgs.getInt(index) : super.getInt(key); - } - - @Override - public int getInt(final double key) { - final int index = ArrayIndex.getArrayIndex(key); - return isMapped(index) ? namedArgs.getInt(index) : super.getInt(key); - } - - @Override - public int getInt(final long key) { - final int index = ArrayIndex.getArrayIndex(key); - return isMapped(index) ? namedArgs.getInt(index) : super.getInt(key); - } - - @Override - public int getInt(final int key) { - final int index = ArrayIndex.getArrayIndex(key); - return isMapped(index) ? namedArgs.getInt(index) : super.getInt(key); - } - - @Override - public long getLong(final Object key) { - final int index = ArrayIndex.getArrayIndex(key); - return isMapped(index) ? namedArgs.getLong(index) : super.getLong(key); - } - - @Override - public long getLong(final double key) { - final int index = ArrayIndex.getArrayIndex(key); - return isMapped(index) ? namedArgs.getLong(index) : super.getLong(key); - } - - @Override - public long getLong(final long key) { - final int index = ArrayIndex.getArrayIndex(key); - return isMapped(index) ? namedArgs.getLong(index) : super.getLong(key); - } - - @Override - public long getLong(final int key) { - final int index = ArrayIndex.getArrayIndex(key); - return isMapped(index) ? namedArgs.getLong(index) : super.getLong(key); - } - - @Override - public double getDouble(final Object key) { - final int index = ArrayIndex.getArrayIndex(key); - return isMapped(index) ? namedArgs.getDouble(index) : super.getDouble(key); - } - - @Override - public double getDouble(final double key) { - final int index = ArrayIndex.getArrayIndex(key); - return isMapped(index) ? namedArgs.getDouble(index) : super.getDouble(key); - } - - @Override - public double getDouble(final long key) { - final int index = ArrayIndex.getArrayIndex(key); - return isMapped(index) ? namedArgs.getDouble(index) : super.getDouble(key); - } - - @Override - public double getDouble(final int key) { - final int index = ArrayIndex.getArrayIndex(key); - return isMapped(index) ? namedArgs.getDouble(index) : super.getDouble(key); - } - - @Override - public Object get(final Object key) { - final int index = ArrayIndex.getArrayIndex(key); - return isMapped(index) ? namedArgs.getObject(index) : super.get(key); - } - - @Override - public Object get(final double key) { - final int index = ArrayIndex.getArrayIndex(key); - return isMapped(index) ? namedArgs.getObject(index) : super.get(key); - } - - @Override - public Object get(final long key) { - final int index = ArrayIndex.getArrayIndex(key); - return isMapped(index) ? namedArgs.getObject(index) : super.get(key); - } - - @Override - public Object get(final int key) { - final int index = ArrayIndex.getArrayIndex(key); - return isMapped(index) ? namedArgs.getObject(index) : super.get(key); - } - - @Override - public void set(final Object key, final int value, final boolean strict) { - final int index = ArrayIndex.getArrayIndex(key); - if (isMapped(index)) { - namedArgs = namedArgs.set(index, value, strict); + assert key >= 0 && key < numParams : "invalid argument index"; + if (isMapped(key)) { + setArray(getArray().set(key, value, false)); } else { - super.set(key, value, strict); + setUnmappedArg(key, value); } } - @Override - public void set(final Object key, final long value, final boolean strict) { - final int index = ArrayIndex.getArrayIndex(key); - if (isMapped(index)) { - namedArgs = namedArgs.set(index, value, strict); - } else { - super.set(key, value, strict); - } - } - - @Override - public void set(final Object key, final double value, final boolean strict) { - final int index = ArrayIndex.getArrayIndex(key); - if (isMapped(index)) { - namedArgs = namedArgs.set(index, value, strict); - } else { - super.set(key, value, strict); - } - } - - @Override - public void set(final Object key, final Object value, final boolean strict) { - final int index = ArrayIndex.getArrayIndex(key); - if (isMapped(index)) { - namedArgs = namedArgs.set(index, value, strict); - } else { - super.set(key, value, strict); - } - } - - @Override - public void set(final double key, final int value, final boolean strict) { - final int index = ArrayIndex.getArrayIndex(key); - if (isMapped(index)) { - namedArgs = namedArgs.set(index, value, strict); - } else { - super.set(key, value, strict); - } - } - - @Override - public void set(final double key, final long value, final boolean strict) { - final int index = ArrayIndex.getArrayIndex(key); - if (isMapped(index)) { - namedArgs = namedArgs.set(index, value, strict); - } else { - super.set(key, value, strict); - } - } - - @Override - public void set(final double key, final double value, final boolean strict) { - final int index = ArrayIndex.getArrayIndex(key); - if (isMapped(index)) { - namedArgs = namedArgs.set(index, value, strict); - } else { - super.set(key, value, strict); - } - } - - @Override - public void set(final double key, final Object value, final boolean strict) { - final int index = ArrayIndex.getArrayIndex(key); - if (isMapped(index)) { - namedArgs = namedArgs.set(index, value, strict); - } else { - super.set(key, value, strict); - } - } - - @Override - public void set(final long key, final int value, final boolean strict) { - final int index = ArrayIndex.getArrayIndex(key); - if (isMapped(index)) { - namedArgs = namedArgs.set(index, value, strict); - } else { - super.set(key, value, strict); - } - } - - @Override - public void set(final long key, final long value, final boolean strict) { - final int index = ArrayIndex.getArrayIndex(key); - if (isMapped(index)) { - namedArgs = namedArgs.set(index, value, strict); - } else { - super.set(key, value, strict); - } - } - - @Override - public void set(final long key, final double value, final boolean strict) { - final int index = ArrayIndex.getArrayIndex(key); - if (isMapped(index)) { - namedArgs = namedArgs.set(index, value, strict); - } else { - super.set(key, value, strict); - } - } - - @Override - public void set(final long key, final Object value, final boolean strict) { - final int index = ArrayIndex.getArrayIndex(key); - if (isMapped(index)) { - namedArgs = namedArgs.set(index, value, strict); - } else { - super.set(key, value, strict); - } - } - - @Override - public void set(final int key, final int value, final boolean strict) { - final int index = ArrayIndex.getArrayIndex(key); - if (isMapped(index)) { - namedArgs = namedArgs.set(index, value, strict); - } else { - super.set(key, value, strict); - } - } - - @Override - public void set(final int key, final long value, final boolean strict) { - final int index = ArrayIndex.getArrayIndex(key); - if (isMapped(index)) { - namedArgs = namedArgs.set(index, value, strict); - } else { - super.set(key, value, strict); - } - } - - @Override - public void set(final int key, final double value, final boolean strict) { - final int index = ArrayIndex.getArrayIndex(key); - if (isMapped(index)) { - namedArgs = namedArgs.set(index, value, strict); - } else { - super.set(key, value, strict); - } - } - - @Override - public void set(final int key, final Object value, final boolean strict) { - final int index = ArrayIndex.getArrayIndex(key); - if (isMapped(index)) { - namedArgs = namedArgs.set(index, value, strict); - } else { - super.set(key, value, strict); - } - } - - @Override - public boolean has(final Object key) { - final int index = ArrayIndex.getArrayIndex(key); - return isMapped(index) || super.has(key); - } - - @Override - public boolean has(final double key) { - final int index = ArrayIndex.getArrayIndex(key); - return isMapped(index) || super.has(key); - } - - @Override - public boolean has(final long key) { - final int index = ArrayIndex.getArrayIndex(key); - return isMapped(index) || super.has(key); - } - - @Override - public boolean has(final int key) { - final int index = ArrayIndex.getArrayIndex(key); - return isMapped(index) || super.has(key); - } - - @Override - public boolean hasOwnProperty(final Object key) { - final int index = ArrayIndex.getArrayIndex(key); - return isMapped(index) || super.hasOwnProperty(key); - } - - @Override - public boolean hasOwnProperty(final int key) { - final int index = ArrayIndex.getArrayIndex(key); - return isMapped(index) || super.hasOwnProperty(key); - } - - @Override - public boolean hasOwnProperty(final long key) { - final int index = ArrayIndex.getArrayIndex(key); - return isMapped(index) || super.hasOwnProperty(key); - } - - @Override - public boolean hasOwnProperty(final double key) { - final int index = ArrayIndex.getArrayIndex(key); - return isMapped(index) || super.hasOwnProperty(key); - } - @Override public boolean delete(final int key, final boolean strict) { final int index = ArrayIndex.getArrayIndex(key); - final boolean success = super.delete(key, strict); - if (success && namedArgs.has(index)) { - setDeleted(index); - } - return success; + return isMapped(index) ? deleteMapped(index, strict) : super.delete(key, strict); } @Override public boolean delete(final long key, final boolean strict) { final int index = ArrayIndex.getArrayIndex(key); - final boolean success = super.delete(key, strict); - if (success && namedArgs.has(index)) { - setDeleted(index); - } - return success; + return isMapped(index) ? deleteMapped(index, strict) : super.delete(key, strict); } @Override public boolean delete(final double key, final boolean strict) { final int index = ArrayIndex.getArrayIndex(key); - final boolean success = super.delete(key, strict); - if (success && namedArgs.has(index)) { - setDeleted(index); - } - return success; + return isMapped(index) ? deleteMapped(index, strict) : super.delete(key, strict); } @Override public boolean delete(final Object key, final boolean strict) { final int index = ArrayIndex.getArrayIndex(key); - final boolean success = super.delete(key, strict); - if (success && namedArgs.has(index)) { - setDeleted(index); - } - return success; + return isMapped(index) ? deleteMapped(index, strict) : super.delete(key, strict); } /** @@ -483,29 +152,27 @@ public final class NativeArguments extends ScriptObject { public boolean defineOwnProperty(final String key, final Object propertyDesc, final boolean reject) { final int index = ArrayIndex.getArrayIndex(key); if (index >= 0) { - final boolean allowed = super.defineOwnProperty(key, propertyDesc, false); - if (!allowed) { + final boolean isMapped = isMapped(index); + final Object oldValue = isMapped ? getArray().getObject(index) : null; + + if (!super.defineOwnProperty(key, propertyDesc, false)) { if (reject) { throw typeError("cant.redefine.property", key, ScriptRuntime.safeToString(this)); } return false; } - if (isMapped(index)) { + if (isMapped) { // When mapped argument is redefined, if new descriptor is accessor property // or data-non-writable property, we have to "unmap" (unlink). final PropertyDescriptor desc = toPropertyDescriptor(Global.instance(), propertyDesc); if (desc.type() == PropertyDescriptor.ACCESSOR) { - setDeleted(index); - } else { - // set "value" from new descriptor to named args - if (desc.has(PropertyDescriptor.VALUE)) { - namedArgs = namedArgs.set(index, desc.getValue(), false); - } - - if (desc.has(PropertyDescriptor.WRITABLE) && !desc.isWritable()) { - setDeleted(index); - } + setDeleted(index, oldValue); + } else if (desc.has(PropertyDescriptor.WRITABLE) && !desc.isWritable()) { + // delete and set value from new descriptor if it has one, otherwise use old value + setDeleted(index, desc.has(PropertyDescriptor.VALUE) ? desc.getValue() : oldValue); + } else if (desc.has(PropertyDescriptor.VALUE)) { + setArray(getArray().set(index, desc.getValue(), false)); } } @@ -519,31 +186,72 @@ public final class NativeArguments extends ScriptObject { // We track deletions using a bit set (delete arguments[index]) private boolean isDeleted(final int index) { - return (deleted != null) ? deleted.get(index) : false; + return deleted != null && deleted.get(index); } - private void setDeleted(final int index) { + private void setDeleted(final int index, final Object unmappedValue) { if (deleted == null) { - deleted = new BitSet((int)namedArgs.length()); + deleted = new BitSet(numMapped); } deleted.set(index, true); + setUnmappedArg(index, unmappedValue); + } + + private boolean deleteMapped(final int index, final boolean strict) { + final Object value = getArray().getObject(index); + final boolean success = super.delete(index, strict); + if (success) { + setDeleted(index, value); + } + return success; + } + + private Object getUnmappedArg(final int key) { + assert key >= 0 && key < numParams; + return unmappedArgs == null ? UNDEFINED : unmappedArgs.getObject(key); + } + + private void setUnmappedArg(final int key, final Object value) { + assert key >= 0 && key < numParams; + if (unmappedArgs == null) { + /* + * Declared number of parameters may be more or less than the actual passed + * runtime arguments count. We need to truncate or extend with undefined values. + * + * Example: + * + * // less declared params + * (function (x) { print(arguments); })(20, 44); + * + * // more declared params + * (function (x, y) { print(arguments); })(3); + */ + final Object[] newValues = new Object[numParams]; + System.arraycopy(getArray().asObjectArray(), 0, newValues, 0, numMapped); + if (numMapped < numParams) { + Arrays.fill(newValues, numMapped, numParams, UNDEFINED); + } + this.unmappedArgs = ArrayData.allocate(newValues); + } + // Set value of argument + unmappedArgs = unmappedArgs.set(key, value, false); } /** * Are arguments[index] and corresponding named parameter linked? * - * In non-strict mode, arguments[index] and corresponding named param - * are "linked" or "mapped". Modifications are tacked b/w each other - till - * (delete arguments[index]) is used. Once deleted, the corresponding arg - * is no longer 'mapped'. Please note that delete can happen only through - * the arguments array - named param can not be deleted. (delete is one-way). + * In non-strict mode, arguments[index] and corresponding named param are "linked" or "mapped" + * if the argument is provided by the caller. Modifications are tacked b/w each other - until + * (delete arguments[index]) is used. Once deleted, the corresponding arg is no longer 'mapped'. + * Please note that delete can happen only through the arguments array - named param can not + * be deleted. (delete is one-way). */ private boolean isMapped(final int index) { - // in named args and not marked as "deleted" - return namedArgs.has(index) && !isDeleted(index); + // in mapped named args and not marked as "deleted" + return index >= 0 && index < numMapped && !isDeleted(index); } - /** + /** * Factory to create correct Arguments object based on strict mode. * * @param arguments the actual arguments array passed diff --git a/nashorn/test/script/basic/JDK-8022731.js b/nashorn/test/script/basic/JDK-8022731.js new file mode 100644 index 00000000000..635bd2d87ac --- /dev/null +++ b/nashorn/test/script/basic/JDK-8022731.js @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * JDK-8022731: NativeArguments has wrong implementation of isMapped() + * + * @test + * @run + */ + +Object.defineProperty(Object.prototype, "0", {value: "proto"}); + +function test0(a, b) { + Object.defineProperty(arguments, "1", {get: function() { return "get" }}); + return arguments[0]; +} + +function test1(a, b) { + Object.defineProperty(arguments, "0", {get: function() { return "get" }}); + return a; +} + +function test2(a, b) { + Object.defineProperty(arguments, "0", {value: "value"}); + delete arguments[0]; + return a; +} + +function test3(a, b) { + arguments[1] = "arg1"; + return b; +} + +function test4(a, b) { + b = "b"; + return arguments[1]; +} + +function test5(a, b) { + Object.defineProperty(arguments, "0", {value: "value"}); + arguments[0] = "new"; + return a; +} + +function test6(a, b) { + Object.defineProperty(arguments, "0", {value: "value"}); + arguments[0] = "new"; + delete arguments[0]; + return a; +} + +function test7(a, b) { + Object.defineProperty(arguments, "0", {value: "value", writable: false}); + arguments[0] = "new"; + return a; +} + +print(test0()); +print(test0("p1", "p2")); +print(test1()); +print(test1("p1")); +print(test2()); +print(test2("p1")); +print(test3()); +print(test3(1, 2)); +print(test4()); +print(test4("p1", "p2")); +print(test5()); +print(test5("p1")); +print(test6()); +print(test6("p1")); +print(test7()); +print(test7("p1")); diff --git a/nashorn/test/script/basic/JDK-8022731.js.EXPECTED b/nashorn/test/script/basic/JDK-8022731.js.EXPECTED new file mode 100644 index 00000000000..32d613095eb --- /dev/null +++ b/nashorn/test/script/basic/JDK-8022731.js.EXPECTED @@ -0,0 +1,16 @@ +proto +p1 +undefined +p1 +undefined +value +undefined +arg1 +undefined +b +undefined +new +undefined +new +undefined +value From cb2ec81051035dd0ad9276f1e766b8aa7c625ede Mon Sep 17 00:00:00 2001 From: Athijegannathan Sundararajan Date: Mon, 12 Aug 2013 17:08:01 +0530 Subject: [PATCH 039/218] 8022615: [nightly] Two nashorn print tests fail in nightly builds on Windows Reviewed-by: lagergren, jlaskey --- .../src/jdk/nashorn/api/scripting/ScriptEngineTest.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/nashorn/test/src/jdk/nashorn/api/scripting/ScriptEngineTest.java b/nashorn/test/src/jdk/nashorn/api/scripting/ScriptEngineTest.java index 53ca43a6f32..fe4bf39ba45 100644 --- a/nashorn/test/src/jdk/nashorn/api/scripting/ScriptEngineTest.java +++ b/nashorn/test/src/jdk/nashorn/api/scripting/ScriptEngineTest.java @@ -1235,7 +1235,8 @@ public class ScriptEngineTest { fail(t.getMessage()); } - assertEquals(sw.toString(), "hello\n"); + // dos2unix - fix line endings if running on windows + assertEquals(sw.toString().replaceAll("\r", ""), "hello\n"); } @Test @@ -1252,6 +1253,7 @@ public class ScriptEngineTest { fail(t.getMessage()); } - assertEquals(sw.toString(), "34 true hello\n"); + // dos2unix - fix line endings if running on windows + assertEquals(sw.toString().replaceAll("\r", ""), "34 true hello\n"); } } From 7e85e9c196a1de46b8603ff2eeeb8de38a71d85e Mon Sep 17 00:00:00 2001 From: Athijegannathan Sundararajan Date: Mon, 12 Aug 2013 18:16:28 +0530 Subject: [PATCH 040/218] 8022598: Object.getPrototypeOf should return null for host objects rather than throwing TypeError Reviewed-by: lagergren, jlaskey, attila, hannesw --- .../internal/objects/NativeObject.java | 7 +++ nashorn/test/script/basic/JDK-8022598.js | 56 +++++++++++++++++++ 2 files changed, 63 insertions(+) create mode 100644 nashorn/test/script/basic/JDK-8022598.js diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeObject.java b/nashorn/src/jdk/nashorn/internal/objects/NativeObject.java index ff72ce5cd97..537ae1ffcc5 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeObject.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeObject.java @@ -113,6 +113,13 @@ public final class NativeObject { } else if (obj instanceof ScriptObjectMirror) { return ((ScriptObjectMirror)obj).getProto(); } else { + final JSType type = JSType.of(obj); + if (type == JSType.OBJECT) { + // host (Java) objects have null __proto__ + return null; + } + + // must be some JS primitive throw notAnObject(obj); } } diff --git a/nashorn/test/script/basic/JDK-8022598.js b/nashorn/test/script/basic/JDK-8022598.js new file mode 100644 index 00000000000..95f2ab49365 --- /dev/null +++ b/nashorn/test/script/basic/JDK-8022598.js @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * JDK-8022598: Object.getPrototypeOf should return null for host objects rather than throwing TypeError + * + * @test + * @run + */ + +// the following should not throw TypeError, just return null instead + +var proto = Object.getPrototypeOf(new java.lang.Object()); +if (proto !== null) { + fail("Expected 'null' __proto__ for host objects"); +} + +// on primitive should result in TypeError + +function checkTypeError(obj) { + try { + Object.getPrototypeOf(obj); + fail("Expected TypeError for Object.getPrototypeOf on " + obj); + } catch (e) { + if (! (e instanceof TypeError)) { + fail("Expected TypeError, but got " + e); + } + } +} + +checkTypeError(undefined); +checkTypeError(null); +checkTypeError(3.1415); +checkTypeError("hello"); +checkTypeError(false); +checkTypeError(true); From 4e85a5ae430b3fd1e4f300cca0bd981395de9830 Mon Sep 17 00:00:00 2001 From: Maurizio Cimadamore Date: Mon, 12 Aug 2013 17:25:07 +0100 Subject: [PATCH 041/218] 6537020: JCK tests: a compile-time error should be given in case of ambiguously imported fields (types, methods) Hiding check does not support interface multiple inheritance Reviewed-by: jjg --- .../com/sun/tools/javac/code/Scope.java | 39 +++++++++--------- .../com/sun/tools/javac/code/Symbol.java | 40 +++++++++++-------- .../com/sun/tools/javac/comp/Check.java | 5 ++- .../com/sun/tools/javac/comp/MemberEnter.java | 12 +++--- .../com/sun/tools/javac/comp/Resolve.java | 39 +++++++----------- .../test/tools/javac/4980495/static/Test.out | 2 +- .../AlreadDefinedStaticImport.java | 2 +- .../AlreadyDefinedStaticImport/p/E1.java | 4 +- .../AlreadyDefinedStaticImport/p/E2.java | 4 +- .../javac/staticImport/6537020/T6537020.java | 26 ++++++++++++ .../javac/staticImport/6537020/T6537020.out | 2 + 11 files changed, 105 insertions(+), 70 deletions(-) create mode 100644 langtools/test/tools/javac/staticImport/6537020/T6537020.java create mode 100644 langtools/test/tools/javac/staticImport/6537020/T6537020.out diff --git a/langtools/src/share/classes/com/sun/tools/javac/code/Scope.java b/langtools/src/share/classes/com/sun/tools/javac/code/Scope.java index 3697e05dead..dee7c42ff9a 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/code/Scope.java +++ b/langtools/src/share/classes/com/sun/tools/javac/code/Scope.java @@ -199,7 +199,7 @@ public class Scope { } public void enter(Symbol sym, Scope s) { - enter(sym, s, s); + enter(sym, s, s, false); } /** @@ -207,7 +207,7 @@ public class Scope { * given scope `s' accessed through `origin'. The last two * arguments are only used in import scopes. */ - public void enter(Symbol sym, Scope s, Scope origin) { + public void enter(Symbol sym, Scope s, Scope origin, boolean staticallyImported) { Assert.check(shared == 0); if (nelems * 3 >= hashMask * 2) dble(); @@ -217,7 +217,7 @@ public class Scope { old = sentinel; nelems++; } - Entry e = makeEntry(sym, old, elems, s, origin); + Entry e = makeEntry(sym, old, elems, s, origin, staticallyImported); table[hash] = e; elems = e; @@ -227,7 +227,7 @@ public class Scope { } } - Entry makeEntry(Symbol sym, Entry shadowed, Entry sibling, Scope scope, Scope origin) { + Entry makeEntry(Symbol sym, Entry shadowed, Entry sibling, Scope scope, Scope origin, boolean staticallyImported) { return new Entry(sym, shadowed, sibling, scope); } @@ -499,6 +499,10 @@ public class Scope { else return shadowed.next(sf); } + public boolean isStaticallyImported() { + return false; + } + public Scope getOrigin() { // The origin is only recorded for import scopes. For all // other scope entries, the "enclosing" type is available @@ -517,20 +521,19 @@ public class Scope { } @Override - Entry makeEntry(Symbol sym, Entry shadowed, Entry sibling, Scope scope, Scope origin) { - return new ImportEntry(sym, shadowed, sibling, scope, origin); - } + Entry makeEntry(Symbol sym, Entry shadowed, Entry sibling, Scope scope, + final Scope origin, final boolean staticallyImported) { + return new Entry(sym, shadowed, sibling, scope) { + @Override + public Scope getOrigin() { + return origin; + } - static class ImportEntry extends Entry { - private Scope origin; - - ImportEntry(Symbol sym, Entry shadowed, Entry sibling, Scope scope, Scope origin) { - super(sym, shadowed, sibling, scope); - this.origin = origin; - } - - @Override - public Scope getOrigin() { return origin; } + @Override + public boolean isStaticallyImported() { + return staticallyImported; + } + }; } } @@ -724,7 +727,7 @@ public class Scope { } @Override - public void enter(Symbol sym, Scope s, Scope origin) { + public void enter(Symbol sym, Scope s, Scope origin, boolean staticallyImported) { throw new UnsupportedOperationException(); } diff --git a/langtools/src/share/classes/com/sun/tools/javac/code/Symbol.java b/langtools/src/share/classes/com/sun/tools/javac/code/Symbol.java index f8b18d18b8e..b36254906d3 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/code/Symbol.java +++ b/langtools/src/share/classes/com/sun/tools/javac/code/Symbol.java @@ -463,26 +463,34 @@ public abstract class Symbol implements Element { return false; } - /** Check for hiding. Note that this doesn't handle multiple - * (interface) inheritance. */ private boolean hiddenIn(ClassSymbol clazz, Types types) { - if (kind == MTH && (flags() & STATIC) == 0) return false; - while (true) { - if (owner == clazz) return false; - Scope.Entry e = clazz.members().lookup(name); - while (e.scope != null) { - if (e.sym == this) return false; - if (e.sym.kind == kind && + Symbol sym = hiddenInInternal(clazz, types); + return sym != null && sym != this; + } + + private Symbol hiddenInInternal(ClassSymbol c, Types types) { + Scope.Entry e = c.members().lookup(name); + while (e.scope != null) { + if (e.sym.kind == kind && (kind != MTH || - (e.sym.flags() & STATIC) != 0 && - types.isSubSignature(e.sym.type, type))) - return true; - e = e.next(); + (e.sym.flags() & STATIC) != 0 && + types.isSubSignature(e.sym.type, type))) { + return e.sym; } - Type superType = types.supertype(clazz.type); - if (!superType.hasTag(CLASS)) return false; - clazz = (ClassSymbol)superType.tsym; + e = e.next(); } + List hiddenSyms = List.nil(); + for (Type st : types.interfaces(c.type).prepend(types.supertype(c.type))) { + if (st != null && (st.hasTag(CLASS))) { + Symbol sym = hiddenInInternal((ClassSymbol)st.tsym, types); + if (sym != null) { + hiddenSyms = hiddenSyms.prepend(hiddenInInternal((ClassSymbol)st.tsym, types)); + } + } + } + return hiddenSyms.contains(this) ? + this : + (hiddenSyms.isEmpty() ? null : hiddenSyms.head); } /** Is this symbol inherited into a given class? diff --git a/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java b/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java index 71f191b0092..f4be291dabc 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java @@ -3329,14 +3329,15 @@ public class Check { boolean isClassDecl = e.scope == s; if ((isClassDecl || sym != e.sym) && sym.kind == e.sym.kind && - sym.name != names.error) { + sym.name != names.error && + (!staticImport || !e.isStaticallyImported())) { if (!e.sym.type.isErroneous()) { String what = e.sym.toString(); if (!isClassDecl) { if (staticImport) log.error(pos, "already.defined.static.single.import", what); else - log.error(pos, "already.defined.single.import", what); + log.error(pos, "already.defined.single.import", what); } else if (sym != e.sym) log.error(pos, "already.defined.this.unit", what); diff --git a/langtools/src/share/classes/com/sun/tools/javac/comp/MemberEnter.java b/langtools/src/share/classes/com/sun/tools/javac/comp/MemberEnter.java index 24a69f09e96..4f23e8d8a1e 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/comp/MemberEnter.java +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/MemberEnter.java @@ -189,7 +189,7 @@ public class MemberEnter extends JCTree.Visitor implements Completer { staticImportAccessible(sym, packge) && sym.isMemberOf(origin, types) && !toScope.includes(sym)) - toScope.enter(sym, fromScope, origin.members()); + toScope.enter(sym, fromScope, origin.members(), true); } } }.importFrom(tsym); @@ -217,7 +217,7 @@ public class MemberEnter extends JCTree.Visitor implements Completer { staticImportAccessible(sym, packge) && !toScope.includes(sym) && sym.isMemberOf(origin, types)) { - toScope.enter(sym, fromScope, origin.members()); + toScope.enter(sym, fromScope, origin.members(), true); } } } @@ -283,7 +283,7 @@ public class MemberEnter extends JCTree.Visitor implements Completer { staticImportAccessible(sym, packge) && sym.isMemberOf(origin, types) && chk.checkUniqueStaticImport(pos, sym, toScope)) - toScope.enter(sym, sym.owner.members(), origin.members()); + toScope.enter(sym, sym.owner.members(), origin.members(), true); } } }.importFrom(tsym); @@ -313,9 +313,9 @@ public class MemberEnter extends JCTree.Visitor implements Completer { staticImportAccessible(sym, packge) && sym.isMemberOf(origin, types)) { found = true; - if (sym.kind == MTH || - sym.kind != TYP && chk.checkUniqueStaticImport(pos, sym, toScope)) - toScope.enter(sym, sym.owner.members(), origin.members()); + if (sym.kind != TYP) { + toScope.enter(sym, sym.owner.members(), origin.members(), true); + } } } } diff --git a/langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java b/langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java index 897cf210140..e2784003285 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java @@ -1344,32 +1344,23 @@ public class Resolve { if (bestSoFar.exists()) return bestSoFar; - Scope.Entry e = env.toplevel.namedImportScope.lookup(name); - for (; e.scope != null; e = e.next()) { - sym = e.sym; - Type origin = e.getOrigin().owner.type; - if (sym.kind == VAR) { - if (e.sym.owner.type != origin) - sym = sym.clone(e.getOrigin().owner); - return isAccessible(env, origin, sym) - ? sym : new AccessError(env, origin, sym); - } - } - Symbol origin = null; - e = env.toplevel.starImportScope.lookup(name); - for (; e.scope != null; e = e.next()) { - sym = e.sym; - if (sym.kind != VAR) - continue; - // invariant: sym.kind == VAR - if (bestSoFar.kind < AMBIGUOUS && sym.owner != bestSoFar.owner) - return new AmbiguityError(bestSoFar, sym); - else if (bestSoFar.kind >= VAR) { - origin = e.getOrigin().owner; - bestSoFar = isAccessible(env, origin.type, sym) - ? sym : new AccessError(env, origin.type, sym); + for (Scope sc : new Scope[] { env.toplevel.namedImportScope, env.toplevel.starImportScope }) { + Scope.Entry e = sc.lookup(name); + for (; e.scope != null; e = e.next()) { + sym = e.sym; + if (sym.kind != VAR) + continue; + // invariant: sym.kind == VAR + if (bestSoFar.kind < AMBIGUOUS && sym.owner != bestSoFar.owner) + return new AmbiguityError(bestSoFar, sym); + else if (bestSoFar.kind >= VAR) { + origin = e.getOrigin().owner; + bestSoFar = isAccessible(env, origin.type, sym) + ? sym : new AccessError(env, origin.type, sym); + } } + if (bestSoFar.exists()) break; } if (bestSoFar.kind == VAR && bestSoFar.owner.type != origin.type) return bestSoFar.clone(origin); diff --git a/langtools/test/tools/javac/4980495/static/Test.out b/langtools/test/tools/javac/4980495/static/Test.out index 84e289271e5..3cf0c35ba0e 100644 --- a/langtools/test/tools/javac/4980495/static/Test.out +++ b/langtools/test/tools/javac/4980495/static/Test.out @@ -1,2 +1,2 @@ -Test.java:9:1: compiler.err.already.defined.static.single.import: f +Test.java:15:9: compiler.err.ref.ambiguous: f, kindname.variable, f, p1.A1, kindname.variable, f, p2.A2 1 error diff --git a/langtools/test/tools/javac/diags/examples/AlreadyDefinedStaticImport/AlreadDefinedStaticImport.java b/langtools/test/tools/javac/diags/examples/AlreadyDefinedStaticImport/AlreadDefinedStaticImport.java index 83445676920..2b4ea9f6b51 100644 --- a/langtools/test/tools/javac/diags/examples/AlreadyDefinedStaticImport/AlreadDefinedStaticImport.java +++ b/langtools/test/tools/javac/diags/examples/AlreadyDefinedStaticImport/AlreadDefinedStaticImport.java @@ -23,5 +23,5 @@ // key: compiler.err.already.defined.static.single.import -import static p.E1.A; +import p.E1.A; import static p.E2.A; diff --git a/langtools/test/tools/javac/diags/examples/AlreadyDefinedStaticImport/p/E1.java b/langtools/test/tools/javac/diags/examples/AlreadyDefinedStaticImport/p/E1.java index b9c09c0703b..034b731a949 100644 --- a/langtools/test/tools/javac/diags/examples/AlreadyDefinedStaticImport/p/E1.java +++ b/langtools/test/tools/javac/diags/examples/AlreadyDefinedStaticImport/p/E1.java @@ -23,4 +23,6 @@ package p; -public enum E1 { A, B, C} +public class E1 { + public static class A { } +} diff --git a/langtools/test/tools/javac/diags/examples/AlreadyDefinedStaticImport/p/E2.java b/langtools/test/tools/javac/diags/examples/AlreadyDefinedStaticImport/p/E2.java index 8341d3e372c..960c25d81e6 100644 --- a/langtools/test/tools/javac/diags/examples/AlreadyDefinedStaticImport/p/E2.java +++ b/langtools/test/tools/javac/diags/examples/AlreadyDefinedStaticImport/p/E2.java @@ -23,4 +23,6 @@ package p; -public enum E2 { A, B, C } +public class E2 { + public static class A { } +} diff --git a/langtools/test/tools/javac/staticImport/6537020/T6537020.java b/langtools/test/tools/javac/staticImport/6537020/T6537020.java new file mode 100644 index 00000000000..3a13b992354 --- /dev/null +++ b/langtools/test/tools/javac/staticImport/6537020/T6537020.java @@ -0,0 +1,26 @@ +/* + * @test /nodynamiccopyright/ + * @bug 6537020 + * @summary JCK tests: a compile-time error should be given in case of ambiguously imported fields (types, methods) + * + * @compile/fail/ref=T6537020.out -XDrawDiagnostics T6537020.java + */ + +package p; + +import static p.T6537020.C.s; + +class T6537020 { + + static class A { + static String s; + } + + interface B { + String s = ""; + } + + static class C extends A implements B { } + + Object o = s; +} diff --git a/langtools/test/tools/javac/staticImport/6537020/T6537020.out b/langtools/test/tools/javac/staticImport/6537020/T6537020.out new file mode 100644 index 00000000000..5fd1d0c9796 --- /dev/null +++ b/langtools/test/tools/javac/staticImport/6537020/T6537020.out @@ -0,0 +1,2 @@ +T6537020.java:25:16: compiler.err.ref.ambiguous: s, kindname.variable, s, p.T6537020.B, kindname.variable, s, p.T6537020.A +1 error From 58d92c516a09ee505bbcbc9aa43b9702ea7f5840 Mon Sep 17 00:00:00 2001 From: Maurizio Cimadamore Date: Mon, 12 Aug 2013 17:28:31 +0100 Subject: [PATCH 042/218] 8021567: Javac doesn't report \"java: reference to method is ambiguous\" any more Javac incorrectly forgets about constant folding results within lambdas Reviewed-by: jjg, vromero --- .../com/sun/tools/javac/code/Type.java | 2 +- .../com/sun/tools/javac/comp/Attr.java | 24 +--------- .../tools/javac/lambda/8021567/T8021567.java | 26 +++++++++++ .../tools/javac/lambda/8021567/T8021567.out | 2 + .../tools/javac/lambda/8021567/T8021567b.java | 45 +++++++++++++++++++ 5 files changed, 75 insertions(+), 24 deletions(-) create mode 100644 langtools/test/tools/javac/lambda/8021567/T8021567.java create mode 100644 langtools/test/tools/javac/lambda/8021567/T8021567.out create mode 100644 langtools/test/tools/javac/lambda/8021567/T8021567b.java diff --git a/langtools/src/share/classes/com/sun/tools/javac/code/Type.java b/langtools/src/share/classes/com/sun/tools/javac/code/Type.java index 2764900d054..9384f43c8e7 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/code/Type.java +++ b/langtools/src/share/classes/com/sun/tools/javac/code/Type.java @@ -1525,7 +1525,7 @@ public abstract class Type implements TypeMirror { } protected void addBound(InferenceBound ib, Type bound, Types types, boolean update) { - Type bound2 = toTypeVarMap.apply(bound); + Type bound2 = toTypeVarMap.apply(bound).baseType(); List prevBounds = bounds.get(ib); for (Type b : prevBounds) { //check for redundancy - use strict version of isSameType on tvars diff --git a/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java b/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java index 335c3249267..955880c4957 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java @@ -2395,7 +2395,7 @@ public class Attr extends JCTree.Visitor { ResultInfo bodyResultInfo = lambdaType.getReturnType() == Type.recoveryType ? recoveryInfo : - new LambdaResultInfo(lambdaType.getReturnType(), funcContext); + new ResultInfo(VAL, lambdaType.getReturnType(), funcContext); localEnv.info.returnResult = bodyResultInfo; Log.DeferredDiagnosticHandler lambdaDeferredHandler = new Log.DeferredDiagnosticHandler(log); @@ -2602,28 +2602,6 @@ public class Attr extends JCTree.Visitor { } } - class LambdaResultInfo extends ResultInfo { - - LambdaResultInfo(Type pt, CheckContext checkContext) { - super(VAL, pt, checkContext); - } - - @Override - protected Type check(DiagnosticPosition pos, Type found) { - return super.check(pos, found.baseType()); - } - - @Override - protected ResultInfo dup(CheckContext newContext) { - return new LambdaResultInfo(pt, newContext); - } - - @Override - protected ResultInfo dup(Type newPt) { - return new LambdaResultInfo(newPt, checkContext); - } - } - /** * Lambda compatibility. Check that given return types, thrown types, parameter types * are compatible with the expected functional interface descriptor. This means that: diff --git a/langtools/test/tools/javac/lambda/8021567/T8021567.java b/langtools/test/tools/javac/lambda/8021567/T8021567.java new file mode 100644 index 00000000000..4de82b50eda --- /dev/null +++ b/langtools/test/tools/javac/lambda/8021567/T8021567.java @@ -0,0 +1,26 @@ +/* + * @test /nodynamiccopyright/ + * @bug 8021567 + * @summary Javac doesn't report "java: reference to method is ambiguous" any more + * @compile/fail/ref=T8021567.out -XDrawDiagnostics T8021567.java + */ + +class T8021567 { + + interface I_int { int m(); } + + interface I_char { char m(); } + + interface I_byte { byte m(); } + + void m(I_byte b) { } + void m(I_char b) { } + void m(I_int b) { } + + void test() { + m(() -> 1); //ambiguous + m(() -> 256); //ok - only method(I_int) applicable + m(() -> { int i = 1; return i; }); //ok - only method(I_int) applicable + m(() -> { int i = 256; return i; }); //ok - only method(I_int) applicable + } +} diff --git a/langtools/test/tools/javac/lambda/8021567/T8021567.out b/langtools/test/tools/javac/lambda/8021567/T8021567.out new file mode 100644 index 00000000000..efb46e5903e --- /dev/null +++ b/langtools/test/tools/javac/lambda/8021567/T8021567.out @@ -0,0 +1,2 @@ +T8021567.java:21:9: compiler.err.ref.ambiguous: m, kindname.method, m(T8021567.I_byte), T8021567, kindname.method, m(T8021567.I_char), T8021567 +1 error diff --git a/langtools/test/tools/javac/lambda/8021567/T8021567b.java b/langtools/test/tools/javac/lambda/8021567/T8021567b.java new file mode 100644 index 00000000000..1b9f5411daf --- /dev/null +++ b/langtools/test/tools/javac/lambda/8021567/T8021567b.java @@ -0,0 +1,45 @@ +/* + * 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 8021567 + * @summary Javac doesn't report "java: reference to method is ambiguous" any more + */ + +public class T8021567b { + + interface SAM { + int m(); + } + + public static void main(String argv[]) { + test(); + } + + static boolean test() { + final int i = 0; + SAM s = () -> i; + return (s.m() == 0); + } +} From bf29c2ec49aea484f911a9302c2e20a32e415132 Mon Sep 17 00:00:00 2001 From: Michael Horowitz Date: Mon, 12 Aug 2013 18:00:17 -0300 Subject: [PATCH 043/218] 8022676: Confusing error message checking instanceof non-class Reviewed-by: jlaskey, sundar --- .../jdk/nashorn/internal/runtime/resources/Messages.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nashorn/src/jdk/nashorn/internal/runtime/resources/Messages.properties b/nashorn/src/jdk/nashorn/internal/runtime/resources/Messages.properties index 8ec4f7e17f1..dadde63756f 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/resources/Messages.properties +++ b/nashorn/src/jdk/nashorn/internal/runtime/resources/Messages.properties @@ -100,7 +100,7 @@ type.error.regex.cant.supply.flags=Cannot supply flags when constructing one Reg type.error.inconsistent.property.descriptor=inconsistent property descriptor type.error.bad.default.value=bad default value: {0} type.error.function.apply.expects.array=Function.prototype.apply expects an Array for second argument -type.error.instanceof.on.non.object=instanceof cannot be used on objects without [[HasInstance]] +type.error.instanceof.on.non.object=instanceof must be called with a javascript or java object as the right-hand argument type.error.cannot.convert.to.interface=object {0} cannot be converted to {1} due to "{2}" type.error.array.reduce.invalid.init=invalid initialValue for Array.prototype.reduce type.error.array.reduceright.invalid.init=invalid initialValue for Array.prototype.reduceRight From d36ef0edd061f841ae7f1aac295b4270d25ce7ca Mon Sep 17 00:00:00 2001 From: Vicente Romero Date: Wed, 14 Aug 2013 10:53:37 +0100 Subject: [PATCH 044/218] 8013394: compile of iterator use fails with error \"defined in an inaccessible class or interface\" Reviewed-by: mcimadamore --- .../com/sun/tools/javac/comp/Lower.java | 2 +- .../CompileErrorWithIteratorTest.java | 85 +++++++++++++++++++ 2 files changed, 86 insertions(+), 1 deletion(-) create mode 100644 langtools/test/tools/javac/T8013394/CompileErrorWithIteratorTest.java diff --git a/langtools/src/share/classes/com/sun/tools/javac/comp/Lower.java b/langtools/src/share/classes/com/sun/tools/javac/comp/Lower.java index 4ee5e63fc28..0773e1b4d60 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/comp/Lower.java +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Lower.java @@ -3436,7 +3436,7 @@ public class Lower extends TreeTranslator { eType, List.nil()); VarSymbol itvar = new VarSymbol(0, names.fromString("i" + target.syntheticNameChar()), - types.erasure(iterator.type.getReturnType()), + types.erasure(types.asSuper(iterator.type.getReturnType(), syms.iteratorType.tsym)), currentMethodSym); JCStatement init = make. diff --git a/langtools/test/tools/javac/T8013394/CompileErrorWithIteratorTest.java b/langtools/test/tools/javac/T8013394/CompileErrorWithIteratorTest.java new file mode 100644 index 00000000000..78d97cad28d --- /dev/null +++ b/langtools/test/tools/javac/T8013394/CompileErrorWithIteratorTest.java @@ -0,0 +1,85 @@ +/* + * 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. + */ + +/* + * @test + * @bug 8013394 + * @summary compile of iterator use fails with error "defined in an inaccessible class or interface" + * @library /tools/javac/lib + * @build ToolBox + * @run main CompileErrorWithIteratorTest + */ + +public class CompileErrorWithIteratorTest { + + private static final String TestCollectionSrc = + "package pkg;\n" + + + "import java.util.Iterator;\n" + + "import java.util.NoSuchElementException;\n" + + + "public class TestCollection implements Iterable {\n" + + " public testCollectionIterator iterator() {\n" + + " return new testCollectionIterator();\n" + + " }\n" + + " class testCollectionIterator implements Iterator {\n" + + " public boolean hasNext() { return true; }\n" + + " public E next() throws NoSuchElementException\n" + + " {\n" + + " return null;\n" + + " }\n" + + " public void remove() {}\n" + + " }\n" + + "}"; + + private static final String TestSrc = + "import pkg.TestCollection;\n" + + "\n" + + "public class Test {\n" + + "\n" + + " public static void main(String[] args) {\n" + + " TestCollection tc1 = new TestCollection();\n" + + " for (String s : tc1) {\n" + + " System.out.println(s);\n" + + " }\n" + + " }\n" + + "}"; + + public static void main(String args[]) throws Exception { + new CompileErrorWithIteratorTest().run(); + } + + void run() throws Exception { + compile(); + } + + void compile() throws Exception { + ToolBox.JavaToolArgs javacParams = + new ToolBox.JavaToolArgs() + .setSources(TestCollectionSrc, TestSrc); + ToolBox.javac(javacParams); + } + +} From ce4eb93249d992cddb2ca11451b04ad3e9ba524d Mon Sep 17 00:00:00 2001 From: Kumar Srinivasan Date: Wed, 14 Aug 2013 07:07:55 -0700 Subject: [PATCH 045/218] 8007517: DefaultMethodRegressionTests.java fail in TL Reviewed-by: jjg, vromero --- .../DefaultMethodRegressionTests.java | 138 ------------------ 1 file changed, 138 deletions(-) delete mode 100644 langtools/test/tools/javac/defaultMethods/defaultMethodExecution/DefaultMethodRegressionTests.java diff --git a/langtools/test/tools/javac/defaultMethods/defaultMethodExecution/DefaultMethodRegressionTests.java b/langtools/test/tools/javac/defaultMethods/defaultMethodExecution/DefaultMethodRegressionTests.java deleted file mode 100644 index 566780d16a3..00000000000 --- a/langtools/test/tools/javac/defaultMethods/defaultMethodExecution/DefaultMethodRegressionTests.java +++ /dev/null @@ -1,138 +0,0 @@ -/* - * 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. 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 - * @ignore 8007517: DefaultMethodRegressionTests.java fail in TL - * @bug 8003639 - * @summary convert lambda testng tests to jtreg and add them - * @run testng DefaultMethodRegressionTests - */ - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import org.testng.annotations.Test; - -import static org.testng.Assert.*; - -/** - * This set of classes/interfaces (K/I/C) is specially designed to expose a - * bug in the JVM where it did not find some overloaded methods in some - * specific situations. (fixed by hotspot changeset ffb9316fd9ed) - */ -interface K { - int bbb(Long l); -} - -interface I extends K { - default void aaa() {} - default void aab() {} - default void aac() {} - - default int bbb(Integer i) { return 22; } - default int bbb(Float f) { return 33; } - default int bbb(Long l) { return 44; } - default int bbb(Double d) { return 55; } - default int bbb(String s) { return 66; } - - default void caa() {} - default void cab() {} - default void cac() {} -} - -class C implements I {} - -public class DefaultMethodRegressionTests { - - @Test(groups = "vm") - public void testLostOverloadedMethod() { - C c = new C(); - assertEquals(c.bbb(new Integer(1)), 22); - assertEquals(c.bbb(new Float(1.1)), 33); - assertEquals(c.bbb(new Long(1L)), 44); - assertEquals(c.bbb(new Double(0.01)), 55); - assertEquals(c.bbb(new String("")), 66); - } - - // Test to ensure that the inference verifier accepts older classfiles - // with classes that implement interfaces with defaults. - @Test(groups = "vm") - public void testInferenceVerifier() { - // interface I { int m() default { return 99; } } - byte I_bytes[] = { - (byte)0xca, (byte)0xfe, (byte)0xba, (byte)0xbe, 0x00, 0x00, 0x00, 0x33, - 0x00, 0x08, 0x07, 0x00, 0x06, 0x07, 0x00, 0x07, - 0x01, 0x00, 0x03, 0x66, 0x6f, 0x6f, 0x01, 0x00, - 0x03, 0x28, 0x29, 0x49, 0x01, 0x00, 0x04, 0x43, - 0x6f, 0x64, 0x65, 0x01, 0x00, 0x01, 0x49, 0x01, - 0x00, 0x10, 0x6a, 0x61, 0x76, 0x61, 0x2f, 0x6c, - 0x61, 0x6e, 0x67, 0x2f, 0x4f, 0x62, 0x6a, 0x65, - 0x63, 0x74, 0x06, 0x00, 0x00, 0x01, 0x00, 0x02, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x01, - 0x00, 0x03, 0x00, 0x04, 0x00, 0x01, 0x00, 0x05, - 0x00, 0x00, 0x00, 0x0f, 0x00, 0x01, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x03, 0x10, 0x63, (byte)0xac, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00 - }; - // public class C implements I {} /* -target 1.5 */ - byte C_bytes[] = { - (byte)0xca, (byte)0xfe, (byte)0xba, (byte)0xbe, 0x00, 0x00, 0x00, 0x31, - 0x00, 0x0c, 0x0a, 0x00, 0x03, 0x00, 0x08, 0x07, - 0x00, 0x09, 0x07, 0x00, 0x0a, 0x07, 0x00, 0x0b, - 0x01, 0x00, 0x06, 0x3c, 0x69, 0x6e, 0x69, 0x74, - 0x3e, 0x01, 0x00, 0x03, 0x28, 0x29, 0x56, 0x01, - 0x00, 0x04, 0x43, 0x6f, 0x64, 0x65, 0x0c, 0x00, - 0x05, 0x00, 0x06, 0x01, 0x00, 0x01, 0x43, 0x01, - 0x00, 0x10, 0x6a, 0x61, 0x76, 0x61, 0x2f, 0x6c, - 0x61, 0x6e, 0x67, 0x2f, 0x4f, 0x62, 0x6a, 0x65, - 0x63, 0x74, 0x01, 0x00, 0x01, 0x49, 0x00, 0x21, - 0x00, 0x02, 0x00, 0x03, 0x00, 0x01, 0x00, 0x04, - 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x05, - 0x00, 0x06, 0x00, 0x01, 0x00, 0x07, 0x00, 0x00, - 0x00, 0x11, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, - 0x00, 0x05, 0x2a, (byte)0xb7, 0x00, 0x01, (byte)0xb1, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00 - }; - - ClassLoader cl = new ClassLoader() { - protected Class findClass(String name) { - if (name.equals("I")) { - return defineClass("I", I_bytes, 0, I_bytes.length); - } else if (name.equals("C")) { - return defineClass("C", C_bytes, 0, C_bytes.length); - } else { - return null; - } - } - }; - try { - Class.forName("C", true, cl); - } catch (Exception e) { - // unmodified verifier will throw VerifyError - fail("No exception should be thrown"); - } - } -} From a28b8a61dcfe7cf91a915cb7bc993bae112078bb Mon Sep 17 00:00:00 2001 From: Athijegannathan Sundararajan Date: Wed, 14 Aug 2013 20:51:53 +0530 Subject: [PATCH 046/218] 8023026: Array.prototype iterator functions like forEach, reduce should work for Java arrays, lists Reviewed-by: jlaskey, lagergren --- .../runtime/arrays/ArrayLikeIterator.java | 27 +++++-- .../runtime/arrays/JavaArrayIterator.java | 80 +++++++++++++++++++ .../runtime/arrays/JavaListIterator.java | 79 ++++++++++++++++++ .../arrays/ReverseJavaArrayIterator.java | 58 ++++++++++++++ .../arrays/ReverseJavaListIterator.java | 58 ++++++++++++++ ...r.java => ReverseScriptArrayIterator.java} | 4 +- ....java => ReverseScriptObjectIterator.java} | 4 +- ...Iterator.java => ScriptArrayIterator.java} | 4 +- ...terator.java => ScriptObjectIterator.java} | 4 +- nashorn/test/script/basic/JDK-8023026.js | 71 ++++++++++++++++ .../test/script/basic/JDK-8023026.js.EXPECTED | 42 ++++++++++ 11 files changed, 417 insertions(+), 14 deletions(-) create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/arrays/JavaArrayIterator.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/arrays/JavaListIterator.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/arrays/ReverseJavaArrayIterator.java create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/arrays/ReverseJavaListIterator.java rename nashorn/src/jdk/nashorn/internal/runtime/arrays/{ReverseArrayIterator.java => ReverseScriptArrayIterator.java} (91%) rename nashorn/src/jdk/nashorn/internal/runtime/arrays/{ReverseMapIterator.java => ReverseScriptObjectIterator.java} (91%) rename nashorn/src/jdk/nashorn/internal/runtime/arrays/{ArrayIterator.java => ScriptArrayIterator.java} (94%) rename nashorn/src/jdk/nashorn/internal/runtime/arrays/{MapIterator.java => ScriptObjectIterator.java} (94%) create mode 100644 nashorn/test/script/basic/JDK-8023026.js create mode 100644 nashorn/test/script/basic/JDK-8023026.js.EXPECTED diff --git a/nashorn/src/jdk/nashorn/internal/runtime/arrays/ArrayLikeIterator.java b/nashorn/src/jdk/nashorn/internal/runtime/arrays/ArrayLikeIterator.java index 70f74d8e342..ab16d2202dc 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/arrays/ArrayLikeIterator.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/arrays/ArrayLikeIterator.java @@ -26,6 +26,7 @@ package jdk.nashorn.internal.runtime.arrays; import java.util.Iterator; +import java.util.List; import jdk.nashorn.api.scripting.ScriptObjectMirror; import jdk.nashorn.internal.runtime.JSType; import jdk.nashorn.internal.runtime.ScriptObject; @@ -49,7 +50,7 @@ abstract public class ArrayLikeIterator implements Iterator { * * @param includeUndefined should undefined elements be included in the iteration? */ - protected ArrayLikeIterator(final boolean includeUndefined) { + ArrayLikeIterator(final boolean includeUndefined) { this.includeUndefined = includeUndefined; this.index = 0; } @@ -118,18 +119,26 @@ abstract public class ArrayLikeIterator implements Iterator { Object obj = object; if (ScriptObject.isArray(obj)) { - return new ArrayIterator((ScriptObject) obj, includeUndefined); + return new ScriptArrayIterator((ScriptObject) obj, includeUndefined); } obj = JSType.toScriptObject(obj); if (obj instanceof ScriptObject) { - return new MapIterator((ScriptObject)obj, includeUndefined); + return new ScriptObjectIterator((ScriptObject)obj, includeUndefined); } if (obj instanceof ScriptObjectMirror) { return new ScriptObjectMirrorIterator((ScriptObjectMirror)obj, includeUndefined); } + if (obj instanceof List) { + return new JavaListIterator((List)obj, includeUndefined); + } + + if (obj != null && obj.getClass().isArray()) { + return new JavaArrayIterator(obj, includeUndefined); + } + return new EmptyArrayLikeIterator(); } @@ -143,19 +152,25 @@ abstract public class ArrayLikeIterator implements Iterator { Object obj = object; if (ScriptObject.isArray(obj)) { - return new ReverseArrayIterator((ScriptObject) obj, includeUndefined); + return new ReverseScriptArrayIterator((ScriptObject) obj, includeUndefined); } obj = JSType.toScriptObject(obj); if (obj instanceof ScriptObject) { - return new ReverseMapIterator((ScriptObject)obj, includeUndefined); + return new ReverseScriptObjectIterator((ScriptObject)obj, includeUndefined); } if (obj instanceof ScriptObjectMirror) { return new ReverseScriptObjectMirrorIterator((ScriptObjectMirror)obj, includeUndefined); } - assert !obj.getClass().isArray(); + if (obj instanceof List) { + return new ReverseJavaListIterator((List)obj, includeUndefined); + } + + if (obj != null && obj.getClass().isArray()) { + return new ReverseJavaArrayIterator(obj, includeUndefined); + } return new EmptyArrayLikeIterator(); } diff --git a/nashorn/src/jdk/nashorn/internal/runtime/arrays/JavaArrayIterator.java b/nashorn/src/jdk/nashorn/internal/runtime/arrays/JavaArrayIterator.java new file mode 100644 index 00000000000..92a80029384 --- /dev/null +++ b/nashorn/src/jdk/nashorn/internal/runtime/arrays/JavaArrayIterator.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2010, 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 jdk.nashorn.internal.runtime.arrays; + +import java.lang.reflect.Array; + +/** + * Iterator over a Java List. + */ +class JavaArrayIterator extends ArrayLikeIterator { + + /** Array to iterate over */ + protected final Object array; + + /** length of array */ + protected final long length; + + /** + * Constructor + * @param array array to iterate over + * @param includeUndefined should undefined elements be included in iteration + */ + protected JavaArrayIterator(final Object array, final boolean includeUndefined) { + super(includeUndefined); + assert array.getClass().isArray() : "expecting Java array object"; + this.array = array; + this.length = Array.getLength(array); + } + + /** + * Is the current index still inside the array + * @return true if inside the array + */ + protected boolean indexInArray() { + return index < length; + } + + @Override + public Object next() { + return Array.get(array, (int)bumpIndex()); + } + + @Override + public long getLength() { + return length; + } + + @Override + public boolean hasNext() { + return indexInArray(); + } + + @Override + public void remove() { + throw new UnsupportedOperationException("remove"); + } +} \ No newline at end of file diff --git a/nashorn/src/jdk/nashorn/internal/runtime/arrays/JavaListIterator.java b/nashorn/src/jdk/nashorn/internal/runtime/arrays/JavaListIterator.java new file mode 100644 index 00000000000..96a8b25b632 --- /dev/null +++ b/nashorn/src/jdk/nashorn/internal/runtime/arrays/JavaListIterator.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2010, 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 jdk.nashorn.internal.runtime.arrays; + +import java.util.List; + +/** + * Iterator over a Java List. + */ +class JavaListIterator extends ArrayLikeIterator { + + /** {@link java.util.List} to iterate over */ + protected final List list; + + /** length of array */ + protected final long length; + + /** + * Constructor + * @param list list to iterate over + * @param includeUndefined should undefined elements be included in iteration + */ + protected JavaListIterator(final List list, final boolean includeUndefined) { + super(includeUndefined); + this.list = list; + this.length = list.size(); + } + + /** + * Is the current index still inside the array + * @return true if inside the array + */ + protected boolean indexInArray() { + return index < length; + } + + @Override + public Object next() { + return list.get((int)bumpIndex()); + } + + @Override + public long getLength() { + return length; + } + + @Override + public boolean hasNext() { + return indexInArray(); + } + + @Override + public void remove() { + list.remove(index); + } +} diff --git a/nashorn/src/jdk/nashorn/internal/runtime/arrays/ReverseJavaArrayIterator.java b/nashorn/src/jdk/nashorn/internal/runtime/arrays/ReverseJavaArrayIterator.java new file mode 100644 index 00000000000..dcb37cfd197 --- /dev/null +++ b/nashorn/src/jdk/nashorn/internal/runtime/arrays/ReverseJavaArrayIterator.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2010, 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 jdk.nashorn.internal.runtime.arrays; + +import java.lang.reflect.Array; + +/** + * Reverse iterator over a array + */ +final class ReverseJavaArrayIterator extends JavaArrayIterator { + /** + * Constructor + * @param array array to iterate over + * @param includeUndefined should undefined elements be included in iteration + */ + public ReverseJavaArrayIterator(final Object array, final boolean includeUndefined) { + super(array, includeUndefined); + this.index = Array.getLength(array) - 1; + } + + @Override + public boolean isReverse() { + return true; + } + + @Override + protected boolean indexInArray() { + return index >= 0; + } + + @Override + protected long bumpIndex() { + return index--; + } +} \ No newline at end of file diff --git a/nashorn/src/jdk/nashorn/internal/runtime/arrays/ReverseJavaListIterator.java b/nashorn/src/jdk/nashorn/internal/runtime/arrays/ReverseJavaListIterator.java new file mode 100644 index 00000000000..390858bc8a2 --- /dev/null +++ b/nashorn/src/jdk/nashorn/internal/runtime/arrays/ReverseJavaListIterator.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2010, 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 jdk.nashorn.internal.runtime.arrays; + +import java.util.List; + +/** + * Reverse iterator over a List + */ +final class ReverseJavaListIterator extends JavaListIterator { + /** + * Constructor + * @param list list to iterate over + * @param includeUndefined should undefined elements be included in iteration + */ + public ReverseJavaListIterator(final List list, final boolean includeUndefined) { + super(list, includeUndefined); + this.index = list.size() - 1; + } + + @Override + public boolean isReverse() { + return true; + } + + @Override + protected boolean indexInArray() { + return index >= 0; + } + + @Override + protected long bumpIndex() { + return index--; + } +} diff --git a/nashorn/src/jdk/nashorn/internal/runtime/arrays/ReverseArrayIterator.java b/nashorn/src/jdk/nashorn/internal/runtime/arrays/ReverseScriptArrayIterator.java similarity index 91% rename from nashorn/src/jdk/nashorn/internal/runtime/arrays/ReverseArrayIterator.java rename to nashorn/src/jdk/nashorn/internal/runtime/arrays/ReverseScriptArrayIterator.java index 4746de860b7..fae1a8ffdee 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/arrays/ReverseArrayIterator.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/arrays/ReverseScriptArrayIterator.java @@ -30,14 +30,14 @@ import jdk.nashorn.internal.runtime.ScriptObject; /** * Reverse iterator over a NativeArray */ -final class ReverseArrayIterator extends ArrayIterator { +final class ReverseScriptArrayIterator extends ScriptArrayIterator { /** * Constructor * @param array array to iterate over * @param includeUndefined should undefined elements be included in iteration */ - public ReverseArrayIterator(final ScriptObject array, final boolean includeUndefined) { + public ReverseScriptArrayIterator(final ScriptObject array, final boolean includeUndefined) { super(array, includeUndefined); this.index = array.getArray().length() - 1; } diff --git a/nashorn/src/jdk/nashorn/internal/runtime/arrays/ReverseMapIterator.java b/nashorn/src/jdk/nashorn/internal/runtime/arrays/ReverseScriptObjectIterator.java similarity index 91% rename from nashorn/src/jdk/nashorn/internal/runtime/arrays/ReverseMapIterator.java rename to nashorn/src/jdk/nashorn/internal/runtime/arrays/ReverseScriptObjectIterator.java index 0822b5a4c02..533104db965 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/arrays/ReverseMapIterator.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/arrays/ReverseScriptObjectIterator.java @@ -31,9 +31,9 @@ import jdk.nashorn.internal.runtime.ScriptObject; /** * Reverse iterator over a map */ -final class ReverseMapIterator extends MapIterator { +final class ReverseScriptObjectIterator extends ScriptObjectIterator { - ReverseMapIterator(final ScriptObject obj, final boolean includeUndefined) { + ReverseScriptObjectIterator(final ScriptObject obj, final boolean includeUndefined) { super(obj, includeUndefined); this.index = JSType.toUint32(obj.getLength()) - 1; } diff --git a/nashorn/src/jdk/nashorn/internal/runtime/arrays/ArrayIterator.java b/nashorn/src/jdk/nashorn/internal/runtime/arrays/ScriptArrayIterator.java similarity index 94% rename from nashorn/src/jdk/nashorn/internal/runtime/arrays/ArrayIterator.java rename to nashorn/src/jdk/nashorn/internal/runtime/arrays/ScriptArrayIterator.java index 8d2de2ced89..0a617815085 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/arrays/ArrayIterator.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/arrays/ScriptArrayIterator.java @@ -30,7 +30,7 @@ import jdk.nashorn.internal.runtime.ScriptObject; /** * Iterator over a NativeArray */ -class ArrayIterator extends ArrayLikeIterator { +class ScriptArrayIterator extends ArrayLikeIterator { /** Array {@link ScriptObject} to iterate over */ protected final ScriptObject array; @@ -43,7 +43,7 @@ class ArrayIterator extends ArrayLikeIterator { * @param array array to iterate over * @param includeUndefined should undefined elements be included in iteration */ - protected ArrayIterator(final ScriptObject array, final boolean includeUndefined) { + protected ScriptArrayIterator(final ScriptObject array, final boolean includeUndefined) { super(includeUndefined); this.array = array; this.length = array.getArray().length(); diff --git a/nashorn/src/jdk/nashorn/internal/runtime/arrays/MapIterator.java b/nashorn/src/jdk/nashorn/internal/runtime/arrays/ScriptObjectIterator.java similarity index 94% rename from nashorn/src/jdk/nashorn/internal/runtime/arrays/MapIterator.java rename to nashorn/src/jdk/nashorn/internal/runtime/arrays/ScriptObjectIterator.java index f8b40cfea8a..73b4c1f5a61 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/arrays/MapIterator.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/arrays/ScriptObjectIterator.java @@ -32,12 +32,12 @@ import jdk.nashorn.internal.runtime.ScriptObject; /** * Iterator over a map */ -class MapIterator extends ArrayLikeIterator { +class ScriptObjectIterator extends ArrayLikeIterator { protected final ScriptObject obj; private final long length; - MapIterator(final ScriptObject obj, final boolean includeUndefined) { + ScriptObjectIterator(final ScriptObject obj, final boolean includeUndefined) { super(includeUndefined); this.obj = obj; this.length = JSType.toUint32(obj.getLength()); diff --git a/nashorn/test/script/basic/JDK-8023026.js b/nashorn/test/script/basic/JDK-8023026.js new file mode 100644 index 00000000000..9080ec8cb33 --- /dev/null +++ b/nashorn/test/script/basic/JDK-8023026.js @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * JDK-8023026: Array.prototype iterator functions like forEach, reduce should work for Java arrays, lists + * + * @test + * @run + */ + +function checkIterations(obj) { + if (typeof obj.getClass == 'function') { + print("iterating on an object of " + obj.getClass()); + } else { + print("iterating on " + String(obj)); + } + + Array.prototype.forEach.call(obj, + function(x) { print("forEach " + x); }); + + print("left sum " + Array.prototype.reduce.call(obj, + function(x, y) { print("reduce", x, y); return x + y; })); + + print("right sum " + Array.prototype.reduceRight.call(obj, + function(x, y) { print("reduceRight", x, y); return x + y; })); + + print("squared " + Array.prototype.map.call(obj, + function(x) x*x)); +} + +var array = new (Java.type("[I"))(4); +for (var i in array) { + array[i] = i; +} + +checkIterations(array); + +var list = new java.util.ArrayList(); +list.add(1); +list.add(3); +list.add(5); +list.add(7); + +checkIterations(list); + +var mirror = loadWithNewGlobal({ + name: "test", + script: "[2, 4, 6, 8]" +}); + +checkIterations(mirror); diff --git a/nashorn/test/script/basic/JDK-8023026.js.EXPECTED b/nashorn/test/script/basic/JDK-8023026.js.EXPECTED new file mode 100644 index 00000000000..333a1ab42b5 --- /dev/null +++ b/nashorn/test/script/basic/JDK-8023026.js.EXPECTED @@ -0,0 +1,42 @@ +iterating on an object of class [I +forEach 0 +forEach 1 +forEach 2 +forEach 3 +reduce 0 1 +reduce 1 2 +reduce 3 3 +left sum 6 +reduceRight 3 2 +reduceRight 5 1 +reduceRight 6 0 +right sum 6 +squared 0,1,4,9 +iterating on an object of class java.util.ArrayList +forEach 1 +forEach 3 +forEach 5 +forEach 7 +reduce 1 3 +reduce 4 5 +reduce 9 7 +left sum 16 +reduceRight 7 5 +reduceRight 12 3 +reduceRight 15 1 +right sum 16 +squared 1,9,25,49 +iterating on [object Array] +forEach 2 +forEach 4 +forEach 6 +forEach 8 +reduce 2 4 +reduce 6 6 +reduce 12 8 +left sum 20 +reduceRight 8 6 +reduceRight 14 4 +reduceRight 18 2 +right sum 20 +squared 4,16,36,64 From 9d372e780132e6ba1c8f36f910047dd3cb581cab Mon Sep 17 00:00:00 2001 From: Ron Durbin Date: Wed, 14 Aug 2013 15:12:00 -0700 Subject: [PATCH 047/218] 8005073: [TESTBUG] remove crufty '_g' support from HS tests Remove crufty '_g' support from HS tests Reviewed-by: dcubed, sla --- hotspot/test/Makefile | 2 -- 1 file changed, 2 deletions(-) diff --git a/hotspot/test/Makefile b/hotspot/test/Makefile index f8bccc6693b..4eff25cf793 100644 --- a/hotspot/test/Makefile +++ b/hotspot/test/Makefile @@ -210,9 +210,7 @@ clienttest: prep $(PRODUCT_HOME) $(PRODUCT_HOME)/bin/java $(JAVA_OPTIONS) -help $(PRODUCT_HOME)/bin/java $(JAVA_OPTIONS) -X $(RM) $(PRODUCT_HOME)/jre/lib/*/client/classes.jsa - $(RM) $(PRODUCT_HOME)/jre/lib/*/client/classes_g.jsa $(RM) $(PRODUCT_HOME)/jre/bin/client/classes.jsa - $(RM) $(PRODUCT_HOME)/jre/bin/client/classes_g.jsa $(PRODUCT_HOME)/bin/java $(JAVA_OPTIONS) -Xshare:dump PHONY_LIST += clienttest From 43991d588a7800a6331f68056c622b1d9ff59f67 Mon Sep 17 00:00:00 2001 From: Jonathan Gibbons Date: Wed, 14 Aug 2013 16:41:01 -0700 Subject: [PATCH 048/218] 8017191: Javadoc is confused by @link to imported classes outside of the set of generated packages Reviewed-by: bpatel --- .../doclets/formats/html/LinkFactoryImpl.java | 2 +- .../formats/html/markup/StringContent.java | 5 ++ .../sun/javadoc/testSeeTag/TestSeeTag.java | 80 +++++++++++++++++++ .../com/sun/javadoc/testSeeTag/pkg/Test.java | 29 +++++++ 4 files changed, 115 insertions(+), 1 deletion(-) create mode 100644 langtools/test/com/sun/javadoc/testSeeTag/TestSeeTag.java create mode 100644 langtools/test/com/sun/javadoc/testSeeTag/pkg/Test.java diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/LinkFactoryImpl.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/LinkFactoryImpl.java index abad36dbf99..890635e3df0 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/LinkFactoryImpl.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/LinkFactoryImpl.java @@ -109,7 +109,7 @@ public class LinkFactoryImpl extends LinkFactory { } } // Can't link so just write label. - link.addContent(label.toString()); + link.addContent(label); if (noLabel && !classLinkInfo.excludeTypeParameterLinks) { link.addContent(getTypeParameterLinks(linkInfo)); } diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/markup/StringContent.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/markup/StringContent.java index 21d67c00cfa..3c602e3b2fb 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/markup/StringContent.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/markup/StringContent.java @@ -70,6 +70,7 @@ public class StringContent extends Content { * DocletAbortException because it * is not supported. */ + @Override public void addContent(Content content) { throw new DocletAbortException(); } @@ -80,6 +81,7 @@ public class StringContent extends Content { * * @param strContent string content to be added */ + @Override public void addContent(String strContent) { appendChars(strContent); } @@ -87,10 +89,12 @@ public class StringContent extends Content { /** * {@inheritDoc} */ + @Override public boolean isEmpty() { return (stringContent.length() == 0); } + @Override public int charCount() { return RawHtml.charCount(stringContent.toString()); } @@ -98,6 +102,7 @@ public class StringContent extends Content { /** * {@inheritDoc} */ + @Override public String toString() { return stringContent.toString(); } diff --git a/langtools/test/com/sun/javadoc/testSeeTag/TestSeeTag.java b/langtools/test/com/sun/javadoc/testSeeTag/TestSeeTag.java new file mode 100644 index 00000000000..2d2f64e6295 --- /dev/null +++ b/langtools/test/com/sun/javadoc/testSeeTag/TestSeeTag.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 8017191 + * @summary Javadoc is confused by at-link to imported classes outside of the set of generated packages + * @author jjg + * @library ../lib/ + * @build JavadocTester TestSeeTag + * @run main TestSeeTag + */ + +public class TestSeeTag extends JavadocTester { + + //Test information. + private static final String BUG_ID = "8017191"; + private static final String OUTPUT_DIR = BUG_ID; + + //Javadoc arguments. + private static final String[] ARGS = new String[] { + "-d", OUTPUT_DIR, "-sourcepath", SRC_DIR, "pkg" + }; + + //Input for string search tests. + private static final String[][] TEST = { + { OUTPUT_DIR + FS + "pkg" + FS + "Test.html", + "List" + } + }; + private static final String[][] NEGATED_TEST = { + { OUTPUT_DIR + FS + "pkg" + FS + "Test.html", + "<code>List</code>" + } + }; + + /** + * The entry point of the test. + * @param args the array of command line arguments. + */ + public static void main(String[] args) { + TestSeeTag tester = new TestSeeTag(); + run(tester, ARGS, TEST, NEGATED_TEST); + tester.printSummary(); + } + + /** + * {@inheritDoc} + */ + public String getBugId() { + return BUG_ID; + } + + /** + * {@inheritDoc} + */ + public String getBugName() { + return getClass().getName(); + } +} diff --git a/langtools/test/com/sun/javadoc/testSeeTag/pkg/Test.java b/langtools/test/com/sun/javadoc/testSeeTag/pkg/Test.java new file mode 100644 index 00000000000..ee997767132 --- /dev/null +++ b/langtools/test/com/sun/javadoc/testSeeTag/pkg/Test.java @@ -0,0 +1,29 @@ +/* + * 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 pkg; +import java.util.List; + +/** @see List */ +public class Test { } + From d91b6547d38af09947e75202d62fe41f1d9ec5fa Mon Sep 17 00:00:00 2001 From: Kumar Srinivasan Date: Wed, 14 Aug 2013 18:58:39 -0700 Subject: [PATCH 049/218] 6840442: JavaCompiler.getTask() has incomplete specification for IllegalArgumentException Reviewed-by: jjg --- langtools/src/share/classes/javax/tools/JavaCompiler.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/langtools/src/share/classes/javax/tools/JavaCompiler.java b/langtools/src/share/classes/javax/tools/JavaCompiler.java index 5588c80d428..09c70bae48e 100644 --- a/langtools/src/share/classes/javax/tools/JavaCompiler.java +++ b/langtools/src/share/classes/javax/tools/JavaCompiler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -251,8 +251,8 @@ public interface JavaCompiler extends Tool, OptionChecker { * occurred in a user supplied component. The * {@linkplain Throwable#getCause() cause} will be the error in * user code. - * @throws IllegalArgumentException if any of the given - * compilation units are of other kind than + * @throws IllegalArgumentException if any of the options are invalid, + * or if any of the given compilation units are of other kind than * {@linkplain JavaFileObject.Kind#SOURCE source} */ CompilationTask getTask(Writer out, From f63547bf71a6a870da1cef7c99653d9b27b5cfed Mon Sep 17 00:00:00 2001 From: John Cuthbertson Date: Thu, 15 Aug 2013 10:52:18 +0200 Subject: [PATCH 050/218] 7145569: G1: optimize nmethods scanning Add a list of nmethods to the RSet for a region that contain references into the region. Skip scanning the code cache during root scanning and scan the nmethod lists during RSet scanning instead. Reviewed-by: tschatzl, brutisso, mgerdin, twisti, kvn --- hotspot/src/share/vm/c1/c1_Runtime1.cpp | 25 +- hotspot/src/share/vm/code/nmethod.cpp | 36 +- hotspot/src/share/vm/code/nmethod.hpp | 2 +- .../gc_implementation/g1/concurrentMark.cpp | 23 +- .../gc_implementation/g1/concurrentMark.hpp | 3 + .../gc_implementation/g1/g1CollectedHeap.cpp | 606 ++++++++++++------ .../gc_implementation/g1/g1CollectedHeap.hpp | 179 +++--- .../gc_implementation/g1/g1GCPhaseTimes.cpp | 20 + .../gc_implementation/g1/g1GCPhaseTimes.hpp | 23 + .../vm/gc_implementation/g1/g1RemSet.cpp | 51 +- .../vm/gc_implementation/g1/g1RemSet.hpp | 30 +- .../gc_implementation/g1/g1RemSetSummary.cpp | 78 ++- .../vm/gc_implementation/g1/g1_globals.hpp | 5 +- .../vm/gc_implementation/g1/heapRegion.cpp | 446 ++++++++----- .../vm/gc_implementation/g1/heapRegion.hpp | 23 +- .../gc_implementation/g1/heapRegionRemSet.cpp | 124 +++- .../gc_implementation/g1/heapRegionRemSet.hpp | 40 +- .../share/vm/gc_interface/collectedHeap.cpp | 8 + .../share/vm/gc_interface/collectedHeap.hpp | 6 + hotspot/src/share/vm/memory/iterator.cpp | 2 +- hotspot/src/share/vm/runtime/sweeper.hpp | 1 + .../src/share/vm/utilities/growableArray.hpp | 1 + 22 files changed, 1256 insertions(+), 476 deletions(-) diff --git a/hotspot/src/share/vm/c1/c1_Runtime1.cpp b/hotspot/src/share/vm/c1/c1_Runtime1.cpp index 908571f6cc4..9a1c4cce21f 100644 --- a/hotspot/src/share/vm/c1/c1_Runtime1.cpp +++ b/hotspot/src/share/vm/c1/c1_Runtime1.cpp @@ -915,16 +915,6 @@ JRT_ENTRY(void, Runtime1::patch_code(JavaThread* thread, Runtime1::StubID stub_i // Return to the now deoptimized frame. } - // If we are patching in a non-perm oop, make sure the nmethod - // is on the right list. - if (ScavengeRootsInCode && mirror.not_null() && mirror()->is_scavengable()) { - MutexLockerEx ml_code (CodeCache_lock, Mutex::_no_safepoint_check_flag); - nmethod* nm = CodeCache::find_nmethod(caller_frame.pc()); - guarantee(nm != NULL, "only nmethods can contain non-perm oops"); - if (!nm->on_scavenge_root_list()) - CodeCache::add_scavenge_root_nmethod(nm); - } - // Now copy code back { @@ -1125,6 +1115,21 @@ JRT_ENTRY(void, Runtime1::patch_code(JavaThread* thread, Runtime1::StubID stub_i } } } + + // If we are patching in a non-perm oop, make sure the nmethod + // is on the right list. + if (ScavengeRootsInCode && mirror.not_null() && mirror()->is_scavengable()) { + MutexLockerEx ml_code (CodeCache_lock, Mutex::_no_safepoint_check_flag); + nmethod* nm = CodeCache::find_nmethod(caller_frame.pc()); + guarantee(nm != NULL, "only nmethods can contain non-perm oops"); + if (!nm->on_scavenge_root_list()) { + CodeCache::add_scavenge_root_nmethod(nm); + } + + // Since we've patched some oops in the nmethod, + // (re)register it with the heap. + Universe::heap()->register_nmethod(nm); + } JRT_END // diff --git a/hotspot/src/share/vm/code/nmethod.cpp b/hotspot/src/share/vm/code/nmethod.cpp index 1dfc3ba8f07..9412feff709 100644 --- a/hotspot/src/share/vm/code/nmethod.cpp +++ b/hotspot/src/share/vm/code/nmethod.cpp @@ -687,6 +687,7 @@ nmethod::nmethod( code_buffer->copy_values_to(this); if (ScavengeRootsInCode && detect_scavenge_root_oops()) { CodeCache::add_scavenge_root_nmethod(this); + Universe::heap()->register_nmethod(this); } debug_only(verify_scavenge_root_oops()); CodeCache::commit(this); @@ -881,6 +882,7 @@ nmethod::nmethod( dependencies->copy_to(this); if (ScavengeRootsInCode && detect_scavenge_root_oops()) { CodeCache::add_scavenge_root_nmethod(this); + Universe::heap()->register_nmethod(this); } debug_only(verify_scavenge_root_oops()); @@ -1300,6 +1302,13 @@ bool nmethod::make_not_entrant_or_zombie(unsigned int state) { methodHandle the_method(method()); No_Safepoint_Verifier nsv; + // during patching, depending on the nmethod state we must notify the GC that + // code has been unloaded, unregistering it. We cannot do this right while + // holding the Patching_lock because we need to use the CodeCache_lock. This + // would be prone to deadlocks. + // This flag is used to remember whether we need to later lock and unregister. + bool nmethod_needs_unregister = false; + { // invalidate osr nmethod before acquiring the patching lock since // they both acquire leaf locks and we don't want a deadlock. @@ -1332,6 +1341,13 @@ bool nmethod::make_not_entrant_or_zombie(unsigned int state) { inc_decompile_count(); } + // If the state is becoming a zombie, signal to unregister the nmethod with + // the heap. + // This nmethod may have already been unloaded during a full GC. + if ((state == zombie) && !is_unloaded()) { + nmethod_needs_unregister = true; + } + // Change state _state = state; @@ -1367,6 +1383,9 @@ bool nmethod::make_not_entrant_or_zombie(unsigned int state) { // safepoint can sneak in, otherwise the oops used by the // dependency logic could have become stale. MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); + if (nmethod_needs_unregister) { + Universe::heap()->unregister_nmethod(this); + } flush_dependencies(NULL); } @@ -1817,21 +1836,10 @@ void nmethod::metadata_do(void f(Metadata*)) { if (_method != NULL) f(_method); } - -// This method is called twice during GC -- once while -// tracing the "active" nmethods on thread stacks during -// the (strong) marking phase, and then again when walking -// the code cache contents during the weak roots processing -// phase. The two uses are distinguished by means of the -// 'do_strong_roots_only' flag, which is true in the first -// case. We want to walk the weak roots in the nmethod -// only in the second case. The weak roots in the nmethod -// are the oops in the ExceptionCache and the InlineCache -// oops. -void nmethod::oops_do(OopClosure* f, bool do_strong_roots_only) { +void nmethod::oops_do(OopClosure* f, bool allow_zombie) { // make sure the oops ready to receive visitors - assert(!is_zombie() && !is_unloaded(), - "should not call follow on zombie or unloaded nmethod"); + assert(allow_zombie || !is_zombie(), "should not call follow on zombie nmethod"); + assert(!is_unloaded(), "should not call follow on unloaded nmethod"); // If the method is not entrant or zombie then a JMP is plastered over the // first few bytes. If an oop in the old code was there, that oop diff --git a/hotspot/src/share/vm/code/nmethod.hpp b/hotspot/src/share/vm/code/nmethod.hpp index 477ceb6dcb6..3178e90d98a 100644 --- a/hotspot/src/share/vm/code/nmethod.hpp +++ b/hotspot/src/share/vm/code/nmethod.hpp @@ -566,7 +566,7 @@ public: void preserve_callee_argument_oops(frame fr, const RegisterMap *reg_map, OopClosure* f); void oops_do(OopClosure* f) { oops_do(f, false); } - void oops_do(OopClosure* f, bool do_strong_roots_only); + void oops_do(OopClosure* f, bool allow_zombie); bool detect_scavenge_root_oops(); void verify_scavenge_root_oops() PRODUCT_RETURN; diff --git a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp index 13a34a45156..04f8ccd0fc7 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp @@ -4529,7 +4529,7 @@ G1PrintRegionLivenessInfoClosure(outputStream* out, const char* phase_name) _total_prev_live_bytes(0), _total_next_live_bytes(0), _hum_used_bytes(0), _hum_capacity_bytes(0), _hum_prev_live_bytes(0), _hum_next_live_bytes(0), - _total_remset_bytes(0) { + _total_remset_bytes(0), _total_strong_code_roots_bytes(0) { G1CollectedHeap* g1h = G1CollectedHeap::heap(); MemRegion g1_committed = g1h->g1_committed(); MemRegion g1_reserved = g1h->g1_reserved(); @@ -4553,9 +4553,11 @@ G1PrintRegionLivenessInfoClosure(outputStream* out, const char* phase_name) G1PPRL_BYTE_H_FORMAT G1PPRL_BYTE_H_FORMAT G1PPRL_DOUBLE_H_FORMAT + G1PPRL_BYTE_H_FORMAT G1PPRL_BYTE_H_FORMAT, "type", "address-range", - "used", "prev-live", "next-live", "gc-eff", "remset"); + "used", "prev-live", "next-live", "gc-eff", + "remset", "code-roots"); _out->print_cr(G1PPRL_LINE_PREFIX G1PPRL_TYPE_H_FORMAT G1PPRL_ADDR_BASE_H_FORMAT @@ -4563,9 +4565,11 @@ G1PrintRegionLivenessInfoClosure(outputStream* out, const char* phase_name) G1PPRL_BYTE_H_FORMAT G1PPRL_BYTE_H_FORMAT G1PPRL_DOUBLE_H_FORMAT + G1PPRL_BYTE_H_FORMAT G1PPRL_BYTE_H_FORMAT, "", "", - "(bytes)", "(bytes)", "(bytes)", "(bytes/ms)", "(bytes)"); + "(bytes)", "(bytes)", "(bytes)", "(bytes/ms)", + "(bytes)", "(bytes)"); } // It takes as a parameter a reference to one of the _hum_* fields, it @@ -4608,6 +4612,8 @@ bool G1PrintRegionLivenessInfoClosure::doHeapRegion(HeapRegion* r) { size_t next_live_bytes = r->next_live_bytes(); double gc_eff = r->gc_efficiency(); size_t remset_bytes = r->rem_set()->mem_size(); + size_t strong_code_roots_bytes = r->rem_set()->strong_code_roots_mem_size(); + if (r->used() == 0) { type = "FREE"; } else if (r->is_survivor()) { @@ -4642,6 +4648,7 @@ bool G1PrintRegionLivenessInfoClosure::doHeapRegion(HeapRegion* r) { _total_prev_live_bytes += prev_live_bytes; _total_next_live_bytes += next_live_bytes; _total_remset_bytes += remset_bytes; + _total_strong_code_roots_bytes += strong_code_roots_bytes; // Print a line for this particular region. _out->print_cr(G1PPRL_LINE_PREFIX @@ -4651,9 +4658,11 @@ bool G1PrintRegionLivenessInfoClosure::doHeapRegion(HeapRegion* r) { G1PPRL_BYTE_FORMAT G1PPRL_BYTE_FORMAT G1PPRL_DOUBLE_FORMAT + G1PPRL_BYTE_FORMAT G1PPRL_BYTE_FORMAT, type, bottom, end, - used_bytes, prev_live_bytes, next_live_bytes, gc_eff , remset_bytes); + used_bytes, prev_live_bytes, next_live_bytes, gc_eff, + remset_bytes, strong_code_roots_bytes); return false; } @@ -4669,7 +4678,8 @@ G1PrintRegionLivenessInfoClosure::~G1PrintRegionLivenessInfoClosure() { G1PPRL_SUM_MB_PERC_FORMAT("used") G1PPRL_SUM_MB_PERC_FORMAT("prev-live") G1PPRL_SUM_MB_PERC_FORMAT("next-live") - G1PPRL_SUM_MB_FORMAT("remset"), + G1PPRL_SUM_MB_FORMAT("remset") + G1PPRL_SUM_MB_FORMAT("code-roots"), bytes_to_mb(_total_capacity_bytes), bytes_to_mb(_total_used_bytes), perc(_total_used_bytes, _total_capacity_bytes), @@ -4677,6 +4687,7 @@ G1PrintRegionLivenessInfoClosure::~G1PrintRegionLivenessInfoClosure() { perc(_total_prev_live_bytes, _total_capacity_bytes), bytes_to_mb(_total_next_live_bytes), perc(_total_next_live_bytes, _total_capacity_bytes), - bytes_to_mb(_total_remset_bytes)); + bytes_to_mb(_total_remset_bytes), + bytes_to_mb(_total_strong_code_roots_bytes)); _out->cr(); } diff --git a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.hpp b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.hpp index 794224b66a7..a01024fcb9f 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.hpp @@ -1257,6 +1257,9 @@ private: // Accumulator for the remembered set size size_t _total_remset_bytes; + // Accumulator for strong code roots memory size + size_t _total_strong_code_roots_bytes; + static double perc(size_t val, size_t total) { if (total == 0) { return 0.0; diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp index bdd3027b995..976ec82c7e1 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp @@ -23,6 +23,7 @@ */ #include "precompiled.hpp" +#include "code/codeCache.hpp" #include "code/icBuffer.hpp" #include "gc_implementation/g1/bufferingOopClosure.hpp" #include "gc_implementation/g1/concurrentG1Refine.hpp" @@ -1176,20 +1177,27 @@ class PostMCRemSetClearClosure: public HeapRegionClosure { ModRefBarrierSet* _mr_bs; public: PostMCRemSetClearClosure(G1CollectedHeap* g1h, ModRefBarrierSet* mr_bs) : - _g1h(g1h), _mr_bs(mr_bs) { } + _g1h(g1h), _mr_bs(mr_bs) {} + bool doHeapRegion(HeapRegion* r) { + HeapRegionRemSet* hrrs = r->rem_set(); + if (r->continuesHumongous()) { + // We'll assert that the strong code root list and RSet is empty + assert(hrrs->strong_code_roots_list_length() == 0, "sanity"); + assert(hrrs->occupied() == 0, "RSet should be empty"); return false; } + _g1h->reset_gc_time_stamps(r); - HeapRegionRemSet* hrrs = r->rem_set(); - if (hrrs != NULL) hrrs->clear(); + hrrs->clear(); // You might think here that we could clear just the cards // corresponding to the used region. But no: if we leave a dirty card // in a region we might allocate into, then it would prevent that card // from being enqueued, and cause it to be missed. // Re: the performance cost: we shouldn't be doing full GC anyway! _mr_bs->clear(MemRegion(r->bottom(), r->end())); + return false; } }; @@ -1269,30 +1277,6 @@ void G1CollectedHeap::print_hrs_post_compaction() { heap_region_iterate(&cl); } -double G1CollectedHeap::verify(bool guard, const char* msg) { - double verify_time_ms = 0.0; - - if (guard && total_collections() >= VerifyGCStartAt) { - double verify_start = os::elapsedTime(); - HandleMark hm; // Discard invalid handles created during verification - prepare_for_verify(); - Universe::verify(VerifyOption_G1UsePrevMarking, msg); - verify_time_ms = (os::elapsedTime() - verify_start) * 1000; - } - - return verify_time_ms; -} - -void G1CollectedHeap::verify_before_gc() { - double verify_time_ms = verify(VerifyBeforeGC, " VerifyBeforeGC:"); - g1_policy()->phase_times()->record_verify_before_time_ms(verify_time_ms); -} - -void G1CollectedHeap::verify_after_gc() { - double verify_time_ms = verify(VerifyAfterGC, " VerifyAfterGC:"); - g1_policy()->phase_times()->record_verify_after_time_ms(verify_time_ms); -} - bool G1CollectedHeap::do_collection(bool explicit_gc, bool clear_all_soft_refs, size_t word_size) { @@ -1433,7 +1417,7 @@ bool G1CollectedHeap::do_collection(bool explicit_gc, // Delete metaspaces for unloaded class loaders and clean up loader_data graph ClassLoaderDataGraph::purge(); - MetaspaceAux::verify_metrics(); + MetaspaceAux::verify_metrics(); // Note: since we've just done a full GC, concurrent // marking is no longer active. Therefore we need not @@ -1504,6 +1488,9 @@ bool G1CollectedHeap::do_collection(bool explicit_gc, heap_region_iterate(&rebuild_rs); } + // Rebuild the strong code root lists for each region + rebuild_strong_code_roots(); + if (true) { // FIXME MetaspaceGC::compute_new_size(); } @@ -3109,6 +3096,145 @@ const char* G1CollectedHeap::top_at_mark_start_str(VerifyOption vo) { return NULL; // keep some compilers happy } +// TODO: VerifyRootsClosure extends OopsInGenClosure so that we can +// pass it as the perm_blk to SharedHeap::process_strong_roots. +// When process_strong_roots stop calling perm_blk->younger_refs_iterate +// we can change this closure to extend the simpler OopClosure. +class VerifyRootsClosure: public OopsInGenClosure { +private: + G1CollectedHeap* _g1h; + VerifyOption _vo; + bool _failures; +public: + // _vo == UsePrevMarking -> use "prev" marking information, + // _vo == UseNextMarking -> use "next" marking information, + // _vo == UseMarkWord -> use mark word from object header. + VerifyRootsClosure(VerifyOption vo) : + _g1h(G1CollectedHeap::heap()), + _vo(vo), + _failures(false) { } + + bool failures() { return _failures; } + + template void do_oop_nv(T* p) { + T heap_oop = oopDesc::load_heap_oop(p); + if (!oopDesc::is_null(heap_oop)) { + oop obj = oopDesc::decode_heap_oop_not_null(heap_oop); + if (_g1h->is_obj_dead_cond(obj, _vo)) { + gclog_or_tty->print_cr("Root location "PTR_FORMAT" " + "points to dead obj "PTR_FORMAT, p, (void*) obj); + if (_vo == VerifyOption_G1UseMarkWord) { + gclog_or_tty->print_cr(" Mark word: "PTR_FORMAT, (void*)(obj->mark())); + } + obj->print_on(gclog_or_tty); + _failures = true; + } + } + } + + void do_oop(oop* p) { do_oop_nv(p); } + void do_oop(narrowOop* p) { do_oop_nv(p); } +}; + +class G1VerifyCodeRootOopClosure: public OopsInGenClosure { + G1CollectedHeap* _g1h; + OopClosure* _root_cl; + nmethod* _nm; + VerifyOption _vo; + bool _failures; + + template void do_oop_work(T* p) { + // First verify that this root is live + _root_cl->do_oop(p); + + if (!G1VerifyHeapRegionCodeRoots) { + // We're not verifying the code roots attached to heap region. + return; + } + + // Don't check the code roots during marking verification in a full GC + if (_vo == VerifyOption_G1UseMarkWord) { + return; + } + + // Now verify that the current nmethod (which contains p) is + // in the code root list of the heap region containing the + // object referenced by p. + + T heap_oop = oopDesc::load_heap_oop(p); + if (!oopDesc::is_null(heap_oop)) { + oop obj = oopDesc::decode_heap_oop_not_null(heap_oop); + + // Now fetch the region containing the object + HeapRegion* hr = _g1h->heap_region_containing(obj); + HeapRegionRemSet* hrrs = hr->rem_set(); + // Verify that the strong code root list for this region + // contains the nmethod + if (!hrrs->strong_code_roots_list_contains(_nm)) { + gclog_or_tty->print_cr("Code root location "PTR_FORMAT" " + "from nmethod "PTR_FORMAT" not in strong " + "code roots for region ["PTR_FORMAT","PTR_FORMAT")", + p, _nm, hr->bottom(), hr->end()); + _failures = true; + } + } + } + +public: + G1VerifyCodeRootOopClosure(G1CollectedHeap* g1h, OopClosure* root_cl, VerifyOption vo): + _g1h(g1h), _root_cl(root_cl), _vo(vo), _nm(NULL), _failures(false) {} + + void do_oop(oop* p) { do_oop_work(p); } + void do_oop(narrowOop* p) { do_oop_work(p); } + + void set_nmethod(nmethod* nm) { _nm = nm; } + bool failures() { return _failures; } +}; + +class G1VerifyCodeRootBlobClosure: public CodeBlobClosure { + G1VerifyCodeRootOopClosure* _oop_cl; + +public: + G1VerifyCodeRootBlobClosure(G1VerifyCodeRootOopClosure* oop_cl): + _oop_cl(oop_cl) {} + + void do_code_blob(CodeBlob* cb) { + nmethod* nm = cb->as_nmethod_or_null(); + if (nm != NULL) { + _oop_cl->set_nmethod(nm); + nm->oops_do(_oop_cl); + } + } +}; + +class YoungRefCounterClosure : public OopClosure { + G1CollectedHeap* _g1h; + int _count; + public: + YoungRefCounterClosure(G1CollectedHeap* g1h) : _g1h(g1h), _count(0) {} + void do_oop(oop* p) { if (_g1h->is_in_young(*p)) { _count++; } } + void do_oop(narrowOop* p) { ShouldNotReachHere(); } + + int count() { return _count; } + void reset_count() { _count = 0; }; +}; + +class VerifyKlassClosure: public KlassClosure { + YoungRefCounterClosure _young_ref_counter_closure; + OopClosure *_oop_closure; + public: + VerifyKlassClosure(G1CollectedHeap* g1h, OopClosure* cl) : _young_ref_counter_closure(g1h), _oop_closure(cl) {} + void do_klass(Klass* k) { + k->oops_do(_oop_closure); + + _young_ref_counter_closure.reset_count(); + k->oops_do(&_young_ref_counter_closure); + if (_young_ref_counter_closure.count() > 0) { + guarantee(k->has_modified_oops(), err_msg("Klass %p, has young refs but is not dirty.", k)); + } + } +}; + class VerifyLivenessOopClosure: public OopClosure { G1CollectedHeap* _g1h; VerifyOption _vo; @@ -3242,75 +3368,7 @@ public: } }; -class YoungRefCounterClosure : public OopClosure { - G1CollectedHeap* _g1h; - int _count; - public: - YoungRefCounterClosure(G1CollectedHeap* g1h) : _g1h(g1h), _count(0) {} - void do_oop(oop* p) { if (_g1h->is_in_young(*p)) { _count++; } } - void do_oop(narrowOop* p) { ShouldNotReachHere(); } - - int count() { return _count; } - void reset_count() { _count = 0; }; -}; - -class VerifyKlassClosure: public KlassClosure { - YoungRefCounterClosure _young_ref_counter_closure; - OopClosure *_oop_closure; - public: - VerifyKlassClosure(G1CollectedHeap* g1h, OopClosure* cl) : _young_ref_counter_closure(g1h), _oop_closure(cl) {} - void do_klass(Klass* k) { - k->oops_do(_oop_closure); - - _young_ref_counter_closure.reset_count(); - k->oops_do(&_young_ref_counter_closure); - if (_young_ref_counter_closure.count() > 0) { - guarantee(k->has_modified_oops(), err_msg("Klass %p, has young refs but is not dirty.", k)); - } - } -}; - -// TODO: VerifyRootsClosure extends OopsInGenClosure so that we can -// pass it as the perm_blk to SharedHeap::process_strong_roots. -// When process_strong_roots stop calling perm_blk->younger_refs_iterate -// we can change this closure to extend the simpler OopClosure. -class VerifyRootsClosure: public OopsInGenClosure { -private: - G1CollectedHeap* _g1h; - VerifyOption _vo; - bool _failures; -public: - // _vo == UsePrevMarking -> use "prev" marking information, - // _vo == UseNextMarking -> use "next" marking information, - // _vo == UseMarkWord -> use mark word from object header. - VerifyRootsClosure(VerifyOption vo) : - _g1h(G1CollectedHeap::heap()), - _vo(vo), - _failures(false) { } - - bool failures() { return _failures; } - - template void do_oop_nv(T* p) { - T heap_oop = oopDesc::load_heap_oop(p); - if (!oopDesc::is_null(heap_oop)) { - oop obj = oopDesc::decode_heap_oop_not_null(heap_oop); - if (_g1h->is_obj_dead_cond(obj, _vo)) { - gclog_or_tty->print_cr("Root location "PTR_FORMAT" " - "points to dead obj "PTR_FORMAT, p, (void*) obj); - if (_vo == VerifyOption_G1UseMarkWord) { - gclog_or_tty->print_cr(" Mark word: "PTR_FORMAT, (void*)(obj->mark())); - } - obj->print_on(gclog_or_tty); - _failures = true; - } - } - } - - void do_oop(oop* p) { do_oop_nv(p); } - void do_oop(narrowOop* p) { do_oop_nv(p); } -}; - -// This is the task used for parallel heap verification. +// This is the task used for parallel verification of the heap regions class G1ParVerifyTask: public AbstractGangTask { private: @@ -3344,20 +3402,15 @@ public: } }; -void G1CollectedHeap::verify(bool silent) { - verify(silent, VerifyOption_G1UsePrevMarking); -} - -void G1CollectedHeap::verify(bool silent, - VerifyOption vo) { +void G1CollectedHeap::verify(bool silent, VerifyOption vo) { if (SafepointSynchronize::is_at_safepoint()) { - if (!silent) { gclog_or_tty->print("Roots "); } - VerifyRootsClosure rootsCl(vo); - assert(Thread::current()->is_VM_thread(), "Expected to be executed serially by the VM thread at this point"); - CodeBlobToOopClosure blobsCl(&rootsCl, /*do_marking=*/ false); + if (!silent) { gclog_or_tty->print("Roots "); } + VerifyRootsClosure rootsCl(vo); + G1VerifyCodeRootOopClosure codeRootsCl(this, &rootsCl, vo); + G1VerifyCodeRootBlobClosure blobsCl(&codeRootsCl); VerifyKlassClosure klassCl(this, &rootsCl); // We apply the relevant closures to all the oops in the @@ -3376,7 +3429,7 @@ void G1CollectedHeap::verify(bool silent, &klassCl ); - bool failures = rootsCl.failures(); + bool failures = rootsCl.failures() || codeRootsCl.failures(); if (vo != VerifyOption_G1UseMarkWord) { // If we're verifying during a full GC then the region sets @@ -3445,6 +3498,34 @@ void G1CollectedHeap::verify(bool silent, } } +void G1CollectedHeap::verify(bool silent) { + verify(silent, VerifyOption_G1UsePrevMarking); +} + +double G1CollectedHeap::verify(bool guard, const char* msg) { + double verify_time_ms = 0.0; + + if (guard && total_collections() >= VerifyGCStartAt) { + double verify_start = os::elapsedTime(); + HandleMark hm; // Discard invalid handles created during verification + prepare_for_verify(); + Universe::verify(VerifyOption_G1UsePrevMarking, msg); + verify_time_ms = (os::elapsedTime() - verify_start) * 1000; + } + + return verify_time_ms; +} + +void G1CollectedHeap::verify_before_gc() { + double verify_time_ms = verify(VerifyBeforeGC, " VerifyBeforeGC:"); + g1_policy()->phase_times()->record_verify_before_time_ms(verify_time_ms); +} + +void G1CollectedHeap::verify_after_gc() { + double verify_time_ms = verify(VerifyAfterGC, " VerifyAfterGC:"); + g1_policy()->phase_times()->record_verify_after_time_ms(verify_time_ms); +} + class PrintRegionClosure: public HeapRegionClosure { outputStream* _st; public: @@ -3866,8 +3947,9 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) { append_secondary_free_list_if_not_empty_with_lock(); } - assert(check_young_list_well_formed(), - "young list should be well formed"); + assert(check_young_list_well_formed(), "young list should be well formed"); + assert(check_heap_region_claim_values(HeapRegion::InitialClaimValue), + "sanity check"); // Don't dynamically change the number of GC threads this early. A value of // 0 is used to indicate serial work. When parallel work is done, @@ -4987,7 +5069,11 @@ public: G1ParPushHeapRSClosure push_heap_rs_cl(_g1h, &pss); - int so = SharedHeap::SO_AllClasses | SharedHeap::SO_Strings | SharedHeap::SO_CodeCache; + // Don't scan the scavengable methods in the code cache as part + // of strong root scanning. The code roots that point into a + // region in the collection set are scanned when we scan the + // region's RSet. + int so = SharedHeap::SO_AllClasses | SharedHeap::SO_Strings; pss.start_strong_roots(); _g1h->g1_process_strong_roots(/* is scavenging */ true, @@ -5029,67 +5115,6 @@ public: // *** Common G1 Evacuation Stuff -// Closures that support the filtering of CodeBlobs scanned during -// external root scanning. - -// Closure applied to reference fields in code blobs (specifically nmethods) -// to determine whether an nmethod contains references that point into -// the collection set. Used as a predicate when walking code roots so -// that only nmethods that point into the collection set are added to the -// 'marked' list. - -class G1FilteredCodeBlobToOopClosure : public CodeBlobToOopClosure { - - class G1PointsIntoCSOopClosure : public OopClosure { - G1CollectedHeap* _g1; - bool _points_into_cs; - public: - G1PointsIntoCSOopClosure(G1CollectedHeap* g1) : - _g1(g1), _points_into_cs(false) { } - - bool points_into_cs() const { return _points_into_cs; } - - template - void do_oop_nv(T* p) { - if (!_points_into_cs) { - T heap_oop = oopDesc::load_heap_oop(p); - if (!oopDesc::is_null(heap_oop) && - _g1->in_cset_fast_test(oopDesc::decode_heap_oop_not_null(heap_oop))) { - _points_into_cs = true; - } - } - } - - virtual void do_oop(oop* p) { do_oop_nv(p); } - virtual void do_oop(narrowOop* p) { do_oop_nv(p); } - }; - - G1CollectedHeap* _g1; - -public: - G1FilteredCodeBlobToOopClosure(G1CollectedHeap* g1, OopClosure* cl) : - CodeBlobToOopClosure(cl, true), _g1(g1) { } - - virtual void do_code_blob(CodeBlob* cb) { - nmethod* nm = cb->as_nmethod_or_null(); - if (nm != NULL && !(nm->test_oops_do_mark())) { - G1PointsIntoCSOopClosure predicate_cl(_g1); - nm->oops_do(&predicate_cl); - - if (predicate_cl.points_into_cs()) { - // At least one of the reference fields or the oop relocations - // in the nmethod points into the collection set. We have to - // 'mark' this nmethod. - // Note: Revisit the following if CodeBlobToOopClosure::do_code_blob() - // or MarkingCodeBlobClosure::do_code_blob() change. - if (!nm->test_set_oops_do_mark()) { - do_newly_marked_nmethod(nm); - } - } - } - } -}; - // This method is run in a GC worker. void @@ -5107,9 +5132,10 @@ g1_process_strong_roots(bool is_scavenging, BufferingOopClosure buf_scan_non_heap_roots(scan_non_heap_roots); - // Walk the code cache w/o buffering, because StarTask cannot handle - // unaligned oop locations. - G1FilteredCodeBlobToOopClosure eager_scan_code_roots(this, scan_non_heap_roots); + assert(so & SO_CodeCache || scan_rs != NULL, "must scan code roots somehow"); + // Walk the code cache/strong code roots w/o buffering, because StarTask + // cannot handle unaligned oop locations. + CodeBlobToOopClosure eager_scan_code_roots(scan_non_heap_roots, true /* do_marking */); process_strong_roots(false, // no scoping; this is parallel code is_scavenging, so, @@ -5154,9 +5180,22 @@ g1_process_strong_roots(bool is_scavenging, } g1_policy()->phase_times()->record_satb_filtering_time(worker_i, satb_filtering_ms); + // If this is an initial mark pause, and we're not scanning + // the entire code cache, we need to mark the oops in the + // strong code root lists for the regions that are not in + // the collection set. + // Note all threads participate in this set of root tasks. + double mark_strong_code_roots_ms = 0.0; + if (g1_policy()->during_initial_mark_pause() && !(so & SO_CodeCache)) { + double mark_strong_roots_start = os::elapsedTime(); + mark_strong_code_roots(worker_i); + mark_strong_code_roots_ms = (os::elapsedTime() - mark_strong_roots_start) * 1000.0; + } + g1_policy()->phase_times()->record_strong_code_root_mark_time(worker_i, mark_strong_code_roots_ms); + // Now scan the complement of the collection set. if (scan_rs != NULL) { - g1_rem_set()->oops_into_collection_set_do(scan_rs, worker_i); + g1_rem_set()->oops_into_collection_set_do(scan_rs, &eager_scan_code_roots, worker_i); } _process_strong_tasks->all_tasks_completed(); } @@ -5774,9 +5813,6 @@ void G1CollectedHeap::evacuate_collection_set(EvacuationInfo& evacuation_info) { process_discovered_references(n_workers); // Weak root processing. - // Note: when JSR 292 is enabled and code blobs can contain - // non-perm oops then we will need to process the code blobs - // here too. { G1STWIsAliveClosure is_alive(this); G1KeepAliveClosure keep_alive(this); @@ -5792,6 +5828,17 @@ void G1CollectedHeap::evacuate_collection_set(EvacuationInfo& evacuation_info) { hot_card_cache->reset_hot_cache(); hot_card_cache->set_use_cache(true); + // Migrate the strong code roots attached to each region in + // the collection set. Ideally we would like to do this + // after we have finished the scanning/evacuation of the + // strong code roots for a particular heap region. + migrate_strong_code_roots(); + + if (g1_policy()->during_initial_mark_pause()) { + // Reset the claim values set during marking the strong code roots + reset_heap_region_claim_values(); + } + finalize_for_evac_failure(); if (evacuation_failed()) { @@ -6588,3 +6635,204 @@ void G1CollectedHeap::verify_region_sets() { _humongous_set.verify_end(); _free_list.verify_end(); } + +// Optimized nmethod scanning + +class RegisterNMethodOopClosure: public OopClosure { + G1CollectedHeap* _g1h; + nmethod* _nm; + + template void do_oop_work(T* p) { + T heap_oop = oopDesc::load_heap_oop(p); + if (!oopDesc::is_null(heap_oop)) { + oop obj = oopDesc::decode_heap_oop_not_null(heap_oop); + HeapRegion* hr = _g1h->heap_region_containing(obj); + assert(!hr->isHumongous(), "code root in humongous region?"); + + // HeapRegion::add_strong_code_root() avoids adding duplicate + // entries but having duplicates is OK since we "mark" nmethods + // as visited when we scan the strong code root lists during the GC. + hr->add_strong_code_root(_nm); + assert(hr->rem_set()->strong_code_roots_list_contains(_nm), "add failed?"); + } + } + +public: + RegisterNMethodOopClosure(G1CollectedHeap* g1h, nmethod* nm) : + _g1h(g1h), _nm(nm) {} + + void do_oop(oop* p) { do_oop_work(p); } + void do_oop(narrowOop* p) { do_oop_work(p); } +}; + +class UnregisterNMethodOopClosure: public OopClosure { + G1CollectedHeap* _g1h; + nmethod* _nm; + + template void do_oop_work(T* p) { + T heap_oop = oopDesc::load_heap_oop(p); + if (!oopDesc::is_null(heap_oop)) { + oop obj = oopDesc::decode_heap_oop_not_null(heap_oop); + HeapRegion* hr = _g1h->heap_region_containing(obj); + assert(!hr->isHumongous(), "code root in humongous region?"); + hr->remove_strong_code_root(_nm); + assert(!hr->rem_set()->strong_code_roots_list_contains(_nm), "remove failed?"); + } + } + +public: + UnregisterNMethodOopClosure(G1CollectedHeap* g1h, nmethod* nm) : + _g1h(g1h), _nm(nm) {} + + void do_oop(oop* p) { do_oop_work(p); } + void do_oop(narrowOop* p) { do_oop_work(p); } +}; + +void G1CollectedHeap::register_nmethod(nmethod* nm) { + CollectedHeap::register_nmethod(nm); + + guarantee(nm != NULL, "sanity"); + RegisterNMethodOopClosure reg_cl(this, nm); + nm->oops_do(®_cl); +} + +void G1CollectedHeap::unregister_nmethod(nmethod* nm) { + CollectedHeap::unregister_nmethod(nm); + + guarantee(nm != NULL, "sanity"); + UnregisterNMethodOopClosure reg_cl(this, nm); + nm->oops_do(®_cl, true); +} + +class MigrateCodeRootsHeapRegionClosure: public HeapRegionClosure { +public: + bool doHeapRegion(HeapRegion *hr) { + assert(!hr->isHumongous(), "humongous region in collection set?"); + hr->migrate_strong_code_roots(); + return false; + } +}; + +void G1CollectedHeap::migrate_strong_code_roots() { + MigrateCodeRootsHeapRegionClosure cl; + double migrate_start = os::elapsedTime(); + collection_set_iterate(&cl); + double migration_time_ms = (os::elapsedTime() - migrate_start) * 1000.0; + g1_policy()->phase_times()->record_strong_code_root_migration_time(migration_time_ms); +} + +// Mark all the code roots that point into regions *not* in the +// collection set. +// +// Note we do not want to use a "marking" CodeBlobToOopClosure while +// walking the the code roots lists of regions not in the collection +// set. Suppose we have an nmethod (M) that points to objects in two +// separate regions - one in the collection set (R1) and one not (R2). +// Using a "marking" CodeBlobToOopClosure here would result in "marking" +// nmethod M when walking the code roots for R1. When we come to scan +// the code roots for R2, we would see that M is already marked and it +// would be skipped and the objects in R2 that are referenced from M +// would not be evacuated. + +class MarkStrongCodeRootCodeBlobClosure: public CodeBlobClosure { + + class MarkStrongCodeRootOopClosure: public OopClosure { + ConcurrentMark* _cm; + HeapRegion* _hr; + uint _worker_id; + + template void do_oop_work(T* p) { + T heap_oop = oopDesc::load_heap_oop(p); + if (!oopDesc::is_null(heap_oop)) { + oop obj = oopDesc::decode_heap_oop_not_null(heap_oop); + // Only mark objects in the region (which is assumed + // to be not in the collection set). + if (_hr->is_in(obj)) { + _cm->grayRoot(obj, (size_t) obj->size(), _worker_id); + } + } + } + + public: + MarkStrongCodeRootOopClosure(ConcurrentMark* cm, HeapRegion* hr, uint worker_id) : + _cm(cm), _hr(hr), _worker_id(worker_id) { + assert(!_hr->in_collection_set(), "sanity"); + } + + void do_oop(narrowOop* p) { do_oop_work(p); } + void do_oop(oop* p) { do_oop_work(p); } + }; + + MarkStrongCodeRootOopClosure _oop_cl; + +public: + MarkStrongCodeRootCodeBlobClosure(ConcurrentMark* cm, HeapRegion* hr, uint worker_id): + _oop_cl(cm, hr, worker_id) {} + + void do_code_blob(CodeBlob* cb) { + nmethod* nm = (cb == NULL) ? NULL : cb->as_nmethod_or_null(); + if (nm != NULL) { + nm->oops_do(&_oop_cl); + } + } +}; + +class MarkStrongCodeRootsHRClosure: public HeapRegionClosure { + G1CollectedHeap* _g1h; + uint _worker_id; + +public: + MarkStrongCodeRootsHRClosure(G1CollectedHeap* g1h, uint worker_id) : + _g1h(g1h), _worker_id(worker_id) {} + + bool doHeapRegion(HeapRegion *hr) { + HeapRegionRemSet* hrrs = hr->rem_set(); + if (hr->isHumongous()) { + // Code roots should never be attached to a humongous region + assert(hrrs->strong_code_roots_list_length() == 0, "sanity"); + return false; + } + + if (hr->in_collection_set()) { + // Don't mark code roots into regions in the collection set here. + // They will be marked when we scan them. + return false; + } + + MarkStrongCodeRootCodeBlobClosure cb_cl(_g1h->concurrent_mark(), hr, _worker_id); + hr->strong_code_roots_do(&cb_cl); + return false; + } +}; + +void G1CollectedHeap::mark_strong_code_roots(uint worker_id) { + MarkStrongCodeRootsHRClosure cl(this, worker_id); + heap_region_par_iterate_chunked(&cl, + worker_id, + workers()->active_workers(), + HeapRegion::ParMarkRootClaimValue); +} + +class RebuildStrongCodeRootClosure: public CodeBlobClosure { + G1CollectedHeap* _g1h; + +public: + RebuildStrongCodeRootClosure(G1CollectedHeap* g1h) : + _g1h(g1h) {} + + void do_code_blob(CodeBlob* cb) { + nmethod* nm = (cb != NULL) ? cb->as_nmethod_or_null() : NULL; + if (nm == NULL) { + return; + } + + if (ScavengeRootsInCode && nm->detect_scavenge_root_oops()) { + _g1h->register_nmethod(nm); + } + } +}; + +void G1CollectedHeap::rebuild_strong_code_roots() { + RebuildStrongCodeRootClosure blob_cl(this); + CodeCache::blobs_do(&blob_cl); +} diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp index 9b52304c996..cfcbb3f7c94 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp @@ -46,6 +46,7 @@ // may combine concurrent marking with parallel, incremental compaction of // heap subsets that will yield large amounts of garbage. +// Forward declarations class HeapRegion; class HRRSCleanupTask; class GenerationSpec; @@ -69,6 +70,7 @@ class STWGCTimer; class G1NewTracer; class G1OldTracer; class EvacuationFailedInfo; +class nmethod; typedef OverflowTaskQueue RefToScanQueue; typedef GenericTaskQueueSet RefToScanQueueSet; @@ -163,18 +165,6 @@ public: : G1AllocRegion("Mutator Alloc Region", false /* bot_updates */) { } }; -// The G1 STW is alive closure. -// An instance is embedded into the G1CH and used as the -// (optional) _is_alive_non_header closure in the STW -// reference processor. It is also extensively used during -// reference processing during STW evacuation pauses. -class G1STWIsAliveClosure: public BoolObjectClosure { - G1CollectedHeap* _g1; -public: - G1STWIsAliveClosure(G1CollectedHeap* g1) : _g1(g1) {} - bool do_object_b(oop p); -}; - class SurvivorGCAllocRegion : public G1AllocRegion { protected: virtual HeapRegion* allocate_new_region(size_t word_size, bool force); @@ -193,6 +183,18 @@ public: : G1AllocRegion("Old GC Alloc Region", true /* bot_updates */) { } }; +// The G1 STW is alive closure. +// An instance is embedded into the G1CH and used as the +// (optional) _is_alive_non_header closure in the STW +// reference processor. It is also extensively used during +// reference processing during STW evacuation pauses. +class G1STWIsAliveClosure: public BoolObjectClosure { + G1CollectedHeap* _g1; +public: + G1STWIsAliveClosure(G1CollectedHeap* g1) : _g1(g1) {} + bool do_object_b(oop p); +}; + class RefineCardTableEntryClosure; class G1CollectedHeap : public SharedHeap { @@ -1549,42 +1551,6 @@ public: virtual jlong millis_since_last_gc(); - // Perform any cleanup actions necessary before allowing a verification. - virtual void prepare_for_verify(); - - // Perform verification. - - // vo == UsePrevMarking -> use "prev" marking information, - // vo == UseNextMarking -> use "next" marking information - // vo == UseMarkWord -> use the mark word in the object header - // - // NOTE: Only the "prev" marking information is guaranteed to be - // consistent most of the time, so most calls to this should use - // vo == UsePrevMarking. - // Currently, there is only one case where this is called with - // vo == UseNextMarking, which is to verify the "next" marking - // information at the end of remark. - // Currently there is only one place where this is called with - // vo == UseMarkWord, which is to verify the marking during a - // full GC. - void verify(bool silent, VerifyOption vo); - - // Override; it uses the "prev" marking information - virtual void verify(bool silent); - - virtual void print_on(outputStream* st) const; - virtual void print_extended_on(outputStream* st) const; - virtual void print_on_error(outputStream* st) const; - - virtual void print_gc_threads_on(outputStream* st) const; - virtual void gc_threads_do(ThreadClosure* tc) const; - - // Override - void print_tracing_info() const; - - // The following two methods are helpful for debugging RSet issues. - void print_cset_rsets() PRODUCT_RETURN; - void print_all_rsets() PRODUCT_RETURN; // Convenience function to be used in situations where the heap type can be // asserted to be this type. @@ -1661,13 +1627,86 @@ public: else return is_obj_ill(obj, hr); } + bool allocated_since_marking(oop obj, HeapRegion* hr, VerifyOption vo); + HeapWord* top_at_mark_start(HeapRegion* hr, VerifyOption vo); + bool is_marked(oop obj, VerifyOption vo); + const char* top_at_mark_start_str(VerifyOption vo); + + ConcurrentMark* concurrent_mark() const { return _cm; } + + // Refinement + + ConcurrentG1Refine* concurrent_g1_refine() const { return _cg1r; } + + // The dirty cards region list is used to record a subset of regions + // whose cards need clearing. The list if populated during the + // remembered set scanning and drained during the card table + // cleanup. Although the methods are reentrant, population/draining + // phases must not overlap. For synchronization purposes the last + // element on the list points to itself. + HeapRegion* _dirty_cards_region_list; + void push_dirty_cards_region(HeapRegion* hr); + HeapRegion* pop_dirty_cards_region(); + + // Optimized nmethod scanning support routines + + // Register the given nmethod with the G1 heap + virtual void register_nmethod(nmethod* nm); + + // Unregister the given nmethod from the G1 heap + virtual void unregister_nmethod(nmethod* nm); + + // Migrate the nmethods in the code root lists of the regions + // in the collection set to regions in to-space. In the event + // of an evacuation failure, nmethods that reference objects + // that were not successfullly evacuated are not migrated. + void migrate_strong_code_roots(); + + // During an initial mark pause, mark all the code roots that + // point into regions *not* in the collection set. + void mark_strong_code_roots(uint worker_id); + + // Rebuild the stong code root lists for each region + // after a full GC + void rebuild_strong_code_roots(); + + // Verification + + // The following is just to alert the verification code + // that a full collection has occurred and that the + // remembered sets are no longer up to date. + bool _full_collection; + void set_full_collection() { _full_collection = true;} + void clear_full_collection() {_full_collection = false;} + bool full_collection() {return _full_collection;} + + // Perform any cleanup actions necessary before allowing a verification. + virtual void prepare_for_verify(); + + // Perform verification. + + // vo == UsePrevMarking -> use "prev" marking information, + // vo == UseNextMarking -> use "next" marking information + // vo == UseMarkWord -> use the mark word in the object header + // + // NOTE: Only the "prev" marking information is guaranteed to be + // consistent most of the time, so most calls to this should use + // vo == UsePrevMarking. + // Currently, there is only one case where this is called with + // vo == UseNextMarking, which is to verify the "next" marking + // information at the end of remark. + // Currently there is only one place where this is called with + // vo == UseMarkWord, which is to verify the marking during a + // full GC. + void verify(bool silent, VerifyOption vo); + + // Override; it uses the "prev" marking information + virtual void verify(bool silent); + // The methods below are here for convenience and dispatch the // appropriate method depending on value of the given VerifyOption - // parameter. The options for that parameter are: - // - // vo == UsePrevMarking -> use "prev" marking information, - // vo == UseNextMarking -> use "next" marking information, - // vo == UseMarkWord -> use mark word from object header + // parameter. The values for that parameter, and their meanings, + // are the same as those above. bool is_obj_dead_cond(const oop obj, const HeapRegion* hr, @@ -1692,31 +1731,21 @@ public: return false; // keep some compilers happy } - bool allocated_since_marking(oop obj, HeapRegion* hr, VerifyOption vo); - HeapWord* top_at_mark_start(HeapRegion* hr, VerifyOption vo); - bool is_marked(oop obj, VerifyOption vo); - const char* top_at_mark_start_str(VerifyOption vo); + // Printing - // The following is just to alert the verification code - // that a full collection has occurred and that the - // remembered sets are no longer up to date. - bool _full_collection; - void set_full_collection() { _full_collection = true;} - void clear_full_collection() {_full_collection = false;} - bool full_collection() {return _full_collection;} + virtual void print_on(outputStream* st) const; + virtual void print_extended_on(outputStream* st) const; + virtual void print_on_error(outputStream* st) const; - ConcurrentMark* concurrent_mark() const { return _cm; } - ConcurrentG1Refine* concurrent_g1_refine() const { return _cg1r; } + virtual void print_gc_threads_on(outputStream* st) const; + virtual void gc_threads_do(ThreadClosure* tc) const; - // The dirty cards region list is used to record a subset of regions - // whose cards need clearing. The list if populated during the - // remembered set scanning and drained during the card table - // cleanup. Although the methods are reentrant, population/draining - // phases must not overlap. For synchronization purposes the last - // element on the list points to itself. - HeapRegion* _dirty_cards_region_list; - void push_dirty_cards_region(HeapRegion* hr); - HeapRegion* pop_dirty_cards_region(); + // Override + void print_tracing_info() const; + + // The following two methods are helpful for debugging RSet issues. + void print_cset_rsets() PRODUCT_RETURN; + void print_all_rsets() PRODUCT_RETURN; public: void stop_conc_gc_threads(); diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.cpp index f6d3b6f4bd9..0eda4b35d71 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.cpp @@ -161,6 +161,8 @@ G1GCPhaseTimes::G1GCPhaseTimes(uint max_gc_threads) : _last_update_rs_times_ms(_max_gc_threads, "%.1lf"), _last_update_rs_processed_buffers(_max_gc_threads, "%d"), _last_scan_rs_times_ms(_max_gc_threads, "%.1lf"), + _last_strong_code_root_scan_times_ms(_max_gc_threads, "%.1lf"), + _last_strong_code_root_mark_times_ms(_max_gc_threads, "%.1lf"), _last_obj_copy_times_ms(_max_gc_threads, "%.1lf"), _last_termination_times_ms(_max_gc_threads, "%.1lf"), _last_termination_attempts(_max_gc_threads, SIZE_FORMAT), @@ -182,6 +184,8 @@ void G1GCPhaseTimes::note_gc_start(uint active_gc_threads) { _last_update_rs_times_ms.reset(); _last_update_rs_processed_buffers.reset(); _last_scan_rs_times_ms.reset(); + _last_strong_code_root_scan_times_ms.reset(); + _last_strong_code_root_mark_times_ms.reset(); _last_obj_copy_times_ms.reset(); _last_termination_times_ms.reset(); _last_termination_attempts.reset(); @@ -197,6 +201,8 @@ void G1GCPhaseTimes::note_gc_end() { _last_update_rs_times_ms.verify(); _last_update_rs_processed_buffers.verify(); _last_scan_rs_times_ms.verify(); + _last_strong_code_root_scan_times_ms.verify(); + _last_strong_code_root_mark_times_ms.verify(); _last_obj_copy_times_ms.verify(); _last_termination_times_ms.verify(); _last_termination_attempts.verify(); @@ -210,6 +216,8 @@ void G1GCPhaseTimes::note_gc_end() { _last_satb_filtering_times_ms.get(i) + _last_update_rs_times_ms.get(i) + _last_scan_rs_times_ms.get(i) + + _last_strong_code_root_scan_times_ms.get(i) + + _last_strong_code_root_mark_times_ms.get(i) + _last_obj_copy_times_ms.get(i) + _last_termination_times_ms.get(i); @@ -239,6 +247,9 @@ double G1GCPhaseTimes::accounted_time_ms() { // Now subtract the time taken to fix up roots in generated code misc_time_ms += _cur_collection_code_root_fixup_time_ms; + // Strong code root migration time + misc_time_ms += _cur_strong_code_root_migration_time_ms; + // Subtract the time taken to clean the card table from the // current value of "other time" misc_time_ms += _cur_clear_ct_time_ms; @@ -257,9 +268,13 @@ void G1GCPhaseTimes::print(double pause_time_sec) { if (_last_satb_filtering_times_ms.sum() > 0.0) { _last_satb_filtering_times_ms.print(2, "SATB Filtering (ms)"); } + if (_last_strong_code_root_mark_times_ms.sum() > 0.0) { + _last_strong_code_root_mark_times_ms.print(2, "Code Root Marking (ms)"); + } _last_update_rs_times_ms.print(2, "Update RS (ms)"); _last_update_rs_processed_buffers.print(3, "Processed Buffers"); _last_scan_rs_times_ms.print(2, "Scan RS (ms)"); + _last_strong_code_root_scan_times_ms.print(2, "Code Root Scanning (ms)"); _last_obj_copy_times_ms.print(2, "Object Copy (ms)"); _last_termination_times_ms.print(2, "Termination (ms)"); if (G1Log::finest()) { @@ -273,12 +288,17 @@ void G1GCPhaseTimes::print(double pause_time_sec) { if (_last_satb_filtering_times_ms.sum() > 0.0) { _last_satb_filtering_times_ms.print(1, "SATB Filtering (ms)"); } + if (_last_strong_code_root_mark_times_ms.sum() > 0.0) { + _last_strong_code_root_mark_times_ms.print(1, "Code Root Marking (ms)"); + } _last_update_rs_times_ms.print(1, "Update RS (ms)"); _last_update_rs_processed_buffers.print(2, "Processed Buffers"); _last_scan_rs_times_ms.print(1, "Scan RS (ms)"); + _last_strong_code_root_scan_times_ms.print(1, "Code Root Scanning (ms)"); _last_obj_copy_times_ms.print(1, "Object Copy (ms)"); } print_stats(1, "Code Root Fixup", _cur_collection_code_root_fixup_time_ms); + print_stats(1, "Code Root Migration", _cur_strong_code_root_migration_time_ms); print_stats(1, "Clear CT", _cur_clear_ct_time_ms); double misc_time_ms = pause_time_sec * MILLIUNITS - accounted_time_ms(); print_stats(1, "Other", misc_time_ms); diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.hpp index a1c5739f1ae..b2de97dc4b6 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1GCPhaseTimes.hpp @@ -119,6 +119,8 @@ class G1GCPhaseTimes : public CHeapObj { WorkerDataArray _last_update_rs_times_ms; WorkerDataArray _last_update_rs_processed_buffers; WorkerDataArray _last_scan_rs_times_ms; + WorkerDataArray _last_strong_code_root_scan_times_ms; + WorkerDataArray _last_strong_code_root_mark_times_ms; WorkerDataArray _last_obj_copy_times_ms; WorkerDataArray _last_termination_times_ms; WorkerDataArray _last_termination_attempts; @@ -128,6 +130,7 @@ class G1GCPhaseTimes : public CHeapObj { double _cur_collection_par_time_ms; double _cur_collection_code_root_fixup_time_ms; + double _cur_strong_code_root_migration_time_ms; double _cur_clear_ct_time_ms; double _cur_ref_proc_time_ms; @@ -179,6 +182,14 @@ class G1GCPhaseTimes : public CHeapObj { _last_scan_rs_times_ms.set(worker_i, ms); } + void record_strong_code_root_scan_time(uint worker_i, double ms) { + _last_strong_code_root_scan_times_ms.set(worker_i, ms); + } + + void record_strong_code_root_mark_time(uint worker_i, double ms) { + _last_strong_code_root_mark_times_ms.set(worker_i, ms); + } + void record_obj_copy_time(uint worker_i, double ms) { _last_obj_copy_times_ms.set(worker_i, ms); } @@ -208,6 +219,10 @@ class G1GCPhaseTimes : public CHeapObj { _cur_collection_code_root_fixup_time_ms = ms; } + void record_strong_code_root_migration_time(double ms) { + _cur_strong_code_root_migration_time_ms = ms; + } + void record_ref_proc_time(double ms) { _cur_ref_proc_time_ms = ms; } @@ -294,6 +309,14 @@ class G1GCPhaseTimes : public CHeapObj { return _last_scan_rs_times_ms.average(); } + double average_last_strong_code_root_scan_time(){ + return _last_strong_code_root_scan_times_ms.average(); + } + + double average_last_strong_code_root_mark_time(){ + return _last_strong_code_root_mark_times_ms.average(); + } + double average_last_obj_copy_time() { return _last_obj_copy_times_ms.average(); } diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp index 673814ce971..5a1b92d3422 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp @@ -104,15 +104,25 @@ void CountNonCleanMemRegionClosure::do_MemRegion(MemRegion mr) { class ScanRSClosure : public HeapRegionClosure { size_t _cards_done, _cards; G1CollectedHeap* _g1h; + OopsInHeapRegionClosure* _oc; + CodeBlobToOopClosure* _code_root_cl; + G1BlockOffsetSharedArray* _bot_shared; CardTableModRefBS *_ct_bs; - int _worker_i; - int _block_size; - bool _try_claimed; + + double _strong_code_root_scan_time_sec; + int _worker_i; + int _block_size; + bool _try_claimed; + public: - ScanRSClosure(OopsInHeapRegionClosure* oc, int worker_i) : + ScanRSClosure(OopsInHeapRegionClosure* oc, + CodeBlobToOopClosure* code_root_cl, + int worker_i) : _oc(oc), + _code_root_cl(code_root_cl), + _strong_code_root_scan_time_sec(0.0), _cards(0), _cards_done(0), _worker_i(worker_i), @@ -160,6 +170,12 @@ public: card_start, card_start + G1BlockOffsetSharedArray::N_words); } + void scan_strong_code_roots(HeapRegion* r) { + double scan_start = os::elapsedTime(); + r->strong_code_roots_do(_code_root_cl); + _strong_code_root_scan_time_sec += (os::elapsedTime() - scan_start); + } + bool doHeapRegion(HeapRegion* r) { assert(r->in_collection_set(), "should only be called on elements of CS."); HeapRegionRemSet* hrrs = r->rem_set(); @@ -173,6 +189,7 @@ public: // _try_claimed || r->claim_iter() // is true: either we're supposed to work on claimed-but-not-complete // regions, or we successfully claimed the region. + HeapRegionRemSetIterator iter(hrrs); size_t card_index; @@ -205,30 +222,43 @@ public: } } if (!_try_claimed) { + // Scan the strong code root list attached to the current region + scan_strong_code_roots(r); + hrrs->set_iter_complete(); } return false; } + + double strong_code_root_scan_time_sec() { + return _strong_code_root_scan_time_sec; + } + size_t cards_done() { return _cards_done;} size_t cards_looked_up() { return _cards;} }; -void G1RemSet::scanRS(OopsInHeapRegionClosure* oc, int worker_i) { +void G1RemSet::scanRS(OopsInHeapRegionClosure* oc, + CodeBlobToOopClosure* code_root_cl, + int worker_i) { double rs_time_start = os::elapsedTime(); HeapRegion *startRegion = _g1->start_cset_region_for_worker(worker_i); - ScanRSClosure scanRScl(oc, worker_i); + ScanRSClosure scanRScl(oc, code_root_cl, worker_i); _g1->collection_set_iterate_from(startRegion, &scanRScl); scanRScl.set_try_claimed(); _g1->collection_set_iterate_from(startRegion, &scanRScl); - double scan_rs_time_sec = os::elapsedTime() - rs_time_start; + double scan_rs_time_sec = (os::elapsedTime() - rs_time_start) + - scanRScl.strong_code_root_scan_time_sec(); - assert( _cards_scanned != NULL, "invariant" ); + assert(_cards_scanned != NULL, "invariant"); _cards_scanned[worker_i] = scanRScl.cards_done(); _g1p->phase_times()->record_scan_rs_time(worker_i, scan_rs_time_sec * 1000.0); + _g1p->phase_times()->record_strong_code_root_scan_time(worker_i, + scanRScl.strong_code_root_scan_time_sec() * 1000.0); } // Closure used for updating RSets and recording references that @@ -288,7 +318,8 @@ void G1RemSet::cleanupHRRS() { } void G1RemSet::oops_into_collection_set_do(OopsInHeapRegionClosure* oc, - int worker_i) { + CodeBlobToOopClosure* code_root_cl, + int worker_i) { #if CARD_REPEAT_HISTO ct_freq_update_histo_and_reset(); #endif @@ -328,7 +359,7 @@ void G1RemSet::oops_into_collection_set_do(OopsInHeapRegionClosure* oc, _g1p->phase_times()->record_update_rs_time(worker_i, 0.0); } if (G1UseParallelRSetScanning || (worker_i == 0)) { - scanRS(oc, worker_i); + scanRS(oc, code_root_cl, worker_i); } else { _g1p->phase_times()->record_scan_rs_time(worker_i, 0.0); } diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.hpp index 954381f9138..513945609fc 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.hpp @@ -81,14 +81,23 @@ public: G1RemSet(G1CollectedHeap* g1, CardTableModRefBS* ct_bs); ~G1RemSet(); - // Invoke "blk->do_oop" on all pointers into the CS in objects in regions - // outside the CS (having invoked "blk->set_region" to set the "from" - // region correctly beforehand.) The "worker_i" param is for the - // parallel case where the number of the worker thread calling this - // function can be helpful in partitioning the work to be done. It - // should be the same as the "i" passed to the calling thread's - // work(i) function. In the sequential case this param will be ingored. - void oops_into_collection_set_do(OopsInHeapRegionClosure* blk, int worker_i); + // Invoke "blk->do_oop" on all pointers into the collection set + // from objects in regions outside the collection set (having + // invoked "blk->set_region" to set the "from" region correctly + // beforehand.) + // + // Invoke code_root_cl->do_code_blob on the unmarked nmethods + // on the strong code roots list for each region in the + // collection set. + // + // The "worker_i" param is for the parallel case where the id + // of the worker thread calling this function can be helpful in + // partitioning the work to be done. It should be the same as + // the "i" passed to the calling thread's work(i) function. + // In the sequential case this param will be ignored. + void oops_into_collection_set_do(OopsInHeapRegionClosure* blk, + CodeBlobToOopClosure* code_root_cl, + int worker_i); // Prepare for and cleanup after an oops_into_collection_set_do // call. Must call each of these once before and after (in sequential @@ -98,7 +107,10 @@ public: void prepare_for_oops_into_collection_set_do(); void cleanup_after_oops_into_collection_set_do(); - void scanRS(OopsInHeapRegionClosure* oc, int worker_i); + void scanRS(OopsInHeapRegionClosure* oc, + CodeBlobToOopClosure* code_root_cl, + int worker_i); + void updateRS(DirtyCardQueue* into_cset_dcq, int worker_i); CardTableModRefBS* ct_bs() { return _ct_bs; } diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1RemSetSummary.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1RemSetSummary.cpp index 13acd1b0da8..4a6b37654d7 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1RemSetSummary.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1RemSetSummary.cpp @@ -127,32 +127,55 @@ void G1RemSetSummary::subtract_from(G1RemSetSummary* other) { class HRRSStatsIter: public HeapRegionClosure { size_t _occupied; - size_t _total_mem_sz; - size_t _max_mem_sz; - HeapRegion* _max_mem_sz_region; + + size_t _total_rs_mem_sz; + size_t _max_rs_mem_sz; + HeapRegion* _max_rs_mem_sz_region; + + size_t _total_code_root_mem_sz; + size_t _max_code_root_mem_sz; + HeapRegion* _max_code_root_mem_sz_region; public: HRRSStatsIter() : _occupied(0), - _total_mem_sz(0), - _max_mem_sz(0), - _max_mem_sz_region(NULL) + _total_rs_mem_sz(0), + _max_rs_mem_sz(0), + _max_rs_mem_sz_region(NULL), + _total_code_root_mem_sz(0), + _max_code_root_mem_sz(0), + _max_code_root_mem_sz_region(NULL) {} bool doHeapRegion(HeapRegion* r) { - size_t mem_sz = r->rem_set()->mem_size(); - if (mem_sz > _max_mem_sz) { - _max_mem_sz = mem_sz; - _max_mem_sz_region = r; + HeapRegionRemSet* hrrs = r->rem_set(); + + // HeapRegionRemSet::mem_size() includes the + // size of the strong code roots + size_t rs_mem_sz = hrrs->mem_size(); + if (rs_mem_sz > _max_rs_mem_sz) { + _max_rs_mem_sz = rs_mem_sz; + _max_rs_mem_sz_region = r; } - _total_mem_sz += mem_sz; - size_t occ = r->rem_set()->occupied(); + _total_rs_mem_sz += rs_mem_sz; + + size_t code_root_mem_sz = hrrs->strong_code_roots_mem_size(); + if (code_root_mem_sz > _max_code_root_mem_sz) { + _max_code_root_mem_sz = code_root_mem_sz; + _max_code_root_mem_sz_region = r; + } + _total_code_root_mem_sz += code_root_mem_sz; + + size_t occ = hrrs->occupied(); _occupied += occ; return false; } - size_t total_mem_sz() { return _total_mem_sz; } - size_t max_mem_sz() { return _max_mem_sz; } + size_t total_rs_mem_sz() { return _total_rs_mem_sz; } + size_t max_rs_mem_sz() { return _max_rs_mem_sz; } + HeapRegion* max_rs_mem_sz_region() { return _max_rs_mem_sz_region; } + size_t total_code_root_mem_sz() { return _total_code_root_mem_sz; } + size_t max_code_root_mem_sz() { return _max_code_root_mem_sz; } + HeapRegion* max_code_root_mem_sz_region() { return _max_code_root_mem_sz_region; } size_t occupied() { return _occupied; } - HeapRegion* max_mem_sz_region() { return _max_mem_sz_region; } }; double calc_percentage(size_t numerator, size_t denominator) { @@ -184,22 +207,33 @@ void G1RemSetSummary::print_on(outputStream* out) { HRRSStatsIter blk; G1CollectedHeap::heap()->heap_region_iterate(&blk); + // RemSet stats out->print_cr(" Total heap region rem set sizes = "SIZE_FORMAT"K." " Max = "SIZE_FORMAT"K.", - blk.total_mem_sz()/K, blk.max_mem_sz()/K); + blk.total_rs_mem_sz()/K, blk.max_rs_mem_sz()/K); out->print_cr(" Static structures = "SIZE_FORMAT"K," " free_lists = "SIZE_FORMAT"K.", HeapRegionRemSet::static_mem_size() / K, HeapRegionRemSet::fl_mem_size() / K); out->print_cr(" "SIZE_FORMAT" occupied cards represented.", blk.occupied()); - HeapRegion* max_mem_sz_region = blk.max_mem_sz_region(); - HeapRegionRemSet* rem_set = max_mem_sz_region->rem_set(); + HeapRegion* max_rs_mem_sz_region = blk.max_rs_mem_sz_region(); + HeapRegionRemSet* max_rs_rem_set = max_rs_mem_sz_region->rem_set(); out->print_cr(" Max size region = "HR_FORMAT", " "size = "SIZE_FORMAT "K, occupied = "SIZE_FORMAT"K.", - HR_FORMAT_PARAMS(max_mem_sz_region), - (rem_set->mem_size() + K - 1)/K, - (rem_set->occupied() + K - 1)/K); - + HR_FORMAT_PARAMS(max_rs_mem_sz_region), + (max_rs_rem_set->mem_size() + K - 1)/K, + (max_rs_rem_set->occupied() + K - 1)/K); out->print_cr(" Did %d coarsenings.", num_coarsenings()); + // Strong code root stats + out->print_cr(" Total heap region code-root set sizes = "SIZE_FORMAT"K." + " Max = "SIZE_FORMAT"K.", + blk.total_code_root_mem_sz()/K, blk.max_code_root_mem_sz()/K); + HeapRegion* max_code_root_mem_sz_region = blk.max_code_root_mem_sz_region(); + HeapRegionRemSet* max_code_root_rem_set = max_code_root_mem_sz_region->rem_set(); + out->print_cr(" Max size region = "HR_FORMAT", " + "size = "SIZE_FORMAT "K, num_elems = "SIZE_FORMAT".", + HR_FORMAT_PARAMS(max_code_root_mem_sz_region), + (max_code_root_rem_set->strong_code_roots_mem_size() + K - 1)/K, + (max_code_root_rem_set->strong_code_roots_list_length())); } diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1_globals.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1_globals.hpp index 3387dc44f0a..c7d8049fea0 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1_globals.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1_globals.hpp @@ -319,7 +319,10 @@ \ diagnostic(bool, G1VerifyRSetsDuringFullGC, false, \ "If true, perform verification of each heap region's " \ - "remembered set when verifying the heap during a full GC.") + "remembered set when verifying the heap during a full GC.") \ + \ + diagnostic(bool, G1VerifyHeapRegionCodeRoots, false, \ + "Verify the code root lists attached to each heap region.") G1_FLAGS(DECLARE_DEVELOPER_FLAG, DECLARE_PD_DEVELOPER_FLAG, DECLARE_PRODUCT_FLAG, DECLARE_PD_PRODUCT_FLAG, DECLARE_DIAGNOSTIC_FLAG, DECLARE_EXPERIMENTAL_FLAG, DECLARE_NOTPRODUCT_FLAG, DECLARE_MANAGEABLE_FLAG, DECLARE_PRODUCT_RW_FLAG) diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp index 9486d208dc9..3a3c99a5edd 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp @@ -23,6 +23,7 @@ */ #include "precompiled.hpp" +#include "code/nmethod.hpp" #include "gc_implementation/g1/g1BlockOffsetTable.inline.hpp" #include "gc_implementation/g1/g1CollectedHeap.inline.hpp" #include "gc_implementation/g1/g1OopClosures.inline.hpp" @@ -50,144 +51,6 @@ FilterOutOfRegionClosure::FilterOutOfRegionClosure(HeapRegion* r, OopClosure* oc) : _r_bottom(r->bottom()), _r_end(r->end()), _oc(oc) { } -class VerifyLiveClosure: public OopClosure { -private: - G1CollectedHeap* _g1h; - CardTableModRefBS* _bs; - oop _containing_obj; - bool _failures; - int _n_failures; - VerifyOption _vo; -public: - // _vo == UsePrevMarking -> use "prev" marking information, - // _vo == UseNextMarking -> use "next" marking information, - // _vo == UseMarkWord -> use mark word from object header. - VerifyLiveClosure(G1CollectedHeap* g1h, VerifyOption vo) : - _g1h(g1h), _bs(NULL), _containing_obj(NULL), - _failures(false), _n_failures(0), _vo(vo) - { - BarrierSet* bs = _g1h->barrier_set(); - if (bs->is_a(BarrierSet::CardTableModRef)) - _bs = (CardTableModRefBS*)bs; - } - - void set_containing_obj(oop obj) { - _containing_obj = obj; - } - - bool failures() { return _failures; } - int n_failures() { return _n_failures; } - - virtual void do_oop(narrowOop* p) { do_oop_work(p); } - virtual void do_oop( oop* p) { do_oop_work(p); } - - void print_object(outputStream* out, oop obj) { -#ifdef PRODUCT - Klass* k = obj->klass(); - const char* class_name = InstanceKlass::cast(k)->external_name(); - out->print_cr("class name %s", class_name); -#else // PRODUCT - obj->print_on(out); -#endif // PRODUCT - } - - template - void do_oop_work(T* p) { - assert(_containing_obj != NULL, "Precondition"); - assert(!_g1h->is_obj_dead_cond(_containing_obj, _vo), - "Precondition"); - T heap_oop = oopDesc::load_heap_oop(p); - if (!oopDesc::is_null(heap_oop)) { - oop obj = oopDesc::decode_heap_oop_not_null(heap_oop); - bool failed = false; - if (!_g1h->is_in_closed_subset(obj) || _g1h->is_obj_dead_cond(obj, _vo)) { - MutexLockerEx x(ParGCRareEvent_lock, - Mutex::_no_safepoint_check_flag); - - if (!_failures) { - gclog_or_tty->print_cr(""); - gclog_or_tty->print_cr("----------"); - } - if (!_g1h->is_in_closed_subset(obj)) { - HeapRegion* from = _g1h->heap_region_containing((HeapWord*)p); - gclog_or_tty->print_cr("Field "PTR_FORMAT - " of live obj "PTR_FORMAT" in region " - "["PTR_FORMAT", "PTR_FORMAT")", - p, (void*) _containing_obj, - from->bottom(), from->end()); - print_object(gclog_or_tty, _containing_obj); - gclog_or_tty->print_cr("points to obj "PTR_FORMAT" not in the heap", - (void*) obj); - } else { - HeapRegion* from = _g1h->heap_region_containing((HeapWord*)p); - HeapRegion* to = _g1h->heap_region_containing((HeapWord*)obj); - gclog_or_tty->print_cr("Field "PTR_FORMAT - " of live obj "PTR_FORMAT" in region " - "["PTR_FORMAT", "PTR_FORMAT")", - p, (void*) _containing_obj, - from->bottom(), from->end()); - print_object(gclog_or_tty, _containing_obj); - gclog_or_tty->print_cr("points to dead obj "PTR_FORMAT" in region " - "["PTR_FORMAT", "PTR_FORMAT")", - (void*) obj, to->bottom(), to->end()); - print_object(gclog_or_tty, obj); - } - gclog_or_tty->print_cr("----------"); - gclog_or_tty->flush(); - _failures = true; - failed = true; - _n_failures++; - } - - if (!_g1h->full_collection() || G1VerifyRSetsDuringFullGC) { - HeapRegion* from = _g1h->heap_region_containing((HeapWord*)p); - HeapRegion* to = _g1h->heap_region_containing(obj); - if (from != NULL && to != NULL && - from != to && - !to->isHumongous()) { - jbyte cv_obj = *_bs->byte_for_const(_containing_obj); - jbyte cv_field = *_bs->byte_for_const(p); - const jbyte dirty = CardTableModRefBS::dirty_card_val(); - - bool is_bad = !(from->is_young() - || to->rem_set()->contains_reference(p) - || !G1HRRSFlushLogBuffersOnVerify && // buffers were not flushed - (_containing_obj->is_objArray() ? - cv_field == dirty - : cv_obj == dirty || cv_field == dirty)); - if (is_bad) { - MutexLockerEx x(ParGCRareEvent_lock, - Mutex::_no_safepoint_check_flag); - - if (!_failures) { - gclog_or_tty->print_cr(""); - gclog_or_tty->print_cr("----------"); - } - gclog_or_tty->print_cr("Missing rem set entry:"); - gclog_or_tty->print_cr("Field "PTR_FORMAT" " - "of obj "PTR_FORMAT", " - "in region "HR_FORMAT, - p, (void*) _containing_obj, - HR_FORMAT_PARAMS(from)); - _containing_obj->print_on(gclog_or_tty); - gclog_or_tty->print_cr("points to obj "PTR_FORMAT" " - "in region "HR_FORMAT, - (void*) obj, - HR_FORMAT_PARAMS(to)); - obj->print_on(gclog_or_tty); - gclog_or_tty->print_cr("Obj head CTE = %d, field CTE = %d.", - cv_obj, cv_field); - gclog_or_tty->print_cr("----------"); - gclog_or_tty->flush(); - _failures = true; - if (!failed) _n_failures++; - } - } - } - } - } -}; - template HeapWord* walk_mem_region_loop(ClosureType* cl, G1CollectedHeap* g1h, HeapRegion* hr, @@ -368,7 +231,7 @@ void HeapRegion::hr_clear(bool par, bool clear_space) { if (!par) { // If this is parallel, this will be done later. HeapRegionRemSet* hrrs = rem_set(); - if (hrrs != NULL) hrrs->clear(); + hrrs->clear(); _claimed = InitialClaimValue; } zero_marked_bytes(); @@ -505,6 +368,7 @@ HeapRegion::HeapRegion(uint hrs_index, _rem_set(NULL), _recorded_rs_length(0), _predicted_elapsed_time_ms(0), _predicted_bytes_to_copy(0) { + _rem_set = new HeapRegionRemSet(sharedOffsetArray, this); _orig_end = mr.end(); // Note that initialize() will set the start of the unmarked area of the // region. @@ -512,8 +376,6 @@ HeapRegion::HeapRegion(uint hrs_index, set_top(bottom()); set_saved_mark(); - _rem_set = new HeapRegionRemSet(sharedOffsetArray, this); - assert(HeapRegionRemSet::num_par_rem_sets() > 0, "Invariant."); } @@ -733,6 +595,160 @@ oops_on_card_seq_iterate_careful(MemRegion mr, return NULL; } +// Code roots support + +void HeapRegion::add_strong_code_root(nmethod* nm) { + HeapRegionRemSet* hrrs = rem_set(); + hrrs->add_strong_code_root(nm); +} + +void HeapRegion::remove_strong_code_root(nmethod* nm) { + HeapRegionRemSet* hrrs = rem_set(); + hrrs->remove_strong_code_root(nm); +} + +void HeapRegion::migrate_strong_code_roots() { + assert(in_collection_set(), "only collection set regions"); + assert(!isHumongous(), "not humongous regions"); + + HeapRegionRemSet* hrrs = rem_set(); + hrrs->migrate_strong_code_roots(); +} + +void HeapRegion::strong_code_roots_do(CodeBlobClosure* blk) const { + HeapRegionRemSet* hrrs = rem_set(); + hrrs->strong_code_roots_do(blk); +} + +class VerifyStrongCodeRootOopClosure: public OopClosure { + const HeapRegion* _hr; + nmethod* _nm; + bool _failures; + bool _has_oops_in_region; + + template void do_oop_work(T* p) { + T heap_oop = oopDesc::load_heap_oop(p); + if (!oopDesc::is_null(heap_oop)) { + oop obj = oopDesc::decode_heap_oop_not_null(heap_oop); + + // Note: not all the oops embedded in the nmethod are in the + // current region. We only look at those which are. + if (_hr->is_in(obj)) { + // Object is in the region. Check that its less than top + if (_hr->top() <= (HeapWord*)obj) { + // Object is above top + gclog_or_tty->print_cr("Object "PTR_FORMAT" in region " + "["PTR_FORMAT", "PTR_FORMAT") is above " + "top "PTR_FORMAT, + obj, _hr->bottom(), _hr->end(), _hr->top()); + _failures = true; + return; + } + // Nmethod has at least one oop in the current region + _has_oops_in_region = true; + } + } + } + +public: + VerifyStrongCodeRootOopClosure(const HeapRegion* hr, nmethod* nm): + _hr(hr), _failures(false), _has_oops_in_region(false) {} + + void do_oop(narrowOop* p) { do_oop_work(p); } + void do_oop(oop* p) { do_oop_work(p); } + + bool failures() { return _failures; } + bool has_oops_in_region() { return _has_oops_in_region; } +}; + +class VerifyStrongCodeRootCodeBlobClosure: public CodeBlobClosure { + const HeapRegion* _hr; + bool _failures; +public: + VerifyStrongCodeRootCodeBlobClosure(const HeapRegion* hr) : + _hr(hr), _failures(false) {} + + void do_code_blob(CodeBlob* cb) { + nmethod* nm = (cb == NULL) ? NULL : cb->as_nmethod_or_null(); + if (nm != NULL) { + // Verify that the nemthod is live + if (!nm->is_alive()) { + gclog_or_tty->print_cr("region ["PTR_FORMAT","PTR_FORMAT"] has dead nmethod " + PTR_FORMAT" in its strong code roots", + _hr->bottom(), _hr->end(), nm); + _failures = true; + } else { + VerifyStrongCodeRootOopClosure oop_cl(_hr, nm); + nm->oops_do(&oop_cl); + if (!oop_cl.has_oops_in_region()) { + gclog_or_tty->print_cr("region ["PTR_FORMAT","PTR_FORMAT"] has nmethod " + PTR_FORMAT" in its strong code roots " + "with no pointers into region", + _hr->bottom(), _hr->end(), nm); + _failures = true; + } else if (oop_cl.failures()) { + gclog_or_tty->print_cr("region ["PTR_FORMAT","PTR_FORMAT"] has other " + "failures for nmethod "PTR_FORMAT, + _hr->bottom(), _hr->end(), nm); + _failures = true; + } + } + } + } + + bool failures() { return _failures; } +}; + +void HeapRegion::verify_strong_code_roots(VerifyOption vo, bool* failures) const { + if (!G1VerifyHeapRegionCodeRoots) { + // We're not verifying code roots. + return; + } + if (vo == VerifyOption_G1UseMarkWord) { + // Marking verification during a full GC is performed after class + // unloading, code cache unloading, etc so the strong code roots + // attached to each heap region are in an inconsistent state. They won't + // be consistent until the strong code roots are rebuilt after the + // actual GC. Skip verifying the strong code roots in this particular + // time. + assert(VerifyDuringGC, "only way to get here"); + return; + } + + HeapRegionRemSet* hrrs = rem_set(); + int strong_code_roots_length = hrrs->strong_code_roots_list_length(); + + // if this region is empty then there should be no entries + // on its strong code root list + if (is_empty()) { + if (strong_code_roots_length > 0) { + gclog_or_tty->print_cr("region ["PTR_FORMAT","PTR_FORMAT"] is empty " + "but has "INT32_FORMAT" code root entries", + bottom(), end(), strong_code_roots_length); + *failures = true; + } + return; + } + + // An H-region should have an empty strong code root list + if (isHumongous()) { + if (strong_code_roots_length > 0) { + gclog_or_tty->print_cr("region ["PTR_FORMAT","PTR_FORMAT"] is humongous " + "but has "INT32_FORMAT" code root entries", + bottom(), end(), strong_code_roots_length); + *failures = true; + } + return; + } + + VerifyStrongCodeRootCodeBlobClosure cb_cl(this); + strong_code_roots_do(&cb_cl); + + if (cb_cl.failures()) { + *failures = true; + } +} + void HeapRegion::print() const { print_on(gclog_or_tty); } void HeapRegion::print_on(outputStream* st) const { if (isHumongous()) { @@ -761,10 +777,143 @@ void HeapRegion::print_on(outputStream* st) const { G1OffsetTableContigSpace::print_on(st); } -void HeapRegion::verify() const { - bool dummy = false; - verify(VerifyOption_G1UsePrevMarking, /* failures */ &dummy); -} +class VerifyLiveClosure: public OopClosure { +private: + G1CollectedHeap* _g1h; + CardTableModRefBS* _bs; + oop _containing_obj; + bool _failures; + int _n_failures; + VerifyOption _vo; +public: + // _vo == UsePrevMarking -> use "prev" marking information, + // _vo == UseNextMarking -> use "next" marking information, + // _vo == UseMarkWord -> use mark word from object header. + VerifyLiveClosure(G1CollectedHeap* g1h, VerifyOption vo) : + _g1h(g1h), _bs(NULL), _containing_obj(NULL), + _failures(false), _n_failures(0), _vo(vo) + { + BarrierSet* bs = _g1h->barrier_set(); + if (bs->is_a(BarrierSet::CardTableModRef)) + _bs = (CardTableModRefBS*)bs; + } + + void set_containing_obj(oop obj) { + _containing_obj = obj; + } + + bool failures() { return _failures; } + int n_failures() { return _n_failures; } + + virtual void do_oop(narrowOop* p) { do_oop_work(p); } + virtual void do_oop( oop* p) { do_oop_work(p); } + + void print_object(outputStream* out, oop obj) { +#ifdef PRODUCT + Klass* k = obj->klass(); + const char* class_name = InstanceKlass::cast(k)->external_name(); + out->print_cr("class name %s", class_name); +#else // PRODUCT + obj->print_on(out); +#endif // PRODUCT + } + + template + void do_oop_work(T* p) { + assert(_containing_obj != NULL, "Precondition"); + assert(!_g1h->is_obj_dead_cond(_containing_obj, _vo), + "Precondition"); + T heap_oop = oopDesc::load_heap_oop(p); + if (!oopDesc::is_null(heap_oop)) { + oop obj = oopDesc::decode_heap_oop_not_null(heap_oop); + bool failed = false; + if (!_g1h->is_in_closed_subset(obj) || _g1h->is_obj_dead_cond(obj, _vo)) { + MutexLockerEx x(ParGCRareEvent_lock, + Mutex::_no_safepoint_check_flag); + + if (!_failures) { + gclog_or_tty->print_cr(""); + gclog_or_tty->print_cr("----------"); + } + if (!_g1h->is_in_closed_subset(obj)) { + HeapRegion* from = _g1h->heap_region_containing((HeapWord*)p); + gclog_or_tty->print_cr("Field "PTR_FORMAT + " of live obj "PTR_FORMAT" in region " + "["PTR_FORMAT", "PTR_FORMAT")", + p, (void*) _containing_obj, + from->bottom(), from->end()); + print_object(gclog_or_tty, _containing_obj); + gclog_or_tty->print_cr("points to obj "PTR_FORMAT" not in the heap", + (void*) obj); + } else { + HeapRegion* from = _g1h->heap_region_containing((HeapWord*)p); + HeapRegion* to = _g1h->heap_region_containing((HeapWord*)obj); + gclog_or_tty->print_cr("Field "PTR_FORMAT + " of live obj "PTR_FORMAT" in region " + "["PTR_FORMAT", "PTR_FORMAT")", + p, (void*) _containing_obj, + from->bottom(), from->end()); + print_object(gclog_or_tty, _containing_obj); + gclog_or_tty->print_cr("points to dead obj "PTR_FORMAT" in region " + "["PTR_FORMAT", "PTR_FORMAT")", + (void*) obj, to->bottom(), to->end()); + print_object(gclog_or_tty, obj); + } + gclog_or_tty->print_cr("----------"); + gclog_or_tty->flush(); + _failures = true; + failed = true; + _n_failures++; + } + + if (!_g1h->full_collection() || G1VerifyRSetsDuringFullGC) { + HeapRegion* from = _g1h->heap_region_containing((HeapWord*)p); + HeapRegion* to = _g1h->heap_region_containing(obj); + if (from != NULL && to != NULL && + from != to && + !to->isHumongous()) { + jbyte cv_obj = *_bs->byte_for_const(_containing_obj); + jbyte cv_field = *_bs->byte_for_const(p); + const jbyte dirty = CardTableModRefBS::dirty_card_val(); + + bool is_bad = !(from->is_young() + || to->rem_set()->contains_reference(p) + || !G1HRRSFlushLogBuffersOnVerify && // buffers were not flushed + (_containing_obj->is_objArray() ? + cv_field == dirty + : cv_obj == dirty || cv_field == dirty)); + if (is_bad) { + MutexLockerEx x(ParGCRareEvent_lock, + Mutex::_no_safepoint_check_flag); + + if (!_failures) { + gclog_or_tty->print_cr(""); + gclog_or_tty->print_cr("----------"); + } + gclog_or_tty->print_cr("Missing rem set entry:"); + gclog_or_tty->print_cr("Field "PTR_FORMAT" " + "of obj "PTR_FORMAT", " + "in region "HR_FORMAT, + p, (void*) _containing_obj, + HR_FORMAT_PARAMS(from)); + _containing_obj->print_on(gclog_or_tty); + gclog_or_tty->print_cr("points to obj "PTR_FORMAT" " + "in region "HR_FORMAT, + (void*) obj, + HR_FORMAT_PARAMS(to)); + obj->print_on(gclog_or_tty); + gclog_or_tty->print_cr("Obj head CTE = %d, field CTE = %d.", + cv_obj, cv_field); + gclog_or_tty->print_cr("----------"); + gclog_or_tty->flush(); + _failures = true; + if (!failed) _n_failures++; + } + } + } + } + } +}; // This really ought to be commoned up into OffsetTableContigSpace somehow. // We would need a mechanism to make that code skip dead objects. @@ -904,6 +1053,13 @@ void HeapRegion::verify(VerifyOption vo, *failures = true; return; } + + verify_strong_code_roots(vo, failures); +} + +void HeapRegion::verify() const { + bool dummy = false; + verify(VerifyOption_G1UsePrevMarking, /* failures */ &dummy); } // G1OffsetTableContigSpace code; copied from space.cpp. Hope this can go diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.hpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.hpp index 7c79195d3e5..68e58d680c9 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.hpp @@ -52,6 +52,7 @@ class HeapRegionRemSet; class HeapRegionRemSetIterator; class HeapRegion; class HeapRegionSetBase; +class nmethod; #define HR_FORMAT "%u:(%s)["PTR_FORMAT","PTR_FORMAT","PTR_FORMAT"]" #define HR_FORMAT_PARAMS(_hr_) \ @@ -371,7 +372,8 @@ class HeapRegion: public G1OffsetTableContigSpace { RebuildRSClaimValue = 5, ParEvacFailureClaimValue = 6, AggregateCountClaimValue = 7, - VerifyCountClaimValue = 8 + VerifyCountClaimValue = 8, + ParMarkRootClaimValue = 9 }; inline HeapWord* par_allocate_no_bot_updates(size_t word_size) { @@ -796,6 +798,25 @@ class HeapRegion: public G1OffsetTableContigSpace { virtual void reset_after_compaction(); + // Routines for managing a list of code roots (attached to the + // this region's RSet) that point into this heap region. + void add_strong_code_root(nmethod* nm); + void remove_strong_code_root(nmethod* nm); + + // During a collection, migrate the successfully evacuated + // strong code roots that referenced into this region to the + // new regions that they now point into. Unsuccessfully + // evacuated code roots are not migrated. + void migrate_strong_code_roots(); + + // Applies blk->do_code_blob() to each of the entries in + // the strong code roots list for this region + void strong_code_roots_do(CodeBlobClosure* blk) const; + + // Verify that the entries on the strong code root list for this + // region are live and include at least one pointer into this region. + void verify_strong_code_roots(VerifyOption vo, bool* failures) const; + void print() const; void print_on(outputStream* st) const; diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp index 635babcbb30..69eaa53c31a 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp @@ -33,6 +33,7 @@ #include "oops/oop.inline.hpp" #include "utilities/bitMap.inline.hpp" #include "utilities/globalDefinitions.hpp" +#include "utilities/growableArray.hpp" class PerRegionTable: public CHeapObj { friend class OtherRegionsTable; @@ -849,7 +850,7 @@ int HeapRegionRemSet::num_par_rem_sets() { HeapRegionRemSet::HeapRegionRemSet(G1BlockOffsetSharedArray* bosa, HeapRegion* hr) - : _bosa(bosa), _other_regions(hr) { + : _bosa(bosa), _strong_code_roots_list(NULL), _other_regions(hr) { reset_for_par_iteration(); } @@ -908,6 +909,12 @@ void HeapRegionRemSet::cleanup() { } void HeapRegionRemSet::clear() { + if (_strong_code_roots_list != NULL) { + delete _strong_code_roots_list; + } + _strong_code_roots_list = new (ResourceObj::C_HEAP, mtGC) + GrowableArray(10, 0, NULL, true); + _other_regions.clear(); assert(occupied() == 0, "Should be clear."); reset_for_par_iteration(); @@ -925,6 +932,121 @@ void HeapRegionRemSet::scrub(CardTableModRefBS* ctbs, _other_regions.scrub(ctbs, region_bm, card_bm); } + +// Code roots support + +void HeapRegionRemSet::add_strong_code_root(nmethod* nm) { + assert(nm != NULL, "sanity"); + // Search for the code blob from the RHS to avoid + // duplicate entries as much as possible + if (_strong_code_roots_list->find_from_end(nm) < 0) { + // Code blob isn't already in the list + _strong_code_roots_list->push(nm); + } +} + +void HeapRegionRemSet::remove_strong_code_root(nmethod* nm) { + assert(nm != NULL, "sanity"); + int idx = _strong_code_roots_list->find(nm); + if (idx >= 0) { + _strong_code_roots_list->remove_at(idx); + } + // Check that there were no duplicates + guarantee(_strong_code_roots_list->find(nm) < 0, "duplicate entry found"); +} + +class NMethodMigrationOopClosure : public OopClosure { + G1CollectedHeap* _g1h; + HeapRegion* _from; + nmethod* _nm; + + uint _num_self_forwarded; + + template void do_oop_work(T* p) { + T heap_oop = oopDesc::load_heap_oop(p); + if (!oopDesc::is_null(heap_oop)) { + oop obj = oopDesc::decode_heap_oop_not_null(heap_oop); + if (_from->is_in(obj)) { + // Reference still points into the source region. + // Since roots are immediately evacuated this means that + // we must have self forwarded the object + assert(obj->is_forwarded(), + err_msg("code roots should be immediately evacuated. " + "Ref: "PTR_FORMAT", " + "Obj: "PTR_FORMAT", " + "Region: "HR_FORMAT, + p, (void*) obj, HR_FORMAT_PARAMS(_from))); + assert(obj->forwardee() == obj, + err_msg("not self forwarded? obj = "PTR_FORMAT, (void*)obj)); + + // The object has been self forwarded. + // Note, if we're during an initial mark pause, there is + // no need to explicitly mark object. It will be marked + // during the regular evacuation failure handling code. + _num_self_forwarded++; + } else { + // The reference points into a promotion or to-space region + HeapRegion* to = _g1h->heap_region_containing(obj); + to->rem_set()->add_strong_code_root(_nm); + } + } + } + +public: + NMethodMigrationOopClosure(G1CollectedHeap* g1h, HeapRegion* from, nmethod* nm): + _g1h(g1h), _from(from), _nm(nm), _num_self_forwarded(0) {} + + void do_oop(narrowOop* p) { do_oop_work(p); } + void do_oop(oop* p) { do_oop_work(p); } + + uint retain() { return _num_self_forwarded > 0; } +}; + +void HeapRegionRemSet::migrate_strong_code_roots() { + assert(hr()->in_collection_set(), "only collection set regions"); + assert(!hr()->isHumongous(), "not humongous regions"); + + ResourceMark rm; + + // List of code blobs to retain for this region + GrowableArray to_be_retained(10); + G1CollectedHeap* g1h = G1CollectedHeap::heap(); + + while (_strong_code_roots_list->is_nonempty()) { + nmethod *nm = _strong_code_roots_list->pop(); + if (nm != NULL) { + NMethodMigrationOopClosure oop_cl(g1h, hr(), nm); + nm->oops_do(&oop_cl); + if (oop_cl.retain()) { + to_be_retained.push(nm); + } + } + } + + // Now push any code roots we need to retain + assert(to_be_retained.is_empty() || hr()->evacuation_failed(), + "Retained nmethod list must be empty or " + "evacuation of this region failed"); + + while (to_be_retained.is_nonempty()) { + nmethod* nm = to_be_retained.pop(); + assert(nm != NULL, "sanity"); + add_strong_code_root(nm); + } +} + +void HeapRegionRemSet::strong_code_roots_do(CodeBlobClosure* blk) const { + for (int i = 0; i < _strong_code_roots_list->length(); i += 1) { + nmethod* nm = _strong_code_roots_list->at(i); + blk->do_code_blob(nm); + } +} + +size_t HeapRegionRemSet::strong_code_roots_mem_size() { + return sizeof(GrowableArray) + + _strong_code_roots_list->max_length() * sizeof(nmethod*); +} + //-------------------- Iteration -------------------- HeapRegionRemSetIterator:: HeapRegionRemSetIterator(const HeapRegionRemSet* hrrs) : diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.hpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.hpp index 1b9e5f46aa5..e40f6195a12 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.hpp @@ -37,6 +37,7 @@ class HeapRegion; class HeapRegionRemSetIterator; class PerRegionTable; class SparsePRT; +class nmethod; // Essentially a wrapper around SparsePRTCleanupTask. See // sparsePRT.hpp for more details. @@ -191,6 +192,10 @@ private: G1BlockOffsetSharedArray* _bosa; G1BlockOffsetSharedArray* bosa() const { return _bosa; } + // A list of code blobs (nmethods) whose code contains pointers into + // the region that owns this RSet. + GrowableArray* _strong_code_roots_list; + OtherRegionsTable _other_regions; enum ParIterState { Unclaimed, Claimed, Complete }; @@ -282,11 +287,13 @@ public: } // The actual # of bytes this hr_remset takes up. + // Note also includes the strong code root set. size_t mem_size() { return _other_regions.mem_size() // This correction is necessary because the above includes the second // part. - + sizeof(this) - sizeof(OtherRegionsTable); + + (sizeof(this) - sizeof(OtherRegionsTable)) + + strong_code_roots_mem_size(); } // Returns the memory occupancy of all static data structures associated @@ -304,6 +311,37 @@ public: bool contains_reference(OopOrNarrowOopStar from) const { return _other_regions.contains_reference(from); } + + // Routines for managing the list of code roots that point into + // the heap region that owns this RSet. + void add_strong_code_root(nmethod* nm); + void remove_strong_code_root(nmethod* nm); + + // During a collection, migrate the successfully evacuated strong + // code roots that referenced into the region that owns this RSet + // to the RSets of the new regions that they now point into. + // Unsuccessfully evacuated code roots are not migrated. + void migrate_strong_code_roots(); + + // Applies blk->do_code_blob() to each of the entries in + // the strong code roots list + void strong_code_roots_do(CodeBlobClosure* blk) const; + + // Returns the number of elements in the strong code roots list + int strong_code_roots_list_length() { + return _strong_code_roots_list->length(); + } + + // Returns true if the strong code roots contains the given + // nmethod. + bool strong_code_roots_list_contains(nmethod* nm) { + return _strong_code_roots_list->contains(nm); + } + + // Returns the amount of memory, in bytes, currently + // consumed by the strong code roots. + size_t strong_code_roots_mem_size(); + void print() const; // Called during a stop-world phase to perform any deferred cleanups. diff --git a/hotspot/src/share/vm/gc_interface/collectedHeap.cpp b/hotspot/src/share/vm/gc_interface/collectedHeap.cpp index dfc963c3bc4..3af380049bb 100644 --- a/hotspot/src/share/vm/gc_interface/collectedHeap.cpp +++ b/hotspot/src/share/vm/gc_interface/collectedHeap.cpp @@ -118,6 +118,14 @@ void CollectedHeap::print_heap_after_gc() { } } +void CollectedHeap::register_nmethod(nmethod* nm) { + assert_locked_or_safepoint(CodeCache_lock); +} + +void CollectedHeap::unregister_nmethod(nmethod* nm) { + assert_locked_or_safepoint(CodeCache_lock); +} + void CollectedHeap::trace_heap(GCWhen::Type when, GCTracer* gc_tracer) { const GCHeapSummary& heap_summary = create_heap_summary(); const MetaspaceSummary& metaspace_summary = create_metaspace_summary(); diff --git a/hotspot/src/share/vm/gc_interface/collectedHeap.hpp b/hotspot/src/share/vm/gc_interface/collectedHeap.hpp index 1f42cfe4839..c26ca77a8b8 100644 --- a/hotspot/src/share/vm/gc_interface/collectedHeap.hpp +++ b/hotspot/src/share/vm/gc_interface/collectedHeap.hpp @@ -49,6 +49,7 @@ class MetaspaceSummary; class Thread; class ThreadClosure; class VirtualSpaceSummary; +class nmethod; class GCMessage : public FormatBuffer<1024> { public: @@ -603,6 +604,11 @@ class CollectedHeap : public CHeapObj { void print_heap_before_gc(); void print_heap_after_gc(); + // Registering and unregistering an nmethod (compiled code) with the heap. + // Override with specific mechanism for each specialized heap type. + virtual void register_nmethod(nmethod* nm); + virtual void unregister_nmethod(nmethod* nm); + void trace_heap_before_gc(GCTracer* gc_tracer); void trace_heap_after_gc(GCTracer* gc_tracer); diff --git a/hotspot/src/share/vm/memory/iterator.cpp b/hotspot/src/share/vm/memory/iterator.cpp index e33a5614d63..545ab921363 100644 --- a/hotspot/src/share/vm/memory/iterator.cpp +++ b/hotspot/src/share/vm/memory/iterator.cpp @@ -64,7 +64,7 @@ void MarkingCodeBlobClosure::do_code_blob(CodeBlob* cb) { } void CodeBlobToOopClosure::do_newly_marked_nmethod(nmethod* nm) { - nm->oops_do(_cl, /*do_strong_roots_only=*/ true); + nm->oops_do(_cl, /*allow_zombie=*/ false); } void CodeBlobToOopClosure::do_code_blob(CodeBlob* cb) { diff --git a/hotspot/src/share/vm/runtime/sweeper.hpp b/hotspot/src/share/vm/runtime/sweeper.hpp index 4bad5bd9be4..da4a13adc77 100644 --- a/hotspot/src/share/vm/runtime/sweeper.hpp +++ b/hotspot/src/share/vm/runtime/sweeper.hpp @@ -83,6 +83,7 @@ class NMethodSweeper : public AllStatic { static jlong peak_disconnect_time() { return _peak_disconnect_time; } #ifdef ASSERT + static bool is_sweeping(nmethod* which) { return _current == which; } // Keep track of sweeper activity in the ring buffer static void record_sweep(nmethod* nm, int line); static void report_events(int id, address entry); diff --git a/hotspot/src/share/vm/utilities/growableArray.hpp b/hotspot/src/share/vm/utilities/growableArray.hpp index 932d0a20260..866a23ad9c1 100644 --- a/hotspot/src/share/vm/utilities/growableArray.hpp +++ b/hotspot/src/share/vm/utilities/growableArray.hpp @@ -194,6 +194,7 @@ template class GrowableArray : public GenericGrowableArray { void clear() { _len = 0; } int length() const { return _len; } + int max_length() const { return _max; } void trunc_to(int l) { assert(l <= _len,"cannot increase length"); _len = l; } bool is_empty() const { return _len == 0; } bool is_nonempty() const { return _len != 0; } From 5e4109012091d5f8a784e4d5f89cd7b1199668d5 Mon Sep 17 00:00:00 2001 From: Bengt Rutisson Date: Fri, 16 Aug 2013 11:26:09 +0200 Subject: [PATCH 051/218] 8023145: G1: G1CollectedHeap::mark_strong_code_roots() needs to handle ParallelGCThreads=0 Reviewed-by: stefank, mgerdin --- .../vm/gc_implementation/g1/g1CollectedHeap.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp index 976ec82c7e1..97a9a1fa54d 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp @@ -6807,10 +6807,14 @@ public: void G1CollectedHeap::mark_strong_code_roots(uint worker_id) { MarkStrongCodeRootsHRClosure cl(this, worker_id); - heap_region_par_iterate_chunked(&cl, - worker_id, - workers()->active_workers(), - HeapRegion::ParMarkRootClaimValue); + if (G1CollectedHeap::use_parallel_gc_threads()) { + heap_region_par_iterate_chunked(&cl, + worker_id, + workers()->active_workers(), + HeapRegion::ParMarkRootClaimValue); + } else { + heap_region_iterate(&cl); + } } class RebuildStrongCodeRootClosure: public CodeBlobClosure { From 8fc3bf871572c455b88715834949a72f7cbe96c7 Mon Sep 17 00:00:00 2001 From: Stefan Karlsson Date: Mon, 19 Aug 2013 13:44:13 +0200 Subject: [PATCH 052/218] 8023227: Enhance layout_helper_log2_element_size assert Reviewed-by: mgerdin, jmasa --- hotspot/src/share/vm/oops/klass.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hotspot/src/share/vm/oops/klass.hpp b/hotspot/src/share/vm/oops/klass.hpp index 1ca027a3762..00b208b4ed0 100644 --- a/hotspot/src/share/vm/oops/klass.hpp +++ b/hotspot/src/share/vm/oops/klass.hpp @@ -352,7 +352,8 @@ class Klass : public Metadata { static int layout_helper_log2_element_size(jint lh) { assert(lh < (jint)_lh_neutral_value, "must be array"); int l2esz = (lh >> _lh_log2_element_size_shift) & _lh_log2_element_size_mask; - assert(l2esz <= LogBitsPerLong, "sanity"); + assert(l2esz <= LogBitsPerLong, + err_msg("sanity. l2esz: 0x%x for lh: 0x%x", (uint)l2esz, (uint)lh)); return l2esz; } static jint array_layout_helper(jint tag, int hsize, BasicType etype, int log2_esize) { From e5f563bfef9e52c6159c7da88bfcf02bf419a432 Mon Sep 17 00:00:00 2001 From: Erik Helin Date: Mon, 19 Aug 2013 18:17:58 +0200 Subject: [PATCH 053/218] 8023219: NPG: MetaspaceMemoryPool should report statistics for all of metaspace Reviewed-by: stefank, sjohanss --- hotspot/src/share/vm/services/memoryPool.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hotspot/src/share/vm/services/memoryPool.cpp b/hotspot/src/share/vm/services/memoryPool.cpp index b28e14bb500..777b8b8f382 100644 --- a/hotspot/src/share/vm/services/memoryPool.cpp +++ b/hotspot/src/share/vm/services/memoryPool.cpp @@ -268,11 +268,11 @@ MemoryUsage MetaspacePool::get_memory_usage() { } size_t MetaspacePool::used_in_bytes() { - return MetaspaceAux::allocated_used_bytes(Metaspace::NonClassType); + return MetaspaceAux::allocated_used_bytes(); } size_t MetaspacePool::capacity_in_bytes() const { - return MetaspaceAux::allocated_capacity_bytes(Metaspace::NonClassType); + return MetaspaceAux::allocated_capacity_bytes(); } size_t MetaspacePool::calculate_max_size() const { From ae7845053fde525ff78a8389f91b5da305eed1d6 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Wed, 21 Aug 2013 10:32:02 +0200 Subject: [PATCH 054/218] 8022784: TaskQueue misses minimal documentation and references for analysis Add appropriate documentation and references to publication to allow easier analysis of the TaskQueue implementation. Reviewed-by: dholmes, ehelin --- hotspot/src/share/vm/utilities/taskqueue.hpp | 35 ++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/hotspot/src/share/vm/utilities/taskqueue.hpp b/hotspot/src/share/vm/utilities/taskqueue.hpp index d3eafd5de47..cdc119dd691 100644 --- a/hotspot/src/share/vm/utilities/taskqueue.hpp +++ b/hotspot/src/share/vm/utilities/taskqueue.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -132,6 +132,8 @@ void TaskQueueStats::reset() { } #endif // TASKQUEUE_STATS +// TaskQueueSuper collects functionality common to all GenericTaskQueue instances. + template class TaskQueueSuper: public CHeapObj { protected: @@ -249,7 +251,36 @@ public: TASKQUEUE_STATS_ONLY(TaskQueueStats stats;) }; - +// +// GenericTaskQueue implements an ABP, Aurora-Blumofe-Plaxton, double- +// ended-queue (deque), intended for use in work stealing. Queue operations +// are non-blocking. +// +// A queue owner thread performs push() and pop_local() operations on one end +// of the queue, while other threads may steal work using the pop_global() +// method. +// +// The main difference to the original algorithm is that this +// implementation allows wrap-around at the end of its allocated +// storage, which is an array. +// +// The original paper is: +// +// Arora, N. S., Blumofe, R. D., and Plaxton, C. G. +// Thread scheduling for multiprogrammed multiprocessors. +// Theory of Computing Systems 34, 2 (2001), 115-144. +// +// The following paper provides an correctness proof and an +// implementation for weakly ordered memory models including (pseudo-) +// code containing memory barriers for a Chase-Lev deque. Chase-Lev is +// similar to ABP, with the main difference that it allows resizing of the +// underlying storage: +// +// Le, N. M., Pop, A., Cohen A., and Nardell, F. Z. +// Correct and efficient work-stealing for weak memory models +// Proceedings of the 18th ACM SIGPLAN symposium on Principles and +// practice of parallel programming (PPoPP 2013), 69-80 +// template class GenericTaskQueue: public TaskQueueSuper { From 9354b09906c37b430140bd157678e2bbf6c11675 Mon Sep 17 00:00:00 2001 From: Jon Masamitsu Date: Wed, 14 Aug 2013 19:52:16 -0700 Subject: [PATCH 055/218] 8021809: Partitioning based on eden sampling during allocation not reset correctly Reviewed-by: ysr, hiroshi --- .../concurrentMarkSweepGeneration.cpp | 60 ++++++++++--------- 1 file changed, 31 insertions(+), 29 deletions(-) diff --git a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp index 54ade2db111..fe53388a05f 100644 --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp @@ -5478,40 +5478,42 @@ CMSParMarkTask::do_young_space_rescan(uint worker_id, HandleMark hm; SequentialSubTasksDone* pst = space->par_seq_tasks(); - assert(pst->valid(), "Uninitialized use?"); uint nth_task = 0; uint n_tasks = pst->n_tasks(); - HeapWord *start, *end; - while (!pst->is_task_claimed(/* reference */ nth_task)) { - // We claimed task # nth_task; compute its boundaries. - if (chunk_top == 0) { // no samples were taken - assert(nth_task == 0 && n_tasks == 1, "Can have only 1 EdenSpace task"); - start = space->bottom(); - end = space->top(); - } else if (nth_task == 0) { - start = space->bottom(); - end = chunk_array[nth_task]; - } else if (nth_task < (uint)chunk_top) { - assert(nth_task >= 1, "Control point invariant"); - start = chunk_array[nth_task - 1]; - end = chunk_array[nth_task]; - } else { - assert(nth_task == (uint)chunk_top, "Control point invariant"); - start = chunk_array[chunk_top - 1]; - end = space->top(); + if (n_tasks > 0) { + assert(pst->valid(), "Uninitialized use?"); + HeapWord *start, *end; + while (!pst->is_task_claimed(/* reference */ nth_task)) { + // We claimed task # nth_task; compute its boundaries. + if (chunk_top == 0) { // no samples were taken + assert(nth_task == 0 && n_tasks == 1, "Can have only 1 EdenSpace task"); + start = space->bottom(); + end = space->top(); + } else if (nth_task == 0) { + start = space->bottom(); + end = chunk_array[nth_task]; + } else if (nth_task < (uint)chunk_top) { + assert(nth_task >= 1, "Control point invariant"); + start = chunk_array[nth_task - 1]; + end = chunk_array[nth_task]; + } else { + assert(nth_task == (uint)chunk_top, "Control point invariant"); + start = chunk_array[chunk_top - 1]; + end = space->top(); + } + MemRegion mr(start, end); + // Verify that mr is in space + assert(mr.is_empty() || space->used_region().contains(mr), + "Should be in space"); + // Verify that "start" is an object boundary + assert(mr.is_empty() || oop(mr.start())->is_oop(), + "Should be an oop"); + space->par_oop_iterate(mr, cl); } - MemRegion mr(start, end); - // Verify that mr is in space - assert(mr.is_empty() || space->used_region().contains(mr), - "Should be in space"); - // Verify that "start" is an object boundary - assert(mr.is_empty() || oop(mr.start())->is_oop(), - "Should be an oop"); - space->par_oop_iterate(mr, cl); + pst->all_tasks_completed(); } - pst->all_tasks_completed(); } void @@ -5788,7 +5790,7 @@ initialize_sequential_subtasks_for_young_gen_rescan(int n_threads) { DefNewGeneration* dng = (DefNewGeneration*)_young_gen; // Eden space - { + if (!dng->eden()->is_empty()) { SequentialSubTasksDone* pst = dng->eden()->par_seq_tasks(); assert(!pst->valid(), "Clobbering existing data?"); // Each valid entry in [0, _eden_chunk_index) represents a task. From 0c6e63367d2dc289c78c4b85ae97602788608f60 Mon Sep 17 00:00:00 2001 From: Bhavesh Patel Date: Wed, 14 Aug 2013 21:44:51 -0700 Subject: [PATCH 056/218] 8016921: Change the profiles table on overview-summary.html page to a list Reviewed-by: jjg --- .../html/AbstractPackageIndexWriter.java | 9 +--- .../formats/html/PackageIndexWriter.java | 48 ++++++------------- .../javadoc/testProfiles/TestProfiles.java | 19 +++++++- 3 files changed, 33 insertions(+), 43 deletions(-) diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/AbstractPackageIndexWriter.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/AbstractPackageIndexWriter.java index 95cd4a44d08..bd84d2caf2d 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/AbstractPackageIndexWriter.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/AbstractPackageIndexWriter.java @@ -159,10 +159,7 @@ public abstract class AbstractPackageIndexWriter extends HtmlDocletWriter { body.addContent(div); if (configuration.showProfiles) { Content profileSummary = configuration.getResource("doclet.Profiles"); - Content profilesTableSummary = configuration.getResource("doclet.Member_Table_Summary", - configuration.getResource("doclet.Profile_Summary"), - configuration.getResource("doclet.profiles")); - addProfilesList(profileSummary, profilesTableSummary, body); + addProfilesList(profileSummary, body); } addPackagesList(packages, text, tableSummary, body); } @@ -214,10 +211,8 @@ public abstract class AbstractPackageIndexWriter extends HtmlDocletWriter { * Do nothing. This will be overridden. * * @param profileSummary the profile summary heading - * @param profilesTableSummary the profiles table summary information * @param body the content tree to which the profiles list will be added */ - protected void addProfilesList(Content profileSummary, Content profilesTableSummary, - Content body) { + protected void addProfilesList(Content profileSummary, Content body) { } } diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/PackageIndexWriter.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/PackageIndexWriter.java index e11ed98b527..e2ef6f56c65 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/PackageIndexWriter.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/PackageIndexWriter.java @@ -123,15 +123,20 @@ public class PackageIndexWriter extends AbstractPackageIndexWriter { /** * {@inheritDoc} */ - protected void addProfilesList(Content profileSummary, String profilesTableSummary, - Content body) { - Content table = HtmlTree.TABLE(HtmlStyle.overviewSummary, 0, 3, 0, profilesTableSummary, - getTableCaption(profileSummary)); - table.addContent(getSummaryTableHeader(profileTableHeader, "col")); - Content tbody = new HtmlTree(HtmlTag.TBODY); - addProfilesList(tbody); - table.addContent(tbody); - Content div = HtmlTree.DIV(HtmlStyle.contentContainer, table); + protected void addProfilesList(Content profileSummary, Content body) { + Content h2 = HtmlTree.HEADING(HtmlTag.H2, profileSummary); + Content profilesDiv = HtmlTree.DIV(h2); + Content ul = new HtmlTree(HtmlTag.UL); + String profileName; + for (int i = 1; i < configuration.profiles.getProfileCount(); i++) { + profileName = Profile.lookup(i).name; + Content profileLinkContent = getTargetProfileLink("classFrame", + new StringContent(profileName), profileName); + Content li = HtmlTree.LI(profileLinkContent); + ul.addContent(li); + } + profilesDiv.addContent(ul); + Content div = HtmlTree.DIV(HtmlStyle.contentContainer, profilesDiv); body.addContent(div); } @@ -150,31 +155,6 @@ public class PackageIndexWriter extends AbstractPackageIndexWriter { body.addContent(div); } - /** - * Adds list of profiles in the index table. Generate link to each profile. - * - * @param tbody the documentation tree to which the list will be added - */ - protected void addProfilesList(Content tbody) { - for (int i = 1; i < configuration.profiles.getProfileCount(); i++) { - String profileName = Profile.lookup(i).name; - Content profileLinkContent = getTargetProfileLink("classFrame", - new StringContent(profileName), profileName); - Content tdProfile = HtmlTree.TD(HtmlStyle.colFirst, profileLinkContent); - HtmlTree tdSummary = new HtmlTree(HtmlTag.TD); - tdSummary.addStyle(HtmlStyle.colLast); - tdSummary.addContent(getSpace()); - HtmlTree tr = HtmlTree.TR(tdProfile); - tr.addContent(tdSummary); - if (i % 2 == 0) { - tr.addStyle(HtmlStyle.altColor); - } else { - tr.addStyle(HtmlStyle.rowColor); - } - tbody.addContent(tr); - } - } - /** * Adds list of packages in the index table. Generate link to each package. * diff --git a/langtools/test/com/sun/javadoc/testProfiles/TestProfiles.java b/langtools/test/com/sun/javadoc/testProfiles/TestProfiles.java index a52d3ccd5ac..7d878d7ecd3 100644 --- a/langtools/test/com/sun/javadoc/testProfiles/TestProfiles.java +++ b/langtools/test/com/sun/javadoc/testProfiles/TestProfiles.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8006124 8009684 + * @bug 8006124 8009684 8016921 * @summary Test javadoc support for profiles. * @author Bhavesh Patel * @library ../lib/ @@ -33,7 +33,7 @@ public class TestProfiles extends JavadocTester { //Test information. - private static final String BUG_ID = "8006124-8009684"; + private static final String BUG_ID = "8006124-8009684-8016921"; private static final String PROFILE_BUG_ID = BUG_ID + "-1"; private static final String PACKAGE_BUG_ID = BUG_ID + "-2"; //Javadoc arguments. @@ -105,6 +105,14 @@ public class TestProfiles extends JavadocTester { {PROFILE_BUG_ID + FS + "index.html", "" + }, + //Test for "overview-summary.html" showing the profile list. + {PROFILE_BUG_ID + FS + "overview-summary.html", + "" } }; private static final String[][] PROFILES_NEGATED_TEST = { @@ -159,6 +167,13 @@ public class TestProfiles extends JavadocTester { }, {PACKAGE_BUG_ID + FS + "pkg2" + FS + "Class1Pkg2.html", "
compact1, compact2, compact3
" + }, + {PACKAGE_BUG_ID + FS + "overview-summary.html", + "" } }; From fd4983b2547cb1de2d2a645fed3adb363df8aa35 Mon Sep 17 00:00:00 2001 From: Erik Joelsson Date: Thu, 15 Aug 2013 17:24:35 +0200 Subject: [PATCH 057/218] 8015145: Smartjavac needs more flexibility with linking to sources Reviewed-by: jjg, ohrstrom --- .../com/sun/tools/sjavac/JavacState.java | 5 ++- .../classes/com/sun/tools/sjavac/Main.java | 17 +++++---- langtools/test/tools/sjavac/SJavac.java | 36 ++++++++++++++++++- 3 files changed, 49 insertions(+), 9 deletions(-) diff --git a/langtools/src/share/classes/com/sun/tools/sjavac/JavacState.java b/langtools/src/share/classes/com/sun/tools/sjavac/JavacState.java index 7e1af207eab..3d09c2d63c1 100644 --- a/langtools/src/share/classes/com/sun/tools/sjavac/JavacState.java +++ b/langtools/src/share/classes/com/sun/tools/sjavac/JavacState.java @@ -808,7 +808,10 @@ public class JavacState // Create a set of filenames with full paths. for (Source s : now.sources().values()) { - calculatedSources.add(s.file().getPath()); + // Don't include link only sources when comparing sources to compile + if (!s.isLinkedOnly()) { + calculatedSources.add(s.file().getPath()); + } } // Read in the file and create another set of filenames with full paths. try { diff --git a/langtools/src/share/classes/com/sun/tools/sjavac/Main.java b/langtools/src/share/classes/com/sun/tools/sjavac/Main.java index 14c65f376ae..f0ed51432ee 100644 --- a/langtools/src/share/classes/com/sun/tools/sjavac/Main.java +++ b/langtools/src/share/classes/com/sun/tools/sjavac/Main.java @@ -249,16 +249,19 @@ public class Main { return -1; } - // Find all source files allowable for linking. + // Create a map of all source files that are available for linking. Both -src and + // -sourcepath point to such files. It is possible to specify multiple + // -sourcepath options to enable different filtering rules. If the + // filters are the same for multiple sourcepaths, they may be concatenated + // using :(;). Before sending the list of sourcepaths to javac, they are + // all concatenated. The list created here is used by the SmartFileWrapper to + // make sure only the correct sources are actually available. // We might find more modules here as well. Map sources_to_link_to = new HashMap(); - // Always reuse -src for linking as well! This means that we might - // get two -sourcepath on the commandline after the rewrite, which is - // fine. We can have as many as we like. You need to have separate -src/-sourcepath/-classpath - // if you need different filtering rules for different roots. If you have the same filtering - // rules for all sourcepath roots, you can concatenate them using :(;) as before. - rewriteOptions(args, "-src", "-sourcepath"); + findFiles(args, "-src", Util.set(".java"), sources_to_link_to, modules, current_module, true); findFiles(args, "-sourcepath", Util.set(".java"), sources_to_link_to, modules, current_module, true); + // Rewrite the -src option to make it through to the javac instances. + rewriteOptions(args, "-src", "-sourcepath"); // Find all class files allowable for linking. // And pickup knowledge of all modules found here. diff --git a/langtools/test/tools/sjavac/SJavac.java b/langtools/test/tools/sjavac/SJavac.java index 1c8d61216a6..6f55e68604e 100644 --- a/langtools/test/tools/sjavac/SJavac.java +++ b/langtools/test/tools/sjavac/SJavac.java @@ -21,6 +21,11 @@ * questions. */ +/* + * @test + * @summary Tests sjavac basic functionality + */ + import java.util.*; import java.io.*; import java.net.*; @@ -82,11 +87,13 @@ class SJavac { compileWithOverrideSource(); compileWithInvisibleSources(); compileCircularSources(); + compileExcludingDependency(); delete(gensrc); delete(gensrc2); delete(gensrc3); delete(bin); + delete(headers); } void initialCompile() throws Exception { @@ -381,6 +388,33 @@ class SJavac { delete(bin); } + /** + * Tests compiling class A that depends on class B without compiling class B + * @throws Exception If test fails + */ + void compileExcludingDependency() throws Exception { + System.out.println("\nVerify that excluding classes from compilation but not from linking works."); + System.out.println("---------------------------------------------------------------------------"); + + delete(gensrc); + delete(bin); + previous_bin_state = collectState(bin); + + populate(gensrc, + "alfa/A.java", + "package alfa; public class A { beta.B b; }", + "beta/B.java", + "package beta; public class B { }"); + + compile("-x", "beta", "-src", "gensrc", "-x", "alfa", "-sourcepath", "gensrc", + "-d", "bin", "--server:portfile=testserver,background=false"); + + Map new_bin_state = collectState(bin); + verifyThatFilesHaveBeenAdded(previous_bin_state, new_bin_state, + "bin/alfa/A.class", + "bin/javac_state"); + } + void removeFrom(Path dir, String... args) throws IOException { for (String filename : args) { Path p = dir.resolve(filename); @@ -405,7 +439,7 @@ class SJavac { } } - void delete(Path root) throws IOException { + void delete(final Path root) throws IOException { if (!Files.exists(root)) return; Files.walkFileTree(root, new SimpleFileVisitor() { @Override From 746be8133889b5cb45e476d083a29bd22deb1e84 Mon Sep 17 00:00:00 2001 From: Vicente Romero Date: Fri, 16 Aug 2013 10:32:42 +0100 Subject: [PATCH 058/218] 8022053: javac generates unverifiable initializer for nested subclass of local class Reviewed-by: jjg, mcimadamore --- .../com/sun/tools/javac/comp/Lower.java | 52 +++++++++---- ...verifiableInitForNestedLocalClassTest.java | 73 +++++++++++++++++++ 2 files changed, 110 insertions(+), 15 deletions(-) create mode 100644 langtools/test/tools/javac/T8022053/UnverifiableInitForNestedLocalClassTest.java diff --git a/langtools/src/share/classes/com/sun/tools/javac/comp/Lower.java b/langtools/src/share/classes/com/sun/tools/javac/comp/Lower.java index 0773e1b4d60..d5f4f4dbfe1 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/comp/Lower.java +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Lower.java @@ -356,22 +356,44 @@ public class Lower extends TreeTranslator { } } + ClassSymbol ownerToCopyFreeVarsFrom(ClassSymbol c) { + if (!c.isLocal()) { + return null; + } + Symbol currentOwner = c.owner; + while ((currentOwner.owner.kind & TYP) != 0 && currentOwner.isLocal()) { + currentOwner = currentOwner.owner; + } + if ((currentOwner.owner.kind & (VAR | MTH)) != 0 && c.isSubClass(currentOwner, types)) { + return (ClassSymbol)currentOwner; + } + return null; + } + /** Return the variables accessed from within a local class, which * are declared in the local class' owner. * (in reverse order of first access). */ List freevars(ClassSymbol c) { + List fvs = freevarCache.get(c); + if (fvs != null) { + return fvs; + } if ((c.owner.kind & (VAR | MTH)) != 0) { - List fvs = freevarCache.get(c); - if (fvs == null) { - FreeVarCollector collector = new FreeVarCollector(c); - collector.scan(classDef(c)); - fvs = collector.fvs; - freevarCache.put(c, fvs); - } + FreeVarCollector collector = new FreeVarCollector(c); + collector.scan(classDef(c)); + fvs = collector.fvs; + freevarCache.put(c, fvs); return fvs; } else { - return List.nil(); + ClassSymbol owner = ownerToCopyFreeVarsFrom(c); + if (owner != null) { + fvs = freevarCache.get(owner); + freevarCache.put(c, fvs); + return fvs; + } else { + return List.nil(); + } } } @@ -1046,7 +1068,7 @@ public class Lower extends TreeTranslator { boolean needsPrivateAccess(Symbol sym) { if ((sym.flags() & PRIVATE) == 0 || sym.owner == currentClass) { return false; - } else if (sym.name == names.init && (sym.owner.owner.kind & (VAR | MTH)) != 0) { + } else if (sym.name == names.init && sym.owner.isLocal()) { // private constructor in local class: relax protection sym.flags_field &= ~PRIVATE; return false; @@ -2448,6 +2470,7 @@ public class Lower extends TreeTranslator { tree.name = Convert.shortName(currentClass.flatName()); // Add this$n and free variables proxy definitions to class. + for (List l = fvdefs; l.nonEmpty(); l = l.tail) { tree.defs = tree.defs.prepend(l.head); enterSynthetic(tree.pos(), l.head.sym, currentClass.members()); @@ -2670,8 +2693,7 @@ public class Lower extends TreeTranslator { //where private void visitMethodDefInternal(JCMethodDecl tree) { if (tree.name == names.init && - (currentClass.isInner() || - (currentClass.owner.kind & (VAR | MTH)) != 0)) { + (currentClass.isInner() || currentClass.isLocal())) { // We are seeing a constructor of an inner class. MethodSymbol m = tree.sym; @@ -2818,7 +2840,7 @@ public class Lower extends TreeTranslator { // If created class is local, add free variables after // explicit constructor arguments. - if ((c.owner.kind & (VAR | MTH)) != 0) { + if (c.isLocal()) { tree.args = tree.args.appendList(loadFreevars(tree.pos(), freevars(c))); } @@ -2837,7 +2859,7 @@ public class Lower extends TreeTranslator { if (tree.encl != null) { thisArg = attr.makeNullCheck(translate(tree.encl)); thisArg.type = tree.encl.type; - } else if ((c.owner.kind & (MTH | VAR)) != 0) { + } else if (c.isLocal()) { // local class thisArg = makeThis(tree.pos(), c.type.getEnclosingType().tsym); } else { @@ -2966,7 +2988,7 @@ public class Lower extends TreeTranslator { // If we are calling a constructor of a local class, add // free variables after explicit constructor arguments. ClassSymbol c = (ClassSymbol)constructor.owner; - if ((c.owner.kind & (VAR | MTH)) != 0) { + if (c.isLocal()) { tree.args = tree.args.appendList(loadFreevars(tree.pos(), freevars(c))); } @@ -2994,7 +3016,7 @@ public class Lower extends TreeTranslator { makeNullCheck(translate(((JCFieldAccess) tree.meth).selected)); tree.meth = make.Ident(constructor); ((JCIdent) tree.meth).name = methName; - } else if ((c.owner.kind & (MTH | VAR)) != 0 || methName == names._this){ + } else if (c.isLocal() || methName == names._this){ // local class or this() call thisArg = makeThis(tree.meth.pos(), c.type.getEnclosingType().tsym); } else { diff --git a/langtools/test/tools/javac/T8022053/UnverifiableInitForNestedLocalClassTest.java b/langtools/test/tools/javac/T8022053/UnverifiableInitForNestedLocalClassTest.java new file mode 100644 index 00000000000..bdf40dbcb1f --- /dev/null +++ b/langtools/test/tools/javac/T8022053/UnverifiableInitForNestedLocalClassTest.java @@ -0,0 +1,73 @@ +/* + * 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 8022053 + * @summary 8022053: javac generates unverifiable initializer for nested subclass of local class + * @run main UnverifiableInitForNestedLocalClassTest + */ + +public class UnverifiableInitForNestedLocalClassTest { + + public static void main(final String[] args) { + test("test"); + } + + static void test(final String arg) { + final String inlined = " inlined "; + class LocalClass { + String m() { + return "LocalClass " + arg + inlined; + } + + class SubClass extends LocalClass { + @Override + String m() { + return "SubClass " + arg + inlined; + } + } + + class SubSubClass extends SubClass { + @Override + String m() { + return "SubSubClass " + arg + inlined; + } + } + + class AnotherLocal { + class AnotherSub extends LocalClass { + @Override + String m() { + return "AnotherSub " + arg + inlined; + } + } + } + } + System.out.println(new LocalClass().m()); + System.out.println(new LocalClass().new SubClass().m()); + System.out.println(new LocalClass().new SubSubClass().m()); + System.out.println(new LocalClass().new AnotherLocal().new AnotherSub().m()); + } + +} From 59e06373391e5c7cf29ebcab18b1852b557af274 Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Thu, 15 Aug 2013 22:33:43 +0200 Subject: [PATCH 059/218] 8015809: More user friendly compile-time errors for uncaught exceptions in lambda expression Producing individual errors for uncaught undeclared exceptions inside lambda expressions, rather than one error for the whole lambda Reviewed-by: mcimadamore --- .../com/sun/tools/javac/code/Type.java | 2 +- .../com/sun/tools/javac/comp/Attr.java | 7 +-- .../com/sun/tools/javac/comp/Flow.java | 49 +++++++++++++++++-- .../tools/javac/resources/compiler.properties | 4 -- .../com/sun/tools/javac/tree/JCTree.java | 2 +- .../ExceptionsInLambda.java} | 41 +++++++++++++--- .../tools/javac/lambda/ExceptionsInLambda.out | 4 ++ .../test/tools/javac/lambda/TargetType21.out | 3 +- 8 files changed, 88 insertions(+), 24 deletions(-) rename langtools/test/tools/javac/{diags/examples/IncompatibleThrownTypesInLambda.java => lambda/ExceptionsInLambda.java} (50%) create mode 100644 langtools/test/tools/javac/lambda/ExceptionsInLambda.out diff --git a/langtools/src/share/classes/com/sun/tools/javac/code/Type.java b/langtools/src/share/classes/com/sun/tools/javac/code/Type.java index 9384f43c8e7..fb6308ba9bd 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/code/Type.java +++ b/langtools/src/share/classes/com/sun/tools/javac/code/Type.java @@ -1161,7 +1161,7 @@ public abstract class Type implements TypeMirror { } public boolean contains(Type elem) { - return elem == this || contains(argtypes, elem) || restype.contains(elem); + return elem == this || contains(argtypes, elem) || restype.contains(elem) || contains(thrown, elem); } public MethodType asMethodType() { return this; } diff --git a/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java b/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java index 955880c4957..5a0a2edf7f7 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java @@ -2607,8 +2607,7 @@ public class Attr extends JCTree.Visitor { * are compatible with the expected functional interface descriptor. This means that: * (i) parameter types must be identical to those of the target descriptor; (ii) return * types must be compatible with the return type of the expected descriptor; - * (iii) thrown types must be 'included' in the thrown types list of the expected - * descriptor. + * (iii) finish inference of thrown types if required. */ private void checkLambdaCompatible(JCLambda tree, Type descriptor, CheckContext checkContext, boolean speculativeAttr) { Type returnType = checkContext.inferenceContext().asFree(descriptor.getReturnType()); @@ -2630,9 +2629,7 @@ public class Attr extends JCTree.Visitor { if (!speculativeAttr) { List thrownTypes = checkContext.inferenceContext().asFree(descriptor.getThrownTypes()); - if (chk.unhandled(tree.inferredThrownTypes == null ? List.nil() : tree.inferredThrownTypes, thrownTypes).nonEmpty()) { - log.error(tree, "incompatible.thrown.types.in.lambda", tree.inferredThrownTypes); - } + chk.unhandled(tree.inferredThrownTypes == null ? List.nil() : tree.inferredThrownTypes, thrownTypes); } } diff --git a/langtools/src/share/classes/com/sun/tools/javac/comp/Flow.java b/langtools/src/share/classes/com/sun/tools/javac/comp/Flow.java index 10ff59c4f74..e488d45b0c0 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/comp/Flow.java +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Flow.java @@ -224,7 +224,7 @@ public class Flow { } try { new AliveAnalyzer().analyzeTree(env, that, make); - new FlowAnalyzer().analyzeTree(env, that, make); + new LambdaFlowAnalyzer().analyzeTree(env, that, make); } finally { if (!speculative) { log.popDiagnosticHandler(diagHandler); @@ -1259,12 +1259,24 @@ public class Flow { ListBuffer prevPending = pendingExits; try { pendingExits = ListBuffer.lb(); - caught = List.of(syms.throwableType); //inhibit exception checking + caught = tree.getDescriptorType(types).getThrownTypes(); thrown = List.nil(); scan(tree.body); - tree.inferredThrownTypes = thrown; - } - finally { + List exits = pendingExits.toList(); + pendingExits = new ListBuffer(); + while (exits.nonEmpty()) { + FlowPendingExit exit = exits.head; + exits = exits.tail; + if (exit.thrown == null) { + Assert.check(exit.tree.hasTag(RETURN)); + } else { + // uncaught throws will be reported later + pendingExits.append(exit); + } + } + + errorUncaught(); + } finally { pendingExits = prevPending; caught = prevCaught; thrown = prevThrown; @@ -1302,6 +1314,33 @@ public class Flow { } } + /** + * Specialized pass that performs inference of thrown types for lambdas. + */ + class LambdaFlowAnalyzer extends FlowAnalyzer { + @Override + public void visitLambda(JCLambda tree) { + if (tree.type != null && + tree.type.isErroneous()) { + return; + } + List prevCaught = caught; + List prevThrown = thrown; + ListBuffer prevPending = pendingExits; + try { + pendingExits = ListBuffer.lb(); + caught = List.of(syms.throwableType); + thrown = List.nil(); + scan(tree.body); + tree.inferredThrownTypes = thrown; + } finally { + pendingExits = prevPending; + caught = prevCaught; + thrown = prevThrown; + } + } + } + /** * This pass implements (i) definite assignment analysis, which ensures that * each variable is assigned when used and (ii) definite unassignment analysis, diff --git a/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties b/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties index 908b0aff112..9361be25f50 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties +++ b/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties @@ -732,10 +732,6 @@ compiler.misc.incompatible.ret.type.in.mref=\ bad return type in method reference\n\ {0} -# 0: list of type -compiler.err.incompatible.thrown.types.in.lambda=\ - incompatible thrown types {0} in lambda expression - # 0: list of type compiler.err.incompatible.thrown.types.in.mref=\ incompatible thrown types {0} in method reference diff --git a/langtools/src/share/classes/com/sun/tools/javac/tree/JCTree.java b/langtools/src/share/classes/com/sun/tools/javac/tree/JCTree.java index 313596a3362..d2e9b67324b 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/tree/JCTree.java +++ b/langtools/src/share/classes/com/sun/tools/javac/tree/JCTree.java @@ -645,7 +645,7 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition { public List targets; public Type getDescriptorType(Types types) { - return types.findDescriptorType(targets.head); + return targets.nonEmpty() ? types.findDescriptorType(targets.head) : types.createErrorType(null); } } diff --git a/langtools/test/tools/javac/diags/examples/IncompatibleThrownTypesInLambda.java b/langtools/test/tools/javac/lambda/ExceptionsInLambda.java similarity index 50% rename from langtools/test/tools/javac/diags/examples/IncompatibleThrownTypesInLambda.java rename to langtools/test/tools/javac/lambda/ExceptionsInLambda.java index 53845226a4b..bb63dae8543 100644 --- a/langtools/test/tools/javac/diags/examples/IncompatibleThrownTypesInLambda.java +++ b/langtools/test/tools/javac/lambda/ExceptionsInLambda.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,12 +21,41 @@ * questions. */ -// key: compiler.err.incompatible.thrown.types.in.lambda +/* + * @test + * @bug 8015809 + * @summary Producing individual errors for uncaught undeclared exceptions inside lambda expressions, instead of one error for whole lambda + * @compile/fail/ref=ExceptionsInLambda.out -XDrawDiagnostics ExceptionsInLambda.java + */ -class IncompatibleThrownTypesInLambda { - interface SAM { - void m(); +import java.io.File; +import java.io.FileInputStream; +import java.io.FileReader; +import java.io.InputStream; +import java.io.Reader; + +public class ExceptionsInLambda { + + public static void main(Runnable p, File f) { + main(() -> { + StringBuilder sb = new StringBuilder(); + + Reader in = new FileReader(f); + int r; + + while ((r = in.read()) != (-1)) { + sb.append((char) r); + } + }, f); + + doOpen(() -> new FileInputStream(f)); } - SAM s = ()-> { throw new Exception(); }; + public static InputStream doOpen(Open open) { + return open.open(); + } + + public interface Open { + public InputStream open(); + } } diff --git a/langtools/test/tools/javac/lambda/ExceptionsInLambda.out b/langtools/test/tools/javac/lambda/ExceptionsInLambda.out new file mode 100644 index 00000000000..5cfa24916f5 --- /dev/null +++ b/langtools/test/tools/javac/lambda/ExceptionsInLambda.out @@ -0,0 +1,4 @@ +ExceptionsInLambda.java:43:25: compiler.err.unreported.exception.need.to.catch.or.throw: java.io.FileNotFoundException +ExceptionsInLambda.java:46:32: compiler.err.unreported.exception.need.to.catch.or.throw: java.io.IOException +ExceptionsInLambda.java:51:22: compiler.err.unreported.exception.need.to.catch.or.throw: java.io.FileNotFoundException +3 errors diff --git a/langtools/test/tools/javac/lambda/TargetType21.out b/langtools/test/tools/javac/lambda/TargetType21.out index 1dd507822d0..904e30f1278 100644 --- a/langtools/test/tools/javac/lambda/TargetType21.out +++ b/langtools/test/tools/javac/lambda/TargetType21.out @@ -1,6 +1,5 @@ TargetType21.java:28:9: compiler.err.ref.ambiguous: call, kindname.method, call(TargetType21.SAM2), TargetType21, kindname.method, call(TargetType21.SAM3), TargetType21 -TargetType21.java:28:14: compiler.err.incompatible.thrown.types.in.lambda: java.lang.Exception TargetType21.java:29:9: compiler.err.ref.ambiguous: call, kindname.method, call(TargetType21.SAM2), TargetType21, kindname.method, call(TargetType21.SAM3), TargetType21 TargetType21.java:30:13: compiler.err.prob.found.req: (compiler.misc.cyclic.inference: A) TargetType21.java:31:9: compiler.err.ref.ambiguous: call, kindname.method, call(TargetType21.SAM1), TargetType21, kindname.method, call(TargetType21.SAM3), TargetType21 -5 errors +4 errors From d992a671028d701165c9fe4118308a7dd5524e91 Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Thu, 15 Aug 2013 22:36:08 +0200 Subject: [PATCH 060/218] 8022508: javac crashes if the generics arity of a base class is wrong Reviewed-by: mcimadamore, vromero --- .../src/share/classes/com/sun/tools/javac/comp/Check.java | 2 +- langtools/test/tools/javac/generics/8016640/T8016640.java | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java b/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java index f4be291dabc..a60395a7ddd 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java @@ -1747,7 +1747,7 @@ public class Check { if (!sup.hasTag(CLASS)) return; for (Type t1 = sup; - t1.tsym.type.isParameterized(); + t1.hasTag(CLASS) && t1.tsym.type.isParameterized(); t1 = types.supertype(t1)) { for (Scope.Entry e1 = t1.tsym.members().elems; e1 != null; diff --git a/langtools/test/tools/javac/generics/8016640/T8016640.java b/langtools/test/tools/javac/generics/8016640/T8016640.java index 39e7c13e3eb..43c7680b094 100644 --- a/langtools/test/tools/javac/generics/8016640/T8016640.java +++ b/langtools/test/tools/javac/generics/8016640/T8016640.java @@ -1,10 +1,11 @@ /* * @test /nodynamiccopyright/ - * @bug 8016640 + * @bug 8016640 8022508 * @summary compiler hangs if the generics arity of a base class is wrong * @compile/fail/ref=T8016640.out -XDrawDiagnostics T8016640.java */ class T8016640 { static class Foo { } static class BadFoo extends Foo { } + static class SubBadFoo extends BadFoo { } } From 4d91f4e69d6d419aeba1b8eddc964ac251f1e6d3 Mon Sep 17 00:00:00 2001 From: Harold Seigel Date: Thu, 15 Aug 2013 20:04:10 -0400 Subject: [PATCH 061/218] 8003424: Enable Class Data Sharing for CompressedOops 8016729: ObjectAlignmentInBytes=16 now forces the use of heap based compressed oops 8005933: The -Xshare:auto option is ignored for -server Move klass metaspace above the heap and support CDS with compressed klass ptrs. Reviewed-by: coleenp, kvn, mgerdin, tschatzl, stefank --- .../src/cpu/sparc/vm/macroAssembler_sparc.cpp | 99 +++-- .../src/cpu/sparc/vm/macroAssembler_sparc.hpp | 3 + hotspot/src/cpu/sparc/vm/relocInfo_sparc.cpp | 4 +- hotspot/src/cpu/sparc/vm/sparc.ad | 19 +- .../src/cpu/sparc/vm/vtableStubs_sparc.cpp | 6 +- hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp | 126 +++--- hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp | 4 + hotspot/src/cpu/x86/vm/relocInfo_x86.cpp | 6 +- .../src/cpu/x86/vm/stubGenerator_x86_32.cpp | 1 - .../src/cpu/x86/vm/stubGenerator_x86_64.cpp | 1 - hotspot/src/cpu/x86/vm/vtableStubs_x86_64.cpp | 4 +- hotspot/src/cpu/x86/vm/x86_64.ad | 154 +------- hotspot/src/share/vm/memory/filemap.cpp | 23 +- hotspot/src/share/vm/memory/filemap.hpp | 11 +- hotspot/src/share/vm/memory/heap.cpp | 7 +- hotspot/src/share/vm/memory/metaspace.cpp | 367 +++++++++++++----- hotspot/src/share/vm/memory/metaspace.hpp | 41 +- .../src/share/vm/memory/metaspaceShared.cpp | 1 - hotspot/src/share/vm/memory/universe.cpp | 62 +-- hotspot/src/share/vm/memory/universe.hpp | 19 +- hotspot/src/share/vm/oops/klass.hpp | 10 + hotspot/src/share/vm/oops/klass.inline.hpp | 40 +- hotspot/src/share/vm/oops/oop.hpp | 13 +- hotspot/src/share/vm/oops/oop.inline.hpp | 55 +-- hotspot/src/share/vm/oops/oopsHierarchy.hpp | 6 +- hotspot/src/share/vm/runtime/arguments.cpp | 105 +++-- hotspot/src/share/vm/runtime/arguments.hpp | 1 + hotspot/src/share/vm/runtime/globals.hpp | 2 +- hotspot/src/share/vm/runtime/init.cpp | 3 +- .../share/vm/utilities/globalDefinitions.hpp | 2 + .../CDSCompressedKPtrs.java | 61 +++ .../CDSCompressedKPtrsError.java | 93 +++++ .../CDSCompressedKPtrs/XShareAuto.java | 76 ++++ .../CdsSameObjectAlignment.java | 3 +- 34 files changed, 876 insertions(+), 552 deletions(-) create mode 100644 hotspot/test/runtime/CDSCompressedKPtrs/CDSCompressedKPtrs.java create mode 100644 hotspot/test/runtime/CDSCompressedKPtrs/CDSCompressedKPtrsError.java create mode 100644 hotspot/test/runtime/CDSCompressedKPtrs/XShareAuto.java diff --git a/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.cpp b/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.cpp index 022e67ba203..d2c4e3b0261 100644 --- a/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,6 +29,7 @@ #include "interpreter/interpreter.hpp" #include "memory/cardTableModRefBS.hpp" #include "memory/resourceArea.hpp" +#include "memory/universe.hpp" #include "prims/methodHandles.hpp" #include "runtime/biasedLocking.hpp" #include "runtime/interfaceSupport.hpp" @@ -1145,7 +1146,7 @@ void MacroAssembler::set_narrow_klass(Klass* k, Register d) { assert(oop_recorder() != NULL, "this assembler needs an OopRecorder"); int klass_index = oop_recorder()->find_index(k); RelocationHolder rspec = metadata_Relocation::spec(klass_index); - narrowOop encoded_k = oopDesc::encode_klass(k); + narrowOop encoded_k = Klass::encode_klass(k); assert_not_delayed(); // Relocation with special format (see relocInfo_sparc.hpp). @@ -1419,7 +1420,6 @@ void MacroAssembler::verify_oop_subroutine() { load_klass(O0_obj, O0_obj); // assert((klass != NULL) br_null_short(O0_obj, pn, fail); - // TODO: Future assert that klass is lower 4g memory for UseCompressedKlassPointers wrccr( O5_save_flags ); // Restore CCR's @@ -4089,52 +4089,91 @@ void MacroAssembler::decode_heap_oop_not_null(Register src, Register dst) { } void MacroAssembler::encode_klass_not_null(Register r) { - assert(Metaspace::is_initialized(), "metaspace should be initialized"); assert (UseCompressedKlassPointers, "must be compressed"); - assert (LogKlassAlignmentInBytes == Universe::narrow_klass_shift(), "decode alg wrong"); - if (Universe::narrow_klass_base() != NULL) - sub(r, G6_heapbase, r); - srlx(r, LogKlassAlignmentInBytes, r); + assert(Universe::narrow_klass_base() != NULL, "narrow_klass_base should be initialized"); + assert(r != G6_heapbase, "bad register choice"); + set((intptr_t)Universe::narrow_klass_base(), G6_heapbase); + sub(r, G6_heapbase, r); + if (Universe::narrow_klass_shift() != 0) { + assert (LogKlassAlignmentInBytes == Universe::narrow_klass_shift(), "decode alg wrong"); + srlx(r, LogKlassAlignmentInBytes, r); + } + reinit_heapbase(); } void MacroAssembler::encode_klass_not_null(Register src, Register dst) { - assert(Metaspace::is_initialized(), "metaspace should be initialized"); - assert (UseCompressedKlassPointers, "must be compressed"); - assert (LogKlassAlignmentInBytes == Universe::narrow_klass_shift(), "decode alg wrong"); - if (Universe::narrow_klass_base() == NULL) { - srlx(src, LogKlassAlignmentInBytes, dst); + if (src == dst) { + encode_klass_not_null(src); } else { - sub(src, G6_heapbase, dst); - srlx(dst, LogKlassAlignmentInBytes, dst); + assert (UseCompressedKlassPointers, "must be compressed"); + assert(Universe::narrow_klass_base() != NULL, "narrow_klass_base should be initialized"); + set((intptr_t)Universe::narrow_klass_base(), dst); + sub(src, dst, dst); + if (Universe::narrow_klass_shift() != 0) { + srlx(dst, LogKlassAlignmentInBytes, dst); + } } } +// Function instr_size_for_decode_klass_not_null() counts the instructions +// generated by decode_klass_not_null() and reinit_heapbase(). Hence, if +// the instructions they generate change, then this method needs to be updated. +int MacroAssembler::instr_size_for_decode_klass_not_null() { + assert (UseCompressedKlassPointers, "only for compressed klass ptrs"); + // set + add + set + int num_instrs = insts_for_internal_set((intptr_t)Universe::narrow_klass_base()) + 1 + + insts_for_internal_set((intptr_t)Universe::narrow_ptrs_base()); + if (Universe::narrow_klass_shift() == 0) { + return num_instrs * BytesPerInstWord; + } else { // sllx + return (num_instrs + 1) * BytesPerInstWord; + } +} + +// !!! If the instructions that get generated here change then function +// instr_size_for_decode_klass_not_null() needs to get updated. void MacroAssembler::decode_klass_not_null(Register r) { - assert(Metaspace::is_initialized(), "metaspace should be initialized"); // Do not add assert code to this unless you change vtableStubs_sparc.cpp // pd_code_size_limit. assert (UseCompressedKlassPointers, "must be compressed"); - assert (LogKlassAlignmentInBytes == Universe::narrow_klass_shift(), "decode alg wrong"); - sllx(r, LogKlassAlignmentInBytes, r); - if (Universe::narrow_klass_base() != NULL) - add(r, G6_heapbase, r); + assert(Universe::narrow_klass_base() != NULL, "narrow_klass_base should be initialized"); + assert(r != G6_heapbase, "bad register choice"); + set((intptr_t)Universe::narrow_klass_base(), G6_heapbase); + if (Universe::narrow_klass_shift() != 0) + sllx(r, LogKlassAlignmentInBytes, r); + add(r, G6_heapbase, r); + reinit_heapbase(); } void MacroAssembler::decode_klass_not_null(Register src, Register dst) { - assert(Metaspace::is_initialized(), "metaspace should be initialized"); - // Do not add assert code to this unless you change vtableStubs_sparc.cpp - // pd_code_size_limit. - assert (UseCompressedKlassPointers, "must be compressed"); - assert (LogKlassAlignmentInBytes == Universe::narrow_klass_shift(), "decode alg wrong"); - sllx(src, LogKlassAlignmentInBytes, dst); - if (Universe::narrow_klass_base() != NULL) - add(dst, G6_heapbase, dst); + if (src == dst) { + decode_klass_not_null(src); + } else { + // Do not add assert code to this unless you change vtableStubs_sparc.cpp + // pd_code_size_limit. + assert (UseCompressedKlassPointers, "must be compressed"); + assert(Universe::narrow_klass_base() != NULL, "narrow_klass_base should be initialized"); + if (Universe::narrow_klass_shift() != 0) { + assert((src != G6_heapbase) && (dst != G6_heapbase), "bad register choice"); + set((intptr_t)Universe::narrow_klass_base(), G6_heapbase); + sllx(src, LogKlassAlignmentInBytes, dst); + add(dst, G6_heapbase, dst); + reinit_heapbase(); + } else { + set((intptr_t)Universe::narrow_klass_base(), dst); + add(src, dst, dst); + } + } } void MacroAssembler::reinit_heapbase() { if (UseCompressedOops || UseCompressedKlassPointers) { - AddressLiteral base(Universe::narrow_ptrs_base_addr()); - load_ptr_contents(base, G6_heapbase); + if (Universe::heap() != NULL) { + set((intptr_t)Universe::narrow_ptrs_base(), G6_heapbase); + } else { + AddressLiteral base(Universe::narrow_ptrs_base_addr()); + load_ptr_contents(base, G6_heapbase); + } } } diff --git a/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.hpp b/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.hpp index 72fd61f52c2..f03dc8e5e72 100644 --- a/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.hpp +++ b/hotspot/src/cpu/sparc/vm/macroAssembler_sparc.hpp @@ -1177,6 +1177,9 @@ public: void push_CPU_state(); void pop_CPU_state(); + // Returns the byte size of the instructions generated by decode_klass_not_null(). + static int instr_size_for_decode_klass_not_null(); + // if heap base register is used - reinit it with the correct value void reinit_heapbase(); diff --git a/hotspot/src/cpu/sparc/vm/relocInfo_sparc.cpp b/hotspot/src/cpu/sparc/vm/relocInfo_sparc.cpp index 97bd2fcc692..e132c42d474 100644 --- a/hotspot/src/cpu/sparc/vm/relocInfo_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/relocInfo_sparc.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -97,7 +97,7 @@ void Relocation::pd_set_data_value(address x, intptr_t o, bool verify_only) { guarantee(Assembler::inv_op2(inst)==Assembler::sethi_op2, "must be sethi"); if (format() != 0) { assert(type() == relocInfo::oop_type || type() == relocInfo::metadata_type, "only narrow oops or klasses case"); - jint np = type() == relocInfo::oop_type ? oopDesc::encode_heap_oop((oop)x) : oopDesc::encode_klass((Klass*)x); + jint np = type() == relocInfo::oop_type ? oopDesc::encode_heap_oop((oop)x) : Klass::encode_klass((Klass*)x); inst &= ~Assembler::hi22(-1); inst |= Assembler::hi22((intptr_t)np); if (verify_only) { diff --git a/hotspot/src/cpu/sparc/vm/sparc.ad b/hotspot/src/cpu/sparc/vm/sparc.ad index 932da4a5930..a72bffdadeb 100644 --- a/hotspot/src/cpu/sparc/vm/sparc.ad +++ b/hotspot/src/cpu/sparc/vm/sparc.ad @@ -559,10 +559,7 @@ int MachCallDynamicJavaNode::ret_addr_offset() { int klass_load_size; if (UseCompressedKlassPointers) { assert(Universe::heap() != NULL, "java heap should be initialized"); - if (Universe::narrow_klass_base() == NULL) - klass_load_size = 2*BytesPerInstWord; // see MacroAssembler::load_klass() - else - klass_load_size = 3*BytesPerInstWord; + klass_load_size = MacroAssembler::instr_size_for_decode_klass_not_null() + 1*BytesPerInstWord; } else { klass_load_size = 1*BytesPerInstWord; } @@ -1663,9 +1660,12 @@ void MachUEPNode::format( PhaseRegAlloc *ra_, outputStream *st ) const { if (UseCompressedKlassPointers) { assert(Universe::heap() != NULL, "java heap should be initialized"); st->print_cr("\tLDUW [R_O0 + oopDesc::klass_offset_in_bytes],R_G5\t! Inline cache check - compressed klass"); - st->print_cr("\tSLL R_G5,3,R_G5"); - if (Universe::narrow_klass_base() != NULL) - st->print_cr("\tADD R_G5,R_G6_heap_base,R_G5"); + st->print_cr("\tSET Universe::narrow_klass_base,R_G6_heap_base"); + if (Universe::narrow_klass_shift() != 0) { + st->print_cr("\tSLL R_G5,3,R_G5"); + } + st->print_cr("\tADD R_G5,R_G6_heap_base,R_G5"); + st->print_cr("\tSET Universe::narrow_ptrs_base,R_G6_heap_base"); } else { st->print_cr("\tLDX [R_O0 + oopDesc::klass_offset_in_bytes],R_G5\t! Inline cache check"); } @@ -2563,10 +2563,7 @@ encode %{ int klass_load_size; if (UseCompressedKlassPointers) { assert(Universe::heap() != NULL, "java heap should be initialized"); - if (Universe::narrow_klass_base() == NULL) - klass_load_size = 2*BytesPerInstWord; - else - klass_load_size = 3*BytesPerInstWord; + klass_load_size = MacroAssembler::instr_size_for_decode_klass_not_null() + 1*BytesPerInstWord; } else { klass_load_size = 1*BytesPerInstWord; } diff --git a/hotspot/src/cpu/sparc/vm/vtableStubs_sparc.cpp b/hotspot/src/cpu/sparc/vm/vtableStubs_sparc.cpp index 3c4f24c3867..39663758035 100644 --- a/hotspot/src/cpu/sparc/vm/vtableStubs_sparc.cpp +++ b/hotspot/src/cpu/sparc/vm/vtableStubs_sparc.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -219,13 +219,13 @@ int VtableStub::pd_code_size_limit(bool is_vtable_stub) { const int basic = 5*BytesPerInstWord + // shift;add for load_klass (only shift with zero heap based) (UseCompressedKlassPointers ? - ((Universe::narrow_klass_base() == NULL) ? BytesPerInstWord : 2*BytesPerInstWord) : 0); + MacroAssembler::instr_size_for_decode_klass_not_null() : 0); return basic + slop; } else { const int basic = (28 LP64_ONLY(+ 6)) * BytesPerInstWord + // shift;add for load_klass (only shift with zero heap based) (UseCompressedKlassPointers ? - ((Universe::narrow_klass_base() == NULL) ? BytesPerInstWord : 2*BytesPerInstWord) : 0); + MacroAssembler::instr_size_for_decode_klass_not_null() : 0); return (basic + slop); } } diff --git a/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp b/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp index 8aad6965156..b331f694959 100644 --- a/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp +++ b/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp @@ -30,6 +30,7 @@ #include "interpreter/interpreter.hpp" #include "memory/cardTableModRefBS.hpp" #include "memory/resourceArea.hpp" +#include "memory/universe.hpp" #include "prims/methodHandles.hpp" #include "runtime/biasedLocking.hpp" #include "runtime/interfaceSupport.hpp" @@ -4810,23 +4811,8 @@ void MacroAssembler::load_klass(Register dst, Register src) { } void MacroAssembler::load_prototype_header(Register dst, Register src) { -#ifdef _LP64 - if (UseCompressedKlassPointers) { - assert (Universe::heap() != NULL, "java heap should be initialized"); - movl(dst, Address(src, oopDesc::klass_offset_in_bytes())); - if (Universe::narrow_klass_shift() != 0) { - assert(LogKlassAlignmentInBytes == Universe::narrow_klass_shift(), "decode alg wrong"); - assert(LogKlassAlignmentInBytes == Address::times_8, "klass not aligned on 64bits?"); - movq(dst, Address(r12_heapbase, dst, Address::times_8, Klass::prototype_header_offset())); - } else { - movq(dst, Address(dst, Klass::prototype_header_offset())); - } - } else -#endif - { - movptr(dst, Address(src, oopDesc::klass_offset_in_bytes())); - movptr(dst, Address(dst, Klass::prototype_header_offset())); - } + load_klass(dst, src); + movptr(dst, Address(dst, Klass::prototype_header_offset())); } void MacroAssembler::store_klass(Register dst, Register src) { @@ -4914,7 +4900,7 @@ void MacroAssembler::store_klass_gap(Register dst, Register src) { #ifdef ASSERT void MacroAssembler::verify_heapbase(const char* msg) { - assert (UseCompressedOops || UseCompressedKlassPointers, "should be compressed"); + assert (UseCompressedOops, "should be compressed"); assert (Universe::heap() != NULL, "java heap should be initialized"); if (CheckCompressedOops) { Label ok; @@ -5058,69 +5044,80 @@ void MacroAssembler::decode_heap_oop_not_null(Register dst, Register src) { } void MacroAssembler::encode_klass_not_null(Register r) { - assert(Metaspace::is_initialized(), "metaspace should be initialized"); -#ifdef ASSERT - verify_heapbase("MacroAssembler::encode_klass_not_null: heap base corrupted?"); -#endif - if (Universe::narrow_klass_base() != NULL) { - subq(r, r12_heapbase); - } + assert(Universe::narrow_klass_base() != NULL, "Base should be initialized"); + // Use r12 as a scratch register in which to temporarily load the narrow_klass_base. + assert(r != r12_heapbase, "Encoding a klass in r12"); + mov64(r12_heapbase, (int64_t)Universe::narrow_klass_base()); + subq(r, r12_heapbase); if (Universe::narrow_klass_shift() != 0) { assert (LogKlassAlignmentInBytes == Universe::narrow_klass_shift(), "decode alg wrong"); shrq(r, LogKlassAlignmentInBytes); } + reinit_heapbase(); } void MacroAssembler::encode_klass_not_null(Register dst, Register src) { - assert(Metaspace::is_initialized(), "metaspace should be initialized"); -#ifdef ASSERT - verify_heapbase("MacroAssembler::encode_klass_not_null2: heap base corrupted?"); -#endif - if (dst != src) { - movq(dst, src); - } - if (Universe::narrow_klass_base() != NULL) { - subq(dst, r12_heapbase); - } - if (Universe::narrow_klass_shift() != 0) { - assert (LogKlassAlignmentInBytes == Universe::narrow_klass_shift(), "decode alg wrong"); - shrq(dst, LogKlassAlignmentInBytes); + if (dst == src) { + encode_klass_not_null(src); + } else { + mov64(dst, (int64_t)Universe::narrow_klass_base()); + negq(dst); + addq(dst, src); + if (Universe::narrow_klass_shift() != 0) { + assert (LogKlassAlignmentInBytes == Universe::narrow_klass_shift(), "decode alg wrong"); + shrq(dst, LogKlassAlignmentInBytes); + } } } +// Function instr_size_for_decode_klass_not_null() counts the instructions +// generated by decode_klass_not_null(register r) and reinit_heapbase(), +// when (Universe::heap() != NULL). Hence, if the instructions they +// generate change, then this method needs to be updated. +int MacroAssembler::instr_size_for_decode_klass_not_null() { + assert (UseCompressedKlassPointers, "only for compressed klass ptrs"); + // mov64 + addq + shlq? + mov64 (for reinit_heapbase()). + return (Universe::narrow_klass_shift() == 0 ? 20 : 24); +} + +// !!! If the instructions that get generated here change then function +// instr_size_for_decode_klass_not_null() needs to get updated. void MacroAssembler::decode_klass_not_null(Register r) { - assert(Metaspace::is_initialized(), "metaspace should be initialized"); // Note: it will change flags + assert(Universe::narrow_klass_base() != NULL, "Base should be initialized"); assert (UseCompressedKlassPointers, "should only be used for compressed headers"); + assert(r != r12_heapbase, "Decoding a klass in r12"); // Cannot assert, unverified entry point counts instructions (see .ad file) // vtableStubs also counts instructions in pd_code_size_limit. // Also do not verify_oop as this is called by verify_oop. if (Universe::narrow_klass_shift() != 0) { assert(LogKlassAlignmentInBytes == Universe::narrow_klass_shift(), "decode alg wrong"); shlq(r, LogKlassAlignmentInBytes); - if (Universe::narrow_klass_base() != NULL) { - addq(r, r12_heapbase); - } - } else { - assert (Universe::narrow_klass_base() == NULL, "sanity"); } + // Use r12 as a scratch register in which to temporarily load the narrow_klass_base. + mov64(r12_heapbase, (int64_t)Universe::narrow_klass_base()); + addq(r, r12_heapbase); + reinit_heapbase(); } void MacroAssembler::decode_klass_not_null(Register dst, Register src) { - assert(Metaspace::is_initialized(), "metaspace should be initialized"); // Note: it will change flags + assert(Universe::narrow_klass_base() != NULL, "Base should be initialized"); assert (UseCompressedKlassPointers, "should only be used for compressed headers"); - // Cannot assert, unverified entry point counts instructions (see .ad file) - // vtableStubs also counts instructions in pd_code_size_limit. - // Also do not verify_oop as this is called by verify_oop. - if (Universe::narrow_klass_shift() != 0) { - assert(LogKlassAlignmentInBytes == Universe::narrow_klass_shift(), "decode alg wrong"); - assert(LogKlassAlignmentInBytes == Address::times_8, "klass not aligned on 64bits?"); - leaq(dst, Address(r12_heapbase, src, Address::times_8, 0)); + if (dst == src) { + decode_klass_not_null(dst); } else { - assert (Universe::narrow_klass_base() == NULL, "sanity"); - if (dst != src) { - movq(dst, src); + // Cannot assert, unverified entry point counts instructions (see .ad file) + // vtableStubs also counts instructions in pd_code_size_limit. + // Also do not verify_oop as this is called by verify_oop. + + mov64(dst, (int64_t)Universe::narrow_klass_base()); + if (Universe::narrow_klass_shift() != 0) { + assert(LogKlassAlignmentInBytes == Universe::narrow_klass_shift(), "decode alg wrong"); + assert(LogKlassAlignmentInBytes == Address::times_8, "klass not aligned on 64bits?"); + leaq(dst, Address(dst, src, Address::times_8, 0)); + } else { + addq(dst, src); } } } @@ -5148,7 +5145,7 @@ void MacroAssembler::set_narrow_klass(Register dst, Klass* k) { assert (oop_recorder() != NULL, "this assembler needs an OopRecorder"); int klass_index = oop_recorder()->find_index(k); RelocationHolder rspec = metadata_Relocation::spec(klass_index); - mov_narrow_oop(dst, oopDesc::encode_klass(k), rspec); + mov_narrow_oop(dst, Klass::encode_klass(k), rspec); } void MacroAssembler::set_narrow_klass(Address dst, Klass* k) { @@ -5156,7 +5153,7 @@ void MacroAssembler::set_narrow_klass(Address dst, Klass* k) { assert (oop_recorder() != NULL, "this assembler needs an OopRecorder"); int klass_index = oop_recorder()->find_index(k); RelocationHolder rspec = metadata_Relocation::spec(klass_index); - mov_narrow_oop(dst, oopDesc::encode_klass(k), rspec); + mov_narrow_oop(dst, Klass::encode_klass(k), rspec); } void MacroAssembler::cmp_narrow_oop(Register dst, jobject obj) { @@ -5182,7 +5179,7 @@ void MacroAssembler::cmp_narrow_klass(Register dst, Klass* k) { assert (oop_recorder() != NULL, "this assembler needs an OopRecorder"); int klass_index = oop_recorder()->find_index(k); RelocationHolder rspec = metadata_Relocation::spec(klass_index); - Assembler::cmp_narrow_oop(dst, oopDesc::encode_klass(k), rspec); + Assembler::cmp_narrow_oop(dst, Klass::encode_klass(k), rspec); } void MacroAssembler::cmp_narrow_klass(Address dst, Klass* k) { @@ -5190,14 +5187,23 @@ void MacroAssembler::cmp_narrow_klass(Address dst, Klass* k) { assert (oop_recorder() != NULL, "this assembler needs an OopRecorder"); int klass_index = oop_recorder()->find_index(k); RelocationHolder rspec = metadata_Relocation::spec(klass_index); - Assembler::cmp_narrow_oop(dst, oopDesc::encode_klass(k), rspec); + Assembler::cmp_narrow_oop(dst, Klass::encode_klass(k), rspec); } void MacroAssembler::reinit_heapbase() { if (UseCompressedOops || UseCompressedKlassPointers) { - movptr(r12_heapbase, ExternalAddress((address)Universe::narrow_ptrs_base_addr())); + if (Universe::heap() != NULL) { + if (Universe::narrow_oop_base() == NULL) { + MacroAssembler::xorptr(r12_heapbase, r12_heapbase); + } else { + mov64(r12_heapbase, (int64_t)Universe::narrow_ptrs_base()); + } + } else { + movptr(r12_heapbase, ExternalAddress((address)Universe::narrow_ptrs_base_addr())); + } } } + #endif // _LP64 diff --git a/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp b/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp index 3acef073c0e..293b3b73a37 100644 --- a/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp +++ b/hotspot/src/cpu/x86/vm/macroAssembler_x86.hpp @@ -371,6 +371,10 @@ class MacroAssembler: public Assembler { void cmp_narrow_klass(Register dst, Klass* k); void cmp_narrow_klass(Address dst, Klass* k); + // Returns the byte size of the instructions generated by decode_klass_not_null() + // when compressed klass pointers are being used. + static int instr_size_for_decode_klass_not_null(); + // if heap base register is used - reinit it with the correct value void reinit_heapbase(); diff --git a/hotspot/src/cpu/x86/vm/relocInfo_x86.cpp b/hotspot/src/cpu/x86/vm/relocInfo_x86.cpp index 4cb5c3f61ca..14868cb45a1 100644 --- a/hotspot/src/cpu/x86/vm/relocInfo_x86.cpp +++ b/hotspot/src/cpu/x86/vm/relocInfo_x86.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -55,9 +55,9 @@ void Relocation::pd_set_data_value(address x, intptr_t o, bool verify_only) { } } else { if (verify_only) { - assert(*(uint32_t*) disp == oopDesc::encode_klass((Klass*)x), "instructions must match"); + assert(*(uint32_t*) disp == Klass::encode_klass((Klass*)x), "instructions must match"); } else { - *(int32_t*) disp = oopDesc::encode_klass((Klass*)x); + *(int32_t*) disp = Klass::encode_klass((Klass*)x); } } } else { diff --git a/hotspot/src/cpu/x86/vm/stubGenerator_x86_32.cpp b/hotspot/src/cpu/x86/vm/stubGenerator_x86_32.cpp index a8abfea6bcd..12fccf9ddd3 100644 --- a/hotspot/src/cpu/x86/vm/stubGenerator_x86_32.cpp +++ b/hotspot/src/cpu/x86/vm/stubGenerator_x86_32.cpp @@ -675,7 +675,6 @@ class StubGenerator: public StubCodeGenerator { __ movptr(rax, Address(rax, oopDesc::klass_offset_in_bytes())); // get klass __ testptr(rax, rax); __ jcc(Assembler::zero, error); // if klass is NULL it is broken - // TODO: Future assert that klass is lower 4g memory for UseCompressedKlassPointers // return if everything seems ok __ bind(exit); diff --git a/hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp b/hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp index e38139d28ec..a16611280fb 100644 --- a/hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp +++ b/hotspot/src/cpu/x86/vm/stubGenerator_x86_64.cpp @@ -1021,7 +1021,6 @@ class StubGenerator: public StubCodeGenerator { __ load_klass(rax, rax); // get klass __ testptr(rax, rax); __ jcc(Assembler::zero, error); // if klass is NULL it is broken - // TODO: Future assert that klass is lower 4g memory for UseCompressedKlassPointers // return if everything seems ok __ bind(exit); diff --git a/hotspot/src/cpu/x86/vm/vtableStubs_x86_64.cpp b/hotspot/src/cpu/x86/vm/vtableStubs_x86_64.cpp index 0dc056cdbaf..518da23eb60 100644 --- a/hotspot/src/cpu/x86/vm/vtableStubs_x86_64.cpp +++ b/hotspot/src/cpu/x86/vm/vtableStubs_x86_64.cpp @@ -211,11 +211,11 @@ int VtableStub::pd_code_size_limit(bool is_vtable_stub) { if (is_vtable_stub) { // Vtable stub size return (DebugVtables ? 512 : 24) + (CountCompiledCalls ? 13 : 0) + - (UseCompressedKlassPointers ? 16 : 0); // 1 leaq can be 3 bytes + 1 long + (UseCompressedKlassPointers ? MacroAssembler::instr_size_for_decode_klass_not_null() : 0); } else { // Itable stub size return (DebugVtables ? 512 : 74) + (CountCompiledCalls ? 13 : 0) + - (UseCompressedKlassPointers ? 32 : 0); // 2 leaqs + (UseCompressedKlassPointers ? MacroAssembler::instr_size_for_decode_klass_not_null() : 0); } // In order to tune these parameters, run the JVM with VM options // +PrintMiscellaneous and +WizardMode to see information about diff --git a/hotspot/src/cpu/x86/vm/x86_64.ad b/hotspot/src/cpu/x86/vm/x86_64.ad index e47976270cd..f550208e94d 100644 --- a/hotspot/src/cpu/x86/vm/x86_64.ad +++ b/hotspot/src/cpu/x86/vm/x86_64.ad @@ -1393,9 +1393,7 @@ void MachUEPNode::format(PhaseRegAlloc* ra_, outputStream* st) const { if (UseCompressedKlassPointers) { st->print_cr("movl rscratch1, [j_rarg0 + oopDesc::klass_offset_in_bytes()]\t# compressed klass"); - if (Universe::narrow_klass_shift() != 0) { - st->print_cr("\tdecode_klass_not_null rscratch1, rscratch1"); - } + st->print_cr("\tdecode_klass_not_null rscratch1, rscratch1"); st->print_cr("\tcmpq rax, rscratch1\t # Inline cache check"); } else { st->print_cr("\tcmpq rax, [j_rarg0 + oopDesc::klass_offset_in_bytes()]\t" @@ -4035,146 +4033,6 @@ operand indPosIndexScaleOffsetNarrow(rRegN reg, immL32 off, rRegI idx, immI2 sca %} %} -operand indirectNarrowKlass(rRegN reg) -%{ - predicate(Universe::narrow_klass_shift() == 0); - constraint(ALLOC_IN_RC(ptr_reg)); - match(DecodeNKlass reg); - - format %{ "[$reg]" %} - interface(MEMORY_INTER) %{ - base($reg); - index(0x4); - scale(0x0); - disp(0x0); - %} -%} - -operand indOffset8NarrowKlass(rRegN reg, immL8 off) -%{ - predicate(Universe::narrow_klass_shift() == 0); - constraint(ALLOC_IN_RC(ptr_reg)); - match(AddP (DecodeNKlass reg) off); - - format %{ "[$reg + $off (8-bit)]" %} - interface(MEMORY_INTER) %{ - base($reg); - index(0x4); - scale(0x0); - disp($off); - %} -%} - -operand indOffset32NarrowKlass(rRegN reg, immL32 off) -%{ - predicate(Universe::narrow_klass_shift() == 0); - constraint(ALLOC_IN_RC(ptr_reg)); - match(AddP (DecodeNKlass reg) off); - - format %{ "[$reg + $off (32-bit)]" %} - interface(MEMORY_INTER) %{ - base($reg); - index(0x4); - scale(0x0); - disp($off); - %} -%} - -operand indIndexOffsetNarrowKlass(rRegN reg, rRegL lreg, immL32 off) -%{ - predicate(Universe::narrow_klass_shift() == 0); - constraint(ALLOC_IN_RC(ptr_reg)); - match(AddP (AddP (DecodeNKlass reg) lreg) off); - - op_cost(10); - format %{"[$reg + $off + $lreg]" %} - interface(MEMORY_INTER) %{ - base($reg); - index($lreg); - scale(0x0); - disp($off); - %} -%} - -operand indIndexNarrowKlass(rRegN reg, rRegL lreg) -%{ - predicate(Universe::narrow_klass_shift() == 0); - constraint(ALLOC_IN_RC(ptr_reg)); - match(AddP (DecodeNKlass reg) lreg); - - op_cost(10); - format %{"[$reg + $lreg]" %} - interface(MEMORY_INTER) %{ - base($reg); - index($lreg); - scale(0x0); - disp(0x0); - %} -%} - -operand indIndexScaleNarrowKlass(rRegN reg, rRegL lreg, immI2 scale) -%{ - predicate(Universe::narrow_klass_shift() == 0); - constraint(ALLOC_IN_RC(ptr_reg)); - match(AddP (DecodeNKlass reg) (LShiftL lreg scale)); - - op_cost(10); - format %{"[$reg + $lreg << $scale]" %} - interface(MEMORY_INTER) %{ - base($reg); - index($lreg); - scale($scale); - disp(0x0); - %} -%} - -operand indIndexScaleOffsetNarrowKlass(rRegN reg, immL32 off, rRegL lreg, immI2 scale) -%{ - predicate(Universe::narrow_klass_shift() == 0); - constraint(ALLOC_IN_RC(ptr_reg)); - match(AddP (AddP (DecodeNKlass reg) (LShiftL lreg scale)) off); - - op_cost(10); - format %{"[$reg + $off + $lreg << $scale]" %} - interface(MEMORY_INTER) %{ - base($reg); - index($lreg); - scale($scale); - disp($off); - %} -%} - -operand indCompressedKlassOffset(rRegN reg, immL32 off) %{ - predicate(UseCompressedKlassPointers && (Universe::narrow_klass_shift() == Address::times_8)); - constraint(ALLOC_IN_RC(ptr_reg)); - match(AddP (DecodeNKlass reg) off); - - op_cost(10); - format %{"[R12 + $reg << 3 + $off] (compressed klass addressing)" %} - interface(MEMORY_INTER) %{ - base(0xc); // R12 - index($reg); - scale(0x3); - disp($off); - %} -%} - -operand indPosIndexScaleOffsetNarrowKlass(rRegN reg, immL32 off, rRegI idx, immI2 scale) -%{ - constraint(ALLOC_IN_RC(ptr_reg)); - predicate(Universe::narrow_klass_shift() == 0 && n->in(2)->in(3)->in(1)->as_Type()->type()->is_long()->_lo >= 0); - match(AddP (AddP (DecodeNKlass reg) (LShiftL (ConvI2L idx) scale)) off); - - op_cost(10); - format %{"[$reg + $off + $idx << $scale]" %} - interface(MEMORY_INTER) %{ - base($reg); - index($idx); - scale($scale); - disp($off); - %} -%} - //----------Special Memory Operands-------------------------------------------- // Stack Slot Operand - This operand is used for loading and storing temporary // values on the stack where a match requires a value to @@ -4345,11 +4203,7 @@ opclass memory(indirect, indOffset8, indOffset32, indIndexOffset, indIndex, indCompressedOopOffset, indirectNarrow, indOffset8Narrow, indOffset32Narrow, indIndexOffsetNarrow, indIndexNarrow, indIndexScaleNarrow, - indIndexScaleOffsetNarrow, indPosIndexScaleOffsetNarrow, - indCompressedKlassOffset, - indirectNarrowKlass, indOffset8NarrowKlass, indOffset32NarrowKlass, - indIndexOffsetNarrowKlass, indIndexNarrowKlass, indIndexScaleNarrowKlass, - indIndexScaleOffsetNarrowKlass, indPosIndexScaleOffsetNarrowKlass); + indIndexScaleOffsetNarrow, indPosIndexScaleOffsetNarrow); //----------PIPELINE----------------------------------------------------------- // Rules which define the behavior of the target architectures pipeline. @@ -6665,7 +6519,7 @@ instruct decodeHeapOop_not_null(rRegP dst, rRegN src, rFlagsReg cr) %{ instruct encodeKlass_not_null(rRegN dst, rRegP src, rFlagsReg cr) %{ match(Set dst (EncodePKlass src)); effect(KILL cr); - format %{ "encode_heap_oop_not_null $dst,$src" %} + format %{ "encode_klass_not_null $dst,$src" %} ins_encode %{ __ encode_klass_not_null($dst$$Register, $src$$Register); %} @@ -6675,7 +6529,7 @@ instruct encodeKlass_not_null(rRegN dst, rRegP src, rFlagsReg cr) %{ instruct decodeKlass_not_null(rRegP dst, rRegN src, rFlagsReg cr) %{ match(Set dst (DecodeNKlass src)); effect(KILL cr); - format %{ "decode_heap_oop_not_null $dst,$src" %} + format %{ "decode_klass_not_null $dst,$src" %} ins_encode %{ Register s = $src$$Register; Register d = $dst$$Register; diff --git a/hotspot/src/share/vm/memory/filemap.cpp b/hotspot/src/share/vm/memory/filemap.cpp index 5dfaf6f9701..d036266b00f 100644 --- a/hotspot/src/share/vm/memory/filemap.cpp +++ b/hotspot/src/share/vm/memory/filemap.cpp @@ -362,15 +362,12 @@ bool FileMapInfo::remap_shared_readonly_as_readwrite() { ReservedSpace FileMapInfo::reserve_shared_memory() { struct FileMapInfo::FileMapHeader::space_info* si = &_header._space[0]; char* requested_addr = si->_base; - size_t alignment = os::vm_allocation_granularity(); - size_t size = align_size_up(SharedReadOnlySize + SharedReadWriteSize + - SharedMiscDataSize + SharedMiscCodeSize, - alignment); + size_t size = FileMapInfo::shared_spaces_size(); // Reserve the space first, then map otherwise map will go right over some // other reserved memory (like the code cache). - ReservedSpace rs(size, alignment, false, requested_addr); + ReservedSpace rs(size, os::vm_allocation_granularity(), false, requested_addr); if (!rs.is_reserved()) { fail_continue(err_msg("Unable to reserve shared space at required address " INTPTR_FORMAT, requested_addr)); return rs; @@ -559,3 +556,19 @@ void FileMapInfo::print_shared_spaces() { si->_base, si->_base + si->_used); } } + +// Unmap mapped regions of shared space. +void FileMapInfo::stop_sharing_and_unmap(const char* msg) { + FileMapInfo *map_info = FileMapInfo::current_info(); + if (map_info) { + map_info->fail_continue(msg); + for (int i = 0; i < MetaspaceShared::n_regions; i++) { + if (map_info->_header._space[i]._base != NULL) { + map_info->unmap_region(i); + map_info->_header._space[i]._base = NULL; + } + } + } else if (DumpSharedSpaces) { + fail_stop(msg, NULL); + } +} diff --git a/hotspot/src/share/vm/memory/filemap.hpp b/hotspot/src/share/vm/memory/filemap.hpp index ee4ccec5bfe..8d7535ed990 100644 --- a/hotspot/src/share/vm/memory/filemap.hpp +++ b/hotspot/src/share/vm/memory/filemap.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -150,6 +150,15 @@ public: // Return true if given address is in the mapped shared space. bool is_in_shared_space(const void* p) NOT_CDS_RETURN_(false); void print_shared_spaces() NOT_CDS_RETURN; + + static size_t shared_spaces_size() { + return align_size_up(SharedReadOnlySize + SharedReadWriteSize + + SharedMiscDataSize + SharedMiscCodeSize, + os::vm_allocation_granularity()); + } + + // Stop CDS sharing and unmap CDS regions. + static void stop_sharing_and_unmap(const char* msg); }; #endif // SHARE_VM_MEMORY_FILEMAP_HPP diff --git a/hotspot/src/share/vm/memory/heap.cpp b/hotspot/src/share/vm/memory/heap.cpp index 727690b5c7f..f00709684b4 100644 --- a/hotspot/src/share/vm/memory/heap.cpp +++ b/hotspot/src/share/vm/memory/heap.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -118,9 +118,12 @@ bool CodeHeap::reserve(size_t reserved_size, size_t committed_size, _number_of_committed_segments = size_to_segments(_memory.committed_size()); _number_of_reserved_segments = size_to_segments(_memory.reserved_size()); assert(_number_of_reserved_segments >= _number_of_committed_segments, "just checking"); + const size_t reserved_segments_alignment = MAX2((size_t)os::vm_page_size(), granularity); + const size_t reserved_segments_size = align_size_up(_number_of_reserved_segments, reserved_segments_alignment); + const size_t committed_segments_size = align_to_page_size(_number_of_committed_segments); // reserve space for _segmap - if (!_segmap.initialize(align_to_page_size(_number_of_reserved_segments), align_to_page_size(_number_of_committed_segments))) { + if (!_segmap.initialize(reserved_segments_size, committed_segments_size)) { return false; } diff --git a/hotspot/src/share/vm/memory/metaspace.cpp b/hotspot/src/share/vm/memory/metaspace.cpp index f230dcf791d..e5871ae7a84 100644 --- a/hotspot/src/share/vm/memory/metaspace.cpp +++ b/hotspot/src/share/vm/memory/metaspace.cpp @@ -35,6 +35,7 @@ #include "memory/resourceArea.hpp" #include "memory/universe.hpp" #include "runtime/globals.hpp" +#include "runtime/java.hpp" #include "runtime/mutex.hpp" #include "runtime/orderAccess.hpp" #include "services/memTracker.hpp" @@ -54,6 +55,8 @@ size_t const allocation_from_dictionary_limit = 64 * K; MetaWord* last_allocated = 0; +size_t Metaspace::_class_metaspace_size; + // Used in declarations in SpaceManager and ChunkManager enum ChunkIndex { ZeroIndex = 0, @@ -261,10 +264,6 @@ class VirtualSpaceNode : public CHeapObj { // count of chunks contained in this VirtualSpace uintx _container_count; - // Convenience functions for logical bottom and end - MetaWord* bottom() const { return (MetaWord*) _virtual_space.low(); } - MetaWord* end() const { return (MetaWord*) _virtual_space.high(); } - // Convenience functions to access the _virtual_space char* low() const { return virtual_space()->low(); } char* high() const { return virtual_space()->high(); } @@ -284,6 +283,10 @@ class VirtualSpaceNode : public CHeapObj { VirtualSpaceNode(ReservedSpace rs) : _top(NULL), _next(NULL), _rs(rs), _container_count(0) {} ~VirtualSpaceNode(); + // Convenience functions for logical bottom and end + MetaWord* bottom() const { return (MetaWord*) _virtual_space.low(); } + MetaWord* end() const { return (MetaWord*) _virtual_space.high(); } + // address of next available space in _virtual_space; // Accessors VirtualSpaceNode* next() { return _next; } @@ -1313,7 +1316,8 @@ bool MetaspaceGC::should_expand(VirtualSpaceList* vsl, size_t word_size) { // Class virtual space should always be expanded. Call GC for the other // metadata virtual space. - if (vsl == Metaspace::class_space_list()) return true; + if (Metaspace::using_class_space() && + (vsl == Metaspace::class_space_list())) return true; // If this is part of an allocation after a GC, expand // unconditionally. @@ -2257,7 +2261,7 @@ void SpaceManager::deallocate(MetaWord* p, size_t word_size) { size_t raw_word_size = get_raw_word_size(word_size); size_t min_size = TreeChunk::min_size(); assert(raw_word_size >= min_size, - err_msg("Should not deallocate dark matter " SIZE_FORMAT, word_size)); + err_msg("Should not deallocate dark matter " SIZE_FORMAT "<" SIZE_FORMAT, word_size, min_size)); block_freelists()->return_block(p, raw_word_size); } @@ -2374,7 +2378,7 @@ MetaWord* SpaceManager::allocate_work(size_t word_size) { if (result == NULL) { result = grow_and_allocate(word_size); } - if (result > 0) { + if (result != 0) { inc_used_metrics(word_size); assert(result != (MetaWord*) chunks_in_use(MediumIndex), "Head of the list is being allocated"); @@ -2478,7 +2482,8 @@ size_t MetaspaceAux::_allocated_used_words[] = {0, 0}; size_t MetaspaceAux::free_bytes() { size_t result = 0; - if (Metaspace::class_space_list() != NULL) { + if (Metaspace::using_class_space() && + (Metaspace::class_space_list() != NULL)) { result = result + Metaspace::class_space_list()->free_bytes(); } if (Metaspace::space_list() != NULL) { @@ -2549,6 +2554,9 @@ size_t MetaspaceAux::free_in_bytes(Metaspace::MetadataType mdtype) { } size_t MetaspaceAux::capacity_bytes_slow(Metaspace::MetadataType mdtype) { + if ((mdtype == Metaspace::ClassType) && !Metaspace::using_class_space()) { + return 0; + } // Don't count the space in the freelists. That space will be // added to the capacity calculation as needed. size_t capacity = 0; @@ -2563,18 +2571,23 @@ size_t MetaspaceAux::capacity_bytes_slow(Metaspace::MetadataType mdtype) { } size_t MetaspaceAux::reserved_in_bytes(Metaspace::MetadataType mdtype) { - size_t reserved = (mdtype == Metaspace::ClassType) ? - Metaspace::class_space_list()->virtual_space_total() : - Metaspace::space_list()->virtual_space_total(); - return reserved * BytesPerWord; + if (mdtype == Metaspace::ClassType) { + return Metaspace::using_class_space() ? + Metaspace::class_space_list()->virtual_space_total() * BytesPerWord : 0; + } else { + return Metaspace::space_list()->virtual_space_total() * BytesPerWord; + } } size_t MetaspaceAux::min_chunk_size() { return Metaspace::first_chunk_word_size(); } size_t MetaspaceAux::free_chunks_total(Metaspace::MetadataType mdtype) { + if ((mdtype == Metaspace::ClassType) && !Metaspace::using_class_space()) { + return 0; + } ChunkManager* chunk = (mdtype == Metaspace::ClassType) ? - Metaspace::class_space_list()->chunk_manager() : - Metaspace::space_list()->chunk_manager(); + Metaspace::class_space_list()->chunk_manager() : + Metaspace::space_list()->chunk_manager(); chunk->slow_verify(); return chunk->free_chunks_total(); } @@ -2615,7 +2628,6 @@ void MetaspaceAux::print_metaspace_change(size_t prev_metadata_used) { // This is printed when PrintGCDetails void MetaspaceAux::print_on(outputStream* out) { - Metaspace::MetadataType ct = Metaspace::ClassType; Metaspace::MetadataType nct = Metaspace::NonClassType; out->print_cr(" Metaspace total " @@ -2629,12 +2641,15 @@ void MetaspaceAux::print_on(outputStream* out) { allocated_capacity_bytes(nct)/K, allocated_used_bytes(nct)/K, reserved_in_bytes(nct)/K); - out->print_cr(" class space " - SIZE_FORMAT "K, used " SIZE_FORMAT "K," - " reserved " SIZE_FORMAT "K", - allocated_capacity_bytes(ct)/K, - allocated_used_bytes(ct)/K, - reserved_in_bytes(ct)/K); + if (Metaspace::using_class_space()) { + Metaspace::MetadataType ct = Metaspace::ClassType; + out->print_cr(" class space " + SIZE_FORMAT "K, used " SIZE_FORMAT "K," + " reserved " SIZE_FORMAT "K", + allocated_capacity_bytes(ct)/K, + allocated_used_bytes(ct)/K, + reserved_in_bytes(ct)/K); + } } // Print information for class space and data space separately. @@ -2659,13 +2674,37 @@ void MetaspaceAux::print_on(outputStream* out, Metaspace::MetadataType mdtype) { assert(!SafepointSynchronize::is_at_safepoint() || used_and_free == capacity_bytes, "Accounting is wrong"); } -// Print total fragmentation for class and data metaspaces separately -void MetaspaceAux::print_waste(outputStream* out) { - - size_t specialized_waste = 0, small_waste = 0, medium_waste = 0; - size_t specialized_count = 0, small_count = 0, medium_count = 0, humongous_count = 0; +// Print total fragmentation for class metaspaces +void MetaspaceAux::print_class_waste(outputStream* out) { + assert(Metaspace::using_class_space(), "class metaspace not used"); size_t cls_specialized_waste = 0, cls_small_waste = 0, cls_medium_waste = 0; size_t cls_specialized_count = 0, cls_small_count = 0, cls_medium_count = 0, cls_humongous_count = 0; + ClassLoaderDataGraphMetaspaceIterator iter; + while (iter.repeat()) { + Metaspace* msp = iter.get_next(); + if (msp != NULL) { + cls_specialized_waste += msp->class_vsm()->sum_waste_in_chunks_in_use(SpecializedIndex); + cls_specialized_count += msp->class_vsm()->sum_count_in_chunks_in_use(SpecializedIndex); + cls_small_waste += msp->class_vsm()->sum_waste_in_chunks_in_use(SmallIndex); + cls_small_count += msp->class_vsm()->sum_count_in_chunks_in_use(SmallIndex); + cls_medium_waste += msp->class_vsm()->sum_waste_in_chunks_in_use(MediumIndex); + cls_medium_count += msp->class_vsm()->sum_count_in_chunks_in_use(MediumIndex); + cls_humongous_count += msp->class_vsm()->sum_count_in_chunks_in_use(HumongousIndex); + } + } + out->print_cr(" class: " SIZE_FORMAT " specialized(s) " SIZE_FORMAT ", " + SIZE_FORMAT " small(s) " SIZE_FORMAT ", " + SIZE_FORMAT " medium(s) " SIZE_FORMAT ", " + "large count " SIZE_FORMAT, + cls_specialized_count, cls_specialized_waste, + cls_small_count, cls_small_waste, + cls_medium_count, cls_medium_waste, cls_humongous_count); +} + +// Print total fragmentation for data and class metaspaces separately +void MetaspaceAux::print_waste(outputStream* out) { + size_t specialized_waste = 0, small_waste = 0, medium_waste = 0; + size_t specialized_count = 0, small_count = 0, medium_count = 0, humongous_count = 0; ClassLoaderDataGraphMetaspaceIterator iter; while (iter.repeat()) { @@ -2678,14 +2717,6 @@ void MetaspaceAux::print_waste(outputStream* out) { medium_waste += msp->vsm()->sum_waste_in_chunks_in_use(MediumIndex); medium_count += msp->vsm()->sum_count_in_chunks_in_use(MediumIndex); humongous_count += msp->vsm()->sum_count_in_chunks_in_use(HumongousIndex); - - cls_specialized_waste += msp->class_vsm()->sum_waste_in_chunks_in_use(SpecializedIndex); - cls_specialized_count += msp->class_vsm()->sum_count_in_chunks_in_use(SpecializedIndex); - cls_small_waste += msp->class_vsm()->sum_waste_in_chunks_in_use(SmallIndex); - cls_small_count += msp->class_vsm()->sum_count_in_chunks_in_use(SmallIndex); - cls_medium_waste += msp->class_vsm()->sum_waste_in_chunks_in_use(MediumIndex); - cls_medium_count += msp->class_vsm()->sum_count_in_chunks_in_use(MediumIndex); - cls_humongous_count += msp->class_vsm()->sum_count_in_chunks_in_use(HumongousIndex); } } out->print_cr("Total fragmentation waste (words) doesn't count free space"); @@ -2695,13 +2726,9 @@ void MetaspaceAux::print_waste(outputStream* out) { "large count " SIZE_FORMAT, specialized_count, specialized_waste, small_count, small_waste, medium_count, medium_waste, humongous_count); - out->print_cr(" class: " SIZE_FORMAT " specialized(s) " SIZE_FORMAT ", " - SIZE_FORMAT " small(s) " SIZE_FORMAT ", " - SIZE_FORMAT " medium(s) " SIZE_FORMAT ", " - "large count " SIZE_FORMAT, - cls_specialized_count, cls_specialized_waste, - cls_small_count, cls_small_waste, - cls_medium_count, cls_medium_waste, cls_humongous_count); + if (Metaspace::using_class_space()) { + print_class_waste(out); + } } // Dump global metaspace things from the end of ClassLoaderDataGraph @@ -2714,7 +2741,9 @@ void MetaspaceAux::dump(outputStream* out) { void MetaspaceAux::verify_free_chunks() { Metaspace::space_list()->chunk_manager()->verify(); - Metaspace::class_space_list()->chunk_manager()->verify(); + if (Metaspace::using_class_space()) { + Metaspace::class_space_list()->chunk_manager()->verify(); + } } void MetaspaceAux::verify_capacity() { @@ -2776,7 +2805,9 @@ Metaspace::Metaspace(Mutex* lock, MetaspaceType type) { Metaspace::~Metaspace() { delete _vsm; - delete _class_vsm; + if (using_class_space()) { + delete _class_vsm; + } } VirtualSpaceList* Metaspace::_space_list = NULL; @@ -2784,9 +2815,123 @@ VirtualSpaceList* Metaspace::_class_space_list = NULL; #define VIRTUALSPACEMULTIPLIER 2 +#ifdef _LP64 +void Metaspace::set_narrow_klass_base_and_shift(address metaspace_base, address cds_base) { + // Figure out the narrow_klass_base and the narrow_klass_shift. The + // narrow_klass_base is the lower of the metaspace base and the cds base + // (if cds is enabled). The narrow_klass_shift depends on the distance + // between the lower base and higher address. + address lower_base; + address higher_address; + if (UseSharedSpaces) { + higher_address = MAX2((address)(cds_base + FileMapInfo::shared_spaces_size()), + (address)(metaspace_base + class_metaspace_size())); + lower_base = MIN2(metaspace_base, cds_base); + } else { + higher_address = metaspace_base + class_metaspace_size(); + lower_base = metaspace_base; + } + Universe::set_narrow_klass_base(lower_base); + if ((uint64_t)(higher_address - lower_base) < (uint64_t)max_juint) { + Universe::set_narrow_klass_shift(0); + } else { + assert(!UseSharedSpaces, "Cannot shift with UseSharedSpaces"); + Universe::set_narrow_klass_shift(LogKlassAlignmentInBytes); + } +} + +// Return TRUE if the specified metaspace_base and cds_base are close enough +// to work with compressed klass pointers. +bool Metaspace::can_use_cds_with_metaspace_addr(char* metaspace_base, address cds_base) { + assert(cds_base != 0 && UseSharedSpaces, "Only use with CDS"); + assert(UseCompressedKlassPointers, "Only use with CompressedKlassPtrs"); + address lower_base = MIN2((address)metaspace_base, cds_base); + address higher_address = MAX2((address)(cds_base + FileMapInfo::shared_spaces_size()), + (address)(metaspace_base + class_metaspace_size())); + return ((uint64_t)(higher_address - lower_base) < (uint64_t)max_juint); +} + +// Try to allocate the metaspace at the requested addr. +void Metaspace::allocate_metaspace_compressed_klass_ptrs(char* requested_addr, address cds_base) { + assert(using_class_space(), "called improperly"); + assert(UseCompressedKlassPointers, "Only use with CompressedKlassPtrs"); + assert(class_metaspace_size() < KlassEncodingMetaspaceMax, + "Metaspace size is too big"); + + ReservedSpace metaspace_rs = ReservedSpace(class_metaspace_size(), + os::vm_allocation_granularity(), + false, requested_addr, 0); + if (!metaspace_rs.is_reserved()) { + if (UseSharedSpaces) { + // Keep trying to allocate the metaspace, increasing the requested_addr + // by 1GB each time, until we reach an address that will no longer allow + // use of CDS with compressed klass pointers. + char *addr = requested_addr; + while (!metaspace_rs.is_reserved() && (addr + 1*G > addr) && + can_use_cds_with_metaspace_addr(addr + 1*G, cds_base)) { + addr = addr + 1*G; + metaspace_rs = ReservedSpace(class_metaspace_size(), + os::vm_allocation_granularity(), false, addr, 0); + } + } + + // If no successful allocation then try to allocate the space anywhere. If + // that fails then OOM doom. At this point we cannot try allocating the + // metaspace as if UseCompressedKlassPointers is off because too much + // initialization has happened that depends on UseCompressedKlassPointers. + // So, UseCompressedKlassPointers cannot be turned off at this point. + if (!metaspace_rs.is_reserved()) { + metaspace_rs = ReservedSpace(class_metaspace_size(), + os::vm_allocation_granularity(), false); + if (!metaspace_rs.is_reserved()) { + vm_exit_during_initialization(err_msg("Could not allocate metaspace: %d bytes", + class_metaspace_size())); + } + } + } + + // If we got here then the metaspace got allocated. + MemTracker::record_virtual_memory_type((address)metaspace_rs.base(), mtClass); + + // Verify that we can use shared spaces. Otherwise, turn off CDS. + if (UseSharedSpaces && !can_use_cds_with_metaspace_addr(metaspace_rs.base(), cds_base)) { + FileMapInfo::stop_sharing_and_unmap( + "Could not allocate metaspace at a compatible address"); + } + + set_narrow_klass_base_and_shift((address)metaspace_rs.base(), + UseSharedSpaces ? (address)cds_base : 0); + + initialize_class_space(metaspace_rs); + + if (PrintCompressedOopsMode || (PrintMiscellaneous && Verbose)) { + gclog_or_tty->print_cr("Narrow klass base: " PTR_FORMAT ", Narrow klass shift: " SIZE_FORMAT, + Universe::narrow_klass_base(), Universe::narrow_klass_shift()); + gclog_or_tty->print_cr("Metaspace Size: " SIZE_FORMAT " Address: " PTR_FORMAT " Req Addr: " PTR_FORMAT, + class_metaspace_size(), metaspace_rs.base(), requested_addr); + } +} + +// For UseCompressedKlassPointers the class space is reserved above the top of +// the Java heap. The argument passed in is at the base of the compressed space. +void Metaspace::initialize_class_space(ReservedSpace rs) { + // The reserved space size may be bigger because of alignment, esp with UseLargePages + assert(rs.size() >= ClassMetaspaceSize, + err_msg(SIZE_FORMAT " != " UINTX_FORMAT, rs.size(), ClassMetaspaceSize)); + assert(using_class_space(), "Must be using class space"); + _class_space_list = new VirtualSpaceList(rs); +} + +#endif + void Metaspace::global_initialize() { // Initialize the alignment for shared spaces. int max_alignment = os::vm_page_size(); + size_t cds_total = 0; + + set_class_metaspace_size(align_size_up(ClassMetaspaceSize, + os::vm_allocation_granularity())); + MetaspaceShared::set_max_alignment(max_alignment); if (DumpSharedSpaces) { @@ -2798,15 +2943,31 @@ void Metaspace::global_initialize() { // Initialize with the sum of the shared space sizes. The read-only // and read write metaspace chunks will be allocated out of this and the // remainder is the misc code and data chunks. - size_t total = align_size_up(SharedReadOnlySize + SharedReadWriteSize + - SharedMiscDataSize + SharedMiscCodeSize, - os::vm_allocation_granularity()); - size_t word_size = total/wordSize; - _space_list = new VirtualSpaceList(word_size); + cds_total = FileMapInfo::shared_spaces_size(); + _space_list = new VirtualSpaceList(cds_total/wordSize); + +#ifdef _LP64 + // Set the compressed klass pointer base so that decoding of these pointers works + // properly when creating the shared archive. + assert(UseCompressedOops && UseCompressedKlassPointers, + "UseCompressedOops and UseCompressedKlassPointers must be set"); + Universe::set_narrow_klass_base((address)_space_list->current_virtual_space()->bottom()); + if (TraceMetavirtualspaceAllocation && Verbose) { + gclog_or_tty->print_cr("Setting_narrow_klass_base to Address: " PTR_FORMAT, + _space_list->current_virtual_space()->bottom()); + } + + // Set the shift to zero. + assert(class_metaspace_size() < (uint64_t)(max_juint) - cds_total, + "CDS region is too large"); + Universe::set_narrow_klass_shift(0); +#endif + } else { // If using shared space, open the file that contains the shared space // and map in the memory before initializing the rest of metaspace (so // the addresses don't conflict) + address cds_address = NULL; if (UseSharedSpaces) { FileMapInfo* mapinfo = new FileMapInfo(); memset(mapinfo, 0, sizeof(FileMapInfo)); @@ -2821,8 +2982,22 @@ void Metaspace::global_initialize() { assert(!mapinfo->is_open() && !UseSharedSpaces, "archive file not closed or shared spaces not disabled."); } + cds_total = FileMapInfo::shared_spaces_size(); + cds_address = (address)mapinfo->region_base(0); } +#ifdef _LP64 + // If UseCompressedKlassPointers is set then allocate the metaspace area + // above the heap and above the CDS area (if it exists). + if (using_class_space()) { + if (UseSharedSpaces) { + allocate_metaspace_compressed_klass_ptrs((char *)(cds_address + cds_total), cds_address); + } else { + allocate_metaspace_compressed_klass_ptrs((char *)CompressedKlassPointersBase, 0); + } + } +#endif + // Initialize these before initializing the VirtualSpaceList _first_chunk_word_size = InitialBootClassLoaderMetaspaceSize / BytesPerWord; _first_chunk_word_size = align_word_size_up(_first_chunk_word_size); @@ -2840,39 +3015,28 @@ void Metaspace::global_initialize() { } } -// For UseCompressedKlassPointers the class space is reserved as a piece of the -// Java heap because the compression algorithm is the same for each. The -// argument passed in is at the top of the compressed space -void Metaspace::initialize_class_space(ReservedSpace rs) { - // The reserved space size may be bigger because of alignment, esp with UseLargePages - assert(rs.size() >= ClassMetaspaceSize, - err_msg(SIZE_FORMAT " != " UINTX_FORMAT, rs.size(), ClassMetaspaceSize)); - _class_space_list = new VirtualSpaceList(rs); -} - -void Metaspace::initialize(Mutex* lock, - MetaspaceType type) { +void Metaspace::initialize(Mutex* lock, MetaspaceType type) { assert(space_list() != NULL, "Metadata VirtualSpaceList has not been initialized"); - _vsm = new SpaceManager(Metaspace::NonClassType, lock, space_list()); + _vsm = new SpaceManager(NonClassType, lock, space_list()); if (_vsm == NULL) { return; } size_t word_size; size_t class_word_size; - vsm()->get_initial_chunk_sizes(type, - &word_size, - &class_word_size); + vsm()->get_initial_chunk_sizes(type, &word_size, &class_word_size); - assert(class_space_list() != NULL, - "Class VirtualSpaceList has not been initialized"); + if (using_class_space()) { + assert(class_space_list() != NULL, + "Class VirtualSpaceList has not been initialized"); - // Allocate SpaceManager for classes. - _class_vsm = new SpaceManager(Metaspace::ClassType, lock, class_space_list()); - if (_class_vsm == NULL) { - return; + // Allocate SpaceManager for classes. + _class_vsm = new SpaceManager(ClassType, lock, class_space_list()); + if (_class_vsm == NULL) { + return; + } } MutexLockerEx cl(SpaceManager::expand_lock(), Mutex::_no_safepoint_check_flag); @@ -2888,11 +3052,13 @@ void Metaspace::initialize(Mutex* lock, } // Allocate chunk for class metadata objects - Metachunk* class_chunk = - class_space_list()->get_initialization_chunk(class_word_size, - class_vsm()->medium_chunk_bunch()); - if (class_chunk != NULL) { - class_vsm()->add_chunk(class_chunk, true); + if (using_class_space()) { + Metachunk* class_chunk = + class_space_list()->get_initialization_chunk(class_word_size, + class_vsm()->medium_chunk_bunch()); + if (class_chunk != NULL) { + class_vsm()->add_chunk(class_chunk, true); + } } _alloc_record_head = NULL; @@ -2906,7 +3072,8 @@ size_t Metaspace::align_word_size_up(size_t word_size) { MetaWord* Metaspace::allocate(size_t word_size, MetadataType mdtype) { // DumpSharedSpaces doesn't use class metadata area (yet) - if (mdtype == ClassType && !DumpSharedSpaces) { + // Also, don't use class_vsm() unless UseCompressedKlassPointers is true. + if (mdtype == ClassType && using_class_space()) { return class_vsm()->allocate(word_size); } else { return vsm()->allocate(word_size); @@ -2937,14 +3104,19 @@ char* Metaspace::bottom() const { } size_t Metaspace::used_words_slow(MetadataType mdtype) const { - // return vsm()->allocated_used_words(); - return mdtype == ClassType ? class_vsm()->sum_used_in_chunks_in_use() : - vsm()->sum_used_in_chunks_in_use(); // includes overhead! + if (mdtype == ClassType) { + return using_class_space() ? class_vsm()->sum_used_in_chunks_in_use() : 0; + } else { + return vsm()->sum_used_in_chunks_in_use(); // includes overhead! + } } size_t Metaspace::free_words(MetadataType mdtype) const { - return mdtype == ClassType ? class_vsm()->sum_free_in_chunks_in_use() : - vsm()->sum_free_in_chunks_in_use(); + if (mdtype == ClassType) { + return using_class_space() ? class_vsm()->sum_free_in_chunks_in_use() : 0; + } else { + return vsm()->sum_free_in_chunks_in_use(); + } } // Space capacity in the Metaspace. It includes @@ -2953,8 +3125,11 @@ size_t Metaspace::free_words(MetadataType mdtype) const { // in the space available in the dictionary which // is already counted in some chunk. size_t Metaspace::capacity_words_slow(MetadataType mdtype) const { - return mdtype == ClassType ? class_vsm()->sum_capacity_in_chunks_in_use() : - vsm()->sum_capacity_in_chunks_in_use(); + if (mdtype == ClassType) { + return using_class_space() ? class_vsm()->sum_capacity_in_chunks_in_use() : 0; + } else { + return vsm()->sum_capacity_in_chunks_in_use(); + } } size_t Metaspace::used_bytes_slow(MetadataType mdtype) const { @@ -2977,8 +3152,8 @@ void Metaspace::deallocate(MetaWord* ptr, size_t word_size, bool is_class) { #endif return; } - if (is_class) { - class_vsm()->deallocate(ptr, word_size); + if (is_class && using_class_space()) { + class_vsm()->deallocate(ptr, word_size); } else { vsm()->deallocate(ptr, word_size); } @@ -2992,7 +3167,7 @@ void Metaspace::deallocate(MetaWord* ptr, size_t word_size, bool is_class) { #endif return; } - if (is_class) { + if (is_class && using_class_space()) { class_vsm()->deallocate(ptr, word_size); } else { vsm()->deallocate(ptr, word_size); @@ -3101,14 +3276,18 @@ void Metaspace::purge() { MutexLockerEx cl(SpaceManager::expand_lock(), Mutex::_no_safepoint_check_flag); space_list()->purge(); - class_space_list()->purge(); + if (using_class_space()) { + class_space_list()->purge(); + } } void Metaspace::print_on(outputStream* out) const { // Print both class virtual space counts and metaspace. if (Verbose) { - vsm()->print_on(out); + vsm()->print_on(out); + if (using_class_space()) { class_vsm()->print_on(out); + } } } @@ -3122,17 +3301,21 @@ bool Metaspace::contains(const void * ptr) { // be needed. Note, locking this can cause inversion problems with the // caller in MetaspaceObj::is_metadata() function. return space_list()->contains(ptr) || - class_space_list()->contains(ptr); + (using_class_space() && class_space_list()->contains(ptr)); } void Metaspace::verify() { vsm()->verify(); - class_vsm()->verify(); + if (using_class_space()) { + class_vsm()->verify(); + } } void Metaspace::dump(outputStream* const out) const { out->print_cr("\nVirtual space manager: " INTPTR_FORMAT, vsm()); vsm()->dump(out); - out->print_cr("\nClass space manager: " INTPTR_FORMAT, class_vsm()); - class_vsm()->dump(out); + if (using_class_space()) { + out->print_cr("\nClass space manager: " INTPTR_FORMAT, class_vsm()); + class_vsm()->dump(out); + } } diff --git a/hotspot/src/share/vm/memory/metaspace.hpp b/hotspot/src/share/vm/memory/metaspace.hpp index cd499341c1d..3d620357bee 100644 --- a/hotspot/src/share/vm/memory/metaspace.hpp +++ b/hotspot/src/share/vm/memory/metaspace.hpp @@ -105,6 +105,16 @@ class Metaspace : public CHeapObj { // Align up the word size to the allocation word size static size_t align_word_size_up(size_t); + // Aligned size of the metaspace. + static size_t _class_metaspace_size; + + static size_t class_metaspace_size() { + return _class_metaspace_size; + } + static void set_class_metaspace_size(size_t metaspace_size) { + _class_metaspace_size = metaspace_size; + } + static size_t _first_chunk_word_size; static size_t _first_class_chunk_word_size; @@ -131,6 +141,17 @@ class Metaspace : public CHeapObj { // maintain a single list for now. void record_allocation(void* ptr, MetaspaceObj::Type type, size_t word_size); +#ifdef _LP64 + static void set_narrow_klass_base_and_shift(address metaspace_base, address cds_base); + + // Returns true if can use CDS with metaspace allocated as specified address. + static bool can_use_cds_with_metaspace_addr(char* metaspace_base, address cds_base); + + static void allocate_metaspace_compressed_klass_ptrs(char* requested_addr, address cds_base); + + static void initialize_class_space(ReservedSpace rs); +#endif + class AllocRecord : public CHeapObj { public: AllocRecord(address ptr, MetaspaceObj::Type type, int byte_size) @@ -151,7 +172,6 @@ class Metaspace : public CHeapObj { // Initialize globals for Metaspace static void global_initialize(); - static void initialize_class_space(ReservedSpace rs); static size_t first_chunk_word_size() { return _first_chunk_word_size; } static size_t first_class_chunk_word_size() { return _first_class_chunk_word_size; } @@ -172,8 +192,6 @@ class Metaspace : public CHeapObj { MetaWord* expand_and_allocate(size_t size, MetadataType mdtype); - static bool is_initialized() { return _class_space_list != NULL; } - static bool contains(const void *ptr); void dump(outputStream* const out) const; @@ -190,6 +208,12 @@ class Metaspace : public CHeapObj { }; void iterate(AllocRecordClosure *closure); + + // Return TRUE only if UseCompressedKlassPointers is True and DumpSharedSpaces is False. + static bool using_class_space() { + return NOT_LP64(false) LP64_ONLY(UseCompressedKlassPointers && !DumpSharedSpaces); + } + }; class MetaspaceAux : AllStatic { @@ -243,8 +267,9 @@ class MetaspaceAux : AllStatic { return _allocated_capacity_words[mdtype]; } static size_t allocated_capacity_words() { - return _allocated_capacity_words[Metaspace::ClassType] + - _allocated_capacity_words[Metaspace::NonClassType]; + return _allocated_capacity_words[Metaspace::NonClassType] + + (Metaspace::using_class_space() ? + _allocated_capacity_words[Metaspace::ClassType] : 0); } static size_t allocated_capacity_bytes(Metaspace::MetadataType mdtype) { return allocated_capacity_words(mdtype) * BytesPerWord; @@ -257,8 +282,9 @@ class MetaspaceAux : AllStatic { return _allocated_used_words[mdtype]; } static size_t allocated_used_words() { - return _allocated_used_words[Metaspace::ClassType] + - _allocated_used_words[Metaspace::NonClassType]; + return _allocated_used_words[Metaspace::NonClassType] + + (Metaspace::using_class_space() ? + _allocated_used_words[Metaspace::ClassType] : 0); } static size_t allocated_used_bytes(Metaspace::MetadataType mdtype) { return allocated_used_words(mdtype) * BytesPerWord; @@ -300,6 +326,7 @@ class MetaspaceAux : AllStatic { static void print_on(outputStream * out); static void print_on(outputStream * out, Metaspace::MetadataType mdtype); + static void print_class_waste(outputStream* out); static void print_waste(outputStream* out); static void dump(outputStream* out); static void verify_free_chunks(); diff --git a/hotspot/src/share/vm/memory/metaspaceShared.cpp b/hotspot/src/share/vm/memory/metaspaceShared.cpp index c7d61f7b732..2a9873957a8 100644 --- a/hotspot/src/share/vm/memory/metaspaceShared.cpp +++ b/hotspot/src/share/vm/memory/metaspaceShared.cpp @@ -52,7 +52,6 @@ void MetaspaceShared::serialize(SerializeClosure* soc) { int tag = 0; soc->do_tag(--tag); - assert(!UseCompressedOops, "UseCompressedOops doesn't work with shared archive"); // Verify the sizes of various metadata in the system. soc->do_tag(sizeof(Method)); soc->do_tag(sizeof(ConstMethod)); diff --git a/hotspot/src/share/vm/memory/universe.cpp b/hotspot/src/share/vm/memory/universe.cpp index 33a857f2a7e..1e380ed39f8 100644 --- a/hotspot/src/share/vm/memory/universe.cpp +++ b/hotspot/src/share/vm/memory/universe.cpp @@ -145,8 +145,6 @@ NarrowPtrStruct Universe::_narrow_oop = { NULL, 0, true }; NarrowPtrStruct Universe::_narrow_klass = { NULL, 0, true }; address Universe::_narrow_ptrs_base; -size_t Universe::_class_metaspace_size; - void Universe::basic_type_classes_do(void f(Klass*)) { f(boolArrayKlassObj()); f(byteArrayKlassObj()); @@ -641,6 +639,8 @@ jint universe_init() { return status; } + Metaspace::global_initialize(); + // Create memory for metadata. Must be after initializing heap for // DumpSharedSpaces. ClassLoaderData::init_null_class_loader_data(); @@ -693,13 +693,9 @@ char* Universe::preferred_heap_base(size_t heap_size, NARROW_OOP_MODE mode) { if (!FLAG_IS_DEFAULT(HeapBaseMinAddress) && (mode == UnscaledNarrowOop)) { base = HeapBaseMinAddress; - // If the total size and the metaspace size are small enough to allow - // UnscaledNarrowOop then just use UnscaledNarrowOop. - } else if ((total_size <= OopEncodingHeapMax) && (mode != HeapBasedNarrowOop) && - (!UseCompressedKlassPointers || - (((OopEncodingHeapMax - heap_size) + Universe::class_metaspace_size()) <= KlassEncodingMetaspaceMax))) { - // We don't need to check the metaspace size here because it is always smaller - // than total_size. + // If the total size is small enough to allow UnscaledNarrowOop then + // just use UnscaledNarrowOop. + } else if ((total_size <= OopEncodingHeapMax) && (mode != HeapBasedNarrowOop)) { if ((total_size <= NarrowOopHeapMax) && (mode == UnscaledNarrowOop) && (Universe::narrow_oop_shift() == 0)) { // Use 32-bits oops without encoding and @@ -716,13 +712,6 @@ char* Universe::preferred_heap_base(size_t heap_size, NARROW_OOP_MODE mode) { base = (OopEncodingHeapMax - heap_size); } } - - // See if ZeroBaseNarrowOop encoding will work for a heap based at - // (KlassEncodingMetaspaceMax - class_metaspace_size()). - } else if (UseCompressedKlassPointers && (mode != HeapBasedNarrowOop) && - (Universe::class_metaspace_size() + HeapBaseMinAddress <= KlassEncodingMetaspaceMax) && - (KlassEncodingMetaspaceMax + heap_size - Universe::class_metaspace_size() <= OopEncodingHeapMax)) { - base = (KlassEncodingMetaspaceMax - Universe::class_metaspace_size()); } else { // UnscaledNarrowOop encoding didn't work, and no base was found for ZeroBasedOops or // HeapBasedNarrowOop encoding was requested. So, can't reserve below 32Gb. @@ -732,8 +721,7 @@ char* Universe::preferred_heap_base(size_t heap_size, NARROW_OOP_MODE mode) { // Set narrow_oop_base and narrow_oop_use_implicit_null_checks // used in ReservedHeapSpace() constructors. // The final values will be set in initialize_heap() below. - if ((base != 0) && ((base + heap_size) <= OopEncodingHeapMax) && - (!UseCompressedKlassPointers || (base + Universe::class_metaspace_size()) <= KlassEncodingMetaspaceMax)) { + if ((base != 0) && ((base + heap_size) <= OopEncodingHeapMax)) { // Use zero based compressed oops Universe::set_narrow_oop_base(NULL); // Don't need guard page for implicit checks in indexed @@ -816,9 +804,7 @@ jint Universe::initialize_heap() { tty->print("heap address: " PTR_FORMAT ", size: " SIZE_FORMAT " MB", Universe::heap()->base(), Universe::heap()->reserved_region().byte_size()/M); } - if (((uint64_t)Universe::heap()->reserved_region().end() > OopEncodingHeapMax) || - (UseCompressedKlassPointers && - ((uint64_t)Universe::heap()->base() + Universe::class_metaspace_size() > KlassEncodingMetaspaceMax))) { + if (((uint64_t)Universe::heap()->reserved_region().end() > OopEncodingHeapMax)) { // Can't reserve heap below 32Gb. // keep the Universe::narrow_oop_base() set in Universe::reserve_heap() Universe::set_narrow_oop_shift(LogMinObjAlignmentInBytes); @@ -849,20 +835,16 @@ jint Universe::initialize_heap() { } } } + if (verbose) { tty->cr(); tty->cr(); } - if (UseCompressedKlassPointers) { - Universe::set_narrow_klass_base(Universe::narrow_oop_base()); - Universe::set_narrow_klass_shift(MIN2(Universe::narrow_oop_shift(), LogKlassAlignmentInBytes)); - } Universe::set_narrow_ptrs_base(Universe::narrow_oop_base()); } - // Universe::narrow_oop_base() is one page below the metaspace - // base. The actual metaspace base depends on alignment constraints - // so we don't know its exact location here. - assert((intptr_t)Universe::narrow_oop_base() <= (intptr_t)(Universe::heap()->base() - os::vm_page_size() - ClassMetaspaceSize) || + // Universe::narrow_oop_base() is one page below the heap. + assert((intptr_t)Universe::narrow_oop_base() <= (intptr_t)(Universe::heap()->base() - + os::vm_page_size()) || Universe::narrow_oop_base() == NULL, "invalid value"); assert(Universe::narrow_oop_shift() == LogMinObjAlignmentInBytes || Universe::narrow_oop_shift() == 0, "invalid value"); @@ -882,12 +864,7 @@ jint Universe::initialize_heap() { // Reserve the Java heap, which is now the same for all GCs. ReservedSpace Universe::reserve_heap(size_t heap_size, size_t alignment) { - // Add in the class metaspace area so the classes in the headers can - // be compressed the same as instances. - // Need to round class space size up because it's below the heap and - // the actual alignment depends on its size. - Universe::set_class_metaspace_size(align_size_up(ClassMetaspaceSize, alignment)); - size_t total_reserved = align_size_up(heap_size + Universe::class_metaspace_size(), alignment); + size_t total_reserved = align_size_up(heap_size, alignment); assert(!UseCompressedOops || (total_reserved <= (OopEncodingHeapMax - os::vm_page_size())), "heap size is too big for compressed oops"); char* addr = Universe::preferred_heap_base(total_reserved, Universe::UnscaledNarrowOop); @@ -923,28 +900,17 @@ ReservedSpace Universe::reserve_heap(size_t heap_size, size_t alignment) { return total_rs; } - // Split the reserved space into main Java heap and a space for - // classes so that they can be compressed using the same algorithm - // as compressed oops. If compress oops and compress klass ptrs are - // used we need the meta space first: if the alignment used for - // compressed oops is greater than the one used for compressed klass - // ptrs, a metadata space on top of the heap could become - // unreachable. - ReservedSpace class_rs = total_rs.first_part(Universe::class_metaspace_size()); - ReservedSpace heap_rs = total_rs.last_part(Universe::class_metaspace_size(), alignment); - Metaspace::initialize_class_space(class_rs); - if (UseCompressedOops) { // Universe::initialize_heap() will reset this to NULL if unscaled // or zero-based narrow oops are actually used. address base = (address)(total_rs.base() - os::vm_page_size()); Universe::set_narrow_oop_base(base); } - return heap_rs; + return total_rs; } -// It's the caller's repsonsibility to ensure glitch-freedom +// It's the caller's responsibility to ensure glitch-freedom // (if required). void Universe::update_heap_info_at_gc() { _heap_capacity_at_last_gc = heap()->capacity(); diff --git a/hotspot/src/share/vm/memory/universe.hpp b/hotspot/src/share/vm/memory/universe.hpp index 69998434380..1ebe5f2b57e 100644 --- a/hotspot/src/share/vm/memory/universe.hpp +++ b/hotspot/src/share/vm/memory/universe.hpp @@ -75,10 +75,10 @@ class LatestMethodCache : public CHeapObj { }; -// For UseCompressedOops and UseCompressedKlassPointers. +// For UseCompressedOops. struct NarrowPtrStruct { - // Base address for oop/klass-within-java-object materialization. - // NULL if using wide oops/klasses or zero based narrow oops/klasses. + // Base address for oop-within-java-object materialization. + // NULL if using wide oops or zero based narrow oops. address _base; // Number of shift bits for encoding/decoding narrow ptrs. // 0 if using wide ptrs or zero based unscaled narrow ptrs, @@ -106,6 +106,7 @@ class Universe: AllStatic { friend class SystemDictionary; friend class VMStructs; friend class VM_PopulateDumpSharedSpace; + friend class Metaspace; friend jint universe_init(); friend void universe2_init(); @@ -184,9 +185,6 @@ class Universe: AllStatic { static struct NarrowPtrStruct _narrow_klass; static address _narrow_ptrs_base; - // Aligned size of the metaspace. - static size_t _class_metaspace_size; - // array of dummy objects used with +FullGCAlot debug_only(static objArrayOop _fullgc_alot_dummy_array;) // index of next entry to clear @@ -238,15 +236,6 @@ class Universe: AllStatic { assert(UseCompressedOops, "no compressed ptrs?"); _narrow_oop._use_implicit_null_checks = use; } - static bool reserve_metaspace_helper(bool with_base = false); - static ReservedHeapSpace reserve_heap_metaspace(size_t heap_size, size_t alignment, bool& contiguous); - - static size_t class_metaspace_size() { - return _class_metaspace_size; - } - static void set_class_metaspace_size(size_t metaspace_size) { - _class_metaspace_size = metaspace_size; - } // Debugging static int _verify_count; // number of verifies done diff --git a/hotspot/src/share/vm/oops/klass.hpp b/hotspot/src/share/vm/oops/klass.hpp index 1ca027a3762..deb2e4fc48b 100644 --- a/hotspot/src/share/vm/oops/klass.hpp +++ b/hotspot/src/share/vm/oops/klass.hpp @@ -703,6 +703,16 @@ class Klass : public Metadata { virtual void oop_verify_on(oop obj, outputStream* st); + static bool is_null(narrowKlass obj); + static bool is_null(Klass* obj); + + // klass encoding for klass pointer in objects. + static narrowKlass encode_klass_not_null(Klass* v); + static narrowKlass encode_klass(Klass* v); + + static Klass* decode_klass_not_null(narrowKlass v); + static Klass* decode_klass(narrowKlass v); + private: // barriers used by klass_oop_store void klass_update_barrier_set(oop v); diff --git a/hotspot/src/share/vm/oops/klass.inline.hpp b/hotspot/src/share/vm/oops/klass.inline.hpp index 3eb62afe827..841a4873a32 100644 --- a/hotspot/src/share/vm/oops/klass.inline.hpp +++ b/hotspot/src/share/vm/oops/klass.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ #ifndef SHARE_VM_OOPS_KLASS_INLINE_HPP #define SHARE_VM_OOPS_KLASS_INLINE_HPP +#include "memory/universe.hpp" #include "oops/klass.hpp" #include "oops/markOop.hpp" @@ -33,4 +34,41 @@ inline void Klass::set_prototype_header(markOop header) { _prototype_header = header; } +inline bool Klass::is_null(Klass* obj) { return obj == NULL; } +inline bool Klass::is_null(narrowKlass obj) { return obj == 0; } + +// Encoding and decoding for klass field. + +inline bool check_klass_alignment(Klass* obj) { + return (intptr_t)obj % KlassAlignmentInBytes == 0; +} + +inline narrowKlass Klass::encode_klass_not_null(Klass* v) { + assert(!is_null(v), "klass value can never be zero"); + assert(check_klass_alignment(v), "Address not aligned"); + int shift = Universe::narrow_klass_shift(); + uint64_t pd = (uint64_t)(pointer_delta((void*)v, Universe::narrow_klass_base(), 1)); + assert(KlassEncodingMetaspaceMax > pd, "change encoding max if new encoding"); + uint64_t result = pd >> shift; + assert((result & CONST64(0xffffffff00000000)) == 0, "narrow klass pointer overflow"); + assert(decode_klass(result) == v, "reversibility"); + return (narrowKlass)result; +} + +inline narrowKlass Klass::encode_klass(Klass* v) { + return is_null(v) ? (narrowKlass)0 : encode_klass_not_null(v); +} + +inline Klass* Klass::decode_klass_not_null(narrowKlass v) { + assert(!is_null(v), "narrow klass value can never be zero"); + int shift = Universe::narrow_klass_shift(); + Klass* result = (Klass*)(void*)((uintptr_t)Universe::narrow_klass_base() + ((uintptr_t)v << shift)); + assert(check_klass_alignment(result), err_msg("address not aligned: " PTR_FORMAT, (void*) result)); + return result; +} + +inline Klass* Klass::decode_klass(narrowKlass v) { + return is_null(v) ? (Klass*)NULL : decode_klass_not_null(v); +} + #endif // SHARE_VM_OOPS_KLASS_INLINE_HPP diff --git a/hotspot/src/share/vm/oops/oop.hpp b/hotspot/src/share/vm/oops/oop.hpp index 94e68ed3263..66a62eaab23 100644 --- a/hotspot/src/share/vm/oops/oop.hpp +++ b/hotspot/src/share/vm/oops/oop.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -62,7 +62,7 @@ class oopDesc { volatile markOop _mark; union _metadata { Klass* _klass; - narrowOop _compressed_klass; + narrowKlass _compressed_klass; } _metadata; // Fast access to barrier set. Must be initialized. @@ -84,7 +84,7 @@ class oopDesc { Klass* klass() const; Klass* klass_or_null() const volatile; Klass** klass_addr(); - narrowOop* compressed_klass_addr(); + narrowKlass* compressed_klass_addr(); void set_klass(Klass* k); @@ -189,13 +189,6 @@ class oopDesc { oop compare_value, bool prebarrier = false); - // klass encoding for klass pointer in objects. - static narrowOop encode_klass_not_null(Klass* v); - static narrowOop encode_klass(Klass* v); - - static Klass* decode_klass_not_null(narrowOop v); - static Klass* decode_klass(narrowOop v); - // Access to fields in a instanceOop through these methods. oop obj_field(int offset) const; volatile oop obj_field_volatile(int offset) const; diff --git a/hotspot/src/share/vm/oops/oop.inline.hpp b/hotspot/src/share/vm/oops/oop.inline.hpp index 3c71e15f87c..9a6c1e1787b 100644 --- a/hotspot/src/share/vm/oops/oop.inline.hpp +++ b/hotspot/src/share/vm/oops/oop.inline.hpp @@ -35,7 +35,7 @@ #include "memory/specialized_oop_closures.hpp" #include "oops/arrayKlass.hpp" #include "oops/arrayOop.hpp" -#include "oops/klass.hpp" +#include "oops/klass.inline.hpp" #include "oops/markOop.inline.hpp" #include "oops/oop.hpp" #include "runtime/atomic.hpp" @@ -70,7 +70,7 @@ inline markOop oopDesc::cas_set_mark(markOop new_mark, markOop old_mark) { inline Klass* oopDesc::klass() const { if (UseCompressedKlassPointers) { - return decode_klass_not_null(_metadata._compressed_klass); + return Klass::decode_klass_not_null(_metadata._compressed_klass); } else { return _metadata._klass; } @@ -79,7 +79,7 @@ inline Klass* oopDesc::klass() const { inline Klass* oopDesc::klass_or_null() const volatile { // can be NULL in CMS if (UseCompressedKlassPointers) { - return decode_klass(_metadata._compressed_klass); + return Klass::decode_klass(_metadata._compressed_klass); } else { return _metadata._klass; } @@ -87,7 +87,7 @@ inline Klass* oopDesc::klass_or_null() const volatile { inline int oopDesc::klass_gap_offset_in_bytes() { assert(UseCompressedKlassPointers, "only applicable to compressed klass pointers"); - return oopDesc::klass_offset_in_bytes() + sizeof(narrowOop); + return oopDesc::klass_offset_in_bytes() + sizeof(narrowKlass); } inline Klass** oopDesc::klass_addr() { @@ -97,9 +97,9 @@ inline Klass** oopDesc::klass_addr() { return (Klass**) &_metadata._klass; } -inline narrowOop* oopDesc::compressed_klass_addr() { +inline narrowKlass* oopDesc::compressed_klass_addr() { assert(UseCompressedKlassPointers, "only called by compressed klass pointers"); - return (narrowOop*) &_metadata._compressed_klass; + return &_metadata._compressed_klass; } inline void oopDesc::set_klass(Klass* k) { @@ -107,7 +107,7 @@ inline void oopDesc::set_klass(Klass* k) { assert(Universe::is_bootstrapping() || k != NULL, "must be a real Klass*"); assert(Universe::is_bootstrapping() || k->is_klass(), "not a Klass*"); if (UseCompressedKlassPointers) { - *compressed_klass_addr() = encode_klass_not_null(k); + *compressed_klass_addr() = Klass::encode_klass_not_null(k); } else { *klass_addr() = k; } @@ -127,7 +127,7 @@ inline void oopDesc::set_klass_to_list_ptr(oop k) { // This is only to be used during GC, for from-space objects, so no // barrier is needed. if (UseCompressedKlassPointers) { - _metadata._compressed_klass = encode_heap_oop(k); // may be null (parnew overflow handling) + _metadata._compressed_klass = (narrowKlass)encode_heap_oop(k); // may be null (parnew overflow handling) } else { _metadata._klass = (Klass*)(address)k; } @@ -136,7 +136,7 @@ inline void oopDesc::set_klass_to_list_ptr(oop k) { inline oop oopDesc::list_ptr_from_klass() { // This is only to be used during GC, for from-space objects. if (UseCompressedKlassPointers) { - return decode_heap_oop(_metadata._compressed_klass); + return decode_heap_oop((narrowOop)_metadata._compressed_klass); } else { // Special case for GC return (oop)(address)_metadata._klass; @@ -176,7 +176,6 @@ inline address* oopDesc::address_field_addr(int offset) const { return (address // the right type and inlines the appopriate code). inline bool oopDesc::is_null(oop obj) { return obj == NULL; } -inline bool oopDesc::is_null(Klass* obj) { return obj == NULL; } inline bool oopDesc::is_null(narrowOop obj) { return obj == 0; } // Algorithm for encoding and decoding oops from 64 bit pointers to 32 bit @@ -186,9 +185,6 @@ inline bool oopDesc::is_null(narrowOop obj) { return obj == 0; } inline bool check_obj_alignment(oop obj) { return (intptr_t)obj % MinObjAlignmentInBytes == 0; } -inline bool check_klass_alignment(Klass* obj) { - return (intptr_t)obj % KlassAlignmentInBytes == 0; -} inline narrowOop oopDesc::encode_heap_oop_not_null(oop v) { assert(!is_null(v), "oop value can never be zero"); @@ -224,39 +220,6 @@ inline oop oopDesc::decode_heap_oop(narrowOop v) { inline oop oopDesc::decode_heap_oop_not_null(oop v) { return v; } inline oop oopDesc::decode_heap_oop(oop v) { return v; } -// Encoding and decoding for klass field. It is copied code, but someday -// might not be the same as oop. - -inline narrowOop oopDesc::encode_klass_not_null(Klass* v) { - assert(!is_null(v), "klass value can never be zero"); - assert(check_klass_alignment(v), "Address not aligned"); - address base = Universe::narrow_klass_base(); - int shift = Universe::narrow_klass_shift(); - uint64_t pd = (uint64_t)(pointer_delta((void*)v, (void*)base, 1)); - assert(KlassEncodingMetaspaceMax > pd, "change encoding max if new encoding"); - uint64_t result = pd >> shift; - assert((result & CONST64(0xffffffff00000000)) == 0, "narrow klass pointer overflow"); - assert(decode_klass(result) == v, "reversibility"); - return (narrowOop)result; -} - -inline narrowOop oopDesc::encode_klass(Klass* v) { - return (is_null(v)) ? (narrowOop)0 : encode_klass_not_null(v); -} - -inline Klass* oopDesc::decode_klass_not_null(narrowOop v) { - assert(!is_null(v), "narrow oop value can never be zero"); - address base = Universe::narrow_klass_base(); - int shift = Universe::narrow_klass_shift(); - Klass* result = (Klass*)(void*)((uintptr_t)base + ((uintptr_t)v << shift)); - assert(check_klass_alignment(result), err_msg("address not aligned: " PTR_FORMAT, (void*) result)); - return result; -} - -inline Klass* oopDesc::decode_klass(narrowOop v) { - return is_null(v) ? (Klass*)NULL : decode_klass_not_null(v); -} - // Load an oop out of the Java heap as is without decoding. // Called by GC to check for null before decoding. inline oop oopDesc::load_heap_oop(oop* p) { return *p; } diff --git a/hotspot/src/share/vm/oops/oopsHierarchy.hpp b/hotspot/src/share/vm/oops/oopsHierarchy.hpp index d599b1bae64..ccf7a5f99e2 100644 --- a/hotspot/src/share/vm/oops/oopsHierarchy.hpp +++ b/hotspot/src/share/vm/oops/oopsHierarchy.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,6 +33,10 @@ // of B, A's representation is a prefix of B's representation. typedef juint narrowOop; // Offset instead of address for an oop within a java object + +// If compressed klass pointers then use narrowKlass. +typedef juint narrowKlass; + typedef void* OopOrNarrowOopStar; typedef class markOopDesc* markOop; diff --git a/hotspot/src/share/vm/runtime/arguments.cpp b/hotspot/src/share/vm/runtime/arguments.cpp index 0662b6912b9..38f38f1c856 100644 --- a/hotspot/src/share/vm/runtime/arguments.cpp +++ b/hotspot/src/share/vm/runtime/arguments.cpp @@ -1393,10 +1393,8 @@ bool verify_object_alignment() { inline uintx max_heap_for_compressed_oops() { // Avoid sign flip. - if (OopEncodingHeapMax < ClassMetaspaceSize + os::vm_page_size()) { - return 0; - } - LP64_ONLY(return OopEncodingHeapMax - ClassMetaspaceSize - os::vm_page_size()); + assert(OopEncodingHeapMax > (uint64_t)os::vm_page_size(), "Unusual page size"); + LP64_ONLY(return OopEncodingHeapMax - os::vm_page_size()); NOT_LP64(ShouldNotReachHere(); return 0); } @@ -1448,6 +1446,35 @@ void Arguments::set_use_compressed_oops() { #endif // ZERO } + +// NOTE: set_use_compressed_klass_ptrs() must be called after calling +// set_use_compressed_oops(). +void Arguments::set_use_compressed_klass_ptrs() { +#ifndef ZERO +#ifdef _LP64 + // UseCompressedOops must be on for UseCompressedKlassPointers to be on. + if (!UseCompressedOops) { + if (UseCompressedKlassPointers) { + warning("UseCompressedKlassPointers requires UseCompressedOops"); + } + FLAG_SET_DEFAULT(UseCompressedKlassPointers, false); + } else { + // Turn on UseCompressedKlassPointers too + if (FLAG_IS_DEFAULT(UseCompressedKlassPointers)) { + FLAG_SET_ERGO(bool, UseCompressedKlassPointers, true); + } + // Check the ClassMetaspaceSize to make sure we use compressed klass ptrs. + if (UseCompressedKlassPointers) { + if (ClassMetaspaceSize > KlassEncodingMetaspaceMax) { + warning("Class metaspace size is too large for UseCompressedKlassPointers"); + FLAG_SET_DEFAULT(UseCompressedKlassPointers, false); + } + } + } +#endif // _LP64 +#endif // !ZERO +} + void Arguments::set_ergonomics_flags() { if (os::is_server_class_machine()) { @@ -1470,7 +1497,8 @@ void Arguments::set_ergonomics_flags() { // server performance. On server class machines, keep the default // off unless it is asked for. Future work: either add bytecode rewriting // at link time, or rewrite bytecodes in non-shared methods. - if (!DumpSharedSpaces && !RequireSharedSpaces) { + if (!DumpSharedSpaces && !RequireSharedSpaces && + (FLAG_IS_DEFAULT(UseSharedSpaces) || !UseSharedSpaces)) { no_shared_spaces(); } } @@ -1478,33 +1506,11 @@ void Arguments::set_ergonomics_flags() { #ifndef ZERO #ifdef _LP64 set_use_compressed_oops(); - // UseCompressedOops must be on for UseCompressedKlassPointers to be on. - if (!UseCompressedOops) { - if (UseCompressedKlassPointers) { - warning("UseCompressedKlassPointers requires UseCompressedOops"); - } - FLAG_SET_DEFAULT(UseCompressedKlassPointers, false); - } else { - // Turn on UseCompressedKlassPointers too - if (FLAG_IS_DEFAULT(UseCompressedKlassPointers)) { - FLAG_SET_ERGO(bool, UseCompressedKlassPointers, true); - } - // Set the ClassMetaspaceSize to something that will not need to be - // expanded, since it cannot be expanded. - if (UseCompressedKlassPointers) { - if (ClassMetaspaceSize > KlassEncodingMetaspaceMax) { - warning("Class metaspace size is too large for UseCompressedKlassPointers"); - FLAG_SET_DEFAULT(UseCompressedKlassPointers, false); - } else if (FLAG_IS_DEFAULT(ClassMetaspaceSize)) { - // 100,000 classes seems like a good size, so 100M assumes around 1K - // per klass. The vtable and oopMap is embedded so we don't have a fixed - // size per klass. Eventually, this will be parameterized because it - // would also be useful to determine the optimal size of the - // systemDictionary. - FLAG_SET_ERGO(uintx, ClassMetaspaceSize, 100*M); - } - } - } + + // set_use_compressed_klass_ptrs() must be called after calling + // set_use_compressed_oops(). + set_use_compressed_klass_ptrs(); + // Also checks that certain machines are slower with compressed oops // in vm_version initialization code. #endif // _LP64 @@ -2153,7 +2159,7 @@ bool Arguments::check_vm_args_consistency() { status = status && verify_object_alignment(); - status = status && verify_min_value(ClassMetaspaceSize, 1*M, + status = status && verify_interval(ClassMetaspaceSize, 1*M, 3*G, "ClassMetaspaceSize"); status = status && verify_interval(MarkStackSizeMax, @@ -3273,33 +3279,22 @@ jint Arguments::parse_options_environment_variable(const char* name, SysClassPat } void Arguments::set_shared_spaces_flags() { -#ifdef _LP64 - const bool must_share = DumpSharedSpaces || RequireSharedSpaces; - - // CompressedOops cannot be used with CDS. The offsets of oopmaps and - // static fields are incorrect in the archive. With some more clever - // initialization, this restriction can probably be lifted. - if (UseCompressedOops) { - if (must_share) { - warning("disabling compressed oops because of %s", - DumpSharedSpaces ? "-Xshare:dump" : "-Xshare:on"); - FLAG_SET_CMDLINE(bool, UseCompressedOops, false); - FLAG_SET_CMDLINE(bool, UseCompressedKlassPointers, false); - } else { - // Prefer compressed oops to class data sharing - if (UseSharedSpaces && Verbose) { - warning("turning off use of shared archive because of compressed oops"); - } - no_shared_spaces(); - } - } -#endif - if (DumpSharedSpaces) { if (RequireSharedSpaces) { warning("cannot dump shared archive while using shared archive"); } UseSharedSpaces = false; +#ifdef _LP64 + if (!UseCompressedOops || !UseCompressedKlassPointers) { + vm_exit_during_initialization( + "Cannot dump shared archive when UseCompressedOops or UseCompressedKlassPointers is off.", NULL); + } + } else { + // UseCompressedOops and UseCompressedKlassPointers must be on for UseSharedSpaces. + if (!UseCompressedOops || !UseCompressedKlassPointers) { + no_shared_spaces(); + } +#endif } } diff --git a/hotspot/src/share/vm/runtime/arguments.hpp b/hotspot/src/share/vm/runtime/arguments.hpp index 89b171f0d46..c5a6854dcc3 100644 --- a/hotspot/src/share/vm/runtime/arguments.hpp +++ b/hotspot/src/share/vm/runtime/arguments.hpp @@ -309,6 +309,7 @@ class Arguments : AllStatic { static void set_g1_gc_flags(); // GC ergonomics static void set_use_compressed_oops(); + static void set_use_compressed_klass_ptrs(); static void set_ergonomics_flags(); static void set_shared_spaces_flags(); // limits the given memory size by the maximum amount of memory this process is diff --git a/hotspot/src/share/vm/runtime/globals.hpp b/hotspot/src/share/vm/runtime/globals.hpp index c598c540ecc..9b67389af47 100644 --- a/hotspot/src/share/vm/runtime/globals.hpp +++ b/hotspot/src/share/vm/runtime/globals.hpp @@ -3036,7 +3036,7 @@ class CommandLineFlags { product(uintx, MaxMetaspaceSize, max_uintx, \ "Maximum size of Metaspaces (in bytes)") \ \ - product(uintx, ClassMetaspaceSize, 2*M, \ + product(uintx, ClassMetaspaceSize, 1*G, \ "Maximum size of InstanceKlass area in Metaspace used for " \ "UseCompressedKlassPointers") \ \ diff --git a/hotspot/src/share/vm/runtime/init.cpp b/hotspot/src/share/vm/runtime/init.cpp index 62f295c7ec6..4533c7e8127 100644 --- a/hotspot/src/share/vm/runtime/init.cpp +++ b/hotspot/src/share/vm/runtime/init.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -95,7 +95,6 @@ jint init_globals() { management_init(); bytecodes_init(); classLoader_init(); - Metaspace::global_initialize(); // must be before codeCache codeCache_init(); VM_Version_init(); os_init_globals(); diff --git a/hotspot/src/share/vm/utilities/globalDefinitions.hpp b/hotspot/src/share/vm/utilities/globalDefinitions.hpp index 181e80a0823..1beae04cc6c 100644 --- a/hotspot/src/share/vm/utilities/globalDefinitions.hpp +++ b/hotspot/src/share/vm/utilities/globalDefinitions.hpp @@ -362,6 +362,8 @@ const int KlassAlignment = KlassAlignmentInBytes / HeapWordSize; // Klass encoding metaspace max size const uint64_t KlassEncodingMetaspaceMax = (uint64_t(max_juint) + 1) << LogKlassAlignmentInBytes; +const jlong CompressedKlassPointersBase = NOT_LP64(0) LP64_ONLY(CONST64(0x800000000)); // 32*G + // Machine dependent stuff #ifdef TARGET_ARCH_x86 diff --git a/hotspot/test/runtime/CDSCompressedKPtrs/CDSCompressedKPtrs.java b/hotspot/test/runtime/CDSCompressedKPtrs/CDSCompressedKPtrs.java new file mode 100644 index 00000000000..b1c8ad996d2 --- /dev/null +++ b/hotspot/test/runtime/CDSCompressedKPtrs/CDSCompressedKPtrs.java @@ -0,0 +1,61 @@ +/* + * 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 8003424 + * @summary Testing UseCompressedKlassPointers with CDS + * @library /testlibrary + * @run main CDSCompressedKPtrs + */ + +import com.oracle.java.testlibrary.*; + +public class CDSCompressedKPtrs { + public static void main(String[] args) throws Exception { + ProcessBuilder pb; + if (Platform.is64bit()) { + pb = ProcessTools.createJavaProcessBuilder( + "-XX:+UseCompressedKlassPointers", "-XX:+UseCompressedOops", + "-XX:+UnlockDiagnosticVMOptions", "-XX:SharedArchiveFile=./sample.jsa", "-Xshare:dump"); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + try { + output.shouldContain("Loading classes to share"); + output.shouldHaveExitValue(0); + + pb = ProcessTools.createJavaProcessBuilder( + "-XX:+UseCompressedKlassPointers", "-XX:+UseCompressedOops", + "-XX:+UnlockDiagnosticVMOptions", "-XX:SharedArchiveFile=./sample.jsa", "-Xshare:on", "-version"); + output = new OutputAnalyzer(pb.start()); + output.shouldContain("sharing"); + output.shouldHaveExitValue(0); + + } catch (RuntimeException e) { + // Report 'passed' if CDS was turned off because we could not allocate + // the klass metaspace at an address that would work with CDS. + output.shouldContain("Could not allocate metaspace at a compatible address"); + output.shouldHaveExitValue(1); + } + } + } +} diff --git a/hotspot/test/runtime/CDSCompressedKPtrs/CDSCompressedKPtrsError.java b/hotspot/test/runtime/CDSCompressedKPtrs/CDSCompressedKPtrsError.java new file mode 100644 index 00000000000..b2cb84ac988 --- /dev/null +++ b/hotspot/test/runtime/CDSCompressedKPtrs/CDSCompressedKPtrsError.java @@ -0,0 +1,93 @@ +/* + * 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 8003424 + * @summary Test that cannot use CDS if UseCompressedKlassPointers is turned off. + * @library /testlibrary + * @run main CDSCompressedKPtrsError + */ + +import com.oracle.java.testlibrary.*; + +public class CDSCompressedKPtrsError { + public static void main(String[] args) throws Exception { + ProcessBuilder pb; + if (Platform.is64bit()) { + pb = ProcessTools.createJavaProcessBuilder( + "-XX:+UseCompressedOops", "-XX:+UseCompressedKlassPointers", "-XX:+UnlockDiagnosticVMOptions", + "-XX:SharedArchiveFile=./sample.jsa", "-Xshare:dump"); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + try { + output.shouldContain("Loading classes to share"); + output.shouldHaveExitValue(0); + + pb = ProcessTools.createJavaProcessBuilder( + "-XX:-UseCompressedKlassPointers", "-XX:-UseCompressedOops", + "-XX:+UnlockDiagnosticVMOptions", "-XX:SharedArchiveFile=./sample.jsa", "-Xshare:on", "-version"); + output = new OutputAnalyzer(pb.start()); + output.shouldContain("Unable to use shared archive"); + output.shouldHaveExitValue(0); + + pb = ProcessTools.createJavaProcessBuilder( + "-XX:-UseCompressedKlassPointers", "-XX:+UseCompressedOops", + "-XX:+UnlockDiagnosticVMOptions", "-XX:SharedArchiveFile=./sample.jsa", "-Xshare:on", "-version"); + output = new OutputAnalyzer(pb.start()); + output.shouldContain("Unable to use shared archive"); + output.shouldHaveExitValue(0); + + pb = ProcessTools.createJavaProcessBuilder( + "-XX:+UseCompressedKlassPointers", "-XX:-UseCompressedOops", + "-XX:+UnlockDiagnosticVMOptions", "-XX:SharedArchiveFile=./sample.jsa", "-Xshare:on", "-version"); + output = new OutputAnalyzer(pb.start()); + output.shouldContain("Unable to use shared archive"); + output.shouldHaveExitValue(0); + + } catch (RuntimeException e) { + output.shouldContain("Unable to use shared archive"); + output.shouldHaveExitValue(1); + } + + // Test bad options with -Xshare:dump. + pb = ProcessTools.createJavaProcessBuilder( + "-XX:-UseCompressedOops", "-XX:+UseCompressedKlassPointers", "-XX:+UnlockDiagnosticVMOptions", + "-XX:SharedArchiveFile=./sample.jsa", "-Xshare:dump"); + output = new OutputAnalyzer(pb.start()); + output.shouldContain("Cannot dump shared archive"); + + pb = ProcessTools.createJavaProcessBuilder( + "-XX:+UseCompressedOops", "-XX:-UseCompressedKlassPointers", "-XX:+UnlockDiagnosticVMOptions", + "-XX:SharedArchiveFile=./sample.jsa", "-Xshare:dump"); + output = new OutputAnalyzer(pb.start()); + output.shouldContain("Cannot dump shared archive"); + + pb = ProcessTools.createJavaProcessBuilder( + "-XX:-UseCompressedOops", "-XX:-UseCompressedKlassPointers", "-XX:+UnlockDiagnosticVMOptions", + "-XX:SharedArchiveFile=./sample.jsa", "-Xshare:dump"); + output = new OutputAnalyzer(pb.start()); + output.shouldContain("Cannot dump shared archive"); + + } + } +} diff --git a/hotspot/test/runtime/CDSCompressedKPtrs/XShareAuto.java b/hotspot/test/runtime/CDSCompressedKPtrs/XShareAuto.java new file mode 100644 index 00000000000..0165b2cc782 --- /dev/null +++ b/hotspot/test/runtime/CDSCompressedKPtrs/XShareAuto.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8005933 + * @summary Test that -Xshare:auto uses CDS when explicitly specified with -server. + * @library /testlibrary + * @run main XShareAuto + */ + +import com.oracle.java.testlibrary.*; + +public class XShareAuto { + public static void main(String[] args) throws Exception { + if (!Platform.is64bit()) { + System.out.println("ObjectAlignmentInBytes for CDS is only " + + "supported on 64bit platforms; this plaform is " + + System.getProperty("sun.arch.data.model")); + System.out.println("Skipping the test"); + return; + } + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-XX:+UnlockDiagnosticVMOptions", "-XX:SharedArchiveFile=./sample.jsa", + "-Xshare:dump"); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldContain("Loading classes to share"); + output.shouldHaveExitValue(0); + + pb = ProcessTools.createJavaProcessBuilder( + "-server", "-XX:+UnlockDiagnosticVMOptions", + "-XX:SharedArchiveFile=./sample.jsa", "-version"); + output = new OutputAnalyzer(pb.start()); + output.shouldNotContain("sharing"); + output.shouldHaveExitValue(0); + + pb = ProcessTools.createJavaProcessBuilder( + "-server", "-Xshare:auto", "-XX:+UnlockDiagnosticVMOptions", + "-XX:SharedArchiveFile=./sample.jsa", "-version"); + output = new OutputAnalyzer(pb.start()); + try { + output.shouldContain("sharing"); + output.shouldHaveExitValue(0); + } catch (RuntimeException e) { + // If this failed then check that it would also be unable + // to share even if -Xshare:on is specified. If so, then + // return a success status. + pb = ProcessTools.createJavaProcessBuilder( + "-server", "-Xshare:on", "-XX:+UnlockDiagnosticVMOptions", + "-XX:SharedArchiveFile=./sample.jsa", "-version"); + output = new OutputAnalyzer(pb.start()); + output.shouldContain("Could not allocate metaspace at a compatible address"); + output.shouldHaveExitValue(1); + } + } +} diff --git a/hotspot/test/runtime/SharedArchiveFile/CdsSameObjectAlignment.java b/hotspot/test/runtime/SharedArchiveFile/CdsSameObjectAlignment.java index e95bae3a790..b956095697b 100644 --- a/hotspot/test/runtime/SharedArchiveFile/CdsSameObjectAlignment.java +++ b/hotspot/test/runtime/SharedArchiveFile/CdsSameObjectAlignment.java @@ -84,8 +84,7 @@ public class CdsSameObjectAlignment { // there is a chance such reservation will fail // If it does, it is NOT considered a failure of the feature, // rather a possible expected outcome, though not likely - output.shouldContain( - "Unable to reserve shared space at required address"); + output.shouldContain("Could not allocate metaspace at a compatible address"); output.shouldHaveExitValue(1); } } From 2f90b28014ae47a63b41f87de7b666ebcaab9def Mon Sep 17 00:00:00 2001 From: Athijegannathan Sundararajan Date: Fri, 16 Aug 2013 15:04:36 +0530 Subject: [PATCH 062/218] 8020355: bind on built-in constructors don't use bound argument values Reviewed-by: lagergren, hannesw --- .../internal/runtime/ScriptFunctionData.java | 11 +++- nashorn/test/script/basic/JDK-8020355.js | 63 +++++++++++++++++++ 2 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 nashorn/test/script/basic/JDK-8020355.js diff --git a/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java b/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java index c1c1de6edd5..06a12c0096b 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java @@ -250,9 +250,18 @@ public abstract class ScriptFunctionData { final int length = args == null ? 0 : args.length; CompiledFunctions boundList = new CompiledFunctions(); - for (final CompiledFunction inv : code) { + if (code.size() == 1) { + // only one variant - bind that + boundList.add(bind(code.first(), fn, self, allArgs)); + } else { + // There are specialized versions. Get the most generic one. + // This is to avoid ambiguous overloaded versions of bound and + // specialized variants and choosing wrong overload. + final MethodHandle genInvoker = getGenericInvoker(); + final CompiledFunction inv = new CompiledFunction(genInvoker.type(), genInvoker, getGenericConstructor()); boundList.add(bind(inv, fn, self, allArgs)); } + ScriptFunctionData boundData = new FinalScriptFunctionData(name, arity == -1 ? -1 : Math.max(0, arity - length), boundList, isStrict(), isBuiltin(), isConstructor()); return boundData; } diff --git a/nashorn/test/script/basic/JDK-8020355.js b/nashorn/test/script/basic/JDK-8020355.js new file mode 100644 index 00000000000..262c458a8e3 --- /dev/null +++ b/nashorn/test/script/basic/JDK-8020355.js @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * JDK-8020355: bind on built-in constructors don't use bound argument values + * + * @test + * @run + */ + +if (Array.bind(null, 2)().length != 2) { + fail("Expected Array.bind(null, 2)().length to be 2"); +} + +if (RegExp.bind(null, "a")().source.length != 1) { + fail("Expected RegExp.bind(null, 'a')().source.length to be 1"); +} + +// check user defined functions as well + +var res = (function(x, y) { return x*y }).bind(null, 20, 30)(); +if (res != 600) { + fail("Expected 600, but got " + res); +} + +var obj = new ((function(x, y) { this.foo = x*y }).bind({}, 20, 30))(); +if (obj.foo != 600) { + fail("Expected this.foo = 600, but got " + res); +} + +// try variadic function as well + +var res = (function() { return arguments[0]*arguments[1] }).bind(null, 20, 30)(); +if (res != 600) { + fail("Expected 600, but got " + res); +} + +var obj = new ((function(x, y) { this.foo = arguments[0]*arguments[1] }).bind({}, 20, 30))(); +if (obj.foo != 600) { + fail("Expected this.foo = 600, but got " + res); +} + + From 7ade7987a0a8ccfde017811623d338b4c4b80237 Mon Sep 17 00:00:00 2001 From: Stefan Karlsson Date: Fri, 16 Aug 2013 13:22:32 +0200 Subject: [PATCH 063/218] 8007074: SIGSEGV at ParMarkBitMap::verify_clear() Replace the broken large pages implementation on Linux. New flag: -XX:+UseTransparentHugePages - Linux specific flag to turn on transparent huge page hinting with madvise(..., MAP_HUGETLB). Changed behavior: -XX:+UseLargePages - tries to use -XX:+UseTransparentHugePages before trying other large pages implementations (on Linux). Changed behavior: -XX:+UseHugeTLBFS - Use upfront allocation of Large Pages instead of using the broken implementation to dynamically committing large pages. Changed behavior: -XX:LargePageSizeInBytes - Turned off the ability to use this flag on Linux and provides warning to user if set to a value different than the OS chosen large page size. Changed behavior: Setting no large page size - Now defaults to use -XX:UseTransparentHugePages if the OS supports it. Previously, -XX:+UseHugeTLBFS was chosen if the OS was configured to use large pages. Reviewed-by: tschatzl, dcubed, brutisso --- hotspot/src/os/bsd/vm/os_bsd.cpp | 9 +- hotspot/src/os/linux/vm/globals_linux.hpp | 3 + hotspot/src/os/linux/vm/os_linux.cpp | 586 ++++++++++++++---- hotspot/src/os/linux/vm/os_linux.hpp | 14 + hotspot/src/os/solaris/vm/os_solaris.cpp | 8 +- hotspot/src/os/windows/vm/os_windows.cpp | 13 +- .../gc_implementation/g1/g1CollectedHeap.cpp | 8 +- .../g1/g1CollectorPolicy.cpp | 3 +- .../src/share/vm/memory/collectorPolicy.cpp | 2 + .../src/share/vm/memory/genCollectedHeap.cpp | 29 +- hotspot/src/share/vm/memory/metaspace.cpp | 2 +- hotspot/src/share/vm/memory/universe.cpp | 32 +- hotspot/src/share/vm/memory/universe.hpp | 2 +- hotspot/src/share/vm/prims/jni.cpp | 6 + hotspot/src/share/vm/runtime/globals.hpp | 3 + hotspot/src/share/vm/runtime/os.hpp | 4 +- hotspot/src/share/vm/runtime/virtualspace.cpp | 205 +++++- hotspot/src/share/vm/runtime/virtualspace.hpp | 1 + hotspot/src/share/vm/services/memTracker.hpp | 9 + .../share/vm/utilities/globalDefinitions.hpp | 16 + 20 files changed, 796 insertions(+), 159 deletions(-) diff --git a/hotspot/src/os/bsd/vm/os_bsd.cpp b/hotspot/src/os/bsd/vm/os_bsd.cpp index 1db3739fa84..6b636d379de 100644 --- a/hotspot/src/os/bsd/vm/os_bsd.cpp +++ b/hotspot/src/os/bsd/vm/os_bsd.cpp @@ -2325,7 +2325,9 @@ void os::large_page_init() { } -char* os::reserve_memory_special(size_t bytes, char* req_addr, bool exec) { +char* os::reserve_memory_special(size_t bytes, size_t alignment, char* req_addr, bool exec) { + fatal("This code is not used or maintained."); + // "exec" is passed in but not used. Creating the shared image for // the code cache doesn't have an SHM_X executable permission to check. assert(UseLargePages && UseSHM, "only for SHM large pages"); @@ -4752,3 +4754,8 @@ int os::get_core_path(char* buffer, size_t bufferSize) { return n; } +#ifndef PRODUCT +void TestReserveMemorySpecial_test() { + // No tests available for this platform +} +#endif diff --git a/hotspot/src/os/linux/vm/globals_linux.hpp b/hotspot/src/os/linux/vm/globals_linux.hpp index af4947b1b86..4dfccc3f6ee 100644 --- a/hotspot/src/os/linux/vm/globals_linux.hpp +++ b/hotspot/src/os/linux/vm/globals_linux.hpp @@ -40,6 +40,9 @@ product(bool, UseHugeTLBFS, false, \ "Use MAP_HUGETLB for large pages") \ \ + product(bool, UseTransparentHugePages, false, \ + "Use MADV_HUGEPAGE for large pages") \ + \ product(bool, LoadExecStackDllInVMThread, true, \ "Load DLLs with executable-stack attribute in the VM Thread") \ \ diff --git a/hotspot/src/os/linux/vm/os_linux.cpp b/hotspot/src/os/linux/vm/os_linux.cpp index df58be635d1..23d3457046d 100644 --- a/hotspot/src/os/linux/vm/os_linux.cpp +++ b/hotspot/src/os/linux/vm/os_linux.cpp @@ -2720,36 +2720,7 @@ void os::pd_commit_memory_or_exit(char* addr, size_t size, bool exec, int os::Linux::commit_memory_impl(char* addr, size_t size, size_t alignment_hint, bool exec) { - int err; - if (UseHugeTLBFS && alignment_hint > (size_t)vm_page_size()) { - int prot = exec ? PROT_READ|PROT_WRITE|PROT_EXEC : PROT_READ|PROT_WRITE; - uintptr_t res = - (uintptr_t) ::mmap(addr, size, prot, - MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS|MAP_HUGETLB, - -1, 0); - if (res != (uintptr_t) MAP_FAILED) { - if (UseNUMAInterleaving) { - numa_make_global(addr, size); - } - return 0; - } - - err = errno; // save errno from mmap() call above - - if (!recoverable_mmap_error(err)) { - // However, it is not clear that this loss of our reserved mapping - // happens with large pages on Linux or that we cannot recover - // from the loss. For now, we just issue a warning and we don't - // call vm_exit_out_of_memory(). This issue is being tracked by - // JBS-8007074. - warn_fail_commit_memory(addr, size, alignment_hint, exec, err); -// vm_exit_out_of_memory(size, OOM_MMAP_ERROR, -// "committing reserved memory."); - } - // Fall through and try to use small pages - } - - err = os::Linux::commit_memory_impl(addr, size, exec); + int err = os::Linux::commit_memory_impl(addr, size, exec); if (err == 0) { realign_memory(addr, size, alignment_hint); } @@ -2774,7 +2745,7 @@ void os::pd_commit_memory_or_exit(char* addr, size_t size, } void os::pd_realign_memory(char *addr, size_t bytes, size_t alignment_hint) { - if (UseHugeTLBFS && alignment_hint > (size_t)vm_page_size()) { + if (UseTransparentHugePages && alignment_hint > (size_t)vm_page_size()) { // We don't check the return value: madvise(MADV_HUGEPAGE) may not // be supported or the memory may already be backed by huge pages. ::madvise(addr, bytes, MADV_HUGEPAGE); @@ -2787,7 +2758,7 @@ void os::pd_free_memory(char *addr, size_t bytes, size_t alignment_hint) { // uncommitted at all. We don't do anything in this case to avoid creating a segment with // small pages on top of the SHM segment. This method always works for small pages, so we // allow that in any case. - if (alignment_hint <= (size_t)os::vm_page_size() || !UseSHM) { + if (alignment_hint <= (size_t)os::vm_page_size() || can_commit_large_page_memory()) { commit_memory(addr, bytes, alignment_hint, !ExecMem); } } @@ -3157,11 +3128,31 @@ bool os::unguard_memory(char* addr, size_t size) { return linux_mprotect(addr, size, PROT_READ|PROT_WRITE); } +bool os::Linux::transparent_huge_pages_sanity_check(bool warn, size_t page_size) { + bool result = false; + void *p = mmap(NULL, page_size * 2, PROT_READ|PROT_WRITE, + MAP_ANONYMOUS|MAP_PRIVATE, + -1, 0); + if (p != MAP_FAILED) { + void *aligned_p = align_ptr_up(p, page_size); + + result = madvise(aligned_p, page_size, MADV_HUGEPAGE) == 0; + + munmap(p, page_size * 2); + } + + if (warn && !result) { + warning("TransparentHugePages is not supported by the operating system."); + } + + return result; +} + bool os::Linux::hugetlbfs_sanity_check(bool warn, size_t page_size) { bool result = false; - void *p = mmap (NULL, page_size, PROT_READ|PROT_WRITE, - MAP_ANONYMOUS|MAP_PRIVATE|MAP_HUGETLB, - -1, 0); + void *p = mmap(NULL, page_size, PROT_READ|PROT_WRITE, + MAP_ANONYMOUS|MAP_PRIVATE|MAP_HUGETLB, + -1, 0); if (p != MAP_FAILED) { // We don't know if this really is a huge page or not. @@ -3182,12 +3173,10 @@ bool os::Linux::hugetlbfs_sanity_check(bool warn, size_t page_size) { } fclose(fp); } - munmap (p, page_size); - if (result) - return true; + munmap(p, page_size); } - if (warn) { + if (warn && !result) { warning("HugeTLBFS is not supported by the operating system."); } @@ -3235,82 +3224,114 @@ static void set_coredump_filter(void) { static size_t _large_page_size = 0; -void os::large_page_init() { - if (!UseLargePages) { - UseHugeTLBFS = false; - UseSHM = false; - return; - } +size_t os::Linux::find_large_page_size() { + size_t large_page_size = 0; - if (FLAG_IS_DEFAULT(UseHugeTLBFS) && FLAG_IS_DEFAULT(UseSHM)) { - // If UseLargePages is specified on the command line try both methods, - // if it's default, then try only HugeTLBFS. - if (FLAG_IS_DEFAULT(UseLargePages)) { - UseHugeTLBFS = true; - } else { - UseHugeTLBFS = UseSHM = true; - } - } - - if (LargePageSizeInBytes) { - _large_page_size = LargePageSizeInBytes; - } else { - // large_page_size on Linux is used to round up heap size. x86 uses either - // 2M or 4M page, depending on whether PAE (Physical Address Extensions) - // mode is enabled. AMD64/EM64T uses 2M page in 64bit mode. IA64 can use - // page as large as 256M. - // - // Here we try to figure out page size by parsing /proc/meminfo and looking - // for a line with the following format: - // Hugepagesize: 2048 kB - // - // If we can't determine the value (e.g. /proc is not mounted, or the text - // format has been changed), we'll use the largest page size supported by - // the processor. + // large_page_size on Linux is used to round up heap size. x86 uses either + // 2M or 4M page, depending on whether PAE (Physical Address Extensions) + // mode is enabled. AMD64/EM64T uses 2M page in 64bit mode. IA64 can use + // page as large as 256M. + // + // Here we try to figure out page size by parsing /proc/meminfo and looking + // for a line with the following format: + // Hugepagesize: 2048 kB + // + // If we can't determine the value (e.g. /proc is not mounted, or the text + // format has been changed), we'll use the largest page size supported by + // the processor. #ifndef ZERO - _large_page_size = IA32_ONLY(4 * M) AMD64_ONLY(2 * M) IA64_ONLY(256 * M) SPARC_ONLY(4 * M) - ARM_ONLY(2 * M) PPC_ONLY(4 * M); + large_page_size = IA32_ONLY(4 * M) AMD64_ONLY(2 * M) IA64_ONLY(256 * M) SPARC_ONLY(4 * M) + ARM_ONLY(2 * M) PPC_ONLY(4 * M); #endif // ZERO - FILE *fp = fopen("/proc/meminfo", "r"); - if (fp) { - while (!feof(fp)) { - int x = 0; - char buf[16]; - if (fscanf(fp, "Hugepagesize: %d", &x) == 1) { - if (x && fgets(buf, sizeof(buf), fp) && strcmp(buf, " kB\n") == 0) { - _large_page_size = x * K; - break; - } - } else { - // skip to next line - for (;;) { - int ch = fgetc(fp); - if (ch == EOF || ch == (int)'\n') break; - } + FILE *fp = fopen("/proc/meminfo", "r"); + if (fp) { + while (!feof(fp)) { + int x = 0; + char buf[16]; + if (fscanf(fp, "Hugepagesize: %d", &x) == 1) { + if (x && fgets(buf, sizeof(buf), fp) && strcmp(buf, " kB\n") == 0) { + large_page_size = x * K; + break; + } + } else { + // skip to next line + for (;;) { + int ch = fgetc(fp); + if (ch == EOF || ch == (int)'\n') break; } } - fclose(fp); } + fclose(fp); } - // print a warning if any large page related flag is specified on command line - bool warn_on_failure = !FLAG_IS_DEFAULT(UseHugeTLBFS); + if (!FLAG_IS_DEFAULT(LargePageSizeInBytes) && LargePageSizeInBytes != large_page_size) { + warning("Setting LargePageSizeInBytes has no effect on this OS. Large page size is " + SIZE_FORMAT "%s.", byte_size_in_proper_unit(large_page_size), + proper_unit_for_byte_size(large_page_size)); + } + return large_page_size; +} + +size_t os::Linux::setup_large_page_size() { + _large_page_size = Linux::find_large_page_size(); const size_t default_page_size = (size_t)Linux::page_size(); if (_large_page_size > default_page_size) { _page_sizes[0] = _large_page_size; _page_sizes[1] = default_page_size; _page_sizes[2] = 0; } - UseHugeTLBFS = UseHugeTLBFS && - Linux::hugetlbfs_sanity_check(warn_on_failure, _large_page_size); - if (UseHugeTLBFS) + return _large_page_size; +} + +bool os::Linux::setup_large_page_type(size_t page_size) { + if (FLAG_IS_DEFAULT(UseHugeTLBFS) && + FLAG_IS_DEFAULT(UseSHM) && + FLAG_IS_DEFAULT(UseTransparentHugePages)) { + // If UseLargePages is specified on the command line try all methods, + // if it's default, then try only UseTransparentHugePages. + if (FLAG_IS_DEFAULT(UseLargePages)) { + UseTransparentHugePages = true; + } else { + UseHugeTLBFS = UseTransparentHugePages = UseSHM = true; + } + } + + if (UseTransparentHugePages) { + bool warn_on_failure = !FLAG_IS_DEFAULT(UseTransparentHugePages); + if (transparent_huge_pages_sanity_check(warn_on_failure, page_size)) { + UseHugeTLBFS = false; + UseSHM = false; + return true; + } + UseTransparentHugePages = false; + } + + if (UseHugeTLBFS) { + bool warn_on_failure = !FLAG_IS_DEFAULT(UseHugeTLBFS); + if (hugetlbfs_sanity_check(warn_on_failure, page_size)) { + UseSHM = false; + return true; + } + UseHugeTLBFS = false; + } + + return UseSHM; +} + +void os::large_page_init() { + if (!UseLargePages) { + UseHugeTLBFS = false; + UseTransparentHugePages = false; UseSHM = false; + return; + } - UseLargePages = UseHugeTLBFS || UseSHM; + size_t large_page_size = Linux::setup_large_page_size(); + UseLargePages = Linux::setup_large_page_type(large_page_size); set_coredump_filter(); } @@ -3319,16 +3340,22 @@ void os::large_page_init() { #define SHM_HUGETLB 04000 #endif -char* os::reserve_memory_special(size_t bytes, char* req_addr, bool exec) { +char* os::Linux::reserve_memory_special_shm(size_t bytes, size_t alignment, char* req_addr, bool exec) { // "exec" is passed in but not used. Creating the shared image for // the code cache doesn't have an SHM_X executable permission to check. assert(UseLargePages && UseSHM, "only for SHM large pages"); + assert(is_ptr_aligned(req_addr, os::large_page_size()), "Unaligned address"); + + if (!is_size_aligned(bytes, os::large_page_size()) || alignment > os::large_page_size()) { + return NULL; // Fallback to small pages. + } key_t key = IPC_PRIVATE; char *addr; bool warn_on_failure = UseLargePages && (!FLAG_IS_DEFAULT(UseLargePages) || + !FLAG_IS_DEFAULT(UseSHM) || !FLAG_IS_DEFAULT(LargePageSizeInBytes) ); char msg[128]; @@ -3376,42 +3403,219 @@ char* os::reserve_memory_special(size_t bytes, char* req_addr, bool exec) { return NULL; } - if ((addr != NULL) && UseNUMAInterleaving) { - numa_make_global(addr, bytes); + return addr; +} + +static void warn_on_large_pages_failure(char* req_addr, size_t bytes, int error) { + assert(error == ENOMEM, "Only expect to fail if no memory is available"); + + bool warn_on_failure = UseLargePages && + (!FLAG_IS_DEFAULT(UseLargePages) || + !FLAG_IS_DEFAULT(UseHugeTLBFS) || + !FLAG_IS_DEFAULT(LargePageSizeInBytes)); + + if (warn_on_failure) { + char msg[128]; + jio_snprintf(msg, sizeof(msg), "Failed to reserve large pages memory req_addr: " + PTR_FORMAT " bytes: " SIZE_FORMAT " (errno = %d).", req_addr, bytes, error); + warning(msg); + } +} + +char* os::Linux::reserve_memory_special_huge_tlbfs_only(size_t bytes, char* req_addr, bool exec) { + assert(UseLargePages && UseHugeTLBFS, "only for Huge TLBFS large pages"); + assert(is_size_aligned(bytes, os::large_page_size()), "Unaligned size"); + assert(is_ptr_aligned(req_addr, os::large_page_size()), "Unaligned address"); + + int prot = exec ? PROT_READ|PROT_WRITE|PROT_EXEC : PROT_READ|PROT_WRITE; + char* addr = (char*)::mmap(req_addr, bytes, prot, + MAP_PRIVATE|MAP_ANONYMOUS|MAP_HUGETLB, + -1, 0); + + if (addr == MAP_FAILED) { + warn_on_large_pages_failure(req_addr, bytes, errno); + return NULL; } - // The memory is committed - MemTracker::record_virtual_memory_reserve_and_commit((address)addr, bytes, mtNone, CALLER_PC); + assert(is_ptr_aligned(addr, os::large_page_size()), "Must be"); return addr; } +char* os::Linux::reserve_memory_special_huge_tlbfs_mixed(size_t bytes, size_t alignment, char* req_addr, bool exec) { + size_t large_page_size = os::large_page_size(); + + assert(bytes >= large_page_size, "Shouldn't allocate large pages for small sizes"); + + // Allocate small pages. + + char* start; + if (req_addr != NULL) { + assert(is_ptr_aligned(req_addr, alignment), "Must be"); + assert(is_size_aligned(bytes, alignment), "Must be"); + start = os::reserve_memory(bytes, req_addr); + assert(start == NULL || start == req_addr, "Must be"); + } else { + start = os::reserve_memory_aligned(bytes, alignment); + } + + if (start == NULL) { + return NULL; + } + + assert(is_ptr_aligned(start, alignment), "Must be"); + + // os::reserve_memory_special will record this memory area. + // Need to release it here to prevent overlapping reservations. + MemTracker::record_virtual_memory_release((address)start, bytes); + + char* end = start + bytes; + + // Find the regions of the allocated chunk that can be promoted to large pages. + char* lp_start = (char*)align_ptr_up(start, large_page_size); + char* lp_end = (char*)align_ptr_down(end, large_page_size); + + size_t lp_bytes = lp_end - lp_start; + + assert(is_size_aligned(lp_bytes, large_page_size), "Must be"); + + if (lp_bytes == 0) { + // The mapped region doesn't even span the start and the end of a large page. + // Fall back to allocate a non-special area. + ::munmap(start, end - start); + return NULL; + } + + int prot = exec ? PROT_READ|PROT_WRITE|PROT_EXEC : PROT_READ|PROT_WRITE; + + + void* result; + + if (start != lp_start) { + result = ::mmap(start, lp_start - start, prot, + MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, + -1, 0); + if (result == MAP_FAILED) { + ::munmap(lp_start, end - lp_start); + return NULL; + } + } + + result = ::mmap(lp_start, lp_bytes, prot, + MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED|MAP_HUGETLB, + -1, 0); + if (result == MAP_FAILED) { + warn_on_large_pages_failure(req_addr, bytes, errno); + // If the mmap above fails, the large pages region will be unmapped and we + // have regions before and after with small pages. Release these regions. + // + // | mapped | unmapped | mapped | + // ^ ^ ^ ^ + // start lp_start lp_end end + // + ::munmap(start, lp_start - start); + ::munmap(lp_end, end - lp_end); + return NULL; + } + + if (lp_end != end) { + result = ::mmap(lp_end, end - lp_end, prot, + MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, + -1, 0); + if (result == MAP_FAILED) { + ::munmap(start, lp_end - start); + return NULL; + } + } + + return start; +} + +char* os::Linux::reserve_memory_special_huge_tlbfs(size_t bytes, size_t alignment, char* req_addr, bool exec) { + assert(UseLargePages && UseHugeTLBFS, "only for Huge TLBFS large pages"); + assert(is_ptr_aligned(req_addr, alignment), "Must be"); + assert(is_power_of_2(alignment), "Must be"); + assert(is_power_of_2(os::large_page_size()), "Must be"); + assert(bytes >= os::large_page_size(), "Shouldn't allocate large pages for small sizes"); + + if (is_size_aligned(bytes, os::large_page_size()) && alignment <= os::large_page_size()) { + return reserve_memory_special_huge_tlbfs_only(bytes, req_addr, exec); + } else { + return reserve_memory_special_huge_tlbfs_mixed(bytes, alignment, req_addr, exec); + } +} + +char* os::reserve_memory_special(size_t bytes, size_t alignment, char* req_addr, bool exec) { + assert(UseLargePages, "only for large pages"); + + char* addr; + if (UseSHM) { + addr = os::Linux::reserve_memory_special_shm(bytes, alignment, req_addr, exec); + } else { + assert(UseHugeTLBFS, "must be"); + addr = os::Linux::reserve_memory_special_huge_tlbfs(bytes, alignment, req_addr, exec); + } + + if (addr != NULL) { + if (UseNUMAInterleaving) { + numa_make_global(addr, bytes); + } + + // The memory is committed + MemTracker::record_virtual_memory_reserve_and_commit((address)addr, bytes, mtNone, CALLER_PC); + } + + return addr; +} + +bool os::Linux::release_memory_special_shm(char* base, size_t bytes) { + // detaching the SHM segment will also delete it, see reserve_memory_special_shm() + return shmdt(base) == 0; +} + +bool os::Linux::release_memory_special_huge_tlbfs(char* base, size_t bytes) { + return pd_release_memory(base, bytes); +} + bool os::release_memory_special(char* base, size_t bytes) { + assert(UseLargePages, "only for large pages"); + MemTracker::Tracker tkr = MemTracker::get_virtual_memory_release_tracker(); - // detaching the SHM segment will also delete it, see reserve_memory_special() - int rslt = shmdt(base); - if (rslt == 0) { + + bool res; + if (UseSHM) { + res = os::Linux::release_memory_special_shm(base, bytes); + } else { + assert(UseHugeTLBFS, "must be"); + res = os::Linux::release_memory_special_huge_tlbfs(base, bytes); + } + + if (res) { tkr.record((address)base, bytes); - return true; } else { tkr.discard(); - return false; } + + return res; } size_t os::large_page_size() { return _large_page_size; } -// HugeTLBFS allows application to commit large page memory on demand; -// with SysV SHM the entire memory region must be allocated as shared +// With SysV SHM the entire memory region must be allocated as shared // memory. +// HugeTLBFS allows application to commit large page memory on demand. +// However, when committing memory with HugeTLBFS fails, the region +// that was supposed to be committed will lose the old reservation +// and allow other threads to steal that memory region. Because of this +// behavior we can't commit HugeTLBFS memory. bool os::can_commit_large_page_memory() { - return UseHugeTLBFS; + return UseTransparentHugePages; } bool os::can_execute_large_page_memory() { - return UseHugeTLBFS; + return UseTransparentHugePages || UseHugeTLBFS; } // Reserve memory at an arbitrary address, only if that area is @@ -4563,21 +4767,23 @@ jint os::init_2(void) UseNUMA = false; } } - // With SHM large pages we cannot uncommit a page, so there's not way + // With SHM and HugeTLBFS large pages we cannot uncommit a page, so there's no way // we can make the adaptive lgrp chunk resizing work. If the user specified - // both UseNUMA and UseLargePages (or UseSHM) on the command line - warn and + // both UseNUMA and UseLargePages (or UseSHM/UseHugeTLBFS) on the command line - warn and // disable adaptive resizing. - if (UseNUMA && UseLargePages && UseSHM) { - if (!FLAG_IS_DEFAULT(UseNUMA)) { - if (FLAG_IS_DEFAULT(UseLargePages) && FLAG_IS_DEFAULT(UseSHM)) { + if (UseNUMA && UseLargePages && !can_commit_large_page_memory()) { + if (FLAG_IS_DEFAULT(UseNUMA)) { + UseNUMA = false; + } else { + if (FLAG_IS_DEFAULT(UseLargePages) && + FLAG_IS_DEFAULT(UseSHM) && + FLAG_IS_DEFAULT(UseHugeTLBFS)) { UseLargePages = false; } else { - warning("UseNUMA is not fully compatible with SHM large pages, disabling adaptive resizing"); + warning("UseNUMA is not fully compatible with SHM/HugeTLBFS large pages, disabling adaptive resizing"); UseAdaptiveSizePolicy = false; UseAdaptiveNUMAChunkSizing = false; } - } else { - UseNUMA = false; } } if (!UseNUMA && ForceNUMA) { @@ -5848,3 +6054,149 @@ void MemNotifyThread::start() { } #endif // JAVASE_EMBEDDED + + +/////////////// Unit tests /////////////// + +#ifndef PRODUCT + +#define test_log(...) \ + do {\ + if (VerboseInternalVMTests) { \ + tty->print_cr(__VA_ARGS__); \ + tty->flush(); \ + }\ + } while (false) + +class TestReserveMemorySpecial : AllStatic { + public: + static void small_page_write(void* addr, size_t size) { + size_t page_size = os::vm_page_size(); + + char* end = (char*)addr + size; + for (char* p = (char*)addr; p < end; p += page_size) { + *p = 1; + } + } + + static void test_reserve_memory_special_huge_tlbfs_only(size_t size) { + if (!UseHugeTLBFS) { + return; + } + + test_log("test_reserve_memory_special_huge_tlbfs_only(" SIZE_FORMAT ")", size); + + char* addr = os::Linux::reserve_memory_special_huge_tlbfs_only(size, NULL, false); + + if (addr != NULL) { + small_page_write(addr, size); + + os::Linux::release_memory_special_huge_tlbfs(addr, size); + } + } + + static void test_reserve_memory_special_huge_tlbfs_only() { + if (!UseHugeTLBFS) { + return; + } + + size_t lp = os::large_page_size(); + + for (size_t size = lp; size <= lp * 10; size += lp) { + test_reserve_memory_special_huge_tlbfs_only(size); + } + } + + static void test_reserve_memory_special_huge_tlbfs_mixed(size_t size, size_t alignment) { + if (!UseHugeTLBFS) { + return; + } + + test_log("test_reserve_memory_special_huge_tlbfs_mixed(" SIZE_FORMAT ", " SIZE_FORMAT ")", + size, alignment); + + assert(size >= os::large_page_size(), "Incorrect input to test"); + + char* addr = os::Linux::reserve_memory_special_huge_tlbfs_mixed(size, alignment, NULL, false); + + if (addr != NULL) { + small_page_write(addr, size); + + os::Linux::release_memory_special_huge_tlbfs(addr, size); + } + } + + static void test_reserve_memory_special_huge_tlbfs_mixed_all_alignments(size_t size) { + size_t lp = os::large_page_size(); + size_t ag = os::vm_allocation_granularity(); + + for (size_t alignment = ag; is_size_aligned(size, alignment); alignment *= 2) { + test_reserve_memory_special_huge_tlbfs_mixed(size, alignment); + } + } + + static void test_reserve_memory_special_huge_tlbfs_mixed() { + size_t lp = os::large_page_size(); + size_t ag = os::vm_allocation_granularity(); + + test_reserve_memory_special_huge_tlbfs_mixed_all_alignments(lp); + test_reserve_memory_special_huge_tlbfs_mixed_all_alignments(lp + ag); + test_reserve_memory_special_huge_tlbfs_mixed_all_alignments(lp + lp / 2); + test_reserve_memory_special_huge_tlbfs_mixed_all_alignments(lp * 2); + test_reserve_memory_special_huge_tlbfs_mixed_all_alignments(lp * 2 + ag); + test_reserve_memory_special_huge_tlbfs_mixed_all_alignments(lp * 2 - ag); + test_reserve_memory_special_huge_tlbfs_mixed_all_alignments(lp * 2 + lp / 2); + test_reserve_memory_special_huge_tlbfs_mixed_all_alignments(lp * 10); + test_reserve_memory_special_huge_tlbfs_mixed_all_alignments(lp * 10 + lp / 2); + } + + static void test_reserve_memory_special_huge_tlbfs() { + if (!UseHugeTLBFS) { + return; + } + + test_reserve_memory_special_huge_tlbfs_only(); + test_reserve_memory_special_huge_tlbfs_mixed(); + } + + static void test_reserve_memory_special_shm(size_t size, size_t alignment) { + if (!UseSHM) { + return; + } + + test_log("test_reserve_memory_special_shm(" SIZE_FORMAT ", " SIZE_FORMAT ")", size, alignment); + + char* addr = os::Linux::reserve_memory_special_shm(size, alignment, NULL, false); + + if (addr != NULL) { + assert(is_ptr_aligned(addr, alignment), "Check"); + assert(is_ptr_aligned(addr, os::large_page_size()), "Check"); + + small_page_write(addr, size); + + os::Linux::release_memory_special_shm(addr, size); + } + } + + static void test_reserve_memory_special_shm() { + size_t lp = os::large_page_size(); + size_t ag = os::vm_allocation_granularity(); + + for (size_t size = ag; size < lp * 3; size += ag) { + for (size_t alignment = ag; is_size_aligned(size, alignment); alignment *= 2) { + test_reserve_memory_special_shm(size, alignment); + } + } + } + + static void test() { + test_reserve_memory_special_huge_tlbfs(); + test_reserve_memory_special_shm(); + } +}; + +void TestReserveMemorySpecial_test() { + TestReserveMemorySpecial::test(); +} + +#endif diff --git a/hotspot/src/os/linux/vm/os_linux.hpp b/hotspot/src/os/linux/vm/os_linux.hpp index 8c5032fc23b..5fa24499319 100644 --- a/hotspot/src/os/linux/vm/os_linux.hpp +++ b/hotspot/src/os/linux/vm/os_linux.hpp @@ -32,6 +32,7 @@ typedef int (*pthread_getattr_func_type) (pthread_t, pthread_attr_t *); class Linux { friend class os; + friend class TestReserveMemorySpecial; // For signal-chaining #define MAXSIGNUM 32 @@ -92,8 +93,21 @@ class Linux { static void rebuild_cpu_to_node_map(); static GrowableArray* cpu_to_node() { return _cpu_to_node; } + static size_t find_large_page_size(); + static size_t setup_large_page_size(); + + static bool setup_large_page_type(size_t page_size); + static bool transparent_huge_pages_sanity_check(bool warn, size_t pages_size); static bool hugetlbfs_sanity_check(bool warn, size_t page_size); + static char* reserve_memory_special_shm(size_t bytes, size_t alignment, char* req_addr, bool exec); + static char* reserve_memory_special_huge_tlbfs(size_t bytes, size_t alignment, char* req_addr, bool exec); + static char* reserve_memory_special_huge_tlbfs_only(size_t bytes, char* req_addr, bool exec); + static char* reserve_memory_special_huge_tlbfs_mixed(size_t bytes, size_t alignment, char* req_addr, bool exec); + + static bool release_memory_special_shm(char* base, size_t bytes); + static bool release_memory_special_huge_tlbfs(char* base, size_t bytes); + static void print_full_memory_info(outputStream* st); static void print_distro_info(outputStream* st); static void print_libversion_info(outputStream* st); diff --git a/hotspot/src/os/solaris/vm/os_solaris.cpp b/hotspot/src/os/solaris/vm/os_solaris.cpp index 0a94cb536ab..c3e6e879077 100644 --- a/hotspot/src/os/solaris/vm/os_solaris.cpp +++ b/hotspot/src/os/solaris/vm/os_solaris.cpp @@ -3385,7 +3385,7 @@ bool os::Solaris::setup_large_pages(caddr_t start, size_t bytes, size_t align) { return true; } -char* os::reserve_memory_special(size_t size, char* addr, bool exec) { +char* os::reserve_memory_special(size_t size, size_t alignment, char* addr, bool exec) { fatal("os::reserve_memory_special should not be called on Solaris."); return NULL; } @@ -6601,3 +6601,9 @@ int os::get_core_path(char* buffer, size_t bufferSize) { return strlen(buffer); } + +#ifndef PRODUCT +void TestReserveMemorySpecial_test() { + // No tests available for this platform +} +#endif diff --git a/hotspot/src/os/windows/vm/os_windows.cpp b/hotspot/src/os/windows/vm/os_windows.cpp index 0674e6f3c83..64a593377c3 100644 --- a/hotspot/src/os/windows/vm/os_windows.cpp +++ b/hotspot/src/os/windows/vm/os_windows.cpp @@ -3156,7 +3156,12 @@ bool os::can_execute_large_page_memory() { return true; } -char* os::reserve_memory_special(size_t bytes, char* addr, bool exec) { +char* os::reserve_memory_special(size_t bytes, size_t alignment, char* addr, bool exec) { + assert(UseLargePages, "only for large pages"); + + if (!is_size_aligned(bytes, os::large_page_size()) || alignment > os::large_page_size()) { + return NULL; // Fallback to small pages. + } const DWORD prot = exec ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE; const DWORD flags = MEM_RESERVE | MEM_COMMIT | MEM_LARGE_PAGES; @@ -5638,3 +5643,9 @@ BOOL os::Advapi32Dll::AdvapiAvailable() { } #endif + +#ifndef PRODUCT +void TestReserveMemorySpecial_test() { + // No tests available for this platform +} +#endif diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp index 97a9a1fa54d..b163a464247 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp @@ -2006,10 +2006,12 @@ jint G1CollectedHeap::initialize() { size_t init_byte_size = collector_policy()->initial_heap_byte_size(); size_t max_byte_size = collector_policy()->max_heap_byte_size(); + size_t heap_alignment = collector_policy()->max_alignment(); // Ensure that the sizes are properly aligned. Universe::check_alignment(init_byte_size, HeapRegion::GrainBytes, "g1 heap"); Universe::check_alignment(max_byte_size, HeapRegion::GrainBytes, "g1 heap"); + Universe::check_alignment(max_byte_size, heap_alignment, "g1 heap"); _cg1r = new ConcurrentG1Refine(this); @@ -2026,12 +2028,8 @@ jint G1CollectedHeap::initialize() { // If this happens then we could end up using a non-optimal // compressed oops mode. - // Since max_byte_size is aligned to the size of a heap region (checked - // above). - Universe::check_alignment(max_byte_size, HeapRegion::GrainBytes, "g1 heap"); - ReservedSpace heap_rs = Universe::reserve_heap(max_byte_size, - HeapRegion::GrainBytes); + heap_alignment); // It is important to do this in a way such that concurrent readers can't // temporarily think something is in the heap. (I've actually seen this diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp index 4c6d2bbf877..75497e7c37f 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp @@ -313,7 +313,8 @@ G1CollectorPolicy::G1CollectorPolicy() : void G1CollectorPolicy::initialize_flags() { set_min_alignment(HeapRegion::GrainBytes); size_t card_table_alignment = GenRemSet::max_alignment_constraint(rem_set_name()); - set_max_alignment(MAX2(card_table_alignment, min_alignment())); + size_t page_size = UseLargePages ? os::large_page_size() : os::vm_page_size(); + set_max_alignment(MAX3(card_table_alignment, min_alignment(), page_size)); if (SurvivorRatio < 1) { vm_exit_during_initialization("Invalid survivor ratio specified"); } diff --git a/hotspot/src/share/vm/memory/collectorPolicy.cpp b/hotspot/src/share/vm/memory/collectorPolicy.cpp index cba14a01459..6a1967daeda 100644 --- a/hotspot/src/share/vm/memory/collectorPolicy.cpp +++ b/hotspot/src/share/vm/memory/collectorPolicy.cpp @@ -193,6 +193,8 @@ size_t GenCollectorPolicy::compute_max_alignment() { alignment = lcm(os::large_page_size(), alignment); } + assert(alignment >= min_alignment(), "Must be"); + return alignment; } diff --git a/hotspot/src/share/vm/memory/genCollectedHeap.cpp b/hotspot/src/share/vm/memory/genCollectedHeap.cpp index e0f82c02d86..3a5ab210c83 100644 --- a/hotspot/src/share/vm/memory/genCollectedHeap.cpp +++ b/hotspot/src/share/vm/memory/genCollectedHeap.cpp @@ -95,13 +95,13 @@ jint GenCollectedHeap::initialize() { guarantee(HeapWordSize == wordSize, "HeapWordSize must equal wordSize"); // The heap must be at least as aligned as generations. - size_t alignment = Generation::GenGrain; + size_t gen_alignment = Generation::GenGrain; _gen_specs = gen_policy()->generations(); // Make sure the sizes are all aligned. for (i = 0; i < _n_gens; i++) { - _gen_specs[i]->align(alignment); + _gen_specs[i]->align(gen_alignment); } // Allocate space for the heap. @@ -109,9 +109,11 @@ jint GenCollectedHeap::initialize() { char* heap_address; size_t total_reserved = 0; int n_covered_regions = 0; - ReservedSpace heap_rs(0); + ReservedSpace heap_rs; - heap_address = allocate(alignment, &total_reserved, + size_t heap_alignment = collector_policy()->max_alignment(); + + heap_address = allocate(heap_alignment, &total_reserved, &n_covered_regions, &heap_rs); if (!heap_rs.is_reserved()) { @@ -168,6 +170,8 @@ char* GenCollectedHeap::allocate(size_t alignment, const size_t pageSize = UseLargePages ? os::large_page_size() : os::vm_page_size(); + assert(alignment % pageSize == 0, "Must be"); + for (int i = 0; i < _n_gens; i++) { total_reserved += _gen_specs[i]->max_size(); if (total_reserved < _gen_specs[i]->max_size()) { @@ -175,24 +179,17 @@ char* GenCollectedHeap::allocate(size_t alignment, } n_covered_regions += _gen_specs[i]->n_covered_regions(); } - assert(total_reserved % pageSize == 0, - err_msg("Gen size; total_reserved=" SIZE_FORMAT ", pageSize=" - SIZE_FORMAT, total_reserved, pageSize)); + assert(total_reserved % alignment == 0, + err_msg("Gen size; total_reserved=" SIZE_FORMAT ", alignment=" + SIZE_FORMAT, total_reserved, alignment)); // Needed until the cardtable is fixed to have the right number // of covered regions. n_covered_regions += 2; - if (UseLargePages) { - assert(total_reserved != 0, "total_reserved cannot be 0"); - total_reserved = round_to(total_reserved, os::large_page_size()); - if (total_reserved < os::large_page_size()) { - vm_exit_during_initialization(overflow_msg); - } - } + *_total_reserved = total_reserved; + *_n_covered_regions = n_covered_regions; - *_total_reserved = total_reserved; - *_n_covered_regions = n_covered_regions; *heap_rs = Universe::reserve_heap(total_reserved, alignment); return heap_rs->base(); } diff --git a/hotspot/src/share/vm/memory/metaspace.cpp b/hotspot/src/share/vm/memory/metaspace.cpp index f654a13878c..cd46888c9c2 100644 --- a/hotspot/src/share/vm/memory/metaspace.cpp +++ b/hotspot/src/share/vm/memory/metaspace.cpp @@ -345,7 +345,7 @@ class VirtualSpaceNode : public CHeapObj { }; // byte_size is the size of the associated virtualspace. -VirtualSpaceNode::VirtualSpaceNode(size_t byte_size) : _top(NULL), _next(NULL), _rs(0), _container_count(0) { +VirtualSpaceNode::VirtualSpaceNode(size_t byte_size) : _top(NULL), _next(NULL), _rs(), _container_count(0) { // align up to vm allocation granularity byte_size = align_size_up(byte_size, os::vm_allocation_granularity()); diff --git a/hotspot/src/share/vm/memory/universe.cpp b/hotspot/src/share/vm/memory/universe.cpp index d85d23e015b..143c0c00c45 100644 --- a/hotspot/src/share/vm/memory/universe.cpp +++ b/hotspot/src/share/vm/memory/universe.cpp @@ -681,17 +681,23 @@ static const uint64_t NarrowOopHeapMax = (uint64_t(max_juint) + 1); // 32Gb // OopEncodingHeapMax == NarrowOopHeapMax << LogMinObjAlignmentInBytes; -char* Universe::preferred_heap_base(size_t heap_size, NARROW_OOP_MODE mode) { +char* Universe::preferred_heap_base(size_t heap_size, size_t alignment, NARROW_OOP_MODE mode) { + assert(is_size_aligned((size_t)OopEncodingHeapMax, alignment), "Must be"); + assert(is_size_aligned((size_t)NarrowOopHeapMax, alignment), "Must be"); + assert(is_size_aligned(heap_size, alignment), "Must be"); + + uintx heap_base_min_address_aligned = align_size_up(HeapBaseMinAddress, alignment); + size_t base = 0; #ifdef _LP64 if (UseCompressedOops) { assert(mode == UnscaledNarrowOop || mode == ZeroBasedNarrowOop || mode == HeapBasedNarrowOop, "mode is invalid"); - const size_t total_size = heap_size + HeapBaseMinAddress; + const size_t total_size = heap_size + heap_base_min_address_aligned; // Return specified base for the first request. if (!FLAG_IS_DEFAULT(HeapBaseMinAddress) && (mode == UnscaledNarrowOop)) { - base = HeapBaseMinAddress; + base = heap_base_min_address_aligned; // If the total size is small enough to allow UnscaledNarrowOop then // just use UnscaledNarrowOop. @@ -742,6 +748,8 @@ char* Universe::preferred_heap_base(size_t heap_size, NARROW_OOP_MODE mode) { } } #endif + + assert(is_ptr_aligned((char*)base, alignment), "Must be"); return (char*)base; // also return NULL (don't care) for 32-bit VM } @@ -867,27 +875,33 @@ ReservedSpace Universe::reserve_heap(size_t heap_size, size_t alignment) { size_t total_reserved = align_size_up(heap_size, alignment); assert(!UseCompressedOops || (total_reserved <= (OopEncodingHeapMax - os::vm_page_size())), "heap size is too big for compressed oops"); - char* addr = Universe::preferred_heap_base(total_reserved, Universe::UnscaledNarrowOop); - ReservedHeapSpace total_rs(total_reserved, alignment, UseLargePages, addr); + bool use_large_pages = UseLargePages && is_size_aligned(alignment, os::large_page_size()); + assert(!UseLargePages + || UseParallelOldGC + || use_large_pages, "Wrong alignment to use large pages"); + + char* addr = Universe::preferred_heap_base(total_reserved, alignment, Universe::UnscaledNarrowOop); + + ReservedHeapSpace total_rs(total_reserved, alignment, use_large_pages, addr); if (UseCompressedOops) { if (addr != NULL && !total_rs.is_reserved()) { // Failed to reserve at specified address - the requested memory // region is taken already, for example, by 'java' launcher. // Try again to reserver heap higher. - addr = Universe::preferred_heap_base(total_reserved, Universe::ZeroBasedNarrowOop); + addr = Universe::preferred_heap_base(total_reserved, alignment, Universe::ZeroBasedNarrowOop); ReservedHeapSpace total_rs0(total_reserved, alignment, - UseLargePages, addr); + use_large_pages, addr); if (addr != NULL && !total_rs0.is_reserved()) { // Failed to reserve at specified address again - give up. - addr = Universe::preferred_heap_base(total_reserved, Universe::HeapBasedNarrowOop); + addr = Universe::preferred_heap_base(total_reserved, alignment, Universe::HeapBasedNarrowOop); assert(addr == NULL, ""); ReservedHeapSpace total_rs1(total_reserved, alignment, - UseLargePages, addr); + use_large_pages, addr); total_rs = total_rs1; } else { total_rs = total_rs0; diff --git a/hotspot/src/share/vm/memory/universe.hpp b/hotspot/src/share/vm/memory/universe.hpp index 1ebe5f2b57e..a8b541d03a1 100644 --- a/hotspot/src/share/vm/memory/universe.hpp +++ b/hotspot/src/share/vm/memory/universe.hpp @@ -346,7 +346,7 @@ class Universe: AllStatic { }; static NARROW_OOP_MODE narrow_oop_mode(); static const char* narrow_oop_mode_to_string(NARROW_OOP_MODE mode); - static char* preferred_heap_base(size_t heap_size, NARROW_OOP_MODE mode); + static char* preferred_heap_base(size_t heap_size, size_t alignment, NARROW_OOP_MODE mode); static char* preferred_metaspace_base(size_t heap_size, NARROW_OOP_MODE mode); static address narrow_oop_base() { return _narrow_oop._base; } static bool is_narrow_oop_base(void* addr) { return (narrow_oop_base() == (address)addr); } diff --git a/hotspot/src/share/vm/prims/jni.cpp b/hotspot/src/share/vm/prims/jni.cpp index 188cf4a6e60..acf79f53525 100644 --- a/hotspot/src/share/vm/prims/jni.cpp +++ b/hotspot/src/share/vm/prims/jni.cpp @@ -5027,9 +5027,15 @@ _JNI_IMPORT_OR_EXPORT_ jint JNICALL JNI_GetDefaultJavaVMInitArgs(void *args_) { tty->print_cr("Running test: " #unit_test_function_call); \ unit_test_function_call +// Forward declaration +void TestReservedSpace_test(); +void TestReserveMemorySpecial_test(); + void execute_internal_vm_tests() { if (ExecuteInternalVMTests) { tty->print_cr("Running internal VM tests"); + run_unit_test(TestReservedSpace_test()); + run_unit_test(TestReserveMemorySpecial_test()); run_unit_test(GlobalDefinitions::test_globals()); run_unit_test(GCTimerAllTest::all()); run_unit_test(arrayOopDesc::test_max_array_length()); diff --git a/hotspot/src/share/vm/runtime/globals.hpp b/hotspot/src/share/vm/runtime/globals.hpp index 9b67389af47..f54939096e9 100644 --- a/hotspot/src/share/vm/runtime/globals.hpp +++ b/hotspot/src/share/vm/runtime/globals.hpp @@ -1933,6 +1933,9 @@ class CommandLineFlags { notproduct(bool, ExecuteInternalVMTests, false, \ "Enable execution of internal VM tests.") \ \ + notproduct(bool, VerboseInternalVMTests, false, \ + "Turn on logging for internal VM tests.") \ + \ product_pd(bool, UseTLAB, "Use thread-local object allocation") \ \ product_pd(bool, ResizeTLAB, \ diff --git a/hotspot/src/share/vm/runtime/os.hpp b/hotspot/src/share/vm/runtime/os.hpp index 03497e1973b..38efad386f1 100644 --- a/hotspot/src/share/vm/runtime/os.hpp +++ b/hotspot/src/share/vm/runtime/os.hpp @@ -328,8 +328,8 @@ class os: AllStatic { static char* non_memory_address_word(); // reserve, commit and pin the entire memory region - static char* reserve_memory_special(size_t size, char* addr = NULL, - bool executable = false); + static char* reserve_memory_special(size_t size, size_t alignment, + char* addr, bool executable); static bool release_memory_special(char* addr, size_t bytes); static void large_page_init(); static size_t large_page_size(); diff --git a/hotspot/src/share/vm/runtime/virtualspace.cpp b/hotspot/src/share/vm/runtime/virtualspace.cpp index 9096a034cef..9e01fe0292f 100644 --- a/hotspot/src/share/vm/runtime/virtualspace.cpp +++ b/hotspot/src/share/vm/runtime/virtualspace.cpp @@ -42,8 +42,19 @@ // ReservedSpace + +// Dummy constructor +ReservedSpace::ReservedSpace() : _base(NULL), _size(0), _noaccess_prefix(0), + _alignment(0), _special(false), _executable(false) { +} + ReservedSpace::ReservedSpace(size_t size) { - initialize(size, 0, false, NULL, 0, false); + size_t page_size = os::page_size_for_region(size, size, 1); + bool large_pages = page_size != (size_t)os::vm_page_size(); + // Don't force the alignment to be large page aligned, + // since that will waste memory. + size_t alignment = os::vm_allocation_granularity(); + initialize(size, alignment, large_pages, NULL, 0, false); } ReservedSpace::ReservedSpace(size_t size, size_t alignment, @@ -129,16 +140,18 @@ void ReservedSpace::initialize(size_t size, size_t alignment, bool large, if (special) { - base = os::reserve_memory_special(size, requested_address, executable); + base = os::reserve_memory_special(size, alignment, requested_address, executable); if (base != NULL) { if (failed_to_reserve_as_requested(base, requested_address, size, true)) { // OS ignored requested address. Try different address. return; } - // Check alignment constraints + // Check alignment constraints. assert((uintptr_t) base % alignment == 0, - "Large pages returned a non-aligned address"); + err_msg("Large pages returned a non-aligned address, base: " + PTR_FORMAT " alignment: " PTR_FORMAT, + base, (void*)(uintptr_t)alignment)); _special = true; } else { // failed; try to reserve regular memory below @@ -715,4 +728,188 @@ void VirtualSpace::print() { tty->print_cr(" - [low_b, high_b]: [" INTPTR_FORMAT ", " INTPTR_FORMAT "]", low_boundary(), high_boundary()); } + +/////////////// Unit tests /////////////// + +#ifndef PRODUCT + +#define test_log(...) \ + do {\ + if (VerboseInternalVMTests) { \ + tty->print_cr(__VA_ARGS__); \ + tty->flush(); \ + }\ + } while (false) + +class TestReservedSpace : AllStatic { + public: + static void small_page_write(void* addr, size_t size) { + size_t page_size = os::vm_page_size(); + + char* end = (char*)addr + size; + for (char* p = (char*)addr; p < end; p += page_size) { + *p = 1; + } + } + + static void release_memory_for_test(ReservedSpace rs) { + if (rs.special()) { + guarantee(os::release_memory_special(rs.base(), rs.size()), "Shouldn't fail"); + } else { + guarantee(os::release_memory(rs.base(), rs.size()), "Shouldn't fail"); + } + } + + static void test_reserved_space1(size_t size, size_t alignment) { + test_log("test_reserved_space1(%p)", (void*) (uintptr_t) size); + + assert(is_size_aligned(size, alignment), "Incorrect input parameters"); + + ReservedSpace rs(size, // size + alignment, // alignment + UseLargePages, // large + NULL, // requested_address + 0); // noacces_prefix + + test_log(" rs.special() == %d", rs.special()); + + assert(rs.base() != NULL, "Must be"); + assert(rs.size() == size, "Must be"); + + assert(is_ptr_aligned(rs.base(), alignment), "aligned sizes should always give aligned addresses"); + assert(is_size_aligned(rs.size(), alignment), "aligned sizes should always give aligned addresses"); + + if (rs.special()) { + small_page_write(rs.base(), size); + } + + release_memory_for_test(rs); + } + + static void test_reserved_space2(size_t size) { + test_log("test_reserved_space2(%p)", (void*)(uintptr_t)size); + + assert(is_size_aligned(size, os::vm_allocation_granularity()), "Must be at least AG aligned"); + + ReservedSpace rs(size); + + test_log(" rs.special() == %d", rs.special()); + + assert(rs.base() != NULL, "Must be"); + assert(rs.size() == size, "Must be"); + + if (rs.special()) { + small_page_write(rs.base(), size); + } + + release_memory_for_test(rs); + } + + static void test_reserved_space3(size_t size, size_t alignment, bool maybe_large) { + test_log("test_reserved_space3(%p, %p, %d)", + (void*)(uintptr_t)size, (void*)(uintptr_t)alignment, maybe_large); + + assert(is_size_aligned(size, os::vm_allocation_granularity()), "Must be at least AG aligned"); + assert(is_size_aligned(size, alignment), "Must be at least aligned against alignment"); + + bool large = maybe_large && UseLargePages && size >= os::large_page_size(); + + ReservedSpace rs(size, alignment, large, false); + + test_log(" rs.special() == %d", rs.special()); + + assert(rs.base() != NULL, "Must be"); + assert(rs.size() == size, "Must be"); + + if (rs.special()) { + small_page_write(rs.base(), size); + } + + release_memory_for_test(rs); + } + + + static void test_reserved_space1() { + size_t size = 2 * 1024 * 1024; + size_t ag = os::vm_allocation_granularity(); + + test_reserved_space1(size, ag); + test_reserved_space1(size * 2, ag); + test_reserved_space1(size * 10, ag); + } + + static void test_reserved_space2() { + size_t size = 2 * 1024 * 1024; + size_t ag = os::vm_allocation_granularity(); + + test_reserved_space2(size * 1); + test_reserved_space2(size * 2); + test_reserved_space2(size * 10); + test_reserved_space2(ag); + test_reserved_space2(size - ag); + test_reserved_space2(size); + test_reserved_space2(size + ag); + test_reserved_space2(size * 2); + test_reserved_space2(size * 2 - ag); + test_reserved_space2(size * 2 + ag); + test_reserved_space2(size * 3); + test_reserved_space2(size * 3 - ag); + test_reserved_space2(size * 3 + ag); + test_reserved_space2(size * 10); + test_reserved_space2(size * 10 + size / 2); + } + + static void test_reserved_space3() { + size_t ag = os::vm_allocation_granularity(); + + test_reserved_space3(ag, ag , false); + test_reserved_space3(ag * 2, ag , false); + test_reserved_space3(ag * 3, ag , false); + test_reserved_space3(ag * 2, ag * 2, false); + test_reserved_space3(ag * 4, ag * 2, false); + test_reserved_space3(ag * 8, ag * 2, false); + test_reserved_space3(ag * 4, ag * 4, false); + test_reserved_space3(ag * 8, ag * 4, false); + test_reserved_space3(ag * 16, ag * 4, false); + + if (UseLargePages) { + size_t lp = os::large_page_size(); + + // Without large pages + test_reserved_space3(lp, ag * 4, false); + test_reserved_space3(lp * 2, ag * 4, false); + test_reserved_space3(lp * 4, ag * 4, false); + test_reserved_space3(lp, lp , false); + test_reserved_space3(lp * 2, lp , false); + test_reserved_space3(lp * 3, lp , false); + test_reserved_space3(lp * 2, lp * 2, false); + test_reserved_space3(lp * 4, lp * 2, false); + test_reserved_space3(lp * 8, lp * 2, false); + + // With large pages + test_reserved_space3(lp, ag * 4 , true); + test_reserved_space3(lp * 2, ag * 4, true); + test_reserved_space3(lp * 4, ag * 4, true); + test_reserved_space3(lp, lp , true); + test_reserved_space3(lp * 2, lp , true); + test_reserved_space3(lp * 3, lp , true); + test_reserved_space3(lp * 2, lp * 2, true); + test_reserved_space3(lp * 4, lp * 2, true); + test_reserved_space3(lp * 8, lp * 2, true); + } + } + + static void test_reserved_space() { + test_reserved_space1(); + test_reserved_space2(); + test_reserved_space3(); + } +}; + +void TestReservedSpace_test() { + TestReservedSpace::test_reserved_space(); +} + +#endif // PRODUCT + #endif diff --git a/hotspot/src/share/vm/runtime/virtualspace.hpp b/hotspot/src/share/vm/runtime/virtualspace.hpp index 0a959e900a0..bca9b6c14fc 100644 --- a/hotspot/src/share/vm/runtime/virtualspace.hpp +++ b/hotspot/src/share/vm/runtime/virtualspace.hpp @@ -53,6 +53,7 @@ class ReservedSpace VALUE_OBJ_CLASS_SPEC { public: // Constructor + ReservedSpace(); ReservedSpace(size_t size); ReservedSpace(size_t size, size_t alignment, bool large, char* requested_address = NULL, diff --git a/hotspot/src/share/vm/services/memTracker.hpp b/hotspot/src/share/vm/services/memTracker.hpp index 364c6b4f235..1072e5d6a3d 100644 --- a/hotspot/src/share/vm/services/memTracker.hpp +++ b/hotspot/src/share/vm/services/memTracker.hpp @@ -87,6 +87,8 @@ class MemTracker : AllStatic { MEMFLAGS flags, address pc = 0, Thread* thread = NULL) { } static inline void record_virtual_memory_commit(address addr, size_t size, address pc = 0, Thread* thread = NULL) { } + static inline void record_virtual_memory_release(address addr, size_t size, + Thread* thread = NULL) { } static inline void record_virtual_memory_type(address base, MEMFLAGS flags, Thread* thread = NULL) { } static inline Tracker get_realloc_tracker() { return _tkr; } @@ -372,6 +374,13 @@ class MemTracker : AllStatic { tkr.record(addr, size, flags, pc); } + static inline void record_virtual_memory_release(address addr, size_t size, + Thread* thread = NULL) { + if (is_on()) { + Tracker tkr(Tracker::Release, thread); + tkr.record(addr, size); + } + } // record memory type on virtual memory base address static inline void record_virtual_memory_type(address base, MEMFLAGS flags, diff --git a/hotspot/src/share/vm/utilities/globalDefinitions.hpp b/hotspot/src/share/vm/utilities/globalDefinitions.hpp index 3b4be625a35..bbee85c8b23 100644 --- a/hotspot/src/share/vm/utilities/globalDefinitions.hpp +++ b/hotspot/src/share/vm/utilities/globalDefinitions.hpp @@ -402,6 +402,14 @@ const jlong CompressedKlassPointersBase = NOT_LP64(0) LP64_ONLY(CONST64(0x800000 #define align_size_up_(size, alignment) (((size) + ((alignment) - 1)) & ~((alignment) - 1)) +inline bool is_size_aligned(size_t size, size_t alignment) { + return align_size_up_(size, alignment) == size; +} + +inline bool is_ptr_aligned(void* ptr, size_t alignment) { + return align_size_up_((intptr_t)ptr, (intptr_t)alignment) == (intptr_t)ptr; +} + inline intptr_t align_size_up(intptr_t size, intptr_t alignment) { return align_size_up_(size, alignment); } @@ -414,6 +422,14 @@ inline intptr_t align_size_down(intptr_t size, intptr_t alignment) { #define is_size_aligned_(size, alignment) ((size) == (align_size_up_(size, alignment))) +inline void* align_ptr_up(void* ptr, size_t alignment) { + return (void*)align_size_up((intptr_t)ptr, (intptr_t)alignment); +} + +inline void* align_ptr_down(void* ptr, size_t alignment) { + return (void*)align_size_down((intptr_t)ptr, (intptr_t)alignment); +} + // Align objects by rounding up their size, in HeapWord units. #define align_object_size_(size) align_size_up_(size, MinObjAlignment) From 92e079eae1ff1b7b478ea9aee7382a8c460cec80 Mon Sep 17 00:00:00 2001 From: Alejandro Murillo Date: Fri, 16 Aug 2013 04:24:07 -0700 Subject: [PATCH 064/218] 8023152: new hotspot build - hs25-b47 Reviewed-by: jcoomes --- hotspot/make/hotspot_version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hotspot/make/hotspot_version b/hotspot/make/hotspot_version index 2ec3b0aaf52..c35e01558a7 100644 --- a/hotspot/make/hotspot_version +++ b/hotspot/make/hotspot_version @@ -35,7 +35,7 @@ HOTSPOT_VM_COPYRIGHT=Copyright 2013 HS_MAJOR_VER=25 HS_MINOR_VER=0 -HS_BUILD_NUMBER=46 +HS_BUILD_NUMBER=47 JDK_MAJOR_VER=1 JDK_MINOR_VER=8 From c5193485ade5e8dec4fb50b891d7cb437ab77552 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hannes=20Walln=C3=B6fer?= Date: Fri, 16 Aug 2013 13:42:44 +0200 Subject: [PATCH 065/218] 8019985: Date.parse("2000-01-01T00:00:00.Z") should return NaN Reviewed-by: sundar, jlaskey --- .../nashorn/internal/parser/DateParser.java | 31 ++++++++---- nashorn/test/script/basic/JDK-8019985.js | 50 +++++++++++++++++++ 2 files changed, 71 insertions(+), 10 deletions(-) create mode 100644 nashorn/test/script/basic/JDK-8019985.js diff --git a/nashorn/src/jdk/nashorn/internal/parser/DateParser.java b/nashorn/src/jdk/nashorn/internal/parser/DateParser.java index 34832bb1b44..b5f7a2a223f 100644 --- a/nashorn/src/jdk/nashorn/internal/parser/DateParser.java +++ b/nashorn/src/jdk/nashorn/internal/parser/DateParser.java @@ -141,7 +141,7 @@ public class DateParser { * Try parsing the date string according to the rules laid out in ES5 15.9.1.15. * The date string must conform to the following format: * - *
  [('-'|'+')yy]yyyy[-MM[-dd]][hh:mm[:ss[.sss]][Z|(+|-)hh:mm]] 
+ *
  [('-'|'+')yy]yyyy[-MM[-dd]][Thh:mm[:ss[.sss]][Z|(+|-)hh:mm]] 
* *

If the string does not contain a time zone offset, the TIMEZONE field * is set to 0 (GMT).

@@ -249,7 +249,7 @@ public class DateParser { switch (token) { case NUMBER: - if (skip(':')) { + if (skipDelimiter(':')) { // A number followed by ':' is parsed as time if (!setTimeField(numValue)) { return false; @@ -260,14 +260,14 @@ public class DateParser { if (token != Token.NUMBER || !setTimeField(numValue)) { return false; } - } while (skip(isSet(SECOND) ? '.' : ':')); + } while (skipDelimiter(isSet(SECOND) ? '.' : ':')); } else { // Parse as date token if (!setDateField(numValue)) { return false; } - skip('-'); + skipDelimiter('-'); } break; @@ -297,7 +297,7 @@ public class DateParser { break; } if (nameValue.type != Name.TIMEZONE_ID) { - skip('-'); + skipDelimiter('-'); } break; @@ -359,7 +359,18 @@ public class DateParser { return pos < length ? string.charAt(pos) : -1; } - private boolean skip(final char c) { + // Skip delimiter if followed by a number. Used for ISO 8601 formatted dates + private boolean skipNumberDelimiter(final char c) { + if (pos < length - 1 && string.charAt(pos) == c + && Character.getType(string.charAt(pos + 1)) == DECIMAL_DIGIT_NUMBER) { + token = null; + pos++; + return true; + } + return false; + } + + private boolean skipDelimiter(final char c) { if (pos < length && string.charAt(pos) == c) { token = null; pos++; @@ -452,14 +463,14 @@ public class DateParser { switch (currentField) { case YEAR: case MONTH: - return skip('-') || peek() == 'T' || peek() == -1; + return skipNumberDelimiter('-') || peek() == 'T' || peek() == -1; case DAY: return peek() == 'T' || peek() == -1; case HOUR: case MINUTE: - return skip(':') || endOfTime(); + return skipNumberDelimiter(':') || endOfTime(); case SECOND: - return skip('.') || endOfTime(); + return skipNumberDelimiter('.') || endOfTime(); default: return true; } @@ -515,7 +526,7 @@ public class DateParser { private int readTimeZoneOffset() { final int sign = string.charAt(pos - 1) == '+' ? 1 : -1; int offset = readNumber(2); - skip(':'); + skipDelimiter(':'); offset = offset * 60 + readNumber(2); return sign * offset; } diff --git a/nashorn/test/script/basic/JDK-8019985.js b/nashorn/test/script/basic/JDK-8019985.js new file mode 100644 index 00000000000..adc7fbf6f4f --- /dev/null +++ b/nashorn/test/script/basic/JDK-8019985.js @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * JDK-8019985: Date.parse("2000-01-01T00:00:00.Z") should return NaN + * + * @test + * @run + */ + +function testFail(str) { + if (!isNaN(Date.parse(str))) { + throw new Error("Parsed invalid date string: " + str); + } +} + +function testOk(str) { + if (isNaN(Date.parse(str))) { + throw new Error("Failed to parse valid date string: " + str); + } +} + +testFail("2000-01-01T00:00:00.Z"); +testFail("2000-01-01T00:00:Z"); +testFail("2000-01-01T00:Z"); +testFail("2000-01-01T00Z"); +testOk("2000-01-01T00:00:00.000Z"); +testOk("2000-01-01T00:00:00.0Z"); +testOk("2000-01-01T00:00:00Z"); +testOk("2000-01-01T00:00Z"); From d0aa753d993b3d87e5ae673645a5dbce9a0021fe Mon Sep 17 00:00:00 2001 From: Jon Masamitsu Date: Fri, 16 Aug 2013 06:12:46 -0700 Subject: [PATCH 066/218] 8022817: CMS should not shrink if compaction was not done Reviewed-by: ysr, mgerdin --- .../concurrentMarkSweepGeneration.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp index fe53388a05f..04b550c718b 100644 --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp @@ -3460,7 +3460,9 @@ void ConcurrentMarkSweepGeneration::shrink_by(size_t bytes) { void ConcurrentMarkSweepGeneration::shrink(size_t bytes) { assert_locked_or_safepoint(Heap_lock); size_t size = ReservedSpace::page_align_size_down(bytes); - if (size > 0) { + // Only shrink if a compaction was done so that all the free space + // in the generation is in a contiguous block at the end. + if (size > 0 && did_compact()) { shrink_by(size); } } @@ -8696,9 +8698,10 @@ void SweepClosure::lookahead_and_flush(FreeChunk* fc, size_t chunk_size) { assert(inFreeRange(), "Should only be called if currently in a free range."); HeapWord* const eob = ((HeapWord*)fc) + chunk_size; assert(_sp->used_region().contains(eob - 1), - err_msg("eob = " PTR_FORMAT " out of bounds wrt _sp = [" PTR_FORMAT "," PTR_FORMAT ")" + err_msg("eob = " PTR_FORMAT " eob-1 = " PTR_FORMAT " _limit = " PTR_FORMAT + " out of bounds wrt _sp = [" PTR_FORMAT "," PTR_FORMAT ")" " when examining fc = " PTR_FORMAT "(" SIZE_FORMAT ")", - _limit, _sp->bottom(), _sp->end(), fc, chunk_size)); + eob, eob-1, _limit, _sp->bottom(), _sp->end(), fc, chunk_size)); if (eob >= _limit) { assert(eob == _limit || fc->is_free(), "Only a free chunk should allow us to cross over the limit"); if (CMSTraceSweeper) { From 99a38df3abc6cff2934f716a916cc2402f1f3fe6 Mon Sep 17 00:00:00 2001 From: Erik Joelsson Date: Fri, 16 Aug 2013 16:00:12 +0200 Subject: [PATCH 067/218] 8023146: Sjavac test failes in langtools nightly Reviewed-by: mcimadamore, jfranck --- langtools/test/tools/sjavac/SJavac.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/langtools/test/tools/sjavac/SJavac.java b/langtools/test/tools/sjavac/SJavac.java index 6f55e68604e..6580ab40984 100644 --- a/langtools/test/tools/sjavac/SJavac.java +++ b/langtools/test/tools/sjavac/SJavac.java @@ -21,11 +21,6 @@ * questions. */ -/* - * @test - * @summary Tests sjavac basic functionality - */ - import java.util.*; import java.io.*; import java.net.*; From 8a03379c45d1220c729f8174aa1158b1f58f510d Mon Sep 17 00:00:00 2001 From: Aleksei Efimov Date: Fri, 16 Aug 2013 18:40:43 +0400 Subject: [PATCH 068/218] 8021820: Number of opened files used in select() is limited to 1024 [macosx] Reviewed-by: alanb, chegar, tbell, smarks --- common/autoconf/generated-configure.sh | 4 ++-- common/autoconf/toolchain.m4 | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/common/autoconf/generated-configure.sh b/common/autoconf/generated-configure.sh index 1f084da68c9..05fefa1b84b 100644 --- a/common/autoconf/generated-configure.sh +++ b/common/autoconf/generated-configure.sh @@ -3794,7 +3794,7 @@ fi #CUSTOM_AUTOCONF_INCLUDE # Do not change or remove the following line, it is needed for consistency checks: -DATE_WHEN_GENERATED=1373384053 +DATE_WHEN_GENERATED=1375350569 ############################################################################### # @@ -29582,7 +29582,7 @@ if test "x$OPENJDK_TARGET_OS" = xsolaris; then CCXXFLAGS_JDK="$CCXXFLAGS_JDK -DSOLARIS" fi if test "x$OPENJDK_TARGET_OS" = xmacosx; then - CCXXFLAGS_JDK="$CCXXFLAGS_JDK -DMACOSX -D_ALLBSD_SOURCE" + CCXXFLAGS_JDK="$CCXXFLAGS_JDK -DMACOSX -D_ALLBSD_SOURCE -D_DARWIN_UNLIMITED_SELECT" # Setting these parameters makes it an error to link to macosx APIs that are # newer than the given OS version and makes the linked binaries compatible even # if built on a newer version of the OS. diff --git a/common/autoconf/toolchain.m4 b/common/autoconf/toolchain.m4 index b2b367f63c2..efaecc18960 100644 --- a/common/autoconf/toolchain.m4 +++ b/common/autoconf/toolchain.m4 @@ -905,7 +905,7 @@ if test "x$OPENJDK_TARGET_OS" = xsolaris; then CCXXFLAGS_JDK="$CCXXFLAGS_JDK -DSOLARIS" fi if test "x$OPENJDK_TARGET_OS" = xmacosx; then - CCXXFLAGS_JDK="$CCXXFLAGS_JDK -DMACOSX -D_ALLBSD_SOURCE" + CCXXFLAGS_JDK="$CCXXFLAGS_JDK -DMACOSX -D_ALLBSD_SOURCE -D_DARWIN_UNLIMITED_SELECT" # Setting these parameters makes it an error to link to macosx APIs that are # newer than the given OS version and makes the linked binaries compatible even # if built on a newer version of the OS. From 9de0661d63d229f73b693f44a4619cc110e9354e Mon Sep 17 00:00:00 2001 From: Marcus Lagergren Date: Fri, 16 Aug 2013 18:51:53 +0200 Subject: [PATCH 069/218] 8023017: SUB missing for widest op == number for BinaryNode Reviewed-by: sundar, jlaskey --- .../codegen/ObjectClassGenerator.java | 3 ++- .../internal/codegen/ObjectCreator.java | 8 ++++--- .../jdk/nashorn/internal/ir/BinaryNode.java | 1 + .../nashorn/internal/ir/BreakableNode.java | 8 +++++++ .../jdk/nashorn/internal/ir/IdentNode.java | 4 ++-- .../internal/ir/LexicalContextNode.java | 8 ++++++- .../internal/objects/NativeArguments.java | 3 +-- .../nashorn/internal/objects/NativeArray.java | 4 ++-- .../jdk/nashorn/internal/parser/Parser.java | 6 ++--- .../jdk/nashorn/internal/runtime/Context.java | 2 ++ .../RecompilableScriptFunctionData.java | 2 +- .../internal/runtime/ScriptFunction.java | 23 +++++++++---------- .../internal/runtime/ScriptObject.java | 17 +++++++++++--- .../runtime/arrays/ArrayLikeIterator.java | 4 ++-- .../runtime/arrays/LongArrayData.java | 3 +-- .../runtime/arrays/SparseArrayData.java | 2 +- .../runtime/linker/BoundDynamicMethod.java | 2 +- .../linker/BoundDynamicMethodLinker.java | 2 +- .../linker/JavaAdapterClassLoader.java | 3 +-- 19 files changed, 66 insertions(+), 39 deletions(-) diff --git a/nashorn/src/jdk/nashorn/internal/codegen/ObjectClassGenerator.java b/nashorn/src/jdk/nashorn/internal/codegen/ObjectClassGenerator.java index fa3d19e5d05..21cc3c5e454 100644 --- a/nashorn/src/jdk/nashorn/internal/codegen/ObjectClassGenerator.java +++ b/nashorn/src/jdk/nashorn/internal/codegen/ObjectClassGenerator.java @@ -317,7 +317,8 @@ public final class ObjectClassGenerator { final String className = getClassName(fieldCount); final String superName = className(ScriptObject.class); final ClassEmitter classEmitter = newClassEmitter(className, superName); - final List initFields = addFields(classEmitter, fieldCount); + + addFields(classEmitter, fieldCount); final MethodEmitter init = newInitMethod(classEmitter); init.returnVoid(); diff --git a/nashorn/src/jdk/nashorn/internal/codegen/ObjectCreator.java b/nashorn/src/jdk/nashorn/internal/codegen/ObjectCreator.java index 2a8ebba71b4..d129d591f97 100644 --- a/nashorn/src/jdk/nashorn/internal/codegen/ObjectCreator.java +++ b/nashorn/src/jdk/nashorn/internal/codegen/ObjectCreator.java @@ -45,9 +45,11 @@ public abstract class ObjectCreator { /** Code generator */ protected final CodeGenerator codegen; - private final boolean isScope; - private final boolean hasArguments; - protected PropertyMap propertyMap; + /** Property map */ + protected PropertyMap propertyMap; + + private final boolean isScope; + private final boolean hasArguments; /** * Constructor diff --git a/nashorn/src/jdk/nashorn/internal/ir/BinaryNode.java b/nashorn/src/jdk/nashorn/internal/ir/BinaryNode.java index 1576fb9316e..169772d7169 100644 --- a/nashorn/src/jdk/nashorn/internal/ir/BinaryNode.java +++ b/nashorn/src/jdk/nashorn/internal/ir/BinaryNode.java @@ -99,6 +99,7 @@ public final class BinaryNode extends Expression implements Assignment * - *
{@code
+     * 
      *   try {
      *     return 2;
      *   } finally {
      *     return 3;
      *   }
-     * }
+ * } * * @return true if can have callsite type */ diff --git a/nashorn/src/jdk/nashorn/internal/ir/LexicalContextNode.java b/nashorn/src/jdk/nashorn/internal/ir/LexicalContextNode.java index bb6a681df8a..b53d9f6b1a2 100644 --- a/nashorn/src/jdk/nashorn/internal/ir/LexicalContextNode.java +++ b/nashorn/src/jdk/nashorn/internal/ir/LexicalContextNode.java @@ -44,8 +44,14 @@ public interface LexicalContextNode { Node accept(final LexicalContext lc, final NodeVisitor visitor); // Would be a default method on Java 8 + /** + * Helper class for accept for items of this lexical context, delegates to the + * subclass accept and makes sure that the node is on the context before accepting + * and gets popped after accepting (and that the stack is consistent in that the + * node has been replaced with the possible new node resulting in visitation) + */ static class Acceptor { - static Node accept(LexicalContextNode node, final NodeVisitor visitor) { + static Node accept(final LexicalContextNode node, final NodeVisitor visitor) { final LexicalContext lc = visitor.getLexicalContext(); lc.push(node); final LexicalContextNode newNode = (LexicalContextNode)node.accept(lc, visitor); diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeArguments.java b/nashorn/src/jdk/nashorn/internal/objects/NativeArguments.java index 55c79da94d0..3a853eff59b 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeArguments.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeArguments.java @@ -266,9 +266,8 @@ public final class NativeArguments extends ScriptObject { final ScriptObject proto = global.getObjectPrototype(); if (isStrict) { return new NativeStrictArguments(arguments, numParams, proto, global.getStrictArgumentsMap()); - } else { - return new NativeArguments(arguments, callee, numParams, proto, global.getArgumentsMap()); } + return new NativeArguments(arguments, callee, numParams, proto, global.getArgumentsMap()); } /** diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeArray.java b/nashorn/src/jdk/nashorn/internal/objects/NativeArray.java index e03cd8dde85..34691194eab 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeArray.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeArray.java @@ -638,9 +638,9 @@ public final class NativeArray extends ScriptObject { if (isScriptArray || obj instanceof Iterable || (obj != null && obj.getClass().isArray())) { final Iterator iter = arrayLikeIterator(obj, true); if (iter.hasNext()) { - for(int i = 0; iter.hasNext(); ++i) { + for (int i = 0; iter.hasNext(); ++i) { final Object value = iter.next(); - if(value == ScriptRuntime.UNDEFINED && isScriptObject && !((ScriptObject)obj).has(i)) { + if (value == ScriptRuntime.UNDEFINED && isScriptObject && !((ScriptObject)obj).has(i)) { // TODO: eventually rewrite arrayLikeIterator to use a three-state enum for handling // UNDEFINED instead of an "includeUndefined" boolean with states SKIP, INCLUDE, // RETURN_EMPTY. Until then, this is how we'll make sure that empty elements don't make it diff --git a/nashorn/src/jdk/nashorn/internal/parser/Parser.java b/nashorn/src/jdk/nashorn/internal/parser/Parser.java index fd97adde551..ab008900f50 100644 --- a/nashorn/src/jdk/nashorn/internal/parser/Parser.java +++ b/nashorn/src/jdk/nashorn/internal/parser/Parser.java @@ -160,10 +160,10 @@ public class Parser extends AbstractParser { if (this.scripting) { this.lineInfoReceiver = new Lexer.LineInfoReceiver() { @Override - public void lineInfo(final int line, final int linePosition) { + public void lineInfo(final int receiverLine, final int receiverLinePosition) { // update the parser maintained line information - Parser.this.line = line; - Parser.this.linePosition = linePosition; + Parser.this.line = receiverLine; + Parser.this.linePosition = receiverLinePosition; } }; } else { diff --git a/nashorn/src/jdk/nashorn/internal/runtime/Context.java b/nashorn/src/jdk/nashorn/internal/runtime/Context.java index 8ff85b93be3..8834592a0b8 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/Context.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/Context.java @@ -48,6 +48,7 @@ import java.security.Permissions; import java.security.PrivilegedAction; import java.security.ProtectionDomain; import java.util.Map; + import jdk.internal.org.objectweb.asm.ClassReader; import jdk.internal.org.objectweb.asm.util.CheckClassAdapter; import jdk.nashorn.api.scripting.ScriptObjectMirror; @@ -888,6 +889,7 @@ public final class Context { return script; } + @SuppressWarnings("static-method") private ScriptLoader createNewLoader() { return AccessController.doPrivileged( new PrivilegedAction() { diff --git a/nashorn/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java b/nashorn/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java index 859a688c1ba..a64479a5987 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java @@ -47,7 +47,7 @@ import jdk.nashorn.internal.parser.TokenType; * This is a subclass that represents a script function that may be regenerated, * for example with specialization based on call site types, or lazily generated. * The common denominator is that it can get new invokers during its lifespan, - * unlike {@link FinalScriptFunctionData} + * unlike {@code FinalScriptFunctionData} */ public final class RecompilableScriptFunctionData extends ScriptFunctionData { diff --git a/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunction.java b/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunction.java index 564f1946810..14aab7560e6 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunction.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunction.java @@ -553,19 +553,18 @@ public abstract class ScriptFunction extends ScriptObject { private static MethodHandle bindToNameIfNeeded(final MethodHandle methodHandle, final String bindName) { if (bindName == null) { return methodHandle; - } else { - // if it is vararg method, we need to extend argument array with - // a new zeroth element that is set to bindName value. - final MethodType methodType = methodHandle.type(); - final int parameterCount = methodType.parameterCount(); - final boolean isVarArg = parameterCount > 0 && methodType.parameterType(parameterCount - 1).isArray(); - - if (isVarArg) { - return MH.filterArguments(methodHandle, 1, MH.insertArguments(ADD_ZEROTH_ELEMENT, 1, bindName)); - } else { - return MH.insertArguments(methodHandle, 1, bindName); - } } + + // if it is vararg method, we need to extend argument array with + // a new zeroth element that is set to bindName value. + final MethodType methodType = methodHandle.type(); + final int parameterCount = methodType.parameterCount(); + final boolean isVarArg = parameterCount > 0 && methodType.parameterType(parameterCount - 1).isArray(); + + if (isVarArg) { + return MH.filterArguments(methodHandle, 1, MH.insertArguments(ADD_ZEROTH_ELEMENT, 1, bindName)); + } + return MH.insertArguments(methodHandle, 1, bindName); } /** diff --git a/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java b/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java index f26e30f00e8..1087005b992 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java @@ -2012,9 +2012,10 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr final boolean scopeAccess = isScope() && NashornCallSiteDescriptor.isScope(desc); if (find != null) { - final Object value = getObjectValue(find); - ScriptFunction func = null; - MethodHandle methodHandle = null; + final Object value = getObjectValue(find); + ScriptFunction func = null; + MethodHandle methodHandle = null; + if (value instanceof ScriptFunction) { func = (ScriptFunction)value; methodHandle = getCallMethodHandle(func, desc.getMethodType(), name); @@ -3219,6 +3220,11 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr return property; } + /** + * Write a value to a spill slot + * @param slot the slot index + * @param value the value + */ protected final void setSpill(final int slot, final Object value) { if (spill == null) { // create new spill. @@ -3233,6 +3239,11 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr spill[slot] = value; } + /** + * Get a value from a spill slot + * @param slot the slot index + * @return the value in the spill slot with the given index + */ protected Object getSpill(final int slot) { return spill != null && slot < spill.length ? spill[slot] : null; } diff --git a/nashorn/src/jdk/nashorn/internal/runtime/arrays/ArrayLikeIterator.java b/nashorn/src/jdk/nashorn/internal/runtime/arrays/ArrayLikeIterator.java index ab16d2202dc..044b21d5879 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/arrays/ArrayLikeIterator.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/arrays/ArrayLikeIterator.java @@ -132,7 +132,7 @@ abstract public class ArrayLikeIterator implements Iterator { } if (obj instanceof List) { - return new JavaListIterator((List)obj, includeUndefined); + return new JavaListIterator((List)obj, includeUndefined); } if (obj != null && obj.getClass().isArray()) { @@ -165,7 +165,7 @@ abstract public class ArrayLikeIterator implements Iterator { } if (obj instanceof List) { - return new ReverseJavaListIterator((List)obj, includeUndefined); + return new ReverseJavaListIterator((List)obj, includeUndefined); } if (obj != null && obj.getClass().isArray()) { diff --git a/nashorn/src/jdk/nashorn/internal/runtime/arrays/LongArrayData.java b/nashorn/src/jdk/nashorn/internal/runtime/arrays/LongArrayData.java index a72ef4a029a..59a63155a72 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/arrays/LongArrayData.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/arrays/LongArrayData.java @@ -98,9 +98,8 @@ final class LongArrayData extends ArrayData { final int length = (int) length(); if (type == Double.class) { return new NumberArrayData(LongArrayData.toDoubleArray(array, length), length); - } else { - return new ObjectArrayData(LongArrayData.toObjectArray(array, length), length); } + return new ObjectArrayData(LongArrayData.toObjectArray(array, length), length); } @Override diff --git a/nashorn/src/jdk/nashorn/internal/runtime/arrays/SparseArrayData.java b/nashorn/src/jdk/nashorn/internal/runtime/arrays/SparseArrayData.java index 0fc466d4652..ed99ce1cb73 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/arrays/SparseArrayData.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/arrays/SparseArrayData.java @@ -60,7 +60,7 @@ class SparseArrayData extends ArrayData { @Override public ArrayData copy() { - return new SparseArrayData(underlying.copy(), length(), new TreeMap(sparseMap)); + return new SparseArrayData(underlying.copy(), length(), new TreeMap<>(sparseMap)); } @Override diff --git a/nashorn/src/jdk/nashorn/internal/runtime/linker/BoundDynamicMethod.java b/nashorn/src/jdk/nashorn/internal/runtime/linker/BoundDynamicMethod.java index 213f2b4f3be..f2089d5a2ba 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/linker/BoundDynamicMethod.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/BoundDynamicMethod.java @@ -29,7 +29,7 @@ import jdk.internal.dynalink.beans.BeansLinker; /** * Represents a Dynalink dynamic method bound to a receiver. Note that objects of this class are just the tuples of - * a method and a bound this, without any behavior. All the behavior is defined in the {@link BoundDynamicMethodLinker}. + * a method and a bound this, without any behavior. All the behavior is defined in the {@code BoundDynamicMethodLinker}. */ final class BoundDynamicMethod { private final Object dynamicMethod; diff --git a/nashorn/src/jdk/nashorn/internal/runtime/linker/BoundDynamicMethodLinker.java b/nashorn/src/jdk/nashorn/internal/runtime/linker/BoundDynamicMethodLinker.java index 03bde6298ff..7a2bc41948d 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/linker/BoundDynamicMethodLinker.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/BoundDynamicMethodLinker.java @@ -37,7 +37,7 @@ import jdk.internal.dynalink.linker.TypeBasedGuardingDynamicLinker; import jdk.internal.dynalink.support.Guards; /** - * Links {@link BoundDynamicMethod} objects. Passes through to Dynalink's BeansLinker for linking a dynamic method + * Links {@code BoundDynamicMethod} objects. Passes through to Dynalink's BeansLinker for linking a dynamic method * (they only respond to "dyn:call"), and modifies the returned invocation to deal with the receiver binding. */ final class BoundDynamicMethodLinker implements TypeBasedGuardingDynamicLinker { diff --git a/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterClassLoader.java b/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterClassLoader.java index 291e4d2ff20..a499aa61c04 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterClassLoader.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterClassLoader.java @@ -114,9 +114,8 @@ final class JavaAdapterClassLoader { if(name.equals(className)) { assert classBytes != null : "what? already cleared .class bytes!!"; return defineClass(name, classBytes, 0, classBytes.length, GENERATED_PROTECTION_DOMAIN); - } else { - throw new ClassNotFoundException(name); } + throw new ClassNotFoundException(name); } }; } From 67ca2239594df652a94e5e0fc4c73c34c42bd1b1 Mon Sep 17 00:00:00 2001 From: Athijegannathan Sundararajan Date: Mon, 19 Aug 2013 17:16:54 +0530 Subject: [PATCH 070/218] 8023210: jjs tools should support a mode where it will load few command line scripts and then entering into interactive shell Reviewed-by: hannesw, attila, lagergren, jlaskey --- .../internal/runtime/options/Options.java | 17 +++++++++-------- nashorn/src/jdk/nashorn/tools/Shell.java | 8 ++++++++ 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/nashorn/src/jdk/nashorn/internal/runtime/options/Options.java b/nashorn/src/jdk/nashorn/internal/runtime/options/Options.java index 900d9dd4e8c..cd774bb3570 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/options/Options.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/options/Options.java @@ -408,13 +408,13 @@ public final class Options { final LinkedList argList = new LinkedList<>(); Collections.addAll(argList, args); - final String extra = getStringProperty(NASHORN_ARGS_PROPERTY, null); - if (extra != null) { - final StringTokenizer st = new StringTokenizer(extra); - while (st.hasMoreTokens()) { - argList.add(st.nextToken()); + final String extra = getStringProperty(NASHORN_ARGS_PROPERTY, null); + if (extra != null) { + final StringTokenizer st = new StringTokenizer(extra); + while (st.hasMoreTokens()) { + argList.add(st.nextToken()); + } } - } while (!argList.isEmpty()) { final String arg = argList.remove(0); @@ -431,8 +431,9 @@ public final class Options { continue; } - // if it doesn't start with -, it's a file - if (!arg.startsWith("-")) { + // If it doesn't start with -, it's a file. But, if it is just "-", + // then it is a file representing standard input. + if (!arg.startsWith("-") || arg.length() == 1) { files.add(arg); continue; } diff --git a/nashorn/src/jdk/nashorn/tools/Shell.java b/nashorn/src/jdk/nashorn/tools/Shell.java index 08b576fb9fa..713f92c4581 100644 --- a/nashorn/src/jdk/nashorn/tools/Shell.java +++ b/nashorn/src/jdk/nashorn/tools/Shell.java @@ -292,6 +292,14 @@ public class Shell { // For each file on the command line. for (final String fileName : files) { + if ("-".equals(fileName)) { + final int res = readEvalPrint(context, global); + if (res != SUCCESS) { + return res; + } + continue; + } + final File file = new File(fileName); final ScriptFunction script = context.compileScript(new Source(fileName, file.toURI().toURL()), global); if (script == null || errors.getNumberOfErrors() != 0) { From a40e2a92362f833298b47bb5d3c7eed29706cb86 Mon Sep 17 00:00:00 2001 From: Kevin Walls Date: Mon, 19 Aug 2013 14:28:58 +0100 Subject: [PATCH 071/218] 8022655: ClassDump ignored jarStream setting Reviewed-by: minqi, sla --- .../classes/sun/jvm/hotspot/tools/jcore/ClassDump.java | 9 +++++++-- hotspot/test/compiler/ciReplay/common.sh | 5 +++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/jcore/ClassDump.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/jcore/ClassDump.java index 418bef9a086..afd7f9865b5 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/jcore/ClassDump.java +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/jcore/ClassDump.java @@ -92,8 +92,13 @@ public class ClassDump extends Tool { System.err.println("Warning: Can not create class filter!"); } } - String outputDirectory = System.getProperty("sun.jvm.hotspot.tools.jcore.outputDir", "."); - setOutputDirectory(outputDirectory); + + // outputDirectory and jarStream are alternatives: setting one closes the other. + // If neither is set, use outputDirectory from the System property: + if (outputDirectory == null && jarStream == null) { + String dirName = System.getProperty("sun.jvm.hotspot.tools.jcore.outputDir", "."); + setOutputDirectory(dirName); + } // walk through the system dictionary SystemDictionary dict = VM.getVM().getSystemDictionary(); diff --git a/hotspot/test/compiler/ciReplay/common.sh b/hotspot/test/compiler/ciReplay/common.sh index ec3b7fe33cf..f8c207b2c8a 100644 --- a/hotspot/test/compiler/ciReplay/common.sh +++ b/hotspot/test/compiler/ciReplay/common.sh @@ -186,6 +186,11 @@ generate_replay() { then # enable core dump ulimit -c unlimited + + if [ $VM_OS = "solaris" ] + then + coreadm -p core $$ + fi fi cmd="${JAVA} ${TESTVMOPTS} $@ \ From 7870f1a6dcbb2c734641b5579909d508021969a4 Mon Sep 17 00:00:00 2001 From: Kumar Srinivasan Date: Mon, 19 Aug 2013 07:47:10 -0700 Subject: [PATCH 072/218] 7071377: Exception when javac -processor is given a class name with invalid postfix Reviewed-by: jjg, vromero --- .../com/sun/tools/javac/comp/Attr.java | 2 +- .../processing/errors/TestClassNames.java | 47 +++++++++++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 langtools/test/tools/javac/processing/errors/TestClassNames.java diff --git a/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java b/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java index 5a0a2edf7f7..17557b3f139 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java @@ -398,7 +398,7 @@ public class Attr extends JCTree.Visitor { @Override public Symbol visitMemberSelect(MemberSelectTree node, Env env) { Symbol site = visit(node.getExpression(), env); - if (site.kind == ERR) + if (site.kind == ERR || site.kind == ABSENT_TYP) return site; Name name = (Name)node.getIdentifier(); if (site.kind == PCK) { diff --git a/langtools/test/tools/javac/processing/errors/TestClassNames.java b/langtools/test/tools/javac/processing/errors/TestClassNames.java new file mode 100644 index 00000000000..3777121d5fd --- /dev/null +++ b/langtools/test/tools/javac/processing/errors/TestClassNames.java @@ -0,0 +1,47 @@ +/* + * 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 7071377 + * @summary verify if erroneous class names are rejected + * @library /tools/javac/lib + * @build TestClassNames JavacTestingAbstractProcessor CompileFail + * @run main CompileFail ERROR -processor TestClassNames TestClassNames.x.y + * @run main CompileFail ERROR -processor TestClassNames x.y.TestClassNames + * @run main CompileFail ERROR -processor NoClass NoClass.x.y + */ + +import java.util.Set; +import javax.annotation.processing.*; +import javax.lang.model.element.*; + +/** + * No-op processor; should not be run. + */ +public class TestClassNames extends JavacTestingAbstractProcessor { + public boolean process(Set annotations, + RoundEnvironment roundEnvironment) { + return true; + } +} From 056fb53c830f7f98795fed9cd1fdf72d9e265fcf Mon Sep 17 00:00:00 2001 From: Yumin Qi Date: Mon, 19 Aug 2013 09:16:35 -0700 Subject: [PATCH 073/218] 8023188: Unsafe volatile double store on bsd is broken Reviewed-by: dcubed, dholmes --- hotspot/src/os_cpu/bsd_x86/vm/orderAccess_bsd_x86.inline.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hotspot/src/os_cpu/bsd_x86/vm/orderAccess_bsd_x86.inline.hpp b/hotspot/src/os_cpu/bsd_x86/vm/orderAccess_bsd_x86.inline.hpp index 8cb9d4a1451..c7459d5a514 100644 --- a/hotspot/src/os_cpu/bsd_x86/vm/orderAccess_bsd_x86.inline.hpp +++ b/hotspot/src/os_cpu/bsd_x86/vm/orderAccess_bsd_x86.inline.hpp @@ -190,7 +190,7 @@ inline void OrderAccess::release_store_fence(volatile juint* p, juint v) inline void OrderAccess::release_store_fence(volatile julong* p, julong v) { release_store_fence((volatile jlong*)p, (jlong)v); } inline void OrderAccess::release_store_fence(volatile jfloat* p, jfloat v) { *p = v; fence(); } -inline void OrderAccess::release_store_fence(volatile jdouble* p, jdouble v) { release_store_fence((volatile jlong*)p, jdouble_cast(v)); } +inline void OrderAccess::release_store_fence(volatile jdouble* p, jdouble v) { release_store_fence((volatile jlong*)p, jlong_cast(v)); } inline void OrderAccess::release_store_ptr_fence(volatile intptr_t* p, intptr_t v) { #ifdef AMD64 From 553b498f51e0fe3922da5019a12e611881671ae4 Mon Sep 17 00:00:00 2001 From: Jiangli Zhou Date: Mon, 19 Aug 2013 14:59:54 -0400 Subject: [PATCH 074/218] 8021948: Change InstanceKlass::_source_file_name and _generic_signature from Symbol* to constant pool indexes Change InstanceKlass::_source_file_name and _generic_signature to u2 fields. Reviewed-by: coleenp, iklam --- .../sun/jvm/hotspot/oops/InstanceKlass.java | 14 ++++---- .../share/vm/classfile/classFileParser.cpp | 14 ++++---- .../share/vm/classfile/classFileParser.hpp | 16 ++++----- hotspot/src/share/vm/oops/instanceKlass.cpp | 10 ++---- hotspot/src/share/vm/oops/instanceKlass.hpp | 34 ++++++++++++++----- .../share/vm/prims/jvmtiRedefineClasses.cpp | 17 +++++++++- hotspot/src/share/vm/runtime/vmStructs.cpp | 4 +-- 7 files changed, 67 insertions(+), 42 deletions(-) diff --git a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java b/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java index 80d5b795b3f..1cc2c8d910a 100644 --- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java +++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java @@ -75,19 +75,19 @@ public class InstanceKlass extends Klass { javaFieldsCount = new CIntField(type.getCIntegerField("_java_fields_count"), 0); constants = new MetadataField(type.getAddressField("_constants"), 0); classLoaderData = type.getAddressField("_class_loader_data"); - sourceFileName = type.getAddressField("_source_file_name"); sourceDebugExtension = type.getAddressField("_source_debug_extension"); innerClasses = type.getAddressField("_inner_classes"); + sourceFileNameIndex = new CIntField(type.getCIntegerField("_source_file_name_index"), 0); nonstaticFieldSize = new CIntField(type.getCIntegerField("_nonstatic_field_size"), 0); staticFieldSize = new CIntField(type.getCIntegerField("_static_field_size"), 0); - staticOopFieldCount = new CIntField(type.getCIntegerField("_static_oop_field_count"), 0); + staticOopFieldCount = new CIntField(type.getCIntegerField("_static_oop_field_count"), 0); nonstaticOopMapSize = new CIntField(type.getCIntegerField("_nonstatic_oop_map_size"), 0); isMarkedDependent = new CIntField(type.getCIntegerField("_is_marked_dependent"), 0); initState = new CIntField(type.getCIntegerField("_init_state"), 0); vtableLen = new CIntField(type.getCIntegerField("_vtable_len"), 0); itableLen = new CIntField(type.getCIntegerField("_itable_len"), 0); breakpoints = type.getAddressField("_breakpoints"); - genericSignature = type.getAddressField("_generic_signature"); + genericSignatureIndex = new CIntField(type.getCIntegerField("_generic_signature_index"), 0); majorVersion = new CIntField(type.getCIntegerField("_major_version"), 0); minorVersion = new CIntField(type.getCIntegerField("_minor_version"), 0); headerSize = Oop.alignObjectOffset(type.getSize()); @@ -134,9 +134,9 @@ public class InstanceKlass extends Klass { private static CIntField javaFieldsCount; private static MetadataField constants; private static AddressField classLoaderData; - private static AddressField sourceFileName; private static AddressField sourceDebugExtension; private static AddressField innerClasses; + private static CIntField sourceFileNameIndex; private static CIntField nonstaticFieldSize; private static CIntField staticFieldSize; private static CIntField staticOopFieldCount; @@ -146,7 +146,7 @@ public class InstanceKlass extends Klass { private static CIntField vtableLen; private static CIntField itableLen; private static AddressField breakpoints; - private static AddressField genericSignature; + private static CIntField genericSignatureIndex; private static CIntField majorVersion; private static CIntField minorVersion; @@ -346,7 +346,7 @@ public class InstanceKlass extends Klass { public ConstantPool getConstants() { return (ConstantPool) constants.getValue(this); } public ClassLoaderData getClassLoaderData() { return ClassLoaderData.instantiateWrapperFor(classLoaderData.getValue(getAddress())); } public Oop getClassLoader() { return getClassLoaderData().getClassLoader(); } - public Symbol getSourceFileName() { return getSymbol(sourceFileName); } + public Symbol getSourceFileName() { return getConstants().getSymbolAt(sourceFileNameIndex.getValue(this)); } public String getSourceDebugExtension(){ return CStringUtilities.getString(sourceDebugExtension.getValue(getAddress())); } public long getNonstaticFieldSize() { return nonstaticFieldSize.getValue(this); } public long getStaticOopFieldCount() { return staticOopFieldCount.getValue(this); } @@ -354,7 +354,7 @@ public class InstanceKlass extends Klass { public boolean getIsMarkedDependent() { return isMarkedDependent.getValue(this) != 0; } public long getVtableLen() { return vtableLen.getValue(this); } public long getItableLen() { return itableLen.getValue(this); } - public Symbol getGenericSignature() { return getSymbol(genericSignature); } + public Symbol getGenericSignature() { return getConstants().getSymbolAt(genericSignatureIndex.getValue(this)); } public long majorVersion() { return majorVersion.getValue(this); } public long minorVersion() { return minorVersion.getValue(this); } diff --git a/hotspot/src/share/vm/classfile/classFileParser.cpp b/hotspot/src/share/vm/classfile/classFileParser.cpp index 3ffacd39aff..507bb477a88 100644 --- a/hotspot/src/share/vm/classfile/classFileParser.cpp +++ b/hotspot/src/share/vm/classfile/classFileParser.cpp @@ -2590,7 +2590,7 @@ void ClassFileParser::parse_classfile_sourcefile_attribute(TRAPS) { valid_symbol_at(sourcefile_index), "Invalid SourceFile attribute at constant pool index %u in class file %s", sourcefile_index, CHECK); - set_class_sourcefile(_cp->symbol_at(sourcefile_index)); + set_class_sourcefile_index(sourcefile_index); } @@ -2728,7 +2728,7 @@ void ClassFileParser::parse_classfile_signature_attribute(TRAPS) { valid_symbol_at(signature_index), "Invalid constant pool index %u in Signature attribute in class file %s", signature_index, CHECK); - set_class_generic_signature(_cp->symbol_at(signature_index)); + set_class_generic_signature_index(signature_index); } void ClassFileParser::parse_classfile_bootstrap_methods_attribute(u4 attribute_byte_length, TRAPS) { @@ -2975,13 +2975,11 @@ void ClassFileParser::parse_classfile_attributes(ClassFileParser::ClassAnnotatio void ClassFileParser::apply_parsed_class_attributes(instanceKlassHandle k) { if (_synthetic_flag) k->set_is_synthetic(); - if (_sourcefile != NULL) { - _sourcefile->increment_refcount(); - k->set_source_file_name(_sourcefile); + if (_sourcefile_index != 0) { + k->set_source_file_name_index(_sourcefile_index); } - if (_generic_signature != NULL) { - _generic_signature->increment_refcount(); - k->set_generic_signature(_generic_signature); + if (_generic_signature_index != 0) { + k->set_generic_signature_index(_generic_signature_index); } if (_sde_buffer != NULL) { k->set_source_debug_extension(_sde_buffer, _sde_length); diff --git a/hotspot/src/share/vm/classfile/classFileParser.hpp b/hotspot/src/share/vm/classfile/classFileParser.hpp index 8f070747250..1b5ed30c5a6 100644 --- a/hotspot/src/share/vm/classfile/classFileParser.hpp +++ b/hotspot/src/share/vm/classfile/classFileParser.hpp @@ -62,8 +62,8 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC { bool _synthetic_flag; int _sde_length; char* _sde_buffer; - Symbol* _sourcefile; - Symbol* _generic_signature; + u2 _sourcefile_index; + u2 _generic_signature_index; // Metadata created before the instance klass is created. Must be deallocated // if not transferred to the InstanceKlass upon successful class loading @@ -81,16 +81,16 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC { Array* _fields_type_annotations; InstanceKlass* _klass; // InstanceKlass once created. - void set_class_synthetic_flag(bool x) { _synthetic_flag = x; } - void set_class_sourcefile(Symbol* x) { _sourcefile = x; } - void set_class_generic_signature(Symbol* x) { _generic_signature = x; } - void set_class_sde_buffer(char* x, int len) { _sde_buffer = x; _sde_length = len; } + void set_class_synthetic_flag(bool x) { _synthetic_flag = x; } + void set_class_sourcefile_index(u2 x) { _sourcefile_index = x; } + void set_class_generic_signature_index(u2 x) { _generic_signature_index = x; } + void set_class_sde_buffer(char* x, int len) { _sde_buffer = x; _sde_length = len; } void init_parsed_class_attributes(ClassLoaderData* loader_data) { _loader_data = loader_data; _synthetic_flag = false; - _sourcefile = NULL; - _generic_signature = NULL; + _sourcefile_index = 0; + _generic_signature_index = 0; _sde_buffer = NULL; _sde_length = 0; // initialize the other flags too: diff --git a/hotspot/src/share/vm/oops/instanceKlass.cpp b/hotspot/src/share/vm/oops/instanceKlass.cpp index a2684d84bb1..29c77a07ccb 100644 --- a/hotspot/src/share/vm/oops/instanceKlass.cpp +++ b/hotspot/src/share/vm/oops/instanceKlass.cpp @@ -269,7 +269,7 @@ InstanceKlass::InstanceKlass(int vtable_len, set_fields(NULL, 0); set_constants(NULL); set_class_loader_data(NULL); - set_source_file_name(NULL); + set_source_file_name_index(0); set_source_debug_extension(NULL, 0); set_array_name(NULL); set_inner_classes(NULL); @@ -284,7 +284,7 @@ InstanceKlass::InstanceKlass(int vtable_len, set_osr_nmethods_head(NULL); set_breakpoints(NULL); init_previous_versions(); - set_generic_signature(NULL); + set_generic_signature_index(0); release_set_methods_jmethod_ids(NULL); release_set_methods_cached_itable_indices(NULL); set_annotations(NULL); @@ -2368,18 +2368,12 @@ void InstanceKlass::release_C_heap_structures() { // unreference array name derived from this class name (arrays of an unloaded // class can't be referenced anymore). if (_array_name != NULL) _array_name->decrement_refcount(); - if (_source_file_name != NULL) _source_file_name->decrement_refcount(); if (_source_debug_extension != NULL) FREE_C_HEAP_ARRAY(char, _source_debug_extension, mtClass); assert(_total_instanceKlass_count >= 1, "Sanity check"); Atomic::dec(&_total_instanceKlass_count); } -void InstanceKlass::set_source_file_name(Symbol* n) { - _source_file_name = n; - if (_source_file_name != NULL) _source_file_name->increment_refcount(); -} - void InstanceKlass::set_source_debug_extension(char* array, int length) { if (array == NULL) { _source_debug_extension = NULL; diff --git a/hotspot/src/share/vm/oops/instanceKlass.hpp b/hotspot/src/share/vm/oops/instanceKlass.hpp index b82b2f83af5..123f6b17911 100644 --- a/hotspot/src/share/vm/oops/instanceKlass.hpp +++ b/hotspot/src/share/vm/oops/instanceKlass.hpp @@ -201,14 +201,10 @@ class InstanceKlass: public Klass { // number_of_inner_classes * 4 + enclosing_method_attribute_size. Array* _inner_classes; - // Name of source file containing this klass, NULL if not specified. - Symbol* _source_file_name; // the source debug extension for this klass, NULL if not specified. // Specified as UTF-8 string without terminating zero byte in the classfile, // it is stored in the instanceklass as a NULL-terminated UTF-8 string char* _source_debug_extension; - // Generic signature, or null if none. - Symbol* _generic_signature; // Array name derived from this class which needs unreferencing // if this class is unloaded. Symbol* _array_name; @@ -217,6 +213,12 @@ class InstanceKlass: public Klass { // (including inherited fields but after header_size()). int _nonstatic_field_size; int _static_field_size; // number words used by static fields (oop and non-oop) in this klass + // Constant pool index to the utf8 entry of the Generic signature, + // or 0 if none. + u2 _generic_signature_index; + // Constant pool index to the utf8 entry for the name of source file + // containing this klass, 0 if not specified. + u2 _source_file_name_index; u2 _static_oop_field_count;// number of static oop fields in this klass u2 _java_fields_count; // The number of declared Java fields int _nonstatic_oop_map_size;// size in words of nonstatic oop map blocks @@ -570,8 +572,16 @@ class InstanceKlass: public Klass { } // source file name - Symbol* source_file_name() const { return _source_file_name; } - void set_source_file_name(Symbol* n); + Symbol* source_file_name() const { + return (_source_file_name_index == 0) ? + (Symbol*)NULL : _constants->symbol_at(_source_file_name_index); + } + u2 source_file_name_index() const { + return _source_file_name_index; + } + void set_source_file_name_index(u2 sourcefile_index) { + _source_file_name_index = sourcefile_index; + } // minor and major version numbers of class file u2 minor_version() const { return _minor_version; } @@ -648,8 +658,16 @@ class InstanceKlass: public Klass { void set_initial_method_idnum(u2 value) { _idnum_allocated_count = value; } // generics support - Symbol* generic_signature() const { return _generic_signature; } - void set_generic_signature(Symbol* sig) { _generic_signature = sig; } + Symbol* generic_signature() const { + return (_generic_signature_index == 0) ? + (Symbol*)NULL : _constants->symbol_at(_generic_signature_index); + } + u2 generic_signature_index() const { + return _generic_signature_index; + } + void set_generic_signature_index(u2 sig_index) { + _generic_signature_index = sig_index; + } u2 enclosing_method_data(int offset); u2 enclosing_method_class_index() { diff --git a/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp b/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp index c6ec25f1406..dd1553af46c 100644 --- a/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp +++ b/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp @@ -1554,6 +1554,20 @@ bool VM_RedefineClasses::rewrite_cp_refs(instanceKlassHandle scratch_class, return false; } + // rewrite sourc file name index: + u2 source_file_name_idx = scratch_class->source_file_name_index(); + if (source_file_name_idx != 0) { + u2 new_source_file_name_idx = find_new_index(source_file_name_idx); + scratch_class->set_source_file_name_index(new_source_file_name_idx); + } + + // rewrite class generic signature index: + u2 generic_signature_index = scratch_class->generic_signature_index(); + if (generic_signature_index != 0) { + u2 new_generic_signature_index = find_new_index(generic_signature_index); + scratch_class->set_generic_signature_index(new_generic_signature_index); + } + return true; } // end rewrite_cp_refs() @@ -3370,7 +3384,8 @@ void VM_RedefineClasses::redefine_single_class(jclass the_jclass, // Leave arrays of jmethodIDs and itable index cache unchanged // Copy the "source file name" attribute from new class version - the_class->set_source_file_name(scratch_class->source_file_name()); + the_class->set_source_file_name_index( + scratch_class->source_file_name_index()); // Copy the "source debug extension" attribute from new class version the_class->set_source_debug_extension( diff --git a/hotspot/src/share/vm/runtime/vmStructs.cpp b/hotspot/src/share/vm/runtime/vmStructs.cpp index 163433b524f..e820614a6de 100644 --- a/hotspot/src/share/vm/runtime/vmStructs.cpp +++ b/hotspot/src/share/vm/runtime/vmStructs.cpp @@ -294,7 +294,7 @@ typedef BinaryTreeDictionary MetablockTreeDictionary; nonstatic_field(InstanceKlass, _java_fields_count, u2) \ nonstatic_field(InstanceKlass, _constants, ConstantPool*) \ nonstatic_field(InstanceKlass, _class_loader_data, ClassLoaderData*) \ - nonstatic_field(InstanceKlass, _source_file_name, Symbol*) \ + nonstatic_field(InstanceKlass, _source_file_name_index, u2) \ nonstatic_field(InstanceKlass, _source_debug_extension, char*) \ nonstatic_field(InstanceKlass, _inner_classes, Array*) \ nonstatic_field(InstanceKlass, _nonstatic_field_size, int) \ @@ -313,7 +313,7 @@ typedef BinaryTreeDictionary MetablockTreeDictionary; nonstatic_field(InstanceKlass, _jni_ids, JNIid*) \ nonstatic_field(InstanceKlass, _osr_nmethods_head, nmethod*) \ nonstatic_field(InstanceKlass, _breakpoints, BreakpointInfo*) \ - nonstatic_field(InstanceKlass, _generic_signature, Symbol*) \ + nonstatic_field(InstanceKlass, _generic_signature_index, u2) \ nonstatic_field(InstanceKlass, _methods_jmethod_ids, jmethodID*) \ nonstatic_field(InstanceKlass, _methods_cached_itable_indices, int*) \ volatile_nonstatic_field(InstanceKlass, _idnum_allocated_count, u2) \ From 7947e49ae3d0893150985da2fe95b9442315efd9 Mon Sep 17 00:00:00 2001 From: Alexander Zuev Date: Tue, 20 Aug 2013 17:34:06 +0400 Subject: [PATCH 075/218] 7182350: Regression in wording of unchecked warning message Reviewed-by: mcimadamore, jjg --- .../com/sun/tools/javac/comp/Check.java | 38 ++++++++++--------- .../test/tools/javac/6758789/T6758789b.out | 2 +- .../test/tools/javac/7182350/T7182350.java | 14 +++++++ .../test/tools/javac/7182350/T7182350.out | 4 ++ .../javac/generics/7015430/T7015430_1.out | 6 +-- .../javac/generics/7015430/T7015430_2.out | 12 +++--- .../tools/javac/generics/7151802/T7151802.out | 2 +- .../generics/inference/6718364/T6718364.out | 2 +- .../generics/inference/7177306/T7177306a.out | 2 +- 9 files changed, 52 insertions(+), 30 deletions(-) create mode 100644 langtools/test/tools/javac/7182350/T7182350.java create mode 100644 langtools/test/tools/javac/7182350/T7182350.out diff --git a/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java b/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java index a60395a7ddd..b5de42c3da0 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java @@ -875,19 +875,23 @@ public class Check { } Type owntype = mtype; List formals = owntype.getParameterTypes(); + List nonInferred = sym.type.getParameterTypes(); + if (nonInferred.length() != formals.length()) nonInferred = formals; Type last = useVarargs ? formals.last() : null; - if (sym.name == names.init && - sym.owner == syms.enumSym) - formals = formals.tail.tail; + if (sym.name == names.init && sym.owner == syms.enumSym) { + formals = formals.tail.tail; + nonInferred = nonInferred.tail.tail; + } List args = argtrees; if (args != null) { //this is null when type-checking a method reference while (formals.head != last) { JCTree arg = args.head; - Warner warn = convertWarner(arg.pos(), arg.type, formals.head); + Warner warn = convertWarner(arg.pos(), arg.type, nonInferred.head); assertConvertible(arg, arg.type, formals.head, warn); args = args.tail; formals = formals.tail; + nonInferred = nonInferred.tail; } if (useVarargs) { Type varArg = types.elemtype(last); @@ -903,17 +907,17 @@ public class Check { Type varParam = owntype.getParameterTypes().last(); Type lastArg = argtypes.last(); if (types.isSubtypeUnchecked(lastArg, types.elemtype(varParam)) && - !types.isSameType(types.erasure(varParam), types.erasure(lastArg))) + !types.isSameType(types.erasure(varParam), types.erasure(lastArg))) log.warning(argtrees.last().pos(), "inexact.non-varargs.call", - types.elemtype(varParam), varParam); + types.elemtype(varParam), varParam); } } if (useVarargs) { Type argtype = owntype.getParameterTypes().last(); if (!types.isReifiable(argtype) && - (!allowSimplifiedVarargs || - sym.attribute(syms.trustMeType.tsym) == null || - !isTrustMeAllowedOnMethod(sym))) { + (!allowSimplifiedVarargs || + sym.attribute(syms.trustMeType.tsym) == null || + !isTrustMeAllowedOnMethod(sym))) { warnUnchecked(env.tree.pos(), "unchecked.generic.array.creation", argtype); @@ -929,15 +933,15 @@ public class Check { return owntype; } //where - private void assertConvertible(JCTree tree, Type actual, Type formal, Warner warn) { - if (types.isConvertible(actual, formal, warn)) - return; + private void assertConvertible(JCTree tree, Type actual, Type formal, Warner warn) { + if (types.isConvertible(actual, formal, warn)) + return; - if (formal.isCompound() - && types.isSubtype(actual, types.supertype(formal)) - && types.isSubtypeUnchecked(actual, types.interfaces(formal), warn)) - return; - } + if (formal.isCompound() + && types.isSubtype(actual, types.supertype(formal)) + && types.isSubtypeUnchecked(actual, types.interfaces(formal), warn)) + return; + } /** * Check that type 't' is a valid instantiation of a generic class diff --git a/langtools/test/tools/javac/6758789/T6758789b.out b/langtools/test/tools/javac/6758789/T6758789b.out index 5bdb51c22cd..89a63fdb2b0 100644 --- a/langtools/test/tools/javac/6758789/T6758789b.out +++ b/langtools/test/tools/javac/6758789/T6758789b.out @@ -1,5 +1,5 @@ T6758789b.java:16:10: compiler.warn.unchecked.meth.invocation.applied: kindname.method, m, T6758789a.Foo, T6758789a.Foo, kindname.class, T6758789a -T6758789b.java:16:11: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), T6758789a.Foo, T6758789a.Foo +T6758789b.java:16:11: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), T6758789a.Foo, T6758789a.Foo - compiler.err.warnings.and.werror 1 error 2 warnings diff --git a/langtools/test/tools/javac/7182350/T7182350.java b/langtools/test/tools/javac/7182350/T7182350.java new file mode 100644 index 00000000000..7470794f4e5 --- /dev/null +++ b/langtools/test/tools/javac/7182350/T7182350.java @@ -0,0 +1,14 @@ +/** + * @test /nodynamiccopyright/ + * @bug 7182350 + * @summary verify correct output of -Xlint:unchecked on methods with unchecked conversations in parameters + * @compile/ref=T7182350.out -XDrawDiagnostics -Xlint:unchecked T7182350.java + */ + +import java.util.*; + +class T7182350 { + public static void quicksort(Vector vector, Comparator compare) { + Collections.sort(vector,compare); + } +} diff --git a/langtools/test/tools/javac/7182350/T7182350.out b/langtools/test/tools/javac/7182350/T7182350.out new file mode 100644 index 00000000000..e88378348c2 --- /dev/null +++ b/langtools/test/tools/javac/7182350/T7182350.out @@ -0,0 +1,4 @@ +T7182350.java:12:25: compiler.warn.unchecked.meth.invocation.applied: kindname.method, sort, java.util.List,java.util.Comparator, java.util.Vector,java.util.Comparator, kindname.class, java.util.Collections +T7182350.java:12:26: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), java.util.Vector, java.util.List +T7182350.java:12:33: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), java.util.Comparator, java.util.Comparator +3 warnings diff --git a/langtools/test/tools/javac/generics/7015430/T7015430_1.out b/langtools/test/tools/javac/generics/7015430/T7015430_1.out index 3bee4e5da71..fb1fb0bf9c8 100644 --- a/langtools/test/tools/javac/generics/7015430/T7015430_1.out +++ b/langtools/test/tools/javac/generics/7015430/T7015430_1.out @@ -1,13 +1,13 @@ T7015430.java:42:14: compiler.warn.unchecked.meth.invocation.applied: kindname.method, empty, java.lang.Iterable, java.lang.Iterable, kindname.class, T7015430 T7015430.java:42:15: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), java.lang.Iterable, java.lang.Iterable T7015430.java:51:41: compiler.warn.unchecked.meth.invocation.applied: kindname.method, empty, java.lang.Iterable, java.lang.Iterable, kindname.class, T7015430 -T7015430.java:51:42: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), java.lang.Iterable, java.lang.Iterable +T7015430.java:51:42: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), java.lang.Iterable, java.lang.Iterable T7015430.java:69:9: compiler.warn.unchecked.meth.invocation.applied: kindname.constructor, , java.lang.Iterable, java.lang.Iterable, kindname.class, T7015430 T7015430.java:69:22: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), java.lang.Iterable, java.lang.Iterable T7015430.java:78:9: compiler.warn.unchecked.meth.invocation.applied: kindname.constructor, , java.lang.Iterable, java.lang.Iterable, kindname.class, T7015430 -T7015430.java:78:40: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), java.lang.Iterable, java.lang.Iterable +T7015430.java:78:40: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), java.lang.Iterable, java.lang.Iterable T7015430.java:105:9: compiler.warn.unchecked.meth.invocation.applied: kindname.constructor, , java.lang.Iterable, java.lang.Iterable, kindname.class, T7015430 -T7015430.java:105:41: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), java.lang.Iterable, java.lang.Iterable +T7015430.java:105:41: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), java.lang.Iterable, java.lang.Iterable T7015430.java:114:9: compiler.warn.unchecked.meth.invocation.applied: kindname.constructor, , java.lang.Iterable, java.lang.Iterable, kindname.class, T7015430 T7015430.java:114:22: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), java.lang.Iterable, java.lang.Iterable T7015430.java:42:14: compiler.err.unreported.exception.need.to.catch.or.throw: java.lang.Exception diff --git a/langtools/test/tools/javac/generics/7015430/T7015430_2.out b/langtools/test/tools/javac/generics/7015430/T7015430_2.out index da5be706917..2d24234c786 100644 --- a/langtools/test/tools/javac/generics/7015430/T7015430_2.out +++ b/langtools/test/tools/javac/generics/7015430/T7015430_2.out @@ -1,15 +1,15 @@ T7015430.java:42:14: compiler.warn.unchecked.meth.invocation.applied: kindname.method, empty, java.lang.Iterable, java.lang.Iterable, kindname.class, T7015430 -T7015430.java:42:15: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), java.lang.Iterable, java.lang.Iterable +T7015430.java:42:15: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), java.lang.Iterable, java.lang.Iterable T7015430.java:51:41: compiler.warn.unchecked.meth.invocation.applied: kindname.method, empty, java.lang.Iterable, java.lang.Iterable, kindname.class, T7015430 -T7015430.java:51:42: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), java.lang.Iterable, java.lang.Iterable +T7015430.java:51:42: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), java.lang.Iterable, java.lang.Iterable T7015430.java:69:9: compiler.warn.unchecked.meth.invocation.applied: kindname.constructor, , java.lang.Iterable, java.lang.Iterable, kindname.class, T7015430 -T7015430.java:69:22: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), java.lang.Iterable, java.lang.Iterable +T7015430.java:69:22: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), java.lang.Iterable, java.lang.Iterable T7015430.java:78:9: compiler.warn.unchecked.meth.invocation.applied: kindname.constructor, , java.lang.Iterable, java.lang.Iterable, kindname.class, T7015430 -T7015430.java:78:40: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), java.lang.Iterable, java.lang.Iterable +T7015430.java:78:40: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), java.lang.Iterable, java.lang.Iterable T7015430.java:105:9: compiler.warn.unchecked.meth.invocation.applied: kindname.constructor, , java.lang.Iterable, java.lang.Iterable, kindname.class, T7015430 -T7015430.java:105:41: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), java.lang.Iterable, java.lang.Iterable +T7015430.java:105:41: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), java.lang.Iterable, java.lang.Iterable T7015430.java:114:9: compiler.warn.unchecked.meth.invocation.applied: kindname.constructor, , java.lang.Iterable, java.lang.Iterable, kindname.class, T7015430 -T7015430.java:114:22: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), java.lang.Iterable, java.lang.Iterable +T7015430.java:114:22: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), java.lang.Iterable, java.lang.Iterable T7015430.java:130:9: compiler.err.unreported.exception.need.to.catch.or.throw: java.lang.Exception 1 error 12 warnings diff --git a/langtools/test/tools/javac/generics/7151802/T7151802.out b/langtools/test/tools/javac/generics/7151802/T7151802.out index dd708d6e91f..5940b014205 100644 --- a/langtools/test/tools/javac/generics/7151802/T7151802.out +++ b/langtools/test/tools/javac/generics/7151802/T7151802.out @@ -1,6 +1,6 @@ T7151802.java:14:31: compiler.warn.unchecked.meth.invocation.applied: kindname.method, get1, Z, T7151802.Foo, kindname.class, T7151802 T7151802.java:22:30: compiler.warn.unchecked.meth.invocation.applied: kindname.method, get3, T7151802.Foo, T7151802.Foo, kindname.class, T7151802 -T7151802.java:22:31: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), T7151802.Foo, T7151802.Foo +T7151802.java:22:31: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), T7151802.Foo, T7151802.Foo T7151802.java:30:36: compiler.warn.unchecked.meth.invocation.applied: kindname.method, get5, compiler.misc.no.args, compiler.misc.no.args, kindname.class, T7151802 T7151802.java:38:31: compiler.warn.unchecked.meth.invocation.applied: kindname.method, get7, T7151802.Foo, T7151802.Foo, kindname.class, T7151802 T7151802.java:38:32: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), T7151802.Foo, T7151802.Foo diff --git a/langtools/test/tools/javac/generics/inference/6718364/T6718364.out b/langtools/test/tools/javac/generics/inference/6718364/T6718364.out index a7a70c6b9d9..47d9db336ab 100644 --- a/langtools/test/tools/javac/generics/inference/6718364/T6718364.out +++ b/langtools/test/tools/javac/generics/inference/6718364/T6718364.out @@ -1,3 +1,3 @@ T6718364.java:13:10: compiler.warn.unchecked.meth.invocation.applied: kindname.method, m, T6718364.X,T, T6718364.X>,T6718364.X, kindname.class, T6718364 -T6718364.java:13:32: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), T6718364.X, T6718364.X +T6718364.java:13:32: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), T6718364.X, T 2 warnings diff --git a/langtools/test/tools/javac/generics/inference/7177306/T7177306a.out b/langtools/test/tools/javac/generics/inference/7177306/T7177306a.out index 4a21e562164..66e9ac8a562 100644 --- a/langtools/test/tools/javac/generics/inference/7177306/T7177306a.out +++ b/langtools/test/tools/javac/generics/inference/7177306/T7177306a.out @@ -1,5 +1,5 @@ T7177306a.java:13:33: compiler.warn.unchecked.meth.invocation.applied: kindname.method, m, java.util.List, java.util.List, kindname.class, T7177306a -T7177306a.java:13:34: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), java.util.List, java.util.List +T7177306a.java:13:34: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), java.util.List, java.util.List T7177306a.java:13:33: compiler.warn.prob.found.req: (compiler.misc.unchecked.assign), T7177306a, T7177306a - compiler.err.warnings.and.werror 1 error From 07d44a65208fcdbbed18d84081513c7bbb3bf929 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joel=20Borggr=C3=A9n-Franck?= Date: Tue, 20 Aug 2013 17:21:47 +0200 Subject: [PATCH 076/218] 8019243: AnnotationTypeMismatchException instead of MirroredTypeException Reviewed-by: jjg --- .../com/sun/tools/javac/code/Attribute.java | 8 ++ .../com/sun/tools/javac/comp/Annotate.java | 16 ++- .../javac/model/AnnotationProxyMaker.java | 5 +- .../Processor.java | 100 ++++++++++++++++++ .../EnsureMirroredTypeException/Source.java | 17 +++ .../EnsureMirroredTypeException/Source.out | 4 + 6 files changed, 147 insertions(+), 3 deletions(-) create mode 100644 langtools/test/tools/javac/processing/errors/EnsureMirroredTypeException/Processor.java create mode 100644 langtools/test/tools/javac/processing/errors/EnsureMirroredTypeException/Source.java create mode 100644 langtools/test/tools/javac/processing/errors/EnsureMirroredTypeException/Source.out diff --git a/langtools/src/share/classes/com/sun/tools/javac/code/Attribute.java b/langtools/src/share/classes/com/sun/tools/javac/code/Attribute.java index bb29eeaa530..990ea0d06e0 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/code/Attribute.java +++ b/langtools/src/share/classes/com/sun/tools/javac/code/Attribute.java @@ -340,6 +340,14 @@ public abstract class Attribute implements AnnotationValue { } } + public static class UnresolvedClass extends Error { + public Type classType; + public UnresolvedClass(Type type, Type classType) { + super(type); + this.classType = classType; + } + } + /** A visitor type for dynamic dispatch on the kind of attribute value. */ public static interface Visitor { void visitConstant(Attribute.Constant value); diff --git a/langtools/src/share/classes/com/sun/tools/javac/comp/Annotate.java b/langtools/src/share/classes/com/sun/tools/javac/comp/Annotate.java index 39587558a46..3a0997bef55 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/comp/Annotate.java +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Annotate.java @@ -332,8 +332,20 @@ public class Annotate { } if (expected.tsym == syms.classType.tsym) { Type result = attr.attribExpr(tree, env, expected); - if (result.isErroneous()) - return new Attribute.Error(expected); + if (result.isErroneous()) { + // Does it look like a class literal? + if (TreeInfo.name(tree) == names._class) { + Name n = (((JCFieldAccess) tree).selected).type.tsym.flatName(); + return new Attribute.UnresolvedClass(expected, + types.createErrorType(n, + syms.unknownSymbol, syms.classType)); + } else { + return new Attribute.Error(expected); + } + } + + // Class literals look like field accesses of a field named class + // at the tree level if (TreeInfo.name(tree) != names._class) { log.error(tree.pos(), "annotation.value.must.be.class.literal"); return new Attribute.Error(expected); diff --git a/langtools/src/share/classes/com/sun/tools/javac/model/AnnotationProxyMaker.java b/langtools/src/share/classes/com/sun/tools/javac/model/AnnotationProxyMaker.java index e44f6734b28..d58c73fa46f 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/model/AnnotationProxyMaker.java +++ b/langtools/src/share/classes/com/sun/tools/javac/model/AnnotationProxyMaker.java @@ -244,7 +244,10 @@ public class AnnotationProxyMaker { } public void visitError(Attribute.Error e) { - value = null; // indicates a type mismatch + if (e instanceof Attribute.UnresolvedClass) + value = new MirroredTypeExceptionProxy(((Attribute.UnresolvedClass)e).classType); + else + value = null; // indicates a type mismatch } diff --git a/langtools/test/tools/javac/processing/errors/EnsureMirroredTypeException/Processor.java b/langtools/test/tools/javac/processing/errors/EnsureMirroredTypeException/Processor.java new file mode 100644 index 00000000000..71e722ef0a7 --- /dev/null +++ b/langtools/test/tools/javac/processing/errors/EnsureMirroredTypeException/Processor.java @@ -0,0 +1,100 @@ +/* + * 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.lang.annotation.*; +import java.util.*; +import javax.annotation.processing.*; +import javax.lang.model.element.*; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.MirroredTypeException; +import javax.lang.model.type.TypeMirror; +import javax.lang.model.type.TypeKind; +import javax.tools.*; + +import com.sun.tools.javac.util.Assert; +import com.sun.tools.javac.code.Symbol; +import static com.sun.tools.javac.code.Symbol.TypeSymbol; + +public class Processor extends JavacTestingAbstractProcessor { + + @Override + public boolean process(Set annotations, RoundEnvironment roundEnv) { + for (Element e : roundEnv.getElementsAnnotatedWith(A.class)) { + A rtg = e.getAnnotation(A.class); + + try { + rtg.a(); + Assert.check(false); //Should not reach here + } catch (MirroredTypeException ex) { + TypeMirror tm = ex.getTypeMirror(); + Assert.check(tm.getKind() == TypeKind.ERROR); + + TypeElement elm = (TypeElement)((DeclaredType)tm).asElement(); + Assert.check(elm.getQualifiedName().toString(). + endsWith("some.path.to.SomeUnknownClass$Inner")); + + TypeSymbol sym = (TypeSymbol)elm; + Assert.check(sym.name.contentEquals("some.path.to.SomeUnknownClass$Inner")); + } + } + for (Element e : roundEnv.getElementsAnnotatedWith(B.class)) { + B rtg = e.getAnnotation(B.class); + + try { + rtg.a(); + Assert.check(false); //Should not reach here + } catch (MirroredTypeException ex) { + TypeMirror tm = ex.getTypeMirror(); + Assert.check(tm.getKind() == TypeKind.ERROR); + + TypeElement elm = (TypeElement)((DeclaredType)tm).asElement(); + Assert.check(elm.getQualifiedName().toString(). + endsWith("SomeUnknownClass")); + + TypeSymbol sym = (TypeSymbol)elm; + Assert.check(sym.name.contentEquals("SomeUnknownClass")); + } + } + for (Element e : roundEnv.getElementsAnnotatedWith(C.class)) { + C rtg = e.getAnnotation(C.class); + + try { + rtg.a(); + Assert.check(false); //Should not reach here + } catch (AnnotationTypeMismatchException ex) { + ; + } + } + return true; + } + + @interface A { + Class a(); + } + @interface B { + Class a(); + } + @interface C { + Class a(); + } +} diff --git a/langtools/test/tools/javac/processing/errors/EnsureMirroredTypeException/Source.java b/langtools/test/tools/javac/processing/errors/EnsureMirroredTypeException/Source.java new file mode 100644 index 00000000000..0f66b6d039d --- /dev/null +++ b/langtools/test/tools/javac/processing/errors/EnsureMirroredTypeException/Source.java @@ -0,0 +1,17 @@ +/* + * @test /nodynamiccopyright/ + * @bug 8019243 + * @summary AnnotationTypeMismatchException instead of MirroredTypeException + * @library /tools/javac/lib + * @build JavacTestingAbstractProcessor Processor + * @compile/fail/ref=Source.out -XDrawDiagnostics -processor Processor Source.java + */ + +@Processor.A(a=some.path.to.SomeUnknownClass$Inner.class) +class Source1{} + +@Processor.B(a=SomeUnknownClass.class) +class Source2{} + +@Processor.C(a=SomeUnknownClass.clas) // this is not a class literal +class Source3{} diff --git a/langtools/test/tools/javac/processing/errors/EnsureMirroredTypeException/Source.out b/langtools/test/tools/javac/processing/errors/EnsureMirroredTypeException/Source.out new file mode 100644 index 00000000000..9e2aafb68a1 --- /dev/null +++ b/langtools/test/tools/javac/processing/errors/EnsureMirroredTypeException/Source.out @@ -0,0 +1,4 @@ +Source.java:10:28: compiler.err.doesnt.exist: some.path.to +Source.java:13:16: compiler.err.cant.resolve: kindname.class, SomeUnknownClass, , +Source.java:16:16: compiler.err.cant.resolve: kindname.variable, SomeUnknownClass, , +3 errors From 557cb9c6b155636e64c0c476464909cb53a838fb Mon Sep 17 00:00:00 2001 From: Joe Darcy Date: Tue, 20 Aug 2013 12:15:19 -0700 Subject: [PATCH 077/218] 8011043: Warn about use of 1.5 and earlier source and target values Reviewed-by: jjg --- .../sun/tools/javac/main/JavaCompiler.java | 23 +++++++++++++ .../tools/javac/resources/compiler.properties | 11 +++++++ .../classes/com/sun/tools/javadoc/Start.java | 2 ++ .../examples/ObsoleteSourceAndTarget.java | 32 +++++++++++++++++++ 4 files changed, 68 insertions(+) create mode 100644 langtools/test/tools/javac/diags/examples/ObsoleteSourceAndTarget.java diff --git a/langtools/src/share/classes/com/sun/tools/javac/main/JavaCompiler.java b/langtools/src/share/classes/com/sun/tools/javac/main/JavaCompiler.java index 0c20e771cd9..6f7ce691e8a 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/main/JavaCompiler.java +++ b/langtools/src/share/classes/com/sun/tools/javac/main/JavaCompiler.java @@ -363,6 +363,7 @@ public class JavaCompiler implements ClassReader.SourceCompleter { throw new Abort(); } source = Source.instance(context); + Target target = Target.instance(context); attr = Attr.instance(context); chk = Check.instance(context); gen = Gen.instance(context); @@ -403,6 +404,8 @@ public class JavaCompiler implements ClassReader.SourceCompleter { } } + checkForObsoleteOptions(target); + verboseCompilePolicy = options.isSet("verboseCompilePolicy"); if (attrParseOnly) @@ -432,6 +435,26 @@ public class JavaCompiler implements ClassReader.SourceCompleter { log.setDiagnosticFormatter(RichDiagnosticFormatter.instance(context)); } + private void checkForObsoleteOptions(Target target) { + // Unless lint checking on options is disabled, check for + // obsolete source and target options. + boolean obsoleteOptionFound = false; + if (options.isUnset(XLINT_CUSTOM, "-" + LintCategory.OPTIONS.option)) { + if (source.compareTo(Source.JDK1_5) <= 0) { + log.warning(LintCategory.OPTIONS, "option.obsolete.source", source.name); + obsoleteOptionFound = true; + } + + if (target.compareTo(Target.JDK1_5) <= 0) { + log.warning(LintCategory.OPTIONS, "option.obsolete.target", source.name); + obsoleteOptionFound = true; + } + + if (obsoleteOptionFound) + log.warning(LintCategory.OPTIONS, "option.obsolete.suppression"); + } + } + /* Switches: */ diff --git a/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties b/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties index 9361be25f50..572478f19e1 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties +++ b/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties @@ -1440,6 +1440,17 @@ compiler.warn.static.not.qualified.by.type=\ compiler.warn.source.no.bootclasspath=\ bootstrap class path not set in conjunction with -source {0} +# 0: string +compiler.warn.option.obsolete.source=\ + source value {0} is obsolete and will be removed in a future release + +# 0: string +compiler.warn.option.obsolete.target=\ + target value {0} is obsolete and will be removed in a future release + +compiler.warn.option.obsolete.suppression=\ + To suppress warnings about obsolete options, use -Xlint:-options. + # 0: name, 1: number, 2: number, 3: number, 4: number compiler.warn.future.attr=\ {0} attribute introduced in version {1}.{2} class files is ignored in version {3}.{4} class files diff --git a/langtools/src/share/classes/com/sun/tools/javadoc/Start.java b/langtools/src/share/classes/com/sun/tools/javadoc/Start.java index 7cee9aa26e3..ab1e75e591e 100644 --- a/langtools/src/share/classes/com/sun/tools/javadoc/Start.java +++ b/langtools/src/share/classes/com/sun/tools/javadoc/Start.java @@ -269,6 +269,8 @@ public class Start extends ToolOption.Helper { setDocletInvoker(docletClass, fileManager, argv); compOpts = Options.instance(context); + // Make sure no obsolete source/target messages are reported + compOpts.put("-Xlint:-options", "-Xlint:-options"); // Parse arguments for (int i = 0 ; i < argv.length ; i++) { diff --git a/langtools/test/tools/javac/diags/examples/ObsoleteSourceAndTarget.java b/langtools/test/tools/javac/diags/examples/ObsoleteSourceAndTarget.java new file mode 100644 index 00000000000..10416fd6aab --- /dev/null +++ b/langtools/test/tools/javac/diags/examples/ObsoleteSourceAndTarget.java @@ -0,0 +1,32 @@ +/* + * 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. + */ + +// key: compiler.warn.option.obsolete.source +// key: compiler.warn.option.obsolete.target +// key: compiler.warn.option.obsolete.suppression +// key: compiler.warn.source.no.bootclasspath +// options: -source 1.5 -target 1.5 + +class ObsoleteSourceAndTarget { + public static void foo() {;} +} From e951505eab09384ae653f741b7555cd88db6e931 Mon Sep 17 00:00:00 2001 From: "Daniel D. Daugherty" Date: Tue, 20 Aug 2013 13:47:40 -0700 Subject: [PATCH 078/218] 8023287: HOTSPOT_BUILD_COMPILER needs to support "Sun Studio 12u3" Recognize 0x5120 as "Sun Studio 12u3". Reviewed-by: dholmes, coleenp --- hotspot/src/share/vm/runtime/vm_version.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hotspot/src/share/vm/runtime/vm_version.cpp b/hotspot/src/share/vm/runtime/vm_version.cpp index 322a5b6c03a..d65bf9646d0 100644 --- a/hotspot/src/share/vm/runtime/vm_version.cpp +++ b/hotspot/src/share/vm/runtime/vm_version.cpp @@ -231,6 +231,8 @@ const char* Abstract_VM_Version::internal_vm_info_string() { #define HOTSPOT_BUILD_COMPILER "Workshop 5.9" #elif __SUNPRO_CC == 0x5100 #define HOTSPOT_BUILD_COMPILER "Sun Studio 12u1" + #elif __SUNPRO_CC == 0x5120 + #define HOTSPOT_BUILD_COMPILER "Sun Studio 12u3" #else #define HOTSPOT_BUILD_COMPILER "unknown Workshop:" XSTR(__SUNPRO_CC) #endif From c9f3cedbfae7a5c50c61986b3e1d937eb6cec3c6 Mon Sep 17 00:00:00 2001 From: Kumar Srinivasan Date: Tue, 20 Aug 2013 14:15:45 -0700 Subject: [PATCH 079/218] 7179455: tools/javac/processing/model/testgetallmembers/Main.java fails against JDK 7 and JDK 8 Reviewed-by: jjg --- .../model/testgetallmembers/Main.java | 27 ++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/langtools/test/tools/javac/processing/model/testgetallmembers/Main.java b/langtools/test/tools/javac/processing/model/testgetallmembers/Main.java index 0a38f07a360..cde00eec2a5 100644 --- a/langtools/test/tools/javac/processing/model/testgetallmembers/Main.java +++ b/langtools/test/tools/javac/processing/model/testgetallmembers/Main.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 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 @@ -31,7 +31,6 @@ import java.io.File; import java.util.*; -import javax.lang.model.SourceVersion; import javax.lang.model.element.Element; import javax.lang.model.element.ElementKind; import javax.lang.model.element.PackageElement; @@ -60,7 +59,10 @@ public class Main { static Elements elements; public static void main(String[] args) throws Exception { - + if (haveAltRt()) { + System.out.println("Warning: alt-rt.jar detected, test skipped"); + return; + } JavaCompiler tool = ToolProvider.getSystemJavaCompiler(); StandardJavaFileManager fm = tool.getStandardFileManager(null, null, null); fm.setLocation(CLASS_PATH, Collections.emptyList()); @@ -123,4 +125,23 @@ public class Main { if (nestedClasses < 3000) throw new AssertionError("Too few nested classes in PLATFORM_CLASS_PATH ;-)"); } + /* + * If -XX:+AggressiveOpts has been used to test, the option currently + * instructs the VM to prepend alt-rt.jar onto the bootclasspath. This + * overrides the default TreeMap implemation in rt.jar causing symbol + * resolution problems (caused by inconsistent inner class), although + * alt-rt.jar is being eliminated, we have this sanity check to detect this + * case and skip the test. + */ + static boolean haveAltRt() { + String bootClassPath = System.getProperty("sun.boot.class.path"); + for (String cp : bootClassPath.split(File.pathSeparator)) { + if (cp.endsWith("alt-rt.jar")) { + System.err.println("Warning: detected alt-rt.jar in " + + "sun.boot.class.path"); + return true; + } + } + return false; + } } From de59aa8b3ffaabecc9e8f9629cfbd839bcfb5b24 Mon Sep 17 00:00:00 2001 From: Jonathan Gibbons Date: Tue, 20 Aug 2013 14:46:54 -0700 Subject: [PATCH 080/218] 8020663: Restructure some properties to facilitate better translation Reviewed-by: darcy --- .../toolkit/resources/doclets.properties | 31 ++++++++++++------- .../doclets/internal/toolkit/util/Util.java | 26 +++++++++++----- 2 files changed, 38 insertions(+), 19 deletions(-) diff --git a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/resources/doclets.properties b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/resources/doclets.properties index a663d386d68..54dff68e55b 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/resources/doclets.properties +++ b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/resources/doclets.properties @@ -176,25 +176,32 @@ doclet.Value=Value doclet.0_and_1={0} and {1} #Documentation for Enums -doclet.enum_values_doc=\n\ +doclet.enum_values_doc.main=\n\ Returns an array containing the constants of this enum type, in\n\ the order they are declared. This method may be used to iterate\n\ over the constants as follows:\n\
\n\
  for ({0} c : {0}.values())\n\
      System.out.println(c);\n\
- 
\n\ - @return an array containing the constants of this enum type, in\n\ - the order they are declared + -doclet.enum_valueof_doc=\n\ +doclet.enum_values_doc.return=\n\ + an array containing the constants of this enum type, in the order they are declared + +doclet.enum_valueof_doc.main=\n\ Returns the enum constant of this type with the specified name.\n\ The string must match exactly an identifier used to declare an\n\ enum constant in this type. (Extraneous whitespace characters are \n\ - not permitted.)\n\ - \n\ - @param name the name of the enum constant to be returned.\n\ - @return the enum constant with the specified name\n\ - @throws IllegalArgumentException if this enum type has no constant\n\ - with the specified name\n\ - @throws NullPointerException if the argument is null + not permitted.) + +doclet.enum_valueof_doc.param_name=\ + the name of the enum constant to be returned. + +doclet.enum_valueof_doc.return=\ + the enum constant with the specified name + +doclet.enum_valueof_doc.throws_ila=\ + if this enum type has no constant with the specified name + +doclet.enum_valueof_doc.throws_npe=\ + if the argument is null diff --git a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/util/Util.java b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/util/Util.java index 289f34804e1..d04a2efc4fe 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/util/Util.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/util/Util.java @@ -667,16 +667,28 @@ public class Util { for (int j = 0; j < methods.length; j++) { MethodDoc currentMethod = methods[j]; if (currentMethod.name().equals("values") && - currentMethod.parameters().length == 0) { - currentMethod.setRawCommentText( - configuration.getText("doclet.enum_values_doc", classDoc.name())); + currentMethod.parameters().length == 0) { + StringBuilder sb = new StringBuilder(); + sb.append(configuration.getText("doclet.enum_values_doc.main", classDoc.name())); + sb.append("\n@return "); + sb.append(configuration.getText("doclet.enum_values_doc.return")); + currentMethod.setRawCommentText(sb.toString()); } else if (currentMethod.name().equals("valueOf") && - currentMethod.parameters().length == 1) { + currentMethod.parameters().length == 1) { Type paramType = currentMethod.parameters()[0].type(); if (paramType != null && - paramType.qualifiedTypeName().equals(String.class.getName())) { - currentMethod.setRawCommentText( - configuration.getText("doclet.enum_valueof_doc")); + paramType.qualifiedTypeName().equals(String.class.getName())) { + StringBuilder sb = new StringBuilder(); + sb.append(configuration.getText("doclet.enum_valueof_doc.main", classDoc.name())); + sb.append("\n@param name "); + sb.append(configuration.getText("doclet.enum_valueof_doc.param_name")); + sb.append("\n@return "); + sb.append(configuration.getText("doclet.enum_valueof_doc.return")); + sb.append("\n@throws IllegalArgumentException "); + sb.append(configuration.getText("doclet.enum_valueof_doc.throws_ila")); + sb.append("\n@throws NullPointerException "); + sb.append(configuration.getText("doclet.enum_valueof_doc.throws_npe")); + currentMethod.setRawCommentText(sb.toString()); } } } From f8295608fb62b476f9ecbd07f5c851c51a109465 Mon Sep 17 00:00:00 2001 From: Jonathan Gibbons Date: Tue, 20 Aug 2013 14:55:20 -0700 Subject: [PATCH 081/218] 8022080: javadoc generates invalid HTML in Turkish locale Reviewed-by: bpatel --- .../tools/doclets/formats/html/markup/HtmlTag.java | 4 +++- .../classes/com/sun/tools/doclint/HtmlTag.java | 13 +++++++++---- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/markup/HtmlTag.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/markup/HtmlTag.java index fe9f5545937..60895e00e97 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/markup/HtmlTag.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/markup/HtmlTag.java @@ -25,6 +25,8 @@ package com.sun.tools.doclets.formats.html.markup; +import java.util.Locale; + /** * Enum representing HTML tags. * @@ -115,7 +117,7 @@ public enum HtmlTag { HtmlTag(BlockType blockType, EndTag endTag ) { this.blockType = blockType; this.endTag = endTag; - this.value = name().toLowerCase(); + this.value = name().toLowerCase(Locale.US); } /** diff --git a/langtools/src/share/classes/com/sun/tools/doclint/HtmlTag.java b/langtools/src/share/classes/com/sun/tools/doclint/HtmlTag.java index 04753149340..f1bce7d6795 100644 --- a/langtools/src/share/classes/com/sun/tools/doclint/HtmlTag.java +++ b/langtools/src/share/classes/com/sun/tools/doclint/HtmlTag.java @@ -30,6 +30,7 @@ import java.util.Collections; import java.util.EnumMap; import java.util.EnumSet; import java.util.HashMap; +import java.util.Locale; import java.util.Map; import javax.lang.model.element.Name; @@ -345,7 +346,7 @@ public enum HtmlTag { WIDTH; public String getText() { - return name().toLowerCase(); + return toLowerCase(name()); } static final Map index = new HashMap(); @@ -424,11 +425,11 @@ public enum HtmlTag { } public String getText() { - return name().toLowerCase(); + return toLowerCase(name()); } public Attr getAttr(Name attrName) { - return Attr.index.get(attrName.toString().toLowerCase()); + return Attr.index.get(toLowerCase(attrName.toString())); } public AttrKind getAttrKind(Name attrName) { @@ -450,6 +451,10 @@ public enum HtmlTag { } static HtmlTag get(Name tagName) { - return index.get(tagName.toString().toLowerCase()); + return index.get(toLowerCase(tagName.toString())); + } + + private static String toLowerCase(String s) { + return s.toLowerCase(Locale.US); } } From c7b90c0ca45558a76816b59ea400d11998f9ba6c Mon Sep 17 00:00:00 2001 From: Jonathan Gibbons Date: Tue, 20 Aug 2013 15:12:16 -0700 Subject: [PATCH 082/218] 8013887: In class use, some tables are randomly unsorted Reviewed-by: bpatel --- .../tools/doclets/formats/html/ClassUseWriter.java | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/ClassUseWriter.java b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/ClassUseWriter.java index 90da398c685..056723e817b 100644 --- a/langtools/src/share/classes/com/sun/tools/doclets/formats/html/ClassUseWriter.java +++ b/langtools/src/share/classes/com/sun/tools/doclets/formats/html/ClassUseWriter.java @@ -25,8 +25,16 @@ package com.sun.tools.doclets.formats.html; -import java.io.*; -import java.util.*; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; import com.sun.javadoc.*; import com.sun.tools.doclets.formats.html.markup.*; @@ -95,7 +103,7 @@ public class ClassUseWriter extends SubWriterHolderWriter { super(configuration, filename); this.classdoc = classdoc; if (mapper.classToPackageAnnotations.containsKey(classdoc.qualifiedName())) - pkgToPackageAnnotations = new HashSet(mapper.classToPackageAnnotations.get(classdoc.qualifiedName())); + pkgToPackageAnnotations = new TreeSet(mapper.classToPackageAnnotations.get(classdoc.qualifiedName())); configuration.currentcd = classdoc; this.pkgSet = new TreeSet(); this.pkgToClassTypeParameter = pkgDivide(mapper.classToClassTypeParam); From b2e2be304684bc50b36ea7e53bf7844521cf91cd Mon Sep 17 00:00:00 2001 From: Mike Duigou Date: Tue, 20 Aug 2013 17:44:35 -0700 Subject: [PATCH 083/218] 8023433: Improve 'make help' Reviewed-by: tbell --- NewMakefile.gmk | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/NewMakefile.gmk b/NewMakefile.gmk index 101ebe06278..4ddbc89c841 100644 --- a/NewMakefile.gmk +++ b/NewMakefile.gmk @@ -98,6 +98,7 @@ help: $(info . # corba and jdk) $(info . make all # Compile everything, all repos and images) $(info . make images # Create complete j2sdk and j2re images) + $(info . make docs # Create javadocs) $(info . make overlay-images # Create limited images for sparc 64 bit platforms) $(info . make profiles # Create complete j2re compact profile images) $(info . make bootcycle-images # Build images twice, second time with newly build JDK) @@ -109,7 +110,7 @@ help: $(info . make test # Run tests, default is all tests (see TEST below)) $(info ) $(info Targets for specific components) - $(info (Component is any of langtools, corba, jaxp, jaxws, hotspot, jdk, images or overlay-images)) + $(info (Component is any of langtools, corba, jaxp, jaxws, hotspot, jdk, nashorn, images, overlay-images, docs or test)) $(info . make # Build and everything it depends on. ) $(info . make -only # Build only, without dependencies. This) $(info . # is faster but can result in incorrect build results!) From 1e740c466f8264e4538c1a1134db49486cdfba01 Mon Sep 17 00:00:00 2001 From: Staffan Larsen Date: Wed, 21 Aug 2013 13:18:52 +0200 Subject: [PATCH 084/218] 8022808: Kitchensink hangs on macos Use pthread_mach_thread_np() instead of mach_thread_self() to avoid leaking resources Reviewed-by: dholmes, rbackman --- hotspot/src/os/bsd/vm/os_bsd.cpp | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/hotspot/src/os/bsd/vm/os_bsd.cpp b/hotspot/src/os/bsd/vm/os_bsd.cpp index 55043ad243a..cc6d13e2c1d 100644 --- a/hotspot/src/os/bsd/vm/os_bsd.cpp +++ b/hotspot/src/os/bsd/vm/os_bsd.cpp @@ -642,13 +642,14 @@ objc_registerThreadWithCollector_t objc_registerThreadWithCollectorFunction = NU #endif #ifdef __APPLE__ -static uint64_t locate_unique_thread_id() { +static uint64_t locate_unique_thread_id(mach_port_t mach_thread_port) { // Additional thread_id used to correlate threads in SA thread_identifier_info_data_t m_ident_info; mach_msg_type_number_t count = THREAD_IDENTIFIER_INFO_COUNT; - thread_info(::mach_thread_self(), THREAD_IDENTIFIER_INFO, + thread_info(mach_thread_port, THREAD_IDENTIFIER_INFO, (thread_info_t) &m_ident_info, &count); + return m_ident_info.thread_id; } #endif @@ -679,9 +680,14 @@ static void *java_start(Thread *thread) { } #ifdef __APPLE__ - // thread_id is mach thread on macos - osthread->set_thread_id(::mach_thread_self()); - osthread->set_unique_thread_id(locate_unique_thread_id()); + // thread_id is mach thread on macos, which pthreads graciously caches and provides for us + mach_port_t thread_id = ::pthread_mach_thread_np(::pthread_self()); + guarantee(thread_id != 0, "thread id missing from pthreads"); + osthread->set_thread_id(thread_id); + + uint64_t unique_thread_id = locate_unique_thread_id(thread_id); + guarantee(unique_thread_id != 0, "unique thread id was not found"); + osthread->set_unique_thread_id(unique_thread_id); #else // thread_id is pthread_id on BSD osthread->set_thread_id(::pthread_self()); @@ -843,8 +849,14 @@ bool os::create_attached_thread(JavaThread* thread) { // Store pthread info into the OSThread #ifdef __APPLE__ - osthread->set_thread_id(::mach_thread_self()); - osthread->set_unique_thread_id(locate_unique_thread_id()); + // thread_id is mach thread on macos, which pthreads graciously caches and provides for us + mach_port_t thread_id = ::pthread_mach_thread_np(::pthread_self()); + guarantee(thread_id != 0, "just checking"); + osthread->set_thread_id(thread_id); + + uint64_t unique_thread_id = locate_unique_thread_id(thread_id); + guarantee(unique_thread_id != 0, "just checking"); + osthread->set_unique_thread_id(unique_thread_id); #else osthread->set_thread_id(::pthread_self()); #endif @@ -1115,7 +1127,7 @@ size_t os::lasterror(char *buf, size_t len) { intx os::current_thread_id() { #ifdef __APPLE__ - return (intx)::mach_thread_self(); + return (intx)::pthread_mach_thread_np(::pthread_self()); #else return (intx)::pthread_self(); #endif From 6db516232b4e0ffba6327106dc3b3987f397001b Mon Sep 17 00:00:00 2001 From: Attila Szegedi Date: Wed, 21 Aug 2013 13:39:09 +0200 Subject: [PATCH 085/218] 8023373: allow super invocation for adapters Reviewed-by: lagergren, sundar --- .../linker/JavaAdapterBytecodeGenerator.java | 92 ++++++++++++++----- nashorn/test/script/basic/JDK-8023373.js | 84 +++++++++++++++++ .../test/script/basic/JDK-8023373.js.EXPECTED | 10 ++ 3 files changed, 161 insertions(+), 25 deletions(-) create mode 100644 nashorn/test/script/basic/JDK-8023373.js create mode 100644 nashorn/test/script/basic/JDK-8023373.js.EXPECTED diff --git a/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterBytecodeGenerator.java b/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterBytecodeGenerator.java index efbf7cf623e..62e529bb89f 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterBytecodeGenerator.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterBytecodeGenerator.java @@ -173,6 +173,9 @@ final class JavaAdapterBytecodeGenerator { private static final String CLASS_INIT = ""; private static final String STATIC_GLOBAL_FIELD_NAME = "staticGlobal"; + // Method name prefix for invoking super-methods + private static final String SUPER_PREFIX = "super$"; + /** * Collection of methods we never override: Object.clone(), Object.finalize(). */ @@ -240,6 +243,7 @@ final class JavaAdapterBytecodeGenerator { } generateConstructors(); generateMethods(); + generateSuperMethods(); // } cw.visitEnd(); } @@ -507,6 +511,10 @@ final class JavaAdapterBytecodeGenerator { private static void endInitMethod(final InstructionAdapter mv) { mv.visitInsn(RETURN); + endMethod(mv); + } + + private static void endMethod(final InstructionAdapter mv) { mv.visitMaxs(0, 0); mv.visitEnd(); } @@ -603,13 +611,8 @@ final class JavaAdapterBytecodeGenerator { */ private void generateMethod(final MethodInfo mi) { final Method method = mi.method; - final int mod = method.getModifiers(); - final int access = ACC_PUBLIC | (method.isVarArgs() ? ACC_VARARGS : 0); final Class[] exceptions = method.getExceptionTypes(); - final String[] exceptionNames = new String[exceptions.length]; - for (int i = 0; i < exceptions.length; ++i) { - exceptionNames[i] = Type.getInternalName(exceptions[i]); - } + final String[] exceptionNames = getExceptionNames(exceptions); final MethodType type = mi.type; final String methodDesc = type.toMethodDescriptorString(); final String name = mi.getName(); @@ -617,14 +620,8 @@ final class JavaAdapterBytecodeGenerator { final Type asmType = Type.getMethodType(methodDesc); final Type[] asmArgTypes = asmType.getArgumentTypes(); - // Determine the first index for a local variable - int nextLocalVar = 1; // this - for(final Type t: asmArgTypes) { - nextLocalVar += t.getSize(); - } - - final InstructionAdapter mv = new InstructionAdapter(cw.visitMethod(access, name, methodDesc, null, - exceptionNames)); + final InstructionAdapter mv = new InstructionAdapter(cw.visitMethod(getAccessModifiers(method), name, + methodDesc, null, exceptionNames)); mv.visitCode(); final Label instanceHandleDefined = new Label(); @@ -646,7 +643,7 @@ final class JavaAdapterBytecodeGenerator { } // No handle is available, fall back to default behavior - if(Modifier.isAbstract(mod)) { + if(Modifier.isAbstract(method.getModifiers())) { // If the super method is abstract, throw an exception mv.anew(UNSUPPORTED_OPERATION_TYPE); mv.dup(); @@ -654,14 +651,7 @@ final class JavaAdapterBytecodeGenerator { mv.athrow(); } else { // If the super method is not abstract, delegate to it. - mv.visitVarInsn(ALOAD, 0); - int nextParam = 1; - for(final Type t: asmArgTypes) { - mv.load(nextParam, t); - nextParam += t.getSize(); - } - mv.invokespecial(superClassName, name, methodDesc); - mv.areturn(asmReturnType); + emitSuperCall(mv, name, methodDesc); } final Label setupGlobal = new Label(); @@ -685,6 +675,12 @@ final class JavaAdapterBytecodeGenerator { // stack: [creatingGlobal, someHandle] mv.visitLabel(setupGlobal); + // Determine the first index for a local variable + int nextLocalVar = 1; // "this" is at 0 + for(final Type t: asmArgTypes) { + nextLocalVar += t.getSize(); + } + // Set our local variable indices final int currentGlobalVar = nextLocalVar++; final int globalsDifferVar = nextLocalVar++; @@ -775,8 +771,7 @@ final class JavaAdapterBytecodeGenerator { } mv.visitTryCatchBlock(tryBlockStart, tryBlockEnd, throwableHandler, THROWABLE_TYPE_NAME); } - mv.visitMaxs(0, 0); - mv.visitEnd(); + endMethod(mv); } /** @@ -817,6 +812,53 @@ final class JavaAdapterBytecodeGenerator { return false; } + private void generateSuperMethods() { + for(final MethodInfo mi: methodInfos) { + if(!Modifier.isAbstract(mi.method.getModifiers())) { + generateSuperMethod(mi); + } + } + } + + private void generateSuperMethod(MethodInfo mi) { + final Method method = mi.method; + + final String methodDesc = mi.type.toMethodDescriptorString(); + final String name = mi.getName(); + + final InstructionAdapter mv = new InstructionAdapter(cw.visitMethod(getAccessModifiers(method), + SUPER_PREFIX + name, methodDesc, null, getExceptionNames(method.getExceptionTypes()))); + mv.visitCode(); + + emitSuperCall(mv, name, methodDesc); + + endMethod(mv); + } + + private void emitSuperCall(final InstructionAdapter mv, final String name, final String methodDesc) { + mv.visitVarInsn(ALOAD, 0); + int nextParam = 1; + final Type methodType = Type.getMethodType(methodDesc); + for(final Type t: methodType.getArgumentTypes()) { + mv.load(nextParam, t); + nextParam += t.getSize(); + } + mv.invokespecial(superClassName, name, methodDesc); + mv.areturn(methodType.getReturnType()); + } + + private static String[] getExceptionNames(final Class[] exceptions) { + final String[] exceptionNames = new String[exceptions.length]; + for (int i = 0; i < exceptions.length; ++i) { + exceptionNames[i] = Type.getInternalName(exceptions[i]); + } + return exceptionNames; + } + + private static int getAccessModifiers(final Method method) { + return ACC_PUBLIC | (method.isVarArgs() ? ACC_VARARGS : 0); + } + /** * Gathers methods that can be implemented or overridden from the specified type into this factory's * {@link #methodInfos} set. It will add all non-final, non-static methods that are either public or protected from diff --git a/nashorn/test/script/basic/JDK-8023373.js b/nashorn/test/script/basic/JDK-8023373.js new file mode 100644 index 00000000000..1a01982020f --- /dev/null +++ b/nashorn/test/script/basic/JDK-8023373.js @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * JDK-8023373: allow super invocation for adapters + * + * @test + * @run + */ + +var CharArray = Java.type("char[]") +var jString = Java.type("java.lang.String") +var Character = Java.type("java.lang.Character") + +function capitalize(s) { + if(s instanceof CharArray) { + return new jString(s).toUpperCase() + } + if(s instanceof jString) { + return s.toUpperCase() + } + return Character.toUpperCase(s) // must be int +} + +var sw = new (Java.type("java.io.StringWriter")) + +var FilterWriterAdapter = Java.extend(Java.type("java.io.FilterWriter")) + +var cw = new FilterWriterAdapter(sw) { + write: function(s, off, len) { + s = capitalize(s) + // Must handle overloads by arity + if(off === undefined) { + cw.super$write(s, 0, s.length()) + } else if (typeof s === "string") { + cw.super$write(s, off, len) + } + } +} + +cw.write("abcd") +cw.write("e".charAt(0)) +cw.write("fgh".toCharArray()) +cw.write("**ijk**", 2, 3) +cw.write("***lmno**".toCharArray(), 3, 4) +cw.flush() +print(sw) + +// Can invoke super for Object methods +print("cw has super hashCode(): " + (typeof cw.super$hashCode === "function")) +print("cw has super equals(): " + (typeof cw.super$equals === "function")) +// Can't invoke super for final methods +print("cw has no super getClass(): " + (typeof cw.super$getClass === "undefined")) +print("cw has no super wait(): " + (typeof cw.super$wait === "undefined")) + +var r = new (Java.type("java.lang.Runnable"))(function() {}) +// Can't invoke super for abstract methods +print("r has no super run(): " + (typeof r.super$run === "undefined")) +// Interfaces can also invoke super Object methods +print("r has super hashCode(): " + (typeof r.super$hashCode === "function")) +print("r has super equals(): " + (typeof r.super$equals === "function")) +// But still can't invoke final methods +print("r has no super getClass(): " + (typeof r.super$getClass === "undefined")) +print("r has no super wait(): " + (typeof r.super$wait === "undefined")) diff --git a/nashorn/test/script/basic/JDK-8023373.js.EXPECTED b/nashorn/test/script/basic/JDK-8023373.js.EXPECTED new file mode 100644 index 00000000000..765eff267c4 --- /dev/null +++ b/nashorn/test/script/basic/JDK-8023373.js.EXPECTED @@ -0,0 +1,10 @@ +ABCDEFGHIJKLMNO +cw has super hashCode(): true +cw has super equals(): true +cw has no super getClass(): true +cw has no super wait(): true +r has no super run(): true +r has super hashCode(): true +r has super equals(): true +r has no super getClass(): true +r has no super wait(): true From 00099d7de244cc41b6bef1852e2f81c001fce596 Mon Sep 17 00:00:00 2001 From: Attila Szegedi Date: Wed, 21 Aug 2013 13:39:40 +0200 Subject: [PATCH 086/218] 8022903: Enhance for-in and for-each for Lists and Maps Reviewed-by: lagergren, sundar --- .../internal/runtime/ScriptRuntime.java | 82 +++++++++++++------ nashorn/test/script/basic/JDK-8022903.js | 55 +++++++++++++ .../test/script/basic/JDK-8022903.js.EXPECTED | 12 +++ 3 files changed, 122 insertions(+), 27 deletions(-) create mode 100644 nashorn/test/script/basic/JDK-8022903.js create mode 100644 nashorn/test/script/basic/JDK-8022903.js.EXPECTED diff --git a/nashorn/src/jdk/nashorn/internal/runtime/ScriptRuntime.java b/nashorn/src/jdk/nashorn/internal/runtime/ScriptRuntime.java index 53c4d4fee78..05ccc9f2876 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptRuntime.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptRuntime.java @@ -37,7 +37,9 @@ import java.lang.invoke.MethodHandles; import java.lang.reflect.Array; import java.util.Collections; import java.util.Iterator; +import java.util.List; import java.util.Locale; +import java.util.Map; import java.util.NoSuchElementException; import java.util.Objects; import jdk.internal.dynalink.beans.StaticClass; @@ -221,49 +223,71 @@ public final class ScriptRuntime { } /** - * Used to determine property iterator used in for in. - * @param obj Object to iterate on. - * @return Iterator. + * Returns an iterator over property identifiers used in the {@code for...in} statement. Note that the ECMAScript + * 5.1 specification, chapter 12.6.4. uses the terminology "property names", which seems to imply that the property + * identifiers are expected to be strings, but this is not actually spelled out anywhere, and Nashorn will in some + * cases deviate from this. Namely, we guarantee to always return an iterator over {@link String} values for any + * built-in JavaScript object. We will however return an iterator over {@link Integer} objects for native Java + * arrays and {@link List} objects, as well as arbitrary objects representing keys of a {@link Map}. Therefore, the + * expression {@code typeof i} within a {@code for(i in obj)} statement can return something other than + * {@code string} when iterating over native Java arrays, {@code List}, and {@code Map} objects. + * @param obj object to iterate on. + * @return iterator over the object's property names. */ - public static Iterator toPropertyIterator(final Object obj) { + public static Iterator toPropertyIterator(final Object obj) { if (obj instanceof ScriptObject) { return ((ScriptObject)obj).propertyIterator(); } if (obj != null && obj.getClass().isArray()) { - final int length = Array.getLength(obj); - - return new Iterator() { - private int index = 0; - - @Override - public boolean hasNext() { - return index < length; - } - - @Override - public String next() { - return "" + index++; //TODO numeric property iterator? - } - - @Override - public void remove() { - throw new UnsupportedOperationException(); - } - }; + return new RangeIterator(Array.getLength(obj)); } if (obj instanceof ScriptObjectMirror) { return ((ScriptObjectMirror)obj).keySet().iterator(); } + if (obj instanceof List) { + return new RangeIterator(((List)obj).size()); + } + + if (obj instanceof Map) { + return ((Map)obj).keySet().iterator(); + } + return Collections.emptyIterator(); } + private static final class RangeIterator implements Iterator { + private final int length; + private int index; + + RangeIterator(int length) { + this.length = length; + } + + @Override + public boolean hasNext() { + return index < length; + } + + @Override + public Integer next() { + return index++; + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + } + /** - * Used to determine property value iterator used in for each in. - * @param obj Object to iterate on. - * @return Iterator. + * Returns an iterator over property values used in the {@code for each...in} statement. Aside from built-in JS + * objects, it also operates on Java arrays, any {@link Iterable}, as well as on {@link Map} objects, iterating over + * map values. + * @param obj object to iterate on. + * @return iterator over the object's property values. */ public static Iterator toValueIterator(final Object obj) { if (obj instanceof ScriptObject) { @@ -301,6 +325,10 @@ public final class ScriptRuntime { return ((ScriptObjectMirror)obj).values().iterator(); } + if (obj instanceof Map) { + return ((Map)obj).values().iterator(); + } + if (obj instanceof Iterable) { return ((Iterable)obj).iterator(); } diff --git a/nashorn/test/script/basic/JDK-8022903.js b/nashorn/test/script/basic/JDK-8022903.js new file mode 100644 index 00000000000..1733c51a4fa --- /dev/null +++ b/nashorn/test/script/basic/JDK-8022903.js @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * JDK-8022903: Enhance for-in and for-each for Lists and Maps + * + * @test + * @run + */ + +var colors = new java.util.ArrayList() +colors.add("red") +colors.add("purple") +colors.add("pink") + +for(var index in colors) { + print("colors[" + index + "]=" + colors[index]) +} + +for each(var color in colors) { + print(color) +} + +var capitals = new java.util.LinkedHashMap() +capitals.Sweden = "Stockholm" +capitals.Hungary = "Budapet" +capitals.Croatia = "Zagreb" + +for(var key in capitals) { + print("capital of " + key + " is " + capitals[key]) +} + +for each(var capital in capitals) { + print(capital) +} diff --git a/nashorn/test/script/basic/JDK-8022903.js.EXPECTED b/nashorn/test/script/basic/JDK-8022903.js.EXPECTED new file mode 100644 index 00000000000..8d64baeb0c7 --- /dev/null +++ b/nashorn/test/script/basic/JDK-8022903.js.EXPECTED @@ -0,0 +1,12 @@ +colors[0]=red +colors[1]=purple +colors[2]=pink +red +purple +pink +capital of Sweden is Stockholm +capital of Hungary is Budapet +capital of Croatia is Zagreb +Stockholm +Budapet +Zagreb From 2bb4ab07cab8d4cc7756bfb80a70aace7c0b91fd Mon Sep 17 00:00:00 2001 From: Athijegannathan Sundararajan Date: Wed, 21 Aug 2013 17:28:53 +0530 Subject: [PATCH 087/218] 8023368: Instance __proto__ property should exist and be writable Reviewed-by: attila, hannesw --- .../api/scripting/ScriptObjectMirror.java | 13 ++++ .../internal/objects/NativeObject.java | 24 +++++- .../internal/runtime/PropertyListener.java | 9 +++ .../runtime/PropertyListenerManager.java | 20 +++++ .../nashorn/internal/runtime/PropertyMap.java | 23 +++++- .../internal/runtime/ScriptEnvironment.java | 4 - .../internal/runtime/ScriptObject.java | 15 ++++ .../runtime/resources/Messages.properties | 2 + .../runtime/resources/Options.properties | 9 --- .../runtime/resources/mozilla_compat.js | 2 +- nashorn/test/script/basic/JDK-8023368.js | 73 +++++++++++++++++++ .../test/script/basic/JDK-8023368.js.EXPECTED | 18 +++++ nashorn/test/script/basic/JDK-8023368_2.js | 73 +++++++++++++++++++ .../script/basic/JDK-8023368_2.js.EXPECTED | 18 +++++ nashorn/test/script/basic/circular_proto.js | 46 ++++++++++++ .../script/basic/circular_proto.js.EXPECTED | 1 + .../test/script/basic/mirror_proto_assign.js | 52 +++++++++++++ .../basic/mirror_proto_assign.js.EXPECTED | 2 + .../basic/nonextensible_proto_assign.js | 44 +++++++++++ .../nonextensible_proto_assign.js.EXPECTED | 1 + 20 files changed, 433 insertions(+), 16 deletions(-) create mode 100644 nashorn/test/script/basic/JDK-8023368.js create mode 100644 nashorn/test/script/basic/JDK-8023368.js.EXPECTED create mode 100644 nashorn/test/script/basic/JDK-8023368_2.js create mode 100644 nashorn/test/script/basic/JDK-8023368_2.js.EXPECTED create mode 100644 nashorn/test/script/basic/circular_proto.js create mode 100644 nashorn/test/script/basic/circular_proto.js.EXPECTED create mode 100644 nashorn/test/script/basic/mirror_proto_assign.js create mode 100644 nashorn/test/script/basic/mirror_proto_assign.js.EXPECTED create mode 100644 nashorn/test/script/basic/nonextensible_proto_assign.js create mode 100644 nashorn/test/script/basic/nonextensible_proto_assign.js.EXPECTED diff --git a/nashorn/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java b/nashorn/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java index fd2ef88a199..dbdb9b67bd5 100644 --- a/nashorn/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java +++ b/nashorn/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java @@ -373,6 +373,19 @@ public final class ScriptObjectMirror extends JSObject implements Bindings { }); } + /** + * Set the __proto__ of this object. + * @param proto new proto for this object + */ + public void setProto(final Object proto) { + inGlobal(new Callable() { + @Override public Void call() { + sobj.setProtoCheck(unwrap(proto, global)); + return null; + } + }); + } + /** * ECMA 8.12.1 [[GetOwnProperty]] (P) * diff --git a/nashorn/src/jdk/nashorn/internal/objects/NativeObject.java b/nashorn/src/jdk/nashorn/internal/objects/NativeObject.java index 537ae1ffcc5..932f328bff6 100644 --- a/nashorn/src/jdk/nashorn/internal/objects/NativeObject.java +++ b/nashorn/src/jdk/nashorn/internal/objects/NativeObject.java @@ -124,6 +124,28 @@ public final class NativeObject { } } + /** + * Nashorn extension: Object.setPrototypeOf ( O, proto ) + * Also found in ES6 draft specification. + * + * @param self self reference + * @param obj object to set prototype for + * @param proto prototype object to be used + * @return object whose prototype is set + */ + @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) + public static Object setPrototypeOf(final Object self, final Object obj, final Object proto) { + if (obj instanceof ScriptObject) { + ((ScriptObject)obj).setProtoCheck(proto); + return obj; + } else if (obj instanceof ScriptObjectMirror) { + ((ScriptObjectMirror)obj).setProto(proto); + return obj; + } + + throw notAnObject(obj); + } + /** * ECMA 15.2.3.3 Object.getOwnPropertyDescriptor ( O, P ) * @@ -184,7 +206,7 @@ public final class NativeObject { // FIXME: should we create a proper object with correct number of // properties? final ScriptObject newObj = Global.newEmptyInstance(); - newObj.setProtoCheck(proto); + newObj.setProto((ScriptObject)proto); if (props != UNDEFINED) { NativeObject.defineProperties(self, newObj, props); } diff --git a/nashorn/src/jdk/nashorn/internal/runtime/PropertyListener.java b/nashorn/src/jdk/nashorn/internal/runtime/PropertyListener.java index 867ac73d1b4..307d58b4f7d 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/PropertyListener.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/PropertyListener.java @@ -54,4 +54,13 @@ public interface PropertyListener { * */ public void propertyModified(ScriptObject object, Property oldProp, Property newProp); + + /** + * Given object's __proto__ has changed. + * + * @param object object whose __proto__ has changed. + * @param oldProto old __proto__ + * @param newProto new __proto__ + */ + public void protoChanged(ScriptObject object, ScriptObject oldProto, ScriptObject newProto); } diff --git a/nashorn/src/jdk/nashorn/internal/runtime/PropertyListenerManager.java b/nashorn/src/jdk/nashorn/internal/runtime/PropertyListenerManager.java index dc1426d827c..27ec2c97438 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/PropertyListenerManager.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/PropertyListenerManager.java @@ -140,6 +140,21 @@ public class PropertyListenerManager implements PropertyListener { } } + /** + * This method can be called to notify __proto__ modification to this object's listeners. + * + * @param object The ScriptObject whose __proto__ was changed. + * @param oldProto old __proto__ + * @param newProto new __proto__ + */ + protected synchronized final void notifyProtoChanged(final ScriptObject object, final ScriptObject oldProto, final ScriptObject newProto) { + if (listeners != null) { + for (PropertyListener listener : listeners.keySet()) { + listener.protoChanged(object, oldProto, newProto); + } + } + } + // PropertyListener methods @Override @@ -156,4 +171,9 @@ public class PropertyListenerManager implements PropertyListener { public final void propertyModified(final ScriptObject object, final Property oldProp, final Property newProp) { notifyPropertyModified(object, oldProp, newProp); } + + @Override + public final void protoChanged(final ScriptObject object, final ScriptObject oldProto, final ScriptObject newProto) { + notifyProtoChanged(object, oldProto, newProto); + } } diff --git a/nashorn/src/jdk/nashorn/internal/runtime/PropertyMap.java b/nashorn/src/jdk/nashorn/internal/runtime/PropertyMap.java index 64f4b449079..e24364d6f03 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/PropertyMap.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/PropertyMap.java @@ -230,7 +230,7 @@ public final class PropertyMap implements Iterable, PropertyListener { } /** - * Indicate that a prototype property hash changed. + * Indicate that a prototype property has changed. * * @param property {@link Property} to invalidate. */ @@ -250,6 +250,18 @@ public final class PropertyMap implements Iterable, PropertyListener { } } + /** + * Indicate that proto itself has changed in hierachy somewhere. + */ + private void invalidateAllProtoGetSwitchPoints() { + assert !isShared() : "proto invalidation on a shared PropertyMap"; + + if (protoGetSwitches != null) { + final Collection sws = protoGetSwitches.values(); + SwitchPoint.invalidateAll(sws.toArray(new SwitchPoint[sws.size()])); + } + } + /** * Add a property to the map, re-binding its getters and setters, * if available, to a given receiver. This is typically the global scope. See @@ -878,6 +890,15 @@ public final class PropertyMap implements Iterable, PropertyListener { invalidateProtoGetSwitchPoint(oldProp); } + @Override + public void protoChanged(final ScriptObject object, final ScriptObject oldProto, final ScriptObject newProto) { + // We may walk and invalidate SwitchPoints for properties inherited + // from 'object' or it's old proto chain. But, it may not be worth it. + // For example, a new proto may have a user defined getter/setter for + // a data property down the chain. So, invalidating all is better. + invalidateAllProtoGetSwitchPoints(); + } + /* * Debugging and statistics. */ diff --git a/nashorn/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java b/nashorn/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java index a2f1f4a0880..8ab6af48ab1 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java @@ -128,9 +128,6 @@ public final class ScriptEnvironment { /** Do not support typed arrays. */ public final boolean _no_typed_arrays; - /** Package to which generated class files are added */ - public final String _package; - /** Only parse the source code, do not compile */ public final boolean _parse_only; @@ -216,7 +213,6 @@ public final class ScriptEnvironment { _no_java = options.getBoolean("no.java"); _no_syntax_extensions = options.getBoolean("no.syntax.extensions"); _no_typed_arrays = options.getBoolean("no.typed.arrays"); - _package = options.getString("package"); _parse_only = options.getBoolean("parse.only"); _print_ast = options.getBoolean("print.ast"); _print_lower_ast = options.getBoolean("print.lower.ast"); diff --git a/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java b/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java index 1087005b992..481a708bcb7 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java @@ -1129,6 +1129,9 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr proto = newProto; if (isPrototype()) { + // tell listeners that my __proto__ has been changed + notifyProtoChanged(this, oldProto, newProto); + if (oldProto != null) { oldProto.removePropertyListener(this); } @@ -1144,7 +1147,19 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr * @param newProto Prototype to set. */ public final void setProtoCheck(final Object newProto) { + if (!isExtensible()) { + throw typeError("__proto__.set.non.extensible", ScriptRuntime.safeToString(this)); + } + if (newProto == null || newProto instanceof ScriptObject) { + // check for circularity + ScriptObject proto = (ScriptObject)newProto; + while (proto != null) { + if (proto == this) { + throw typeError("circular.__proto__.set", ScriptRuntime.safeToString(this)); + } + proto = proto.getProto(); + } setProto((ScriptObject)newProto); } else { final ScriptObject global = Context.getGlobalTrusted(); diff --git a/nashorn/src/jdk/nashorn/internal/runtime/resources/Messages.properties b/nashorn/src/jdk/nashorn/internal/runtime/resources/Messages.properties index dadde63756f..68f68c0a25b 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/resources/Messages.properties +++ b/nashorn/src/jdk/nashorn/internal/runtime/resources/Messages.properties @@ -94,6 +94,8 @@ type.error.cant.delete.property=Cannot delete property "{0}" of {1} type.error.cant.redefine.property=Cannot redefine property "{0}" of {1} type.error.property.not.writable="{0}" is not a writable property of {1} type.error.object.non.extensible=Cannot add new property "{0}" to non-extensible {1} +type.error.__proto__.set.non.extensible=Cannot set __proto__ of non-extensible {0} +type.error.circular.__proto__.set=Cannot create__proto__ cycle for {0} # miscellaneous type.error.regex.cant.supply.flags=Cannot supply flags when constructing one RegExp from another diff --git a/nashorn/src/jdk/nashorn/internal/runtime/resources/Options.properties b/nashorn/src/jdk/nashorn/internal/runtime/resources/Options.properties index 452ae88c928..e3510fa1004 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/resources/Options.properties +++ b/nashorn/src/jdk/nashorn/internal/runtime/resources/Options.properties @@ -216,15 +216,6 @@ nashorn.option.no.typed.arrays = { \ default=false \ } -nashorn.option.package = { \ - name="--package", \ - is_undocumented=true, \ - desc="Package to which generated .class files are added.", \ - params="", \ - type=String, \ - default="" \ -} - nashorn.option.parse.only = { \ name="--parse-only", \ is_undocumented=true, \ diff --git a/nashorn/src/jdk/nashorn/internal/runtime/resources/mozilla_compat.js b/nashorn/src/jdk/nashorn/internal/runtime/resources/mozilla_compat.js index 8a9fcc7de0c..60bdc7b1ab0 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/resources/mozilla_compat.js +++ b/nashorn/src/jdk/nashorn/internal/runtime/resources/mozilla_compat.js @@ -144,7 +144,7 @@ Object.defineProperty(Object.prototype, "__proto__", { return Object.getPrototypeOf(this); }, set: function(x) { - throw new TypeError("__proto__ set not supported"); + Object.setPrototypeOf(this, x); } }); diff --git a/nashorn/test/script/basic/JDK-8023368.js b/nashorn/test/script/basic/JDK-8023368.js new file mode 100644 index 00000000000..9f32805caa8 --- /dev/null +++ b/nashorn/test/script/basic/JDK-8023368.js @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * JDK-8023368: Instance __proto__ property should exist and be writable. + * + * @test + * @run + */ + +load("nashorn:mozilla_compat.js"); + +// function to force same callsites +function check(obj) { + print(obj.func()); + print(obj.x); + print(obj.toString()); +} + +function Func() { +} + +Func.prototype.func = function() { + return "Func.prototype.func"; +} + +Func.prototype.x = "hello"; + +var obj = new Func(); +var obj2 = Object.create(obj); + +// check direct and indirect __proto__ change +check(obj); +check(obj2); +obj.__proto__ = { + func: function() { + return "obj.__proto__.func @ " + __LINE__; + }, + x: 344 +}; + +check(obj); +check(obj2); + +// check indirect (1 and 2 levels) __proto__ function change +obj.__proto__.__proto__ = { + toString: function() { + return "new object.toString"; + } +}; + +check(obj); +check(obj2); diff --git a/nashorn/test/script/basic/JDK-8023368.js.EXPECTED b/nashorn/test/script/basic/JDK-8023368.js.EXPECTED new file mode 100644 index 00000000000..4ca8d077d38 --- /dev/null +++ b/nashorn/test/script/basic/JDK-8023368.js.EXPECTED @@ -0,0 +1,18 @@ +Func.prototype.func +hello +[object Object] +Func.prototype.func +hello +[object Object] +obj.__proto__.func @ 57 +344 +[object Object] +obj.__proto__.func @ 57 +344 +[object Object] +obj.__proto__.func @ 57 +344 +new object.toString +obj.__proto__.func @ 57 +344 +new object.toString diff --git a/nashorn/test/script/basic/JDK-8023368_2.js b/nashorn/test/script/basic/JDK-8023368_2.js new file mode 100644 index 00000000000..4999de1d89e --- /dev/null +++ b/nashorn/test/script/basic/JDK-8023368_2.js @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * JDK-8023368: Instance __proto__ property should exist and be writable. + * + * @test + * @run + */ + +// check Object.setPrototypeOf extension rather than using __proto__ + +// function to force same callsites +function check(obj) { + print(obj.func()); + print(obj.x); + print(obj.toString()); +} + +function Func() { +} + +Func.prototype.func = function() { + return "Func.prototype.func"; +} + +Func.prototype.x = "hello"; + +var obj = new Func(); +var obj2 = Object.create(obj); + +// check direct and indirect __proto__ change +check(obj); +check(obj2); +Object.setPrototypeOf(obj, { + func: function() { + return "obj.__proto__.func @ " + __LINE__; + }, + x: 344 +}); + +check(obj); +check(obj2); + +// check indirect (1 and 2 levels) __proto__ function change +Object.setPrototypeOf(Object.getPrototypeOf(obj), { + toString: function() { + return "new object.toString"; + } +}); + +check(obj); +check(obj2); diff --git a/nashorn/test/script/basic/JDK-8023368_2.js.EXPECTED b/nashorn/test/script/basic/JDK-8023368_2.js.EXPECTED new file mode 100644 index 00000000000..4ca8d077d38 --- /dev/null +++ b/nashorn/test/script/basic/JDK-8023368_2.js.EXPECTED @@ -0,0 +1,18 @@ +Func.prototype.func +hello +[object Object] +Func.prototype.func +hello +[object Object] +obj.__proto__.func @ 57 +344 +[object Object] +obj.__proto__.func @ 57 +344 +[object Object] +obj.__proto__.func @ 57 +344 +new object.toString +obj.__proto__.func @ 57 +344 +new object.toString diff --git a/nashorn/test/script/basic/circular_proto.js b/nashorn/test/script/basic/circular_proto.js new file mode 100644 index 00000000000..5ae8f9cd03b --- /dev/null +++ b/nashorn/test/script/basic/circular_proto.js @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * JDK-8023368: Instance __proto__ property should exist and be writable. + * + * @test + * @run + */ + +// check that we cannot create __proto__ cycle +load("nashorn:mozilla_compat.js"); + +var obj = {}; +var obj2 = Object.create(obj); + +// attempt to create __proto__ cycle +try { + obj.__proto__ = obj2; + fail("Should have thrown TypeError"); +} catch (e) { + if (! (e instanceof TypeError)) { + fail("Expected TypeError, got " + e); + } + print(e); +} diff --git a/nashorn/test/script/basic/circular_proto.js.EXPECTED b/nashorn/test/script/basic/circular_proto.js.EXPECTED new file mode 100644 index 00000000000..66b541b6dfc --- /dev/null +++ b/nashorn/test/script/basic/circular_proto.js.EXPECTED @@ -0,0 +1 @@ +TypeError: Cannot create__proto__ cycle for [object Object] diff --git a/nashorn/test/script/basic/mirror_proto_assign.js b/nashorn/test/script/basic/mirror_proto_assign.js new file mode 100644 index 00000000000..d748cbc40ca --- /dev/null +++ b/nashorn/test/script/basic/mirror_proto_assign.js @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * JDK-8023368: Instance __proto__ property should exist and be writable. + * + * @test + * @run + */ + +// check that Object.setPrototypeOf works for mirror objects as well. + +var global = loadWithNewGlobal({ + name: "test", + script: "var obj = {}; this" +}); + +var proto = global.eval("({ foo: 323 })"); + +Object.setPrototypeOf(global.obj, proto); + +function func(obj) { + // check proto inherited value + print("obj.foo = " + obj.foo); +} + +func(global.obj); + +var newProto = global.eval("({ foo: 'hello' })"); +Object.setPrototypeOf(global.obj, newProto); + +func(global.obj); diff --git a/nashorn/test/script/basic/mirror_proto_assign.js.EXPECTED b/nashorn/test/script/basic/mirror_proto_assign.js.EXPECTED new file mode 100644 index 00000000000..168d50e06f8 --- /dev/null +++ b/nashorn/test/script/basic/mirror_proto_assign.js.EXPECTED @@ -0,0 +1,2 @@ +obj.foo = 323 +obj.foo = hello diff --git a/nashorn/test/script/basic/nonextensible_proto_assign.js b/nashorn/test/script/basic/nonextensible_proto_assign.js new file mode 100644 index 00000000000..0240420d332 --- /dev/null +++ b/nashorn/test/script/basic/nonextensible_proto_assign.js @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * JDK-8023368: Instance __proto__ property should exist and be writable. + * + * @test + * @run + */ + +load("nashorn:mozilla_compat.js") + +// check that we cannot assign to __proto__ of a non-extensible object +try { + var obj = {} + Object.preventExtensions(obj); + obj.__proto__ = { }; + fail("Should have thrown TypeError"); +} catch (e) { + if (! (e instanceof TypeError)) { + fail("Expected TypeError, got " + e); + } + print(e); +} diff --git a/nashorn/test/script/basic/nonextensible_proto_assign.js.EXPECTED b/nashorn/test/script/basic/nonextensible_proto_assign.js.EXPECTED new file mode 100644 index 00000000000..d9a6c2e9a0f --- /dev/null +++ b/nashorn/test/script/basic/nonextensible_proto_assign.js.EXPECTED @@ -0,0 +1 @@ +TypeError: Cannot set __proto__ of non-extensible [object Object] From 4c3c3b6caacc75eec2a3bfd4b66262a9b6c2e578 Mon Sep 17 00:00:00 2001 From: Bengt Rutisson Date: Wed, 21 Aug 2013 22:35:56 +0200 Subject: [PATCH 088/218] 8022872: G1: Use correct GC cause for young GC triggered by humongous allocations Reviewed-by: tonyp, tschatzl --- .../share/vm/gc_implementation/g1/g1CollectedHeap.cpp | 11 +++++++---- .../share/vm/gc_implementation/g1/g1CollectedHeap.hpp | 7 ++++--- .../vm/gc_implementation/g1/vm_operations_g1.cpp | 3 --- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp index 97a9a1fa54d..055474297a6 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp @@ -981,7 +981,8 @@ HeapWord* G1CollectedHeap::attempt_allocation_slow(size_t word_size, if (should_try_gc) { bool succeeded; - result = do_collection_pause(word_size, gc_count_before, &succeeded); + result = do_collection_pause(word_size, gc_count_before, &succeeded, + GCCause::_g1_inc_collection_pause); if (result != NULL) { assert(succeeded, "only way to get back a non-NULL result"); return result; @@ -1106,7 +1107,8 @@ HeapWord* G1CollectedHeap::attempt_allocation_humongous(size_t word_size, // enough space for the allocation to succeed after the pause. bool succeeded; - result = do_collection_pause(word_size, gc_count_before, &succeeded); + result = do_collection_pause(word_size, gc_count_before, &succeeded, + GCCause::_g1_humongous_allocation); if (result != NULL) { assert(succeeded, "only way to get back a non-NULL result"); return result; @@ -3700,14 +3702,15 @@ void G1CollectedHeap::gc_epilogue(bool full /* Ignored */) { HeapWord* G1CollectedHeap::do_collection_pause(size_t word_size, unsigned int gc_count_before, - bool* succeeded) { + bool* succeeded, + GCCause::Cause gc_cause) { assert_heap_not_locked_and_not_at_safepoint(); g1_policy()->record_stop_world_start(); VM_G1IncCollectionPause op(gc_count_before, word_size, false, /* should_initiate_conc_mark */ g1_policy()->max_pause_time_ms(), - GCCause::_g1_inc_collection_pause); + gc_cause); VMThread::execute(&op); HeapWord* result = op.result(); diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp index cfcbb3f7c94..aecaa5e97ac 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp @@ -776,9 +776,10 @@ protected: // it has to be read while holding the Heap_lock. Currently, both // methods that call do_collection_pause() release the Heap_lock // before the call, so it's easy to read gc_count_before just before. - HeapWord* do_collection_pause(size_t word_size, - unsigned int gc_count_before, - bool* succeeded); + HeapWord* do_collection_pause(size_t word_size, + unsigned int gc_count_before, + bool* succeeded, + GCCause::Cause gc_cause); // The guts of the incremental collection pause, executed by the vm // thread. It returns false if it is unable to do the collection due diff --git a/hotspot/src/share/vm/gc_implementation/g1/vm_operations_g1.cpp b/hotspot/src/share/vm/gc_implementation/g1/vm_operations_g1.cpp index 3be06e6ae10..9f298da3873 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/vm_operations_g1.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/vm_operations_g1.cpp @@ -70,9 +70,6 @@ VM_G1IncCollectionPause::VM_G1IncCollectionPause( guarantee(target_pause_time_ms > 0.0, err_msg("target_pause_time_ms = %1.6lf should be positive", target_pause_time_ms)); - guarantee(word_size == 0 || gc_cause == GCCause::_g1_inc_collection_pause, - "we can only request an allocation if the GC cause is for " - "an incremental GC pause"); _gc_cause = gc_cause; } From 1dc32a077ec0608953f56dd6468606a5cade28ac Mon Sep 17 00:00:00 2001 From: Werner Dietl Date: Wed, 21 Aug 2013 16:13:50 -0700 Subject: [PATCH 089/218] 8023515: import type-annotations updates Reviewed-by: jjg --- .../com/sun/source/tree/MethodTree.java | 8 + .../sun/source/tree/TypeParameterTree.java | 14 ++ .../com/sun/tools/javac/code/Printer.java | 12 +- .../sun/tools/javac/code/TypeAnnotations.java | 25 ++- .../sun/tools/javac/comp/LambdaToMethod.java | 2 +- .../com/sun/tools/javac/comp/MemberEnter.java | 2 +- .../JavacProcessingEnvironment.java | 2 +- .../tools/javac/resources/compiler.properties | 2 +- .../com/sun/tools/javac/tree/Pretty.java | 58 +++--- .../classfile/CombinationsTargetTest2.java | 84 +++++++-- .../failures/DummyProcessor.java | 43 +++++ .../typeAnnotations/failures/T8020715.java | 49 +++++ .../referenceinfos/Constructors.java | 20 +++ .../javac/tree/TypeAnnotationsPretty.java | 170 ++++++++++++++++++ 14 files changed, 429 insertions(+), 62 deletions(-) create mode 100644 langtools/test/tools/javac/annotations/typeAnnotations/failures/DummyProcessor.java create mode 100644 langtools/test/tools/javac/annotations/typeAnnotations/failures/T8020715.java create mode 100644 langtools/test/tools/javac/tree/TypeAnnotationsPretty.java diff --git a/langtools/src/share/classes/com/sun/source/tree/MethodTree.java b/langtools/src/share/classes/com/sun/source/tree/MethodTree.java index 8d9820ba5fe..987c3742767 100644 --- a/langtools/src/share/classes/com/sun/source/tree/MethodTree.java +++ b/langtools/src/share/classes/com/sun/source/tree/MethodTree.java @@ -53,7 +53,15 @@ public interface MethodTree extends Tree { Tree getReturnType(); List getTypeParameters(); List getParameters(); + + /** + * Return an explicit receiver parameter ("this" parameter). + * + * @return an explicit receiver parameter ("this" parameter) + * @since 1.8 + */ VariableTree getReceiverParameter(); + List getThrows(); BlockTree getBody(); Tree getDefaultValue(); // for annotation types diff --git a/langtools/src/share/classes/com/sun/source/tree/TypeParameterTree.java b/langtools/src/share/classes/com/sun/source/tree/TypeParameterTree.java index 293a38b35a5..6dd469a7601 100644 --- a/langtools/src/share/classes/com/sun/source/tree/TypeParameterTree.java +++ b/langtools/src/share/classes/com/sun/source/tree/TypeParameterTree.java @@ -36,6 +36,8 @@ import javax.lang.model.element.Name; * name * * name extends bounds + * + * annotations name * * * @jls section 4.4 @@ -48,5 +50,17 @@ import javax.lang.model.element.Name; public interface TypeParameterTree extends Tree { Name getName(); List getBounds(); + + /** + * Return annotations on the type parameter declaration. + * + * Annotations need Target meta-annotations of + * {@link java.lang.annotation.ElementType#TYPE_PARAMETER} or + * {@link java.lang.annotation.ElementType#TYPE_USE} + * to appear in this position. + * + * @return annotations on the type parameter declaration + * @since 1.8 + */ List getAnnotations(); } diff --git a/langtools/src/share/classes/com/sun/tools/javac/code/Printer.java b/langtools/src/share/classes/com/sun/tools/javac/code/Printer.java index be0b5038018..aa05cc29204 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/code/Printer.java +++ b/langtools/src/share/classes/com/sun/tools/javac/code/Printer.java @@ -27,8 +27,6 @@ package com.sun.tools.javac.code; import java.util.Locale; -import javax.lang.model.type.TypeKind; - import com.sun.tools.javac.api.Messages; import com.sun.tools.javac.code.Type.AnnotatedType; import com.sun.tools.javac.code.Type.ArrayType; @@ -191,7 +189,7 @@ public abstract class Printer implements Type.Visitor, Symbol.Vi void printBaseElementType(Type t, StringBuilder sb, Locale locale) { Type arrel = t; - while (arrel.getKind() == TypeKind.ARRAY) { + while (arrel.hasTag(TypeTag.ARRAY)) { arrel = arrel.unannotatedType(); arrel = ((ArrayType) arrel).elemtype; } @@ -200,7 +198,7 @@ public abstract class Printer implements Type.Visitor, Symbol.Vi void printBrackets(Type t, StringBuilder sb, Locale locale) { Type arrel = t; - while (arrel.getKind() == TypeKind.ARRAY) { + while (arrel.hasTag(TypeTag.ARRAY)) { if (arrel.isAnnotated()) { sb.append(' '); sb.append(arrel.getAnnotationMirrors()); @@ -264,12 +262,12 @@ public abstract class Printer implements Type.Visitor, Symbol.Vi public String visitAnnotatedType(AnnotatedType t, Locale locale) { if (t.typeAnnotations != null && t.typeAnnotations.nonEmpty()) { - if (t.underlyingType.getKind() == TypeKind.ARRAY) { + if (t.underlyingType.hasTag(TypeTag.ARRAY)) { StringBuilder res = new StringBuilder(); printBaseElementType(t, res, locale); printBrackets(t, res, locale); return res.toString(); - } else if (t.underlyingType.getKind() == TypeKind.DECLARED && + } else if (t.underlyingType.hasTag(TypeTag.CLASS) && t.underlyingType.getEnclosingType() != Type.noType) { return visit(t.underlyingType.getEnclosingType(), locale) + ". " + @@ -348,7 +346,7 @@ public abstract class Printer implements Type.Visitor, Symbol.Vi args = args.tail; buf.append(','); } - if (args.head.unannotatedType().getKind() == TypeKind.ARRAY) { + if (args.head.unannotatedType().hasTag(TypeTag.ARRAY)) { buf.append(visit(((ArrayType) args.head.unannotatedType()).elemtype, locale)); if (args.head.getAnnotationMirrors().nonEmpty()) { buf.append(' '); diff --git a/langtools/src/share/classes/com/sun/tools/javac/code/TypeAnnotations.java b/langtools/src/share/classes/com/sun/tools/javac/code/TypeAnnotations.java index 260715dff64..642de5d4c4a 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/code/TypeAnnotations.java +++ b/langtools/src/share/classes/com/sun/tools/javac/code/TypeAnnotations.java @@ -29,6 +29,8 @@ import javax.lang.model.element.Element; import javax.lang.model.element.ElementKind; import javax.lang.model.type.TypeKind; +import javax.tools.JavaFileObject; + import com.sun.tools.javac.code.Attribute; import com.sun.tools.javac.code.Attribute.TypeCompound; import com.sun.tools.javac.code.Flags; @@ -52,12 +54,16 @@ import com.sun.tools.javac.code.Symbol.VarSymbol; import com.sun.tools.javac.code.Symbol.MethodSymbol; import com.sun.tools.javac.comp.Annotate; import com.sun.tools.javac.comp.Annotate.Annotator; +import com.sun.tools.javac.comp.AttrContext; +import com.sun.tools.javac.comp.Env; import com.sun.tools.javac.tree.JCTree; +import com.sun.tools.javac.tree.TreeInfo; import com.sun.tools.javac.tree.JCTree.JCBlock; import com.sun.tools.javac.tree.JCTree.JCClassDecl; import com.sun.tools.javac.tree.JCTree.JCExpression; import com.sun.tools.javac.tree.JCTree.JCLambda; import com.sun.tools.javac.tree.JCTree.JCMethodDecl; +import com.sun.tools.javac.tree.JCTree.JCMethodInvocation; import com.sun.tools.javac.tree.JCTree.JCNewClass; import com.sun.tools.javac.tree.JCTree.JCTypeApply; import com.sun.tools.javac.tree.JCTree.JCVariableDecl; @@ -90,11 +96,17 @@ public class TypeAnnotations { * later processing. */ public static void organizeTypeAnnotationsSignatures(final Symtab syms, final Names names, - final Log log, final JCClassDecl tree, Annotate annotate) { + final Log log, final Env env, final JCClassDecl tree, final Annotate annotate) { annotate.afterRepeated( new Annotator() { @Override public void enterAnnotation() { - new TypeAnnotationPositions(syms, names, log, true).scan(tree); + JavaFileObject oldSource = log.useSource(env.toplevel.sourcefile); + + try { + new TypeAnnotationPositions(syms, names, log, true).scan(tree); + } finally { + log.useSource(oldSource); + } } } ); } @@ -906,7 +918,14 @@ public class TypeAnnotations { if (!invocation.typeargs.contains(tree)) { Assert.error("{" + tree + "} is not an argument in the invocation: " + invocation); } - p.type = TargetType.METHOD_INVOCATION_TYPE_ARGUMENT; + MethodSymbol exsym = (MethodSymbol) TreeInfo.symbol(invocation.getMethodSelect()); + if (exsym == null) { + Assert.error("could not determine symbol for {" + invocation + "}"); + } else if (exsym.isConstructor()) { + p.type = TargetType.CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT; + } else { + p.type = TargetType.METHOD_INVOCATION_TYPE_ARGUMENT; + } p.pos = invocation.pos; p.type_index = invocation.typeargs.indexOf(tree); return; diff --git a/langtools/src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java b/langtools/src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java index 577d7cc30a6..7633f96d1df 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java @@ -249,7 +249,7 @@ public class LambdaToMethod extends TreeTranslator { MethodType lambdaType = (MethodType) sym.type; { - MethodSymbol owner = (MethodSymbol) localContext.owner; + Symbol owner = localContext.owner; ListBuffer ownerTypeAnnos = new ListBuffer(); ListBuffer lambdaTypeAnnos = new ListBuffer(); diff --git a/langtools/src/share/classes/com/sun/tools/javac/comp/MemberEnter.java b/langtools/src/share/classes/com/sun/tools/javac/comp/MemberEnter.java index 4f23e8d8a1e..cdd3db2bcdd 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/comp/MemberEnter.java +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/MemberEnter.java @@ -1089,7 +1089,7 @@ public class MemberEnter extends JCTree.Visitor implements Completer { } } if (allowTypeAnnos) { - TypeAnnotations.organizeTypeAnnotationsSignatures(syms, names, log, tree, annotate); + TypeAnnotations.organizeTypeAnnotationsSignatures(syms, names, log, env, tree, annotate); } } diff --git a/langtools/src/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java b/langtools/src/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java index 4e966f9b716..7aca9f55726 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java +++ b/langtools/src/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java @@ -89,7 +89,7 @@ import static com.sun.tools.javac.util.JCDiagnostic.DiagnosticFlag.*; * deletion without notice. */ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closeable { - Options options; + private final Options options; private final boolean printProcessorInfo; private final boolean printRounds; diff --git a/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties b/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties index 572478f19e1..5d1a22b84a1 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties +++ b/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties @@ -2248,7 +2248,7 @@ compiler.err.cant.annotate.static.class=\ # TODO 308: make a better error message # 0: unused compiler.err.cant.annotate.nested.type=\ - nested type cannot be annotated + scoping construct for static nested type cannot be annotated # 0: type, 1: type compiler.err.incorrect.receiver.name=\ diff --git a/langtools/src/share/classes/com/sun/tools/javac/tree/Pretty.java b/langtools/src/share/classes/com/sun/tools/javac/tree/Pretty.java index e7c1e12b1cf..653d9e54eff 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/tree/Pretty.java +++ b/langtools/src/share/classes/com/sun/tools/javac/tree/Pretty.java @@ -944,10 +944,17 @@ public class Pretty extends JCTree.Visitor { try { if (tree.elemtype != null) { print("new "); - printTypeAnnotations(tree.annotations); JCTree elem = tree.elemtype; printBaseElementType(elem); - boolean isElemAnnoType = elem instanceof JCAnnotatedType; + + if (!tree.annotations.isEmpty()) { + print(' '); + printTypeAnnotations(tree.annotations); + } + if (tree.elems != null) { + print("[]"); + } + int i = 0; List> da = tree.dimAnnotations; for (List l = tree.dims; l.nonEmpty(); l = l.tail) { @@ -960,17 +967,7 @@ public class Pretty extends JCTree.Visitor { printExpr(l.head); print("]"); } - if (tree.elems != null) { - if (isElemAnnoType) { - print(' '); - printTypeAnnotations(((JCAnnotatedType)tree.elemtype).annotations); - } - print("[]"); - } - if (isElemAnnoType) - elem = ((JCAnnotatedType)elem).underlyingType; - if (elem instanceof JCArrayTypeTree) - printBrackets((JCArrayTypeTree) elem); + printBrackets(elem); } if (tree.elems != null) { print("{"); @@ -1260,20 +1257,24 @@ public class Pretty extends JCTree.Visitor { } // prints the brackets of a nested array in reverse order - private void printBrackets(JCArrayTypeTree tree) throws IOException { - JCTree elem; + // tree is either JCArrayTypeTree or JCAnnotatedTypeTree + private void printBrackets(JCTree tree) throws IOException { + JCTree elem = tree; while (true) { - elem = tree.elemtype; if (elem.hasTag(ANNOTATED_TYPE)) { JCAnnotatedType atype = (JCAnnotatedType) elem; elem = atype.underlyingType; - if (!elem.hasTag(TYPEARRAY)) break; - print(' '); - printTypeAnnotations(atype.annotations); + if (elem.hasTag(TYPEARRAY)) { + print(' '); + printTypeAnnotations(atype.annotations); + } + } + if (elem.hasTag(TYPEARRAY)) { + print("[]"); + elem = ((JCArrayTypeTree)elem).elemtype; + } else { + break; } - print("[]"); - if (!elem.hasTag(TYPEARRAY)) break; - tree = (JCArrayTypeTree) elem; } } @@ -1378,22 +1379,15 @@ public class Pretty extends JCTree.Visitor { public void visitAnnotatedType(JCAnnotatedType tree) { try { - if (tree.underlyingType.getKind() == JCTree.Kind.MEMBER_SELECT) { + if (tree.underlyingType.hasTag(SELECT)) { JCFieldAccess access = (JCFieldAccess) tree.underlyingType; printExpr(access.selected, TreeInfo.postfixPrec); print("."); printTypeAnnotations(tree.annotations); print(access.name); - } else if (tree.underlyingType.getKind() == JCTree.Kind.ARRAY_TYPE) { - JCArrayTypeTree array = (JCArrayTypeTree) tree.underlyingType; + } else if (tree.underlyingType.hasTag(TYPEARRAY)) { printBaseElementType(tree); - print(' '); - printTypeAnnotations(tree.annotations); - print("[]"); - JCExpression elem = array.elemtype; - if (elem.hasTag(TYPEARRAY)) { - printBrackets((JCArrayTypeTree) elem); - } + printBrackets(tree); } else { printTypeAnnotations(tree.annotations); printExpr(tree.underlyingType); diff --git a/langtools/test/tools/javac/annotations/typeAnnotations/classfile/CombinationsTargetTest2.java b/langtools/test/tools/javac/annotations/typeAnnotations/classfile/CombinationsTargetTest2.java index b660855a5b0..644b68471a2 100644 --- a/langtools/test/tools/javac/annotations/typeAnnotations/classfile/CombinationsTargetTest2.java +++ b/langtools/test/tools/javac/annotations/typeAnnotations/classfile/CombinationsTargetTest2.java @@ -35,13 +35,16 @@ public class CombinationsTargetTest2 extends ClassfileTestHelper { // Test count helps identify test case in event of failure. int testcount = 0; - // Base test case template descriptions + // Base test case template descriptions;true==annotations in code attribute. enum srce { src1("(repeating) type annotations on on field in method body",true), src2("(repeating) type annotations on type parameters, bounds and type arguments", true), src3("(repeating) type annotations on type parameters of class, method return value in method", true), src4("(repeating) type annotations on field in anonymous class", false), - src5("(repeating) type annotations on field in anonymous class", false); + src5("(repeating) type annotations on field in anonymous class", false), + src6("(repeating) type annotations on void method declaration", false), + src7("(repeating) type annotations in use of instanceof", true), + src8("(repeating) type annotations in use of instanceof in method", true); String description; Boolean local; @@ -84,6 +87,12 @@ public class CombinationsTargetTest2 extends ClassfileTestHelper { test( 0, 8, 0, 0, As, BDs, ABMix, "RUNTIME", et, ++testrun, srce.src1); test( 2, 0, 2, 0, As, BDs, ABMix, "CLASS", et, ++testrun, srce.src5); test( 0, 2, 0, 2, As, BDs, ABMix, "RUNTIME", et, ++testrun, srce.src5); + test( 0, 0, 2, 0, As, BDs, ABMix, "CLASS", et, ++testrun, srce.src6); + test( 0, 0, 0, 2, As, BDs, ABMix, "RUNTIME", et, ++testrun, srce.src6); + test( 2, 0, 0, 0, As, BDs, ABMix, "CLASS", et, ++testrun, srce.src7); + test( 0, 2, 0, 0, As, BDs, ABMix, "RUNTIME", et, ++testrun, srce.src7); + test( 4, 0, 0, 0, As, BDs, ABMix, "CLASS", et, ++testrun, srce.src8); + test( 0, 4, 0, 0, As, BDs, ABMix, "RUNTIME", et, ++testrun, srce.src8); break; case "FIELD": test( 8, 0, 0, 0, As, BDs, ABMix, "CLASS", et, ++testrun, srce.src1); @@ -121,18 +130,6 @@ public class CombinationsTargetTest2 extends ClassfileTestHelper { ", ABmix=" + ABmix + ", retention: " + rtn + ", anno2: " + et2 + ", src=" + source + "\n " + source.description; - if( -// 8005681 - src1,2,3 - skip cases with repeated annotations on new, array, cast. - (( source.equals(srce.src1) || source.equals(srce.src2) || - source.equals(srce.src3)) && (ABmix || (Arepeats && BDrepeats))) - // 8008928 - src4,5 - this change cause crash with t-a on anon class) - || (source.equals(srce.src4) || source.equals(srce.src5)) - ) { - System.out.println(testDef + - "\n 8005681-skip repeated annotations on new,array,cast"); - return; - } - println(testDef); // Create test source and File. String sourceString = sourceString(tname, rtn, et2, Arepeats, @@ -178,9 +175,7 @@ public class CombinationsTargetTest2 extends ClassfileTestHelper { println("Pass"); } - // // Source for test cases - // String sourceString(String testname, String retentn, String annot2, Boolean Arepeats, Boolean BDrepeats, Boolean ABmix, srce src) { @@ -359,6 +354,63 @@ public class CombinationsTargetTest2 extends ClassfileTestHelper { hasInnerClass=true; innerClassname="$1"; break; + case src6: // (repeating)annotations on void method declaration + /* + * class Test95{ + * @A @A @B @B public void test() { }; + * } + */ + source = new String( source + + "// " + src.description + "\n" + + "class "+ testname + "{\n" + + " _As_ _Bs_ public void test() { }\n" + + "}\n").concat(sourceBase).replace("_OTHER_", annot2).replace("_As_",As).replace("_Bs_",Bs) + + "\n\n"; + hasInnerClass=false; + break; + case src7: // (repeating) type annotations in use of instanceof + /* + * class Test10{ + * String data = "test"; + * boolean dataIsString = ( data instanceof @A @B @A @B String); + * } + */ + source = new String( source + + "// " + src.description + "\n" + + "class "+ testname + "{\n" + + " String data = \"test\";\n" + + " boolean dataIsString = ( data instanceof _As_ _Bs_ String);\n" + + "}\n").concat(sourceBase).replace("_OTHER_", annot2).replace("_As_",As).replace("_Bs_",Bs) + + "\n\n"; + hasInnerClass=false; + break; + case src8: // (repeating) type annotations in use of instanceof + /* + * class Test20{ + * String data = "test"; + * Boolean isString() { + * if( data instanceof @A @B @A @B String ) + * return true; + * else + * return( data instanceof @A @B @A @B String ); + * } + * } + */ + source = new String( source + + "// " + src.description + "\n" + + "class "+ testname + "{\n" + + " String data = \"test\";\n" + + " Boolean isString() { \n" + + " if( data instanceof _As_ _Bs_ String )\n" + + " return true;\n" + + " else\n" + + " return( data instanceof _As_ _Bs_ String );\n" + + " }\n" + + "}\n").concat(sourceBase).replace("_OTHER_", annot2).replace("_As_",As).replace("_Bs_",Bs) + + "\n\n"; + hasInnerClass=false; + break; + } return imports + source; } diff --git a/langtools/test/tools/javac/annotations/typeAnnotations/failures/DummyProcessor.java b/langtools/test/tools/javac/annotations/typeAnnotations/failures/DummyProcessor.java new file mode 100644 index 00000000000..26bd4d288b3 --- /dev/null +++ b/langtools/test/tools/javac/annotations/typeAnnotations/failures/DummyProcessor.java @@ -0,0 +1,43 @@ +/* + * 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 javax.annotation.processing.*; +import javax.lang.model.SourceVersion; +import javax.lang.model.element.TypeElement; + +import java.util.Set; + +/* A simple annotation processor. */ +@SupportedAnnotationTypes("*") +public class DummyProcessor extends AbstractProcessor { + @Override + public SourceVersion getSupportedSourceVersion() { + return SourceVersion.latest(); + } + + @Override + public final boolean process(Set annotations, + RoundEnvironment roundEnv) { + return false; + } +} diff --git a/langtools/test/tools/javac/annotations/typeAnnotations/failures/T8020715.java b/langtools/test/tools/javac/annotations/typeAnnotations/failures/T8020715.java new file mode 100644 index 00000000000..89670f3edf4 --- /dev/null +++ b/langtools/test/tools/javac/annotations/typeAnnotations/failures/T8020715.java @@ -0,0 +1,49 @@ +/* + * 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 Regression: compiling program with lambda crashed compiler + * @bug 8020715 + * @compile T8020715.java + */ +class T8020715 { + // This crashed. + private static void makeTask1() { + class LocalClass { + private Runnable r = () -> {}; + } + } + + // This crashed, too. + private void makeTask2() { + class LocalClass { + private Runnable r = () -> {}; + } + } + + // This is fine. + private class InnerClass { + private Runnable r = () -> {}; + } +} diff --git a/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/Constructors.java b/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/Constructors.java index 38e46159cea..a8d1311eb47 100644 --- a/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/Constructors.java +++ b/langtools/test/tools/javac/annotations/typeAnnotations/referenceinfos/Constructors.java @@ -85,4 +85,24 @@ public class Constructors { " } } }"; } + @TADescriptions({ + @TADescription(annotation = "TA", type = CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT, + typeIndex = 0, offset = 4), + @TADescription(annotation = "TB", type = CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT, + typeIndex = 0, offset = 0) + }) + public String generic1() { + return "class Test { Test(int i) { new <@TA T>Test(); }" + + " Test() { <@TB String>this(0); } }"; + } + + @TADescriptions({ + @TADescription(annotation = "TA", type = CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT, + typeIndex = 0, offset = 0) + }) + public String generic2() { + return "class Super { Super(int i) { } } " + + "class Test extends Super { Test() { <@TA String>super(0); } }"; + } + } diff --git a/langtools/test/tools/javac/tree/TypeAnnotationsPretty.java b/langtools/test/tools/javac/tree/TypeAnnotationsPretty.java new file mode 100644 index 00000000000..0ca021c9b3d --- /dev/null +++ b/langtools/test/tools/javac/tree/TypeAnnotationsPretty.java @@ -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 + * @bug 1234567 + * @summary test Pretty print of type annotations + * @author wmdietl + */ + +import com.sun.source.tree.ClassTree; +import com.sun.source.tree.CompilationUnitTree; +import com.sun.tools.javac.api.JavacTaskImpl; +import com.sun.tools.javac.tree.JCTree; + +import java.io.IOException; +import java.net.URI; +import java.util.Arrays; +import java.util.List; +import java.util.LinkedList; + +import javax.tools.JavaCompiler; +import javax.tools.JavaFileObject; +import javax.tools.SimpleJavaFileObject; +import javax.tools.ToolProvider; + +public class TypeAnnotationsPretty { + private final JavaCompiler tool; + + TypeAnnotationsPretty() { + tool = ToolProvider.getSystemJavaCompiler(); + } + + private List matches = new LinkedList(); + private List mismatches = new LinkedList(); + + public static void main(String... args) throws Exception { + TypeAnnotationsPretty tap = new TypeAnnotationsPretty(); + + tap.runField("@TA()\nObject cls = null"); + tap.runField("@TA()\nObject cls = new @TA() Object()"); + + tap.runField("@TA()\nList<@TB() Object> cls = null"); + tap.runField("@TA()\nList<@TB() Object> cls = new @TA() LinkedList<@TB() Object>()"); + + tap.runField("Class[] cls = null"); + tap.runField("@TA()\nClass[] cls = null"); + tap.runField("Class @TA() [] cls = null"); + tap.runField("@TA()\nClass @TB() [] cls = null"); + + tap.runField("Class[] cls = new Class[]{Object.class}"); + tap.runField("@TA()\nClass[] cls = new @TA() Class[]{Object.class}"); + tap.runField("Class @TB() [] cls = new Class @TB() []{Object.class}"); + tap.runField("@TA()\nClass @TB() [] cls = new @TA() Class @TB() []{Object.class}"); + tap.runField("@TA()\nClass @TB() [] @TC() [] cls = new @TA() Class @TB() [10] @TC() []"); + tap.runField("Class @TB() [] @TC() [] cls = new Class @TB() [10] @TC() []"); + tap.runField("@TA()\nClass @TB() [] @TC() [] @TD() [] cls = new @TA() Class @TB() [10] @TC() [] @TD() []"); + + tap.runMethod("\n@TA()\nObject test(@TB()\nList<@TC() String> p) {\n" + + " return null;\n" + + "}"); + + + if (!tap.matches.isEmpty()) { + for (String m : tap.matches) + System.out.println(m); + } + if (!tap.mismatches.isEmpty()) { + for (String mm : tap.mismatches) + System.err.println(mm + "\n"); + throw new RuntimeException("Tests failed!"); + } + } + + private static final String prefix = + "import java.lang.annotation.*;" + + "import java.util.*;" + + "public class Test {"; + + private static final String postfix = + "@Target(ElementType.TYPE_USE)" + + "@interface TA {}" + + "@Target(ElementType.TYPE_USE)" + + "@interface TB {}" + + "@Target(ElementType.TYPE_USE)" + + "@interface TC {}" + + "@Target(ElementType.TYPE_USE)" + + "@interface TD {}"; + + + private void runField(String code) throws IOException { + String src = prefix + + code + "; }" + + postfix; + + JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, null, null, null, + null, Arrays.asList(new MyFileObject(src))); + + + for (CompilationUnitTree cut : ct.parse()) { + JCTree.JCVariableDecl var = + (JCTree.JCVariableDecl) ((ClassTree) cut.getTypeDecls().get(0)).getMembers().get(0); + + if (!code.equals(var.toString())) { + mismatches.add("Expected: " + code + + "\nObtained: " + var.toString()); + } else { + matches.add("Passed: " + code); + } + } + } + + private void runMethod(String code) throws IOException { + String src = prefix + + code + "}" + + postfix; + + JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, null, null, null, + null, Arrays.asList(new MyFileObject(src))); + + + for (CompilationUnitTree cut : ct.parse()) { + JCTree.JCMethodDecl var = + (JCTree.JCMethodDecl) ((ClassTree) cut.getTypeDecls().get(0)).getMembers().get(0); + + if (!code.equals(var.toString())) { + mismatches.add("Expected: " + code + + "\nObtained: " + var.toString()); + } else { + matches.add("Passed: " + code); + } + } + } +} + + +class MyFileObject extends SimpleJavaFileObject { + + private String text; + + public MyFileObject(String text) { + super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE); + this.text = text; + } + + @Override + public CharSequence getCharContent(boolean ignoreEncodingErrors) { + return text; + } +} From 8073e1a535e6234a0e4b5f4650c403999242c8fe Mon Sep 17 00:00:00 2001 From: Eric McCorkle Date: Wed, 21 Aug 2013 20:23:36 -0400 Subject: [PATCH 090/218] 7118412: Shadowing of type-variables vs. member types 4987840: What is the scope of an annotation? Fixed issue with shadowing of type names. Reviewed-by: jjg, abuckley, mcimadamore --- .../com/sun/tools/javac/comp/Resolve.java | 99 +++++++++++++++---- 1 file changed, 81 insertions(+), 18 deletions(-) diff --git a/langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java b/langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java index e2784003285..0439e0d6132 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java @@ -1859,7 +1859,10 @@ public class Resolve { } } - /** Find qualified member type. + + /** + * Find a type declared in a scope (not inherited). Return null + * if none is found. * @param env The current environment. * @param site The original type from where the selection takes * place. @@ -1868,12 +1871,10 @@ public class Resolve { * always a superclass or implemented interface of * site's class. */ - Symbol findMemberType(Env env, - Type site, - Name name, - TypeSymbol c) { - Symbol bestSoFar = typeNotFound; - Symbol sym; + Symbol findImmediateMemberType(Env env, + Type site, + Name name, + TypeSymbol c) { Scope.Entry e = c.members().lookup(name); while (e.scope != null) { if (e.sym.kind == TYP) { @@ -1883,6 +1884,24 @@ public class Resolve { } e = e.next(); } + return typeNotFound; + } + + /** Find a member type inherited from a superclass or interface. + * @param env The current environment. + * @param site The original type from where the selection takes + * place. + * @param name The type's name. + * @param c The class to search for the member type. This is + * always a superclass or implemented interface of + * site's class. + */ + Symbol findInheritedMemberType(Env env, + Type site, + Name name, + TypeSymbol c) { + Symbol bestSoFar = typeNotFound; + Symbol sym; Type st = types.supertype(c.type); if (st != null && st.hasTag(CLASS)) { sym = findMemberType(env, site, name, st.tsym); @@ -1901,6 +1920,28 @@ public class Resolve { return bestSoFar; } + /** Find qualified member type. + * @param env The current environment. + * @param site The original type from where the selection takes + * place. + * @param name The type's name. + * @param c The class to search for the member type. This is + * always a superclass or implemented interface of + * site's class. + */ + Symbol findMemberType(Env env, + Type site, + Name name, + TypeSymbol c) { + Symbol sym = findImmediateMemberType(env, site, name, c); + + if (sym != typeNotFound) + return sym; + + return findInheritedMemberType(env, site, name, c); + + } + /** Find a global type in given scope and load corresponding class. * @param env The current environment. * @param scope The scope in which to look for the type. @@ -1919,6 +1960,21 @@ public class Resolve { return bestSoFar; } + Symbol findTypeVar(Env env, Name name, boolean staticOnly) { + for (Scope.Entry e = env.info.scope.lookup(name); + e.scope != null; + e = e.next()) { + if (e.sym.kind == TYP) { + if (staticOnly && + e.sym.type.hasTag(TYPEVAR) && + e.sym.owner.kind == TYP) + return new StaticError(e.sym); + return e.sym; + } + } + return typeNotFound; + } + /** Find an unqualified type symbol. * @param env The current environment. * @param name The type's name. @@ -1929,19 +1985,26 @@ public class Resolve { boolean staticOnly = false; for (Env env1 = env; env1.outer != null; env1 = env1.outer) { if (isStatic(env1)) staticOnly = true; - for (Scope.Entry e = env1.info.scope.lookup(name); - e.scope != null; - e = e.next()) { - if (e.sym.kind == TYP) { - if (staticOnly && - e.sym.type.hasTag(TYPEVAR) && - e.sym.owner.kind == TYP) return new StaticError(e.sym); - return e.sym; - } + // First, look for a type variable and the first member type + final Symbol tyvar = findTypeVar(env1, name, staticOnly); + sym = findImmediateMemberType(env1, env1.enclClass.sym.type, + name, env1.enclClass.sym); + + // Return the type variable if we have it, and have no + // immediate member, OR the type variable is for a method. + if (tyvar != typeNotFound) { + if (sym == typeNotFound || + (tyvar.kind == TYP && tyvar.exists() && + tyvar.owner.kind == MTH)) + return tyvar; } - sym = findMemberType(env1, env1.enclClass.sym.type, name, - env1.enclClass.sym); + // If the environment is a class def, finish up, + // otherwise, do the entire findMemberType + if (sym == typeNotFound) + sym = findInheritedMemberType(env1, env1.enclClass.sym.type, + name, env1.enclClass.sym); + if (staticOnly && sym.kind == TYP && sym.type.hasTag(CLASS) && sym.type.getEnclosingType().hasTag(CLASS) && From 64412dad178d5fac931394cb2b7778cbed840ef6 Mon Sep 17 00:00:00 2001 From: Jonathan Gibbons Date: Wed, 21 Aug 2013 17:26:22 -0700 Subject: [PATCH 091/218] 8022287: javac.sym.Profiles uses a static Map when it should not Reviewed-by: ksrini --- .../com/sun/tools/javac/sym/Profiles.java | 2 +- .../tools/javac/profiles/ProfileTest.java | 114 ++++++++++++++++++ 2 files changed, 115 insertions(+), 1 deletion(-) create mode 100644 langtools/test/tools/javac/profiles/ProfileTest.java diff --git a/langtools/src/share/classes/com/sun/tools/javac/sym/Profiles.java b/langtools/src/share/classes/com/sun/tools/javac/sym/Profiles.java index 8cae1dd3696..1ebea23192d 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/sym/Profiles.java +++ b/langtools/src/share/classes/com/sun/tools/javac/sym/Profiles.java @@ -148,7 +148,7 @@ public abstract class Profiles { } } - final static Map packages = new TreeMap(); + final Map packages = new TreeMap(); final int maxProfile = 4; // Three compact profiles plus full JRE diff --git a/langtools/test/tools/javac/profiles/ProfileTest.java b/langtools/test/tools/javac/profiles/ProfileTest.java new file mode 100644 index 00000000000..7e081a5b81e --- /dev/null +++ b/langtools/test/tools/javac/profiles/ProfileTest.java @@ -0,0 +1,114 @@ +/* + * 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 8022287 + * @summary javac.sym.Profiles uses a static Map when it should not + */ + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; + +import com.sun.tools.javac.sym.Profiles; + +public class ProfileTest { + public static void main(String... args) throws Exception { + new ProfileTest().run(); + } + + public void run() throws Exception { + test("A"); + test("B"); + + if (errors > 0) + throw new Exception(errors + " occurred"); + } + + void test(String base) throws IOException { + System.err.println("test " + base); + File profileDesc = createFiles(base); + checkProfile(profileDesc, base); + } + + void checkProfile(File profileDesc, String base) throws IOException { + Profiles p = Profiles.read(profileDesc); + for (int i = 0; i < p.getProfileCount(); i++) { + System.err.println(p.getPackages(i)); + for (String pkg: p.getPackages(i)) { + if (!pkg.endsWith(base)) + error("unexpected package " + pkg + " for profile " + i); + } + } + } + + File createFiles(String base) throws IOException { + File baseDir = new File(base); + baseDir.mkdirs(); + for (int p = 1; p <= 4; p++) { + String pkg = "pkg" + p + base; + File pkgDir = new File(baseDir, pkg); + pkgDir.mkdirs(); + File clssFile = new File(pkgDir, pkg + "Class.java"); + try (PrintWriter out = new PrintWriter(new FileWriter(clssFile))) { + out.println("package " + pkgDir.getName() + ";"); + out.println("class " + clssFile.getName().replace(".java", "")); + } + } + + File profileDesc = new File(baseDir, "profiles" + base + ".txt"); + try (PrintWriter out = new PrintWriter(new FileWriter(profileDesc))) { + for (int p = 1; p <= 4; p++) { + String pkg = "pkg" + p + base; + createPackage(baseDir, pkg, "Pkg" + p + base + "Class"); + out.println("PROFILE_" + p + "_RTJAR_INCLUDE_PACKAGES := " + pkg); + out.println("PROFILE_" + p + "_RTJAR_INCLUDE_TYPES :="); + out.println("PROFILE_" + p + "_RTJAR_EXCLUDE_TYPES :="); + out.println("PROFILE_" + p + "_INCLUDE_METAINF_SERVICES := "); + } + } + + return profileDesc; + } + + void createPackage(File baseDir, String pkg, String... classNames) throws IOException { + File pkgDir = new File(baseDir, pkg); + pkgDir.mkdirs(); + for (String className: classNames) { + File clssFile = new File(pkgDir, className + ".java"); + try (PrintWriter out = new PrintWriter(new FileWriter(clssFile))) { + out.println("package " + pkg + ";"); + out.println("public class " + className + " { }"); + } + } + } + + void error(String msg) { + System.err.println("Error: " + msg); + errors++; + } + + int errors; +} From febfa82cfb3e4b434f7aa426b73d2efc3a3ffbc8 Mon Sep 17 00:00:00 2001 From: Eric McCorkle Date: Wed, 21 Aug 2013 20:41:42 -0400 Subject: [PATCH 092/218] 8023520: Add missing test for JDK-7118412 The test for JDK-7118412 was dropped from the changeset in a merging accident. Reviewed-by: jjg --- .../tools/javac/7118412/ShadowingTest.java | 287 ++++++++++++++++++ 1 file changed, 287 insertions(+) create mode 100644 langtools/test/tools/javac/7118412/ShadowingTest.java diff --git a/langtools/test/tools/javac/7118412/ShadowingTest.java b/langtools/test/tools/javac/7118412/ShadowingTest.java new file mode 100644 index 00000000000..4bbcfc636c6 --- /dev/null +++ b/langtools/test/tools/javac/7118412/ShadowingTest.java @@ -0,0 +1,287 @@ +/* + * 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 7118412 + * @summary Shadowing of type-variables vs. member types + */ +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringWriter; + +public class ShadowingTest { + + // We generate a method "test" that tries to call T.. This controls whether + // "test" is static or not. + private enum MethodContext { + STATIC("static "), + INSTANCE(""); + + public final String methodcontext; + + MethodContext(final String methodcontext) { + this.methodcontext = methodcontext; + } + } + + // These control whether or not a type parameter, method type + // parameter, or inner class get declared (and in the case of + // inner classes, whether it's static or not. + + private enum MethodTypeParameterDecl { + NO(""), + YES(" "); + + public final String tyvar; + + MethodTypeParameterDecl(final String tyvar) { + this.tyvar = tyvar; + } + } + + private enum InsideDef { + NONE(""), + STATIC("static class T { public void inner() {} }\n"), + INSTANCE("class T { public void inner() {} }\n"); + + public final String instancedef; + + InsideDef(final String instancedef) { + this.instancedef = instancedef; + } + } + + private enum TypeParameterDecl { + NO(""), + YES(""); + + public final String tyvar; + + TypeParameterDecl(final String tyvar) { + this.tyvar = tyvar; + } + } + + // Represents what method we try to call. This is a way of + // checking which T we're seeing. + private enum MethodCall { + // Method type variables extend Number, so we have intValue + METHOD_TYPEVAR("intValue"), + // The inner class declaration has a method called "inner" + INNER_CLASS("inner"), + // The class type variables extend Collection, so we call iterator + TYPEVAR("iterator"), + // The outer class declaration has a method called "outer" + OUTER_CLASS("outer"); + + public final String methodcall; + + MethodCall(final String methodcall) { + this.methodcall = methodcall; + } + + } + + public boolean succeeds(final MethodCall call, + final MethodTypeParameterDecl mtyvar, + final MethodContext ctx, + final InsideDef inside, + final TypeParameterDecl tyvar) { + switch(call) { + // We want to resolve to the method type variable + case METHOD_TYPEVAR: switch(mtyvar) { + // If the method type variable exists, then T will + // resolve to it, and we'll have intValue. + case YES: return true; + // Otherwise, this cannot succeed. + default: return false; + } + // We want to resolve to the inner class + case INNER_CLASS: switch(mtyvar) { + // The method type parameter will shadow the inner + // class, so there can't be one. + case NO: switch(ctx) { + // If we're not static, then either one should succeed. + case INSTANCE: switch(inside) { + case INSTANCE: + case STATIC: + return true; + default: return false; + } + case STATIC: switch(inside) { + // If we are static, and the inner class is + // static, then we also succeed, because we + // can't see the type variable. + case STATIC: return true; + case INSTANCE: switch(tyvar) { + // If we're calling from a non-static + // context, there can't be a class type + // variable, because that will shadow the + // static inner class definition. + case NO: return true; + default: return false; + } + // If the inner class isn't declared, we can't + // see it. + default: return false; + } + // Can't get here. + default: return false; + } + default: return false; + } + // We want to resolve to the class type parameter + case TYPEVAR: switch(mtyvar) { + // We can't have a method type parameter, as that would + // shadow the class type parameter + case NO: switch(ctx) { + case INSTANCE: switch(inside) { + // We have to be in an instance context. If + // we're static, we can't see the type + // variable. + case NONE: switch(tyvar) { + // Obviously, the type parameter has to be declared. + case YES: return true; + default: return false; + } + default: return false; + } + default: return false; + } + default: return false; + } + // We want to resolve to the outer class + case OUTER_CLASS: switch(mtyvar) { + case NO: switch(inside) { + case NONE: switch(tyvar) { + // Basically, nothing else can be declared, or + // else we can't see it. Even if our context + // is static, the compiler will complain if + // non-static T's exist, because they will + // shadow the outer class. + case NO: return true; + default: return false; + } + default: return false; + } + default: return false; + } + } + return false; + } + + private static final File classesdir = new File("7118412"); + + private int errors = 0; + + private int dirnum = 0; + + private void doTest(final MethodTypeParameterDecl mtyvar, + final TypeParameterDecl tyvar, + final InsideDef insidedef, final MethodContext ctx, + final MethodCall call) + throws IOException { + final String content = "import java.util.Collection;\n" + + "class Test" + tyvar.tyvar + " {\n" + + " " + insidedef.instancedef + + " " + ctx.methodcontext + mtyvar.tyvar + "void test(T t) { t." + + call.methodcall + "(); }\n" + + "}\n" + + "class T { void outer() {} }\n"; + final File dir = new File(classesdir, "" + dirnum); + final File Test_java = writeFile(dir, "Test.java", content); + dirnum++; + if(succeeds(call, mtyvar, ctx, insidedef, tyvar)) { + if(!assert_compile_succeed(Test_java)) + System.err.println("Failed file:\n" + content); + } + else { + if(!assert_compile_fail(Test_java)) + System.err.println("Failed file:\n" + content); + } + } + + private void run() throws Exception { + classesdir.mkdir(); + for(MethodTypeParameterDecl mtyvar : MethodTypeParameterDecl.values()) + for(TypeParameterDecl tyvar : TypeParameterDecl.values()) + for(InsideDef insidedef : InsideDef.values()) + for(MethodContext ctx : MethodContext.values()) + for(MethodCall methodcall : MethodCall.values()) + doTest(mtyvar, tyvar, insidedef, ctx, methodcall); + if (errors != 0) + throw new Exception("ShadowingTest test failed with " + + errors + " errors."); + } + + private boolean assert_compile_fail(final File file) { + final String filename = file.getPath(); + final String[] args = { filename }; + final StringWriter sw = new StringWriter(); + final PrintWriter pw = new PrintWriter(sw); + final int rc = com.sun.tools.javac.Main.compile(args, pw); + pw.close(); + if (rc == 0) { + System.err.println("Compilation of " + file.getName() + + " didn't fail as expected."); + errors++; + return false; + } else return true; + } + + private boolean assert_compile_succeed(final File file) { + final String filename = file.getPath(); + final String[] args = { filename }; + final StringWriter sw = new StringWriter(); + final PrintWriter pw = new PrintWriter(sw); + final int rc = com.sun.tools.javac.Main.compile(args, pw); + pw.close(); + if (rc != 0) { + System.err.println("Compilation of " + file.getName() + + " didn't succeed as expected. Output:"); + System.err.println(sw.toString()); + errors++; + return false; + } else return true; + } + + private File writeFile(final File dir, + final String path, + final String body) throws IOException { + final File f = new File(dir, path); + f.getParentFile().mkdirs(); + final FileWriter out = new FileWriter(f); + out.write(body); + out.close(); + return f; + } + + public static void main(String... args) throws Exception { + new ShadowingTest().run(); + } + +} From b87db568f08306339fb64c78c43a418da5051e41 Mon Sep 17 00:00:00 2001 From: Henry Jen Date: Mon, 26 Aug 2013 22:32:50 -0700 Subject: [PATCH 093/218] 8023275: Wrapping collections should override default methods Reviewed-by: mduigou, psandoz --- .../share/classes/java/util/Collections.java | 57 ++++++- jdk/test/java/util/Collections/Wrappers.java | 146 ++++++++++++++++++ 2 files changed, 197 insertions(+), 6 deletions(-) create mode 100644 jdk/test/java/util/Collections/Wrappers.java diff --git a/jdk/src/share/classes/java/util/Collections.java b/jdk/src/share/classes/java/util/Collections.java index 16263277f70..2404b4fc9ad 100644 --- a/jdk/src/share/classes/java/util/Collections.java +++ b/jdk/src/share/classes/java/util/Collections.java @@ -27,7 +27,6 @@ package java.util; import java.io.Serializable; import java.io.ObjectOutputStream; import java.io.IOException; -import java.io.InvalidObjectException; import java.lang.reflect.Array; import java.util.function.BiConsumer; import java.util.function.BiFunction; @@ -35,6 +34,7 @@ import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Predicate; import java.util.function.UnaryOperator; +import java.util.stream.IntStream; import java.util.stream.Stream; import java.util.stream.StreamSupport; @@ -1148,7 +1148,16 @@ public class Collections { public Spliterator spliterator() { return (Spliterator)c.spliterator(); } - + @SuppressWarnings("unchecked") + @Override + public Stream stream() { + return (Stream)c.stream(); + } + @SuppressWarnings("unchecked") + @Override + public Stream parallelStream() { + return (Stream)c.parallelStream(); + } } /** @@ -2009,8 +2018,8 @@ public class Collections { * through the returned collection.

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

      *  Collection c = Collections.synchronizedCollection(myCollection);
      *     ...
@@ -2120,6 +2129,14 @@ public class Collections {
         public Spliterator spliterator() {
             return c.spliterator(); // Must be manually synched by user!
         }
+        @Override
+        public Stream stream() {
+            return c.stream(); // Must be manually synched by user!
+        }
+        @Override
+        public Stream parallelStream() {
+            return c.parallelStream(); // Must be manually synched by user!
+        }
         private void writeObject(ObjectOutputStream s) throws IOException {
             synchronized (mutex) {s.defaultWriteObject();}
         }
@@ -3172,6 +3189,10 @@ public class Collections {
         }
         @Override
         public Spliterator spliterator() {return c.spliterator();}
+        @Override
+        public Stream stream()           {return c.stream();}
+        @Override
+        public Stream parallelStream()   {return c.parallelStream();}
     }
 
     /**
@@ -5096,6 +5117,22 @@ public class Collections {
                                                    ") > toIndex(" + toIndex + ")");
             return new CopiesList<>(toIndex - fromIndex, element);
         }
+
+        // Override default methods in Collection
+        @Override
+        public Stream stream() {
+            return IntStream.range(0, n).mapToObj(i -> element);
+        }
+
+        @Override
+        public Stream parallelStream() {
+            return IntStream.range(0, n).parallel().mapToObj(i -> element);
+        }
+
+        @Override
+        public Spliterator spliterator() {
+            return stream().spliterator();
+        }
     }
 
     /**
@@ -5503,6 +5540,10 @@ public class Collections {
 
         @Override
         public Spliterator spliterator() {return s.spliterator();}
+        @Override
+        public Stream stream()           {return s.stream();}
+        @Override
+        public Stream parallelStream()   {return s.parallelStream();}
 
         private static final long serialVersionUID = 2454657854757543876L;
 
@@ -5568,10 +5609,14 @@ public class Collections {
         @Override
         public void forEach(Consumer action) {q.forEach(action);}
         @Override
-        public Spliterator spliterator() {return q.spliterator();}
-        @Override
         public boolean removeIf(Predicate filter) {
             return q.removeIf(filter);
         }
+        @Override
+        public Spliterator spliterator() {return q.spliterator();}
+        @Override
+        public Stream stream()           {return q.stream();}
+        @Override
+        public Stream parallelStream()   {return q.parallelStream();}
     }
 }
diff --git a/jdk/test/java/util/Collections/Wrappers.java b/jdk/test/java/util/Collections/Wrappers.java
new file mode 100644
index 00000000000..3882a4efdd1
--- /dev/null
+++ b/jdk/test/java/util/Collections/Wrappers.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @run testng Wrappers
+ * @summary Ensure Collections wrapping classes provide non-default implementations
+ */
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Objects;
+import java.util.TreeMap;
+import java.util.TreeSet;
+
+import org.testng.annotations.Test;
+import org.testng.annotations.DataProvider;
+
+import static org.testng.Assert.assertFalse;
+
+@Test(groups = "unit")
+public class Wrappers {
+    static Object[][] collections;
+
+    @DataProvider(name="collections")
+    public static Object[][] collectionCases() {
+        if (collections != null) {
+            return collections;
+        }
+
+        List cases = new ArrayList<>();
+        LinkedList seedList = new LinkedList<>();
+        ArrayList seedRandomAccess = new ArrayList<>();
+        TreeSet seedSet = new TreeSet<>();
+        TreeMap seedMap = new TreeMap<>();
+
+        for (int i = 1; i <= 10; i++) {
+            seedList.add(i);
+            seedRandomAccess.add(i);
+            seedSet.add(i);
+            seedMap.put(i, i);
+        }
+
+        cases.add(new Object[] { Collections.unmodifiableCollection(seedList) });
+        cases.add(new Object[] { Collections.unmodifiableList(seedList) });
+        cases.add(new Object[] { Collections.unmodifiableList(seedRandomAccess) });
+        cases.add(new Object[] { Collections.unmodifiableSet(seedSet) });
+        cases.add(new Object[] { Collections.unmodifiableSortedSet(seedSet) });
+        cases.add(new Object[] { Collections.unmodifiableNavigableSet(seedSet) });
+
+        // As sets from map also need to be unmodifiable, thus a wrapping
+        // layer exist and should not have default methods
+        cases.add(new Object[] { Collections.unmodifiableMap(seedMap).entrySet() });
+        cases.add(new Object[] { Collections.unmodifiableMap(seedMap).keySet() });
+        cases.add(new Object[] { Collections.unmodifiableMap(seedMap).values() });
+        cases.add(new Object[] { Collections.unmodifiableSortedMap(seedMap).entrySet() });
+        cases.add(new Object[] { Collections.unmodifiableSortedMap(seedMap).keySet() });
+        cases.add(new Object[] { Collections.unmodifiableSortedMap(seedMap).values() });
+        cases.add(new Object[] { Collections.unmodifiableNavigableMap(seedMap).entrySet() });
+        cases.add(new Object[] { Collections.unmodifiableNavigableMap(seedMap).keySet() });
+        cases.add(new Object[] { Collections.unmodifiableNavigableMap(seedMap).values() });
+
+        // Synchronized
+        cases.add(new Object[] { Collections.synchronizedCollection(seedList) });
+        cases.add(new Object[] { Collections.synchronizedList(seedList) });
+        cases.add(new Object[] { Collections.synchronizedList(seedRandomAccess) });
+        cases.add(new Object[] { Collections.synchronizedSet(seedSet) });
+        cases.add(new Object[] { Collections.synchronizedSortedSet(seedSet) });
+        cases.add(new Object[] { Collections.synchronizedNavigableSet(seedSet) });
+
+        // As sets from map also need to be synchronized on the map, thus a
+        // wrapping layer exist and should not have default methods
+        cases.add(new Object[] { Collections.synchronizedMap(seedMap).entrySet() });
+        cases.add(new Object[] { Collections.synchronizedMap(seedMap).keySet() });
+        cases.add(new Object[] { Collections.synchronizedMap(seedMap).values() });
+        cases.add(new Object[] { Collections.synchronizedSortedMap(seedMap).entrySet() });
+        cases.add(new Object[] { Collections.synchronizedSortedMap(seedMap).keySet() });
+        cases.add(new Object[] { Collections.synchronizedSortedMap(seedMap).values() });
+        cases.add(new Object[] { Collections.synchronizedNavigableMap(seedMap).entrySet() });
+        cases.add(new Object[] { Collections.synchronizedNavigableMap(seedMap).keySet() });
+        cases.add(new Object[] { Collections.synchronizedNavigableMap(seedMap).values() });
+
+        // Checked
+        cases.add(new Object[] { Collections.checkedCollection(seedList, Integer.class) });
+        cases.add(new Object[] { Collections.checkedList(seedList, Integer.class) });
+        cases.add(new Object[] { Collections.checkedList(seedRandomAccess, Integer.class) });
+        cases.add(new Object[] { Collections.checkedSet(seedSet, Integer.class) });
+        cases.add(new Object[] { Collections.checkedSortedSet(seedSet, Integer.class) });
+        cases.add(new Object[] { Collections.checkedNavigableSet(seedSet, Integer.class) });
+        cases.add(new Object[] { Collections.checkedQueue(seedList, Integer.class) });
+
+        // asLifoQueue is another wrapper
+        cases.add(new Object[] { Collections.asLifoQueue(seedList) });
+
+        collections = cases.toArray(new Object[0][]);
+        return collections;
+    }
+
+    static Method[] defaultMethods;
+
+    static {
+        List list = new ArrayList<>();
+        Method[] methods = Collection.class.getMethods();
+        for (Method m: methods) {
+            if (m.isDefault()) {
+                list.add(m);
+            }
+        }
+        defaultMethods = list.toArray(new Method[0]);
+    }
+
+    @Test(dataProvider = "collections")
+    public static void testAllDefaultMethodsOverridden(Collection c) throws NoSuchMethodException {
+        Class cls = c.getClass();
+        for (Method m: defaultMethods) {
+            Method m2 = cls.getMethod(m.getName(), m.getParameterTypes());
+            // default had been override
+            assertFalse(m2.isDefault(), cls.getCanonicalName());
+        }
+    }
+}
+

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

To correct the wrong GroupCurly group index backoff code

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

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

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

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

diff --git a/jdk/src/share/classes/java/util/Comparator.java b/jdk/src/share/classes/java/util/Comparator.java
index 55d5efb9866..b19481df198 100644
--- a/jdk/src/share/classes/java/util/Comparator.java
+++ b/jdk/src/share/classes/java/util/Comparator.java
@@ -199,7 +199,7 @@ public interface Comparator {
      * composed using following code,
      *
      * 
{@code
-     *     Comparator cmp = Comparator.comparing(String::length)
+     *     Comparator cmp = Comparator.comparingInt(String::length)
      *             .thenComparing(String.CASE_INSENSITIVE_ORDER);
      * }
* @@ -270,18 +270,18 @@ public interface Comparator { * extracts a {@code int} sort key. * * @implSpec This default implementation behaves as if {@code - * thenComparing(comparing(keyExtractor))}. + * thenComparing(comparingInt(keyExtractor))}. * * @param keyExtractor the function used to extract the integer sort key * @return a lexicographic-order comparator composed of this and then the * {@code int} sort key * @throws NullPointerException if the argument is null. - * @see #comparing(ToIntFunction) + * @see #comparingInt(ToIntFunction) * @see #thenComparing(Comparator) * @since 1.8 */ - default Comparator thenComparing(ToIntFunction keyExtractor) { - return thenComparing(comparing(keyExtractor)); + default Comparator thenComparingInt(ToIntFunction keyExtractor) { + return thenComparing(comparingInt(keyExtractor)); } /** @@ -289,18 +289,18 @@ public interface Comparator { * extracts a {@code long} sort key. * * @implSpec This default implementation behaves as if {@code - * thenComparing(comparing(keyExtractor))}. + * thenComparing(comparingLong(keyExtractor))}. * * @param keyExtractor the function used to extract the long sort key * @return a lexicographic-order comparator composed of this and then the * {@code long} sort key * @throws NullPointerException if the argument is null. - * @see #comparing(ToLongFunction) + * @see #comparingLong(ToLongFunction) * @see #thenComparing(Comparator) * @since 1.8 */ - default Comparator thenComparing(ToLongFunction keyExtractor) { - return thenComparing(comparing(keyExtractor)); + default Comparator thenComparingLong(ToLongFunction keyExtractor) { + return thenComparing(comparingLong(keyExtractor)); } /** @@ -308,18 +308,18 @@ public interface Comparator { * extracts a {@code double} sort key. * * @implSpec This default implementation behaves as if {@code - * thenComparing(comparing(keyExtractor))}. + * thenComparing(comparingDouble(keyExtractor))}. * * @param keyExtractor the function used to extract the double sort key * @return a lexicographic-order comparator composed of this and then the * {@code double} sort key * @throws NullPointerException if the argument is null. - * @see #comparing(ToDoubleFunction) + * @see #comparingDouble(ToDoubleFunction) * @see #thenComparing(Comparator) * @since 1.8 */ - default Comparator thenComparing(ToDoubleFunction keyExtractor) { - return thenComparing(comparing(keyExtractor)); + default Comparator thenComparingDouble(ToDoubleFunction keyExtractor) { + return thenComparing(comparingDouble(keyExtractor)); } /** @@ -484,7 +484,7 @@ public interface Comparator { * @throws NullPointerException if the argument is null * @since 1.8 */ - public static Comparator comparing(ToIntFunction keyExtractor) { + public static Comparator comparingInt(ToIntFunction keyExtractor) { Objects.requireNonNull(keyExtractor); return (Comparator & Serializable) (c1, c2) -> Integer.compare(keyExtractor.applyAsInt(c1), keyExtractor.applyAsInt(c2)); @@ -505,7 +505,7 @@ public interface Comparator { * @throws NullPointerException if the argument is null * @since 1.8 */ - public static Comparator comparing(ToLongFunction keyExtractor) { + public static Comparator comparingLong(ToLongFunction keyExtractor) { Objects.requireNonNull(keyExtractor); return (Comparator & Serializable) (c1, c2) -> Long.compare(keyExtractor.applyAsLong(c1), keyExtractor.applyAsLong(c2)); @@ -526,7 +526,7 @@ public interface Comparator { * @throws NullPointerException if the argument is null * @since 1.8 */ - public static Comparator comparing(ToDoubleFunction keyExtractor) { + public static Comparator comparingDouble(ToDoubleFunction keyExtractor) { Objects.requireNonNull(keyExtractor); return (Comparator & Serializable) (c1, c2) -> Double.compare(keyExtractor.applyAsDouble(c1), keyExtractor.applyAsDouble(c2)); diff --git a/jdk/test/java/util/Comparator/BasicTest.java b/jdk/test/java/util/Comparator/BasicTest.java index 5bbb700e0b3..b4eb5d4ac40 100644 --- a/jdk/test/java/util/Comparator/BasicTest.java +++ b/jdk/test/java/util/Comparator/BasicTest.java @@ -90,7 +90,7 @@ public class BasicTest { Thing[] things = new Thing[intValues.length]; for (int i=0; i comp = Comparator.comparing(new ToIntFunction() { + Comparator comp = Comparator.comparingInt(new ToIntFunction() { @Override public int applyAsInt(Thing thing) { return thing.getIntField(); @@ -104,7 +104,7 @@ public class BasicTest { Thing[] things = new Thing[longValues.length]; for (int i=0; i comp = Comparator.comparing(new ToLongFunction() { + Comparator comp = Comparator.comparingLong(new ToLongFunction() { @Override public long applyAsLong(Thing thing) { return thing.getLongField(); @@ -118,7 +118,7 @@ public class BasicTest { Thing[] things = new Thing[doubleValues.length]; for (int i=0; i comp = Comparator.comparing(new ToDoubleFunction() { + Comparator comp = Comparator.comparingDouble(new ToDoubleFunction() { @Override public double applyAsDouble(Thing thing) { return thing.getDoubleField(); @@ -211,8 +211,8 @@ public class BasicTest { }; public void testComparatorDefaultMethods() { - Comparator cmp = Comparator.comparing((Function) People::getFirstName); - Comparator cmp2 = Comparator.comparing((Function) People::getLastName); + Comparator cmp = Comparator.comparing(People::getFirstName); + Comparator cmp2 = Comparator.comparing(People::getLastName); // reverseOrder assertComparison(cmp.reversed(), people[1], people[0]); // thenComparing(Comparator) @@ -222,20 +222,20 @@ public class BasicTest { assertComparison(cmp.thenComparing(People::getLastName), people[0], people[1]); assertComparison(cmp.thenComparing(People::getLastName), people[4], people[0]); // thenComparing(ToIntFunction) - assertComparison(cmp.thenComparing(People::getAge), people[0], people[1]); - assertComparison(cmp.thenComparing(People::getAge), people[1], people[5]); + assertComparison(cmp.thenComparingInt(People::getAge), people[0], people[1]); + assertComparison(cmp.thenComparingInt(People::getAge), people[1], people[5]); // thenComparing(ToLongFunction) - assertComparison(cmp.thenComparing(People::getAgeAsLong), people[0], people[1]); - assertComparison(cmp.thenComparing(People::getAgeAsLong), people[1], people[5]); + assertComparison(cmp.thenComparingLong(People::getAgeAsLong), people[0], people[1]); + assertComparison(cmp.thenComparingLong(People::getAgeAsLong), people[1], people[5]); // thenComparing(ToDoubleFunction) - assertComparison(cmp.thenComparing(People::getAgeAsDouble), people[0], people[1]); - assertComparison(cmp.thenComparing(People::getAgeAsDouble), people[1], people[5]); + assertComparison(cmp.thenComparingDouble(People::getAgeAsDouble), people[0], people[1]); + assertComparison(cmp.thenComparingDouble(People::getAgeAsDouble), people[1], people[5]); } public void testNullsFirst() { Comparator strcmp = Comparator.nullsFirst(Comparator.naturalOrder()); - Comparator cmp = Comparator.comparing(People::getLastName, strcmp) + Comparator cmp = Comparator.comparing(People::getLastName, strcmp) .thenComparing(People::getFirstName, strcmp); // Mary.null vs Mary.Cook - solve by last name assertComparison(cmp, people[6], people[5]); @@ -243,7 +243,7 @@ public class BasicTest { assertComparison(cmp, people[7], people[6]); // More than one thenComparing - strcmp = Comparator.nullsFirst(Comparator.comparing((ToIntFunction) String::length) + strcmp = Comparator.nullsFirst(Comparator.comparingInt(String::length) .thenComparing(String.CASE_INSENSITIVE_ORDER)); assertComparison(strcmp, null, "abc"); assertComparison(strcmp, "ab", "abc"); @@ -273,7 +273,7 @@ public class BasicTest { public void testNullsLast() { Comparator strcmp = Comparator.nullsLast(Comparator.naturalOrder()); - Comparator cmp = Comparator.comparing(People::getLastName, strcmp) + Comparator cmp = Comparator.comparing(People::getLastName, strcmp) .thenComparing(People::getFirstName, strcmp); // Mary.null vs Mary.Cook - solve by last name assertComparison(cmp, people[5], people[6]); @@ -281,7 +281,7 @@ public class BasicTest { assertComparison(cmp, people[7], people[6]); // More than one thenComparing - strcmp = Comparator.nullsLast(Comparator.comparing((ToIntFunction) String::length) + strcmp = Comparator.nullsLast(Comparator.comparingInt(String::length) .thenComparing(String.CASE_INSENSITIVE_ORDER)); assertComparison(strcmp, "abc", null); assertComparison(strcmp, "ab", "abc"); @@ -341,28 +341,28 @@ public class BasicTest { } catch (NullPointerException npe) {} try { - Comparator cmp = Comparator.comparing((Function) null, Comparator.naturalOrder()); + Comparator cmp = Comparator.comparing(null, Comparator.naturalOrder()); fail("comparing(null, cmp) should throw NPE"); } catch (NullPointerException npe) {} try { - Comparator cmp = Comparator.comparing((Function) People::getFirstName, null); + Comparator cmp = Comparator.comparing(People::getFirstName, null); fail("comparing(f, null) should throw NPE"); } catch (NullPointerException npe) {} try { - Comparator cmp = Comparator.comparing((Function) null); + Comparator cmp = Comparator.comparing(null); fail("comparing(null) should throw NPE"); } catch (NullPointerException npe) {} try { - Comparator cmp = Comparator.comparing((ToIntFunction) null); + Comparator cmp = Comparator.comparingInt(null); fail("comparing(null) should throw NPE"); } catch (NullPointerException npe) {} try { - Comparator cmp = Comparator.comparing((ToLongFunction) null); + Comparator cmp = Comparator.comparingLong(null); fail("comparing(null) should throw NPE"); } catch (NullPointerException npe) {} try { - Comparator cmp = Comparator.comparing((ToDoubleFunction) null); + Comparator cmp = Comparator.comparingDouble(null); fail("comparing(null) should throw NPE"); } catch (NullPointerException npe) {} } diff --git a/jdk/test/java/util/Map/EntryComparators.java b/jdk/test/java/util/Map/EntryComparators.java index ce607a36901..631107eada9 100644 --- a/jdk/test/java/util/Map/EntryComparators.java +++ b/jdk/test/java/util/Map/EntryComparators.java @@ -115,8 +115,8 @@ public class EntryComparators { // Comparator cmp = Comparator.naturalOrder(); // Should fail to compiler as People is not comparable // We can use simple comparator, but those have been tested above. // Thus choose to do compose for some level of interation. - Comparator cmp1 = Comparator.comparing((Function) People::getFirstName); - Comparator cmp2 = Comparator.comparing((Function) People::getLastName); + Comparator cmp1 = Comparator.comparing(People::getFirstName); + Comparator cmp2 = Comparator.comparing(People::getLastName); Comparator cmp = cmp1.thenComparing(cmp2); assertPairComparison(people[0], people[0], people[1], people[1], diff --git a/jdk/test/java/util/function/BinaryOperator/BasicTest.java b/jdk/test/java/util/function/BinaryOperator/BasicTest.java index 1519fb88177..0c37a9c5c62 100644 --- a/jdk/test/java/util/function/BinaryOperator/BasicTest.java +++ b/jdk/test/java/util/function/BinaryOperator/BasicTest.java @@ -67,26 +67,26 @@ public class BasicTest { }; public void testMaxBy() { - Comparator cmp = Comparator.comparing((Function) People::getFirstName); + Comparator cmp = Comparator.comparing(People::getFirstName); // lesser assertSame(maxBy(cmp).apply(people[0], people[1]), people[1]); // euqal - cmp = Comparator.comparing((Function) People::getLastName); + cmp = Comparator.comparing(People::getLastName); assertSame(maxBy(cmp).apply(people[0], people[1]), people[0]); // greater - cmp = Comparator.comparing((ToIntFunction) People::getAge); + cmp = Comparator.comparingInt(People::getAge); assertSame(maxBy(cmp).apply(people[0], people[1]), people[0]); } - public void testLesserOf() { - Comparator cmp = Comparator.comparing((Function) People::getFirstName); + public void testMinBy() { + Comparator cmp = Comparator.comparing(People::getFirstName); // lesser assertSame(minBy(cmp).apply(people[0], people[1]), people[0]); // euqal - cmp = Comparator.comparing((Function) People::getLastName); + cmp = Comparator.comparing(People::getLastName); assertSame(minBy(cmp).apply(people[0], people[1]), people[0]); // greater - cmp = Comparator.comparing((ToIntFunction) People::getAge); + cmp = Comparator.comparingInt(People::getAge); assertSame(minBy(cmp).apply(people[0], people[1]), people[1]); } From f3ca3801d9915c9fa6b70bc085584e959bfcca67 Mon Sep 17 00:00:00 2001 From: Vladimir Kempik Date: Wed, 21 Aug 2013 22:12:11 -0700 Subject: [PATCH 096/218] 8020530: Non heap memory size calculated incorrectly Reviewed-by: coleenp, sla --- hotspot/src/share/vm/services/management.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/hotspot/src/share/vm/services/management.cpp b/hotspot/src/share/vm/services/management.cpp index a2c8944ee42..5cc0cc4ffcc 100644 --- a/hotspot/src/share/vm/services/management.cpp +++ b/hotspot/src/share/vm/services/management.cpp @@ -876,8 +876,6 @@ JVM_ENTRY(jobject, jmm_GetMemoryUsage(JNIEnv* env, jboolean heap)) total_used += u.used(); total_committed += u.committed(); - // if any one of the memory pool has undefined init_size or max_size, - // set it to -1 if (u.init_size() == (size_t)-1) { has_undefined_init_size = true; } @@ -894,6 +892,15 @@ JVM_ENTRY(jobject, jmm_GetMemoryUsage(JNIEnv* env, jboolean heap)) } } + // if any one of the memory pool has undefined init_size or max_size, + // set it to -1 + if (has_undefined_init_size) { + total_init = (size_t)-1; + } + if (has_undefined_max_size) { + total_max = (size_t)-1; + } + MemoryUsage usage((heap ? InitialHeapSize : total_init), total_used, total_committed, From 7b989a82fd6d727cef92ff53884c2bf7aef26bbc Mon Sep 17 00:00:00 2001 From: Vicente Romero Date: Thu, 22 Aug 2013 10:22:44 +0100 Subject: [PATCH 097/218] 8022316: Generic throws, overriding and method reference Reviewed-by: jjg, mcimadamore --- .../com/sun/tools/javac/code/Types.java | 23 +++++- ...lerErrorGenericThrowPlusMethodRefTest.java | 78 +++++++++++++++++++ ...ilerErrorGenericThrowPlusMethodRefTest.out | 2 + 3 files changed, 99 insertions(+), 4 deletions(-) create mode 100644 langtools/test/tools/javac/T8022316/CompilerErrorGenericThrowPlusMethodRefTest.java create mode 100644 langtools/test/tools/javac/T8022316/CompilerErrorGenericThrowPlusMethodRefTest.out diff --git a/langtools/src/share/classes/com/sun/tools/javac/code/Types.java b/langtools/src/share/classes/com/sun/tools/javac/code/Types.java index e1887b5f4a6..06744bf6d06 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/code/Types.java +++ b/langtools/src/share/classes/com/sun/tools/javac/code/Types.java @@ -505,12 +505,27 @@ public class Types { //merge thrown types - form the intersection of all the thrown types in //all the signatures in the list + boolean toErase = !bestSoFar.type.hasTag(FORALL); List thrown = null; - for (Symbol msym1 : methodSyms) { - Type mt1 = memberType(origin.type, msym1); + Type mt1 = memberType(origin.type, bestSoFar); + for (Symbol msym2 : methodSyms) { + Type mt2 = memberType(origin.type, msym2); + List thrown_mt2 = mt2.getThrownTypes(); + if (toErase) { + thrown_mt2 = erasure(thrown_mt2); + } else { + /* If bestSoFar is generic then all the methods are generic. + * The opposite is not true: a non generic method can override + * a generic method (raw override) so it's safe to cast mt1 and + * mt2 to ForAll. + */ + ForAll fa1 = (ForAll)mt1; + ForAll fa2 = (ForAll)mt2; + thrown_mt2 = subst(thrown_mt2, fa2.tvars, fa1.tvars); + } thrown = (thrown == null) ? - mt1.getThrownTypes() : - chk.intersect(mt1.getThrownTypes(), thrown); + thrown_mt2 : + chk.intersect(thrown_mt2, thrown); } final List thrown1 = thrown; diff --git a/langtools/test/tools/javac/T8022316/CompilerErrorGenericThrowPlusMethodRefTest.java b/langtools/test/tools/javac/T8022316/CompilerErrorGenericThrowPlusMethodRefTest.java new file mode 100644 index 00000000000..f7d0391649e --- /dev/null +++ b/langtools/test/tools/javac/T8022316/CompilerErrorGenericThrowPlusMethodRefTest.java @@ -0,0 +1,78 @@ +/* + * 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. + */ + +/* + * @test + * @bug 8022316 + * @summary Generic throws, overriding and method reference + * @compile/fail/ref=CompilerErrorGenericThrowPlusMethodRefTest.out -XDrawDiagnostics CompilerErrorGenericThrowPlusMethodRefTest.java + */ + +@SuppressWarnings("unchecked") +public class CompilerErrorGenericThrowPlusMethodRefTest { + interface SAM11 { + public void foo() throws E ; + } + + interface SAM12 extends SAM11{ + @Override + public void foo() throws Throwable; + } + + public void boo() throws RuntimeException {} + + static void test1() { + try { + SAM12 s2 = new CompilerErrorGenericThrowPlusMethodRefTest()::boo; + s2.foo(); + } catch(Throwable ex) {} + } + + static void test2() { + SAM11 s1 = null; + s1.foo(); + s1.foo(); + } + + interface SAM21 { + void m(E arg) throws E; + } + + interface SAM22 { + void m(F arg) throws F; + } + + interface SAM23 extends SAM21, SAM22 {} + + public void bar(E e) throws E {} + + static void test3(E e) { + try { + SAM23 s2 = new CompilerErrorGenericThrowPlusMethodRefTest()::bar; + s2.m(e); + } catch(Exception ex) {} + } + +} diff --git a/langtools/test/tools/javac/T8022316/CompilerErrorGenericThrowPlusMethodRefTest.out b/langtools/test/tools/javac/T8022316/CompilerErrorGenericThrowPlusMethodRefTest.out new file mode 100644 index 00000000000..58015ae026e --- /dev/null +++ b/langtools/test/tools/javac/T8022316/CompilerErrorGenericThrowPlusMethodRefTest.out @@ -0,0 +1,2 @@ +CompilerErrorGenericThrowPlusMethodRefTest.java:55:26: compiler.err.unreported.exception.need.to.catch.or.throw: java.lang.Exception +1 error From c65abc95dfa512606607d6d6378cf17c1dc34678 Mon Sep 17 00:00:00 2001 From: Vicente Romero Date: Thu, 22 Aug 2013 13:12:43 +0100 Subject: [PATCH 098/218] 8023112: javac should not use lazy constant evaluation approach for method references Reviewed-by: jjg, mcimadamore --- .../com/sun/tools/javac/comp/Attr.java | 4 +- .../com/sun/tools/javac/comp/MemberEnter.java | 56 +++++++++++++++++- ...pLazyConstantCreationForMethodRefTest.java | 58 +++++++++++++++++++ 3 files changed, 113 insertions(+), 5 deletions(-) create mode 100644 langtools/test/tools/javac/T8023112/SkipLazyConstantCreationForMethodRefTest.java diff --git a/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java b/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java index 17557b3f139..6ef409d9339 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java @@ -1063,9 +1063,7 @@ public class Attr extends JCTree.Visitor { if (tree.init != null) { if ((v.flags_field & FINAL) != 0 && - !tree.init.hasTag(NEWCLASS) && - !tree.init.hasTag(LAMBDA) && - !tree.init.hasTag(REFERENCE)) { + memberEnter.needsLazyConstValue(tree.init)) { // In this case, `v' is final. Ensure that it's initializer is // evaluated. v.getConstValue(); // ensure initializer is evaluated diff --git a/langtools/src/share/classes/com/sun/tools/javac/comp/MemberEnter.java b/langtools/src/share/classes/com/sun/tools/javac/comp/MemberEnter.java index cdd3db2bcdd..9f9dd4fb874 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/comp/MemberEnter.java +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/MemberEnter.java @@ -677,8 +677,7 @@ public class MemberEnter extends JCTree.Visitor implements Completer { if (tree.init != null) { v.flags_field |= HASINIT; if ((v.flags_field & FINAL) != 0 && - !tree.init.hasTag(NEWCLASS) && - !tree.init.hasTag(LAMBDA)) { + needsLazyConstValue(tree.init)) { Env initEnv = getInitEnv(tree, env); initEnv.info.enclVar = v; v.setLazyConstValue(initEnv(tree, initEnv), attr, tree.init); @@ -700,6 +699,59 @@ public class MemberEnter extends JCTree.Visitor implements Completer { } } + public boolean needsLazyConstValue(JCTree tree) { + InitTreeVisitor initTreeVisitor = new InitTreeVisitor(); + tree.accept(initTreeVisitor); + return initTreeVisitor.result; + } + + /** Visitor class for expressions which might be constant expressions. + */ + static class InitTreeVisitor extends JCTree.Visitor { + + private boolean result = true; + + @Override + public void visitTree(JCTree tree) {} + + @Override + public void visitNewClass(JCNewClass that) { + result = false; + } + + @Override + public void visitLambda(JCLambda that) { + result = false; + } + + @Override + public void visitReference(JCMemberReference that) { + result = false; + } + + @Override + public void visitSelect(JCFieldAccess tree) { + tree.selected.accept(this); + } + + @Override + public void visitConditional(JCConditional tree) { + tree.cond.accept(this); + tree.truepart.accept(this); + tree.falsepart.accept(this); + } + + @Override + public void visitParens(JCParens tree) { + tree.expr.accept(this); + } + + @Override + public void visitTypeCast(JCTypeCast tree) { + tree.expr.accept(this); + } + } + /** Create a fresh environment for a variable's initializer. * If the variable is a field, the owner of the environment's scope * is be the variable itself, otherwise the owner is the method diff --git a/langtools/test/tools/javac/T8023112/SkipLazyConstantCreationForMethodRefTest.java b/langtools/test/tools/javac/T8023112/SkipLazyConstantCreationForMethodRefTest.java new file mode 100644 index 00000000000..e0c530c5c47 --- /dev/null +++ b/langtools/test/tools/javac/T8023112/SkipLazyConstantCreationForMethodRefTest.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. 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 8023112 + * @summary Mixing up the method type argument with the class type for method + * reference ClassType::new + * @compile SkipLazyConstantCreationForMethodRefTest.java + */ + +public class SkipLazyConstantCreationForMethodRefTest { + SkipLazyConstantCreationForMethodRefTest(int a, boolean b) {} + SkipLazyConstantCreationForMethodRefTest() {} +} + +class SubClass extends SkipLazyConstantCreationForMethodRefTest { + SubClass(int a, boolean b) {} +} + +interface SAM { + SubClass m(int a, boolean b); +} + +interface Tester1 { + SAM s11 = SubClass::new; + SAM s12 = (SubClass::new); + SAM s13 = (SAM)SubClass::new; + SAM s14 = true ? s11 : s12; + SAM s15 = true ? s11 : (SAM)SubClass::new; + SAM s16 = true ? (SAM)SubClass::new : s12; +} + +interface Tester2 { + SAM s21 = Tester1.s11; +} From cc6216ae2ecdf8d51eb70ebd4aeb8f361c740fef Mon Sep 17 00:00:00 2001 From: Athijegannathan Sundararajan Date: Thu, 22 Aug 2013 18:46:26 +0530 Subject: [PATCH 099/218] 8023551: Mirror functions can not be invoked using invokeMethod, invokeFunction Reviewed-by: attila, jlaskey, lagergren --- .../api/scripting/NashornScriptEngine.java | 15 ++++--- .../api/scripting/ScriptObjectMirror.java | 20 +++++---- nashorn/test/script/basic/JDK-8023551.js | 42 +++++++++++++++++++ .../test/script/basic/JDK-8023551.js.EXPECTED | 2 + .../api/scripting/ScriptEngineTest.java | 26 ++++++++++++ 5 files changed, 91 insertions(+), 14 deletions(-) create mode 100644 nashorn/test/script/basic/JDK-8023551.js create mode 100644 nashorn/test/script/basic/JDK-8023551.js.EXPECTED diff --git a/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngine.java b/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngine.java index 063bc08fd70..e3f09139e95 100644 --- a/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngine.java +++ b/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngine.java @@ -321,10 +321,11 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C private ScriptObject getNashornGlobalFrom(final ScriptContext ctxt) { final Bindings bindings = ctxt.getBindings(ScriptContext.ENGINE_SCOPE); if (bindings instanceof ScriptObjectMirror) { - ScriptObject sobj = ((ScriptObjectMirror)bindings).getScriptObject(); - if (sobj instanceof GlobalObject) { - return sobj; - } + final ScriptObjectMirror mirror = (ScriptObjectMirror)bindings; + ScriptObject sobj = ((ScriptObjectMirror)bindings).getScriptObject(); + if (sobj instanceof GlobalObject && sobj.isOfContext(nashornContext)) { + return sobj; + } } // didn't find global object from context given - return the engine-wide global @@ -402,8 +403,10 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C args = ScriptRuntime.EMPTY_ARRAY; } // if no arguments passed, expose it - args = ((GlobalObject)ctxtGlobal).wrapAsObject(args); - ctxtGlobal.set("arguments", args, false); + if (! (args instanceof ScriptObject)) { + args = ((GlobalObject)ctxtGlobal).wrapAsObject(args); + ctxtGlobal.set("arguments", args, false); + } } private Object invokeImpl(final Object selfObject, final String name, final Object... args) throws ScriptException, NoSuchMethodException { diff --git a/nashorn/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java b/nashorn/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java index dbdb9b67bd5..0e11c8af8cf 100644 --- a/nashorn/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java +++ b/nashorn/src/jdk/nashorn/api/scripting/ScriptObjectMirror.java @@ -99,12 +99,14 @@ public final class ScriptObjectMirror extends JSObject implements Bindings { } final Object val = functionName == null? sobj : sobj.get(functionName); - if (! (val instanceof ScriptFunction)) { - throw new NoSuchMethodException("No such function " + ((functionName != null)? functionName : "")); + if (val instanceof ScriptFunction) { + final Object[] modArgs = globalChanged? wrapArray(args, oldGlobal) : args; + return wrap(ScriptRuntime.checkAndApply((ScriptFunction)val, sobj, unwrapArray(modArgs, global)), global); + } else if (val instanceof ScriptObjectMirror && ((ScriptObjectMirror)val).isFunction()) { + return ((ScriptObjectMirror)val).call(null, args); } - final Object[] modArgs = globalChanged? wrapArray(args, oldGlobal) : args; - return wrap(ScriptRuntime.checkAndApply((ScriptFunction)val, sobj, unwrapArray(modArgs, global)), global); + throw new NoSuchMethodException("No such function " + ((functionName != null)? functionName : "")); } catch (final RuntimeException | Error e) { throw e; } catch (final Throwable t) { @@ -127,12 +129,14 @@ public final class ScriptObjectMirror extends JSObject implements Bindings { } final Object val = functionName == null? sobj : sobj.get(functionName); - if (! (val instanceof ScriptFunction)) { - throw new RuntimeException("not a constructor " + ((functionName != null)? functionName : "")); + if (val instanceof ScriptFunction) { + final Object[] modArgs = globalChanged? wrapArray(args, oldGlobal) : args; + return wrap(ScriptRuntime.checkAndConstruct((ScriptFunction)val, unwrapArray(modArgs, global)), global); + } else if (val instanceof ScriptObjectMirror && ((ScriptObjectMirror)val).isFunction()) { + return ((ScriptObjectMirror)val).newObject(null, args); } - final Object[] modArgs = globalChanged? wrapArray(args, oldGlobal) : args; - return wrap(ScriptRuntime.checkAndConstruct((ScriptFunction)val, unwrapArray(modArgs, global)), global); + throw new RuntimeException("not a constructor " + ((functionName != null)? functionName : "")); } catch (final RuntimeException | Error e) { throw e; } catch (final Throwable t) { diff --git a/nashorn/test/script/basic/JDK-8023551.js b/nashorn/test/script/basic/JDK-8023551.js new file mode 100644 index 00000000000..8545fbb5ef4 --- /dev/null +++ b/nashorn/test/script/basic/JDK-8023551.js @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * JDK-8023551: Mirror functions can not be invoked using invokeMethod, invokeFunction + * + * @test + * @run + */ + +var m = new javax.script.ScriptEngineManager(); +var e = m.getEngineByName("nashorn"); + +function func(x) { + print("func: " + x); +} + +e.put("func", func); +e.invokeFunction("func", "hello"); + +var obj = e.eval("({ foo: func })"); +e.invokeMethod(obj, "foo", "world"); diff --git a/nashorn/test/script/basic/JDK-8023551.js.EXPECTED b/nashorn/test/script/basic/JDK-8023551.js.EXPECTED new file mode 100644 index 00000000000..90e9041f6fc --- /dev/null +++ b/nashorn/test/script/basic/JDK-8023551.js.EXPECTED @@ -0,0 +1,2 @@ +func: hello +func: world diff --git a/nashorn/test/src/jdk/nashorn/api/scripting/ScriptEngineTest.java b/nashorn/test/src/jdk/nashorn/api/scripting/ScriptEngineTest.java index fe4bf39ba45..3cad7095517 100644 --- a/nashorn/test/src/jdk/nashorn/api/scripting/ScriptEngineTest.java +++ b/nashorn/test/src/jdk/nashorn/api/scripting/ScriptEngineTest.java @@ -1256,4 +1256,30 @@ public class ScriptEngineTest { // dos2unix - fix line endings if running on windows assertEquals(sw.toString().replaceAll("\r", ""), "34 true hello\n"); } + + @Test + public void mirrorNewObjectGlobalFunctionTest() throws ScriptException { + final ScriptEngineManager m = new ScriptEngineManager(); + final ScriptEngine e = m.getEngineByName("nashorn"); + final ScriptEngine e2 = m.getEngineByName("nashorn"); + + e.eval("function func() {}"); + e2.put("foo", e.get("func")); + final Object e2global = e2.eval("this"); + final Object newObj = ((ScriptObjectMirror)e2global).newObject("foo"); + assertTrue(newObj instanceof ScriptObjectMirror); + } + + @Test + public void mirrorNewObjectInstanceFunctionTest() throws ScriptException { + final ScriptEngineManager m = new ScriptEngineManager(); + final ScriptEngine e = m.getEngineByName("nashorn"); + final ScriptEngine e2 = m.getEngineByName("nashorn"); + + e.eval("function func() {}"); + e2.put("func", e.get("func")); + final Object e2obj = e2.eval("({ foo: func })"); + final Object newObj = ((ScriptObjectMirror)e2obj).newObject("foo"); + assertTrue(newObj instanceof ScriptObjectMirror); + } } From 863bbb911b3e84a556cdf0dd56360dc18642408c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hannes=20Walln=C3=B6fer?= Date: Thu, 22 Aug 2013 17:23:50 +0200 Subject: [PATCH 100/218] 8023531: new RegExp('').toString() should return '/(?:)/' Reviewed-by: sundar, jlaskey --- .../internal/runtime/ScriptObject.java | 58 +++++----- .../nashorn/internal/runtime/WithObject.java | 2 +- .../internal/runtime/regexp/RegExp.java | 2 +- nashorn/test/script/basic/JDK-8023531.js | 106 ++++++++++++++++++ 4 files changed, 135 insertions(+), 33 deletions(-) create mode 100644 nashorn/test/script/basic/JDK-8023531.js diff --git a/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java b/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java index 481a708bcb7..363891d9ce4 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java @@ -1008,10 +1008,6 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr return getMap().findProperty(key); } - static String convertKey(final Object key) { - return (key instanceof String) ? (String)key : JSType.toString(key); - } - /** * Overridden by {@link jdk.nashorn.internal.objects.NativeArguments} class (internal use.) * Used for argument access in a vararg function using parameter name. @@ -2374,7 +2370,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr return array.getInt(index); } - return getInt(index, convertKey(key)); + return getInt(index, JSType.toString(key)); } @Override @@ -2386,7 +2382,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr return array.getInt(index); } - return getInt(index, convertKey(key)); + return getInt(index, JSType.toString(key)); } @Override @@ -2398,7 +2394,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr return array.getInt(index); } - return getInt(index, convertKey(key)); + return getInt(index, JSType.toString(key)); } @Override @@ -2409,7 +2405,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr return array.getInt(key); } - return getInt(key, convertKey(key)); + return getInt(key, JSType.toString(key)); } private long getLong(final int index, final String key) { @@ -2451,7 +2447,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr return array.getLong(index); } - return getLong(index, convertKey(key)); + return getLong(index, JSType.toString(key)); } @Override @@ -2463,7 +2459,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr return array.getLong(index); } - return getLong(index, convertKey(key)); + return getLong(index, JSType.toString(key)); } @Override @@ -2475,7 +2471,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr return array.getLong(index); } - return getLong(index, convertKey(key)); + return getLong(index, JSType.toString(key)); } @Override @@ -2486,7 +2482,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr return array.getLong(key); } - return getLong(key, convertKey(key)); + return getLong(key, JSType.toString(key)); } private double getDouble(final int index, final String key) { @@ -2528,7 +2524,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr return array.getDouble(index); } - return getDouble(index, convertKey(key)); + return getDouble(index, JSType.toString(key)); } @Override @@ -2540,7 +2536,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr return array.getDouble(index); } - return getDouble(index, convertKey(key)); + return getDouble(index, JSType.toString(key)); } @Override @@ -2552,7 +2548,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr return array.getDouble(index); } - return getDouble(index, convertKey(key)); + return getDouble(index, JSType.toString(key)); } @Override @@ -2563,7 +2559,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr return array.getDouble(key); } - return getDouble(key, convertKey(key)); + return getDouble(key, JSType.toString(key)); } private Object get(final int index, final String key) { @@ -2605,7 +2601,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr return array.getObject(index); } - return get(index, convertKey(key)); + return get(index, JSType.toString(key)); } @Override @@ -2617,7 +2613,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr return array.getObject(index); } - return get(index, convertKey(key)); + return get(index, JSType.toString(key)); } @Override @@ -2629,7 +2625,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr return array.getObject(index); } - return get(index, convertKey(key)); + return get(index, JSType.toString(key)); } @Override @@ -2640,7 +2636,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr return array.getObject(key); } - return get(key, convertKey(key)); + return get(key, JSType.toString(key)); } /** @@ -2655,7 +2651,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr final long longIndex = index & JSType.MAX_UINT; if (!getArray().has(index)) { - final String key = convertKey(longIndex); + final String key = JSType.toString(longIndex); final FindProperty find = findProperty(key, true); if (find != null) { @@ -2801,7 +2797,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr return; } - final String propName = convertKey(key); + final String propName = JSType.toString(key); final FindProperty find = findProperty(propName, true); setObject(find, strict, propName, value); @@ -3023,7 +3019,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr } } - final FindProperty find = findProperty(convertKey(key), true); + final FindProperty find = findProperty(JSType.toString(key), true); return find != null; } @@ -3040,7 +3036,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr } } - final FindProperty find = findProperty(convertKey(key), true); + final FindProperty find = findProperty(JSType.toString(key), true); return find != null; } @@ -3057,7 +3053,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr } } - final FindProperty find = findProperty(convertKey(key), true); + final FindProperty find = findProperty(JSType.toString(key), true); return find != null; } @@ -3074,7 +3070,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr } } - final FindProperty find = findProperty(convertKey(key), true); + final FindProperty find = findProperty(JSType.toString(key), true); return find != null; } @@ -3087,7 +3083,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr return true; } - final FindProperty find = findProperty(convertKey(key), false); + final FindProperty find = findProperty(JSType.toString(key), false); return find != null; } @@ -3100,7 +3096,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr return true; } - final FindProperty find = findProperty(convertKey(key), false); + final FindProperty find = findProperty(JSType.toString(key), false); return find != null; } @@ -3113,7 +3109,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr return true; } - final FindProperty find = findProperty(convertKey(key), false); + final FindProperty find = findProperty(JSType.toString(key), false); return find != null; } @@ -3126,7 +3122,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr return true; } - final FindProperty find = findProperty(convertKey(key), false); + final FindProperty find = findProperty(JSType.toString(key), false); return find != null; } @@ -3196,7 +3192,7 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr } private boolean deleteObject(final Object key, final boolean strict) { - final String propName = convertKey(key); + final String propName = JSType.toString(key); final FindProperty find = findProperty(propName, false); if (find == null) { diff --git a/nashorn/src/jdk/nashorn/internal/runtime/WithObject.java b/nashorn/src/jdk/nashorn/internal/runtime/WithObject.java index 7c08e8545ab..46de1d13ee5 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/WithObject.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/WithObject.java @@ -73,7 +73,7 @@ public final class WithObject extends ScriptObject implements Scope { public boolean delete(final Object key, final boolean strict) { if (expression instanceof ScriptObject) { final ScriptObject self = (ScriptObject)expression; - final String propName = ScriptObject.convertKey(key); + final String propName = JSType.toString(key); final FindProperty find = self.findProperty(propName, true); diff --git a/nashorn/src/jdk/nashorn/internal/runtime/regexp/RegExp.java b/nashorn/src/jdk/nashorn/internal/runtime/regexp/RegExp.java index ff694b90790..65c944e14c9 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/regexp/RegExp.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/regexp/RegExp.java @@ -60,7 +60,7 @@ public abstract class RegExp { * @param flags the flags string */ protected RegExp(final String source, final String flags) { - this.source = source; + this.source = source.length() == 0 ? "(?:)" : source; for (int i = 0; i < flags.length(); i++) { final char ch = flags.charAt(i); switch (ch) { diff --git a/nashorn/test/script/basic/JDK-8023531.js b/nashorn/test/script/basic/JDK-8023531.js new file mode 100644 index 00000000000..819e46b73cf --- /dev/null +++ b/nashorn/test/script/basic/JDK-8023531.js @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * JDK-8023531: new RegExp('').toString() should return '/(?:)/' + * + * @test + * @run + */ + +if (new RegExp("").toString() !== "/(?:)/") { + throw new Error(); +} else if (!(new RegExp("").test(""))) { + throw new Error(); +} + +if (new RegExp("", "g").toString() !== "/(?:)/g") { + throw new Error(); +} else if (!(new RegExp("", "g").test(""))) { + throw new Error(); +} + +if (new RegExp("", "i").toString() !== "/(?:)/i") { + throw new Error(); +} else if (!(new RegExp("", "i").test(""))) { + throw new Error(); +} + +if (new RegExp("", "m").toString() !== "/(?:)/m") { + throw new Error(); +} else if (!(new RegExp("", "m").test(""))) { + throw new Error(); +} + +if (RegExp("").toString() !== "/(?:)/") { + throw new Error(); +} else if (!RegExp("").test("")) { + throw new Error(); +} + +if (RegExp("", "g").toString() !== "/(?:)/g") { + throw new Error(); +} else if (!RegExp("", "g").test("")) { + throw new Error(); +} + +if (RegExp("", "i").toString() !== "/(?:)/i") { + throw new Error(); +} else if (!RegExp("", "i").test("")) { + throw new Error(); +} + +if (RegExp("", "m").toString() !== "/(?:)/m") { + throw new Error(); +} else if (!RegExp("", "m").test("")) { + throw new Error(); +} + +var re = /abc/; +re.compile(""); +if (re.toString() !== "/(?:)/") { + throw new Error(); +} else if (!re.test("")) { + throw new Error(); +} + +re.compile("", "g"); +if (re.toString() !== "/(?:)/g") { + throw new Error(); +} else if (!re.test("")) { + throw new Error(); +} + +re.compile("", "i"); +if (re.toString() !== "/(?:)/i") { + throw new Error(); +} else if (!re.test("")) { + throw new Error(); +} + +re.compile("", "m"); +if (re.toString() !== "/(?:)/m") { + throw new Error(); +} else if (!re.test("")) { + throw new Error(); +} From 2df9b70f5e59694313df2acb99f92c2e701ce449 Mon Sep 17 00:00:00 2001 From: Harold Seigel Date: Thu, 22 Aug 2013 11:52:27 -0400 Subject: [PATCH 101/218] 7121403: [TESTBUG] runtime/7051189/Xchecksig.sh fails on 64bit solaris 8023393: Need to suppress info message if -Xcheck:jni used with libjsig.dylab on Mac OSX Rewrite 7051189 test in Java, port Linux fix for 7051189 to Mac OSX. Reviewed-by: coleenp, dholmes, mseledtsov, ccheung --- hotspot/src/os/bsd/vm/os_bsd.cpp | 8 +- hotspot/test/runtime/7051189/Xchecksig.sh | 126 ------------------ .../runtime/XCheckJniJsig/XCheckJSig.java | 82 ++++++++++++ 3 files changed, 88 insertions(+), 128 deletions(-) delete mode 100644 hotspot/test/runtime/7051189/Xchecksig.sh create mode 100644 hotspot/test/runtime/XCheckJniJsig/XCheckJSig.java diff --git a/hotspot/src/os/bsd/vm/os_bsd.cpp b/hotspot/src/os/bsd/vm/os_bsd.cpp index cc6d13e2c1d..1db3739fa84 100644 --- a/hotspot/src/os/bsd/vm/os_bsd.cpp +++ b/hotspot/src/os/bsd/vm/os_bsd.cpp @@ -3287,11 +3287,15 @@ void os::Bsd::install_signal_handlers() { // and if UserSignalHandler is installed all bets are off if (CheckJNICalls) { if (libjsig_is_loaded) { - tty->print_cr("Info: libjsig is activated, all active signal checking is disabled"); + if (PrintJNIResolving) { + tty->print_cr("Info: libjsig is activated, all active signal checking is disabled"); + } check_signals = false; } if (AllowUserSignalHandlers) { - tty->print_cr("Info: AllowUserSignalHandlers is activated, all active signal checking is disabled"); + if (PrintJNIResolving) { + tty->print_cr("Info: AllowUserSignalHandlers is activated, all active signal checking is disabled"); + } check_signals = false; } } diff --git a/hotspot/test/runtime/7051189/Xchecksig.sh b/hotspot/test/runtime/7051189/Xchecksig.sh deleted file mode 100644 index 143e1445624..00000000000 --- a/hotspot/test/runtime/7051189/Xchecksig.sh +++ /dev/null @@ -1,126 +0,0 @@ -# -# Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -# or visit www.oracle.com if you need additional information or have any -# questions. -# - - -# @test Xchecksig.sh -# @bug 7051189 -# @summary Need to suppress info message if -xcheck:jni used with libjsig.so -# @run shell Xchecksig.sh -# - -if [ "${TESTSRC}" = "" ] -then - TESTSRC=${PWD} - echo "TESTSRC not set. Using "${TESTSRC}" as default" -fi -echo "TESTSRC=${TESTSRC}" -## Adding common setup Variables for running shell tests. -. ${TESTSRC}/../../test_env.sh - -OS=`uname -s` -case "$OS" in - Windows_* | CYGWIN_* ) - printf "Not testing libjsig.so on Windows. PASSED.\n " - exit 0 - ;; -esac - -JAVA=${TESTJAVA}${FS}bin${FS}java - -# LD_PRELOAD arch needs to match the binary we run, so run the java -# 64-bit binary directly if we are testing 64-bit (bin/ARCH/java). -# Check if TESTVMOPS contains -d64, but cannot use -# java ${TESTVMOPS} to run "java -d64" with LD_PRELOAD. - -if [ ${OS} -eq "SunOS" ] -then - printf "SunOS test TESTVMOPTS = ${TESTVMOPTS}" - printf ${TESTVMOPTS} | grep d64 > /dev/null - if [ $? -eq 0 ] - then - printf "SunOS 64-bit test\n" - BIT_FLAG=-d64 - fi -fi - -ARCH=`uname -p` -case $ARCH in - i386) - if [ X${BIT_FLAG} != "X" ] - then - ARCH=amd64 - JAVA=${TESTJAVA}${FS}bin${FS}${ARCH}${FS}java - fi - ;; - sparc) - if [ X${BIT_FLAG} != "X" ] - then - ARCH=sparcv9 - JAVA=${TESTJAVA}${FS}bin${FS}${ARCH}${FS}java - fi - ;; - * ) - printf "Not testing architecture $ARCH, skipping test.\n" - exit 0 - ;; -esac - -LIBJSIG=${COMPILEJAVA}${FS}jre${FS}lib${FS}${ARCH}${FS}libjsig.so - -# If libjsig and binary do not match, skip test. - -A=`file ${LIBJSIG} | awk '{ print $3 }'` -B=`file ${JAVA} | awk '{ print $3 }'` - -if [ $A -ne $B ] -then - printf "Mismatching binary and library to preload, skipping test.\n" - exit 0 -fi - -if [ ! -f ${LIBJSIG} ] -then - printf "Skipping test: libjsig missing for given architecture: ${LIBJSIG}\n" - exit 0 -fi -# Use java -version to test, java version info appears on stderr, -# the libjsig message we are removing appears on stdout. - -# grep returns zero meaning found, non-zero means not found: - -LD_PRELOAD=${LIBJSIG} ${JAVA} ${TESTVMOPTS} -Xcheck:jni -version 2>&1 | grep "libjsig is activated" -if [ $? -eq 0 ]; then - printf "Failed: -Xcheck:jni prints message when libjsig.so is loaded.\n" - exit 1 -fi - - -LD_PRELOAD=${LIBJSIG} ${JAVA} ${TESTVMOPTS} -Xcheck:jni -verbose:jni -version 2>&1 | grep "libjsig is activated" -if [ $? != 0 ]; then - printf "Failed: -Xcheck:jni does not print message when libjsig.so is loaded and -verbose:jni is set.\n" - exit 1 -fi - -printf "PASSED\n" -exit 0 - diff --git a/hotspot/test/runtime/XCheckJniJsig/XCheckJSig.java b/hotspot/test/runtime/XCheckJniJsig/XCheckJSig.java new file mode 100644 index 00000000000..ae0ad73cd3d --- /dev/null +++ b/hotspot/test/runtime/XCheckJniJsig/XCheckJSig.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 7051189 8023393 + * @summary Need to suppress info message if -Xcheck:jni is used with libjsig.so + * @library /testlibrary + * @run main XCheckJSig + */ + +import java.util.*; +import com.oracle.java.testlibrary.*; + +public class XCheckJSig { + public static void main(String args[]) throws Throwable { + + System.out.println("Regression test for bugs 7051189 and 8023393"); + if (!Platform.isSolaris() && !Platform.isLinux() && !Platform.isOSX()) { + System.out.println("Test only applicable on Solaris, Linux, and Mac OSX, skipping"); + return; + } + + String jdk_path = System.getProperty("test.jdk"); + String os_arch = Platform.getOsArch(); + String libjsig; + String env_var; + if (Platform.isOSX()) { + libjsig = jdk_path + "/jre/lib/server/libjsig.dylib"; + env_var = "DYLD_INSERT_LIBRARIES"; + } else { + libjsig = jdk_path + "/jre/lib/" + os_arch + "/libjsig.so"; + env_var = "LD_PRELOAD"; + } + String java_program; + if (Platform.isSolaris()) { + // On Solaris, need to call the 64-bit Java directly in order for + // LD_PRELOAD to work because libjsig.so is 64-bit. + java_program = jdk_path + "/jre/bin/" + os_arch + "/java"; + } else { + java_program = JDKToolFinder.getJDKTool("java"); + } + // If this test fails, these might be useful to know. + System.out.println("libjsig: " + libjsig); + System.out.println("osArch: " + os_arch); + System.out.println("java_program: " + java_program); + + ProcessBuilder pb = new ProcessBuilder(java_program, "-Xcheck:jni", "-version"); + Map env = pb.environment(); + env.put(env_var, libjsig); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldNotContain("libjsig is activated"); + output.shouldHaveExitValue(0); + + pb = new ProcessBuilder(java_program, "-Xcheck:jni", "-verbose:jni", "-version"); + env = pb.environment(); + env.put(env_var, libjsig); + output = new OutputAnalyzer(pb.start()); + output.shouldContain("libjsig is activated"); + output.shouldHaveExitValue(0); + } +} From 2c440a807868b094ceaf50178c5fbebf69459dd9 Mon Sep 17 00:00:00 2001 From: Christine Lu Date: Thu, 22 Aug 2013 09:09:55 -0700 Subject: [PATCH 102/218] Added tag jdk8-b104 for changeset 35bf25e3bb38 --- .hgtags-top-repo | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags-top-repo b/.hgtags-top-repo index 456aa0fa60e..93bd4b7ecc3 100644 --- a/.hgtags-top-repo +++ b/.hgtags-top-repo @@ -225,3 +225,4 @@ d2dcb110e9dbaf9903c05b211df800e78e4b394e jdk8-b100 9f74a220677dc265a724515d8e2617548cef62f1 jdk8-b101 5eb3c1dc348f72a7f84f7d9d07834e8bbe09a799 jdk8-b102 b7e64be81c8a7690703df5711f4fc2375da8a9cb jdk8-b103 +96c1b9b7524b52c3fcefc90ffad4c767396727c8 jdk8-b104 From 080d427e3472215a28b4cffb23a70459863fdac5 Mon Sep 17 00:00:00 2001 From: Christine Lu Date: Thu, 22 Aug 2013 09:09:57 -0700 Subject: [PATCH 103/218] Added tag jdk8-b104 for changeset 2b0842168ce5 --- corba/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/corba/.hgtags b/corba/.hgtags index 6aa967721af..6c9c4234507 100644 --- a/corba/.hgtags +++ b/corba/.hgtags @@ -225,3 +225,4 @@ c8286839d0df04aba819ec4bef12b86babccf30e jdk8-b90 a013024b07475782f1fa8e196e950b34b4077663 jdk8-b101 528c7e76eaeee022817ee085668459bc97cf5665 jdk8-b102 49c4a777fdfd648d4c3fffc940fdb97a23108ca8 jdk8-b103 +d411c60a8c2fe8fdc572af907775e90f7eefd513 jdk8-b104 From 9276e491e866fd39a0bf3d92b1b32331833484b8 Mon Sep 17 00:00:00 2001 From: Christine Lu Date: Thu, 22 Aug 2013 09:10:01 -0700 Subject: [PATCH 104/218] Added tag jdk8-b104 for changeset 78f23ea4586e --- hotspot/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/hotspot/.hgtags b/hotspot/.hgtags index b58c3218710..a4f4b9bc869 100644 --- a/hotspot/.hgtags +++ b/hotspot/.hgtags @@ -369,3 +369,4 @@ c4697c1c448416108743b59118b4a2498b339d0c jdk8-b102 7f55137d6aa81efc6eb0035813709f2cb6a26b8b hs25-b45 6f9be7f87b9653e94fd8fb3070891a0cc91b15bf jdk8-b103 580430d131ccd475e2f2ad4006531b8c4813d102 hs25-b46 +104743074675359cfbf7f4dcd9ab2a5974a16627 jdk8-b104 From bcda5085aff62da9fad85bc4de4039302e5e82f7 Mon Sep 17 00:00:00 2001 From: Christine Lu Date: Thu, 22 Aug 2013 09:10:08 -0700 Subject: [PATCH 105/218] Added tag jdk8-b104 for changeset 1fc167004a38 --- jaxp/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/jaxp/.hgtags b/jaxp/.hgtags index 03148a2fdb0..4dd37bb1e61 100644 --- a/jaxp/.hgtags +++ b/jaxp/.hgtags @@ -225,3 +225,4 @@ adf49c3ef83c160d53ece623049b2cdccaf78fc7 jdk8-b99 0a7432f898e579ea35e8c51e3edab37f949168e4 jdk8-b101 7cffafa606e9fb865e7b5e6a56e0a681ce5cf617 jdk8-b102 b1ceab582fc6d795b20aaa8a3fde2eba34af9399 jdk8-b103 +a22fe9bd01e6c7e7ddc7995dfc9471711692b8d1 jdk8-b104 From 86b719e366b4173b2121dca79c684d307048c839 Mon Sep 17 00:00:00 2001 From: Christine Lu Date: Thu, 22 Aug 2013 09:10:09 -0700 Subject: [PATCH 106/218] Added tag jdk8-b104 for changeset 94ae8ce0f0fa --- jaxws/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/jaxws/.hgtags b/jaxws/.hgtags index bc095c0cca8..b63da97d38f 100644 --- a/jaxws/.hgtags +++ b/jaxws/.hgtags @@ -225,3 +225,4 @@ b1fb4612a2caea52b5661b87509e560fa044b194 jdk8-b98 60b623a361642a0f5aef5f06dad9e5f279b9d9a9 jdk8-b101 988a5f2ac559dcab05698b8a8633aa453e012260 jdk8-b102 6cdc6ed987801c175a1217d0d3e53c3bd69ba52e jdk8-b103 +42211ab0ab1cca51a050d184634cf1db7ef81fbf jdk8-b104 From f06b171fe2b45e5f61a4c4024f20cfeec44efe09 Mon Sep 17 00:00:00 2001 From: Christine Lu Date: Thu, 22 Aug 2013 09:10:22 -0700 Subject: [PATCH 107/218] Added tag jdk8-b104 for changeset c45de6831abc --- langtools/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/langtools/.hgtags b/langtools/.hgtags index 42ea6c743db..564ae188549 100644 --- a/langtools/.hgtags +++ b/langtools/.hgtags @@ -225,3 +225,4 @@ ce5a90df517bdceb2739d7dd3e6764b070def802 jdk8-b98 0324dbf07b0f1cc51ad9fa18976489d02d23b60d jdk8-b101 453a305e116507847cc6577b80b4d9794bcb08bf jdk8-b102 76cfe7c61f2575ea5400845b8e80dab6f4b1d7d0 jdk8-b103 +dd4a00c220c6e14d9b2ce93a2bd436a1d04f0d03 jdk8-b104 From a758468eee3f263e67e5a89faaa2854cfba95a79 Mon Sep 17 00:00:00 2001 From: Christine Lu Date: Thu, 22 Aug 2013 09:10:25 -0700 Subject: [PATCH 108/218] Added tag jdk8-b104 for changeset 9b5ad625745e --- nashorn/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/nashorn/.hgtags b/nashorn/.hgtags index 0c5b8ca45af..85251da686a 100644 --- a/nashorn/.hgtags +++ b/nashorn/.hgtags @@ -213,3 +213,4 @@ d6bd440ac5b97bb1205b6c3274569c1cfe626723 jdk8-b96 a302b05d0ee460679501dc01004f70eb395fadf5 jdk8-b101 e966ff0a3ffef8a687eaf5a14167bb595b623d02 jdk8-b102 414203de4374e1964a9918c38a95fb245010a9f1 jdk8-b103 +afc100513451d22f0b8135999d6eb52f36df3d36 jdk8-b104 From 0d3a9fcd89fe72288d9e22aa1c3584227159740e Mon Sep 17 00:00:00 2001 From: Eric McCorkle Date: Thu, 22 Aug 2013 12:47:46 -0400 Subject: [PATCH 109/218] 8020745: Suspicious MethodParameters attribute generated for local classes capturing local variables Corrected an error in a previous patch that caused captured locals to be added to the beginning, not the end of a parameter list. Reviewed-by: jjg, mcimadamore, ksrini, abuckley --- .../com/sun/tools/javac/code/Symbol.java | 3 + .../com/sun/tools/javac/comp/Lower.java | 6 +- .../com/sun/tools/javac/jvm/ClassWriter.java | 8 + .../javac/8015701/AnonymousParameters.java | 89 ------ .../javac/MethodParameters/CaptureTest.java | 289 ++++++++++++++++++ 5 files changed, 303 insertions(+), 92 deletions(-) delete mode 100644 langtools/test/tools/javac/8015701/AnonymousParameters.java create mode 100644 langtools/test/tools/javac/MethodParameters/CaptureTest.java diff --git a/langtools/src/share/classes/com/sun/tools/javac/code/Symbol.java b/langtools/src/share/classes/com/sun/tools/javac/code/Symbol.java index b36254906d3..c4a4a820344 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/code/Symbol.java +++ b/langtools/src/share/classes/com/sun/tools/javac/code/Symbol.java @@ -1231,6 +1231,9 @@ public abstract class Symbol implements Element { /** The extra (synthetic/mandated) parameters of the method. */ public List extraParams = List.nil(); + /** The captured local variables in an anonymous class */ + public List capturedLocals = List.nil(); + /** The parameters of the method. */ public List params = null; diff --git a/langtools/src/share/classes/com/sun/tools/javac/comp/Lower.java b/langtools/src/share/classes/com/sun/tools/javac/comp/Lower.java index d5f4f4dbfe1..75e1d388666 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/comp/Lower.java +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Lower.java @@ -2735,9 +2735,9 @@ public class Lower extends TreeTranslator { for (List l = fvs; l.nonEmpty(); l = l.tail) { if (TreeInfo.isInitialConstructor(tree)) { final Name pName = proxyName(l.head.name); - m.extraParams = - m.extraParams.append((VarSymbol) - (proxies.lookup(pName).sym)); + m.capturedLocals = + m.capturedLocals.append((VarSymbol) + (proxies.lookup(pName).sym)); added = added.prepend( initField(tree.body.pos, pName)); } diff --git a/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassWriter.java b/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassWriter.java index ac8b94a8310..73eb2d34acf 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassWriter.java +++ b/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassWriter.java @@ -657,6 +657,14 @@ public class ClassWriter extends ClassFile { databuf.appendChar(pool.put(s.name)); databuf.appendChar(flags); } + // Now write the captured locals + for (VarSymbol s : m.capturedLocals) { + final int flags = + ((int) s.flags() & (FINAL | SYNTHETIC | MANDATED)) | + ((int) m.flags() & SYNTHETIC); + databuf.appendChar(pool.put(s.name)); + databuf.appendChar(flags); + } endAttr(attrIndex); return 1; } else diff --git a/langtools/test/tools/javac/8015701/AnonymousParameters.java b/langtools/test/tools/javac/8015701/AnonymousParameters.java deleted file mode 100644 index 746b2b9696a..00000000000 --- a/langtools/test/tools/javac/8015701/AnonymousParameters.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * 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. - */ - -/* - * @test - * @bug 8015701 - * @summary javac should generate method parameters correctly. - * @compile -parameters AnonymousParameters.java - * @run main AnonymousParameters - */ -import java.lang.Class; -import java.lang.reflect.Constructor; -import java.lang.reflect.Parameter; -import java.util.concurrent.Callable; - -public class AnonymousParameters { - - String[] names = { - "this$0", - "val$message" - }; - - public static void main(String... args) throws Exception { - new AnonymousParameters().run(); - } - - void run() throws Exception { - Class cls = new ParameterNames().makeInner("hello").getClass(); - Constructor ctor = cls.getDeclaredConstructors()[0]; - Parameter[] params = ctor.getParameters(); - - if(params.length == 2) { - for(int i = 0; i < 2; i++) { - System.err.println("Testing parameter " + params[i].getName()); - if(!params[i].getName().equals(names[i])) - error("Expected parameter name " + names[i] + - " got " + params[i].getName()); - } - } else - error("Expected 2 parameters"); - - if(0 != errors) - throw new Exception("MethodParameters test failed with " + - errors + " errors"); - } - - void error(String msg) { - System.err.println("Error: " + msg); - errors++; - } - - int errors; -} - -class ParameterNames { - - public Callable makeInner(final String message) { - return new Callable() { - public String call() throws Exception { - return message; - } - }; - } - - public static void main(String... args) throws Exception { - ParameterNames test = new ParameterNames(); - System.out.println(test.makeInner("Hello").call()); - } -} diff --git a/langtools/test/tools/javac/MethodParameters/CaptureTest.java b/langtools/test/tools/javac/MethodParameters/CaptureTest.java new file mode 100644 index 00000000000..ed865faecd4 --- /dev/null +++ b/langtools/test/tools/javac/MethodParameters/CaptureTest.java @@ -0,0 +1,289 @@ +/* + * 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. + */ + +/* + * @test + * @bug 8015701 + * @summary Test method parameter attribute generation with captured locals. + * @compile -parameters CaptureTest.java + * @run main CaptureTest + */ +import java.lang.Class; +import java.lang.reflect.Constructor; +import java.lang.reflect.Parameter; +import java.lang.reflect.Modifier; +import java.util.List; +import java.util.ArrayList; + +public class CaptureTest { + + private static final int SYNTHETIC = 0x1000; + private static final int MANDATED = 0x8000; + + public static void main(String... args) throws Exception { + new CaptureTest().run(); + } + + + private void run() throws Exception { + final Encloser pn = new Encloser(); + + /* Cases covered here: + * + * - Local class + * - Inner class + * - Anonymous class + * - Anonymous class extending a local + * - Anonymous class extending an inner + */ + pn.makeLocal("hello").check(); + pn.makeInner("hello").check(); + pn.makeAnon("hello").check(); + pn.makeAnonExtendsLocal("hello").check(); + pn.makeAnonExtendsInner("hello").check(); + + if (0 != errors) + throw new Exception("MethodParameters test failed with " + + errors + " errors"); + } + + private void error(final String msg) { + System.err.println("Error: " + msg); + errors++; + } + + int errors; + + abstract class Tester { + + public Tester(final int param) {} + + protected abstract String[] names(); + protected abstract int[] modifiers(); + protected abstract Class[] types(); + + public void check() { + final Class cls = this.getClass(); + final Constructor ctor = cls.getDeclaredConstructors()[0]; + final Parameter[] params = ctor.getParameters(); + final String[] names = names(); + final int[] modifiers = modifiers(); + final Class[] types = types(); + + System.err.println("Testing class " + cls); + + if (params.length == names.length) { + for (int i = 0; i < names.length; i++) { + System.err.println("Testing parameter " + params[i].getName()); + if (!params[i].getName().equals(names[i])) + error("Expected parameter name " + names[i] + + " got " + params[i].getName()); + if (params[i].getModifiers() != modifiers[i]) + error("Expected parameter modifiers " + + modifiers[i] + " got " + + params[i].getModifiers()); + if (!params[i].getType().equals(types[i])) + error("Expected parameter type " + types[i] + + " got " + params[i].getType()); + } + } else + error("Expected " + names.length + " parameters"); + + } + + } + + class Encloser { + private class InnerTester extends Tester { + public InnerTester(final int innerparam) { + super(innerparam); + } + + protected String[] names() { + return new String[] { + "this$1", + "innerparam" + }; + } + + protected int[] modifiers() { + return new int[] { + Modifier.FINAL | SYNTHETIC, + Modifier.FINAL + }; + } + + protected Class[] types() { + return new Class[] { + Encloser.class, + int.class + }; + } + } + + public Tester makeInner(final String message) { + return new InnerTester(2); + } + + public Tester makeLocal(final String message) { + class LocalTester extends Tester { + public LocalTester(final int localparam) { + super(localparam); + } + + protected String[] names() { + return new String[] { + "this$1", + "localparam", + "val$message" + }; + } + + protected int[] modifiers() { + return new int[] { + Modifier.FINAL | MANDATED, + Modifier.FINAL, + Modifier.FINAL | SYNTHETIC + }; + } + + protected Class[] types() { + return new Class[] { + Encloser.class, + int.class, + String.class + }; + } + + public String message() { + return message; + } + } + + return new LocalTester(2); + } + + public Tester makeAnonExtendsLocal(final String message) { + abstract class LocalTester extends Tester { + public LocalTester(final int localparam) { + super(localparam); + } + + protected String[] names() { + return new String[] { + "this$1", + "localparam", + "val$message" + }; + } + + protected int[] modifiers() { + return new int[] { + Modifier.FINAL | MANDATED, + Modifier.FINAL, + Modifier.FINAL | SYNTHETIC + }; + } + + protected Class[] types() { + return new Class[] { + Encloser.class, + int.class, + String.class + }; + } + + } + + return new LocalTester(2) { + public String message() { + return message; + } + }; + } + + public Tester makeAnonExtendsInner(final String message) { + return new InnerTester(2) { + protected String[] names() { + return new String[] { + "this$1", + "innerparam", + "val$message" + }; + } + + protected int[] modifiers() { + return new int[] { + Modifier.FINAL | MANDATED, + Modifier.FINAL, + Modifier.FINAL | SYNTHETIC + }; + } + + protected Class[] types() { + return new Class[] { + Encloser.class, + int.class, + String.class + }; + } + + public String message() { + return message; + } + }; + } + + public Tester makeAnon(final String message) { + return new Tester(2) { + protected String[] names() { + return new String[] { + "this$1", + "param", + "val$message" + }; + } + + protected int[] modifiers() { + return new int[] { + Modifier.FINAL | MANDATED, + Modifier.FINAL, + Modifier.FINAL | SYNTHETIC + }; + } + + protected Class[] types() { + return new Class[] { + Encloser.class, + int.class, + String.class + }; + } + + public String message() { + return message; + } + }; + } + } +} From 5d8a44e119b274e979d2398f593c848af3d28336 Mon Sep 17 00:00:00 2001 From: James Laskey Date: Thu, 22 Aug 2013 13:51:24 -0300 Subject: [PATCH 110/218] 8023228: Debugger information gather is too slow Reviewed-by: sundar, lagergren --- .../jdk/nashorn/internal/runtime/Context.java | 5 + .../internal/runtime/DebuggerSupport.java | 310 ++++++++++++++++++ 2 files changed, 315 insertions(+) create mode 100644 nashorn/src/jdk/nashorn/internal/runtime/DebuggerSupport.java diff --git a/nashorn/src/jdk/nashorn/internal/runtime/Context.java b/nashorn/src/jdk/nashorn/internal/runtime/Context.java index 8834592a0b8..217080d0d3a 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/Context.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/Context.java @@ -91,6 +91,11 @@ public final class Context { */ public static final String NASHORN_JAVA_REFLECTION = "nashorn.JavaReflection"; + /* Force DebuggerSupport to be loaded. */ + static { + DebuggerSupport.FORCELOAD = true; + } + /** * ContextCodeInstaller that has the privilege of installing classes in the Context. * Can only be instantiated from inside the context and is opaque to other classes diff --git a/nashorn/src/jdk/nashorn/internal/runtime/DebuggerSupport.java b/nashorn/src/jdk/nashorn/internal/runtime/DebuggerSupport.java new file mode 100644 index 00000000000..e5017d7b247 --- /dev/null +++ b/nashorn/src/jdk/nashorn/internal/runtime/DebuggerSupport.java @@ -0,0 +1,310 @@ +/* + * Copyright (c) 2010, 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 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 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 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 jdk.nashorn.internal.runtime; + +import java.util.HashSet; +import java.util.Set; + +/** + * This class provides support for external debuggers. Its primary purpose is + * is to simplify the debugger tasks and provide better performance. + */ +final class DebuggerSupport { + /** + * Hook to force the loading of the DebuggerSupport class so that it is + * available to external debuggers. + */ + static boolean FORCELOAD = true; + + static { + /** + * Hook to force the loading of the DebuggerValueDesc class so that it is + * available to external debuggers. + */ + DebuggerValueDesc forceLoad = new DebuggerValueDesc(null, false, null, null); + } + + /** This class is used to send a bulk description of a value. */ + static class DebuggerValueDesc { + /** Property key (or index) or field name. */ + final String key; + + /** If the value is expandable. */ + final boolean expandable; + + /** Property or field value as object. */ + final Object valueAsObject; + + /** Property or field value as string. */ + final String valueAsString; + + DebuggerValueDesc(final String key, final boolean expandable, final Object valueAsObject, final String valueAsString) { + this.key = key; + this.expandable = expandable; + this.valueAsObject = valueAsObject; + this.valueAsString = valueAsString; + } + } + + /** + * Return the current context global. + * @return context global. + */ + static Object getGlobal() { + return Context.getGlobalTrusted(); + } + + /** + * This method returns a bulk description of an object's properties. + * @param object Script object to be displayed by the debugger. + * @param all true if to include non-enumerable values. + * @return An array of DebuggerValueDesc. + */ + static DebuggerValueDesc[] valueInfos(final Object object, final boolean all) { + assert object instanceof ScriptObject; + return getDebuggerValueDescs((ScriptObject)object, all, new HashSet<>()); + } + + /** + * This method returns a debugger description of the value. + * @param name Name of value (property name). + * @param value Data value. + * @param all true if to include non-enumerable values. + * @return A DebuggerValueDesc. + */ + static DebuggerValueDesc valueInfo(final String name, final Object value, final boolean all) { + return valueInfo(name, value, all, new HashSet<>()); + } + + /** + * This method returns a debugger description of the value. + * @param name Name of value (property name). + * @param value Data value. + * @param all true if to include non-enumerable values. + * @param duplicates Duplication set to avoid cycles. + * @return A DebuggerValueDesc. + */ + private static DebuggerValueDesc valueInfo(final String name, final Object value, final boolean all, final Set duplicates) { + if (value instanceof ScriptObject && !(value instanceof ScriptFunction)) { + final ScriptObject object = (ScriptObject)value; + return new DebuggerValueDesc(name, !object.isEmpty(), value, objectAsString(object, all, duplicates)); + } else { + return new DebuggerValueDesc(name, false, value, valueAsString(value)); + } + } + + /** + * Generate the descriptions for an object's properties. + * @param object Object to introspect. + * @param all true if to include non-enumerable values. + * @param duplicates Duplication set to avoid cycles. + * @return An array of DebuggerValueDesc. + */ + private static DebuggerValueDesc[] getDebuggerValueDescs(final ScriptObject object, final boolean all, final Set duplicates) { + if (duplicates.contains(object)) { + return null; + } + + duplicates.add(object); + + final String[] keys = object.getOwnKeys(all); + final DebuggerValueDesc[] descs = new DebuggerValueDesc[keys.length]; + + for (int i = 0; i < keys.length; i++) { + final String key = keys[i]; + descs[i] = valueInfo(key, object.get(key), true, duplicates); + } + + duplicates.remove(object); + + return descs; + } + + /** + * Generate a string representation of a Script object. + * @param object Script object to represent. + * @param all true if to include non-enumerable values. + * @param duplicates Duplication set to avoid cycles. + * @return String representation. + */ + private static String objectAsString(final ScriptObject object, final boolean all, final Set duplicates) { + final StringBuilder sb = new StringBuilder(); + + if (ScriptObject.isArray(object)) { + sb.append('['); + final long length = object.getLong("length"); + + for (long i = 0; i < length; i++) { + if (object.has(i)) { + final Object valueAsObject = object.get(i); + final boolean isUndefined = JSType.of(valueAsObject) == JSType.UNDEFINED; + + if (isUndefined) { + if (i != 0) { + sb.append(","); + } + } else { + if (i != 0) { + sb.append(", "); + } + + if (valueAsObject instanceof ScriptObject && !(valueAsObject instanceof ScriptFunction)) { + final String objectString = objectAsString((ScriptObject)valueAsObject, true, duplicates); + sb.append(objectString != null ? objectString : "{...}"); + } else { + sb.append(valueAsString(valueAsObject)); + } + } + } else { + if (i != 0) { + sb.append(','); + } + } + } + + sb.append(']'); + } else { + sb.append('{'); + final DebuggerValueDesc[] descs = getDebuggerValueDescs(object, all, duplicates); + + if (descs != null) { + for (int i = 0; i < descs.length; i++) { + if (i != 0) { + sb.append(", "); + } + + final String valueAsString = descs[i].valueAsString; + sb.append(descs[i].key); + sb.append(": "); + sb.append(descs[i].valueAsString); + } + } + + sb.append('}'); + } + + return sb.toString(); + } + + /** + * This method returns a string representation of a value. + * @param value Arbitrary value to be displayed by the debugger. + * @return A string representation of the value or an array of DebuggerValueDesc. + */ + private static String valueAsString(final Object value) { + final JSType type = JSType.of(value); + + switch (type) { + case BOOLEAN: + return value.toString(); + + case STRING: + return escape((String)value); + + case NUMBER: + return JSType.toString(((Number)value).doubleValue()); + + case NULL: + return "null"; + + case UNDEFINED: + return "undefined"; + + case OBJECT: + return ScriptRuntime.safeToString(value); + + case FUNCTION: + if (value instanceof ScriptFunction) { + return ((ScriptFunction)value).toSource(); + } else { + return value.toString(); + } + + default: + return value.toString(); + } + } + + /** + * Escape a string into a form that can be parsed by JavaScript. + * @param value String to be escaped. + * @return Escaped string. + */ + private static String escape(final String value) { + final StringBuilder sb = new StringBuilder(); + + sb.append("\""); + + for (final char ch : value.toCharArray()) { + switch (ch) { + case '\\': + sb.append("\\\\"); + break; + case '"': + sb.append("\\\""); + break; + case '\'': + sb.append("\\\'"); + break; + case '\b': + sb.append("\\b"); + break; + case '\f': + sb.append("\\f"); + break; + case '\n': + sb.append("\\n"); + break; + case '\r': + sb.append("\\r"); + break; + case '\t': + sb.append("\\t"); + break; + default: + if (ch < ' ' || ch >= 0xFF) { + sb.append("\\u"); + + final String hex = Integer.toHexString(ch); + for (int i = hex.length(); i < 4; i++) { + sb.append('0'); + } + sb.append(hex); + } else { + sb.append(ch); + } + + break; + } + } + + sb.append("\""); + + return sb.toString(); + } +} + + From 7b5f6c66a5cdc0ed4efb6e1e65c7ea41155314ec Mon Sep 17 00:00:00 2001 From: Athijegannathan Sundararajan Date: Thu, 22 Aug 2013 22:32:16 +0530 Subject: [PATCH 111/218] 8023560: Arbitrary javax.script.Bindings objects as ENGINE_SCOPE objects are not handled as expected Reviewed-by: jlaskey, lagergren, hannesw --- .../api/scripting/NashornScriptEngine.java | 57 ++++++++++++++++--- .../internal/runtime/ScriptEnvironment.java | 4 ++ .../runtime/resources/Options.properties | 8 +++ .../api/scripting/ScriptEngineTest.java | 47 +++++++++++++++ .../runtime/TrustedScriptEngineTest.java | 24 ++++++++ 5 files changed, 133 insertions(+), 7 deletions(-) diff --git a/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngine.java b/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngine.java index e3f09139e95..213b8890948 100644 --- a/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngine.java +++ b/nashorn/src/jdk/nashorn/api/scripting/NashornScriptEngine.java @@ -55,6 +55,7 @@ import javax.script.ScriptContext; import javax.script.ScriptEngine; import javax.script.ScriptEngineFactory; import javax.script.ScriptException; +import javax.script.SimpleBindings; import jdk.nashorn.internal.runtime.Context; import jdk.nashorn.internal.runtime.ErrorManager; import jdk.nashorn.internal.runtime.GlobalObject; @@ -74,6 +75,11 @@ import jdk.nashorn.internal.runtime.options.Options; */ public final class NashornScriptEngine extends AbstractScriptEngine implements Compilable, Invocable { + /** + * Key used to associate Nashorn global object mirror with arbitrary Bindings instance. + */ + public static final String NASHORN_GLOBAL = "nashorn.global"; + private static AccessControlContext createPermAccCtxt(final String permName) { final Permissions perms = new Permissions(); perms.add(new RuntimePermission(permName)); @@ -85,6 +91,8 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C private final ScriptEngineFactory factory; private final Context nashornContext; + // do we want to share single Nashorn global instance across ENGINE_SCOPEs? + private final boolean _global_per_engine; private final ScriptObject global; // initialized bit late to be made 'final'. Property object for "context" // property of global object @@ -134,6 +142,9 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C } }, CREATE_CONTEXT_ACC_CTXT); + // cache this option that is used often + this._global_per_engine = nashornContext.getEnv()._global_per_engine; + // create new global object this.global = createNashornGlobal(); // set the default engine scope for the default context @@ -176,8 +187,14 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C @Override public Bindings createBindings() { - final ScriptObject newGlobal = createNashornGlobal(); - return new ScriptObjectMirror(newGlobal, newGlobal); + if (_global_per_engine) { + // just create normal SimpleBindings. + // We use same 'global' for all Bindings. + return new SimpleBindings(); + } else { + final ScriptObject newGlobal = createNashornGlobal(); + return new ScriptObjectMirror(newGlobal, newGlobal); + } } // Compilable methods @@ -319,17 +336,43 @@ public final class NashornScriptEngine extends AbstractScriptEngine implements C } private ScriptObject getNashornGlobalFrom(final ScriptContext ctxt) { + if (_global_per_engine) { + // shared single global for all ENGINE_SCOPE Bindings + return global; + } + final Bindings bindings = ctxt.getBindings(ScriptContext.ENGINE_SCOPE); + // is this Nashorn's own Bindings implementation? if (bindings instanceof ScriptObjectMirror) { - final ScriptObjectMirror mirror = (ScriptObjectMirror)bindings; - ScriptObject sobj = ((ScriptObjectMirror)bindings).getScriptObject(); - if (sobj instanceof GlobalObject && sobj.isOfContext(nashornContext)) { + final ScriptObject sobj = globalFromMirror((ScriptObjectMirror)bindings); + if (sobj != null) { return sobj; } } - // didn't find global object from context given - return the engine-wide global - return global; + // Arbitrary user Bindings implementation. Look for NASHORN_GLOBAL in it! + Object scope = bindings.get(NASHORN_GLOBAL); + if (scope instanceof ScriptObjectMirror) { + final ScriptObject sobj = globalFromMirror((ScriptObjectMirror)scope); + if (sobj != null) { + return sobj; + } + } + + // We didn't find associated nashorn global mirror in the Bindings given! + // Create new global instance mirror and associate with the Bindings. + final ScriptObjectMirror mirror = (ScriptObjectMirror)createBindings(); + bindings.put(NASHORN_GLOBAL, mirror); + return mirror.getScriptObject(); + } + + private ScriptObject globalFromMirror(final ScriptObjectMirror mirror) { + ScriptObject sobj = mirror.getScriptObject(); + if (sobj instanceof GlobalObject && sobj.isOfContext(nashornContext)) { + return sobj; + } + + return null; } private ScriptObject createNashornGlobal() { diff --git a/nashorn/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java b/nashorn/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java index 8ab6af48ab1..5327471051a 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java +++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java @@ -86,6 +86,9 @@ public final class ScriptEnvironment { /** Launch using as fx application */ public final boolean _fx; + /** Use single Global instance per jsr223 engine instance. */ + public final boolean _global_per_engine; + /** * Behavior when encountering a function declaration in a lexical context where only statements are acceptable * (function declarations are source elements, but not statements). @@ -208,6 +211,7 @@ public final class ScriptEnvironment { _function_statement = FunctionStatementBehavior.ACCEPT; } _fx = options.getBoolean("fx"); + _global_per_engine = options.getBoolean("global.per.engine"); _lazy_compilation = options.getBoolean("lazy.compilation"); _loader_per_compile = options.getBoolean("loader.per.compile"); _no_java = options.getBoolean("no.java"); diff --git a/nashorn/src/jdk/nashorn/internal/runtime/resources/Options.properties b/nashorn/src/jdk/nashorn/internal/runtime/resources/Options.properties index e3510fa1004..508759f92f1 100644 --- a/nashorn/src/jdk/nashorn/internal/runtime/resources/Options.properties +++ b/nashorn/src/jdk/nashorn/internal/runtime/resources/Options.properties @@ -157,6 +157,14 @@ nashorn.option.fx = { \ default=false \ } +nashorn.option.global.per.engine = { \ + name="--global-per-engine", \ + desc="Use single Global instance per script engine instance.", \ + is_undocumented=true, \ + type=Boolean, \ + default=false \ +} + nashorn.option.log = { \ name="--log", \ is_undocumented=true, \ diff --git a/nashorn/test/src/jdk/nashorn/api/scripting/ScriptEngineTest.java b/nashorn/test/src/jdk/nashorn/api/scripting/ScriptEngineTest.java index 3cad7095517..b21b2414f84 100644 --- a/nashorn/test/src/jdk/nashorn/api/scripting/ScriptEngineTest.java +++ b/nashorn/test/src/jdk/nashorn/api/scripting/ScriptEngineTest.java @@ -47,6 +47,7 @@ import javax.script.ScriptEngine; import javax.script.ScriptEngineFactory; import javax.script.ScriptEngineManager; import javax.script.ScriptException; +import javax.script.SimpleBindings; import javax.script.SimpleScriptContext; import org.testng.Assert; import org.testng.annotations.Test; @@ -1282,4 +1283,50 @@ public class ScriptEngineTest { final Object newObj = ((ScriptObjectMirror)e2obj).newObject("foo"); assertTrue(newObj instanceof ScriptObjectMirror); } + + @Test + public void userEngineScopeBindingsTest() throws ScriptException { + final ScriptEngineManager m = new ScriptEngineManager(); + final ScriptEngine e = m.getEngineByName("nashorn"); + e.eval("function func() {}"); + + final ScriptContext newContext = new SimpleScriptContext(); + newContext.setBindings(new SimpleBindings(), ScriptContext.ENGINE_SCOPE); + // we are using a new bindings - so it should have 'func' defined + Object value = e.eval("typeof func", newContext); + assertTrue(value.equals("undefined")); + } + + @Test + public void userEngineScopeBindingsNoLeakTest() throws ScriptException { + final ScriptEngineManager m = new ScriptEngineManager(); + final ScriptEngine e = m.getEngineByName("nashorn"); + final ScriptContext newContext = new SimpleScriptContext(); + newContext.setBindings(new SimpleBindings(), ScriptContext.ENGINE_SCOPE); + e.eval("function foo() {}", newContext); + + // in the default context's ENGINE_SCOPE, 'foo' shouldn't exist + assertTrue(e.eval("typeof foo").equals("undefined")); + } + + @Test + public void userEngineScopeBindingsRetentionTest() throws ScriptException { + final ScriptEngineManager m = new ScriptEngineManager(); + final ScriptEngine e = m.getEngineByName("nashorn"); + final ScriptContext newContext = new SimpleScriptContext(); + newContext.setBindings(new SimpleBindings(), ScriptContext.ENGINE_SCOPE); + e.eval("function foo() {}", newContext); + + // definition retained with user's ENGINE_SCOPE Binding + assertTrue(e.eval("typeof foo", newContext).equals("function")); + + final Bindings oldBindings = newContext.getBindings(ScriptContext.ENGINE_SCOPE); + // but not in another ENGINE_SCOPE binding + newContext.setBindings(new SimpleBindings(), ScriptContext.ENGINE_SCOPE); + assertTrue(e.eval("typeof foo", newContext).equals("undefined")); + + // restore ENGINE_SCOPE and check again + newContext.setBindings(oldBindings, ScriptContext.ENGINE_SCOPE); + assertTrue(e.eval("typeof foo", newContext).equals("function")); + } } diff --git a/nashorn/test/src/jdk/nashorn/internal/runtime/TrustedScriptEngineTest.java b/nashorn/test/src/jdk/nashorn/internal/runtime/TrustedScriptEngineTest.java index f7f7c6ae298..469d890ebd5 100644 --- a/nashorn/test/src/jdk/nashorn/internal/runtime/TrustedScriptEngineTest.java +++ b/nashorn/test/src/jdk/nashorn/internal/runtime/TrustedScriptEngineTest.java @@ -32,7 +32,10 @@ import static org.testng.Assert.fail; import javax.script.ScriptEngine; import javax.script.ScriptEngineFactory; import javax.script.ScriptEngineManager; +import javax.script.ScriptContext; import javax.script.ScriptException; +import javax.script.SimpleBindings; +import javax.script.SimpleScriptContext; import jdk.nashorn.api.scripting.NashornScriptEngineFactory; import org.testng.annotations.Test; @@ -196,4 +199,25 @@ public class TrustedScriptEngineTest { } fail("Cannot find nashorn factory!"); } + + @Test + public void globalPerEngineTest() throws ScriptException { + final NashornScriptEngineFactory fac = new NashornScriptEngineFactory(); + final String[] options = new String[] { "--global-per-engine" }; + final ScriptEngine e = fac.getScriptEngine(options); + + e.eval("function foo() {}"); + + final ScriptContext newCtx = new SimpleScriptContext(); + newCtx.setBindings(e.createBindings(), ScriptContext.ENGINE_SCOPE); + + // all global definitions shared and so 'foo' should be + // visible in new Bindings as well. + assertTrue(e.eval("typeof foo", newCtx).equals("function")); + + e.eval("function bar() {}", newCtx); + + // bar should be visible in default context + assertTrue(e.eval("typeof bar").equals("function")); + } } From f61c7dc88b26e52426264783dfdc63e097b60657 Mon Sep 17 00:00:00 2001 From: Ioi Lam Date: Thu, 22 Aug 2013 10:20:50 -0700 Subject: [PATCH 112/218] 8023406: make/windows/build_vm_def.sh takes too long even when BUILD_WIN_SA != 1 Avoid dumping C++ vtable when BUILD_WIN_SA != 1 Reviewed-by: dcubed, sla, tbell --- hotspot/make/windows/build_vm_def.sh | 18 ++++++++++++++++-- hotspot/make/windows/makefiles/debug.make | 3 --- hotspot/make/windows/makefiles/fastdebug.make | 3 --- hotspot/make/windows/makefiles/product.make | 3 --- .../make/windows/makefiles/projectcreator.make | 6 +++++- hotspot/make/windows/makefiles/vm.make | 8 ++++++++ 6 files changed, 29 insertions(+), 12 deletions(-) diff --git a/hotspot/make/windows/build_vm_def.sh b/hotspot/make/windows/build_vm_def.sh index c54a1803b93..fa82d26a81a 100644 --- a/hotspot/make/windows/build_vm_def.sh +++ b/hotspot/make/windows/build_vm_def.sh @@ -42,8 +42,6 @@ else MKS_HOME=`dirname "$SH"` fi -echo "EXPORTS" > vm1.def - AWK="$MKS_HOME/awk.exe" if [ ! -e $AWK ]; then AWK="$MKS_HOME/gawk.exe" @@ -55,6 +53,22 @@ CAT="$MKS_HOME/cat.exe" RM="$MKS_HOME/rm.exe" DUMPBIN="link.exe /dump" +if [ "$1" = "-nosa" ]; then + echo EXPORTS > vm.def + echo "" + echo "***" + echo "*** Not building SA: BUILD_WIN_SA != 1" + echo "*** C++ Vtables NOT included in vm.def" + echo "*** This jvm.dll will NOT work properly with SA." + echo "***" + echo "*** When in doubt, set BUILD_WIN_SA=1, clean and rebuild." + echo "***" + echo "" + exit +fi + +echo "EXPORTS" > vm1.def + # When called from IDE the first param should contain the link version, otherwise may be nill if [ "x$1" != "x" ]; then LD_VER="$1" diff --git a/hotspot/make/windows/makefiles/debug.make b/hotspot/make/windows/makefiles/debug.make index 2fca2182841..14a07083434 100644 --- a/hotspot/make/windows/makefiles/debug.make +++ b/hotspot/make/windows/makefiles/debug.make @@ -49,9 +49,6 @@ HS_BUILD_ID=$(HS_BUILD_VER)-debug # Force resources to be rebuilt every time $(Res_Files): FORCE -vm.def: $(Obj_Files) - sh $(WorkSpace)/make/windows/build_vm_def.sh - $(AOUT): $(Res_Files) $(Obj_Files) vm.def $(LD) @<< $(LD_FLAGS) /out:$@ /implib:$*.lib /def:vm.def $(Obj_Files) $(Res_Files) diff --git a/hotspot/make/windows/makefiles/fastdebug.make b/hotspot/make/windows/makefiles/fastdebug.make index cde98f214ea..a85e129cf6e 100644 --- a/hotspot/make/windows/makefiles/fastdebug.make +++ b/hotspot/make/windows/makefiles/fastdebug.make @@ -48,9 +48,6 @@ HS_BUILD_ID=$(HS_BUILD_VER)-fastdebug # Force resources to be rebuilt every time $(Res_Files): FORCE -vm.def: $(Obj_Files) - sh $(WorkSpace)/make/windows/build_vm_def.sh - $(AOUT): $(Res_Files) $(Obj_Files) vm.def $(LD) @<< $(LD_FLAGS) /out:$@ /implib:$*.lib /def:vm.def $(Obj_Files) $(Res_Files) diff --git a/hotspot/make/windows/makefiles/product.make b/hotspot/make/windows/makefiles/product.make index 407484cd46e..713ec0e54ca 100644 --- a/hotspot/make/windows/makefiles/product.make +++ b/hotspot/make/windows/makefiles/product.make @@ -51,9 +51,6 @@ HS_BUILD_ID=$(HS_BUILD_VER) # Force resources to be rebuilt every time $(Res_Files): FORCE -vm.def: $(Obj_Files) - sh $(WorkSpace)/make/windows/build_vm_def.sh - $(AOUT): $(Res_Files) $(Obj_Files) vm.def $(LD) @<< $(LD_FLAGS) /out:$@ /implib:$*.lib /def:vm.def $(Obj_Files) $(Res_Files) diff --git a/hotspot/make/windows/makefiles/projectcreator.make b/hotspot/make/windows/makefiles/projectcreator.make index a5336c6bf51..d512796f8fe 100644 --- a/hotspot/make/windows/makefiles/projectcreator.make +++ b/hotspot/make/windows/makefiles/projectcreator.make @@ -92,6 +92,10 @@ ProjectCreatorIDEOptions = \ -disablePch getThread_windows_$(Platform_arch).cpp \ -disablePch_compiler2 opcodes.cpp +!if "$(BUILD_WIN_SA)" != "1" +BUILD_VM_DEF_FLAG=-nosa +!endif + # Common options for the IDE builds for c1, and c2 ProjectCreatorIDEOptions=\ $(ProjectCreatorIDEOptions) \ @@ -104,7 +108,7 @@ ProjectCreatorIDEOptions=\ -jdkTargetRoot $(HOTSPOTJDKDIST) \ -define ALIGN_STACK_FRAMES \ -define VM_LITTLE_ENDIAN \ - -prelink "" "Generating vm.def..." "cd $(HOTSPOTBUILDSPACE)\%f\%b set HOTSPOTMKSHOME=$(HOTSPOTMKSHOME) set JAVA_HOME=$(HOTSPOTJDKDIST) $(HOTSPOTMKSHOME)\sh $(HOTSPOTWORKSPACE)\make\windows\build_vm_def.sh $(LD_VER)" \ + -prelink "" "Generating vm.def..." "cd $(HOTSPOTBUILDSPACE)\%f\%b set HOTSPOTMKSHOME=$(HOTSPOTMKSHOME) set JAVA_HOME=$(HOTSPOTJDKDIST) $(HOTSPOTMKSHOME)\sh $(HOTSPOTWORKSPACE)\make\windows\build_vm_def.sh $(BUILD_VM_DEF_FLAG) $(LD_VER)" \ -ignoreFile jsig.c \ -ignoreFile jvmtiEnvRecommended.cpp \ -ignoreFile jvmtiEnvStub.cpp \ diff --git a/hotspot/make/windows/makefiles/vm.make b/hotspot/make/windows/makefiles/vm.make index 8b5e23d4a28..229be6870a7 100644 --- a/hotspot/make/windows/makefiles/vm.make +++ b/hotspot/make/windows/makefiles/vm.make @@ -393,3 +393,11 @@ default:: _build_pch_file.obj: @echo #include "precompiled.hpp" > ../generated/_build_pch_file.cpp $(CXX) $(CXX_FLAGS) /Fp"vm.pch" /Yc"precompiled.hpp" /c ../generated/_build_pch_file.cpp + +!if "$(BUILD_WIN_SA)" != "1" +BUILD_VM_DEF_FLAG=-nosa +!endif + +vm.def: $(Obj_Files) + sh $(WorkSpace)/make/windows/build_vm_def.sh $(BUILD_VM_DEF_FLAG) + From 32a617d198df607b011264664622af777d831308 Mon Sep 17 00:00:00 2001 From: Jonathan Gibbons Date: Thu, 22 Aug 2013 12:41:20 -0700 Subject: [PATCH 113/218] 8022173: Relax some warnings in doclint Reviewed-by: darcy --- .../classes/com/sun/tools/doclint/HtmlTag.java | 13 ++++++++----- langtools/test/tools/doclint/html/ListTagsTest.java | 3 ++- .../test/tools/doclint/html/OtherTagsTest.java | 3 ++- langtools/test/tools/doclint/html/OtherTagsTest.out | 10 +++++----- .../test/tools/doclint/html/TableTagsTest.java | 3 ++- 5 files changed, 19 insertions(+), 13 deletions(-) diff --git a/langtools/src/share/classes/com/sun/tools/doclint/HtmlTag.java b/langtools/src/share/classes/com/sun/tools/doclint/HtmlTag.java index f1bce7d6795..3b8f8599e09 100644 --- a/langtools/src/share/classes/com/sun/tools/doclint/HtmlTag.java +++ b/langtools/src/share/classes/com/sun/tools/doclint/HtmlTag.java @@ -42,12 +42,14 @@ import static com.sun.tools.doclint.HtmlTag.Attr.*; * * The intent of this class is to embody the semantics of W3C HTML 4.01 * to the extent supported/used by javadoc. + * In time, we may wish to transition javadoc and doclint to using HTML 5. * * This is derivative of com.sun.tools.doclets.formats.html.markup.HtmlTag. * Eventually, these two should be merged back together, and possibly made * public. * * @see HTML 4.01 Specification + * @see HTML 5 Specification * @author Bhavesh Patel * @author Jonathan Gibbons (revised) */ @@ -119,7 +121,8 @@ public enum HtmlTag { HEAD(BlockType.OTHER, EndKind.REQUIRED), - HR(BlockType.BLOCK, EndKind.NONE), + HR(BlockType.BLOCK, EndKind.NONE, + attrs(AttrKind.OK, WIDTH)), // OK in 4.01; not allowed in 5 HTML(BlockType.OTHER, EndKind.REQUIRED), @@ -152,7 +155,7 @@ public enum HtmlTag { OL(BlockType.BLOCK, EndKind.REQUIRED, EnumSet.of(Flag.EXPECT_CONTENT), - attrs(AttrKind.USE_CSS, START, TYPE)){ + attrs(AttrKind.OK, START, TYPE)) { @Override public boolean accepts(HtmlTag t) { return (t == LI); @@ -196,8 +199,8 @@ public enum HtmlTag { TABLE(BlockType.BLOCK, EndKind.REQUIRED, EnumSet.of(Flag.EXPECT_CONTENT), attrs(AttrKind.OK, SUMMARY, Attr.FRAME, RULES, BORDER, - CELLPADDING, CELLSPACING), - attrs(AttrKind.USE_CSS, ALIGN, WIDTH, BGCOLOR)) { + CELLPADDING, CELLSPACING, WIDTH), // width OK in 4.01; not allowed in 5 + attrs(AttrKind.USE_CSS, ALIGN, BGCOLOR)) { @Override public boolean accepts(HtmlTag t) { switch (t) { @@ -267,7 +270,7 @@ public enum HtmlTag { UL(BlockType.BLOCK, EndKind.REQUIRED, EnumSet.of(Flag.EXPECT_CONTENT), - attrs(AttrKind.USE_CSS, COMPACT, TYPE)){ + attrs(AttrKind.OK, COMPACT, TYPE)) { // OK in 4.01; not allowed in 5 @Override public boolean accepts(HtmlTag t) { return (t == LI); diff --git a/langtools/test/tools/doclint/html/ListTagsTest.java b/langtools/test/tools/doclint/html/ListTagsTest.java index 571c8f9e6f6..1d55bfd2cbf 100644 --- a/langtools/test/tools/doclint/html/ListTagsTest.java +++ b/langtools/test/tools/doclint/html/ListTagsTest.java @@ -1,6 +1,6 @@ /* * @test /nodynamiccopyright/ - * @bug 8006251 8013405 + * @bug 8006251 8013405 8022173 * @summary test list tags * @library .. * @build DocLintTester @@ -15,6 +15,7 @@ public class ListTagsTest { *
  1. abc
*
  1. bad
*
  1. bad
+ *
  1. bad
*
  • abc
*/ public void supportedTags() { } diff --git a/langtools/test/tools/doclint/html/OtherTagsTest.java b/langtools/test/tools/doclint/html/OtherTagsTest.java index ce6af8246c7..df72dac05fd 100644 --- a/langtools/test/tools/doclint/html/OtherTagsTest.java +++ b/langtools/test/tools/doclint/html/OtherTagsTest.java @@ -1,6 +1,6 @@ /* * @test /nodynamiccopyright/ - * @bug 8006251 + * @bug 8006251 8022173 * @summary test other tags * @library .. * @build DocLintTester @@ -14,6 +14,7 @@ public class OtherTagsTest { * * * + *
* * * diff --git a/langtools/test/tools/doclint/html/OtherTagsTest.out b/langtools/test/tools/doclint/html/OtherTagsTest.out index 0ead88e77a5..3fbcb15781c 100644 --- a/langtools/test/tools/doclint/html/OtherTagsTest.out +++ b/langtools/test/tools/doclint/html/OtherTagsTest.out @@ -10,19 +10,19 @@ OtherTagsTest.java:15: error: element not allowed in documentation comments: * ^ -OtherTagsTest.java:17: error: element not allowed in documentation comments: +OtherTagsTest.java:18: error: element not allowed in documentation comments: * ^ -OtherTagsTest.java:18: error: element not allowed in documentation comments: +OtherTagsTest.java:19: error: element not allowed in documentation comments: * ^ -OtherTagsTest.java:19: error: element not allowed in documentation comments: +OtherTagsTest.java:20: error: element not allowed in documentation comments: <noframes> * <noframes> ^ -OtherTagsTest.java:20: error: element not allowed in documentation comments: ^ -OtherTagsTest.java:21: error: element not allowed in documentation comments: +OtherTagsTest.java:22: error: element not allowed in documentation comments: <title> * <title> ^ 9 errors diff --git a/langtools/test/tools/doclint/html/TableTagsTest.java b/langtools/test/tools/doclint/html/TableTagsTest.java index 7cea1b35f9d..c5cb2e54290 100644 --- a/langtools/test/tools/doclint/html/TableTagsTest.java +++ b/langtools/test/tools/doclint/html/TableTagsTest.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8006251 + * @bug 8006251 8022173 * @summary test table tags * @library .. * @build DocLintTester @@ -39,6 +39,7 @@ public class TableTagsTest { *
*
*
+ *
*/ public void supportedTags() { } } From 4a2acff75d2066d11019a215e04b778eaa2c2c48 Mon Sep 17 00:00:00 2001 From: Omair Majid Date: Thu, 22 Aug 2013 16:00:13 -0400 Subject: [PATCH 114/218] 8023480: Create a jvm.cfg for zero on 32 bit architectures Reviewed-by: dholmes, erikj --- jdk/makefiles/CopyFiles.gmk | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/jdk/makefiles/CopyFiles.gmk b/jdk/makefiles/CopyFiles.gmk index cb479bba1c5..2b3cbf2e200 100644 --- a/jdk/makefiles/CopyFiles.gmk +++ b/jdk/makefiles/CopyFiles.gmk @@ -292,8 +292,11 @@ endif JVMCFG_DIR := $(JDK_OUTPUTDIR)/lib$(OPENJDK_TARGET_CPU_LIBDIR) JVMCFG := $(JVMCFG_DIR)/jvm.cfg +# To do: should this also support -zeroshark? -ifeq ($(OPENJDK_TARGET_CPU_BITS),32) +ifeq ($(OPENJDK_TARGET_CPU_BITS),64) + COPY_JVM_CFG_FILE := true +else # On 32-bit machines we have three potential VMs: client, server and minimal. # Historically we usually have both client and server and so that is what the # committed jvm.cfg expects (including platform specific ergonomics switches @@ -302,16 +305,21 @@ ifeq ($(OPENJDK_TARGET_CPU_BITS),32) # The main problem is deciding whether to use aliases for the VMs that are not # present and the current position is that we add aliases for client and server, but # not for minimal. - # To do: should this also support, -zero and -zeroshark? - CLIENT_AND_SERVER := $(and $(findstring true,$(JVM_VARIANT_SERVER)),$(findstring true,$(JVM_VARIANT_CLIENT))) - ifeq ($(CLIENT_AND_SERVER), true) - # Use the committed jvm.cfg for this 32 bit setup (the minimal - # VM is already KNOWN on platforms that potentially support it) + COPY_JVM_CFG_FILE := true + else + # For zero, the default jvm.cfg file is sufficient + ifeq ($(JVM_VARIANT_ZERO), true) + COPY_JVM_CFG_FILE := true + endif + endif +endif + +ifeq ($(COPY_JVM_CFG_FILE), true) $(JVMCFG): $(JVMCFG_SRC) $(call install-file) - else +else $(JVMCFG): $(MKDIR) -p $(@D) $(RM) $(@) @@ -338,12 +346,6 @@ ifeq ($(OPENJDK_TARGET_CPU_BITS),32) endif endif endif - endif - -else - # Use the default jvm.cfg for this 64 bit setup. - $(JVMCFG): $(JVMCFG_SRC) - $(call install-file) endif COPY_FILES += $(JVMCFG) From 5c6c0a8d1dc5e47897094766190ebe5d8f3e5d14 Mon Sep 17 00:00:00 2001 From: Jiangli Zhou Date: Thu, 22 Aug 2013 19:27:42 -0400 Subject: [PATCH 115/218] 8023547: com/sun/jdi/RedefineMulti.sh fails with IllegalArgumentException after JDK-8021948 Need to check if the constant pool mapping returns 0. Reviewed-by: coleenp, sspitsyn --- .../src/share/vm/prims/jvmtiRedefineClasses.cpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp b/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp index dd1553af46c..803cf9a7545 100644 --- a/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp +++ b/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp @@ -1554,18 +1554,22 @@ bool VM_RedefineClasses::rewrite_cp_refs(instanceKlassHandle scratch_class, return false; } - // rewrite sourc file name index: + // rewrite source file name index: u2 source_file_name_idx = scratch_class->source_file_name_index(); if (source_file_name_idx != 0) { u2 new_source_file_name_idx = find_new_index(source_file_name_idx); - scratch_class->set_source_file_name_index(new_source_file_name_idx); + if (new_source_file_name_idx != 0) { + scratch_class->set_source_file_name_index(new_source_file_name_idx); + } } // rewrite class generic signature index: u2 generic_signature_index = scratch_class->generic_signature_index(); if (generic_signature_index != 0) { u2 new_generic_signature_index = find_new_index(generic_signature_index); - scratch_class->set_generic_signature_index(new_generic_signature_index); + if (new_generic_signature_index != 0) { + scratch_class->set_generic_signature_index(new_generic_signature_index); + } } return true; @@ -1737,7 +1741,10 @@ void VM_RedefineClasses::rewrite_cp_refs_in_method(methodHandle method, for (int i = 0; i < len; i++) { const u2 cp_index = elem[i].name_cp_index; - elem[i].name_cp_index = find_new_index(cp_index); + const u2 new_cp_index = find_new_index(cp_index); + if (new_cp_index != 0) { + elem[i].name_cp_index = new_cp_index; + } } } } // end rewrite_cp_refs_in_method() From ea17b8decf3f892b7d15750ef466e162abb717d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20Gr=C3=B6nlund?= Date: Fri, 23 Aug 2013 10:36:34 +0200 Subject: [PATCH 116/218] 8023457: Event based tracing framework needs a mutex for thread groups Reviewed-by: acorn, sla --- hotspot/src/share/vm/runtime/mutexLocker.cpp | 16 +++++++++++----- hotspot/src/share/vm/runtime/mutexLocker.hpp | 8 +++++--- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/hotspot/src/share/vm/runtime/mutexLocker.cpp b/hotspot/src/share/vm/runtime/mutexLocker.cpp index 14e65081d62..f513b7b376c 100644 --- a/hotspot/src/share/vm/runtime/mutexLocker.cpp +++ b/hotspot/src/share/vm/runtime/mutexLocker.cpp @@ -124,13 +124,15 @@ Monitor* GCTaskManager_lock = NULL; Mutex* Management_lock = NULL; Monitor* Service_lock = NULL; -Mutex* Stacktrace_lock = NULL; +Monitor* PeriodicTask_lock = NULL; -Monitor* JfrQuery_lock = NULL; +#ifdef INCLUDE_TRACE +Mutex* JfrStacktrace_lock = NULL; Monitor* JfrMsg_lock = NULL; Mutex* JfrBuffer_lock = NULL; Mutex* JfrStream_lock = NULL; -Monitor* PeriodicTask_lock = NULL; +Mutex* JfrThreadGroups_lock = NULL; +#endif #define MAX_NUM_MUTEX 128 static Monitor * _mutex_array[MAX_NUM_MUTEX]; @@ -206,7 +208,6 @@ void mutex_init() { def(Patching_lock , Mutex , special, true ); // used for safepointing and code patching. def(ObjAllocPost_lock , Monitor, special, false); def(Service_lock , Monitor, special, true ); // used for service thread operations - def(Stacktrace_lock , Mutex, special, true ); // used for JFR stacktrace database def(JmethodIdCreation_lock , Mutex , leaf, true ); // used for creating jmethodIDs. def(SystemDictionary_lock , Monitor, leaf, true ); // lookups done by VM thread @@ -272,11 +273,16 @@ void mutex_init() { def(Debug3_lock , Mutex , nonleaf+4, true ); def(ProfileVM_lock , Monitor, special, false); // used for profiling of the VMThread def(CompileThread_lock , Monitor, nonleaf+5, false ); + def(PeriodicTask_lock , Monitor, nonleaf+5, true); +#ifdef INCLUDE_TRACE def(JfrMsg_lock , Monitor, leaf, true); def(JfrBuffer_lock , Mutex, nonleaf+1, true); + def(JfrThreadGroups_lock , Mutex, nonleaf+1, true); def(JfrStream_lock , Mutex, nonleaf+2, true); - def(PeriodicTask_lock , Monitor, nonleaf+5, true); + def(JfrStacktrace_lock , Mutex, special, true ); +#endif + } GCMutexLocker::GCMutexLocker(Monitor * mutex) { diff --git a/hotspot/src/share/vm/runtime/mutexLocker.hpp b/hotspot/src/share/vm/runtime/mutexLocker.hpp index 7a2e240bd4f..d98b8d890fd 100644 --- a/hotspot/src/share/vm/runtime/mutexLocker.hpp +++ b/hotspot/src/share/vm/runtime/mutexLocker.hpp @@ -137,13 +137,15 @@ extern Mutex* HotCardCache_lock; // protects the hot card cache extern Mutex* Management_lock; // a lock used to serialize JVM management extern Monitor* Service_lock; // a lock used for service thread operation -extern Mutex* Stacktrace_lock; // used to guard access to the stacktrace table +extern Monitor* PeriodicTask_lock; // protects the periodic task structure -extern Monitor* JfrQuery_lock; // protects JFR use +#ifdef INCLUDE_TRACE +extern Mutex* JfrStacktrace_lock; // used to guard access to the JFR stacktrace table extern Monitor* JfrMsg_lock; // protects JFR messaging extern Mutex* JfrBuffer_lock; // protects JFR buffer operations extern Mutex* JfrStream_lock; // protects JFR stream access -extern Monitor* PeriodicTask_lock; // protects the periodic task structure +extern Mutex* JfrThreadGroups_lock; // protects JFR access to Thread Groups +#endif // A MutexLocker provides mutual exclusion with respect to a given mutex // for the scope which contains the locker. The lock is an OS lock, not From e8f5679bc5d4eb1ea82bd51e664d1aa75a92100d Mon Sep 17 00:00:00 2001 From: Miroslav Kos Date: Fri, 23 Aug 2013 09:57:21 +0100 Subject: [PATCH 117/218] 8022885: Update JAX-WS RI integration to 2.2.9-b14140 8013016: Rebase 8009009 against the latest jdk8/jaxws Reviewed-by: alanb, chegar --- .../tools/ParallelWorldClassLoader.java | 3 +- .../probe/provider/annotations/Probe.java | 7 +- .../impl/AverageRangeStatisticImpl.java | 6 +- .../impl/BoundaryStatisticImpl.java | 6 +- .../impl/BoundedRangeStatisticImpl.java | 7 +- .../statistics/impl/CountStatisticImpl.java | 6 +- .../statistics/impl/RangeStatisticImpl.java | 6 +- .../statistics/impl/StatisticImpl.java | 15 +- .../statistics/impl/StringStatisticImpl.java | 5 +- .../statistics/impl/TimeStatisticImpl.java | 6 +- .../internal/jxc/MessageBundle.properties | 4 +- .../internal/jxc/MessageBundle_de.properties | 4 +- .../internal/jxc/MessageBundle_es.properties | 4 +- .../internal/jxc/MessageBundle_fr.properties | 4 +- .../internal/jxc/MessageBundle_it.properties | 4 +- .../internal/jxc/MessageBundle_ja.properties | 4 +- .../internal/jxc/MessageBundle_ko.properties | 4 +- .../jxc/MessageBundle_pt_BR.properties | 4 +- .../jxc/MessageBundle_zh_CN.properties | 4 +- .../jxc/MessageBundle_zh_TW.properties | 4 +- .../jxc/gen/config/AttributesImpl.java | 3 + .../internal/jxc/gen/config/Classes.java | 148 +- .../tools/internal/jxc/gen/config/Config.java | 80 +- .../jxc/gen/config/NGCCEventReceiver.java | 4 +- .../jxc/gen/config/NGCCEventSource.java | 4 +- .../internal/jxc/gen/config/NGCCHandler.java | 4 +- .../jxc/gen/config/NGCCInterleaveFilter.java | 3 + .../internal/jxc/gen/config/NGCCRuntime.java | 4 +- .../tools/internal/jxc/gen/config/Schema.java | 152 +- .../sun/tools/internal/ws/version.properties | 8 +- .../internal/xjc/MessageBundle.properties | 12 +- .../internal/xjc/MessageBundle_de.properties | 12 +- .../internal/xjc/MessageBundle_es.properties | 12 +- .../internal/xjc/MessageBundle_fr.properties | 12 +- .../internal/xjc/MessageBundle_it.properties | 12 +- .../internal/xjc/MessageBundle_ja.properties | 12 +- .../internal/xjc/MessageBundle_ko.properties | 12 +- .../xjc/MessageBundle_pt_BR.properties | 12 +- .../xjc/MessageBundle_zh_CN.properties | 12 +- .../xjc/MessageBundle_zh_TW.properties | 12 +- .../sun/tools/internal/xjc/SchemaCache.java | 6 +- .../spec/XmlAccessorOrderWriter.java | 5 + .../spec/XmlAccessorTypeWriter.java | 5 + .../spec/XmlAnyAttributeWriter.java | 5 + .../annotation/spec/XmlAnyElementWriter.java | 5 + .../spec/XmlAttachmentRefWriter.java | 5 + .../annotation/spec/XmlAttributeWriter.java | 5 + .../annotation/spec/XmlElementDeclWriter.java | 5 + .../annotation/spec/XmlElementRefWriter.java | 5 + .../annotation/spec/XmlElementRefsWriter.java | 5 + .../spec/XmlElementWrapperWriter.java | 5 + .../annotation/spec/XmlElementWriter.java | 5 + .../annotation/spec/XmlElementsWriter.java | 5 + .../annotation/spec/XmlEnumValueWriter.java | 5 + .../annotation/spec/XmlEnumWriter.java | 5 + .../annotation/spec/XmlIDREFWriter.java | 5 + .../annotation/spec/XmlIDWriter.java | 5 + .../spec/XmlInlineBinaryDataWriter.java | 5 + .../spec/XmlJavaTypeAdapterWriter.java | 5 + .../annotation/spec/XmlListWriter.java | 5 + .../annotation/spec/XmlMimeTypeWriter.java | 5 + .../annotation/spec/XmlMixedWriter.java | 5 + .../annotation/spec/XmlNsWriter.java | 5 + .../annotation/spec/XmlRegistryWriter.java | 5 + .../annotation/spec/XmlRootElementWriter.java | 5 + .../annotation/spec/XmlSchemaTypeWriter.java | 5 + .../annotation/spec/XmlSchemaTypesWriter.java | 5 + .../annotation/spec/XmlSchemaWriter.java | 5 + .../annotation/spec/XmlSeeAlsoWriter.java | 5 + .../annotation/spec/XmlTransientWriter.java | 5 + .../annotation/spec/XmlTypeWriter.java | 5 + .../annotation/spec/XmlValueWriter.java | 5 + .../generator/bean/MessageBundle.properties | 2 +- .../internal/xjc/model/CPropertyInfo.java | 3 +- .../tools/internal/xjc/model/CTypeRef.java | 35 +- .../internal/xjc/model/package-info.java | 6 +- .../AbstractReferenceFinderImpl.java | 49 +- .../xjc/reader/internalizer/DOMForest.java | 53 +- .../com/sun/xml/internal/bind/Util.java | 2 +- .../sun/xml/internal/bind/v2/Messages.java | 4 +- .../xml/internal/bind/v2/Messages.properties | 8 +- .../bind/v2/model/annotation/Init.java | 5 +- .../model/annotation/XmlAttributeQuick.java | 5 + .../model/annotation/XmlElementDeclQuick.java | 5 + .../v2/model/annotation/XmlElementQuick.java | 5 + .../model/annotation/XmlElementRefQuick.java | 5 + .../model/annotation/XmlElementRefsQuick.java | 5 + .../v2/model/annotation/XmlEnumQuick.java | 5 + .../model/annotation/XmlRootElementQuick.java | 5 + .../v2/model/annotation/XmlSchemaQuick.java | 5 + .../model/annotation/XmlSchemaTypeQuick.java | 5 + .../model/annotation/XmlTransientQuick.java | 5 + .../v2/model/annotation/XmlTypeQuick.java | 5 + .../v2/model/annotation/XmlValueQuick.java | 5 + .../bind/v2/model/core/package-info.java | 6 +- .../impl/RuntimeBuiltinLeafInfoImpl.java | 15 +- .../xml/internal/bind/v2/package-info.java | 4 - .../bind/v2/runtime/BridgeAdapter.java | 4 - .../internal/bind/v2/runtime/Coordinator.java | 69 +- .../bind/v2/runtime/XMLSerializer.java | 2 - .../reflect/PrimitiveArrayListerBoolean.java | 9 +- .../PrimitiveArrayListerCharacter.java | 9 +- .../reflect/PrimitiveArrayListerDouble.java | 9 +- .../reflect/PrimitiveArrayListerFloat.java | 9 +- .../reflect/PrimitiveArrayListerInteger.java | 9 +- .../reflect/PrimitiveArrayListerLong.java | 9 +- .../reflect/PrimitiveArrayListerShort.java | 9 +- .../reflect/opt/FieldAccessor_Boolean.java | 8 +- .../reflect/opt/FieldAccessor_Character.java | 8 +- .../reflect/opt/FieldAccessor_Double.java | 8 +- .../reflect/opt/FieldAccessor_Float.java | 8 +- .../reflect/opt/FieldAccessor_Integer.java | 8 +- .../reflect/opt/FieldAccessor_Long.java | 8 +- .../reflect/opt/FieldAccessor_Short.java | 8 +- .../reflect/opt/MethodAccessor_Boolean.java | 8 +- .../reflect/opt/MethodAccessor_Character.java | 8 +- .../reflect/opt/MethodAccessor_Double.java | 8 +- .../reflect/opt/MethodAccessor_Float.java | 8 +- .../reflect/opt/MethodAccessor_Integer.java | 8 +- .../reflect/opt/MethodAccessor_Long.java | 8 +- .../reflect/opt/MethodAccessor_Short.java | 8 +- .../opt/TransducedAccessor_field_Double.java | 8 +- .../opt/TransducedAccessor_field_Float.java | 8 +- .../opt/TransducedAccessor_field_Long.java | 8 +- .../opt/TransducedAccessor_field_Short.java | 8 +- .../TransducedAccessor_method_Boolean.java | 8 +- .../opt/TransducedAccessor_method_Double.java | 8 +- .../opt/TransducedAccessor_method_Float.java | 8 +- .../opt/TransducedAccessor_method_Long.java | 8 +- .../opt/TransducedAccessor_method_Short.java | 8 +- .../bind/v2/runtime/unmarshaller/Loader.java | 8 +- .../v2/runtime/unmarshaller/Messages.java | 1 + .../runtime/unmarshaller/Messages.properties | 4 + .../v2/runtime/unmarshaller/SAXConnector.java | 44 +- .../unmarshaller/UnmarshallingContext.java | 79 +- .../runtime/unmarshaller/XsiTypeLoader.java | 15 +- .../v2/schemagen/xmlschema/Annotated.java | 5 + .../v2/schemagen/xmlschema/Annotation.java | 5 + .../bind/v2/schemagen/xmlschema/Any.java | 5 + .../bind/v2/schemagen/xmlschema/Appinfo.java | 5 + .../v2/schemagen/xmlschema/AttrDecls.java | 5 + .../v2/schemagen/xmlschema/AttributeType.java | 5 + .../schemagen/xmlschema/ComplexContent.java | 5 + .../schemagen/xmlschema/ComplexExtension.java | 5 + .../xmlschema/ComplexRestriction.java | 5 + .../v2/schemagen/xmlschema/ComplexType.java | 15 +- .../schemagen/xmlschema/ComplexTypeHost.java | 5 + .../schemagen/xmlschema/ComplexTypeModel.java | 5 + .../v2/schemagen/xmlschema/Documentation.java | 5 + .../bind/v2/schemagen/xmlschema/Element.java | 9 +- .../v2/schemagen/xmlschema/ExplicitGroup.java | 5 + .../v2/schemagen/xmlschema/ExtensionType.java | 5 + .../schemagen/xmlschema/FixedOrDefault.java | 5 + .../bind/v2/schemagen/xmlschema/Import.java | 5 + .../bind/v2/schemagen/xmlschema/List.java | 5 + .../schemagen/xmlschema/LocalAttribute.java | 5 + .../v2/schemagen/xmlschema/LocalElement.java | 5 + .../schemagen/xmlschema/NestedParticle.java | 5 + .../v2/schemagen/xmlschema/NoFixedFacet.java | 5 + .../bind/v2/schemagen/xmlschema/Occurs.java | 11 +- .../v2/schemagen/xmlschema/Redefinable.java | 5 + .../bind/v2/schemagen/xmlschema/Schema.java | 13 +- .../v2/schemagen/xmlschema/SchemaTop.java | 5 + .../v2/schemagen/xmlschema/SimpleContent.java | 5 + .../schemagen/xmlschema/SimpleDerivation.java | 5 + .../schemagen/xmlschema/SimpleExtension.java | 5 + .../xmlschema/SimpleRestriction.java | 5 + .../xmlschema/SimpleRestrictionModel.java | 5 + .../v2/schemagen/xmlschema/SimpleType.java | 5 + .../schemagen/xmlschema/SimpleTypeHost.java | 5 + .../xmlschema/TopLevelAttribute.java | 5 + .../schemagen/xmlschema/TopLevelElement.java | 9 +- .../schemagen/xmlschema/TypeDefParticle.java | 5 + .../bind/v2/schemagen/xmlschema/TypeHost.java | 5 + .../bind/v2/schemagen/xmlschema/Union.java | 5 + .../bind/v2/schemagen/xmlschema/Wildcard.java | 5 + .../internal/bind/v2/util/EditDistance.java | 22 +- .../xml/internal/bind/v2/util/XmlFactory.java | 25 +- .../internal/dtdparser/DTDEventListener.java | 2 +- .../internal/dtdparser/DTDHandlerBase.java | 2 +- .../sun/xml/internal/dtdparser/DTDParser.java | 18 +- .../dtdparser/EndOfInputException.java | 2 +- .../xml/internal/dtdparser/EntityDecl.java | 2 +- .../internal/dtdparser/ExternalEntity.java | 2 +- .../xml/internal/dtdparser/InputEntity.java | 2 +- .../internal/dtdparser/InternalEntity.java | 2 +- .../internal/dtdparser/MessageCatalog.java | 2 +- .../sun/xml/internal/dtdparser/Resolver.java | 2 +- .../internal/dtdparser/SimpleHashtable.java | 2 +- .../sun/xml/internal/dtdparser/XmlChars.java | 2 +- .../sun/xml/internal/dtdparser/XmlNames.java | 2 +- .../sun/xml/internal/dtdparser/XmlReader.java | 6 +- .../sun/xml/internal/dtdparser/package.html | 2 +- .../dtdparser/resources/Messages.properties | 2 +- .../buffer/AbstractCreatorProcessor.java | 3 +- .../stream/buffer/AbstractProcessor.java | 2 +- .../stream/buffer/AttributesHolder.java | 22 +- .../stream/buffer/FragmentedArray.java | 10 +- .../stream/buffer/MutableXMLStreamBuffer.java | 2 +- .../stream/buffer/XMLStreamBuffer.java | 2 +- .../buffer/XMLStreamBufferException.java | 2 +- .../stream/buffer/XMLStreamBufferMark.java | 2 +- .../stream/buffer/XMLStreamBufferResult.java | 2 +- .../stream/buffer/XMLStreamBufferSource.java | 2 +- .../buffer/sax/DefaultWithLexicalHandler.java | 2 +- .../internal/stream/buffer/sax/Features.java | 2 +- .../stream/buffer/sax/Properties.java | 2 +- .../stream/buffer/sax/SAXBufferCreator.java | 2 +- .../buffer/stax/StreamBufferCreator.java | 2 +- .../stax/StreamReaderBufferCreator.java | 5 +- .../stax/StreamReaderBufferProcessor.java | 2 +- .../stax/StreamWriterBufferCreator.java | 2 +- .../xml/internal/txw2/output/XMLWriter.java | 2 +- .../xml/internal/ws/api/message/Packet.java | 3 + .../xml/internal/ws/api/server/Container.java | 4 +- .../server/ThreadLocalContainerResolver.java | 12 +- .../api/streaming/XMLStreamReaderFactory.java | 189 +- .../wsdl/writer/WSDLGeneratorExtension.java | 4 +- .../ws/commons/xmlutil/Converter.java | 21 +- .../xml/internal/ws/encoding/MtomCodec.java | 40 +- .../ws/encoding/StreamSOAP11Codec.java | 6 - .../ws/encoding/StreamSOAP12Codec.java | 6 - .../internal/ws/encoding/StreamSOAPCodec.java | 110 +- .../xml/internal/ws/encoding/TagInfoset.java | 35 +- .../ws/message/AbstractMessageImpl.java | 42 +- .../internal/ws/message/jaxb/JAXBHeader.java | 17 +- .../internal/ws/message/jaxb/JAXBMessage.java | 79 +- .../internal/ws/message/saaj/SAAJMessage.java | 96 +- .../ws/message/stream/StreamMessage.java | 250 +- .../ws/resources/StreamingMessages.java | 36 + .../ws/resources/streaming.properties | 7 +- .../internal/ws/server/SDDocumentImpl.java | 4 +- .../internal/ws/spi/db/BindingContext.java | 32 +- .../pipe/AbstractSchemaValidationTube.java | 6 +- .../ws/util/resources/Messages_en.properties | 2 +- .../xml/internal/ws/util/version.properties | 8 +- .../sun/xml/internal/ws/util/xml/XmlUtil.java | 22 + .../ws/wsdl/writer/WSDLGenerator.java | 2 +- .../internal/xsom/impl/parser/Messages.java | 8 +- .../xsom/impl/parser/Messages.properties | 8 +- .../impl/parser/SAXParserFactoryAdaptor.java | 6 +- .../xsom/impl/parser/state/Schema.java | 1378 +++++------ .../impl/parser/state/SimpleType_List.java | 192 +- .../parser/state/SimpleType_Restriction.java | 292 +-- .../impl/parser/state/SimpleType_Union.java | 166 +- .../xsom/impl/parser/state/annotation.java | 10 +- .../impl/parser/state/attributeDeclBody.java | 328 +-- .../impl/parser/state/attributeGroupDecl.java | 250 +- .../xsom/impl/parser/state/attributeUses.java | 924 ++++---- .../xsom/impl/parser/state/complexType.java | 2098 ++++++++--------- .../complexType_complexContent_body.java | 80 +- .../impl/parser/state/elementDeclBody.java | 1048 ++++---- .../xsom/impl/parser/state/erSet.java | 10 +- .../xsom/impl/parser/state/ersSet.java | 10 +- .../xsom/impl/parser/state/facet.java | 246 +- .../xsom/impl/parser/state/group.java | 244 +- .../impl/parser/state/identityConstraint.java | 428 ++-- .../xsom/impl/parser/state/importDecl.java | 134 +- .../xsom/impl/parser/state/includeDecl.java | 114 +- .../impl/parser/state/modelGroupBody.java | 220 +- .../xsom/impl/parser/state/notation.java | 298 +-- .../xsom/impl/parser/state/occurs.java | 152 +- .../xsom/impl/parser/state/particle.java | 876 +++---- .../xsom/impl/parser/state/qname.java | 10 +- .../xsom/impl/parser/state/redefine.java | 210 +- .../xsom/impl/parser/state/simpleType.java | 242 +- .../xsom/impl/parser/state/wildcardBody.java | 248 +- .../xsom/impl/parser/state/xpath.java | 162 +- .../xml/internal/xsom/parser/JAXPParser.java | 46 +- .../xml/internal/xsom/parser/XSOMParser.java | 5 +- .../xsom/util/DomAnnotationParserFactory.java | 13 +- .../jaxws_classes/javax/xml/bind/Binder.java | 2 +- .../javax/xml/bind/ContextFinder.java | 59 +- .../javax/xml/bind/DataBindingException.java | 2 +- .../javax/xml/bind/DatatypeConverter.java | 4 +- .../javax/xml/bind/DatatypeConverterImpl.java | 2 +- .../xml/bind/DatatypeConverterInterface.java | 2 +- .../jaxws_classes/javax/xml/bind/Element.java | 2 +- .../javax/xml/bind/GetPropertyAction.java | 2 +- .../jaxws_classes/javax/xml/bind/JAXB.java | 2 +- .../javax/xml/bind/JAXBContext.java | 2 +- .../javax/xml/bind/JAXBElement.java | 2 +- .../javax/xml/bind/JAXBException.java | 2 +- .../javax/xml/bind/JAXBIntrospector.java | 2 +- .../javax/xml/bind/JAXBPermission.java | 2 +- .../javax/xml/bind/MarshalException.java | 2 +- .../javax/xml/bind/Messages.java | 2 +- .../javax/xml/bind/Messages.properties | 2 +- .../javax/xml/bind/NotIdentifiableEvent.java | 2 +- .../javax/xml/bind/ParseConversionEvent.java | 2 +- .../javax/xml/bind/PrintConversionEvent.java | 2 +- .../javax/xml/bind/PropertyException.java | 2 +- .../javax/xml/bind/SchemaOutputResolver.java | 2 +- .../xml/bind/TypeConstraintException.java | 2 +- .../javax/xml/bind/UnmarshalException.java | 2 +- .../javax/xml/bind/Unmarshaller.java | 2 +- .../javax/xml/bind/UnmarshallerHandler.java | 2 +- .../javax/xml/bind/ValidationEvent.java | 2 +- .../xml/bind/ValidationEventHandler.java | 2 +- .../xml/bind/ValidationEventLocator.java | 2 +- .../javax/xml/bind/ValidationException.java | 2 +- .../javax/xml/bind/Validator.java | 2 +- .../javax/xml/bind/WhiteSpaceProcessor.java | 2 +- .../javax/xml/bind/annotation/DomHandler.java | 2 +- .../xml/bind/annotation/W3CDomHandler.java | 2 +- .../xml/bind/annotation/XmlAccessOrder.java | 2 +- .../xml/bind/annotation/XmlAccessType.java | 2 +- .../xml/bind/annotation/XmlAccessorOrder.java | 2 +- .../xml/bind/annotation/XmlAccessorType.java | 2 +- .../xml/bind/annotation/XmlAnyAttribute.java | 2 +- .../xml/bind/annotation/XmlAnyElement.java | 2 +- .../xml/bind/annotation/XmlAttachmentRef.java | 2 +- .../xml/bind/annotation/XmlAttribute.java | 2 +- .../javax/xml/bind/annotation/XmlElement.java | 2 +- .../xml/bind/annotation/XmlElementDecl.java | 2 +- .../xml/bind/annotation/XmlElementRef.java | 2 +- .../xml/bind/annotation/XmlElementRefs.java | 2 +- .../bind/annotation/XmlElementWrapper.java | 2 +- .../xml/bind/annotation/XmlElements.java | 2 +- .../javax/xml/bind/annotation/XmlEnum.java | 2 +- .../xml/bind/annotation/XmlEnumValue.java | 2 +- .../javax/xml/bind/annotation/XmlID.java | 2 +- .../javax/xml/bind/annotation/XmlIDREF.java | 2 +- .../javax/xml/bind/annotation/XmlList.java | 2 +- .../javax/xml/bind/annotation/XmlMixed.java | 2 +- .../javax/xml/bind/annotation/XmlNs.java | 2 +- .../javax/xml/bind/annotation/XmlNsForm.java | 2 +- .../xml/bind/annotation/XmlRegistry.java | 2 +- .../xml/bind/annotation/XmlRootElement.java | 2 +- .../javax/xml/bind/annotation/XmlSchema.java | 2 +- .../xml/bind/annotation/XmlSchemaType.java | 2 +- .../xml/bind/annotation/XmlSchemaTypes.java | 2 +- .../javax/xml/bind/annotation/XmlSeeAlso.java | 2 +- .../xml/bind/annotation/XmlTransient.java | 2 +- .../javax/xml/bind/annotation/XmlType.java | 2 +- .../javax/xml/bind/annotation/XmlValue.java | 2 +- .../adapters/CollapsedStringAdapter.java | 4 +- .../annotation/adapters/HexBinaryAdapter.java | 2 +- .../adapters/NormalizedStringAdapter.java | 2 +- .../adapters/XmlJavaTypeAdapter.java | 2 +- .../adapters/XmlJavaTypeAdapters.java | 2 +- .../xml/bind/annotation/adapters/package.html | 2 +- .../javax/xml/bind/annotation/package.html | 2 +- .../bind/attachment/AttachmentMarshaller.java | 2 +- .../attachment/AttachmentUnmarshaller.java | 2 +- .../javax/xml/bind/attachment/package.html | 2 +- .../bind/helpers/AbstractMarshallerImpl.java | 2 +- .../helpers/AbstractUnmarshallerImpl.java | 2 +- .../DefaultValidationEventHandler.java | 2 +- .../javax/xml/bind/helpers/Messages.java | 2 +- .../xml/bind/helpers/Messages.properties | 2 +- .../helpers/NotIdentifiableEventImpl.java | 2 +- .../helpers/ParseConversionEventImpl.java | 2 +- .../helpers/PrintConversionEventImpl.java | 2 +- .../xml/bind/helpers/ValidationEventImpl.java | 2 +- .../helpers/ValidationEventLocatorImpl.java | 2 +- .../javax/xml/bind/helpers/package.html | 2 +- .../jaxws_classes/javax/xml/bind/package.html | 2 +- .../javax/xml/bind/util/JAXBResult.java | 2 +- .../javax/xml/bind/util/JAXBSource.java | 7 +- .../javax/xml/bind/util/Messages.java | 2 +- .../javax/xml/bind/util/Messages.properties | 2 +- .../bind/util/ValidationEventCollector.java | 2 +- .../javax/xml/bind/util/package.html | 2 +- 364 files changed, 7408 insertions(+), 6257 deletions(-) diff --git a/jaxws/src/share/jaxws_classes/com/sun/istack/internal/tools/ParallelWorldClassLoader.java b/jaxws/src/share/jaxws_classes/com/sun/istack/internal/tools/ParallelWorldClassLoader.java index 50cfa7470b8..5ed042edd59 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/istack/internal/tools/ParallelWorldClassLoader.java +++ b/jaxws/src/share/jaxws_classes/com/sun/istack/internal/tools/ParallelWorldClassLoader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -211,6 +211,7 @@ public class ParallelWorldClassLoader extends ClassLoader implements Closeable { throw new ClassNotFoundException("Loaded outside a jar "+url); url = url.substring(4); // cut off jar: url = url.substring(0,url.lastIndexOf('!')); // cut off everything after '!' + url = url.replaceAll(" ", "%20"); // support white spaces in path return new URL(url); } } diff --git a/jaxws/src/share/jaxws_classes/com/sun/org/glassfish/external/probe/provider/annotations/Probe.java b/jaxws/src/share/jaxws_classes/com/sun/org/glassfish/external/probe/provider/annotations/Probe.java index e66c91ace9e..04ff4c485d1 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/org/glassfish/external/probe/provider/annotations/Probe.java +++ b/jaxws/src/share/jaxws_classes/com/sun/org/glassfish/external/probe/provider/annotations/Probe.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 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 @@ -47,5 +47,8 @@ public @interface Probe { public boolean self() default false; public String providerName() default ""; public String moduleName() default ""; - + public boolean stateful() default false; + public String profileNames() default ""; + public boolean statefulReturn() default false; + public boolean statefulException() default false; } diff --git a/jaxws/src/share/jaxws_classes/com/sun/org/glassfish/external/statistics/impl/AverageRangeStatisticImpl.java b/jaxws/src/share/jaxws_classes/com/sun/org/glassfish/external/statistics/impl/AverageRangeStatisticImpl.java index 3f6df88592b..bbba5738ce9 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/org/glassfish/external/statistics/impl/AverageRangeStatisticImpl.java +++ b/jaxws/src/share/jaxws_classes/com/sun/org/glassfish/external/statistics/impl/AverageRangeStatisticImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,7 +27,6 @@ package com.sun.org.glassfish.external.statistics.impl; -import java.util.concurrent.atomic.AtomicLong; import java.util.Map; import java.lang.reflect.*; import com.sun.org.glassfish.external.statistics.AverageRangeStatistic; @@ -139,6 +138,8 @@ public final class AverageRangeStatisticImpl extends StatisticImpl implements // todo: equals implementation public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + checkMethod(method); + Object result; try { result = method.invoke(this, args); @@ -147,7 +148,6 @@ public final class AverageRangeStatisticImpl extends StatisticImpl implements } catch (Exception e) { throw new RuntimeException("unexpected invocation exception: " + e.getMessage()); - } finally { } return result; } diff --git a/jaxws/src/share/jaxws_classes/com/sun/org/glassfish/external/statistics/impl/BoundaryStatisticImpl.java b/jaxws/src/share/jaxws_classes/com/sun/org/glassfish/external/statistics/impl/BoundaryStatisticImpl.java index 5eeafaf5ae5..633771fa2ce 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/org/glassfish/external/statistics/impl/BoundaryStatisticImpl.java +++ b/jaxws/src/share/jaxws_classes/com/sun/org/glassfish/external/statistics/impl/BoundaryStatisticImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,7 +27,6 @@ package com.sun.org.glassfish.external.statistics.impl; import com.sun.org.glassfish.external.statistics.BoundaryStatistic; -import java.util.concurrent.atomic.AtomicLong; import java.util.Map; import java.lang.reflect.*; @@ -81,6 +80,8 @@ public final class BoundaryStatisticImpl extends StatisticImpl // todo: equals implementation public Object invoke(Object proxy, Method m, Object[] args) throws Throwable { + checkMethod(m); + Object result; try { result = m.invoke(this, args); @@ -89,7 +90,6 @@ public final class BoundaryStatisticImpl extends StatisticImpl } catch (Exception e) { throw new RuntimeException("unexpected invocation exception: " + e.getMessage()); - } finally { } return result; } diff --git a/jaxws/src/share/jaxws_classes/com/sun/org/glassfish/external/statistics/impl/BoundedRangeStatisticImpl.java b/jaxws/src/share/jaxws_classes/com/sun/org/glassfish/external/statistics/impl/BoundedRangeStatisticImpl.java index 9cbf7b5fa51..52c8479d75a 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/org/glassfish/external/statistics/impl/BoundedRangeStatisticImpl.java +++ b/jaxws/src/share/jaxws_classes/com/sun/org/glassfish/external/statistics/impl/BoundedRangeStatisticImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,8 +26,8 @@ package com.sun.org.glassfish.external.statistics.impl; + import com.sun.org.glassfish.external.statistics.BoundedRangeStatistic; -import java.util.concurrent.atomic.AtomicLong; import java.util.Map; import java.lang.reflect.*; @@ -145,6 +145,8 @@ public final class BoundedRangeStatisticImpl extends StatisticImpl // todo: equals implementation public Object invoke(Object proxy, Method m, Object[] args) throws Throwable { + checkMethod(m); + Object result; try { result = m.invoke(this, args); @@ -153,7 +155,6 @@ public final class BoundedRangeStatisticImpl extends StatisticImpl } catch (Exception e) { throw new RuntimeException("unexpected invocation exception: " + e.getMessage()); - } finally { } return result; } diff --git a/jaxws/src/share/jaxws_classes/com/sun/org/glassfish/external/statistics/impl/CountStatisticImpl.java b/jaxws/src/share/jaxws_classes/com/sun/org/glassfish/external/statistics/impl/CountStatisticImpl.java index f593de23e75..351627b6f6a 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/org/glassfish/external/statistics/impl/CountStatisticImpl.java +++ b/jaxws/src/share/jaxws_classes/com/sun/org/glassfish/external/statistics/impl/CountStatisticImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,7 +26,6 @@ package com.sun.org.glassfish.external.statistics.impl; import com.sun.org.glassfish.external.statistics.CountStatistic; -import java.util.concurrent.atomic.AtomicLong; import java.util.Map; import java.lang.reflect.*; @@ -103,6 +102,8 @@ public final class CountStatisticImpl extends StatisticImpl // todo: equals implementation public Object invoke(Object proxy, Method m, Object[] args) throws Throwable { + checkMethod(m); + Object result; try { result = m.invoke(this, args); @@ -111,7 +112,6 @@ public final class CountStatisticImpl extends StatisticImpl } catch (Exception e) { throw new RuntimeException("unexpected invocation exception: " + e.getMessage()); - } finally { } return result; } diff --git a/jaxws/src/share/jaxws_classes/com/sun/org/glassfish/external/statistics/impl/RangeStatisticImpl.java b/jaxws/src/share/jaxws_classes/com/sun/org/glassfish/external/statistics/impl/RangeStatisticImpl.java index cfe702a01c6..9f6ec99d89b 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/org/glassfish/external/statistics/impl/RangeStatisticImpl.java +++ b/jaxws/src/share/jaxws_classes/com/sun/org/glassfish/external/statistics/impl/RangeStatisticImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,7 +27,6 @@ package com.sun.org.glassfish.external.statistics.impl; import com.sun.org.glassfish.external.statistics.RangeStatistic; -import java.util.concurrent.atomic.AtomicLong; import java.util.Map; import java.lang.reflect.*; @@ -125,6 +124,8 @@ public final class RangeStatisticImpl extends StatisticImpl // todo: equals implementation public Object invoke(Object proxy, Method m, Object[] args) throws Throwable { + checkMethod(m); + Object result; try { result = m.invoke(this, args); @@ -133,7 +134,6 @@ public final class RangeStatisticImpl extends StatisticImpl } catch (Exception e) { throw new RuntimeException("unexpected invocation exception: " + e.getMessage()); - } finally { } return result; } diff --git a/jaxws/src/share/jaxws_classes/com/sun/org/glassfish/external/statistics/impl/StatisticImpl.java b/jaxws/src/share/jaxws_classes/com/sun/org/glassfish/external/statistics/impl/StatisticImpl.java index 708f06a5393..d257019a2b6 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/org/glassfish/external/statistics/impl/StatisticImpl.java +++ b/jaxws/src/share/jaxws_classes/com/sun/org/glassfish/external/statistics/impl/StatisticImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,8 +26,8 @@ package com.sun.org.glassfish.external.statistics.impl; import com.sun.org.glassfish.external.statistics.Statistic; -import java.io.Serializable; -import java.util.concurrent.atomic.AtomicLong; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -133,4 +133,13 @@ public abstract class StatisticImpl implements Statistic { protected static boolean isValidString(String str) { return (str!=null && str.length()>0); } + + protected void checkMethod(Method method) { + if (method == null || method.getDeclaringClass() == null + || !Statistic.class.isAssignableFrom(method.getDeclaringClass()) + || Modifier.isStatic(method.getModifiers())) { + throw new RuntimeException("Invalid method on invoke"); + } + } + } diff --git a/jaxws/src/share/jaxws_classes/com/sun/org/glassfish/external/statistics/impl/StringStatisticImpl.java b/jaxws/src/share/jaxws_classes/com/sun/org/glassfish/external/statistics/impl/StringStatisticImpl.java index 972f1c175cb..f8486daf7e1 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/org/glassfish/external/statistics/impl/StringStatisticImpl.java +++ b/jaxws/src/share/jaxws_classes/com/sun/org/glassfish/external/statistics/impl/StringStatisticImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -90,6 +90,8 @@ public final class StringStatisticImpl extends StatisticImpl // todo: equals implementation public Object invoke(Object proxy, Method m, Object[] args) throws Throwable { + checkMethod(m); + Object result; try { result = m.invoke(this, args); @@ -98,7 +100,6 @@ public final class StringStatisticImpl extends StatisticImpl } catch (Exception e) { throw new RuntimeException("unexpected invocation exception: " + e.getMessage()); - } finally { } return result; } diff --git a/jaxws/src/share/jaxws_classes/com/sun/org/glassfish/external/statistics/impl/TimeStatisticImpl.java b/jaxws/src/share/jaxws_classes/com/sun/org/glassfish/external/statistics/impl/TimeStatisticImpl.java index 6e6bd723382..27936b7ee46 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/org/glassfish/external/statistics/impl/TimeStatisticImpl.java +++ b/jaxws/src/share/jaxws_classes/com/sun/org/glassfish/external/statistics/impl/TimeStatisticImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,7 +28,6 @@ package com.sun.org.glassfish.external.statistics.impl; import com.sun.org.glassfish.external.statistics.TimeStatistic; -import java.util.concurrent.atomic.AtomicLong; import java.util.Map; import java.lang.reflect.*; @@ -145,6 +144,8 @@ public final class TimeStatisticImpl extends StatisticImpl // todo: equals implementation public Object invoke(Object proxy, Method m, Object[] args) throws Throwable { + checkMethod(m); + Object result; try { result = m.invoke(this, args); @@ -153,7 +154,6 @@ public final class TimeStatisticImpl extends StatisticImpl } catch (Exception e) { throw new RuntimeException("unexpected invocation exception: " + e.getMessage()); - } finally { } return result; } diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle.properties b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle.properties index c1805f1ff17..430a8d8ef0d 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle.properties +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle.properties @@ -30,10 +30,10 @@ BASEDIR_DOESNT_EXIST = \ Non-existent directory: {0} VERSION = \ - schemagen 2.2.8-b01 + schemagen 2.2.8-b20130806.1801 FULLVERSION = \ - schemagen full version "2.2.8-b01" + schemagen full version "2.2.8-b20130806.1801" USAGE = \ Usage: schemagen [-options ...] \n\ diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_de.properties b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_de.properties index 971c1709e2e..ddf736faf0a 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_de.properties +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_de.properties @@ -27,8 +27,8 @@ UNEXPECTED_NGCC_TOKEN = Nicht erkanntes {0} in Zeile {1} Spalte {2} BASEDIR_DOESNT_EXIST = Nicht vorhandenes Verzeichnis: {0} -VERSION = schemagen 2.2.8-b01 +VERSION = schemagen 2.2.8-b20130806.1801 -FULLVERSION = schemagen vollst\u00E4ndige Version "2.2.8-b01" +FULLVERSION = schemagen vollst\u00E4ndige Version "2.2.8-b20130806.1801" USAGE = Verwendung: schemagen [-options ...] \nOptionen: \n\\ \\ \\ \\ -d : Gibt an, wo die von Prozessor und javac generierten Klassendateien gespeichert werden sollen\n\\ \\ \\ \\ -cp : Gibt an, wo die vom Benutzer angegebenen Dateien gespeichert sind\n\\ \\ \\ \\ -classpath : Gibt an, wo die vom Benutzer angegebenen Dateien gespeichert sind\n\\ \\ \\ \\ -encoding : Gibt die Codierung f\u00FCr die Annotationsverarbeitung/den javac-Aufruf an \n\\ \\ \\ \\ -episode : Generiert Episodendatei f\u00FCr separate Kompilierung\n\\ \\ \\ \\ -version : Zeigt Versionsinformation an\n\\ \\ \\ \\ -fullversion : Zeigt vollst\u00E4ndige Versionsinformationen an\n\\ \\ \\ \\ -help : Zeigt diese Verwendungsmeldung an diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_es.properties b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_es.properties index 030047264b7..d9a1b2ee510 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_es.properties +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_es.properties @@ -27,8 +27,8 @@ UNEXPECTED_NGCC_TOKEN = Aparece un {0} inesperado en la l\u00EDnea {1} y la colu BASEDIR_DOESNT_EXIST = Directorio no existente: {0} -VERSION = schemagen 2.2.8-b01 +VERSION = schemagen 2.2.8-b20130806.1801 -FULLVERSION = versi\u00F3n completa de schemagen "2.2.8-b01" +FULLVERSION = versi\u00F3n completa de schemagen "2.2.8-b20130806.1801" USAGE = Sintaxis: schemagen [-options ...] \nOpciones: \n\\ \\ \\ \\ -d : especifique d\u00F3nde se colocan los archivos de clase generados por javac y el procesador\n\\ \\ \\ \\ -cp : especifique d\u00F3nde se encuentran los archivos especificados por el usuario\n\\ \\ \\ \\ -encoding : especifique la codificaci\u00F3n que se va a utilizar para el procesamiento de anotaciones/llamada de javac\n\\ \\ \\ \\ -episode : genera un archivo de episodio para una compilaci\u00F3n diferente\n\\ \\ \\ \\ -version : muestra la informaci\u00F3n de la versi\u00F3n\n\\ \\ \\ \\ -fullversion : muestra la informaci\u00F3n completa de la versi\u00F3n\n\\ \\ \\ \\ -help : muestra este mensaje de sintaxis diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_fr.properties b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_fr.properties index b3107ee4418..1ed6126bac8 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_fr.properties +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_fr.properties @@ -27,8 +27,8 @@ UNEXPECTED_NGCC_TOKEN = Un \u00E9l\u00E9ment {0} inattendu appara\u00EEt \u00E0 BASEDIR_DOESNT_EXIST = R\u00E9pertoire {0} inexistant -VERSION = schemagen 2.2.8-b01 +VERSION = schemagen 2.2.8-b20130806.1801 -FULLVERSION = version compl\u00E8te de schemagen "2.2.8-b01" +FULLVERSION = version compl\u00E8te de schemagen "2.2.8-b20130806.1801" USAGE = Syntaxe : schemagen [-options ...] \nOptions : \n\ \ \ \ -d : indiquez o\u00F9 placer les fichiers de classe g\u00E9n\u00E9r\u00E9s par le processeur et le compilateur javac\n\ \ \ \ -cp : indiquez o\u00F9 trouver les fichiers sp\u00E9cifi\u00E9s par l'utilisateur\n\ \ \ \ -classpath : indiquez o\u00F9 trouver les fichiers sp\u00E9cifi\u00E9s par l'utilisateur\n\ \ \ \ -encoding : indiquez l'encodage \u00E0 utiliser pour l'appel de javac/traitement de l'annotation \n\ \ \ \ -episode : g\u00E9n\u00E9rez un fichier d'\u00E9pisode pour la compilation s\u00E9par\u00E9e\n\ \ \ \ -version : affichez les informations de version\n\ \ \ \ -fullversion : affichez les informations compl\u00E8tes de version\n\ \ \ \ -help : affichez ce message de syntaxe diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_it.properties b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_it.properties index 0aa7cf4c807..0208b66294e 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_it.properties +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_it.properties @@ -27,8 +27,8 @@ UNEXPECTED_NGCC_TOKEN = {0} imprevisto visualizzato sulla riga {1} colonna {2} BASEDIR_DOESNT_EXIST = Directory non esistente: {0} -VERSION = schemagen 2.2.8-b01 +VERSION = schemagen 2.2.8-b20130806.1801 -FULLVERSION = versione completa schemagen "2.2.8-b01" +FULLVERSION = versione completa schemagen "2.2.8-b20130806.1801" USAGE = Uso: schemagen [-options ...] \nOpzioni: \n\ \ \ \ -d : specifica dove posizionare il processore e i file della classe generata javac\n\ \ \ \ -cp : specifica dove trovare i file specificati dall'utente\n\ \ \ \ -classpath : specifica dove trovare i file specificati dall'utente\n\ \ \ \ -encoding : specifica la codifica da usare per l'elaborazione dell'annotazione/richiamo javac \n\ \ \ \ -episode : genera il file di episodio per la compilazione separata\n\ \ \ \ -version : visualizza le informazioni sulla versione\n\ \ \ \ -fullversion : visualizza le informazioni sulla versione completa\n\ \ \ \ -help : visualizza questo messaggio sull'uso diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_ja.properties b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_ja.properties index b8889bb6e22..7678e5d8f3b 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_ja.properties +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_ja.properties @@ -27,8 +27,8 @@ UNEXPECTED_NGCC_TOKEN = \u4E88\u671F\u3057\u306A\u3044{0}\u304C\u884C{1}\u3001\u BASEDIR_DOESNT_EXIST = \u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u304C\u5B58\u5728\u3057\u307E\u305B\u3093: {0} -VERSION = schemagen 2.2.8-b01 +VERSION = schemagen 2.2.8-b20130806.1801 -FULLVERSION = schemagen\u30D5\u30EB\u30FB\u30D0\u30FC\u30B8\u30E7\u30F3"2.2.8-b01" +FULLVERSION = schemagen\u30D5\u30EB\u30FB\u30D0\u30FC\u30B8\u30E7\u30F3"2.2.8-b20130806.1801" USAGE = \u4F7F\u7528\u65B9\u6CD5: schemagen [-options ...] \n\u30AA\u30D7\u30B7\u30E7\u30F3: \n\ \ \ \ -d : \u30D7\u30ED\u30BB\u30C3\u30B5\u304A\u3088\u3073javac\u304C\u751F\u6210\u3057\u305F\u30AF\u30E9\u30B9\u30FB\u30D5\u30A1\u30A4\u30EB\u3092\u7F6E\u304F\u4F4D\u7F6E\u3092\u6307\u5B9A\u3057\u307E\u3059\n\ \ \ \ -cp : \u30E6\u30FC\u30B6\u30FC\u304C\u6307\u5B9A\u3057\u305F\u30D5\u30A1\u30A4\u30EB\u3092\u691C\u7D22\u3059\u308B\u4F4D\u7F6E\u3092\u6307\u5B9A\u3057\u307E\u3059\n\ \ \ \ -classpath : \u30E6\u30FC\u30B6\u30FC\u304C\u6307\u5B9A\u3057\u305F\u30D5\u30A1\u30A4\u30EB\u3092\u691C\u7D22\u3059\u308B\u4F4D\u7F6E\u3092\u6307\u5B9A\u3057\u307E\u3059\n\ \ \ \ -encoding : \u6CE8\u91C8\u51E6\u7406/javac\u547C\u51FA\u3057\u306B\u4F7F\u7528\u3059\u308B\u30A8\u30F3\u30B3\u30FC\u30C7\u30A3\u30F3\u30B0\u3092\u6307\u5B9A\u3057\u307E\u3059\n\ \ \ \ -episode : \u30B3\u30F3\u30D1\u30A4\u30EB\u3054\u3068\u306B\u30A8\u30D4\u30BD\u30FC\u30C9\u30FB\u30D5\u30A1\u30A4\u30EB\u3092\u751F\u6210\u3057\u307E\u3059\n\ \ \ \ -version : \u30D0\u30FC\u30B8\u30E7\u30F3\u60C5\u5831\u3092\u8868\u793A\u3057\u307E\u3059\n\ \ \ \ -fullversion : \u30D5\u30EB\u30FB\u30D0\u30FC\u30B8\u30E7\u30F3\u60C5\u5831\u3092\u8868\u793A\u3057\u307E\u3059\n\ \ \ \ -help : \u3053\u306E\u4F7F\u7528\u4F8B\u30E1\u30C3\u30BB\u30FC\u30B8\u3092\u8868\u793A\u3057\u307E\u3059 diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_ko.properties b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_ko.properties index b89650bd0ff..cfc4364d80a 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_ko.properties +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_ko.properties @@ -27,8 +27,8 @@ UNEXPECTED_NGCC_TOKEN = \uC608\uC0C1\uCE58 \uC54A\uC740 {0}\uC774(\uAC00) {1}\uD BASEDIR_DOESNT_EXIST = \uC874\uC7AC\uD558\uC9C0 \uC54A\uB294 \uB514\uB809\uD1A0\uB9AC: {0} -VERSION = schemagen 2.2.8-b01 +VERSION = schemagen 2.2.8-b20130806.1801 -FULLVERSION = schemagen \uC815\uC2DD \uBC84\uC804 "2.2.8-b01" +FULLVERSION = schemagen \uC815\uC2DD \uBC84\uC804 "2.2.8-b20130806.1801" USAGE = \uC0AC\uC6A9\uBC95: schemagen [-options ...] \n\uC635\uC158: \n\ \ \ \ -d : \uD504\uB85C\uC138\uC11C \uBC0F javac\uC5D0\uC11C \uC0DD\uC131\uD55C \uD074\uB798\uC2A4 \uD30C\uC77C\uC744 \uBC30\uCE58\uD560 \uC704\uCE58\uB97C \uC9C0\uC815\uD569\uB2C8\uB2E4.\n\ \ \ \ -cp : \uC0AC\uC6A9\uC790\uAC00 \uC9C0\uC815\uD55C \uD30C\uC77C\uC744 \uCC3E\uC744 \uC704\uCE58\uB97C \uC9C0\uC815\uD569\uB2C8\uB2E4.\n\ \ \ \ -classpath : \uC0AC\uC6A9\uC790\uAC00 \uC9C0\uC815\uD55C \uD30C\uC77C\uC744 \uCC3E\uC744 \uC704\uCE58\uB97C \uC9C0\uC815\uD569\uB2C8\uB2E4.\n\ \ \ \ -encoding : \uC8FC\uC11D \uCC98\uB9AC/javac \uD638\uCD9C\uC5D0 \uC0AC\uC6A9\uD560 \uC778\uCF54\uB529\uC744 \uC9C0\uC815\uD569\uB2C8\uB2E4. \n\ \ \ \ -episode : \uBCC4\uB3C4 \uCEF4\uD30C\uC77C\uC744 \uC704\uD574 episode \uD30C\uC77C\uC744 \uC0DD\uC131\uD569\uB2C8\uB2E4.\n\ \ \ \ -version : \uBC84\uC804 \uC815\uBCF4\uB97C \uD45C\uC2DC\uD569\uB2C8\uB2E4.\n\ \ \ \ -fullversion : \uC815\uC2DD \uBC84\uC804 \uC815\uBCF4\uB97C \uD45C\uC2DC\uD569\uB2C8\uB2E4.\n\ \ \ \ -help : \uC774 \uC0AC\uC6A9\uBC95 \uBA54\uC2DC\uC9C0\uB97C \uD45C\uC2DC\uD569\uB2C8\uB2E4. diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_pt_BR.properties b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_pt_BR.properties index fc9f8afbc11..318ab2c54f2 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_pt_BR.properties +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_pt_BR.properties @@ -27,8 +27,8 @@ UNEXPECTED_NGCC_TOKEN = {0} inesperado aparece na linha {1} coluna {2} BASEDIR_DOESNT_EXIST = Diret\u00F3rio n\u00E3o existente: {0} -VERSION = gera\u00E7\u00E3o do esquema 2.2.8-b01 +VERSION = gera\u00E7\u00E3o do esquema 2.2.8-b20130806.1801 -FULLVERSION = vers\u00E3o completa da gera\u00E7\u00E3o do esquema "2.2.8-b01" +FULLVERSION = vers\u00E3o completa da gera\u00E7\u00E3o do esquema "2.2.8-b20130806.1801" USAGE = Uso: gera\u00E7\u00E3o do esquema [-options ...] \nOp\u00E7\u00F5es: \n\\ \\ \\ \\ -d : especificar onde colocar o processador e os arquivos da classe gerados por javac\n\\ \\ \\ \\ -cp : especificar onde localizar arquivos especificados pelo usu\u00E1rio\n\\ \\ \\ \\ -classpath : especificar onde localizar os arquivos especificados pelo usu\u00E1rio\n\\ \\ \\ \\ -encoding : especificar codifica\u00E7\u00E3o a ser usada para processamento de anota\u00E7\u00E3o/chamada javac \n\\ \\ \\ \\ -episode : gerar arquivo do epis\u00F3dio para compila\u00E7\u00E3o separada\n\\ \\ \\ \\ -version : exibir informa\u00E7\u00F5es da vers\u00E3o\n\\ \\ \\ \\ -fullversion : exibir informa\u00E7\u00F5es da vers\u00E3o completa\n\\ \\ \\ \\ -help : exibir esta mensagem de uso diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_zh_CN.properties b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_zh_CN.properties index 4493b23dd18..87636c0d3cd 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_zh_CN.properties +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_zh_CN.properties @@ -27,8 +27,8 @@ UNEXPECTED_NGCC_TOKEN = \u5728\u7B2C {1} \u884C, \u7B2C {2} \u5217\u51FA\u73B0\u BASEDIR_DOESNT_EXIST = \u4E0D\u5B58\u5728\u7684\u76EE\u5F55: {0} -VERSION = schemagen 2.2.8-b01 +VERSION = schemagen 2.2.8-b20130806.1801 -FULLVERSION = schemagen \u5B8C\u6574\u7248\u672C "2.2.8-b01" +FULLVERSION = schemagen \u5B8C\u6574\u7248\u672C "2.2.8-b20130806.1801" USAGE = \u7528\u6CD5: schemagen [-options ...] \n\u9009\u9879: \n\ \ \ \ -d : \u6307\u5B9A\u653E\u7F6E\u5904\u7406\u7A0B\u5E8F\u548C javac \u751F\u6210\u7684\u7C7B\u6587\u4EF6\u7684\u4F4D\u7F6E\n\ \ \ \ -cp : \u6307\u5B9A\u67E5\u627E\u7528\u6237\u6307\u5B9A\u6587\u4EF6\u7684\u4F4D\u7F6E\n\ \ \ \ -classpath : \u6307\u5B9A\u67E5\u627E\u7528\u6237\u6307\u5B9A\u6587\u4EF6\u7684\u4F4D\u7F6E\n\ \ \ \ -encoding : \u6307\u5B9A\u7528\u4E8E\u6CE8\u91CA\u5904\u7406/javac \u8C03\u7528\u7684\u7F16\u7801\n\ \ \ \ -episode : \u751F\u6210\u7247\u6BB5\u6587\u4EF6\u4EE5\u4F9B\u5355\u72EC\u7F16\u8BD1\n\ \ \ \ -version : \u663E\u793A\u7248\u672C\u4FE1\u606F\n\ \ \ \ -fullversion : \u663E\u793A\u5B8C\u6574\u7684\u7248\u672C\u4FE1\u606F\n\ \ \ \ -help : \u663E\u793A\u6B64\u7528\u6CD5\u6D88\u606F diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_zh_TW.properties b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_zh_TW.properties index 45748f11a28..d828ed5f8e4 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_zh_TW.properties +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/MessageBundle_zh_TW.properties @@ -27,8 +27,8 @@ UNEXPECTED_NGCC_TOKEN = \u672A\u9810\u671F\u7684 {0} \u986F\u793A\u65BC\u884C {1 BASEDIR_DOESNT_EXIST = \u4E0D\u5B58\u5728\u7684\u76EE\u9304: {0} -VERSION = schemagen 2.2.8-b01 +VERSION = schemagen 2.2.8-b20130806.1801 -FULLVERSION = schemagen \u5B8C\u6574\u7248\u672C "2.2.8-b01" +FULLVERSION = schemagen \u5B8C\u6574\u7248\u672C "2.2.8-b20130806.1801" USAGE = \u7528\u6CD5: schemagen [-options ...] \n\u9078\u9805: \n\\ \\ \\ \\ -d : \u6307\u5B9A\u8655\u7406\u5668\u4EE5\u53CA javac \u7522\u751F\u7684\u985E\u5225\u6A94\u6848\u653E\u7F6E\u4F4D\u7F6E\n\\ \\ \\ \\ -cp : \u6307\u5B9A\u8981\u5C0B\u627E\u4F7F\u7528\u8005\u6307\u5B9A\u6A94\u6848\u7684\u4F4D\u7F6E\n\\ \\ \\ \\ -classpath : \u6307\u5B9A\u8981\u5C0B\u627E\u4F7F\u7528\u8005\u6307\u5B9A\u6A94\u6848\u7684\u4F4D\u7F6E\n\\ \\ \\ \\ -encoding : \u6307\u5B9A\u8981\u7528\u65BC\u8A3B\u89E3\u8655\u7406/javac \u547C\u53EB\u7684\u7DE8\u78BC \n\\ \\ \\ \\ -episode : \u7522\u751F\u7368\u7ACB\u7DE8\u8B6F\u7684\u4E8B\u4EF6 (episode) \u6A94\u6848\n\\ \\ \\ \\ -version : \u986F\u793A\u7248\u672C\u8CC7\u8A0A\n\\ \\ \\ \\ -fullversion : \u986F\u793A\u5B8C\u6574\u7248\u672C\u8CC7\u8A0A\n\\ \\ \\ \\ -help : \u986F\u793A\u6B64\u7528\u6CD5\u8A0A\u606F diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/gen/config/AttributesImpl.java b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/gen/config/AttributesImpl.java index be038f6a6d0..6ad38ce17b9 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/gen/config/AttributesImpl.java +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/gen/config/AttributesImpl.java @@ -64,6 +64,9 @@ import org.xml.sax.Attributes; * AttributeList} interface, it also includes a much more efficient * implementation using a single array rather than a set of Vectors.

* + *

+ * Auto-generated, do not edit. + *

* @since SAX 2.0 * @author David Megginson, * sax@megginson.com diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/gen/config/Classes.java b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/gen/config/Classes.java index 60968c00c56..bbd1ba07b0e 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/gen/config/Classes.java +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/gen/config/Classes.java @@ -33,7 +33,11 @@ import com.sun.tools.internal.jxc.NGCCRuntimeEx; import java.util.List; import java.util.ArrayList; - +/** + *

+ * Auto-generated, do not edit. + *

+ */ public class Classes extends NGCCHandler { private String __text; private String exclude_content; @@ -78,17 +82,11 @@ public class Classes extends NGCCHandler { $localName = $__local; $qname = $__qname; switch($_ngcc_current_state) { - case 4: + case 12: { - $_ngcc_current_state = 3; - $runtime.sendEnterElement(super._cookie, $__uri, $__local, $__qname, $attrs); - } - break; - case 11: - { - if(($__uri.equals("") && $__local.equals("includes"))) { + if(($__uri.equals("") && $__local.equals("classes"))) { $runtime.onEnterElementConsumed($__uri, $__local, $__qname, $attrs); - $_ngcc_current_state = 10; + $_ngcc_current_state = 11; } else { unexpectedEnterElement($__qname); @@ -107,22 +105,28 @@ public class Classes extends NGCCHandler { } } break; - case 0: + case 4: { - revertToParentFromEnterElement(this, super._cookie, $__uri, $__local, $__qname, $attrs); + $_ngcc_current_state = 3; + $runtime.sendEnterElement(super._cookie, $__uri, $__local, $__qname, $attrs); } break; - case 12: + case 11: { - if(($__uri.equals("") && $__local.equals("classes"))) { + if(($__uri.equals("") && $__local.equals("includes"))) { $runtime.onEnterElementConsumed($__uri, $__local, $__qname, $attrs); - $_ngcc_current_state = 11; + $_ngcc_current_state = 10; } else { unexpectedEnterElement($__qname); } } break; + case 0: + { + revertToParentFromEnterElement(this, super._cookie, $__uri, $__local, $__qname, $attrs); + } + break; default: { unexpectedEnterElement($__qname); @@ -137,23 +141,18 @@ public class Classes extends NGCCHandler { $localName = $__local; $qname = $__qname; switch($_ngcc_current_state) { + case 2: + { + $_ngcc_current_state = 1; + $runtime.sendLeaveElement(super._cookie, $__uri, $__local, $__qname); + } + break; case 4: { $_ngcc_current_state = 3; $runtime.sendLeaveElement(super._cookie, $__uri, $__local, $__qname); } break; - case 3: - { - if(($__uri.equals("") && $__local.equals("excludes"))) { - $runtime.onLeaveElementConsumed($__uri, $__local, $__qname); - $_ngcc_current_state = 1; - } - else { - unexpectedLeaveElement($__qname); - } - } - break; case 1: { if(($__uri.equals("") && $__local.equals("classes"))) { @@ -165,6 +164,22 @@ public class Classes extends NGCCHandler { } } break; + case 3: + { + if(($__uri.equals("") && $__local.equals("excludes"))) { + $runtime.onLeaveElementConsumed($__uri, $__local, $__qname); + $_ngcc_current_state = 1; + } + else { + unexpectedLeaveElement($__qname); + } + } + break; + case 0: + { + revertToParentFromLeaveElement(this, super._cookie, $__uri, $__local, $__qname); + } + break; case 8: { if(($__uri.equals("") && $__local.equals("includes"))) { @@ -176,17 +191,6 @@ public class Classes extends NGCCHandler { } } break; - case 2: - { - $_ngcc_current_state = 1; - $runtime.sendLeaveElement(super._cookie, $__uri, $__local, $__qname); - } - break; - case 0: - { - revertToParentFromLeaveElement(this, super._cookie, $__uri, $__local, $__qname); - } - break; default: { unexpectedLeaveElement($__qname); @@ -201,18 +205,18 @@ public class Classes extends NGCCHandler { $localName = $__local; $qname = $__qname; switch($_ngcc_current_state) { - case 4: - { - $_ngcc_current_state = 3; - $runtime.sendEnterAttribute(super._cookie, $__uri, $__local, $__qname); - } - break; case 2: { $_ngcc_current_state = 1; $runtime.sendEnterAttribute(super._cookie, $__uri, $__local, $__qname); } break; + case 4: + { + $_ngcc_current_state = 3; + $runtime.sendEnterAttribute(super._cookie, $__uri, $__local, $__qname); + } + break; case 0: { revertToParentFromEnterAttribute(this, super._cookie, $__uri, $__local, $__qname); @@ -232,18 +236,18 @@ public class Classes extends NGCCHandler { $localName = $__local; $qname = $__qname; switch($_ngcc_current_state) { - case 4: - { - $_ngcc_current_state = 3; - $runtime.sendLeaveAttribute(super._cookie, $__uri, $__local, $__qname); - } - break; case 2: { $_ngcc_current_state = 1; $runtime.sendLeaveAttribute(super._cookie, $__uri, $__local, $__qname); } break; + case 4: + { + $_ngcc_current_state = 3; + $runtime.sendLeaveAttribute(super._cookie, $__uri, $__local, $__qname); + } + break; case 0: { revertToParentFromLeaveAttribute(this, super._cookie, $__uri, $__local, $__qname); @@ -260,6 +264,12 @@ public class Classes extends NGCCHandler { public void text(String $value) throws SAXException { int $ai; switch($_ngcc_current_state) { + case 2: + { + $_ngcc_current_state = 1; + $runtime.sendText(super._cookie, $value); + } + break; case 4: { exclude_content = $value; @@ -267,20 +277,6 @@ public class Classes extends NGCCHandler { action0(); } break; - case 3: - { - exclude_content = $value; - $_ngcc_current_state = 3; - action0(); - } - break; - case 9: - { - include_content = $value; - $_ngcc_current_state = 8; - action2(); - } - break; case 10: { __text = $value; @@ -288,6 +284,13 @@ public class Classes extends NGCCHandler { action3(); } break; + case 3: + { + exclude_content = $value; + $_ngcc_current_state = 3; + action0(); + } + break; case 6: { __text = $value; @@ -295,22 +298,23 @@ public class Classes extends NGCCHandler { action1(); } break; - case 8: + case 0: + { + revertToParentFromText(this, super._cookie, $value); + } + break; + case 9: { include_content = $value; $_ngcc_current_state = 8; action2(); } break; - case 2: + case 8: { - $_ngcc_current_state = 1; - $runtime.sendText(super._cookie, $value); - } - break; - case 0: - { - revertToParentFromText(this, super._cookie, $value); + include_content = $value; + $_ngcc_current_state = 8; + action2(); } break; } diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/gen/config/Config.java b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/gen/config/Config.java index f806a817416..60aef42c838 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/gen/config/Config.java +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/gen/config/Config.java @@ -36,7 +36,11 @@ import java.util.List; import java.util.ArrayList; import java.io.File; - +/** + *

+ * Auto-generated, do not edit. + *

+ */ public class Config extends NGCCHandler { private String bd; private Schema _schema; @@ -74,15 +78,19 @@ public class Config extends NGCCHandler { $localName = $__local; $qname = $__qname; switch($_ngcc_current_state) { - case 2: + case 0: + { + revertToParentFromEnterElement(this, super._cookie, $__uri, $__local, $__qname, $attrs); + } + break; + case 1: { if(($__uri.equals("") && $__local.equals("schema"))) { - NGCCHandler h = new Schema(this, super._source, $runtime, 16, baseDir); + NGCCHandler h = new Schema(this, super._source, $runtime, 19, baseDir); spawnChildFromEnterElement(h, $__uri, $__local, $__qname, $attrs); } else { - $_ngcc_current_state = 1; - $runtime.sendEnterElement(super._cookie, $__uri, $__local, $__qname, $attrs); + unexpectedEnterElement($__qname); } } break; @@ -100,7 +108,7 @@ public class Config extends NGCCHandler { case 4: { if(($__uri.equals("") && $__local.equals("classes"))) { - NGCCHandler h = new Classes(this, super._source, $runtime, 18); + NGCCHandler h = new Classes(this, super._source, $runtime, 22); spawnChildFromEnterElement(h, $__uri, $__local, $__qname, $attrs); } else { @@ -108,19 +116,15 @@ public class Config extends NGCCHandler { } } break; - case 0: - { - revertToParentFromEnterElement(this, super._cookie, $__uri, $__local, $__qname, $attrs); - } - break; - case 1: + case 2: { if(($__uri.equals("") && $__local.equals("schema"))) { - NGCCHandler h = new Schema(this, super._source, $runtime, 15, baseDir); + NGCCHandler h = new Schema(this, super._source, $runtime, 20, baseDir); spawnChildFromEnterElement(h, $__uri, $__local, $__qname, $attrs); } else { - unexpectedEnterElement($__qname); + $_ngcc_current_state = 1; + $runtime.sendEnterElement(super._cookie, $__uri, $__local, $__qname, $attrs); } } break; @@ -149,12 +153,6 @@ public class Config extends NGCCHandler { $localName = $__local; $qname = $__qname; switch($_ngcc_current_state) { - case 2: - { - $_ngcc_current_state = 1; - $runtime.sendLeaveElement(super._cookie, $__uri, $__local, $__qname); - } - break; case 0: { revertToParentFromLeaveElement(this, super._cookie, $__uri, $__local, $__qname); @@ -171,6 +169,12 @@ public class Config extends NGCCHandler { } } break; + case 2: + { + $_ngcc_current_state = 1; + $runtime.sendLeaveElement(super._cookie, $__uri, $__local, $__qname); + } + break; case 7: { if(($ai = $runtime.getAttributeIndex("","baseDir"))>=0) { @@ -196,17 +200,17 @@ public class Config extends NGCCHandler { $localName = $__local; $qname = $__qname; switch($_ngcc_current_state) { + case 0: + { + revertToParentFromEnterAttribute(this, super._cookie, $__uri, $__local, $__qname); + } + break; case 2: { $_ngcc_current_state = 1; $runtime.sendEnterAttribute(super._cookie, $__uri, $__local, $__qname); } break; - case 0: - { - revertToParentFromEnterAttribute(this, super._cookie, $__uri, $__local, $__qname); - } - break; case 7: { if(($__uri.equals("") && $__local.equals("baseDir"))) { @@ -231,10 +235,9 @@ public class Config extends NGCCHandler { $localName = $__local; $qname = $__qname; switch($_ngcc_current_state) { - case 2: + case 0: { - $_ngcc_current_state = 1; - $runtime.sendLeaveAttribute(super._cookie, $__uri, $__local, $__qname); + revertToParentFromLeaveAttribute(this, super._cookie, $__uri, $__local, $__qname); } break; case 5: @@ -247,9 +250,10 @@ public class Config extends NGCCHandler { } } break; - case 0: + case 2: { - revertToParentFromLeaveAttribute(this, super._cookie, $__uri, $__local, $__qname); + $_ngcc_current_state = 1; + $runtime.sendLeaveAttribute(super._cookie, $__uri, $__local, $__qname); } break; default: @@ -263,10 +267,9 @@ public class Config extends NGCCHandler { public void text(String $value) throws SAXException { int $ai; switch($_ngcc_current_state) { - case 2: + case 0: { - $_ngcc_current_state = 1; - $runtime.sendText(super._cookie, $value); + revertToParentFromText(this, super._cookie, $value); } break; case 6: @@ -276,9 +279,10 @@ public class Config extends NGCCHandler { action1(); } break; - case 0: + case 2: { - revertToParentFromText(this, super._cookie, $value); + $_ngcc_current_state = 1; + $runtime.sendText(super._cookie, $value); } break; case 7: @@ -294,20 +298,20 @@ public class Config extends NGCCHandler { public void onChildCompleted(Object result, int cookie, boolean needAttCheck)throws SAXException { switch(cookie) { - case 16: + case 19: { this._schema = ((Schema)result); action0(); $_ngcc_current_state = 1; } break; - case 18: + case 22: { this.classes = ((Classes)result); $_ngcc_current_state = 2; } break; - case 15: + case 20: { this._schema = ((Schema)result); action0(); diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/gen/config/NGCCEventReceiver.java b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/gen/config/NGCCEventReceiver.java index 15fbe303731..ee80bdf8a10 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/gen/config/NGCCEventReceiver.java +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/gen/config/NGCCEventReceiver.java @@ -29,7 +29,9 @@ import org.xml.sax.Attributes; import org.xml.sax.SAXException; /** - * + *

+ * Auto-generated, do not edit. + *

* * @author Kohsuke Kawaguchi (kk@kohsuke.org) */ diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/gen/config/NGCCEventSource.java b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/gen/config/NGCCEventSource.java index b90624a9648..f1ffb72d635 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/gen/config/NGCCEventSource.java +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/gen/config/NGCCEventSource.java @@ -29,7 +29,9 @@ import org.xml.sax.Attributes; import org.xml.sax.SAXException; /** - * + *

+ * Auto-generated, do not edit. + *

* * @author Kohsuke Kawaguchi (kk@kohsuke.org) */ diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/gen/config/NGCCHandler.java b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/gen/config/NGCCHandler.java index 8fe7a1a84f0..fe4d5e9bcfd 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/gen/config/NGCCHandler.java +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/gen/config/NGCCHandler.java @@ -29,7 +29,9 @@ import org.xml.sax.Attributes; import org.xml.sax.SAXException; /** - * + *

+ * Auto-generated, do not edit. + *

* * @version $Id: NGCCHandler.java,v 1.9 2002/09/29 02:55:48 okajima Exp $ * @author Kohsuke Kawaguchi (kk@kohsuke.org) diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/gen/config/NGCCInterleaveFilter.java b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/gen/config/NGCCInterleaveFilter.java index ddb023451ae..702b0bdbedf 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/gen/config/NGCCInterleaveFilter.java +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/gen/config/NGCCInterleaveFilter.java @@ -32,6 +32,9 @@ import org.xml.sax.SAXException; * Dispatches incoming events into sub handlers appropriately * so that the interleaving semantics will be correctly realized. * + *

+ * Auto-generated, do not edit. + *

* @author Kohsuke Kawaguchi (kk@kohsuke.org) */ public abstract class NGCCInterleaveFilter implements NGCCEventSource, NGCCEventReceiver { diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/gen/config/NGCCRuntime.java b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/gen/config/NGCCRuntime.java index 74837e33070..a9184d6f84b 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/gen/config/NGCCRuntime.java +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/gen/config/NGCCRuntime.java @@ -50,7 +50,9 @@ import org.xml.sax.SAXParseException; *
  • manage mapping between namespace URIs and prefixes. * *
  • TODO: provide support for interleaving. - * + *

    + * Auto-generated, do not edit. + *

    * @version $Id: NGCCRuntime.java,v 1.15 2002/09/29 02:55:48 okajima Exp $ * @author Kohsuke Kawaguchi (kk@kohsuke.org) */ diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/gen/config/Schema.java b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/gen/config/Schema.java index 18de25f4a88..f238314c0b0 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/gen/config/Schema.java +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/jxc/gen/config/Schema.java @@ -32,7 +32,11 @@ import com.sun.tools.internal.jxc.NGCCRuntimeEx; import java.io.File; - +/** + *

    + * Auto-generated, do not edit. + *

    + */ public class Schema extends NGCCHandler { private File baseDir; private String loc; @@ -72,18 +76,6 @@ public class Schema extends NGCCHandler { revertToParentFromEnterElement(this, super._cookie, $__uri, $__local, $__qname, $attrs); } break; - case 6: - { - if(($ai = $runtime.getAttributeIndex("","namespace"))>=0) { - $runtime.consumeAttribute($ai); - $runtime.sendEnterElement(super._cookie, $__uri, $__local, $__qname, $attrs); - } - else { - $_ngcc_current_state = 2; - $runtime.sendEnterElement(super._cookie, $__uri, $__local, $__qname, $attrs); - } - } - break; case 2: { if(($ai = $runtime.getAttributeIndex("","location"))>=0) { @@ -96,6 +88,18 @@ public class Schema extends NGCCHandler { } } break; + case 6: + { + if(($ai = $runtime.getAttributeIndex("","namespace"))>=0) { + $runtime.consumeAttribute($ai); + $runtime.sendEnterElement(super._cookie, $__uri, $__local, $__qname, $attrs); + } + else { + $_ngcc_current_state = 2; + $runtime.sendEnterElement(super._cookie, $__uri, $__local, $__qname, $attrs); + } + } + break; case 10: { if(($__uri.equals("") && $__local.equals("schema"))) { @@ -121,23 +125,22 @@ public class Schema extends NGCCHandler { $localName = $__local; $qname = $__qname; switch($_ngcc_current_state) { + case 1: + { + if(($__uri.equals("") && $__local.equals("schema"))) { + $runtime.onLeaveElementConsumed($__uri, $__local, $__qname); + $_ngcc_current_state = 0; + } + else { + unexpectedLeaveElement($__qname); + } + } + break; case 0: { revertToParentFromLeaveElement(this, super._cookie, $__uri, $__local, $__qname); } break; - case 6: - { - if(($ai = $runtime.getAttributeIndex("","namespace"))>=0) { - $runtime.consumeAttribute($ai); - $runtime.sendLeaveElement(super._cookie, $__uri, $__local, $__qname); - } - else { - $_ngcc_current_state = 2; - $runtime.sendLeaveElement(super._cookie, $__uri, $__local, $__qname); - } - } - break; case 2: { if(($ai = $runtime.getAttributeIndex("","location"))>=0) { @@ -150,14 +153,15 @@ public class Schema extends NGCCHandler { } } break; - case 1: + case 6: { - if(($__uri.equals("") && $__local.equals("schema"))) { - $runtime.onLeaveElementConsumed($__uri, $__local, $__qname); - $_ngcc_current_state = 0; + if(($ai = $runtime.getAttributeIndex("","namespace"))>=0) { + $runtime.consumeAttribute($ai); + $runtime.sendLeaveElement(super._cookie, $__uri, $__local, $__qname); } else { - unexpectedLeaveElement($__qname); + $_ngcc_current_state = 2; + $runtime.sendLeaveElement(super._cookie, $__uri, $__local, $__qname); } } break; @@ -180,17 +184,6 @@ public class Schema extends NGCCHandler { revertToParentFromEnterAttribute(this, super._cookie, $__uri, $__local, $__qname); } break; - case 6: - { - if(($__uri.equals("") && $__local.equals("namespace"))) { - $_ngcc_current_state = 8; - } - else { - $_ngcc_current_state = 2; - $runtime.sendEnterAttribute(super._cookie, $__uri, $__local, $__qname); - } - } - break; case 2: { if(($__uri.equals("") && $__local.equals("location"))) { @@ -202,6 +195,17 @@ public class Schema extends NGCCHandler { } } break; + case 6: + { + if(($__uri.equals("") && $__local.equals("namespace"))) { + $_ngcc_current_state = 8; + } + else { + $_ngcc_current_state = 2; + $runtime.sendEnterAttribute(super._cookie, $__uri, $__local, $__qname); + } + } + break; default: { unexpectedEnterAttribute($__qname); @@ -221,22 +225,6 @@ public class Schema extends NGCCHandler { revertToParentFromLeaveAttribute(this, super._cookie, $__uri, $__local, $__qname); } break; - case 7: - { - if(($__uri.equals("") && $__local.equals("namespace"))) { - $_ngcc_current_state = 2; - } - else { - unexpectedLeaveAttribute($__qname); - } - } - break; - case 6: - { - $_ngcc_current_state = 2; - $runtime.sendLeaveAttribute(super._cookie, $__uri, $__local, $__qname); - } - break; case 3: { if(($__uri.equals("") && $__local.equals("location"))) { @@ -247,12 +235,28 @@ public class Schema extends NGCCHandler { } } break; + case 7: + { + if(($__uri.equals("") && $__local.equals("namespace"))) { + $_ngcc_current_state = 2; + } + else { + unexpectedLeaveAttribute($__qname); + } + } + break; case 2: { $_ngcc_current_state = 1; $runtime.sendLeaveAttribute(super._cookie, $__uri, $__local, $__qname); } break; + case 6: + { + $_ngcc_current_state = 2; + $runtime.sendLeaveAttribute(super._cookie, $__uri, $__local, $__qname); + } + break; default: { unexpectedLeaveAttribute($__qname); @@ -270,23 +274,6 @@ public class Schema extends NGCCHandler { $_ngcc_current_state = 7; } break; - case 0: - { - revertToParentFromText(this, super._cookie, $value); - } - break; - case 6: - { - if(($ai = $runtime.getAttributeIndex("","namespace"))>=0) { - $runtime.consumeAttribute($ai); - $runtime.sendText(super._cookie, $value); - } - else { - $_ngcc_current_state = 2; - $runtime.sendText(super._cookie, $value); - } - } - break; case 4: { loc = $value; @@ -294,6 +281,11 @@ public class Schema extends NGCCHandler { action0(); } break; + case 0: + { + revertToParentFromText(this, super._cookie, $value); + } + break; case 2: { if(($ai = $runtime.getAttributeIndex("","location"))>=0) { @@ -306,6 +298,18 @@ public class Schema extends NGCCHandler { } } break; + case 6: + { + if(($ai = $runtime.getAttributeIndex("","namespace"))>=0) { + $runtime.consumeAttribute($ai); + $runtime.sendText(super._cookie, $value); + } + else { + $_ngcc_current_state = 2; + $runtime.sendText(super._cookie, $value); + } + } + break; } } diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/ws/version.properties b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/ws/version.properties index 5d7ed24b883..9862bdc6bb2 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/ws/version.properties +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/ws/version.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ # questions. # -build-id=2.2.9-b14027 -build-version=JAX-WS RI 2.2.9-b14027 +build-id=2.2.9-b14140 +build-version=JAX-WS RI 2.2.9-b14140 major-version=2.2.9 -svn-revision=14027 +svn-revision=14140 diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle.properties b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle.properties index 4e64ca0c717..bf21c1ee0f9 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle.properties +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle.properties @@ -171,23 +171,23 @@ Driver.CompilingSchema = \ Driver.FailedToGenerateCode = \ Failed to produce code. -# DO NOT localize the 2.2.8-b01 string - it is a token for an ant +# DO NOT localize the 2.2.8-b20130806.1801 string - it is a token for an ant Driver.FilePrologComment = \ - This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b01 \n\ + This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b20130806.1801 \n\ See http://java.sun.com/xml/jaxb \n\ Any modifications to this file will be lost upon recompilation of the source schema. \n\ Generated on: {0} \n Driver.Version = \ - xjc 2.2.8-b01 + xjc 2.2.8-b20130806.1801 Driver.FullVersion = \ - xjc full version "2.2.8-b01-b28" + xjc full version "2.2.8-b20130806.1801" -Driver.BuildID = 2.2.8-b01 +Driver.BuildID = 2.2.8-b20130806.1801 # for JDK integration - include version in source zip -jaxb.jdk.version=2.2.8-b01 +jaxb.jdk.version=@@JAXB_JDK_VERSION@@ # see java.text.SimpleDateFormat for format syntax # DO NOT LOCALIZE, Format should not be changed, English locale is used to transform this string into a real date. diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_de.properties b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_de.properties index 3fee895ed99..560d6b66a90 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_de.properties +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_de.properties @@ -96,17 +96,17 @@ Driver.CompilingSchema = Ein Schema wird kompiliert ... Driver.FailedToGenerateCode = Code konnte nicht erzeugt werden. -# DO NOT localize the 2.2.8-b01 string - it is a token for an ant -Driver.FilePrologComment = Diese Datei wurde mit der JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b01 generiert \nSiehe http://java.sun.com/xml/jaxb \n\u00c4nderungen an dieser Datei gehen bei einer Neukompilierung des Quellschemas verloren. \nGeneriert: {0} \n +# DO NOT localize the 2.2.8-b20130806.1801 string - it is a token for an ant +Driver.FilePrologComment = Diese Datei wurde mit der JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b20130806.1801 generiert \nSiehe http://java.sun.com/xml/jaxb \n\u00c4nderungen an dieser Datei gehen bei einer Neukompilierung des Quellschemas verloren. \nGeneriert: {0} \n -Driver.Version = xjc 2.2.8-b01 +Driver.Version = xjc 2.2.8-b20130806.1801 -Driver.FullVersion = xjc vollst\u00e4ndige Version "2.2.8-b01-b28" +Driver.FullVersion = xjc vollst\u00E4ndige Version "2.2.8-b20130806.1801" -Driver.BuildID = 2.2.8-b01 +Driver.BuildID = 2.2.8-b20130806.1801 # for JDK integration - include version in source zip -jaxb.jdk.version=2.2.8-b01 +jaxb.jdk.version=@@JAXB_JDK_VERSION@@ # see java.text.SimpleDateFormat for format syntax # DO NOT LOCALIZE, Format should not be changed, English locale is used to transform this string into a real date. diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_es.properties b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_es.properties index ee3e09df36a..47a66fc719e 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_es.properties +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_es.properties @@ -96,17 +96,17 @@ Driver.CompilingSchema = Compilando un esquema... Driver.FailedToGenerateCode = Fallo al producir c\u00f3digo. -# DO NOT localize the 2.2.8-b01 string - it is a token for an ant -Driver.FilePrologComment = Este archivo ha sido generado por la arquitectura JavaTM para la implantaci\u00f3n de la referencia de enlace (JAXB) XML v2.2.8-b01 \nVisite http://java.sun.com/xml/jaxb \nTodas las modificaciones realizadas en este archivo se perder\u00e1n si se vuelve a compilar el esquema de origen. \nGenerado el: {0} \n +# DO NOT localize the 2.2.8-b20130806.1801 string - it is a token for an ant +Driver.FilePrologComment = Este archivo ha sido generado por la arquitectura JavaTM para la implantaci\u00f3n de la referencia de enlace (JAXB) XML v2.2.8-b20130806.1801 \nVisite http://java.sun.com/xml/jaxb \nTodas las modificaciones realizadas en este archivo se perder\u00e1n si se vuelve a compilar el esquema de origen. \nGenerado el: {0} \n -Driver.Version = xjc 2.2.8-b01 +Driver.Version = xjc 2.2.8-b20130806.1801 -Driver.FullVersion = versi\u00f3n completa de xjc "2.2.8-b01-b28" +Driver.FullVersion = versi\u00F3n completa de xjc "2.2.8-b20130806.1801" -Driver.BuildID = 2.2.8-b01 +Driver.BuildID = 2.2.8-b20130806.1801 # for JDK integration - include version in source zip -jaxb.jdk.version=2.2.8-b01 +jaxb.jdk.version=@@JAXB_JDK_VERSION@@ # see java.text.SimpleDateFormat for format syntax # DO NOT LOCALIZE, Format should not be changed, English locale is used to transform this string into a real date. diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_fr.properties b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_fr.properties index d5a8fbbacbf..a9dea414d78 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_fr.properties +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_fr.properties @@ -96,17 +96,17 @@ Driver.CompilingSchema = compilation d'un sch\u00e9ma... Driver.FailedToGenerateCode = Echec de la production du code. -# DO NOT localize the 2.2.8-b01 string - it is a token for an ant -Driver.FilePrologComment = Ce fichier a \u00e9t\u00e9 g\u00e9n\u00e9r\u00e9 par l''impl\u00e9mentation de r\u00e9f\u00e9rence JavaTM Architecture for XML Binding (JAXB), v2.2.8-b01 \nVoir http://java.sun.com/xml/jaxb \nToute modification apport\u00e9e \u00e0 ce fichier sera perdue lors de la recompilation du sch\u00e9ma source. \nG\u00e9n\u00e9r\u00e9 le : {0} \n +# DO NOT localize the 2.2.8-b20130806.1801 string - it is a token for an ant +Driver.FilePrologComment = Ce fichier a \u00e9t\u00e9 g\u00e9n\u00e9r\u00e9 par l''impl\u00e9mentation de r\u00e9f\u00e9rence JavaTM Architecture for XML Binding (JAXB), v2.2.8-b20130806.1801 \nVoir http://java.sun.com/xml/jaxb \nToute modification apport\u00e9e \u00e0 ce fichier sera perdue lors de la recompilation du sch\u00e9ma source. \nG\u00e9n\u00e9r\u00e9 le : {0} \n -Driver.Version = xjc 2.2.8-b01 +Driver.Version = xjc 2.2.8-b20130806.1801 -Driver.FullVersion = version compl\u00e8te xjc "2.2.8-b01-b28" +Driver.FullVersion = version compl\u00E8te xjc "2.2.8-b20130806.1801" -Driver.BuildID = 2.2.8-b01 +Driver.BuildID = 2.2.8-b20130806.1801 # for JDK integration - include version in source zip -jaxb.jdk.version=2.2.8-b01 +jaxb.jdk.version=@@JAXB_JDK_VERSION@@ # see java.text.SimpleDateFormat for format syntax # DO NOT LOCALIZE, Format should not be changed, English locale is used to transform this string into a real date. diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_it.properties b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_it.properties index 33441891015..b63eb553179 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_it.properties +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_it.properties @@ -96,17 +96,17 @@ Driver.CompilingSchema = compilazione di uno schema in corso... Driver.FailedToGenerateCode = Produzione del codice non riuscita. -# DO NOT localize the 2.2.8-b01 string - it is a token for an ant -Driver.FilePrologComment = Questo file \u00e8 stato generato dall''architettura JavaTM per XML Binding (JAXB) Reference Implementation, v2.2.8-b01 \nVedere http://java.sun.com/xml/jaxb \nQualsiasi modifica a questo file andr\u00e0 persa durante la ricompilazione dello schema di origine. \nGenerato il: {0} \n +# DO NOT localize the 2.2.8-b20130806.1801 string - it is a token for an ant +Driver.FilePrologComment = Questo file \u00e8 stato generato dall''architettura JavaTM per XML Binding (JAXB) Reference Implementation, v2.2.8-b20130806.1801 \nVedere http://java.sun.com/xml/jaxb \nQualsiasi modifica a questo file andr\u00e0 persa durante la ricompilazione dello schema di origine. \nGenerato il: {0} \n -Driver.Version = xjc 2.2.8-b01 +Driver.Version = xjc 2.2.8-b20130806.1801 -Driver.FullVersion = versione completa xjc "2.2.8-b01-b28" +Driver.FullVersion = versione completa xjc "2.2.8-b20130806.1801" -Driver.BuildID = 2.2.8-b01 +Driver.BuildID = 2.2.8-b20130806.1801 # for JDK integration - include version in source zip -jaxb.jdk.version=2.2.8-b01 +jaxb.jdk.version=@@JAXB_JDK_VERSION@@ # see java.text.SimpleDateFormat for format syntax # DO NOT LOCALIZE, Format should not be changed, English locale is used to transform this string into a real date. diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_ja.properties b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_ja.properties index edd5c648e7c..8dd5b8a84af 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_ja.properties +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_ja.properties @@ -96,17 +96,17 @@ Driver.CompilingSchema = \u30b9\u30ad\u30fc\u30de\u306e\u30b3\u30f3\u30d1\u30a4\ Driver.FailedToGenerateCode = \u30b3\u30fc\u30c9\u306e\u751f\u6210\u306b\u5931\u6557\u3057\u307e\u3057\u305f\u3002 -# DO NOT localize the 2.2.8-b01 string - it is a token for an ant -Driver.FilePrologComment = \u3053\u306e\u30d5\u30a1\u30a4\u30eb\u306f\u3001JavaTM Architecture for XML Binding(JAXB) Reference Implementation\u3001v2.2.8-b01\u306b\u3088\u3063\u3066\u751f\u6210\u3055\u308c\u307e\u3057\u305f \nhttp://java.sun.com/xml/jaxb\u3092\u53c2\u7167\u3057\u3066\u304f\u3060\u3055\u3044 \n\u30bd\u30fc\u30b9\u30fb\u30b9\u30ad\u30fc\u30de\u306e\u518d\u30b3\u30f3\u30d1\u30a4\u30eb\u6642\u306b\u3053\u306e\u30d5\u30a1\u30a4\u30eb\u306e\u5909\u66f4\u306f\u5931\u308f\u308c\u307e\u3059\u3002 \n\u751f\u6210\u65e5: {0} \n +# DO NOT localize the 2.2.8-b20130806.1801 string - it is a token for an ant +Driver.FilePrologComment = \u3053\u306e\u30d5\u30a1\u30a4\u30eb\u306f\u3001JavaTM Architecture for XML Binding(JAXB) Reference Implementation\u3001v2.2.8-b20130806.1801\u306b\u3088\u3063\u3066\u751f\u6210\u3055\u308c\u307e\u3057\u305f \nhttp://java.sun.com/xml/jaxb\u3092\u53c2\u7167\u3057\u3066\u304f\u3060\u3055\u3044 \n\u30bd\u30fc\u30b9\u30fb\u30b9\u30ad\u30fc\u30de\u306e\u518d\u30b3\u30f3\u30d1\u30a4\u30eb\u6642\u306b\u3053\u306e\u30d5\u30a1\u30a4\u30eb\u306e\u5909\u66f4\u306f\u5931\u308f\u308c\u307e\u3059\u3002 \n\u751f\u6210\u65e5: {0} \n -Driver.Version = xjc 2.2.8-b01 +Driver.Version = xjc 2.2.8-b20130806.1801 -Driver.FullVersion = xjc\u30d5\u30eb\u30fb\u30d0\u30fc\u30b8\u30e7\u30f3"2.2.8-b01-b28" +Driver.FullVersion = xjc\u30D5\u30EB\u30FB\u30D0\u30FC\u30B8\u30E7\u30F3"2.2.8-b20130806.1801" -Driver.BuildID = 2.2.8-b01 +Driver.BuildID = 2.2.8-b20130806.1801 # for JDK integration - include version in source zip -jaxb.jdk.version=2.2.8-b01 +jaxb.jdk.version=@@JAXB_JDK_VERSION@@ # see java.text.SimpleDateFormat for format syntax # DO NOT LOCALIZE, Format should not be changed, English locale is used to transform this string into a real date. diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_ko.properties b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_ko.properties index d493f5bd054..3d0f6b9f369 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_ko.properties +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_ko.properties @@ -96,17 +96,17 @@ Driver.CompilingSchema = \uc2a4\ud0a4\ub9c8\ub97c \ucef4\ud30c\uc77c\ud558\ub294 Driver.FailedToGenerateCode = \ucf54\ub4dc \uc0dd\uc131\uc744 \uc2e4\ud328\ud588\uc2b5\ub2c8\ub2e4. -# DO NOT localize the 2.2.8-b01 string - it is a token for an ant -Driver.FilePrologComment = \uc774 \ud30c\uc77c\uc740 JAXB(JavaTM Architecture for XML Binding) \ucc38\uc870 \uad6c\ud604 2.2.8-b01 \ubc84\uc804\uc744 \ud1b5\ud574 \uc0dd\uc131\ub418\uc5c8\uc2b5\ub2c8\ub2e4. \nhttp://java.sun.com/xml/jaxb\ub97c \ucc38\uc870\ud558\uc2ed\uc2dc\uc624. \n\uc774 \ud30c\uc77c\uc744 \uc218\uc815\ud558\uba74 \uc18c\uc2a4 \uc2a4\ud0a4\ub9c8\ub97c \uc7ac\ucef4\ud30c\uc77c\ud560 \ub54c \uc218\uc815 \uc0ac\ud56d\uc774 \uc190\uc2e4\ub429\ub2c8\ub2e4. \n\uc0dd\uc131 \ub0a0\uc9dc: {0} \n +# DO NOT localize the 2.2.8-b20130806.1801 string - it is a token for an ant +Driver.FilePrologComment = \uc774 \ud30c\uc77c\uc740 JAXB(JavaTM Architecture for XML Binding) \ucc38\uc870 \uad6c\ud604 2.2.8-b20130806.1801 \ubc84\uc804\uc744 \ud1b5\ud574 \uc0dd\uc131\ub418\uc5c8\uc2b5\ub2c8\ub2e4. \nhttp://java.sun.com/xml/jaxb\ub97c \ucc38\uc870\ud558\uc2ed\uc2dc\uc624. \n\uc774 \ud30c\uc77c\uc744 \uc218\uc815\ud558\uba74 \uc18c\uc2a4 \uc2a4\ud0a4\ub9c8\ub97c \uc7ac\ucef4\ud30c\uc77c\ud560 \ub54c \uc218\uc815 \uc0ac\ud56d\uc774 \uc190\uc2e4\ub429\ub2c8\ub2e4. \n\uc0dd\uc131 \ub0a0\uc9dc: {0} \n -Driver.Version = XJC 2.2.8-b01 +Driver.Version = XJC 2.2.8-b20130806.1801 -Driver.FullVersion = XJC \uc815\uc2dd \ubc84\uc804 "2.2.8-b01-b28" +Driver.FullVersion = XJC \uC815\uC2DD \uBC84\uC804 "2.2.8-b20130806.1801" -Driver.BuildID = 2.2.8-b01 +Driver.BuildID = 2.2.8-b20130806.1801 # for JDK integration - include version in source zip -jaxb.jdk.version=2.2.8-b01 +jaxb.jdk.version=@@JAXB_JDK_VERSION@@ # see java.text.SimpleDateFormat for format syntax # DO NOT LOCALIZE, Format should not be changed, English locale is used to transform this string into a real date. diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_pt_BR.properties b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_pt_BR.properties index 3ac7a0bf2c3..c7eb0286e2e 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_pt_BR.properties +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_pt_BR.properties @@ -96,17 +96,17 @@ Driver.CompilingSchema = compilando um esquema... Driver.FailedToGenerateCode = Falha ao produzir o c\u00f3digo. -# DO NOT localize the 2.2.8-b01 string - it is a token for an ant -Driver.FilePrologComment = Este arquivo foi gerado pela Arquitetura JavaTM para Implementa\u00e7\u00e3o de Refer\u00eancia (JAXB) de Bind XML, v2.2.8-b01 \nConsulte http://java.sun.com/xml/jaxb \nTodas as modifica\u00e7\u00f5es neste arquivo ser\u00e3o perdidas ap\u00f3s a recompila\u00e7\u00e3o do esquema de origem. \nGerado em: {0} \n +# DO NOT localize the 2.2.8-b20130806.1801 string - it is a token for an ant +Driver.FilePrologComment = Este arquivo foi gerado pela Arquitetura JavaTM para Implementa\u00e7\u00e3o de Refer\u00eancia (JAXB) de Bind XML, v2.2.8-b20130806.1801 \nConsulte http://java.sun.com/xml/jaxb \nTodas as modifica\u00e7\u00f5es neste arquivo ser\u00e3o perdidas ap\u00f3s a recompila\u00e7\u00e3o do esquema de origem. \nGerado em: {0} \n -Driver.Version = xjc 2.2.8-b01 +Driver.Version = xjc 2.2.8-b20130806.1801 -Driver.FullVersion = vers\u00e3o completa de xjc "2.2.8-b01-b28" +Driver.FullVersion = vers\u00E3o completa de xjc "2.2.8-b20130806.1801" -Driver.BuildID = 2.2.8-b01 +Driver.BuildID = 2.2.8-b20130806.1801 # for JDK integration - include version in source zip -jaxb.jdk.version=2.2.8-b01 +jaxb.jdk.version=@@JAXB_JDK_VERSION@@ # see java.text.SimpleDateFormat for format syntax # DO NOT LOCALIZE, Format should not be changed, English locale is used to transform this string into a real date. diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_zh_CN.properties b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_zh_CN.properties index 610bb1e3cc7..748aab67e38 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_zh_CN.properties +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_zh_CN.properties @@ -96,17 +96,17 @@ Driver.CompilingSchema = \u6b63\u5728\u7f16\u8bd1\u6a21\u5f0f... Driver.FailedToGenerateCode = \u65e0\u6cd5\u751f\u6210\u4ee3\u7801\u3002 -# DO NOT localize the 2.2.8-b01 string - it is a token for an ant -Driver.FilePrologComment = \u6b64\u6587\u4ef6\u662f\u7531 JavaTM Architecture for XML Binding (JAXB) \u5f15\u7528\u5b9e\u73b0 v2.2.8-b01 \u751f\u6210\u7684\n\u8bf7\u8bbf\u95ee http://java.sun.com/xml/jaxb \n\u5728\u91cd\u65b0\u7f16\u8bd1\u6e90\u6a21\u5f0f\u65f6, \u5bf9\u6b64\u6587\u4ef6\u7684\u6240\u6709\u4fee\u6539\u90fd\u5c06\u4e22\u5931\u3002\n\u751f\u6210\u65f6\u95f4: {0} \n +# DO NOT localize the 2.2.8-b20130806.1801 string - it is a token for an ant +Driver.FilePrologComment = \u6b64\u6587\u4ef6\u662f\u7531 JavaTM Architecture for XML Binding (JAXB) \u5f15\u7528\u5b9e\u73b0 v2.2.8-b20130806.1801 \u751f\u6210\u7684\n\u8bf7\u8bbf\u95ee http://java.sun.com/xml/jaxb \n\u5728\u91cd\u65b0\u7f16\u8bd1\u6e90\u6a21\u5f0f\u65f6, \u5bf9\u6b64\u6587\u4ef6\u7684\u6240\u6709\u4fee\u6539\u90fd\u5c06\u4e22\u5931\u3002\n\u751f\u6210\u65f6\u95f4: {0} \n -Driver.Version = xjc 2.2.8-b01 +Driver.Version = xjc 2.2.8-b20130806.1801 -Driver.FullVersion = xjc \u5b8c\u6574\u7248\u672c "2.2.8-b01-b28" +Driver.FullVersion = xjc \u5B8C\u6574\u7248\u672C "2.2.8-b20130806.1801" -Driver.BuildID = 2.2.8-b01 +Driver.BuildID = 2.2.8-b20130806.1801 # for JDK integration - include version in source zip -jaxb.jdk.version=2.2.8-b01 +jaxb.jdk.version=@@JAXB_JDK_VERSION@@ # see java.text.SimpleDateFormat for format syntax # DO NOT LOCALIZE, Format should not be changed, English locale is used to transform this string into a real date. diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_zh_TW.properties b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_zh_TW.properties index 3ed7786c9ec..a305e7e7445 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_zh_TW.properties +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/MessageBundle_zh_TW.properties @@ -96,17 +96,17 @@ Driver.CompilingSchema = \u6b63\u5728\u7de8\u8b6f\u7db1\u8981... Driver.FailedToGenerateCode = \u7121\u6cd5\u7522\u751f\u7a0b\u5f0f\u78bc. -# DO NOT localize the 2.2.8-b01 string - it is a token for an ant -Driver.FilePrologComment = \u6b64\u6a94\u6848\u662f\u7531 JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b01 \u6240\u7522\u751f \n\u8acb\u53c3\u95b1 http://java.sun.com/xml/jaxb \n\u4e00\u65e6\u91cd\u65b0\u7de8\u8b6f\u4f86\u6e90\u7db1\u8981, \u5c0d\u6b64\u6a94\u6848\u6240\u505a\u7684\u4efb\u4f55\u4fee\u6539\u90fd\u5c07\u6703\u907a\u5931. \n\u7522\u751f\u6642\u9593: {0} \n +# DO NOT localize the 2.2.8-b20130806.1801 string - it is a token for an ant +Driver.FilePrologComment = \u6b64\u6a94\u6848\u662f\u7531 JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b20130806.1801 \u6240\u7522\u751f \n\u8acb\u53c3\u95b1 http://java.sun.com/xml/jaxb \n\u4e00\u65e6\u91cd\u65b0\u7de8\u8b6f\u4f86\u6e90\u7db1\u8981, \u5c0d\u6b64\u6a94\u6848\u6240\u505a\u7684\u4efb\u4f55\u4fee\u6539\u90fd\u5c07\u6703\u907a\u5931. \n\u7522\u751f\u6642\u9593: {0} \n -Driver.Version = xjc 2.2.8-b01 +Driver.Version = xjc 2.2.8-b20130806.1801 -Driver.FullVersion = xjc \u5b8c\u6574\u7248\u672c "2.2.8-b01-b28" +Driver.FullVersion = xjc \u5B8C\u6574\u7248\u672C "2.2.8-b20130806.1801" -Driver.BuildID = 2.2.8-b01 +Driver.BuildID = 2.2.8-b20130806.1801 # for JDK integration - include version in source zip -jaxb.jdk.version=2.2.8-b01 +jaxb.jdk.version=@@JAXB_JDK_VERSION@@ # see java.text.SimpleDateFormat for format syntax # DO NOT LOCALIZE, Format should not be changed, English locale is used to transform this string into a real date. diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/SchemaCache.java b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/SchemaCache.java index ca8302358fc..c28fd50db86 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/SchemaCache.java +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/SchemaCache.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,6 +35,8 @@ import com.sun.xml.internal.bind.v2.util.XmlFactory; import javax.xml.XMLConstants; import org.xml.sax.SAXException; +import static com.sun.xml.internal.bind.v2.util.XmlFactory.allowFileAccess; + /** * Wraps a JAXP {@link Schema} object and lazily instantiate it. * @@ -59,7 +61,7 @@ public final class SchemaCache { try { // do not disable secure processing - these are well-known schemas SchemaFactory sf = XmlFactory.createSchemaFactory(XMLConstants.W3C_XML_SCHEMA_NS_URI, false); - schema = sf.newSchema(source); + schema = allowFileAccess(sf, false).newSchema(source); } catch (SAXException e) { // we make sure that the schema is correct before we ship. throw new AssertionError(e); diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlAccessorOrderWriter.java b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlAccessorOrderWriter.java index e394a36c4c4..e5e8ecb8225 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlAccessorOrderWriter.java +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlAccessorOrderWriter.java @@ -29,6 +29,11 @@ import javax.xml.bind.annotation.XmlAccessOrder; import javax.xml.bind.annotation.XmlAccessorOrder; import com.sun.codemodel.internal.JAnnotationWriter; +/** + *

    + * Auto-generated, do not edit. + *

    + */ public interface XmlAccessorOrderWriter extends JAnnotationWriter { diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlAccessorTypeWriter.java b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlAccessorTypeWriter.java index 307991c2a9b..ae7c008d461 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlAccessorTypeWriter.java +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlAccessorTypeWriter.java @@ -29,6 +29,11 @@ import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import com.sun.codemodel.internal.JAnnotationWriter; +/** + *

    + * Auto-generated, do not edit. + *

    + */ public interface XmlAccessorTypeWriter extends JAnnotationWriter { diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlAnyAttributeWriter.java b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlAnyAttributeWriter.java index c17df86b4b3..22d5b3d6475 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlAnyAttributeWriter.java +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlAnyAttributeWriter.java @@ -28,6 +28,11 @@ package com.sun.tools.internal.xjc.generator.annotation.spec; import javax.xml.bind.annotation.XmlAnyAttribute; import com.sun.codemodel.internal.JAnnotationWriter; +/** + *

    + * Auto-generated, do not edit. + *

    + */ public interface XmlAnyAttributeWriter extends JAnnotationWriter { diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlAnyElementWriter.java b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlAnyElementWriter.java index 14a96fe355a..139a665d523 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlAnyElementWriter.java +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlAnyElementWriter.java @@ -29,6 +29,11 @@ import javax.xml.bind.annotation.XmlAnyElement; import com.sun.codemodel.internal.JAnnotationWriter; import com.sun.codemodel.internal.JType; +/** + *

    + * Auto-generated, do not edit. + *

    + */ public interface XmlAnyElementWriter extends JAnnotationWriter { diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlAttachmentRefWriter.java b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlAttachmentRefWriter.java index be5262b135c..b9c8db4857a 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlAttachmentRefWriter.java +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlAttachmentRefWriter.java @@ -28,6 +28,11 @@ package com.sun.tools.internal.xjc.generator.annotation.spec; import javax.xml.bind.annotation.XmlAttachmentRef; import com.sun.codemodel.internal.JAnnotationWriter; +/** + *

    + * Auto-generated, do not edit. + *

    + */ public interface XmlAttachmentRefWriter extends JAnnotationWriter { diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlAttributeWriter.java b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlAttributeWriter.java index 6596c951619..fc32e7b84b4 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlAttributeWriter.java +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlAttributeWriter.java @@ -28,6 +28,11 @@ package com.sun.tools.internal.xjc.generator.annotation.spec; import javax.xml.bind.annotation.XmlAttribute; import com.sun.codemodel.internal.JAnnotationWriter; +/** + *

    + * Auto-generated, do not edit. + *

    + */ public interface XmlAttributeWriter extends JAnnotationWriter { diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlElementDeclWriter.java b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlElementDeclWriter.java index 6954df88959..91981dfc1d9 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlElementDeclWriter.java +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlElementDeclWriter.java @@ -29,6 +29,11 @@ import javax.xml.bind.annotation.XmlElementDecl; import com.sun.codemodel.internal.JAnnotationWriter; import com.sun.codemodel.internal.JType; +/** + *

    + * Auto-generated, do not edit. + *

    + */ public interface XmlElementDeclWriter extends JAnnotationWriter { diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlElementRefWriter.java b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlElementRefWriter.java index abbd33fe09e..ebd9f434d4e 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlElementRefWriter.java +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlElementRefWriter.java @@ -29,6 +29,11 @@ import javax.xml.bind.annotation.XmlElementRef; import com.sun.codemodel.internal.JAnnotationWriter; import com.sun.codemodel.internal.JType; +/** + *

    + * Auto-generated, do not edit. + *

    + */ public interface XmlElementRefWriter extends JAnnotationWriter { diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlElementRefsWriter.java b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlElementRefsWriter.java index c6f3a214e6a..a7276b0078d 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlElementRefsWriter.java +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlElementRefsWriter.java @@ -28,6 +28,11 @@ package com.sun.tools.internal.xjc.generator.annotation.spec; import javax.xml.bind.annotation.XmlElementRefs; import com.sun.codemodel.internal.JAnnotationWriter; +/** + *

    + * Auto-generated, do not edit. + *

    + */ public interface XmlElementRefsWriter extends JAnnotationWriter { diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlElementWrapperWriter.java b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlElementWrapperWriter.java index 36808950d90..bd604e3c55e 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlElementWrapperWriter.java +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlElementWrapperWriter.java @@ -28,6 +28,11 @@ package com.sun.tools.internal.xjc.generator.annotation.spec; import javax.xml.bind.annotation.XmlElementWrapper; import com.sun.codemodel.internal.JAnnotationWriter; +/** + *

    + * Auto-generated, do not edit. + *

    + */ public interface XmlElementWrapperWriter extends JAnnotationWriter { diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlElementWriter.java b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlElementWriter.java index c89073be8dc..f78d0c8eba1 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlElementWriter.java +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlElementWriter.java @@ -29,6 +29,11 @@ import javax.xml.bind.annotation.XmlElement; import com.sun.codemodel.internal.JAnnotationWriter; import com.sun.codemodel.internal.JType; +/** + *

    + * Auto-generated, do not edit. + *

    + */ public interface XmlElementWriter extends JAnnotationWriter { diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlElementsWriter.java b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlElementsWriter.java index 204c1eb6e89..d7e165bcb03 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlElementsWriter.java +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlElementsWriter.java @@ -28,6 +28,11 @@ package com.sun.tools.internal.xjc.generator.annotation.spec; import javax.xml.bind.annotation.XmlElements; import com.sun.codemodel.internal.JAnnotationWriter; +/** + *

    + * Auto-generated, do not edit. + *

    + */ public interface XmlElementsWriter extends JAnnotationWriter { diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlEnumValueWriter.java b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlEnumValueWriter.java index cc2e79259a9..5f22405a47c 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlEnumValueWriter.java +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlEnumValueWriter.java @@ -28,6 +28,11 @@ package com.sun.tools.internal.xjc.generator.annotation.spec; import javax.xml.bind.annotation.XmlEnumValue; import com.sun.codemodel.internal.JAnnotationWriter; +/** + *

    + * Auto-generated, do not edit. + *

    + */ public interface XmlEnumValueWriter extends JAnnotationWriter { diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlEnumWriter.java b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlEnumWriter.java index 93da5e0689d..814110e35a5 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlEnumWriter.java +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlEnumWriter.java @@ -29,6 +29,11 @@ import javax.xml.bind.annotation.XmlEnum; import com.sun.codemodel.internal.JAnnotationWriter; import com.sun.codemodel.internal.JType; +/** + *

    + * Auto-generated, do not edit. + *

    + */ public interface XmlEnumWriter extends JAnnotationWriter { diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlIDREFWriter.java b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlIDREFWriter.java index ec5055dd65d..213d0b8bc99 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlIDREFWriter.java +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlIDREFWriter.java @@ -28,6 +28,11 @@ package com.sun.tools.internal.xjc.generator.annotation.spec; import javax.xml.bind.annotation.XmlIDREF; import com.sun.codemodel.internal.JAnnotationWriter; +/** + *

    + * Auto-generated, do not edit. + *

    + */ public interface XmlIDREFWriter extends JAnnotationWriter { diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlIDWriter.java b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlIDWriter.java index 1046aa6b449..e6a0a74ad8c 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlIDWriter.java +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlIDWriter.java @@ -28,6 +28,11 @@ package com.sun.tools.internal.xjc.generator.annotation.spec; import javax.xml.bind.annotation.XmlID; import com.sun.codemodel.internal.JAnnotationWriter; +/** + *

    + * Auto-generated, do not edit. + *

    + */ public interface XmlIDWriter extends JAnnotationWriter { diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlInlineBinaryDataWriter.java b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlInlineBinaryDataWriter.java index 2bd4cc10fe8..d82eee23695 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlInlineBinaryDataWriter.java +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlInlineBinaryDataWriter.java @@ -28,6 +28,11 @@ package com.sun.tools.internal.xjc.generator.annotation.spec; import javax.xml.bind.annotation.XmlInlineBinaryData; import com.sun.codemodel.internal.JAnnotationWriter; +/** + *

    + * Auto-generated, do not edit. + *

    + */ public interface XmlInlineBinaryDataWriter extends JAnnotationWriter { diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlJavaTypeAdapterWriter.java b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlJavaTypeAdapterWriter.java index 05fc8f78c53..f749545771f 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlJavaTypeAdapterWriter.java +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlJavaTypeAdapterWriter.java @@ -29,6 +29,11 @@ import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; import com.sun.codemodel.internal.JAnnotationWriter; import com.sun.codemodel.internal.JType; +/** + *

    + * Auto-generated, do not edit. + *

    + */ public interface XmlJavaTypeAdapterWriter extends JAnnotationWriter { diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlListWriter.java b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlListWriter.java index 46a88b80b57..5444bd858c5 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlListWriter.java +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlListWriter.java @@ -28,6 +28,11 @@ package com.sun.tools.internal.xjc.generator.annotation.spec; import javax.xml.bind.annotation.XmlList; import com.sun.codemodel.internal.JAnnotationWriter; +/** + *

    + * Auto-generated, do not edit. + *

    + */ public interface XmlListWriter extends JAnnotationWriter { diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlMimeTypeWriter.java b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlMimeTypeWriter.java index e8b7b16ce40..2bf6dbbad95 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlMimeTypeWriter.java +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlMimeTypeWriter.java @@ -28,6 +28,11 @@ package com.sun.tools.internal.xjc.generator.annotation.spec; import javax.xml.bind.annotation.XmlMimeType; import com.sun.codemodel.internal.JAnnotationWriter; +/** + *

    + * Auto-generated, do not edit. + *

    + */ public interface XmlMimeTypeWriter extends JAnnotationWriter { diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlMixedWriter.java b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlMixedWriter.java index 43e9268fae7..9fb7ab246a8 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlMixedWriter.java +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlMixedWriter.java @@ -28,6 +28,11 @@ package com.sun.tools.internal.xjc.generator.annotation.spec; import javax.xml.bind.annotation.XmlMixed; import com.sun.codemodel.internal.JAnnotationWriter; +/** + *

    + * Auto-generated, do not edit. + *

    + */ public interface XmlMixedWriter extends JAnnotationWriter { diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlNsWriter.java b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlNsWriter.java index f5892f33be6..e8d33c4b14a 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlNsWriter.java +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlNsWriter.java @@ -28,6 +28,11 @@ package com.sun.tools.internal.xjc.generator.annotation.spec; import javax.xml.bind.annotation.XmlNs; import com.sun.codemodel.internal.JAnnotationWriter; +/** + *

    + * Auto-generated, do not edit. + *

    + */ public interface XmlNsWriter extends JAnnotationWriter { diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlRegistryWriter.java b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlRegistryWriter.java index 9be6184d2de..b964e91a41a 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlRegistryWriter.java +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlRegistryWriter.java @@ -28,6 +28,11 @@ package com.sun.tools.internal.xjc.generator.annotation.spec; import javax.xml.bind.annotation.XmlRegistry; import com.sun.codemodel.internal.JAnnotationWriter; +/** + *

    + * Auto-generated, do not edit. + *

    + */ public interface XmlRegistryWriter extends JAnnotationWriter { diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlRootElementWriter.java b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlRootElementWriter.java index 743f979cfb6..1071c904f6a 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlRootElementWriter.java +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlRootElementWriter.java @@ -28,6 +28,11 @@ package com.sun.tools.internal.xjc.generator.annotation.spec; import javax.xml.bind.annotation.XmlRootElement; import com.sun.codemodel.internal.JAnnotationWriter; +/** + *

    + * Auto-generated, do not edit. + *

    + */ public interface XmlRootElementWriter extends JAnnotationWriter { diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlSchemaTypeWriter.java b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlSchemaTypeWriter.java index af4c9b962fe..7601f031b6c 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlSchemaTypeWriter.java +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlSchemaTypeWriter.java @@ -29,6 +29,11 @@ import javax.xml.bind.annotation.XmlSchemaType; import com.sun.codemodel.internal.JAnnotationWriter; import com.sun.codemodel.internal.JType; +/** + *

    + * Auto-generated, do not edit. + *

    + */ public interface XmlSchemaTypeWriter extends JAnnotationWriter { diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlSchemaTypesWriter.java b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlSchemaTypesWriter.java index d682b572084..2f0957eaa9b 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlSchemaTypesWriter.java +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlSchemaTypesWriter.java @@ -28,6 +28,11 @@ package com.sun.tools.internal.xjc.generator.annotation.spec; import javax.xml.bind.annotation.XmlSchemaTypes; import com.sun.codemodel.internal.JAnnotationWriter; +/** + *

    + * Auto-generated, do not edit. + *

    + */ public interface XmlSchemaTypesWriter extends JAnnotationWriter { diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlSchemaWriter.java b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlSchemaWriter.java index 5eaa83dcda6..05849e6532a 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlSchemaWriter.java +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlSchemaWriter.java @@ -29,6 +29,11 @@ import javax.xml.bind.annotation.XmlNsForm; import javax.xml.bind.annotation.XmlSchema; import com.sun.codemodel.internal.JAnnotationWriter; +/** + *

    + * Auto-generated, do not edit. + *

    + */ public interface XmlSchemaWriter extends JAnnotationWriter { diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlSeeAlsoWriter.java b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlSeeAlsoWriter.java index 908f9d8c951..6b2037991d2 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlSeeAlsoWriter.java +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlSeeAlsoWriter.java @@ -29,6 +29,11 @@ import javax.xml.bind.annotation.XmlSeeAlso; import com.sun.codemodel.internal.JAnnotationWriter; import com.sun.codemodel.internal.JType; +/** + *

    + * Auto-generated, do not edit. + *

    + */ public interface XmlSeeAlsoWriter extends JAnnotationWriter { diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlTransientWriter.java b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlTransientWriter.java index e3836020952..61bfb4dd5d3 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlTransientWriter.java +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlTransientWriter.java @@ -28,6 +28,11 @@ package com.sun.tools.internal.xjc.generator.annotation.spec; import javax.xml.bind.annotation.XmlTransient; import com.sun.codemodel.internal.JAnnotationWriter; +/** + *

    + * Auto-generated, do not edit. + *

    + */ public interface XmlTransientWriter extends JAnnotationWriter { diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlTypeWriter.java b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlTypeWriter.java index 8f252dec97f..05172dbd1a9 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlTypeWriter.java +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlTypeWriter.java @@ -29,6 +29,11 @@ import javax.xml.bind.annotation.XmlType; import com.sun.codemodel.internal.JAnnotationWriter; import com.sun.codemodel.internal.JType; +/** + *

    + * Auto-generated, do not edit. + *

    + */ public interface XmlTypeWriter extends JAnnotationWriter { diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlValueWriter.java b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlValueWriter.java index 3e43d63b53b..308b93c6003 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlValueWriter.java +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/annotation/spec/XmlValueWriter.java @@ -28,6 +28,11 @@ package com.sun.tools.internal.xjc.generator.annotation.spec; import javax.xml.bind.annotation.XmlValue; import com.sun.codemodel.internal.JAnnotationWriter; +/** + *

    + * Auto-generated, do not edit. + *

    + */ public interface XmlValueWriter extends JAnnotationWriter { diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/bean/MessageBundle.properties b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/bean/MessageBundle.properties index aa1a7266ba8..abcc8c55853 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/bean/MessageBundle.properties +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/generator/bean/MessageBundle.properties @@ -26,7 +26,7 @@ METHOD_COLLISION = \ The "{0}" method is defined on both "{1}" and "{2}" and is causing a collision. -# {0} - enumeration constant value (but something that couldn?t be translated to a valid java identifier e.g. starting special character, number, ..) e.g. Cannot derive a valid Java identifier from "5.6.0". Specify a customization to change the name. +# {0} - enumeration constant value (but something that couldn�t be translated to a valid java identifier e.g. starting special character, number, ..) e.g. Cannot derive a valid Java identifier from "5.6.0". Specify a customization to change the name. ERR_UNUSABLE_NAME = \ Cannot derive a valid Java identifier from "{0}". Specify a customization to change the name. diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/model/CPropertyInfo.java b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/model/CPropertyInfo.java index 53326ac1f64..9910526253b 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/model/CPropertyInfo.java +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/model/CPropertyInfo.java @@ -29,6 +29,7 @@ import java.lang.annotation.Annotation; import java.util.Collection; import java.util.Map; +import javax.xml.XMLConstants; import javax.xml.bind.annotation.XmlTransient; import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; import javax.xml.namespace.QName; @@ -298,7 +299,7 @@ public abstract class CPropertyInfo implements PropertyInfo, CCust // this is anonymous type. can't have @XmlSchemaType return false; - if(!typeName.getNamespaceURI().equals(WellKnownNamespace.XML_SCHEMA)) + if(!XMLConstants.W3C_XML_SCHEMA_NS_URI.equals(typeName.getNamespaceURI())) // if we put application-defined type name, it will be undefined // by the time we generate a schema. return false; diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/model/CTypeRef.java b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/model/CTypeRef.java index 4a622ae132b..62416b0d28d 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/model/CTypeRef.java +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/model/CTypeRef.java @@ -25,6 +25,7 @@ package com.sun.tools.internal.xjc.model; +import javax.xml.XMLConstants; import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; import javax.xml.namespace.QName; @@ -34,6 +35,7 @@ import com.sun.tools.internal.xjc.reader.xmlschema.BGMBuilder; import com.sun.xml.internal.bind.v2.model.core.PropertyInfo; import com.sun.xml.internal.bind.v2.model.core.TypeRef; import com.sun.xml.internal.bind.v2.runtime.RuntimeUtil; +import com.sun.xml.internal.xsom.XSType; import com.sun.xml.internal.xsom.XmlString; import com.sun.xml.internal.xsom.XSElementDecl; import com.sun.istack.internal.Nullable; @@ -74,11 +76,34 @@ public final class CTypeRef implements TypeRef { } public static QName getSimpleTypeName(XSElementDecl decl) { - if(decl==null) return null; - QName typeName = null; - if(decl.getType().isSimpleType()) - typeName = BGMBuilder.getName(decl.getType()); - return typeName; + if(decl==null || !decl.getType().isSimpleType()) + return null; // null if not simple type + return resolveSimpleTypeName(decl.getType()); + } + + /** + * Recursively search for type name. + * + * This is needed to find correct type for refs like: + * + * + * + * + * + * + * + * + * + * + * @param declType given type + * @return simpleTypeName or null + */ + private static QName resolveSimpleTypeName(XSType declType) { + QName name = BGMBuilder.getName(declType); + if (name != null && !XMLConstants.W3C_XML_SCHEMA_NS_URI.equals(name.getNamespaceURI())) + return resolveSimpleTypeName(declType.getBaseType()); + else + return name; } public CTypeRef(CNonElement type, QName elementName, QName typeName, boolean nillable, XmlString defaultValue) { diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/model/package-info.java b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/model/package-info.java index a9f9a24a46f..22bfb767745 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/model/package-info.java +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/model/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -55,7 +55,3 @@ * */ package com.sun.tools.internal.xjc.model; - -import com.sun.xml.internal.xsom.XSComponent; - -import org.xml.sax.Locator; diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/reader/internalizer/AbstractReferenceFinderImpl.java b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/reader/internalizer/AbstractReferenceFinderImpl.java index 8155ffc56ca..f0ec687b927 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/reader/internalizer/AbstractReferenceFinderImpl.java +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/reader/internalizer/AbstractReferenceFinderImpl.java @@ -25,29 +25,27 @@ package com.sun.tools.internal.xjc.reader.internalizer; -import java.io.IOException; -import java.io.File; -import java.net.URI; -import java.net.URISyntaxException; - import com.sun.istack.internal.SAXParseException2; - import org.xml.sax.Attributes; import org.xml.sax.Locator; import org.xml.sax.SAXException; import org.xml.sax.SAXParseException; import org.xml.sax.helpers.XMLFilterImpl; +import java.io.File; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; + /** * XMLFilter that finds references to other schema files from * SAX events. - * + *

    * This implementation is a base implementation for typical case * where we just need to look for a particular attribute which * contains an URL to another schema file. * - * @author - * Kohsuke Kawaguchi (kohsuke.kawaguchi@sun.com) + * @author Kohsuke Kawaguchi (kohsuke.kawaguchi@sun.com) */ public abstract class AbstractReferenceFinderImpl extends XMLFilterImpl { @@ -61,12 +59,9 @@ public abstract class AbstractReferenceFinderImpl extends XMLFilterImpl { * IF the given element contains a reference to an external resource, * return its URL. * - * @param nsURI - * Namespace URI of the current element - * @param localName - * Local name of the current element - * @return - * It's OK to return a relative URL. + * @param nsURI Namespace URI of the current element + * @param localName Local name of the current element + * @return It's OK to return a relative URL. */ protected abstract String findExternalResource(String nsURI, String localName, Attributes atts); @@ -83,16 +78,21 @@ public abstract class AbstractReferenceFinderImpl extends XMLFilterImpl { // absolutize URL. String lsi = locator.getSystemId(); String ref; - if (lsi.startsWith("jar:")) { - int bangIdx = lsi.indexOf('!'); - if (bangIdx > 0) { - ref = lsi.substring(0, bangIdx + 1) - + new URI(lsi.substring(bangIdx + 1)).resolve(new URI(relativeRef)).toString(); + URI relRefURI = new URI(relativeRef); + if (relRefURI.isAbsolute()) + ref = relativeRef; + else { + if (lsi.startsWith("jar:")) { + int bangIdx = lsi.indexOf('!'); + if (bangIdx > 0) { + ref = lsi.substring(0, bangIdx + 1) + + new URI(lsi.substring(bangIdx + 1)).resolve(new URI(relativeRef)).toString(); + } else { + ref = relativeRef; + } } else { - ref = relativeRef; + ref = new URI(lsi).resolve(new URI(relativeRef)).toString(); } - } else { - ref = new URI(lsi).resolve(new URI(relativeRef)).toString(); } // then parse this schema as well, @@ -121,6 +121,7 @@ public abstract class AbstractReferenceFinderImpl extends XMLFilterImpl { throw spe; } } + private Locator locator; @Override @@ -128,4 +129,4 @@ public abstract class AbstractReferenceFinderImpl extends XMLFilterImpl { super.setDocumentLocator(locator); this.locator = locator; } -}; +} diff --git a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/reader/internalizer/DOMForest.java b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/reader/internalizer/DOMForest.java index cdb3360a902..b31ae389454 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/reader/internalizer/DOMForest.java +++ b/jaxws/src/share/jaxws_classes/com/sun/tools/internal/xjc/reader/internalizer/DOMForest.java @@ -25,18 +25,21 @@ package com.sun.tools.internal.xjc.reader.internalizer; -import java.io.IOException; -import java.io.OutputStream; -import java.io.OutputStreamWriter; -import java.util.ArrayList; -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 com.sun.istack.internal.NotNull; +import com.sun.istack.internal.XMLStreamReaderToContentHandler; +import com.sun.tools.internal.xjc.ErrorReceiver; +import com.sun.tools.internal.xjc.Options; +import com.sun.tools.internal.xjc.reader.Const; +import com.sun.tools.internal.xjc.util.ErrorReceiverFilter; +import com.sun.xml.internal.bind.marshaller.DataWriter; +import com.sun.xml.internal.bind.v2.util.XmlFactory; +import com.sun.xml.internal.xsom.parser.JAXPParser; +import com.sun.xml.internal.xsom.parser.XMLParser; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.xml.sax.*; +import org.xml.sax.helpers.XMLFilterImpl; -import static javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; @@ -51,27 +54,13 @@ import javax.xml.transform.dom.DOMSource; import javax.xml.transform.sax.SAXResult; import javax.xml.transform.sax.SAXSource; import javax.xml.validation.SchemaFactory; +import java.io.IOException; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.util.*; -import com.sun.istack.internal.NotNull; -import com.sun.istack.internal.XMLStreamReaderToContentHandler; -import com.sun.tools.internal.xjc.ErrorReceiver; -import com.sun.tools.internal.xjc.Options; -import com.sun.tools.internal.xjc.reader.Const; -import com.sun.tools.internal.xjc.util.ErrorReceiverFilter; -import com.sun.xml.internal.bind.marshaller.DataWriter; -import com.sun.xml.internal.bind.v2.util.XmlFactory; -import com.sun.xml.internal.xsom.parser.JAXPParser; -import com.sun.xml.internal.xsom.parser.XMLParser; - -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.xml.sax.ContentHandler; -import org.xml.sax.EntityResolver; -import org.xml.sax.InputSource; -import org.xml.sax.SAXException; -import org.xml.sax.SAXParseException; -import org.xml.sax.XMLReader; -import org.xml.sax.helpers.XMLFilterImpl; +import static com.sun.xml.internal.bind.v2.util.XmlFactory.allowFileAccess; +import static javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI; /** @@ -471,7 +460,7 @@ public final class DOMForest { } try { - sf.newSchema(sources.toArray(new SAXSource[0])); + allowFileAccess(sf, options.disableXmlSecurity).newSchema(sources.toArray(new SAXSource[0])); } catch (SAXException e) { // error should have been reported. } catch (RuntimeException re) { diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/Util.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/Util.java index 3f98a6a821f..c6a077ebf42 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/Util.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/Util.java @@ -30,7 +30,7 @@ import java.util.logging.Logger; /** * @author Kohsuke Kawaguchi */ -public abstract class Util { +public final class Util { private Util() {} // no instanciation /** diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/Messages.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/Messages.java index 0632d97f6aa..17bcfdea789 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/Messages.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/Messages.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,6 +40,8 @@ public enum Messages { NO_DEFAULT_CONSTRUCTOR_IN_INNER_CLASS, // 1 arg INVALID_TYPE_IN_MAP, // 0args INVALID_JAXP_IMPLEMENTATION, // 1 arg + JAXP_SUPPORTED_PROPERTY, // 1 arg + JAXP_UNSUPPORTED_PROPERTY, // 1 arg ; private static final ResourceBundle rb = ResourceBundle.getBundle(Messages.class.getName()); diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/Messages.properties b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/Messages.properties index d4043dd228b..98e2c8ab576 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/Messages.properties +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/Messages.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -50,3 +50,9 @@ INVALID_TYPE_IN_MAP = \ INVALID_JAXP_IMPLEMENTATION = \ You are running with invalid JAXP api or implementation. JAXP api/implementation of version 1.3.1 (included in JDK6) or higher is required. In case you are using ant, make sure ant 1.7.0 or higher is used - older versions of ant contain JAXP api/impl version 1.2 (in xml-apis.jar). If you want to keep using older ant versions, you have to configure it to use higher the JAXP api/impl versions. + +JAXP_SUPPORTED_PROPERTY =\ + Property "{0}" is supported and has been successfully set by used JAXP implementation. + +JAXP_UNSUPPORTED_PROPERTY =\ + Property "{0}" is not supported by used JAXP implementation. diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/model/annotation/Init.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/model/annotation/Init.java index d0796ec997b..fd53efd4438 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/model/annotation/Init.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/model/annotation/Init.java @@ -25,7 +25,10 @@ package com.sun.xml.internal.bind.v2.model.annotation; - +/** + *

    Auto-generated, do not edit.

    + * + */ class Init { diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/model/annotation/XmlAttributeQuick.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/model/annotation/XmlAttributeQuick.java index 4caf7b2aa2d..a7dee028a92 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/model/annotation/XmlAttributeQuick.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/model/annotation/XmlAttributeQuick.java @@ -28,6 +28,11 @@ package com.sun.xml.internal.bind.v2.model.annotation; import java.lang.annotation.Annotation; import javax.xml.bind.annotation.XmlAttribute; + +/** + *

    Auto-generated, do not edit.

    + * + */ final class XmlAttributeQuick extends Quick implements XmlAttribute diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/model/annotation/XmlElementDeclQuick.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/model/annotation/XmlElementDeclQuick.java index 008fbf907a8..1bd5e5688a7 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/model/annotation/XmlElementDeclQuick.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/model/annotation/XmlElementDeclQuick.java @@ -28,6 +28,11 @@ package com.sun.xml.internal.bind.v2.model.annotation; import java.lang.annotation.Annotation; import javax.xml.bind.annotation.XmlElementDecl; + +/** + *

    Auto-generated, do not edit.

    + * + */ final class XmlElementDeclQuick extends Quick implements XmlElementDecl diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/model/annotation/XmlElementQuick.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/model/annotation/XmlElementQuick.java index 7db0a4b1368..b745944de1c 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/model/annotation/XmlElementQuick.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/model/annotation/XmlElementQuick.java @@ -28,6 +28,11 @@ package com.sun.xml.internal.bind.v2.model.annotation; import java.lang.annotation.Annotation; import javax.xml.bind.annotation.XmlElement; + +/** + *

    Auto-generated, do not edit.

    + * + */ final class XmlElementQuick extends Quick implements XmlElement diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/model/annotation/XmlElementRefQuick.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/model/annotation/XmlElementRefQuick.java index 5756f2fd2bf..dffbe66cc5e 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/model/annotation/XmlElementRefQuick.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/model/annotation/XmlElementRefQuick.java @@ -28,6 +28,11 @@ package com.sun.xml.internal.bind.v2.model.annotation; import java.lang.annotation.Annotation; import javax.xml.bind.annotation.XmlElementRef; + +/** + *

    Auto-generated, do not edit.

    + * + */ final class XmlElementRefQuick extends Quick implements XmlElementRef diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/model/annotation/XmlElementRefsQuick.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/model/annotation/XmlElementRefsQuick.java index 294a233f34b..a5ef63bd1ea 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/model/annotation/XmlElementRefsQuick.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/model/annotation/XmlElementRefsQuick.java @@ -29,6 +29,11 @@ import java.lang.annotation.Annotation; import javax.xml.bind.annotation.XmlElementRef; import javax.xml.bind.annotation.XmlElementRefs; + +/** + *

    Auto-generated, do not edit.

    + * + */ final class XmlElementRefsQuick extends Quick implements XmlElementRefs diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/model/annotation/XmlEnumQuick.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/model/annotation/XmlEnumQuick.java index d2c7698af9a..540ce654498 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/model/annotation/XmlEnumQuick.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/model/annotation/XmlEnumQuick.java @@ -28,6 +28,11 @@ package com.sun.xml.internal.bind.v2.model.annotation; import java.lang.annotation.Annotation; import javax.xml.bind.annotation.XmlEnum; + +/** + *

    Auto-generated, do not edit.

    + * + */ final class XmlEnumQuick extends Quick implements XmlEnum diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/model/annotation/XmlRootElementQuick.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/model/annotation/XmlRootElementQuick.java index e52cfcc9fbe..fcf5eda3ee7 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/model/annotation/XmlRootElementQuick.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/model/annotation/XmlRootElementQuick.java @@ -28,6 +28,11 @@ package com.sun.xml.internal.bind.v2.model.annotation; import java.lang.annotation.Annotation; import javax.xml.bind.annotation.XmlRootElement; + +/** + *

    Auto-generated, do not edit.

    + * + */ final class XmlRootElementQuick extends Quick implements XmlRootElement diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/model/annotation/XmlSchemaQuick.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/model/annotation/XmlSchemaQuick.java index 1c4b782f922..f1862ba9eb1 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/model/annotation/XmlSchemaQuick.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/model/annotation/XmlSchemaQuick.java @@ -30,6 +30,11 @@ import javax.xml.bind.annotation.XmlNs; import javax.xml.bind.annotation.XmlNsForm; import javax.xml.bind.annotation.XmlSchema; + +/** + *

    Auto-generated, do not edit.

    + * + */ final class XmlSchemaQuick extends Quick implements XmlSchema diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/model/annotation/XmlSchemaTypeQuick.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/model/annotation/XmlSchemaTypeQuick.java index ad513f2f897..58f6ecda4f0 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/model/annotation/XmlSchemaTypeQuick.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/model/annotation/XmlSchemaTypeQuick.java @@ -28,6 +28,11 @@ package com.sun.xml.internal.bind.v2.model.annotation; import java.lang.annotation.Annotation; import javax.xml.bind.annotation.XmlSchemaType; + +/** + *

    Auto-generated, do not edit.

    + * + */ final class XmlSchemaTypeQuick extends Quick implements XmlSchemaType diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/model/annotation/XmlTransientQuick.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/model/annotation/XmlTransientQuick.java index b0bf8f52411..0200bad8e26 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/model/annotation/XmlTransientQuick.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/model/annotation/XmlTransientQuick.java @@ -28,6 +28,11 @@ package com.sun.xml.internal.bind.v2.model.annotation; import java.lang.annotation.Annotation; import javax.xml.bind.annotation.XmlTransient; + +/** + *

    Auto-generated, do not edit.

    + * + */ final class XmlTransientQuick extends Quick implements XmlTransient diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/model/annotation/XmlTypeQuick.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/model/annotation/XmlTypeQuick.java index 3e33cd54878..abb8541bed9 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/model/annotation/XmlTypeQuick.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/model/annotation/XmlTypeQuick.java @@ -28,6 +28,11 @@ package com.sun.xml.internal.bind.v2.model.annotation; import java.lang.annotation.Annotation; import javax.xml.bind.annotation.XmlType; + +/** + *

    Auto-generated, do not edit.

    + * + */ final class XmlTypeQuick extends Quick implements XmlType diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/model/annotation/XmlValueQuick.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/model/annotation/XmlValueQuick.java index a6b391911b4..fdc0cb24da4 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/model/annotation/XmlValueQuick.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/model/annotation/XmlValueQuick.java @@ -28,6 +28,11 @@ package com.sun.xml.internal.bind.v2.model.annotation; import java.lang.annotation.Annotation; import javax.xml.bind.annotation.XmlValue; + +/** + *

    Auto-generated, do not edit.

    + * + */ final class XmlValueQuick extends Quick implements XmlValue diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/model/core/package-info.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/model/core/package-info.java index 1b6ad95b223..1ac8d1eb48c 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/model/core/package-info.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/model/core/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -59,10 +59,6 @@ @XmlSchema(namespace="http://jaxb.dev.java.net/xjc/model",elementFormDefault=QUALIFIED) package com.sun.xml.internal.bind.v2.model.core; -import java.lang.reflect.Type; -import java.lang.reflect.Method; -import java.lang.reflect.Field; - import javax.xml.bind.annotation.XmlSchema; import static javax.xml.bind.annotation.XmlNsForm.QUALIFIED; diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/model/impl/RuntimeBuiltinLeafInfoImpl.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/model/impl/RuntimeBuiltinLeafInfoImpl.java index f1a28b6a729..4a2c160fa8b 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/model/impl/RuntimeBuiltinLeafInfoImpl.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/model/impl/RuntimeBuiltinLeafInfoImpl.java @@ -91,6 +91,9 @@ import com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data; import com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext; import com.sun.xml.internal.bind.v2.util.ByteArrayOutputStreamEx; import com.sun.xml.internal.bind.v2.util.DataSourceSource; +import java.util.logging.Logger; +import com.sun.xml.internal.bind.Util; +import java.util.logging.Level; import org.xml.sax.SAXException; @@ -105,6 +108,8 @@ import org.xml.sax.SAXException; public abstract class RuntimeBuiltinLeafInfoImpl extends BuiltinLeafInfoImpl implements RuntimeBuiltinLeafInfo, Transducer { + private static final Logger logger = Util.getClassLogger(); + private RuntimeBuiltinLeafInfoImpl(Class type, QName... typeNames) { super(type, typeNames); LEAVES.put(type,this); @@ -196,6 +201,7 @@ public abstract class RuntimeBuiltinLeafInfoImpl extends BuiltinLeafInfoImpl< public static final List> builtinBeanInfos; public static final String MAP_ANYURI_TO_URI = "mapAnyUriToUri"; + public static final String USE_OLD_GMONTH_MAPPING = "jaxb.ri.useOldGmonthMapping"; static { @@ -960,7 +966,14 @@ public abstract class RuntimeBuiltinLeafInfoImpl extends BuiltinLeafInfoImpl< m.put(DatatypeConstants.DATETIME, "%Y-%M-%DT%h:%m:%s"+ "%z"); m.put(DatatypeConstants.DATE, "%Y-%M-%D" +"%z"); m.put(DatatypeConstants.TIME, "%h:%m:%s"+ "%z"); - m.put(DatatypeConstants.GMONTH, "--%M--%z"); + if (System.getProperty(USE_OLD_GMONTH_MAPPING) == null) { + m.put(DatatypeConstants.GMONTH, "--%M%z"); // E2-12 Error. http://www.w3.org/2001/05/xmlschema-errata#e2-12 + } else { // backw. compatibility + if (logger.isLoggable(Level.FINE)) { + logger.log(Level.FINE, "Old GMonth mapping used."); + } + m.put(DatatypeConstants.GMONTH, "--%M--%z"); + } m.put(DatatypeConstants.GDAY, "---%D" + "%z"); m.put(DatatypeConstants.GYEAR, "%Y" + "%z"); m.put(DatatypeConstants.GYEARMONTH, "%Y-%M" + "%z"); diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/package-info.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/package-info.java index bc2975af1e8..b52f12cca07 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/package-info.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/package-info.java @@ -180,7 +180,3 @@ * @ArchitectureDocument */ package com.sun.xml.internal.bind.v2; - -import javax.xml.bind.JAXBContext; - -import com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl; diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/BridgeAdapter.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/BridgeAdapter.java index d3afb47615c..252f0ea6abd 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/BridgeAdapter.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/BridgeAdapter.java @@ -88,13 +88,11 @@ final class BridgeAdapter extends InternalBridge { private OnWire adaptM(Marshaller m,InMemory v) throws JAXBException { XMLSerializer serializer = ((MarshallerImpl)m).serializer; - serializer.setThreadAffinity(); serializer.pushCoordinator(); try { return _adaptM(serializer, v); } finally { serializer.popCoordinator(); - serializer.resetThreadAffinity(); } } @@ -132,7 +130,6 @@ final class BridgeAdapter extends InternalBridge { private @NotNull InMemory adaptU(Unmarshaller _u, OnWire v) throws JAXBException { UnmarshallerImpl u = (UnmarshallerImpl) _u; XmlAdapter a = u.coordinator.getAdapter(adapter); - u.coordinator.setThreadAffinity(); u.coordinator.pushCoordinator(); try { return a.unmarshal(v); @@ -140,7 +137,6 @@ final class BridgeAdapter extends InternalBridge { throw new UnmarshalException(e); } finally { u.coordinator.popCoordinator(); - u.coordinator.resetThreadAffinity(); } } diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/Coordinator.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/Coordinator.java index a76532ad7d0..6e66188b9f3 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/Coordinator.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/Coordinator.java @@ -94,75 +94,37 @@ public abstract class Coordinator implements ErrorHandler, ValidationEventHandle return adapters.containsKey(type); } + // this much is necessary to avoid calling get and set twice when we push. + private static final ThreadLocal activeTable = new ThreadLocal(); + /** * The {@link Coordinator} in charge before this {@link Coordinator}. */ - private Object old; - - /** - * A 'pointer' to a {@link Coordinator} that keeps track of the currently active {@link Coordinator}. - * Having this improves the runtime performance. - */ - private Object[] table; - - /** - * When we set {@link #table} to null, record who did it. - * This is for trouble-shooting a possible concurrency issue reported at: - * http://forums.java.net/jive/thread.jspa?threadID=15132 - */ - public Exception guyWhoSetTheTableToNull; - - /** - * Associates this {@link Coordinator} with the current thread. - * Should be called at the very beginning of the episode. - */ - protected final void setThreadAffinity() { - table = activeTable.get(); - assert table!=null; - } - - /** - * Dis-associate this {@link Coordinator} with the current thread. - * Sohuld be called at the end of the episode to avoid memory leak. - */ - protected final void resetThreadAffinity() { - if (activeTable != null) { - activeTable.remove(); - } - if(debugTableNPE) - guyWhoSetTheTableToNull = new Exception(); // remember that we set it to null - table = null; - } + private Coordinator old; /** * Called whenever an execution flow enters the realm of this {@link Coordinator}. */ protected final void pushCoordinator() { - old = table[0]; - table[0] = this; + old = activeTable.get(); + activeTable.set(this); } /** * Called whenever an execution flow exits the realm of this {@link Coordinator}. */ protected final void popCoordinator() { - assert table[0]==this; - table[0] = old; + if (old != null) + activeTable.set(old); + else + activeTable.remove(); old = null; // avoid memory leak } public static Coordinator _getInstance() { - return (Coordinator) activeTable.get()[0]; + return activeTable.get(); } - // this much is necessary to avoid calling get and set twice when we push. - private static final ThreadLocal activeTable = new ThreadLocal() { - @Override - public Object[] initialValue() { - return new Object[1]; - } - }; - // // // ErrorHandler implementation @@ -207,13 +169,4 @@ public abstract class Coordinator implements ErrorHandler, ValidationEventHandle throw saxException; } } - - public static boolean debugTableNPE; - - static { - try { - debugTableNPE = Boolean.getBoolean(Coordinator.class.getName()+".debugTableNPE"); - } catch (SecurityException t) { - } - } } diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/XMLSerializer.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/XMLSerializer.java index 4c14187a7ff..941b5684275 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/XMLSerializer.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/XMLSerializer.java @@ -812,7 +812,6 @@ public final class XMLSerializer extends Coordinator { * Similar to 'schemaLocation' but this one works for xsi:noNamespaceSchemaLocation */ public void startDocument(XmlOutput out,boolean fragment,String schemaLocation,String noNsSchemaLocation) throws IOException, SAXException, XMLStreamException { - setThreadAffinity(); pushCoordinator(); nsContext.reset(); nse = nsContext.getCurrent(); @@ -841,7 +840,6 @@ public final class XMLSerializer extends Coordinator { out = null; clearCurrentProperty(); popCoordinator(); - resetThreadAffinity(); } /** diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/PrimitiveArrayListerBoolean.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/PrimitiveArrayListerBoolean.java index f0a0b4e475c..853b2373298 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/PrimitiveArrayListerBoolean.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/PrimitiveArrayListerBoolean.java @@ -30,10 +30,13 @@ import com.sun.xml.internal.bind.v2.runtime.XMLSerializer; /** * {@link Lister} for primitive type arrays. - * + *

    + * Auto-generated, do not edit. + *

    *

    - * B y t e ArrayLister is used as the master to generate the rest of the - * lister classes. Do not modify the generated copies. + * B y t e ArrayLister is used as the master to generate the rest of the + * lister classes. Do not modify the generated copies. + *

    */ final class PrimitiveArrayListerBoolean extends Lister { diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/PrimitiveArrayListerCharacter.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/PrimitiveArrayListerCharacter.java index 3a0ab85c3c1..c50f53b0251 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/PrimitiveArrayListerCharacter.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/PrimitiveArrayListerCharacter.java @@ -30,10 +30,13 @@ import com.sun.xml.internal.bind.v2.runtime.XMLSerializer; /** * {@link Lister} for primitive type arrays. - * + *

    + * Auto-generated, do not edit. + *

    *

    - * B y t e ArrayLister is used as the master to generate the rest of the - * lister classes. Do not modify the generated copies. + * B y t e ArrayLister is used as the master to generate the rest of the + * lister classes. Do not modify the generated copies. + *

    */ final class PrimitiveArrayListerCharacter extends Lister { diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/PrimitiveArrayListerDouble.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/PrimitiveArrayListerDouble.java index c85a92672a7..bd6e03cdc5c 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/PrimitiveArrayListerDouble.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/PrimitiveArrayListerDouble.java @@ -30,10 +30,13 @@ import com.sun.xml.internal.bind.v2.runtime.XMLSerializer; /** * {@link Lister} for primitive type arrays. - * + *

    + * Auto-generated, do not edit. + *

    *

    - * B y t e ArrayLister is used as the master to generate the rest of the - * lister classes. Do not modify the generated copies. + * B y t e ArrayLister is used as the master to generate the rest of the + * lister classes. Do not modify the generated copies. + *

    */ final class PrimitiveArrayListerDouble extends Lister { diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/PrimitiveArrayListerFloat.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/PrimitiveArrayListerFloat.java index b5bd7e4eec3..5ced3035d6b 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/PrimitiveArrayListerFloat.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/PrimitiveArrayListerFloat.java @@ -30,10 +30,13 @@ import com.sun.xml.internal.bind.v2.runtime.XMLSerializer; /** * {@link Lister} for primitive type arrays. - * + *

    + * Auto-generated, do not edit. + *

    *

    - * B y t e ArrayLister is used as the master to generate the rest of the - * lister classes. Do not modify the generated copies. + * B y t e ArrayLister is used as the master to generate the rest of the + * lister classes. Do not modify the generated copies. + *

    */ final class PrimitiveArrayListerFloat extends Lister { diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/PrimitiveArrayListerInteger.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/PrimitiveArrayListerInteger.java index cdb8e58c4cd..98a075461ed 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/PrimitiveArrayListerInteger.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/PrimitiveArrayListerInteger.java @@ -30,10 +30,13 @@ import com.sun.xml.internal.bind.v2.runtime.XMLSerializer; /** * {@link Lister} for primitive type arrays. - * + *

    + * Auto-generated, do not edit. + *

    *

    - * B y t e ArrayLister is used as the master to generate the rest of the - * lister classes. Do not modify the generated copies. + * B y t e ArrayLister is used as the master to generate the rest of the + * lister classes. Do not modify the generated copies. + *

    */ final class PrimitiveArrayListerInteger extends Lister { diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/PrimitiveArrayListerLong.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/PrimitiveArrayListerLong.java index 5598ca66bb2..4412b7ed9d6 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/PrimitiveArrayListerLong.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/PrimitiveArrayListerLong.java @@ -30,10 +30,13 @@ import com.sun.xml.internal.bind.v2.runtime.XMLSerializer; /** * {@link Lister} for primitive type arrays. - * + *

    + * Auto-generated, do not edit. + *

    *

    - * B y t e ArrayLister is used as the master to generate the rest of the - * lister classes. Do not modify the generated copies. + * B y t e ArrayLister is used as the master to generate the rest of the + * lister classes. Do not modify the generated copies. + *

    */ final class PrimitiveArrayListerLong extends Lister { diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/PrimitiveArrayListerShort.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/PrimitiveArrayListerShort.java index ddc61a7856d..8493f8465ba 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/PrimitiveArrayListerShort.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/PrimitiveArrayListerShort.java @@ -30,10 +30,13 @@ import com.sun.xml.internal.bind.v2.runtime.XMLSerializer; /** * {@link Lister} for primitive type arrays. - * + *

    + * Auto-generated, do not edit. + *

    *

    - * B y t e ArrayLister is used as the master to generate the rest of the - * lister classes. Do not modify the generated copies. + * B y t e ArrayLister is used as the master to generate the rest of the + * lister classes. Do not modify the generated copies. + *

    */ final class PrimitiveArrayListerShort extends Lister { diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/opt/FieldAccessor_Boolean.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/opt/FieldAccessor_Boolean.java index 28cdee67715..e1e36db9561 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/opt/FieldAccessor_Boolean.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/opt/FieldAccessor_Boolean.java @@ -29,10 +29,12 @@ import com.sun.xml.internal.bind.v2.runtime.reflect.Accessor; /** * Template {@link Accessor} for boolean fields. - * + *

    + * Auto-generated, do not edit. + *

    *

    - * All the FieldAccessors are generated from FieldAccessor_B y t e - * + * All the FieldAccessors are generated from FieldAccessor_B y t e + *

    * @author Kohsuke Kawaguchi */ public class FieldAccessor_Boolean extends Accessor { diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/opt/FieldAccessor_Character.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/opt/FieldAccessor_Character.java index 3ec52cf0063..171b42f772a 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/opt/FieldAccessor_Character.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/opt/FieldAccessor_Character.java @@ -29,10 +29,12 @@ import com.sun.xml.internal.bind.v2.runtime.reflect.Accessor; /** * Template {@link Accessor} for char fields. - * + *

    + * Auto-generated, do not edit. + *

    *

    - * All the FieldAccessors are generated from FieldAccessor_B y t e - * + * All the FieldAccessors are generated from FieldAccessor_B y t e + *

    * @author Kohsuke Kawaguchi */ public class FieldAccessor_Character extends Accessor { diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/opt/FieldAccessor_Double.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/opt/FieldAccessor_Double.java index 9ef4c1f41bd..be024e9a4d7 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/opt/FieldAccessor_Double.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/opt/FieldAccessor_Double.java @@ -29,10 +29,12 @@ import com.sun.xml.internal.bind.v2.runtime.reflect.Accessor; /** * Template {@link Accessor} for double fields. - * + *

    + * Auto-generated, do not edit. + *

    *

    - * All the FieldAccessors are generated from FieldAccessor_B y t e - * + * All the FieldAccessors are generated from FieldAccessor_B y t e + *

    * @author Kohsuke Kawaguchi */ public class FieldAccessor_Double extends Accessor { diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/opt/FieldAccessor_Float.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/opt/FieldAccessor_Float.java index a7651a646b3..d5e1af13623 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/opt/FieldAccessor_Float.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/opt/FieldAccessor_Float.java @@ -29,10 +29,12 @@ import com.sun.xml.internal.bind.v2.runtime.reflect.Accessor; /** * Template {@link Accessor} for float fields. - * + *

    + * Auto-generated, do not edit. + *

    *

    - * All the FieldAccessors are generated from FieldAccessor_B y t e - * + * All the FieldAccessors are generated from FieldAccessor_B y t e + *

    * @author Kohsuke Kawaguchi */ public class FieldAccessor_Float extends Accessor { diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/opt/FieldAccessor_Integer.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/opt/FieldAccessor_Integer.java index db6cb8eb0dc..467fa79ae81 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/opt/FieldAccessor_Integer.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/opt/FieldAccessor_Integer.java @@ -29,10 +29,12 @@ import com.sun.xml.internal.bind.v2.runtime.reflect.Accessor; /** * Template {@link Accessor} for int fields. - * + *

    + * Auto-generated, do not edit. + *

    *

    - * All the FieldAccessors are generated from FieldAccessor_B y t e - * + * All the FieldAccessors are generated from FieldAccessor_B y t e + *

    * @author Kohsuke Kawaguchi */ public class FieldAccessor_Integer extends Accessor { diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/opt/FieldAccessor_Long.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/opt/FieldAccessor_Long.java index 60adf9d4c4b..1980cb33c0d 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/opt/FieldAccessor_Long.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/opt/FieldAccessor_Long.java @@ -29,10 +29,12 @@ import com.sun.xml.internal.bind.v2.runtime.reflect.Accessor; /** * Template {@link Accessor} for long fields. - * + *

    + * Auto-generated, do not edit. + *

    *

    - * All the FieldAccessors are generated from FieldAccessor_B y t e - * + * All the FieldAccessors are generated from FieldAccessor_B y t e + *

    * @author Kohsuke Kawaguchi */ public class FieldAccessor_Long extends Accessor { diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/opt/FieldAccessor_Short.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/opt/FieldAccessor_Short.java index 84315f634e4..49a000aea49 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/opt/FieldAccessor_Short.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/opt/FieldAccessor_Short.java @@ -29,10 +29,12 @@ import com.sun.xml.internal.bind.v2.runtime.reflect.Accessor; /** * Template {@link Accessor} for short fields. - * + *

    + * Auto-generated, do not edit. + *

    *

    - * All the FieldAccessors are generated from FieldAccessor_B y t e - * + * All the FieldAccessors are generated from FieldAccessor_B y t e + *

    * @author Kohsuke Kawaguchi */ public class FieldAccessor_Short extends Accessor { diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/opt/MethodAccessor_Boolean.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/opt/MethodAccessor_Boolean.java index 8176a657c41..07fde9b0938 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/opt/MethodAccessor_Boolean.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/opt/MethodAccessor_Boolean.java @@ -29,10 +29,12 @@ import com.sun.xml.internal.bind.v2.runtime.reflect.Accessor; /** * Template {@link Accessor} for boolean getter/setter. - * + *

    + * Auto-generated, do not edit. + *

    *

    - * All the MethodAccessors are generated from MethodAccessor_B y t e - * + * All the MethodAccessors are generated from MethodAccessor_B y t e + *

    * @author Kohsuke Kawaguchi */ public class MethodAccessor_Boolean extends Accessor { diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/opt/MethodAccessor_Character.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/opt/MethodAccessor_Character.java index 92c94901f7e..856d35508ad 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/opt/MethodAccessor_Character.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/opt/MethodAccessor_Character.java @@ -29,10 +29,12 @@ import com.sun.xml.internal.bind.v2.runtime.reflect.Accessor; /** * Template {@link Accessor} for boolean getter/setter. - * + *

    + * Auto-generated, do not edit. + *

    *

    - * All the MethodAccessors are generated from MethodAccessor_B y t e - * + * All the MethodAccessors are generated from MethodAccessor_B y t e + *

    * @author Kohsuke Kawaguchi */ public class MethodAccessor_Character extends Accessor { diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/opt/MethodAccessor_Double.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/opt/MethodAccessor_Double.java index f7d9d873231..4b12972bee9 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/opt/MethodAccessor_Double.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/opt/MethodAccessor_Double.java @@ -29,10 +29,12 @@ import com.sun.xml.internal.bind.v2.runtime.reflect.Accessor; /** * Template {@link Accessor} for boolean getter/setter. - * + *

    + * Auto-generated, do not edit. + *

    *

    - * All the MethodAccessors are generated from MethodAccessor_B y t e - * + * All the MethodAccessors are generated from MethodAccessor_B y t e + *

    * @author Kohsuke Kawaguchi */ public class MethodAccessor_Double extends Accessor { diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/opt/MethodAccessor_Float.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/opt/MethodAccessor_Float.java index 9b6f0f2142a..54d9af2cf78 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/opt/MethodAccessor_Float.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/opt/MethodAccessor_Float.java @@ -29,10 +29,12 @@ import com.sun.xml.internal.bind.v2.runtime.reflect.Accessor; /** * Template {@link Accessor} for boolean getter/setter. - * + *

    + * Auto-generated, do not edit. + *

    *

    - * All the MethodAccessors are generated from MethodAccessor_B y t e - * + * All the MethodAccessors are generated from MethodAccessor_B y t e + *

    * @author Kohsuke Kawaguchi */ public class MethodAccessor_Float extends Accessor { diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/opt/MethodAccessor_Integer.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/opt/MethodAccessor_Integer.java index 54462b3e3d6..8b5ea50f39c 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/opt/MethodAccessor_Integer.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/opt/MethodAccessor_Integer.java @@ -29,10 +29,12 @@ import com.sun.xml.internal.bind.v2.runtime.reflect.Accessor; /** * Template {@link Accessor} for boolean getter/setter. - * + *

    + * Auto-generated, do not edit. + *

    *

    - * All the MethodAccessors are generated from MethodAccessor_B y t e - * + * All the MethodAccessors are generated from MethodAccessor_B y t e + *

    * @author Kohsuke Kawaguchi */ public class MethodAccessor_Integer extends Accessor { diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/opt/MethodAccessor_Long.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/opt/MethodAccessor_Long.java index 82beed25f98..f7d2c2617b4 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/opt/MethodAccessor_Long.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/opt/MethodAccessor_Long.java @@ -29,10 +29,12 @@ import com.sun.xml.internal.bind.v2.runtime.reflect.Accessor; /** * Template {@link Accessor} for boolean getter/setter. - * + *

    + * Auto-generated, do not edit. + *

    *

    - * All the MethodAccessors are generated from MethodAccessor_B y t e - * + * All the MethodAccessors are generated from MethodAccessor_B y t e + *

    * @author Kohsuke Kawaguchi */ public class MethodAccessor_Long extends Accessor { diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/opt/MethodAccessor_Short.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/opt/MethodAccessor_Short.java index 5828e099759..f91bc0b75a6 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/opt/MethodAccessor_Short.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/opt/MethodAccessor_Short.java @@ -29,10 +29,12 @@ import com.sun.xml.internal.bind.v2.runtime.reflect.Accessor; /** * Template {@link Accessor} for boolean getter/setter. - * + *

    + * Auto-generated, do not edit. + *

    *

    - * All the MethodAccessors are generated from MethodAccessor_B y t e - * + * All the MethodAccessors are generated from MethodAccessor_B y t e + *

    * @author Kohsuke Kawaguchi */ public class MethodAccessor_Short extends Accessor { diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/opt/TransducedAccessor_field_Double.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/opt/TransducedAccessor_field_Double.java index 38242c9f9fe..54f7dbe6c87 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/opt/TransducedAccessor_field_Double.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/opt/TransducedAccessor_field_Double.java @@ -31,10 +31,12 @@ import com.sun.xml.internal.bind.v2.runtime.reflect.DefaultTransducedAccessor; /** * Template {@link TransducedAccessor} for a double field. - * + *

    + * Auto-generated, do not edit. + *

    *

    - * All the TransducedAccessor_field are generated from TransducedAccessor_field_B y t e - * + * All the TransducedAccessor_field are generated from TransducedAccessor_field_B y t e + *

    * @author Kohsuke Kawaguchi * * @see TransducedAccessor#get diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/opt/TransducedAccessor_field_Float.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/opt/TransducedAccessor_field_Float.java index 5bd8d6281f8..6b67f61e5c2 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/opt/TransducedAccessor_field_Float.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/opt/TransducedAccessor_field_Float.java @@ -31,10 +31,12 @@ import com.sun.xml.internal.bind.v2.runtime.reflect.DefaultTransducedAccessor; /** * Template {@link TransducedAccessor} for a float field. - * + *

    + * Auto-generated, do not edit. + *

    *

    - * All the TransducedAccessor_field are generated from TransducedAccessor_field_B y t e - * + * All the TransducedAccessor_field are generated from TransducedAccessor_field_B y t e + *

    * @author Kohsuke Kawaguchi * * @see TransducedAccessor#get diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/opt/TransducedAccessor_field_Long.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/opt/TransducedAccessor_field_Long.java index 367510fcaac..beb68e56668 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/opt/TransducedAccessor_field_Long.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/opt/TransducedAccessor_field_Long.java @@ -31,10 +31,12 @@ import com.sun.xml.internal.bind.v2.runtime.reflect.DefaultTransducedAccessor; /** * Template {@link TransducedAccessor} for a long field. - * + *

    + * Auto-generated, do not edit. + *

    *

    - * All the TransducedAccessor_field are generated from TransducedAccessor_field_B y t e - * + * All the TransducedAccessor_field are generated from TransducedAccessor_field_B y t e + *

    * @author Kohsuke Kawaguchi * * @see TransducedAccessor#get diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/opt/TransducedAccessor_field_Short.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/opt/TransducedAccessor_field_Short.java index 3713627f988..437f91175ba 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/opt/TransducedAccessor_field_Short.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/opt/TransducedAccessor_field_Short.java @@ -31,10 +31,12 @@ import com.sun.xml.internal.bind.v2.runtime.reflect.DefaultTransducedAccessor; /** * Template {@link TransducedAccessor} for a short field. - * + *

    + * Auto-generated, do not edit. + *

    *

    - * All the TransducedAccessor_field are generated from TransducedAccessor_field_B y t e - * + * All the TransducedAccessor_field are generated from TransducedAccessor_field_B y t e + *

    * @author Kohsuke Kawaguchi * * @see TransducedAccessor#get diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/opt/TransducedAccessor_method_Boolean.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/opt/TransducedAccessor_method_Boolean.java index c9fb036d79c..f7cd6ccdda7 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/opt/TransducedAccessor_method_Boolean.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/opt/TransducedAccessor_method_Boolean.java @@ -31,10 +31,12 @@ import com.sun.xml.internal.bind.v2.runtime.reflect.DefaultTransducedAccessor; /** * Template {@link TransducedAccessor} for a boolean field. - * + *

    + * Auto-generated, do not edit. + *

    *

    - * All the TransducedAccessor_field are generated from TransducedAccessor_field_B y t e - * + * All the TransducedAccessor_field are generated from TransducedAccessor_field_B y t e + *

    * @author Kohsuke Kawaguchi * * @see TransducedAccessor#get diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/opt/TransducedAccessor_method_Double.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/opt/TransducedAccessor_method_Double.java index 958d998c0b1..fe87c4bb000 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/opt/TransducedAccessor_method_Double.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/opt/TransducedAccessor_method_Double.java @@ -31,10 +31,12 @@ import com.sun.xml.internal.bind.v2.runtime.reflect.DefaultTransducedAccessor; /** * Template {@link TransducedAccessor} for a double field. - * + *

    + * Auto-generated, do not edit. + *

    *

    - * All the TransducedAccessor_field are generated from TransducedAccessor_field_B y t e - * + * All the TransducedAccessor_field are generated from TransducedAccessor_field_B y t e + *

    * @author Kohsuke Kawaguchi * * @see TransducedAccessor#get diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/opt/TransducedAccessor_method_Float.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/opt/TransducedAccessor_method_Float.java index 9ca22b97171..16a51cfddb8 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/opt/TransducedAccessor_method_Float.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/opt/TransducedAccessor_method_Float.java @@ -31,10 +31,12 @@ import com.sun.xml.internal.bind.v2.runtime.reflect.DefaultTransducedAccessor; /** * Template {@link TransducedAccessor} for a float field. - * + *

    + * Auto-generated, do not edit. + *

    *

    - * All the TransducedAccessor_field are generated from TransducedAccessor_field_B y t e - * + * All the TransducedAccessor_field are generated from TransducedAccessor_field_B y t e + *

    * @author Kohsuke Kawaguchi * * @see TransducedAccessor#get diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/opt/TransducedAccessor_method_Long.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/opt/TransducedAccessor_method_Long.java index 2a25f304674..3ca907058a9 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/opt/TransducedAccessor_method_Long.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/opt/TransducedAccessor_method_Long.java @@ -31,10 +31,12 @@ import com.sun.xml.internal.bind.v2.runtime.reflect.DefaultTransducedAccessor; /** * Template {@link TransducedAccessor} for a long field. - * + *

    + * Auto-generated, do not edit. + *

    *

    - * All the TransducedAccessor_field are generated from TransducedAccessor_field_B y t e - * + * All the TransducedAccessor_field are generated from TransducedAccessor_field_B y t e + *

    * @author Kohsuke Kawaguchi * * @see TransducedAccessor#get diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/opt/TransducedAccessor_method_Short.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/opt/TransducedAccessor_method_Short.java index b4b567ad09b..f4a50ef1dfe 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/opt/TransducedAccessor_method_Short.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/opt/TransducedAccessor_method_Short.java @@ -31,10 +31,12 @@ import com.sun.xml.internal.bind.v2.runtime.reflect.DefaultTransducedAccessor; /** * Template {@link TransducedAccessor} for a short field. - * + *

    + * Auto-generated, do not edit. + *

    *

    - * All the TransducedAccessor_field are generated from TransducedAccessor_field_B y t e - * + * All the TransducedAccessor_field are generated from TransducedAccessor_field_B y t e + *

    * @author Kohsuke Kawaguchi * * @see TransducedAccessor#get diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/unmarshaller/Loader.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/unmarshaller/Loader.java index ef75619f986..9c9ccea3ffc 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/unmarshaller/Loader.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/unmarshaller/Loader.java @@ -94,11 +94,15 @@ public abstract class Loader { @SuppressWarnings({"StringEquality"}) protected final void reportUnexpectedChildElement(TagName ea, boolean canRecover) throws SAXException { - if(canRecover && !UnmarshallingContext.getInstance().parent.hasEventHandler()) + if (canRecover) { // this error happens particurly often (when input documents contain a lot of unexpected elements to be ignored), // so don't bother computing all the messages and etc if we know that // there's no event handler to receive the error in the end. See #286 - return; + UnmarshallingContext context = UnmarshallingContext.getInstance(); + if (!context.parent.hasEventHandler() // is somebody listening? + || !context.shouldErrorBeReported()) // should we report error? + return; + } if(ea.uri!=ea.uri.intern() || ea.local!=ea.local.intern()) reportError(Messages.UNINTERNED_STRINGS.format(), canRecover ); else diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/unmarshaller/Messages.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/unmarshaller/Messages.java index f37be69b4b9..2390f67fcdd 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/unmarshaller/Messages.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/unmarshaller/Messages.java @@ -40,6 +40,7 @@ enum Messages { UNRECOGNIZED_TYPE_NAME_MAYBE, // 2 args UNABLE_TO_CREATE_MAP, // 1 arg UNINTERNED_STRINGS, // no args + ERRORS_LIMIT_EXCEEDED, // no arg ; private static final ResourceBundle rb = ResourceBundle.getBundle(Messages.class.getName()); diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/unmarshaller/Messages.properties b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/unmarshaller/Messages.properties index e6d4960f657..b4eb4cc5097 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/unmarshaller/Messages.properties +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/unmarshaller/Messages.properties @@ -50,3 +50,7 @@ UNABLE_TO_CREATE_MAP = \ UNINTERNED_STRINGS = \ Namespace URIs and local names to the unmarshaller needs to be interned. + +# user have to set Logger.getLogger("com.sun.xml.internal.bind").setLevel(Level.FINEST) +ERRORS_LIMIT_EXCEEDED = \ + Errors limit exceeded. To receive all errors set 'com.sun.xml.internal.bind' logger to FINEST level. diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/unmarshaller/SAXConnector.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/unmarshaller/SAXConnector.java index 7695de9ee1f..44998166542 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/unmarshaller/SAXConnector.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/unmarshaller/SAXConnector.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,11 +25,14 @@ package com.sun.xml.internal.bind.v2.runtime.unmarshaller; +import com.sun.xml.internal.bind.Util; import javax.xml.bind.JAXBException; import javax.xml.bind.UnmarshallerHandler; import com.sun.xml.internal.bind.WhiteSpaceProcessor; import com.sun.xml.internal.bind.v2.runtime.ClassBeanInfoImpl; +import java.util.logging.Level; +import java.util.logging.Logger; import org.xml.sax.Attributes; import org.xml.sax.Locator; @@ -44,6 +47,8 @@ public final class SAXConnector implements UnmarshallerHandler { private LocatorEx loc; + private static final Logger logger = Util.getClassLogger(); + /** * SAX may fire consecutive characters event, but we don't allow it. * so use this buffer to perform buffering. @@ -56,6 +61,7 @@ public final class SAXConnector implements UnmarshallerHandler { private static final class TagNameImpl extends TagName { String qname; + @Override public String getQname() { return qname; } @@ -76,6 +82,7 @@ public final class SAXConnector implements UnmarshallerHandler { this.loc = externalLocator; } + @Override public Object getResult() throws JAXBException, IllegalStateException { return context.getResult(); } @@ -84,6 +91,7 @@ public final class SAXConnector implements UnmarshallerHandler { return context; } + @Override public void setDocumentLocator(final Locator locator) { if(loc!=null) return; // we already have an external locator. ignore. @@ -91,23 +99,43 @@ public final class SAXConnector implements UnmarshallerHandler { this.loc = new LocatorExWrapper(locator); } + @Override public void startDocument() throws SAXException { + if (logger.isLoggable(Level.FINER)) { + logger.log(Level.FINER, "SAXConnector.startDocument"); + } next.startDocument(loc,null); } + @Override public void endDocument() throws SAXException { + if (logger.isLoggable(Level.FINER)) { + logger.log(Level.FINER, "SAXConnector.endDocument"); + } next.endDocument(); } + @Override public void startPrefixMapping(String prefix, String uri) throws SAXException { + if (logger.isLoggable(Level.FINER)) { + logger.log(Level.FINER, "SAXConnector.startPrefixMapping: {0}:{1}", new Object[]{prefix, uri}); + } next.startPrefixMapping(prefix,uri); } + @Override public void endPrefixMapping(String prefix) throws SAXException { + if (logger.isLoggable(Level.FINER)) { + logger.log(Level.FINER, "SAXConnector.endPrefixMapping: {0}", new Object[]{prefix}); + } next.endPrefixMapping(prefix); } + @Override public void startElement(String uri, String local, String qname, Attributes atts) throws SAXException { + if (logger.isLoggable(Level.FINER)) { + logger.log(Level.FINER, "SAXConnector.startElement: {0}:{1}:{2}, attrs: {3}", new Object[]{uri, local, qname, atts}); + } // work gracefully with misconfigured parsers that don't support namespaces if( uri==null || uri.length()==0 ) uri=""; @@ -135,7 +163,11 @@ public final class SAXConnector implements UnmarshallerHandler { next.startElement(tagName); } + @Override public void endElement(String uri, String localName, String qName) throws SAXException { + if (logger.isLoggable(Level.FINER)) { + logger.log(Level.FINER, "SAXConnector.startElement: {0}:{1}:{2}", new Object[]{uri, localName, qName}); + } processText(false); tagName.uri = uri; tagName.local = localName; @@ -144,19 +176,29 @@ public final class SAXConnector implements UnmarshallerHandler { } + @Override public final void characters( char[] buf, int start, int len ) { + if (logger.isLoggable(Level.FINEST)) { + logger.log(Level.FINEST, "SAXConnector.characters: {0}", buf); + } if( predictor.expectText() ) buffer.append(buf,start,len); } + @Override public final void ignorableWhitespace( char[] buf, int start, int len ) { + if (logger.isLoggable(Level.FINEST)) { + logger.log(Level.FINEST, "SAXConnector.characters{0}", buf); + } characters(buf,start,len); } + @Override public void processingInstruction(String target, String data) { // nop } + @Override public void skippedEntity(String name) { // nop } diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/unmarshaller/UnmarshallingContext.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/unmarshaller/UnmarshallingContext.java index 7362acc68c0..35519196193 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/unmarshaller/UnmarshallingContext.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/unmarshaller/UnmarshallingContext.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,6 +35,8 @@ import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.concurrent.Callable; +import java.util.logging.Level; +import java.util.logging.Logger; import javax.xml.XMLConstants; import javax.xml.bind.JAXBElement; @@ -51,6 +53,7 @@ import com.sun.istack.internal.NotNull; import com.sun.istack.internal.Nullable; import com.sun.istack.internal.SAXParseException2; import com.sun.xml.internal.bind.IDResolver; +import com.sun.xml.internal.bind.Util; import com.sun.xml.internal.bind.api.AccessorException; import com.sun.xml.internal.bind.api.ClassResolver; import com.sun.xml.internal.bind.unmarshaller.InfosetScanner; @@ -59,6 +62,8 @@ import com.sun.xml.internal.bind.v2.runtime.AssociationMap; import com.sun.xml.internal.bind.v2.runtime.Coordinator; import com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl; import com.sun.xml.internal.bind.v2.runtime.JaxBeanInfo; +import java.util.logging.Level; +import java.util.logging.Logger; import org.xml.sax.ErrorHandler; import org.xml.sax.SAXException; @@ -76,6 +81,8 @@ import org.xml.sax.helpers.LocatorImpl; public final class UnmarshallingContext extends Coordinator implements NamespaceContext, ValidationEventHandler, ErrorHandler, XmlVisitor, XmlVisitor.TextPredictor { + private static final Logger logger = Logger.getLogger(UnmarshallingContext.class.getName()); + /** * Root state. */ @@ -176,6 +183,14 @@ public final class UnmarshallingContext extends Coordinator */ public @Nullable ClassLoader classLoader; + /** + * The variable introduced to avoid reporting n^10 similar errors. + * After error is reported counter is decremented. When it became 0 - errors should not be reported any more. + * + * volatile is required to ensure that concurrent threads will see changed value + */ + private static volatile int errorsCounter = 10; + /** * State information for each element. */ @@ -260,21 +275,32 @@ public final class UnmarshallingContext extends Coordinator return UnmarshallingContext.this; } + @SuppressWarnings("LeakingThisInConstructor") private State(State prev) { this.prev = prev; - if(prev!=null) + if (prev!=null) { prev.next = this; + } } private void push() { - if(next==null) + if (logger.isLoggable(Level.FINEST)) { + logger.log(Level.FINEST, "State.push"); + } + if (next==null) { + assert current == this; allocateMoreStates(); + } + nil = false; State n = next; n.numNsDecl = nsLen; current = n; } private void pop() { + if (logger.isLoggable(Level.FINEST)) { + logger.log(Level.FINEST, "State.pop"); + } assert prev!=null; loader = null; nil = false; @@ -381,8 +407,9 @@ public final class UnmarshallingContext extends Coordinator assert current.next==null; State s = current; - for( int i=0; i<8; i++ ) + for (int i=0; i<8; i++) { s = new State(s); + } } public void clearStates() { @@ -436,6 +463,7 @@ public final class UnmarshallingContext extends Coordinator } } + @Override public void startDocument(LocatorEx locator, NamespaceContext nsContext) throws SAXException { if(locator!=null) this.locator = locator; @@ -449,8 +477,6 @@ public final class UnmarshallingContext extends Coordinator isUnmarshalInProgress = true; nsLen=0; - setThreadAffinity(); - if(expectedType!=null) root.loader = EXPECTED_TYPE_ROOT_LOADER; else @@ -459,6 +485,7 @@ public final class UnmarshallingContext extends Coordinator idResolver.startDocument(this); } + @Override public void startElement(TagName tagName) throws SAXException { pushCoordinator(); try { @@ -486,6 +513,7 @@ public final class UnmarshallingContext extends Coordinator current.loader.startElement(current,tagName); } + @Override public void text(CharSequence pcdata) throws SAXException { State cur = current; pushCoordinator(); @@ -502,6 +530,7 @@ public final class UnmarshallingContext extends Coordinator } } + @Override public final void endElement(TagName tagName) throws SAXException { pushCoordinator(); try { @@ -526,6 +555,7 @@ public final class UnmarshallingContext extends Coordinator } } + @Override public void endDocument() throws SAXException { runPatchers(); idResolver.endDocument(); @@ -537,14 +567,13 @@ public final class UnmarshallingContext extends Coordinator // at the successful completion, scope must be all closed assert root==current; - - resetThreadAffinity(); } /** * You should be always calling this through {@link TextPredictor}. */ @Deprecated + @Override public boolean expectText() { return current.loader.expectText; } @@ -553,10 +582,12 @@ public final class UnmarshallingContext extends Coordinator * You should be always getting {@link TextPredictor} from {@link XmlVisitor}. */ @Deprecated + @Override public TextPredictor getPredictor() { return this; } + @Override public UnmarshallingContext getContext() { return this; } @@ -650,6 +681,7 @@ public final class UnmarshallingContext extends Coordinator event.getLinkedException() ) ); } + @Override public boolean handleEvent(ValidationEvent event) { try { // if the handler says "abort", we will not return the object. @@ -680,6 +712,7 @@ public final class UnmarshallingContext extends Coordinator handleEvent(new ValidationEventImpl(ValidationEvent.ERROR,msg,locator.getLocation())); } + @Override protected ValidationEventLocator getLocation() { return locator.getLocation(); } @@ -801,6 +834,7 @@ public final class UnmarshallingContext extends Coordinator private String[] nsBind = new String[16]; private int nsLen=0; + @Override public void startPrefixMapping( String prefix, String uri ) { if(nsBind.length==nsLen) { // expand the buffer @@ -811,6 +845,7 @@ public final class UnmarshallingContext extends Coordinator nsBind[nsLen++] = prefix; nsBind[nsLen++] = uri; } + @Override public void endPrefixMapping( String prefix ) { nsLen-=2; } @@ -868,6 +903,7 @@ public final class UnmarshallingContext extends Coordinator // NamespaceContext2 implementation // + @Override public Iterator getPrefixes(String uri) { // TODO: could be implemented much faster // wrap it into unmodifiable list so that the remove method @@ -899,6 +935,7 @@ public final class UnmarshallingContext extends Coordinator return a; } + @Override public String getPrefix(String uri) { if( uri==null ) throw new IllegalArgumentException(); @@ -919,6 +956,7 @@ public final class UnmarshallingContext extends Coordinator return null; } + @Override public String getNamespaceURI(String prefix) { if (prefix == null) throw new IllegalArgumentException(); @@ -1059,6 +1097,7 @@ public final class UnmarshallingContext extends Coordinator return getInstance().getJAXBContext().getValidRootNames(); } + @Override public void receive(State state, Object o) { if(state.backup!=null) { ((JAXBElement)state.backup).setValue(o); @@ -1095,6 +1134,7 @@ public final class UnmarshallingContext extends Coordinator state.loader = new XsiNilLoader(context.expectedType.getLoader(null,true)); } + @Override public void receive(State state, Object o) { JAXBElement e = (JAXBElement)state.target; e.setValue(o); @@ -1233,4 +1273,27 @@ public final class UnmarshallingContext extends Coordinator return null; } + /** + * Based on current {@link Logger} {@link Level} and errorCounter value determines if error should be reported. + * + * If the method called and return true it is expected that error will be reported. And that's why + * errorCounter is automatically decremented during the check. + * + * NOT THREAD SAFE!!! In case of heave concurrency access several additional errors could be reported. It's not expected to be the + * problem. Otherwise add synchronization here. + * + * @return true in case if {@link Level#FINEST} is set OR we haven't exceed errors reporting limit. + */ + public boolean shouldErrorBeReported() throws SAXException { + if (logger.isLoggable(Level.FINEST)) + return true; + + if (errorsCounter >= 0) { + --errorsCounter; + if (errorsCounter == 0) // it's possible to miss this because of concurrency. If required add synchronization here + handleEvent(new ValidationEventImpl(ValidationEvent.WARNING, Messages.ERRORS_LIMIT_EXCEEDED.format(), + getLocator().getLocation(), null), true); + } + return errorsCounter >= 0; + } } diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/unmarshaller/XsiTypeLoader.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/unmarshaller/XsiTypeLoader.java index b577c3c498f..f35a3f521ea 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/unmarshaller/XsiTypeLoader.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/unmarshaller/XsiTypeLoader.java @@ -92,12 +92,15 @@ public class XsiTypeLoader extends Loader { return defaultBeanInfo; beanInfo = context.getJAXBContext().getGlobalType(type); - if(beanInfo==null) { - String nearest = context.getJAXBContext().getNearestTypeName(type); - if(nearest!=null) - reportError(Messages.UNRECOGNIZED_TYPE_NAME_MAYBE.format(type,nearest),true); - else - reportError(Messages.UNRECOGNIZED_TYPE_NAME.format(type),true); + if(beanInfo==null) { // let's report an error + if (context.parent.hasEventHandler() // is somebody listening? + && context.shouldErrorBeReported()) { // should we report error? + String nearest = context.getJAXBContext().getNearestTypeName(type); + if(nearest!=null) + reportError(Messages.UNRECOGNIZED_TYPE_NAME_MAYBE.format(type,nearest),true); + else + reportError(Messages.UNRECOGNIZED_TYPE_NAME.format(type),true); + } } // TODO: resurrect the following check // else diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/Annotated.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/Annotated.java index 4b9165cd9b1..c60dde2d321 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/Annotated.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/Annotated.java @@ -29,6 +29,11 @@ import com.sun.xml.internal.txw2.TypedXmlWriter; import com.sun.xml.internal.txw2.annotation.XmlAttribute; import com.sun.xml.internal.txw2.annotation.XmlElement; +/** + *

    + * Auto-generated, do not edit. + *

    + */ public interface Annotated extends TypedXmlWriter { diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/Annotation.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/Annotation.java index 75c93a82f1b..795f12573f6 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/Annotation.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/Annotation.java @@ -29,6 +29,11 @@ import com.sun.xml.internal.txw2.TypedXmlWriter; import com.sun.xml.internal.txw2.annotation.XmlAttribute; import com.sun.xml.internal.txw2.annotation.XmlElement; +/** + *

    + * Auto-generated, do not edit. + *

    + */ @XmlElement("annotation") public interface Annotation extends TypedXmlWriter diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/Any.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/Any.java index 6765b2d61c5..7df5329c0cb 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/Any.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/Any.java @@ -28,6 +28,11 @@ package com.sun.xml.internal.bind.v2.schemagen.xmlschema; import com.sun.xml.internal.txw2.TypedXmlWriter; import com.sun.xml.internal.txw2.annotation.XmlElement; +/** + *

    + * Auto-generated, do not edit. + *

    + */ @XmlElement("any") public interface Any extends Occurs, Wildcard, TypedXmlWriter diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/Appinfo.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/Appinfo.java index 028d505219b..b31d3092b37 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/Appinfo.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/Appinfo.java @@ -29,6 +29,11 @@ import com.sun.xml.internal.txw2.TypedXmlWriter; import com.sun.xml.internal.txw2.annotation.XmlAttribute; import com.sun.xml.internal.txw2.annotation.XmlElement; +/** + *

    + * Auto-generated, do not edit. + *

    + */ @XmlElement("appinfo") public interface Appinfo extends TypedXmlWriter diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/AttrDecls.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/AttrDecls.java index 633ccad8c78..53c7ec260bb 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/AttrDecls.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/AttrDecls.java @@ -28,6 +28,11 @@ package com.sun.xml.internal.bind.v2.schemagen.xmlschema; import com.sun.xml.internal.txw2.TypedXmlWriter; import com.sun.xml.internal.txw2.annotation.XmlElement; +/** + *

    + * Auto-generated, do not edit. + *

    + */ public interface AttrDecls extends TypedXmlWriter { diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/AttributeType.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/AttributeType.java index 1a0169d70e2..4e0e2f6ce75 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/AttributeType.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/AttributeType.java @@ -29,6 +29,11 @@ import javax.xml.namespace.QName; import com.sun.xml.internal.txw2.TypedXmlWriter; import com.sun.xml.internal.txw2.annotation.XmlAttribute; +/** + *

    + * Auto-generated, do not edit. + *

    + */ public interface AttributeType extends SimpleTypeHost, TypedXmlWriter { diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/ComplexContent.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/ComplexContent.java index 27e826e0f71..33eddd83397 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/ComplexContent.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/ComplexContent.java @@ -29,6 +29,11 @@ import com.sun.xml.internal.txw2.TypedXmlWriter; import com.sun.xml.internal.txw2.annotation.XmlAttribute; import com.sun.xml.internal.txw2.annotation.XmlElement; +/** + *

    + * Auto-generated, do not edit. + *

    + */ @XmlElement("complexContent") public interface ComplexContent extends Annotated, TypedXmlWriter diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/ComplexExtension.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/ComplexExtension.java index c80b11ce90e..b141601dd0c 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/ComplexExtension.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/ComplexExtension.java @@ -28,6 +28,11 @@ package com.sun.xml.internal.bind.v2.schemagen.xmlschema; import com.sun.xml.internal.txw2.TypedXmlWriter; import com.sun.xml.internal.txw2.annotation.XmlElement; +/** + *

    + * Auto-generated, do not edit. + *

    + */ @XmlElement("extension") public interface ComplexExtension extends AttrDecls, ExtensionType, TypeDefParticle, TypedXmlWriter diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/ComplexRestriction.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/ComplexRestriction.java index d08f1157c6e..7919fc43885 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/ComplexRestriction.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/ComplexRestriction.java @@ -30,6 +30,11 @@ import com.sun.xml.internal.txw2.TypedXmlWriter; import com.sun.xml.internal.txw2.annotation.XmlAttribute; import com.sun.xml.internal.txw2.annotation.XmlElement; +/** + *

    + * Auto-generated, do not edit. + *

    + */ @XmlElement("restriction") public interface ComplexRestriction extends Annotated, AttrDecls, TypeDefParticle, TypedXmlWriter diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/ComplexType.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/ComplexType.java index 23b7a2802c2..cda5e014879 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/ComplexType.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/ComplexType.java @@ -29,24 +29,29 @@ import com.sun.xml.internal.txw2.TypedXmlWriter; import com.sun.xml.internal.txw2.annotation.XmlAttribute; import com.sun.xml.internal.txw2.annotation.XmlElement; +/** + *

    + * Auto-generated, do not edit. + *

    + */ @XmlElement("complexType") public interface ComplexType extends Annotated, ComplexTypeModel, TypedXmlWriter { - @XmlAttribute("final") - public ComplexType _final(String value); - @XmlAttribute("final") public ComplexType _final(String[] value); - @XmlAttribute - public ComplexType block(String value); + @XmlAttribute("final") + public ComplexType _final(String value); @XmlAttribute public ComplexType block(String[] value); + @XmlAttribute + public ComplexType block(String value); + @XmlAttribute("abstract") public ComplexType _abstract(boolean value); diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/ComplexTypeHost.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/ComplexTypeHost.java index 3ac98c52239..e0d02068e77 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/ComplexTypeHost.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/ComplexTypeHost.java @@ -28,6 +28,11 @@ package com.sun.xml.internal.bind.v2.schemagen.xmlschema; import com.sun.xml.internal.txw2.TypedXmlWriter; import com.sun.xml.internal.txw2.annotation.XmlElement; +/** + *

    + * Auto-generated, do not edit. + *

    + */ public interface ComplexTypeHost extends TypeHost, TypedXmlWriter { diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/ComplexTypeModel.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/ComplexTypeModel.java index afdcf0da125..dc8493ca6c5 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/ComplexTypeModel.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/ComplexTypeModel.java @@ -29,6 +29,11 @@ import com.sun.xml.internal.txw2.TypedXmlWriter; import com.sun.xml.internal.txw2.annotation.XmlAttribute; import com.sun.xml.internal.txw2.annotation.XmlElement; +/** + *

    + * Auto-generated, do not edit. + *

    + */ public interface ComplexTypeModel extends AttrDecls, TypeDefParticle, TypedXmlWriter { diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/Documentation.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/Documentation.java index 7661cc53b6c..f8abb212326 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/Documentation.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/Documentation.java @@ -29,6 +29,11 @@ import com.sun.xml.internal.txw2.TypedXmlWriter; import com.sun.xml.internal.txw2.annotation.XmlAttribute; import com.sun.xml.internal.txw2.annotation.XmlElement; +/** + *

    + * Auto-generated, do not edit. + *

    + */ @XmlElement("documentation") public interface Documentation extends TypedXmlWriter diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/Element.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/Element.java index 20e2e91bb41..29ea473a34b 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/Element.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/Element.java @@ -29,6 +29,11 @@ import javax.xml.namespace.QName; import com.sun.xml.internal.txw2.TypedXmlWriter; import com.sun.xml.internal.txw2.annotation.XmlAttribute; +/** + *

    + * Auto-generated, do not edit. + *

    + */ public interface Element extends Annotated, ComplexTypeHost, FixedOrDefault, SimpleTypeHost, TypedXmlWriter { @@ -38,10 +43,10 @@ public interface Element public Element type(QName value); @XmlAttribute - public Element block(String value); + public Element block(String[] value); @XmlAttribute - public Element block(String[] value); + public Element block(String value); @XmlAttribute public Element nillable(boolean value); diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/ExplicitGroup.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/ExplicitGroup.java index b8a83d574ff..60b324a9655 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/ExplicitGroup.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/ExplicitGroup.java @@ -27,6 +27,11 @@ package com.sun.xml.internal.bind.v2.schemagen.xmlschema; import com.sun.xml.internal.txw2.TypedXmlWriter; +/** + *

    + * Auto-generated, do not edit. + *

    + */ public interface ExplicitGroup extends Annotated, NestedParticle, Occurs, TypedXmlWriter { diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/ExtensionType.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/ExtensionType.java index 13da8c041a1..145fcb6f55f 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/ExtensionType.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/ExtensionType.java @@ -29,6 +29,11 @@ import javax.xml.namespace.QName; import com.sun.xml.internal.txw2.TypedXmlWriter; import com.sun.xml.internal.txw2.annotation.XmlAttribute; +/** + *

    + * Auto-generated, do not edit. + *

    + */ public interface ExtensionType extends Annotated, TypedXmlWriter { diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/FixedOrDefault.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/FixedOrDefault.java index 74a2007f767..5e47900a3c4 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/FixedOrDefault.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/FixedOrDefault.java @@ -28,6 +28,11 @@ package com.sun.xml.internal.bind.v2.schemagen.xmlschema; import com.sun.xml.internal.txw2.TypedXmlWriter; import com.sun.xml.internal.txw2.annotation.XmlAttribute; +/** + *

    + * Auto-generated, do not edit. + *

    + */ public interface FixedOrDefault extends TypedXmlWriter { diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/Import.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/Import.java index ac5a24ca9e1..d842c031d10 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/Import.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/Import.java @@ -29,6 +29,11 @@ import com.sun.xml.internal.txw2.TypedXmlWriter; import com.sun.xml.internal.txw2.annotation.XmlAttribute; import com.sun.xml.internal.txw2.annotation.XmlElement; +/** + *

    + * Auto-generated, do not edit. + *

    + */ @XmlElement("import") public interface Import extends Annotated, TypedXmlWriter diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/List.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/List.java index 93517581d48..8cf2dafb1f2 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/List.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/List.java @@ -30,6 +30,11 @@ import com.sun.xml.internal.txw2.TypedXmlWriter; import com.sun.xml.internal.txw2.annotation.XmlAttribute; import com.sun.xml.internal.txw2.annotation.XmlElement; +/** + *

    + * Auto-generated, do not edit. + *

    + */ @XmlElement("list") public interface List extends Annotated, SimpleTypeHost, TypedXmlWriter diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/LocalAttribute.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/LocalAttribute.java index 4cde3d0f4e2..6aab764d384 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/LocalAttribute.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/LocalAttribute.java @@ -30,6 +30,11 @@ import com.sun.xml.internal.txw2.TypedXmlWriter; import com.sun.xml.internal.txw2.annotation.XmlAttribute; import com.sun.xml.internal.txw2.annotation.XmlElement; +/** + *

    + * Auto-generated, do not edit. + *

    + */ @XmlElement("attribute") public interface LocalAttribute extends Annotated, AttributeType, FixedOrDefault, TypedXmlWriter diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/LocalElement.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/LocalElement.java index ef28b4539e5..277b127f7ab 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/LocalElement.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/LocalElement.java @@ -30,6 +30,11 @@ import com.sun.xml.internal.txw2.TypedXmlWriter; import com.sun.xml.internal.txw2.annotation.XmlAttribute; import com.sun.xml.internal.txw2.annotation.XmlElement; +/** + *

    + * Auto-generated, do not edit. + *

    + */ @XmlElement("element") public interface LocalElement extends Element, Occurs, TypedXmlWriter diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/NestedParticle.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/NestedParticle.java index f3a467279f3..3a03e478558 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/NestedParticle.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/NestedParticle.java @@ -28,6 +28,11 @@ package com.sun.xml.internal.bind.v2.schemagen.xmlschema; import com.sun.xml.internal.txw2.TypedXmlWriter; import com.sun.xml.internal.txw2.annotation.XmlElement; +/** + *

    + * Auto-generated, do not edit. + *

    + */ public interface NestedParticle extends TypedXmlWriter { diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/NoFixedFacet.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/NoFixedFacet.java index 8e4f91a22d7..0f357fa431b 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/NoFixedFacet.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/NoFixedFacet.java @@ -28,6 +28,11 @@ package com.sun.xml.internal.bind.v2.schemagen.xmlschema; import com.sun.xml.internal.txw2.TypedXmlWriter; import com.sun.xml.internal.txw2.annotation.XmlAttribute; +/** + *

    + * Auto-generated, do not edit. + *

    + */ public interface NoFixedFacet extends Annotated, TypedXmlWriter { diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/Occurs.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/Occurs.java index eab4228a471..a1a06dca0f4 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/Occurs.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/Occurs.java @@ -28,6 +28,11 @@ package com.sun.xml.internal.bind.v2.schemagen.xmlschema; import com.sun.xml.internal.txw2.TypedXmlWriter; import com.sun.xml.internal.txw2.annotation.XmlAttribute; +/** + *

    + * Auto-generated, do not edit. + *

    + */ public interface Occurs extends TypedXmlWriter { @@ -36,10 +41,10 @@ public interface Occurs @XmlAttribute public Occurs minOccurs(int value); - @XmlAttribute - public Occurs maxOccurs(int value); - @XmlAttribute public Occurs maxOccurs(String value); + @XmlAttribute + public Occurs maxOccurs(int value); + } diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/Redefinable.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/Redefinable.java index 0b1e3795512..6f1efab7180 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/Redefinable.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/Redefinable.java @@ -27,6 +27,11 @@ package com.sun.xml.internal.bind.v2.schemagen.xmlschema; import com.sun.xml.internal.txw2.TypedXmlWriter; +/** + *

    + * Auto-generated, do not edit. + *

    + */ public interface Redefinable extends ComplexTypeHost, SimpleTypeHost, TypedXmlWriter { diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/Schema.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/Schema.java index f5dd58071c0..d69edfffe8b 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/Schema.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/Schema.java @@ -29,6 +29,11 @@ import com.sun.xml.internal.txw2.TypedXmlWriter; import com.sun.xml.internal.txw2.annotation.XmlAttribute; import com.sun.xml.internal.txw2.annotation.XmlElement; +/** + *

    + * Auto-generated, do not edit. + *

    + */ @XmlElement("schema") public interface Schema extends SchemaTop, TypedXmlWriter @@ -56,18 +61,18 @@ public interface Schema @XmlAttribute public Schema attributeFormDefault(String value); - @XmlAttribute - public Schema blockDefault(String value); - @XmlAttribute public Schema blockDefault(String[] value); @XmlAttribute - public Schema finalDefault(String value); + public Schema blockDefault(String value); @XmlAttribute public Schema finalDefault(String[] value); + @XmlAttribute + public Schema finalDefault(String value); + @XmlAttribute public Schema version(String value); diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/SchemaTop.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/SchemaTop.java index 4f081655d28..636aa26964b 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/SchemaTop.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/SchemaTop.java @@ -28,6 +28,11 @@ package com.sun.xml.internal.bind.v2.schemagen.xmlschema; import com.sun.xml.internal.txw2.TypedXmlWriter; import com.sun.xml.internal.txw2.annotation.XmlElement; +/** + *

    + * Auto-generated, do not edit. + *

    + */ public interface SchemaTop extends Redefinable, TypedXmlWriter { diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/SimpleContent.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/SimpleContent.java index aa97834c847..b8c4d680f0c 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/SimpleContent.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/SimpleContent.java @@ -28,6 +28,11 @@ package com.sun.xml.internal.bind.v2.schemagen.xmlschema; import com.sun.xml.internal.txw2.TypedXmlWriter; import com.sun.xml.internal.txw2.annotation.XmlElement; +/** + *

    + * Auto-generated, do not edit. + *

    + */ @XmlElement("simpleContent") public interface SimpleContent extends Annotated, TypedXmlWriter diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/SimpleDerivation.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/SimpleDerivation.java index 6750c8ba937..9f5eed6d56b 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/SimpleDerivation.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/SimpleDerivation.java @@ -28,6 +28,11 @@ package com.sun.xml.internal.bind.v2.schemagen.xmlschema; import com.sun.xml.internal.txw2.TypedXmlWriter; import com.sun.xml.internal.txw2.annotation.XmlElement; +/** + *

    + * Auto-generated, do not edit. + *

    + */ public interface SimpleDerivation extends TypedXmlWriter { diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/SimpleExtension.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/SimpleExtension.java index aad7b63beaf..5ee557f699b 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/SimpleExtension.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/SimpleExtension.java @@ -28,6 +28,11 @@ package com.sun.xml.internal.bind.v2.schemagen.xmlschema; import com.sun.xml.internal.txw2.TypedXmlWriter; import com.sun.xml.internal.txw2.annotation.XmlElement; +/** + *

    + * Auto-generated, do not edit. + *

    + */ @XmlElement("extension") public interface SimpleExtension extends AttrDecls, ExtensionType, TypedXmlWriter diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/SimpleRestriction.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/SimpleRestriction.java index 4350e0f1513..84027ac24ec 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/SimpleRestriction.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/SimpleRestriction.java @@ -28,6 +28,11 @@ package com.sun.xml.internal.bind.v2.schemagen.xmlschema; import com.sun.xml.internal.txw2.TypedXmlWriter; import com.sun.xml.internal.txw2.annotation.XmlElement; +/** + *

    + * Auto-generated, do not edit. + *

    + */ @XmlElement("restriction") public interface SimpleRestriction extends Annotated, AttrDecls, SimpleRestrictionModel, TypedXmlWriter diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/SimpleRestrictionModel.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/SimpleRestrictionModel.java index cbcaa7ba32a..04c2d42cf79 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/SimpleRestrictionModel.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/SimpleRestrictionModel.java @@ -30,6 +30,11 @@ import com.sun.xml.internal.txw2.TypedXmlWriter; import com.sun.xml.internal.txw2.annotation.XmlAttribute; import com.sun.xml.internal.txw2.annotation.XmlElement; +/** + *

    + * Auto-generated, do not edit. + *

    + */ public interface SimpleRestrictionModel extends SimpleTypeHost, TypedXmlWriter { diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/SimpleType.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/SimpleType.java index 676aa6c68bc..2fed7d4ef6c 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/SimpleType.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/SimpleType.java @@ -29,6 +29,11 @@ import com.sun.xml.internal.txw2.TypedXmlWriter; import com.sun.xml.internal.txw2.annotation.XmlAttribute; import com.sun.xml.internal.txw2.annotation.XmlElement; +/** + *

    + * Auto-generated, do not edit. + *

    + */ @XmlElement("simpleType") public interface SimpleType extends Annotated, SimpleDerivation, TypedXmlWriter diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/SimpleTypeHost.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/SimpleTypeHost.java index b1db7aedc5f..1957ec4aa3f 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/SimpleTypeHost.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/SimpleTypeHost.java @@ -28,6 +28,11 @@ package com.sun.xml.internal.bind.v2.schemagen.xmlschema; import com.sun.xml.internal.txw2.TypedXmlWriter; import com.sun.xml.internal.txw2.annotation.XmlElement; +/** + *

    + * Auto-generated, do not edit. + *

    + */ public interface SimpleTypeHost extends TypeHost, TypedXmlWriter { diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/TopLevelAttribute.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/TopLevelAttribute.java index 18a0d59ade4..324029f3386 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/TopLevelAttribute.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/TopLevelAttribute.java @@ -29,6 +29,11 @@ import com.sun.xml.internal.txw2.TypedXmlWriter; import com.sun.xml.internal.txw2.annotation.XmlAttribute; import com.sun.xml.internal.txw2.annotation.XmlElement; +/** + *

    + * Auto-generated, do not edit. + *

    + */ @XmlElement("attribute") public interface TopLevelAttribute extends Annotated, AttributeType, FixedOrDefault, TypedXmlWriter diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/TopLevelElement.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/TopLevelElement.java index 86af9f71f95..ad737c6224f 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/TopLevelElement.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/TopLevelElement.java @@ -30,6 +30,11 @@ import com.sun.xml.internal.txw2.TypedXmlWriter; import com.sun.xml.internal.txw2.annotation.XmlAttribute; import com.sun.xml.internal.txw2.annotation.XmlElement; +/** + *

    + * Auto-generated, do not edit. + *

    + */ @XmlElement("element") public interface TopLevelElement extends Element, TypedXmlWriter @@ -37,10 +42,10 @@ public interface TopLevelElement @XmlAttribute("final") - public TopLevelElement _final(String value); + public TopLevelElement _final(String[] value); @XmlAttribute("final") - public TopLevelElement _final(String[] value); + public TopLevelElement _final(String value); @XmlAttribute("abstract") public TopLevelElement _abstract(boolean value); diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/TypeDefParticle.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/TypeDefParticle.java index 10b2486fc84..9b826fb075a 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/TypeDefParticle.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/TypeDefParticle.java @@ -28,6 +28,11 @@ package com.sun.xml.internal.bind.v2.schemagen.xmlschema; import com.sun.xml.internal.txw2.TypedXmlWriter; import com.sun.xml.internal.txw2.annotation.XmlElement; +/** + *

    + * Auto-generated, do not edit. + *

    + */ public interface TypeDefParticle extends TypedXmlWriter { diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/TypeHost.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/TypeHost.java index 3cbe692627b..a3443ac859b 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/TypeHost.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/TypeHost.java @@ -27,6 +27,11 @@ package com.sun.xml.internal.bind.v2.schemagen.xmlschema; import com.sun.xml.internal.txw2.TypedXmlWriter; +/** + *

    + * Auto-generated, do not edit. + *

    + */ public interface TypeHost extends TypedXmlWriter { diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/Union.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/Union.java index 5878c937266..077895db2d6 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/Union.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/Union.java @@ -30,6 +30,11 @@ import com.sun.xml.internal.txw2.TypedXmlWriter; import com.sun.xml.internal.txw2.annotation.XmlAttribute; import com.sun.xml.internal.txw2.annotation.XmlElement; +/** + *

    + * Auto-generated, do not edit. + *

    + */ @XmlElement("union") public interface Union extends Annotated, SimpleTypeHost, TypedXmlWriter diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/Wildcard.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/Wildcard.java index 1aa7c49837d..37a49e07532 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/Wildcard.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/schemagen/xmlschema/Wildcard.java @@ -28,6 +28,11 @@ package com.sun.xml.internal.bind.v2.schemagen.xmlschema; import com.sun.xml.internal.txw2.TypedXmlWriter; import com.sun.xml.internal.txw2.annotation.XmlAttribute; +/** + *

    + * Auto-generated, do not edit. + *

    + */ public interface Wildcard extends Annotated, TypedXmlWriter { diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/util/EditDistance.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/util/EditDistance.java index 36eba4d00ed..b2c82b5cd07 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/util/EditDistance.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/util/EditDistance.java @@ -25,8 +25,10 @@ package com.sun.xml.internal.bind.v2.util; -import java.util.Collection; +import java.util.AbstractMap; import java.util.Arrays; +import java.util.Collection; +import java.util.WeakHashMap; /** * Computes the string edit distance. @@ -40,6 +42,12 @@ import java.util.Arrays; */ public class EditDistance { + /** + * Weak results cache to avoid additional computations. + * Because of high complexity caching is required. + */ + private static final WeakHashMap, Integer> CACHE = new WeakHashMap, Integer>(); + /** * Computes the edit distance between two strings. * @@ -47,7 +55,17 @@ public class EditDistance { * The complexity is O(nm) where n=a.length() and m=b.length(). */ public static int editDistance( String a, String b ) { - return new EditDistance(a,b).calc(); + // let's check cache + AbstractMap.SimpleEntry entry = new AbstractMap.SimpleEntry(a, b); // using this class to avoid creation of my own which will handle PAIR of values + Integer result = null; + if (CACHE.containsKey(entry)) + result = CACHE.get(entry); // looks like we have it + + if (result == null) { + result = new EditDistance(a, b).calc(); + CACHE.put(entry, result); // cache the result + } + return result; } /** diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/util/XmlFactory.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/util/XmlFactory.java index d64a689f73f..969cf451649 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/util/XmlFactory.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/util/XmlFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -38,6 +38,8 @@ import javax.xml.transform.TransformerFactory; import javax.xml.validation.SchemaFactory; import javax.xml.xpath.XPathFactory; import javax.xml.xpath.XPathFactoryConfigurationException; + +import org.xml.sax.SAXException; import org.xml.sax.SAXNotRecognizedException; import org.xml.sax.SAXNotSupportedException; @@ -49,6 +51,9 @@ import org.xml.sax.SAXNotSupportedException; */ public class XmlFactory { + // not in older JDK, so must be duplicated here, otherwise javax.xml.XMLConstants should be used + public static final String ACCESS_EXTERNAL_SCHEMA = "http://javax.xml.XMLConstants/property/accessExternalSchema"; + private static final Logger LOGGER = Logger.getLogger(XmlFactory.class.getName()); /** @@ -186,4 +191,22 @@ public class XmlFactory { } } + public static SchemaFactory allowFileAccess(SchemaFactory sf, boolean disableSecureProcessing) { + + // if feature secure processing enabled, nothing to do, file is allowed, + // or user is able to control access by standard JAXP mechanisms + if (disableSecureProcessing) { + return sf; + } + + try { + sf.setProperty(ACCESS_EXTERNAL_SCHEMA, "file"); + LOGGER.log(Level.FINE, Messages.JAXP_SUPPORTED_PROPERTY.format(ACCESS_EXTERNAL_SCHEMA)); + } catch (SAXException ignored) { + // nothing to do; support depends on version JDK or SAX implementation + LOGGER.log(Level.CONFIG, Messages.JAXP_UNSUPPORTED_PROPERTY.format(ACCESS_EXTERNAL_SCHEMA), ignored); + } + return sf; + } + } diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/dtdparser/DTDEventListener.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/dtdparser/DTDEventListener.java index 9a94f862b68..a5f64014099 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/dtdparser/DTDEventListener.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/dtdparser/DTDEventListener.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 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 diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/dtdparser/DTDHandlerBase.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/dtdparser/DTDHandlerBase.java index 9d24fbcd957..2e7801a1685 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/dtdparser/DTDHandlerBase.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/dtdparser/DTDHandlerBase.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 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 diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/dtdparser/DTDParser.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/dtdparser/DTDParser.java index e296ef54828..68b7f6df1b7 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/dtdparser/DTDParser.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/dtdparser/DTDParser.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 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 @@ -57,7 +57,7 @@ import java.util.Vector; * @author David Brownell * @author Janet Koenig * @author Kohsuke KAWAGUCHI - * @version $Id: DTDParser.java,v 1.2 2009-04-16 15:25:49 snajper Exp $ + * @version $Id: DTDParser.java,v 1.2 2009/04/16 15:25:49 snajper Exp $ */ public class DTDParser { public final static String TYPE_CDATA = "CDATA"; @@ -215,25 +215,25 @@ public class DTDParser { */ public void parse(String uri) throws IOException, SAXException { - InputSource inSource; + InputSource in; init(); // System.out.println ("parse (\"" + uri + "\")"); - inSource = resolver.resolveEntity(null, uri); + in = resolver.resolveEntity(null, uri); // If custom resolver punts resolution to parser, handle it ... - if (inSource == null) { - inSource = Resolver.createInputSource(new java.net.URL(uri), false); + if (in == null) { + in = Resolver.createInputSource(new java.net.URL(uri), false); // ... or if custom resolver doesn't correctly construct the // input entity, patch it up enough so relative URIs work, and // issue a warning to minimize later confusion. - } else if (inSource.getSystemId() == null) { + } else if (in.getSystemId() == null) { warning("P-065", null); - inSource.setSystemId(uri); + in.setSystemId(uri); } - parseInternal(inSource); + parseInternal(in); } // makes sure the parser is reset to "before a document" diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/dtdparser/EndOfInputException.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/dtdparser/EndOfInputException.java index aa7eeae0271..a7cc5224bfa 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/dtdparser/EndOfInputException.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/dtdparser/EndOfInputException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 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 diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/dtdparser/EntityDecl.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/dtdparser/EntityDecl.java index 6c735929868..9db54f6821a 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/dtdparser/EntityDecl.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/dtdparser/EntityDecl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 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 diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/dtdparser/ExternalEntity.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/dtdparser/ExternalEntity.java index 4ab87249c73..aa396902206 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/dtdparser/ExternalEntity.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/dtdparser/ExternalEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 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 diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/dtdparser/InputEntity.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/dtdparser/InputEntity.java index c296f367c56..65a0b7bfa80 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/dtdparser/InputEntity.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/dtdparser/InputEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 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 diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/dtdparser/InternalEntity.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/dtdparser/InternalEntity.java index 1509693010f..00e125a190f 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/dtdparser/InternalEntity.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/dtdparser/InternalEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 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 diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/dtdparser/MessageCatalog.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/dtdparser/MessageCatalog.java index 5f4e8238844..7ad1e12146e 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/dtdparser/MessageCatalog.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/dtdparser/MessageCatalog.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 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 diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/dtdparser/Resolver.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/dtdparser/Resolver.java index 90b2ec3e851..ed8cbfe0134 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/dtdparser/Resolver.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/dtdparser/Resolver.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 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 diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/dtdparser/SimpleHashtable.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/dtdparser/SimpleHashtable.java index 1cf1939776b..bbe4e5fc14f 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/dtdparser/SimpleHashtable.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/dtdparser/SimpleHashtable.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 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 diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/dtdparser/XmlChars.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/dtdparser/XmlChars.java index 90d400b82ee..848ad1dd289 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/dtdparser/XmlChars.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/dtdparser/XmlChars.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 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 diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/dtdparser/XmlNames.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/dtdparser/XmlNames.java index 2f13e882fdf..5ba9f15b2b2 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/dtdparser/XmlNames.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/dtdparser/XmlNames.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 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 diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/dtdparser/XmlReader.java b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/dtdparser/XmlReader.java index 88bfeb2e144..37b6ecfefc5 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/dtdparser/XmlReader.java +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/dtdparser/XmlReader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 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 @@ -86,7 +86,7 @@ final class XmlReader extends Reader { // /** - * Constructs the reader from an input stream, auto-detecting + * Constructs the reader from an input stream, autodetecting * the encoding to use according to the heuristic specified * in the XML 1.0 recommendation. * @@ -104,7 +104,7 @@ final class XmlReader extends Reader { * * @param in the input stream from which the reader is constructed * @param encoding the IETF standard name of the encoding to use; - * if null, auto-detection is used. + * if null, autodetection is used. * @throws IOException on error, including unrecognized encoding */ public static Reader createReader(InputStream in, String encoding) diff --git a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/dtdparser/package.html b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/dtdparser/package.html index 5a61d1d361c..950d8da179b 100644 --- a/jaxws/src/share/jaxws_classes/com/sun/xml/internal/dtdparser/package.html +++ b/jaxws/src/share/jaxws_classes/com/sun/xml/internal/dtdparser/package.html @@ -1,5 +1,5 @@ KO-1!!! "+obj1.getClass().getSimpleName()+ + ".equals got NPE with a null field: "+param); + npe.printStackTrace(); + failed++; + } + + try { + obj2.equals(obj1); + System.out.println("OK-2: "+obj2.getClass().getSimpleName()+ + ".equals worked with a null field: "+param); + } catch (NullPointerException npe) { + System.out.println("--->KO-2!!! "+obj2.getClass().getSimpleName()+ + ".equals got NPE with a null field: "+param); + npe.printStackTrace(); + failed++; + } + + try { + obj1.equals(null); + obj2.equals(null); + + System.out.println("OK-3: "+obj1.getClass().getSimpleName()+ + ".equals worked with a null object."); + } catch (NullPointerException npe) { + System.out.println("--->KO-3!!! "+obj1.getClass().getSimpleName()+ + ".equals got NPE with a null object."); + npe.printStackTrace(); + failed++; + } + } +} diff --git a/jdk/test/javax/management/openmbean/OpenMBeanInfoHashCodeNPETest.java b/jdk/test/javax/management/openmbean/OpenMBeanInfoHashCodeNPETest.java new file mode 100644 index 00000000000..3c829434193 --- /dev/null +++ b/jdk/test/javax/management/openmbean/OpenMBeanInfoHashCodeNPETest.java @@ -0,0 +1,173 @@ +/* + * 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 javax.management.MBeanNotificationInfo; +import javax.management.modelmbean.DescriptorSupport; +import javax.management.openmbean.OpenMBeanAttributeInfo; +import javax.management.openmbean.OpenMBeanAttributeInfoSupport; +import javax.management.openmbean.OpenMBeanConstructorInfo; +import javax.management.openmbean.OpenMBeanConstructorInfoSupport; +import javax.management.openmbean.OpenMBeanInfo; +import javax.management.openmbean.OpenMBeanInfoSupport; +import javax.management.openmbean.OpenMBeanOperationInfo; +import javax.management.openmbean.OpenMBeanOperationInfoSupport; +import javax.management.openmbean.OpenMBeanParameterInfo; +import javax.management.openmbean.OpenMBeanParameterInfoSupport; +import javax.management.openmbean.SimpleType; + +/* + * @test + * @bug 8023529 + * @summary Test that OpenMBean*Info.hashCode do not throw NPE + * @author Shanliang JIANG + * @run clean OpenMBeanInfoHashCodeNPETest + * @run build OpenMBeanInfoHashCodeNPETest + * @run main OpenMBeanInfoHashCodeNPETest + */ +public class OpenMBeanInfoHashCodeNPETest { + private static int failed = 0; + + public static void main(String[] args) throws Exception { + System.out.println("---OpenMBeanInfoHashCodeNPETest-main ..."); + + // ---- + System.out.println("\n---Testing on OpenMBeanInfohashCodeTest..."); + OpenMBeanAttributeInfo openMBeanAttributeInfo = new OpenMBeanAttributeInfoSupport( + "name", "description", SimpleType.INTEGER, true, true, false, null, new Integer[]{1, 2, 3}); + test(openMBeanAttributeInfo, "defaultValue"); + + openMBeanAttributeInfo = new OpenMBeanAttributeInfoSupport( + "name", "description", SimpleType.INTEGER, true, true, false, 1, null); + test(openMBeanAttributeInfo, "legalValues"); + + // ---- + System.out.println("\n---Testing on OpenMBeanConstructorInfoSupport..."); + OpenMBeanConstructorInfo openMBeanConstructorInfo; + + openMBeanConstructorInfo = new OpenMBeanConstructorInfoSupport( + "name", "description", null, new DescriptorSupport()); + test(openMBeanConstructorInfo, "sigs"); + + openMBeanConstructorInfo = new OpenMBeanConstructorInfoSupport( + "name", "description", new OpenMBeanParameterInfo[]{}, null); + test(openMBeanConstructorInfo, "Descriptor"); + + // ---- + System.out.println("\n---Testing on OpenMBeanOperationInfoSupport..."); + OpenMBeanOperationInfo openMBeanOperationInfo; + + openMBeanOperationInfo = new OpenMBeanOperationInfoSupport( + "name", "description", null, SimpleType.INTEGER, 1, new DescriptorSupport()); + test(openMBeanOperationInfo, "sigs"); + + openMBeanOperationInfo = new OpenMBeanOperationInfoSupport( + "name", "description", new OpenMBeanParameterInfo[]{}, SimpleType.INTEGER, 1, null); + test(openMBeanOperationInfo, "Descriptor"); + + // ---- + System.out.println("\n---Testing on OpenMBeanParameterInfoSupport 1..."); + OpenMBeanParameterInfo openMBeanParameterInfo; + + openMBeanParameterInfo = new OpenMBeanParameterInfoSupport( + "name", "description", SimpleType.INTEGER, null, -1, 1); + test(openMBeanParameterInfo, "default value"); + + openMBeanParameterInfo = new OpenMBeanParameterInfoSupport( + "name", "description", SimpleType.INTEGER, 0, null, 1); + test(openMBeanParameterInfo, "min value"); + + openMBeanParameterInfo = new OpenMBeanParameterInfoSupport( + "name", "description", SimpleType.INTEGER, 0, -1, null); + test(openMBeanParameterInfo, "max value"); + + // ---- + System.out.println("\n---Testing on OpenMBeanParameterInfoSupport 2..."); + openMBeanParameterInfo = new OpenMBeanParameterInfoSupport( + "name", "description", SimpleType.INTEGER, 1, new Integer[]{-1, 1, 2}); + + openMBeanParameterInfo = new OpenMBeanParameterInfoSupport( + "name", "description", SimpleType.INTEGER, null, new Integer[]{-1, 1, 2}); + test(openMBeanParameterInfo, "default value"); + + openMBeanParameterInfo = new OpenMBeanParameterInfoSupport( + "name", "description", SimpleType.INTEGER, 1, null); + test(openMBeanParameterInfo, "legal values"); + + // ---- + System.out.println("\n---Testing on OpenMBeanInfoSupport..."); + String className = "toto"; + String description = "titi"; + OpenMBeanAttributeInfo[] attrInfos = new OpenMBeanAttributeInfo[]{}; + OpenMBeanConstructorInfo[] constrInfos = new OpenMBeanConstructorInfo[]{}; + OpenMBeanOperationInfo[] operaInfos = new OpenMBeanOperationInfo[]{}; + MBeanNotificationInfo[] notifInfos = new MBeanNotificationInfo[]{}; + + OpenMBeanInfo ominfo = new OpenMBeanInfoSupport(null, description, attrInfos, constrInfos, operaInfos, notifInfos); + test(ominfo, "class name"); + + ominfo = new OpenMBeanInfoSupport(className, null, attrInfos, constrInfos, operaInfos, notifInfos); + test(ominfo, "description"); + + ominfo = new OpenMBeanInfoSupport(className, description, null, constrInfos, operaInfos, notifInfos); + test(ominfo, "attrInfos"); + + ominfo = new OpenMBeanInfoSupport(className, description, attrInfos, null, operaInfos, notifInfos); + test(ominfo, "constructor infos"); + + ominfo = new OpenMBeanInfoSupport(className, description, attrInfos, constrInfos, null, notifInfos); + test(ominfo, "operation infos"); + + ominfo = new OpenMBeanInfoSupport(className, description, attrInfos, constrInfos, operaInfos, null); + test(ominfo, "notif infos"); + + if (failed > 0) { + throw new RuntimeException("Test failed: "+failed); + } else { + System.out.println("---Test: PASSED"); + } + } + + private static void test(Object obj, String param) { + try { + obj.hashCode(); + System.out.println("OK-1: "+obj.getClass().getSimpleName()+ + ".hashCode worked with a null paramer: "+param); + } catch (NullPointerException npe) { + System.out.println("--->KO-1!!! "+obj.getClass().getSimpleName()+ + ".hashCode got NPE with null paramer: "+param); + npe.printStackTrace(); + failed++; + } + + try { + obj.toString(); + System.out.println("OK-1: "+obj.getClass().getSimpleName()+ + ".toString worked with a null paramer: "+param); + } catch (NullPointerException npe) { + System.out.println("--->KO-1!!! "+obj.getClass().getSimpleName()+ + ".toString got NPE with null paramer: "+param); + npe.printStackTrace(); + failed++; + } + } +} From c138883ba101d3c900ff6a0ccce7c3729ef59de8 Mon Sep 17 00:00:00 2001 From: Joe Darcy Date: Thu, 12 Sep 2013 01:47:05 -0700 Subject: [PATCH 210/218] 8024643: Turn on javac lint checking in building the jdk repo Reviewed-by: erikj, ihse, smarks --- jdk/makefiles/Setup.gmk | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/jdk/makefiles/Setup.gmk b/jdk/makefiles/Setup.gmk index 8012e547b55..4da575fed1a 100644 --- a/jdk/makefiles/Setup.gmk +++ b/jdk/makefiles/Setup.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 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 @@ -25,6 +25,10 @@ DISABLE_WARNINGS:=-Xlint:all,-deprecation,-unchecked,-rawtypes,-cast,-serial,-dep-ann,-static,-fallthrough,-try,-varargs,-empty,-finally +# To build with all warnings enabled, do the following: +# make JAVAC_WARNINGS="-Xlint:all -Xmaxwarns 10000" +JAVAC_WARNINGS:=-Xlint:-unchecked,-deprecation,-overrides,classfile,dep-ann,divzero,varargs -Werror + # The generate old bytecode javac setup uses the new compiler to compile for the # boot jdk to generate tools that need to be run with the boot jdk. # Thus we force the target bytecode to 7. @@ -41,7 +45,7 @@ $(eval $(call SetupJavaCompiler,GENERATE_JDKBYTECODE,\ JVM:=$(JAVA),\ JAVAC:=$(NEW_JAVAC),\ FLAGS:=-bootclasspath $(JDK_OUTPUTDIR)/classes -source 8 -target 8 \ - -encoding ascii -XDignore.symbol.file=true $(DISABLE_WARNINGS) \ + -encoding ascii -XDignore.symbol.file=true $(JAVAC_WARNINGS) \ $(GENERATE_JDKBYTECODE_EXTRA_FLAGS),\ SERVER_DIR:=$(SJAVAC_SERVER_DIR),\ SERVER_JVM:=$(SJAVAC_SERVER_JAVA))) From f0317e41c1e0fb4abb5863b64db477e7b3230a53 Mon Sep 17 00:00:00 2001 From: Daniel Fuchs Date: Thu, 12 Sep 2013 17:01:39 +0200 Subject: [PATCH 211/218] 8024525: Make Logger log methods call isLoggable() This changeset makes the various Logger logging method call isLoggable() instead of inlining the level checks. Reviewed-by: mchung, alanb --- .../classes/java/util/logging/Logger.java | 77 +-- .../Logger/isLoggable/TestIsLoggable.java | 512 ++++++++++++++++++ 2 files changed, 532 insertions(+), 57 deletions(-) create mode 100644 jdk/test/java/util/logging/Logger/isLoggable/TestIsLoggable.java diff --git a/jdk/src/share/classes/java/util/logging/Logger.java b/jdk/src/share/classes/java/util/logging/Logger.java index 1393ba2aa0d..19e31352c43 100644 --- a/jdk/src/share/classes/java/util/logging/Logger.java +++ b/jdk/src/share/classes/java/util/logging/Logger.java @@ -635,7 +635,7 @@ public class Logger { * @param record the LogRecord to be published */ public void log(LogRecord record) { - if (record.getLevel().intValue() < levelValue || levelValue == offValue) { + if (!isLoggable(record.getLevel())) { return; } Filter theFilter = filter; @@ -689,7 +689,7 @@ public class Logger { * @param msg The string message (or a key in the message catalog) */ public void log(Level level, String msg) { - if (level.intValue() < levelValue || levelValue == offValue) { + if (!isLoggable(level)) { return; } LogRecord lr = new LogRecord(level, msg); @@ -710,7 +710,7 @@ public class Logger { * desired log message */ public void log(Level level, Supplier msgSupplier) { - if (level.intValue() < levelValue || levelValue == offValue) { + if (!isLoggable(level)) { return; } LogRecord lr = new LogRecord(level, msgSupplier.get()); @@ -729,7 +729,7 @@ public class Logger { * @param param1 parameter to the message */ public void log(Level level, String msg, Object param1) { - if (level.intValue() < levelValue || levelValue == offValue) { + if (!isLoggable(level)) { return; } LogRecord lr = new LogRecord(level, msg); @@ -750,7 +750,7 @@ public class Logger { * @param params array of parameters to the message */ public void log(Level level, String msg, Object params[]) { - if (level.intValue() < levelValue || levelValue == offValue) { + if (!isLoggable(level)) { return; } LogRecord lr = new LogRecord(level, msg); @@ -775,7 +775,7 @@ public class Logger { * @param thrown Throwable associated with log message. */ public void log(Level level, String msg, Throwable thrown) { - if (level.intValue() < levelValue || levelValue == offValue) { + if (!isLoggable(level)) { return; } LogRecord lr = new LogRecord(level, msg); @@ -803,7 +803,7 @@ public class Logger { * @since 1.8 */ public void log(Level level, Throwable thrown, Supplier msgSupplier) { - if (level.intValue() < levelValue || levelValue == offValue) { + if (!isLoggable(level)) { return; } LogRecord lr = new LogRecord(level, msgSupplier.get()); @@ -829,7 +829,7 @@ public class Logger { * @param msg The string message (or a key in the message catalog) */ public void logp(Level level, String sourceClass, String sourceMethod, String msg) { - if (level.intValue() < levelValue || levelValue == offValue) { + if (!isLoggable(level)) { return; } LogRecord lr = new LogRecord(level, msg); @@ -856,7 +856,7 @@ public class Logger { */ public void logp(Level level, String sourceClass, String sourceMethod, Supplier msgSupplier) { - if (level.intValue() < levelValue || levelValue == offValue) { + if (!isLoggable(level)) { return; } LogRecord lr = new LogRecord(level, msgSupplier.get()); @@ -881,7 +881,7 @@ public class Logger { */ public void logp(Level level, String sourceClass, String sourceMethod, String msg, Object param1) { - if (level.intValue() < levelValue || levelValue == offValue) { + if (!isLoggable(level)) { return; } LogRecord lr = new LogRecord(level, msg); @@ -908,7 +908,7 @@ public class Logger { */ public void logp(Level level, String sourceClass, String sourceMethod, String msg, Object params[]) { - if (level.intValue() < levelValue || levelValue == offValue) { + if (!isLoggable(level)) { return; } LogRecord lr = new LogRecord(level, msg); @@ -939,7 +939,7 @@ public class Logger { */ public void logp(Level level, String sourceClass, String sourceMethod, String msg, Throwable thrown) { - if (level.intValue() < levelValue || levelValue == offValue) { + if (!isLoggable(level)) { return; } LogRecord lr = new LogRecord(level, msg); @@ -973,7 +973,7 @@ public class Logger { */ public void logp(Level level, String sourceClass, String sourceMethod, Throwable thrown, Supplier msgSupplier) { - if (level.intValue() < levelValue || levelValue == offValue) { + if (!isLoggable(level)) { return; } LogRecord lr = new LogRecord(level, msgSupplier.get()); @@ -1021,7 +1021,7 @@ public class Logger { */ public void logrb(Level level, String sourceClass, String sourceMethod, String bundleName, String msg) { - if (level.intValue() < levelValue || levelValue == offValue) { + if (!isLoggable(level)) { return; } LogRecord lr = new LogRecord(level, msg); @@ -1052,7 +1052,7 @@ public class Logger { */ public void logrb(Level level, String sourceClass, String sourceMethod, String bundleName, String msg, Object param1) { - if (level.intValue() < levelValue || levelValue == offValue) { + if (!isLoggable(level)) { return; } LogRecord lr = new LogRecord(level, msg); @@ -1085,7 +1085,7 @@ public class Logger { */ public void logrb(Level level, String sourceClass, String sourceMethod, String bundleName, String msg, Object params[]) { - if (level.intValue() < levelValue || levelValue == offValue) { + if (!isLoggable(level)) { return; } LogRecord lr = new LogRecord(level, msg); @@ -1122,7 +1122,7 @@ public class Logger { */ public void logrb(Level level, String sourceClass, String sourceMethod, String bundleName, String msg, Throwable thrown) { - if (level.intValue() < levelValue || levelValue == offValue) { + if (!isLoggable(level)) { return; } LogRecord lr = new LogRecord(level, msg); @@ -1148,9 +1148,6 @@ public class Logger { * @param sourceMethod name of method that is being entered */ public void entering(String sourceClass, String sourceMethod) { - if (Level.FINER.intValue() < levelValue) { - return; - } logp(Level.FINER, sourceClass, sourceMethod, "ENTRY"); } @@ -1167,11 +1164,7 @@ public class Logger { * @param param1 parameter to the method being entered */ public void entering(String sourceClass, String sourceMethod, Object param1) { - if (Level.FINER.intValue() < levelValue) { - return; - } - Object params[] = { param1 }; - logp(Level.FINER, sourceClass, sourceMethod, "ENTRY {0}", params); + logp(Level.FINER, sourceClass, sourceMethod, "ENTRY {0}", param1); } /** @@ -1188,14 +1181,12 @@ public class Logger { * @param params array of parameters to the method being entered */ public void entering(String sourceClass, String sourceMethod, Object params[]) { - if (Level.FINER.intValue() < levelValue) { - return; - } String msg = "ENTRY"; if (params == null ) { logp(Level.FINER, sourceClass, sourceMethod, msg); return; } + if (!isLoggable(Level.FINER)) return; for (int i = 0; i < params.length; i++) { msg = msg + " {" + i + "}"; } @@ -1213,9 +1204,6 @@ public class Logger { * @param sourceMethod name of the method */ public void exiting(String sourceClass, String sourceMethod) { - if (Level.FINER.intValue() < levelValue) { - return; - } logp(Level.FINER, sourceClass, sourceMethod, "RETURN"); } @@ -1233,10 +1221,6 @@ public class Logger { * @param result Object that is being returned */ public void exiting(String sourceClass, String sourceMethod, Object result) { - if (Level.FINER.intValue() < levelValue) { - return; - } - Object params[] = { result }; logp(Level.FINER, sourceClass, sourceMethod, "RETURN {0}", result); } @@ -1262,7 +1246,7 @@ public class Logger { * @param thrown The Throwable that is being thrown. */ public void throwing(String sourceClass, String sourceMethod, Throwable thrown) { - if (Level.FINER.intValue() < levelValue || levelValue == offValue ) { + if (!isLoggable(Level.FINER)) { return; } LogRecord lr = new LogRecord(Level.FINER, "THROW"); @@ -1286,9 +1270,6 @@ public class Logger { * @param msg The string message (or a key in the message catalog) */ public void severe(String msg) { - if (Level.SEVERE.intValue() < levelValue) { - return; - } log(Level.SEVERE, msg); } @@ -1302,9 +1283,6 @@ public class Logger { * @param msg The string message (or a key in the message catalog) */ public void warning(String msg) { - if (Level.WARNING.intValue() < levelValue) { - return; - } log(Level.WARNING, msg); } @@ -1318,9 +1296,6 @@ public class Logger { * @param msg The string message (or a key in the message catalog) */ public void info(String msg) { - if (Level.INFO.intValue() < levelValue) { - return; - } log(Level.INFO, msg); } @@ -1334,9 +1309,6 @@ public class Logger { * @param msg The string message (or a key in the message catalog) */ public void config(String msg) { - if (Level.CONFIG.intValue() < levelValue) { - return; - } log(Level.CONFIG, msg); } @@ -1350,9 +1322,6 @@ public class Logger { * @param msg The string message (or a key in the message catalog) */ public void fine(String msg) { - if (Level.FINE.intValue() < levelValue) { - return; - } log(Level.FINE, msg); } @@ -1366,9 +1335,6 @@ public class Logger { * @param msg The string message (or a key in the message catalog) */ public void finer(String msg) { - if (Level.FINER.intValue() < levelValue) { - return; - } log(Level.FINER, msg); } @@ -1382,9 +1348,6 @@ public class Logger { * @param msg The string message (or a key in the message catalog) */ public void finest(String msg) { - if (Level.FINEST.intValue() < levelValue) { - return; - } log(Level.FINEST, msg); } diff --git a/jdk/test/java/util/logging/Logger/isLoggable/TestIsLoggable.java b/jdk/test/java/util/logging/Logger/isLoggable/TestIsLoggable.java new file mode 100644 index 00000000000..a6f95b83364 --- /dev/null +++ b/jdk/test/java/util/logging/Logger/isLoggable/TestIsLoggable.java @@ -0,0 +1,512 @@ +/* + * 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.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.logging.Handler; +import java.util.logging.Level; +import java.util.logging.LogManager; +import java.util.logging.LogRecord; +import java.util.logging.Logger; + +/** + * @test + * @bug 8024525 + * @summary checks that isLoggable() can be overridden to control logging. + * @author danielfuchs + * @run main/othervm TestIsLoggable + */ +public class TestIsLoggable { + + // This logger can be configured to override its default level + // for a particular set of thread ids + public static final class ThreadLogger extends Logger { + + final Map threadMap = + Collections.synchronizedMap(new HashMap()); + + public ThreadLogger(String name) { + super(name, null); + } + + @Override + public boolean isLoggable(Level level) { + final Level threadLevel = threadMap.get(Thread.currentThread().getId()); + if (threadLevel == null) return super.isLoggable(level); + final int levelValue = threadLevel.intValue(); + final int offValue = Level.OFF.intValue(); + if (level.intValue() < levelValue || levelValue == offValue) { + return false; + } + return true; + } + + } + + public static final class TestHandler extends Handler { + + final List messages = new CopyOnWriteArrayList<>(); + + @Override + public void publish(LogRecord record) { + messages.add(record.getMessage()); + } + + @Override + public void flush() { + } + + @Override + public void close() throws SecurityException { + messages.clear(); + } + + } + + // Sorted list of standard levels + static final List LEVELS = Collections.unmodifiableList( + java.util.Arrays.asList(new Level[] { + Level.SEVERE, Level.WARNING, Level.INFO, Level.CONFIG, + Level.FINE, Level.FINER, Level.FINEST + })); + + // Test cases: + // LEV_ test logger.severe(msg) .. logger.finest(msg) + // LOG_ logger.log(Level.SEVERE, msg) ... logger.log(Level.FINEST, msg) + // LOG1_ logger.log(Level.SEVERE, msg, param1) ... + // LOG2_ logger.log(Level.SEVERE, msg, params[]) ... + // LOG3_ logger.log(Level.SEVERE, msg, throwable) ... + // LOGP_ logger.logp(Level.SEVERE, class, method, msg) ... + // LOGP1_ logger.logp(Level.SEVERE, class, method, msg, param1) ... + // LOGP2_ logger.logp(Level.SEVERE, class, method, msg, params[]) ... + // LOGP3_ logger.logp(Level.SEVERE, class, method, msg, throwable) ... + public static enum LogTest { + LEV_SEVERE, LEV_WARNING, LEV_INFO, LEV_CONFIG, LEV_FINE, LEV_FINER, LEV_FINEST, + LOG_SEVERE, LOG_WARNING, LOG_INFO, LOG_CONFIG, LOG_FINE, LOG_FINER, LOG_FINEST, + LOG1_SEVERE, LOG1_WARNING, LOG1_INFO, LOG1_CONFIG, LOG1_FINE, LOG1_FINER, LOG1_FINEST, + LOG2_SEVERE, LOG2_WARNING, LOG2_INFO, LOG2_CONFIG, LOG2_FINE, LOG2_FINER, LOG2_FINEST, + LOG3_SEVERE, LOG3_WARNING, LOG3_INFO, LOG3_CONFIG, LOG3_FINE, LOG3_FINER, LOG3_FINEST, + LOGP_SEVERE, LOGP_WARNING, LOGP_INFO, LOGP_CONFIG, LOGP_FINE, LOGP_FINER, LOGP_FINEST, + LOGP1_SEVERE, LOGP1_WARNING, LOGP1_INFO, LOGP1_CONFIG, LOGP1_FINE, LOGP1_FINER, LOGP1_FINEST, + LOGP2_SEVERE, LOGP2_WARNING, LOGP2_INFO, LOGP2_CONFIG, LOGP2_FINE, LOGP2_FINER, LOGP2_FINEST, + LOGP3_SEVERE, LOGP3_WARNING, LOGP3_INFO, LOGP3_CONFIG, LOGP3_FINE, LOGP3_FINER, LOGP3_FINEST; + + // call the method Logger.severe() ... Logger.finest() corresponding + // to the given level 'l' (severe() for SEVERE etc...) + public void loglevel(Level l, Logger logger, String message) { + LogTest test = LogTest.valueOf("LEV_"+l.getName()); + switch(test) { + case LEV_SEVERE: + logger.severe(message); + break; + case LEV_WARNING: + logger.warning(message); + break; + case LEV_INFO: + logger.info(message); + break; + case LEV_CONFIG: + logger.config(message); + break; + case LEV_FINE: + logger.fine(message); + break; + case LEV_FINER: + logger.finer(message); + break; + case LEV_FINEST: + logger.finest(message); + break; + } + } + + // The threshold at which the logger is expected to start logging. + // trick: we derive the threshold level from the testcase name... + public Level threshold() { + for (Level l : LEVELS ) { + if (this.toString().endsWith(l.getName())) { + return l; + } + } + return Level.OFF; + } + + // Levels for which the logger is expected to log something. + public List loggable() { + return LEVELS.subList(0, LEVELS.indexOf(threshold())+1); + } + + // Levels which will be blocked because they are weaker than the + // threshold() + public List weaker() { + return LEVELS.subList(LEVELS.indexOf(threshold())+1, LEVELS.size()); + } + + // Log a message at this testcase threshold, using this testcase method. + public void log(Logger logger, String message) { + log(threshold(), logger, message); + } + + // Log a message at the given level, using this testcase method. + public void log(Level level, Logger logger, String message) { + if (this.toString().startsWith("LOG_")) { + logger.log(level, message); + } else if (this.toString().startsWith("LOG1_")) { + logger.log(level, message, "dummy param"); + } else if (this.toString().startsWith("LOG2_")) { + logger.log(level, message, new Object[] {"dummy", "param"}); + } else if (this.toString().startsWith("LOG3_")) { + logger.log(level, message, new Exception("dummy exception")); + } else if (this.toString().startsWith("LOGP_")) { + logger.logp(level, "TestCase", "log", message); + } else if (this.toString().startsWith("LOGP1_")) { + logger.logp(level, "TestCase", "log", message, "dummy param"); + } else if (this.toString().startsWith("LOGP2_")) { + logger.logp(level, "TestCase", "log", message, + new Object[] {"dummy", "param"}); + } else if (this.toString().startsWith("LOGP3_")) { + logger.logp(level, "TestCase", "log", message, + new Exception("dummy exception")); + } else if (this.toString().startsWith("LEV_")) { + loglevel(level, logger, message); + } + } + + // String description of the logging method called. + public String method() { + if (this.toString().startsWith("LOG_")) { + return "Logger.log(Level." + threshold().getName() +", msg): "; + } else if (this.toString().startsWith("LOG1_")) { + return "Logger.log(Level." + threshold().getName() +", msg, param1): "; + } else if (this.toString().startsWith("LOG2_")) { + return "Logger.log(Level." + threshold().getName() +", msg, params[]): "; + } else if (this.toString().startsWith("LOG3_")) { + return "Logger.log(Level." + threshold().getName() +", msg, throwable): "; + } else if (this.toString().startsWith("LEV_")) { + return "Logger."+threshold().getName().toLowerCase(Locale.ROOT)+"(): "; + } else if (this.toString().startsWith("LOGP_")) { + return "Logger.logp(Level." + threshold().getName() +", msg): "; + } else if (this.toString().startsWith("LOGP1_")) { + return "Logger.logp(Level." + threshold().getName() +", msg, param1): "; + } else if (this.toString().startsWith("LOGP2_")) { + return "Logger.logp(Level." + threshold().getName() +", msg, params[]): "; + } else if (this.toString().startsWith("LOGP3_")) { + return "Logger.logp(Level." + threshold().getName() +", msg, throwable): "; + } + throw new RuntimeException("Unknown test case: "+this); + } + } + + // The purpose of this test is to verify that the various log methods in + // Logger now call Logger.isLoggable(). + // To do that - we're going to use a subclass of Logger, ThreadLogger, which + // only overrides isLoggable() - and compare the level it is given to a level + // it finds in a map indexed with the current thread id. + // We will register a TestHandler with our ThreadLogger which will store + // the messages in a messages map. This will allow us to verify whether the + // logging method we're testing has or hasn't logged. + // + // The TestCase enum above allows us to test a combination of every possible + // log method with every possible level inside a loop - with the + // exception of exiting/entering/throwing that we will be testing + // outside of that loop. + // + public static void main(String... args) { + LogManager manager = LogManager.getLogManager(); + ThreadLogger logger = new ThreadLogger("foo.bar"); + //manager.addLogger(logger); + TestHandler handler = new TestHandler(); + logger.addHandler(handler); + + //By default, logger's level is Level.INFO + final List loggable = LEVELS.subList(0, LEVELS.indexOf(Level.INFO)+1); + + // Check our test implementation of logger.isLoggable(); + // + // Since we haven't put anything in the threadMap, isLoggable() should + // return true for all levels stronger or equals to Level.INFO. + // here we're just checking that our implementation of + // ThreadLogger.isLoggable() returns what we want - we're just testing + // the test code... + for (Level level : LEVELS) { + if (logger.isLoggable(level) != loggable.contains(level)) { + throw new RuntimeException(level + + ": unexpected result for isLoggable(): expected " + + (loggable.contains(level))); + } + } + + // Test that entering/exiting/throwing call isLoggable() + + // Here we test the default behavior: this call shouldn't log anything + // because by default the logger level is Level.INFO and these + // methods log at Level.FINER. + // So by default - these methods don't log anything. We check it here. + logger.entering("blah", "blah"); + logger.entering("blah", "blah", "blah"); + logger.entering("blah", "blah", new Object[] {"blah"}); + if (!handler.messages.isEmpty()) { + throw new RuntimeException("Expected empty, got "+handler.messages); + } + + logger.exiting("blah", "blah"); + logger.exiting("blah", "blah", "blah"); + logger.exiting("blah", "blah", new Object[] {"blah"}); + if (!handler.messages.isEmpty()) { + throw new RuntimeException("Expected empty, got "+handler.messages); + } + + logger.throwing("blah", "blah", new Exception("blah")); + if (!handler.messages.isEmpty()) { + throw new RuntimeException("Expected empty, got "+handler.messages); + } + + // Now we're going to put each level in turn in the threadMap. + // This means that isLoggable(Level.FINER) should now return true if the + // level in the map is not one of the level in the 'stronger' list below + // (here stronger=stronger than FINER) + final List stronger = LEVELS.subList(0, LEVELS.indexOf(Level.FINER)); + for (Level l : LEVELS) { + + logger.threadMap.put(Thread.currentThread().getId(), l); + + // Check that our implementation of isLoggable(level) now returns true + // if 'level' is stronger or equals to 'l' - here we're just checking + // that our implementation of ThreadLogger.isLoggable() returns what + // we want - we're just testing the test code... + final List loggableLevels = LEVELS.subList(0, LEVELS.indexOf(l)+1); + for (Level level : LEVELS) { + if (logger.isLoggable(level) != loggableLevels.contains(level)) { + throw new RuntimeException(level + + ": unexpected result for isLoggable(): expected " + + (loggableLevels.contains(level))); + } + } + + // These methods should now start to log when the level we put in + // the map is weaker or equals to Level.FINER. + // This validates that these methods now call ThreadLogger.isLoggable() + // since the default level for our logger is still Level.INFO. + // If the methods didn't call ThreadLogger.isLoggable() they wouldn't + // log anything, whatever we put in the threadMap... + + logger.entering("blah", "blah"); + logger.entering("blah", "blah", "blah"); + logger.entering("blah", "blah", new Object[] {"blah"}); + if (stronger.contains(l)) { + if (!handler.messages.isEmpty()) { + throw new RuntimeException(l + + ": Expected empty, got " + handler.messages); + } + } else { + if (handler.messages.size() != 3) { + throw new RuntimeException(l + + ": Expected size 3, got " + handler.messages); + } + } + + logger.exiting("blah", "blah"); + logger.exiting("blah", "blah", "blah"); + logger.exiting("blah", "blah", new Object[] {"blah"}); + if (stronger.contains(l)) { + if (!handler.messages.isEmpty()) { + throw new RuntimeException(l + + ": Expected empty, got " + handler.messages); + } + } else { + if (handler.messages.size() != 6) { + throw new RuntimeException(l + + ": Expected size 6, got " + handler.messages); + } + } + + logger.throwing("blah", "blah", new Exception("blah")); + if (stronger.contains(l)) { + if (!handler.messages.isEmpty()) { + throw new RuntimeException(l + + ": Expected empty, got " + handler.messages); + } + } else { + if (handler.messages.size() != 7) { + throw new RuntimeException(l + + ": Expected size 7, got " + handler.messages); + } + } + if (!stronger.contains(l)) { + System.out.println(l + ": Logger.entering/exiting/throwing: " + + handler.messages); + } + handler.messages.clear(); + } + + // Cleanup so that we can start the next test with a clean plate... + handler.messages.clear(); + logger.threadMap.clear(); + + // Test that each logging method calls isLoggable() + // + for (LogTest testCase : LogTest.values()) { + // Each test case is a combination of: + // 1. A level to put in the threadMap. + // 2. A log method to call + final String method = testCase.method(); + + // check our implementation of logger.isLoggable(); + // by default the logger level is Level.INFO, so our implementation + // of isLoggable() should return true for all levels stronger or + // equal to INFO and false for the others. + // We check that here. + for (Level level : LEVELS) { + if (logger.isLoggable(level) != loggable.contains(level)) { + throw new RuntimeException(level + + ": unexpected result for isLoggable(): expected " + + (loggable.contains(level))); + } + } + + // Check that by default the log method will not log for level + // weaker than Level.INFO. + for (Level l : LEVELS.subList(LEVELS.indexOf(Level.INFO) + 1, LEVELS.size())) { + final String test = method + l + ": "; + testCase.log(l, logger, "blah"); + if (!handler.messages.isEmpty()) { + throw new RuntimeException(test + + "Expected empty, got " + handler.messages); + } + } + + // Let's put Level.OFF in the threadMap. Nothing should be logged, + // whichever level is used... + logger.threadMap.put(Thread.currentThread().getId(), Level.OFF); + + // Check that isLoggable() now always return false. + for (Level level : LEVELS) { + if (logger.isLoggable(level)) { + throw new RuntimeException(level + + ": unexpected result for isLoggable(): expected " + + false); + } + } + + // Check that the log method of the test case won't log, whatever + // level we pass to it. This validates that level method calls + // isLoggable() - because otherwise it would log for levels stronger + // or equal to INFO. + for (Level l : LEVELS) { + final String test = "[threadMap=OFF] " + method + l + ": "; + testCase.log(l, logger, "blah"); + if (!handler.messages.isEmpty()) { + throw new RuntimeException(test + + "Expected empty, got " + handler.messages); + } + } + System.out.println("[threadMap=OFF] " + method + "logged " + handler.messages); + + // Now put the testcase's level in the threadMap. + logger.threadMap.put(Thread.currentThread().getId(), testCase.threshold()); + + // The levels for which logging should happen are those that are stronger + // or equals to the testcase's thresholds. + final List loggableLevels = + LEVELS.subList(0, LEVELS.indexOf(testCase.threshold())+1); + + // Check that our implementation of isLoggable() is taking into account + // what we put in the map. + for (Level level : LEVELS) { + if (logger.isLoggable(level) != loggableLevels.contains(level)) { + throw new RuntimeException(level + + ": unexpected result for isLoggable(): expected " + + (loggableLevels.contains(level))); + } + } + + // Now check that the log method is indeed calling our implementation + // of isLoggable(). We do this by first verifying that it won't log + // for levels weaker than what we put in the map. + // + for (Level l : testCase.weaker()) { + final String test = method + l + ": "; + testCase.log(l, logger, "blah"); + if (!handler.messages.isEmpty()) { + throw new RuntimeException(test + + "Expected empty, got " + handler.messages); + } + } + + // Then we check that it will log for the testcase threshold. + final String test2 = method + testCase.threshold() + ": "; + testCase.log(logger, testCase.threshold() + " blah"); + if (handler.messages.isEmpty()) { + throw new RuntimeException(test2 + + "Expected 1 message, but list is empty"); + } + if (!handler.messages.contains(testCase.threshold() + " blah")) { + throw new RuntimeException(test2 + " blah not found: " + + handler.messages); + } + handler.messages.clear(); + + // Now we check that it logs for all 'loggable' level (and doesn't + // log for the others). + for (Level l : LEVELS) { + final String test = method + l + ": "; + testCase.log(l, logger, l + ": blah"); + if (testCase.loggable().contains(l)) { + if (!handler.messages.contains(l + ": blah")) { + throw new RuntimeException(test + "blah not found: " + + handler.messages); + } + } else { + if (handler.messages.contains(l + ": blah")) { + throw new RuntimeException(test + "blah found: " + + handler.messages); + } + } + } + if (handler.messages.size() != testCase.loggable().size()) { + throw new RuntimeException(method + + " Sizes don't match: expected " + + testCase.loggable().size() + " got " + + handler.messages); + } + + // Some visual feedback on what happened. + System.out.println(method + "logged " + handler.messages); + + // Cleanup for next step. + // Since we're iterating over all possible levels we can be + // sure that we haven't missed anything. + // For instance - it could be argued that logger.severe() will + // always log. But since we have 1 case where we put Level.OFF in + // the map and we have verified that severe() didn't log in that + // case, but that it logged in any other case, then we know + // beyond doubt that it called our implementation of isLoggable(). + logger.threadMap.clear(); + handler.messages.clear(); + } + + } +} From 04a877811a0a515b7a28ed7ec493a5948f56e3e1 Mon Sep 17 00:00:00 2001 From: Roger Riggs Date: Thu, 12 Sep 2013 10:58:38 -0400 Subject: [PATCH 212/218] 8024618: Issues with French locale on compact1,2: expected: but was: Tests against the data of the French locale are not valid as conformance tests and are redundant with testing of the US Locale above Reviewed-by: alanb --- .../time/format/TCKDateTimeTextPrinting.java | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/jdk/test/java/time/tck/java/time/format/TCKDateTimeTextPrinting.java b/jdk/test/java/time/tck/java/time/format/TCKDateTimeTextPrinting.java index 52f51369a0c..b547a837fb8 100644 --- a/jdk/test/java/time/tck/java/time/format/TCKDateTimeTextPrinting.java +++ b/jdk/test/java/time/tck/java/time/format/TCKDateTimeTextPrinting.java @@ -155,23 +155,6 @@ public class TCKDateTimeTextPrinting { } } - //----------------------------------------------------------------------- - @Test - public void test_print_appendText2arg_french_long() throws Exception { - DateTimeFormatter f = builder.appendText(MONTH_OF_YEAR, TextStyle.FULL).toFormatter(Locale.FRENCH); - LocalDateTime dt = LocalDateTime.of(2010, 1, 1, 0, 0); - String text = f.format(dt); - assertEquals(text, "janvier"); - } - - @Test - public void test_print_appendText2arg_french_short() throws Exception { - DateTimeFormatter f = builder.appendText(MONTH_OF_YEAR, TextStyle.SHORT).toFormatter(Locale.FRENCH); - LocalDateTime dt = LocalDateTime.of(2010, 1, 1, 0, 0); - String text = f.format(dt); - assertEquals(text, "janv."); - } - //----------------------------------------------------------------------- @Test public void test_appendTextMap() throws Exception { From 383970e790ef1c61d96c569acd0c25d413d5bbb9 Mon Sep 17 00:00:00 2001 From: Lance Andersen Date: Thu, 12 Sep 2013 13:20:26 -0400 Subject: [PATCH 213/218] 8015340: remove erroneous @since tag Reviewed-by: darcy --- jdk/src/share/classes/java/sql/PreparedStatement.java | 1 - 1 file changed, 1 deletion(-) diff --git a/jdk/src/share/classes/java/sql/PreparedStatement.java b/jdk/src/share/classes/java/sql/PreparedStatement.java index e4d16e86e6f..83c005cee3d 100644 --- a/jdk/src/share/classes/java/sql/PreparedStatement.java +++ b/jdk/src/share/classes/java/sql/PreparedStatement.java @@ -954,7 +954,6 @@ public interface PreparedStatement extends Statement { * the JDBC driver does not support this data type * @see Types * - * @since 1.6 */ void setObject(int parameterIndex, Object x, int targetSqlType, int scaleOrLength) throws SQLException; From bef65e773f5fabbd397f2dc354d18e9250dd429b Mon Sep 17 00:00:00 2001 From: Brian Goetz Date: Fri, 6 Sep 2013 22:20:01 -0700 Subject: [PATCH 214/218] 8011916: Spec update for java.util.stream 8024339: j.u.s.Stream.reduce(BinaryOperator) throws unexpected NPE Reviewed-by: mduigou --- .../share/classes/java/util/Collection.java | 1 + .../java/util/function/package-info.java | 1 + .../classes/java/util/stream/BaseStream.java | 107 +- .../classes/java/util/stream/Collector.java | 184 ++-- .../classes/java/util/stream/Collectors.java | 31 +- .../java/util/stream/DoublePipeline.java | 10 +- .../java/util/stream/DoubleStream.java | 225 +++-- .../classes/java/util/stream/IntPipeline.java | 10 +- .../classes/java/util/stream/IntStream.java | 234 +++-- .../java/util/stream/LongPipeline.java | 10 +- .../classes/java/util/stream/LongStream.java | 233 +++-- .../java/util/stream/PipelineHelper.java | 2 +- .../java/util/stream/ReferencePipeline.java | 13 +- .../classes/java/util/stream/Stream.java | 269 +++-- .../java/util/stream/StreamSpliterators.java | 3 +- .../java/util/stream/StreamSupport.java | 24 +- .../java/util/stream/package-info.java | 929 ++++++++++-------- 17 files changed, 1395 insertions(+), 891 deletions(-) diff --git a/jdk/src/share/classes/java/util/Collection.java b/jdk/src/share/classes/java/util/Collection.java index 00ddc1035ed..dba273e6885 100644 --- a/jdk/src/share/classes/java/util/Collection.java +++ b/jdk/src/share/classes/java/util/Collection.java @@ -549,6 +549,7 @@ public interface Collection extends Iterable { * @return a {@code Spliterator} over the elements in this collection * @since 1.8 */ + @Override default Spliterator spliterator() { return Spliterators.spliterator(this, 0); } diff --git a/jdk/src/share/classes/java/util/function/package-info.java b/jdk/src/share/classes/java/util/function/package-info.java index 158d1f0212d..f437f9494b7 100644 --- a/jdk/src/share/classes/java/util/function/package-info.java +++ b/jdk/src/share/classes/java/util/function/package-info.java @@ -105,5 +105,6 @@ * * * @see java.lang.FunctionalInterface + * @since 1.8 */ package java.util.function; diff --git a/jdk/src/share/classes/java/util/stream/BaseStream.java b/jdk/src/share/classes/java/util/stream/BaseStream.java index 9c87a309098..4b7006b59c0 100644 --- a/jdk/src/share/classes/java/util/stream/BaseStream.java +++ b/jdk/src/share/classes/java/util/stream/BaseStream.java @@ -24,16 +24,103 @@ */ package java.util.stream; +import java.nio.charset.Charset; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Collection; 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}: * - * @param type of stream elements - * @param type of stream implementing {@code BaseStream} + *
    {@code
    + *     int sum = widgets.stream()
    + *                      .filter(w -> w.getColor() == RED)
    + *                      .mapToInt(w -> w.getWeight())
    + *                      .sum();
    + * }
    + * + * In this example, {@code widgets} is a {@code Collection}. 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. + * + *

    To perform a computation, stream + * operations are composed into a + * stream pipeline. A stream pipeline consists of a source (which + * might be an array, a collection, a generator function, an IO channel, + * etc), zero or more intermediate operations (which transform a + * stream into another stream, such as {@link Stream#filter(Predicate)}), and a + * terminal operation (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. + * + *

    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. + * + *

    A stream pipeline, like the "widgets" example above, can be viewed as + * a query 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. + * + *

    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 functional interface 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 + * effectively stateless + * (their result should not depend on any state that might change during + * execution of the stream pipeline.) + * + *

    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. + * + *

    Streams have a {@link #close()} method and implement {@link AutoCloseable}, + * but nearly all stream instances do not actually need to be closed after use. + * Generally, only streams whose source is an IO channel (such as those returned + * by {@link Files#lines(Path, Charset)}) will require closing. Most streams + * are backed by collections, arrays, or generating functions, which require no + * special resource management. (If a stream does require closing, it can be + * declared as a resource in a {@code try}-with-resources statement.) + * + *

    Stream pipelines may execute either sequentially or in + * parallel. 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 the type of the stream elements + * @param the type of of the stream implementing {@code BaseStream} * @since 1.8 + * @see java.util.stream */ public interface BaseStream> extends AutoCloseable { @@ -58,14 +145,11 @@ public interface BaseStream> Spliterator 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(); @@ -96,7 +180,8 @@ public interface BaseStream> /** * Returns an equivalent stream that is * unordered. 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. * *

    This is an intermediate * operation. diff --git a/jdk/src/share/classes/java/util/stream/Collector.java b/jdk/src/share/classes/java/util/stream/Collector.java index 49629176032..e409d569808 100644 --- a/jdk/src/share/classes/java/util/stream/Collector.java +++ b/jdk/src/share/classes/java/util/stream/Collector.java @@ -26,6 +26,7 @@ package java.util.stream; 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.Function; import java.util.function.Supplier; /** - * A reduction operation that - * folds input elements into a mutable result container, optionally transforming + * A mutable reduction operation 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. * *

    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. - * - *

    The following are examples of using the predefined {@code Collector} - * implementations in {@link Collectors} with the {@code Stream} API to perform - * mutable reduction tasks: - *

    {@code
    - *     // Accumulate names into a List
    - *     List list = people.stream().map(Person::getName).collect(Collectors.toList());
    - *
    - *     // Accumulate names into a TreeSet
    - *     Set 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> byDept
    - *         = employees.stream()
    - *                    .collect(Collectors.groupingBy(Employee::getDepartment));
    - *
    - *     // Find highest-paid employee by department
    - *     Map> highestPaidByDept
    - *         = employees.stream()
    - *                    .collect(Collectors.groupingBy(Employee::getDepartment,
    - *                                                   Collectors.maxBy(Comparators.comparing(Employee::getSalary))));
    - *
    - *     // Partition students into passing and failing
    - *     Map> passingFailing =
    - *         students.stream()
    - *                 .collect(Collectors.partitioningBy(s -> s.getGrade() >= PASS_THRESHOLD));
    - *
    - * }
    + * such as "maximum valued transaction by seller", etc. The class {@link Collectors} + * provides implementations of many common mutable reductions. * *

    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:

      + *
    • creation of a new result container ({@link #supplier()})
    • + *
    • incorporating a new data element into a result container ({@link #accumulator()})
    • + *
    • combining two result containers into one ({@link #combiner()})
    • + *
    • performing an optional final transform on the container ({@link #finisher()})
    • + *
    * *

    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. + * + *

    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. + * + *

    To ensure that sequential and parallel executions produce equivalent + * results, the collector functions must satisfy an identity and an + * associativity constraints. + * + *

    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())}. + * + *

    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: + *

    {@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
    + * } 
    + * + *

    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.) * *

    Libraries that implement reduction based on {@code Collector}, such as * {@link Stream#collect(Collector)}, must adhere to the following constraints: @@ -132,6 +136,20 @@ import java.util.function.Supplier; * originating data is unordered. * * + *

    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 a {@code TreeSet} with: + * + *

    {@code
    + *     Collector> intoSet =
    + *         Collector.of(TreeSet::new, TreeSet::add,
    + *                      (left, right) -> { left.addAll(right); return left; });
    + * }
    + * + * (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,27 +162,35 @@ import java.util.function.Supplier; * *

    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.) * - *

    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()}, 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)}). + *

    Collectors are designed to be composed; 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: * - * TODO Associativity and commutativity + *

    {@code
    + *     Collector summingSalaries
    + *         = Collectors.summingInt(Employee::getSalary))
    + * }
    + * + * 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)}: + * + *
    {@code
    + *     Collector> summingSalariesByDept
    + *         = Collectors.groupingBy(Employee::getDepartment, summingSalaries);
    + * }
    * * @see Stream#collect(Collector) * @see Collectors * * @param the type of input elements to the reduction operation * @param the mutable accumulation type of the reduction operation (often - * hidden as an implementation detail) + * hidden as an implementation detail) * @param the result type of the reduction operation * @since 1.8 */ @@ -177,25 +203,25 @@ public interface Collector { Supplier 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 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 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}. * *

    If the characteristic {@code IDENTITY_TRANSFORM} is * set, this function may be presumed to be an identity transform with an @@ -228,12 +254,17 @@ public interface Collector { * @param The type of input elements for the new collector * @param 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 Collector of(Supplier supplier, BiConsumer accumulator, BinaryOperator combiner, Characteristics... characteristics) { + Objects.requireNonNull(supplier); + Objects.requireNonNull(accumulator); + Objects.requireNonNull(combiner); + Objects.requireNonNull(characteristics); Set cs = (characteristics.length == 0) ? Collectors.CH_ID : Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.IDENTITY_FINISH, @@ -254,6 +285,7 @@ public interface Collector { * @param The type of input elements for the new collector * @param The intermediate accumulation type of the new collector * @param The final result type of the new collector + * @throws NullPointerException if any argument is null * @return the new {@code Collector} */ public static Collector of(Supplier supplier, @@ -261,6 +293,11 @@ public interface Collector { BinaryOperator combiner, Function finisher, Characteristics... characteristics) { + Objects.requireNonNull(supplier); + Objects.requireNonNull(accumulator); + Objects.requireNonNull(combiner); + Objects.requireNonNull(finisher); + Objects.requireNonNull(characteristics); Set cs = Collectors.CH_NOID; if (characteristics.length > 0) { cs = EnumSet.noneOf(Characteristics.class); @@ -288,8 +325,9 @@ public interface Collector { 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, diff --git a/jdk/src/share/classes/java/util/stream/Collectors.java b/jdk/src/share/classes/java/util/stream/Collectors.java index bdbd8ad0774..00f7c866311 100644 --- a/jdk/src/share/classes/java/util/stream/Collectors.java +++ b/jdk/src/share/classes/java/util/stream/Collectors.java @@ -62,37 +62,35 @@ import java.util.function.ToLongFunction; * operations, such as accumulating elements into collections, summarizing * elements according to various criteria, etc. * - *

    The following are examples of using the predefined {@code Collector} - * implementations in {@link Collectors} with the {@code Stream} API to perform - * mutable reduction tasks: + *

    The following are examples of using the predefined collectors to perform + * common mutable reduction tasks: * *

    {@code
      *     // Accumulate names into a List
      *     List list = people.stream().map(Person::getName).collect(Collectors.toList());
      *
      *     // Accumulate names into a TreeSet
    - *     Set list = people.stream().map(Person::getName).collect(Collectors.toCollection(TreeSet::new));
    + *     Set 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 total = employees.stream()
    + *                          .collect(Collectors.summingInt(Employee::getSalary)));
      *
      *     // Group employees by department
      *     Map> byDept
      *         = employees.stream()
      *                    .collect(Collectors.groupingBy(Employee::getDepartment));
      *
    - *     // Find highest-paid employee by department
    - *     Map> highestPaidByDept
    + *     // Compute sum of salaries by department
    + *     Map totalByDept
      *         = employees.stream()
      *                    .collect(Collectors.groupingBy(Employee::getDepartment,
    - *                                                   Collectors.maxBy(Comparator.comparing(Employee::getSalary))));
    + *                                                   Collectors.summingInt(Employee::getSalary)));
      *
      *     // Partition students into passing and failing
      *     Map> passingFailing =
    @@ -101,8 +99,6 @@ import java.util.function.ToLongFunction;
      *
      * }
    * - * TODO explanation of parallel collection - * * @since 1.8 */ public final class Collectors { @@ -222,7 +218,8 @@ public final class Collectors { /** * 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 the type of the input elements * @return a {@code Collector} which collects all the input elements into a @@ -238,7 +235,9 @@ public final class Collectors { /** * 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 Set} is required, use + * {@link #toCollection(Supplier)}. * *

    This is an {@link Collector.Characteristics#UNORDERED unordered} * Collector. @@ -903,7 +902,7 @@ public final class Collectors { * where the city names are sorted: *

    {@code
          *     ConcurrentMap> namesByCity
    -     *         = people.stream().collect(groupingByConcurrent(Person::getCity, ConcurrentSkipListMap::new,
    +     *         = people.stream().collect(groupingByConcurrent(Person::getCity,
          *                                                        mapping(Person::getLastName, toSet())));
          * }
    * diff --git a/jdk/src/share/classes/java/util/stream/DoublePipeline.java b/jdk/src/share/classes/java/util/stream/DoublePipeline.java index 75981d5801f..43b3d04bed9 100644 --- a/jdk/src/share/classes/java/util/stream/DoublePipeline.java +++ b/jdk/src/share/classes/java/util/stream/DoublePipeline.java @@ -313,8 +313,8 @@ abstract class DoublePipeline } @Override - public final DoubleStream peek(DoubleConsumer consumer) { - Objects.requireNonNull(consumer); + public final DoubleStream peek(DoubleConsumer action) { + Objects.requireNonNull(action); return new StatelessOp(this, StreamShape.DOUBLE_VALUE, 0) { @Override @@ -322,7 +322,7 @@ abstract class DoublePipeline return new Sink.ChainedDouble(sink) { @Override public void accept(double t) { - consumer.accept(t); + action.accept(t); downstream.accept(t); } }; @@ -436,14 +436,14 @@ abstract class DoublePipeline } @Override - public final R collect(Supplier resultFactory, + public final R collect(Supplier supplier, ObjDoubleConsumer accumulator, BiConsumer combiner) { BinaryOperator operator = (left, right) -> { combiner.accept(left, right); return left; }; - return evaluate(ReduceOps.makeDouble(resultFactory, accumulator, operator)); + return evaluate(ReduceOps.makeDouble(supplier, accumulator, operator)); } @Override diff --git a/jdk/src/share/classes/java/util/stream/DoubleStream.java b/jdk/src/share/classes/java/util/stream/DoubleStream.java index bf356926154..f10092ac7a5 100644 --- a/jdk/src/share/classes/java/util/stream/DoubleStream.java +++ b/jdk/src/share/classes/java/util/stream/DoubleStream.java @@ -24,13 +24,18 @@ */ package java.util.stream; +import java.nio.charset.Charset; +import java.nio.file.Files; +import java.nio.file.Path; 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 +50,87 @@ import java.util.function.ObjDoubleConsumer; 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 consumed 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}: * - *

    For sequential stream pipelines, all operations are performed in the - * encounter order of the pipeline - * source, if the pipeline source has a defined encounter order. + *

    {@code
    + *     double sum = widgets.stream()
    + *                         .filter(w -> w.getColor() == RED)
    + *                         .mapToDouble(w -> w.getWeight())
    + *                         .sum();
    + * }
    * - *

    For parallel stream pipelines, unless otherwise specified, intermediate - * stream operations preserve the - * encounter order 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 non-interference - * requirements, 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. + * In this example, {@code widgets} is a {@code Collection}. 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. * - *

    Unless otherwise noted, passing a {@code null} argument to any stream - * method may result in a {@link NullPointerException}. + *

    To perform a computation, stream + * operations are composed into a + * stream pipeline. A stream pipeline consists of a source (which + * might be an array, a collection, a generator function, an IO channel, + * etc), zero or more intermediate operations (which transform a + * stream into another stream, such as {@link DoubleStream#filter(DoublePredicate)}), and a + * terminal operation (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. * - * @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. + *

    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. + * + *

    A stream pipeline, like the "widgets" example above, can be viewed as + * a query 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. + * + *

    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 functional interface 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 + * effectively stateless + * (their result should not depend on any state that might change during + * execution of the stream pipeline.) + * + *

    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. + * + *

    Streams have a {@link #close()} method and implement {@link AutoCloseable}, + * but nearly all stream instances do not actually need to be closed after use. + * Generally, only streams whose source is an IO channel (such as those returned + * by {@link Files#lines(Path, Charset)}) will require closing. Most streams + * are backed by collections, arrays, or generating functions, which require no + * special resource management. (If a stream does require closing, it can be + * declared as a resource in a {@code try}-with-resources statement.) + * + *

    Stream pipelines may execute either sequentially or in + * parallel. 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 java.util.stream @@ -159,22 +211,13 @@ public interface DoubleStream extends BaseStream { /** * 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.) * *

    This is an intermediate * operation. * - * @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: - *

    {@code
    -     *     orderStream.flatMap(order -> order.getLineItems().stream())...
    -     * }
    - * * @param mapper a * non-interfering, stateless function to apply to * each element which produces an {@code DoubleStream} of new @@ -226,18 +269,18 @@ public interface DoubleStream extends BaseStream { *
    {@code
          *     list.stream()
          *         .filter(filteringFunction)
    -     *         .peek(e -> {System.out.println("Filtered value: " + e); });
    +     *         .peek(e -> System.out.println("Filtered value: " + e));
          *         .map(mappingFunction)
    -     *         .peek(e -> {System.out.println("Mapped value: " + e); });
    +     *         .peek(e -> System.out.println("Mapped value: " + e));
          *         .collect(Collectors.toDoubleSummaryStastistics());
          * }
    * - * @param consumer a + * @param action a * non-interfering 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 +297,8 @@ public interface DoubleStream extends BaseStream { /** * 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. * *

    This is a stateful @@ -269,10 +312,10 @@ public interface DoubleStream extends BaseStream { /** * 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. * *

    This is a short-circuiting * stateful intermediate operation. @@ -421,12 +464,12 @@ public interface DoubleStream extends BaseStream { /** * Performs a mutable * reduction 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: *

    {@code
    -     *     R result = resultFactory.get();
    +     *     R result = supplier.get();
          *     for (double element : this stream)
          *         accumulator.accept(result, element);
          *     return result;
    @@ -440,10 +483,9 @@ public interface DoubleStream extends BaseStream {
          * operation.
          *
          * @param  type of the result
    -     * @param resultFactory 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.
    +     * @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.
          * @param accumulator an associative
          *                    non-interfering,
          *                    stateless function for incorporating an additional
    @@ -455,7 +497,7 @@ public interface DoubleStream extends BaseStream {
          * @return the result of the reduction
          * @see Stream#collect(Supplier, BiConsumer, BiConsumer)
          */
    -     R collect(Supplier resultFactory,
    +     R collect(Supplier supplier,
                       ObjDoubleConsumer accumulator,
                       BiConsumer combiner);
     
    @@ -467,12 +509,15 @@ public interface DoubleStream extends BaseStream {
          * 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
    -     * reduction and is
    +     * reduction and is
          * equivalent to:
          * 
    {@code
          *     return reduce(0, Double::sum);
          * }
    * + *

    This is a terminal + * operation. + * * @return the sum of elements in this stream */ double sum(); @@ -483,12 +528,15 @@ public interface DoubleStream extends BaseStream { * 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 - * reduction and is + * reduction and is * equivalent to: *

    {@code
          *     return reduce(Double::min);
          * }
    * + *

    This is a terminal + * operation. + * * @return an {@code OptionalDouble} containing the minimum element of this * stream, or an empty optional if the stream is empty */ @@ -501,12 +549,15 @@ public interface DoubleStream extends BaseStream { * the numerical comparison operators, this method considers negative zero * to be strictly smaller than positive zero. This is a * special case of a - * reduction and is + * reduction and is * equivalent to: *

    {@code
          *     return reduce(Double::max);
          * }
    * + *

    This is a terminal + * operation. + * * @return an {@code OptionalDouble} containing the maximum element of this * stream, or an empty optional if the stream is empty */ @@ -514,7 +565,7 @@ public interface DoubleStream extends BaseStream { /** * Returns the count of elements in this stream. This is a special case of - * a reduction and is + * a reduction and is * equivalent to: *

    {@code
          *     return mapToLong(e -> 1L).sum();
    @@ -535,7 +586,10 @@ public interface DoubleStream extends BaseStream {
          * 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
    -     * reduction.
    +     * reduction.
    +     *
    +     * 

    This is a terminal + * operation. * * @return an {@code OptionalDouble} containing the average element of this * stream, or an empty optional if the stream is empty @@ -545,7 +599,10 @@ public interface DoubleStream extends BaseStream { /** * Returns a {@code DoubleSummaryStatistics} describing various summary data * about the elements of this stream. This is a special - * case of a reduction. + * case of a reduction. + * + *

    This is a terminal + * operation. * * @return a {@code DoubleSummaryStatistics} describing various summary data * about the elements of this stream @@ -602,9 +659,8 @@ public interface DoubleStream extends BaseStream { /** * 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. * *

    This is a short-circuiting * terminal operation. @@ -624,8 +680,8 @@ public interface DoubleStream extends BaseStream { *

    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 +693,9 @@ public interface DoubleStream extends BaseStream { * Returns a {@code Stream} consisting of the elements of this stream, * boxed to {@code Double}. * + *

    This is an intermediate + * operation. + * * @return a {@code Stream} consistent of the elements of this stream, * each boxed to a {@code Double} */ @@ -686,7 +745,7 @@ public interface DoubleStream extends BaseStream { } /** - * 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 +755,7 @@ public interface DoubleStream extends BaseStream { } /** - * 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 +793,8 @@ public interface DoubleStream extends BaseStream { } /** - * 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,16 +807,16 @@ public interface DoubleStream extends BaseStream { } /** - * 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. 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); @@ -772,9 +831,9 @@ public interface DoubleStream extends BaseStream { /** * A mutable builder for a {@code DoubleStream}. * - *

    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 + *

    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. diff --git a/jdk/src/share/classes/java/util/stream/IntPipeline.java b/jdk/src/share/classes/java/util/stream/IntPipeline.java index f35bc1d7a8e..13f7e0a9731 100644 --- a/jdk/src/share/classes/java/util/stream/IntPipeline.java +++ b/jdk/src/share/classes/java/util/stream/IntPipeline.java @@ -349,8 +349,8 @@ abstract class IntPipeline } @Override - public final IntStream peek(IntConsumer consumer) { - Objects.requireNonNull(consumer); + public final IntStream peek(IntConsumer action) { + Objects.requireNonNull(action); return new StatelessOp(this, StreamShape.INT_VALUE, 0) { @Override @@ -358,7 +358,7 @@ abstract class IntPipeline return new Sink.ChainedInt(sink) { @Override public void accept(int t) { - consumer.accept(t); + action.accept(t); downstream.accept(t); } }; @@ -473,14 +473,14 @@ abstract class IntPipeline } @Override - public final R collect(Supplier resultFactory, + public final R collect(Supplier supplier, ObjIntConsumer accumulator, BiConsumer combiner) { BinaryOperator operator = (left, right) -> { combiner.accept(left, right); return left; }; - return evaluate(ReduceOps.makeInt(resultFactory, accumulator, operator)); + return evaluate(ReduceOps.makeInt(supplier, accumulator, operator)); } @Override diff --git a/jdk/src/share/classes/java/util/stream/IntStream.java b/jdk/src/share/classes/java/util/stream/IntStream.java index c107ca46de9..07f9ab5dc78 100644 --- a/jdk/src/share/classes/java/util/stream/IntStream.java +++ b/jdk/src/share/classes/java/util/stream/IntStream.java @@ -24,7 +24,11 @@ */ package java.util.stream; +import java.nio.charset.Charset; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.Arrays; +import java.util.Collection; import java.util.IntSummaryStatistics; import java.util.Objects; import java.util.OptionalDouble; @@ -32,6 +36,7 @@ import java.util.OptionalInt; 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 +51,87 @@ import java.util.function.ObjIntConsumer; 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 consumed 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}: * - *

    For sequential stream pipelines, all operations are performed in the - * encounter order of the pipeline - * source, if the pipeline source has a defined encounter order. + *

    {@code
    + *     int sum = widgets.stream()
    + *                      .filter(w -> w.getColor() == RED)
    + *                      .mapToInt(w -> w.getWeight())
    + *                      .sum();
    + * }
    * - *

    For parallel stream pipelines, unless otherwise specified, intermediate - * stream operations preserve the - * encounter order 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 non-interference - * requirements, 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. + * In this example, {@code widgets} is a {@code Collection}. 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. * - *

    Unless otherwise noted, passing a {@code null} argument to any stream - * method may result in a {@link NullPointerException}. + *

    To perform a computation, stream + * operations are composed into a + * stream pipeline. A stream pipeline consists of a source (which + * might be an array, a collection, a generator function, an IO channel, + * etc), zero or more intermediate operations (which transform a + * stream into another stream, such as {@link IntStream#filter(IntPredicate)}), and a + * terminal operation (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. * - * @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. + *

    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. + * + *

    A stream pipeline, like the "widgets" example above, can be viewed as + * a query 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. + * + *

    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 functional interface 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 + * effectively stateless + * (their result should not depend on any state that might change during + * execution of the stream pipeline.) + * + *

    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. + * + *

    Streams have a {@link #close()} method and implement {@link AutoCloseable}, + * but nearly all stream instances do not actually need to be closed after use. + * Generally, only streams whose source is an IO channel (such as those returned + * by {@link Files#lines(Path, Charset)}) will require closing. Most streams + * are backed by collections, arrays, or generating functions, which require no + * special resource management. (If a stream does require closing, it can be + * declared as a resource in a {@code try}-with-resources statement.) + * + *

    Stream pipelines may execute either sequentially or in + * parallel. 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 java.util.stream @@ -160,22 +212,13 @@ public interface IntStream extends BaseStream { /** * 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.) * *

    This is an intermediate * operation. * - * @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: - *

    {@code
    -     *     orderStream.flatMap(order -> order.getLineItems().stream())...
    -     * }
    - * * @param mapper a * non-interfering, stateless function to apply to * each element which produces an {@code IntStream} of new @@ -224,18 +267,18 @@ public interface IntStream extends BaseStream { *
    {@code
          *     list.stream()
          *         .filter(filteringFunction)
    -     *         .peek(e -> {System.out.println("Filtered value: " + e); });
    +     *         .peek(e -> System.out.println("Filtered value: " + e));
          *         .map(mappingFunction)
    -     *         .peek(e -> {System.out.println("Mapped value: " + e); });
    +     *         .peek(e -> System.out.println("Mapped value: " + e));
          *         .collect(Collectors.toIntSummaryStastistics());
          * }
    * - * @param consumer a - * non-interfering action to perform on the elements as - * they are consumed from the stream + * @param action a + * non-interfering 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 +295,8 @@ public interface IntStream extends BaseStream { /** * 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. * *

    This is a stateful @@ -267,10 +310,10 @@ public interface IntStream extends BaseStream { /** * 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. * *

    This is a short-circuiting * stateful intermediate operation. @@ -419,12 +462,12 @@ public interface IntStream extends BaseStream { /** * Performs a mutable * reduction 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: *

    {@code
    -     *     R result = resultFactory.get();
    +     *     R result = supplier.get();
          *     for (int element : this stream)
          *         accumulator.accept(result, element);
          *     return result;
    @@ -437,10 +480,9 @@ public interface IntStream extends BaseStream {
          * operation.
          *
          * @param  type of the result
    -     * @param resultFactory 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.
    +     * @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.
          * @param accumulator an associative
          *                    non-interfering,
          *                    stateless function for incorporating an additional
    @@ -452,18 +494,21 @@ public interface IntStream extends BaseStream {
          * @return the result of the reduction
          * @see Stream#collect(Supplier, BiConsumer, BiConsumer)
          */
    -     R collect(Supplier resultFactory,
    +     R collect(Supplier supplier,
                       ObjIntConsumer accumulator,
                       BiConsumer combiner);
     
         /**
          * Returns the sum of elements in this stream.  This is a special case
    -     * of a reduction
    +     * of a reduction
          * and is equivalent to:
          * 
    {@code
          *     return reduce(0, Integer::sum);
          * }
    * + *

    This is a terminal + * operation. + * * @return the sum of elements in this stream */ int sum(); @@ -471,7 +516,7 @@ public interface IntStream extends BaseStream { /** * 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 reduction + * case of a reduction * and is equivalent to: *

    {@code
          *     return reduce(Integer::min);
    @@ -479,7 +524,6 @@ public interface IntStream extends BaseStream {
          *
          * 

    This is a terminal operation. * - * @return an {@code OptionalInt} containing the minimum element of this * stream, or an empty {@code OptionalInt} if the stream is empty */ @@ -488,7 +532,7 @@ public interface IntStream extends BaseStream { /** * 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 reduction + * case of a reduction * and is equivalent to: *

    {@code
          *     return reduce(Integer::max);
    @@ -504,7 +548,7 @@ public interface IntStream extends BaseStream {
     
         /**
          * Returns the count of elements in this stream.  This is a special case of
    -     * a reduction and is
    +     * a reduction and is
          * equivalent to:
          * 
    {@code
          *     return mapToLong(e -> 1L).sum();
    @@ -520,7 +564,10 @@ public interface IntStream extends BaseStream {
          * 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
    -     * reduction.
    +     * reduction.
    +     *
    +     * 

    This is a terminal + * operation. * * @return an {@code OptionalDouble} containing the average element of this * stream, or an empty optional if the stream is empty @@ -530,7 +577,10 @@ public interface IntStream extends BaseStream { /** * Returns an {@code IntSummaryStatistics} describing various * summary data about the elements of this stream. This is a special - * case of a reduction. + * case of a reduction. + * + *

    This is a terminal + * operation. * * @return an {@code IntSummaryStatistics} describing various summary data * about the elements of this stream @@ -587,9 +637,8 @@ public interface IntStream extends BaseStream { /** * 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. * *

    This is a short-circuiting * terminal operation. @@ -609,8 +658,8 @@ public interface IntStream extends BaseStream { *

    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 +671,9 @@ public interface IntStream extends BaseStream { * Returns a {@code LongStream} consisting of the elements of this stream, * converted to {@code long}. * + *

    This is an intermediate + * operation. + * * @return a {@code LongStream} consisting of the elements of this stream, * converted to {@code long} */ @@ -631,6 +683,9 @@ public interface IntStream extends BaseStream { * Returns a {@code DoubleStream} consisting of the elements of this stream, * converted to {@code double}. * + *

    This is an intermediate + * operation. + * * @return a {@code DoubleStream} consisting of the elements of this stream, * converted to {@code double} */ @@ -640,6 +695,9 @@ public interface IntStream extends BaseStream { * Returns a {@code Stream} consisting of the elements of this stream, * each boxed to an {@code Integer}. * + *

    This is an intermediate + * operation. + * * @return a {@code Stream} consistent of the elements of this stream, * each boxed to an {@code Integer} */ @@ -688,7 +746,7 @@ public interface IntStream extends BaseStream { } /** - * 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 +756,7 @@ public interface IntStream extends BaseStream { } /** - * 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 +794,8 @@ public interface IntStream extends BaseStream { } /** - * 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 +808,7 @@ public interface IntStream extends BaseStream { } /** - * 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 +834,7 @@ public interface IntStream extends BaseStream { } /** - * 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,16 +860,16 @@ public interface IntStream extends BaseStream { } /** - * 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. 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); @@ -826,9 +884,9 @@ public interface IntStream extends BaseStream { /** * A mutable builder for an {@code IntStream}. * - *

    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 + *

    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. diff --git a/jdk/src/share/classes/java/util/stream/LongPipeline.java b/jdk/src/share/classes/java/util/stream/LongPipeline.java index a59ec3f5f00..5ed030e02a1 100644 --- a/jdk/src/share/classes/java/util/stream/LongPipeline.java +++ b/jdk/src/share/classes/java/util/stream/LongPipeline.java @@ -330,8 +330,8 @@ abstract class LongPipeline } @Override - public final LongStream peek(LongConsumer consumer) { - Objects.requireNonNull(consumer); + public final LongStream peek(LongConsumer action) { + Objects.requireNonNull(action); return new StatelessOp(this, StreamShape.LONG_VALUE, 0) { @Override @@ -339,7 +339,7 @@ abstract class LongPipeline return new Sink.ChainedLong(sink) { @Override public void accept(long t) { - consumer.accept(t); + action.accept(t); downstream.accept(t); } }; @@ -455,14 +455,14 @@ abstract class LongPipeline } @Override - public final R collect(Supplier resultFactory, + public final R collect(Supplier supplier, ObjLongConsumer accumulator, BiConsumer combiner) { BinaryOperator operator = (left, right) -> { combiner.accept(left, right); return left; }; - return evaluate(ReduceOps.makeLong(resultFactory, accumulator, operator)); + return evaluate(ReduceOps.makeLong(supplier, accumulator, operator)); } @Override diff --git a/jdk/src/share/classes/java/util/stream/LongStream.java b/jdk/src/share/classes/java/util/stream/LongStream.java index e64c67204dc..ca61d2f200e 100644 --- a/jdk/src/share/classes/java/util/stream/LongStream.java +++ b/jdk/src/share/classes/java/util/stream/LongStream.java @@ -24,7 +24,11 @@ */ package java.util.stream; +import java.nio.charset.Charset; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.Arrays; +import java.util.Collection; import java.util.LongSummaryStatistics; import java.util.Objects; import java.util.OptionalDouble; @@ -32,6 +36,7 @@ import java.util.OptionalLong; 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 +51,87 @@ import java.util.function.ObjLongConsumer; 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 consumed 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}: * - *

    For sequential stream pipelines, all operations are performed in the - * encounter order of the pipeline - * source, if the pipeline source has a defined encounter order. + *

    {@code
    + *     long sum = widgets.stream()
    + *                       .filter(w -> w.getColor() == RED)
    + *                       .mapToLong(w -> w.getWeight())
    + *                       .sum();
    + * }
    * - *

    For parallel stream pipelines, unless otherwise specified, intermediate - * stream operations preserve the - * encounter order 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 non-interference - * requirements, 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. + * In this example, {@code widgets} is a {@code Collection}. 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. * - *

    Unless otherwise noted, passing a {@code null} argument to any stream - * method may result in a {@link NullPointerException}. + *

    To perform a computation, stream + * operations are composed into a + * stream pipeline. A stream pipeline consists of a source (which + * might be an array, a collection, a generator function, an IO channel, + * etc), zero or more intermediate operations (which transform a + * stream into another stream, such as {@link LongStream#filter(LongPredicate)}), and a + * terminal operation (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. * - * @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. + *

    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. + * + *

    A stream pipeline, like the "widgets" example above, can be viewed as + * a query 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. + * + *

    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 functional interface 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 + * effectively stateless + * (their result should not depend on any state that might change during + * execution of the stream pipeline.) + * + *

    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. + * + *

    Streams have a {@link #close()} method and implement {@link AutoCloseable}, + * but nearly all stream instances do not actually need to be closed after use. + * Generally, only streams whose source is an IO channel (such as those returned + * by {@link Files#lines(Path, Charset)}) will require closing. Most streams + * are backed by collections, arrays, or generating functions, which require no + * special resource management. (If a stream does require closing, it can be + * declared as a resource in a {@code try}-with-resources statement.) + * + *

    Stream pipelines may execute either sequentially or in + * parallel. 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 java.util.stream @@ -160,22 +212,13 @@ public interface LongStream extends BaseStream { /** * 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.) * *

    This is an intermediate * operation. * - * @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: - *

    {@code
    -     *     orderStream.flatMap(order -> order.getLineItems().stream())...
    -     * }
    - * * @param mapper a * non-interfering, stateless function to apply to * each element which produces an {@code LongStream} of new @@ -224,18 +267,18 @@ public interface LongStream extends BaseStream { *
    {@code
          *     list.stream()
          *         .filter(filteringFunction)
    -     *         .peek(e -> {System.out.println("Filtered value: " + e); });
    +     *         .peek(e -> System.out.println("Filtered value: " + e));
          *         .map(mappingFunction)
    -     *         .peek(e -> {System.out.println("Mapped value: " + e); });
    +     *         .peek(e -> System.out.println("Mapped value: " + e));
          *         .collect(Collectors.toLongSummaryStastistics());
          * }
    * - * @param consumer a - * non-interfering action to perform on the elements as - * they are consumed from the stream + * @param action a + * non-interfering 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 +295,8 @@ public interface LongStream extends BaseStream { /** * 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. * *

    This is a stateful @@ -267,10 +310,10 @@ public interface LongStream extends BaseStream { /** * 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. * *

    This is a short-circuiting * stateful intermediate operation. @@ -419,12 +462,12 @@ public interface LongStream extends BaseStream { /** * Performs a mutable * reduction 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: *

    {@code
    -     *     R result = resultFactory.get();
    +     *     R result = supplier.get();
          *     for (long element : this stream)
          *         accumulator.accept(result, element);
          *     return result;
    @@ -437,10 +480,9 @@ public interface LongStream extends BaseStream {
          * operation.
          *
          * @param  type of the result
    -     * @param resultFactory 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.
    +     * @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.
          * @param accumulator an associative
          *                    non-interfering,
          *                    stateless function for incorporating an additional
    @@ -452,18 +494,21 @@ public interface LongStream extends BaseStream {
          * @return the result of the reduction
          * @see Stream#collect(Supplier, BiConsumer, BiConsumer)
          */
    -     R collect(Supplier resultFactory,
    +     R collect(Supplier supplier,
                       ObjLongConsumer accumulator,
                       BiConsumer combiner);
     
         /**
          * Returns the sum of elements in this stream.  This is a special case
    -     * of a reduction
    +     * of a reduction
          * and is equivalent to:
          * 
    {@code
          *     return reduce(0, Long::sum);
          * }
    * + *

    This is a terminal + * operation. + * * @return the sum of elements in this stream */ long sum(); @@ -471,7 +516,7 @@ public interface LongStream extends BaseStream { /** * 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 reduction + * case of a reduction * and is equivalent to: *

    {@code
          *     return reduce(Long::min);
    @@ -479,7 +524,6 @@ public interface LongStream extends BaseStream {
          *
          * 

    This is a terminal operation. * - * @return an {@code OptionalLong} containing the minimum element of this * stream, or an empty {@code OptionalLong} if the stream is empty */ @@ -488,7 +532,7 @@ public interface LongStream extends BaseStream { /** * 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 reduction + * case of a reduction * and is equivalent to: *

    {@code
          *     return reduce(Long::max);
    @@ -504,7 +548,7 @@ public interface LongStream extends BaseStream {
     
         /**
          * Returns the count of elements in this stream.  This is a special case of
    -     * a reduction and is
    +     * a reduction and is
          * equivalent to:
          * 
    {@code
          *     return map(e -> 1L).sum();
    @@ -520,7 +564,10 @@ public interface LongStream extends BaseStream {
          * 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
    -     * reduction.
    +     * reduction.
    +     *
    +     * 

    This is a terminal + * operation. * * @return an {@code OptionalDouble} containing the average element of this * stream, or an empty optional if the stream is empty @@ -530,7 +577,10 @@ public interface LongStream extends BaseStream { /** * Returns a {@code LongSummaryStatistics} describing various summary data * about the elements of this stream. This is a special case of a - * reduction. + * reduction. + * + *

    This is a terminal + * operation. * * @return a {@code LongSummaryStatistics} describing various summary data * about the elements of this stream @@ -587,9 +637,8 @@ public interface LongStream extends BaseStream { /** * 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. * *

    This is a short-circuiting * terminal operation. @@ -609,8 +658,8 @@ public interface LongStream extends BaseStream { *

    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 +671,9 @@ public interface LongStream extends BaseStream { * Returns a {@code DoubleStream} consisting of the elements of this stream, * converted to {@code double}. * + *

    This is an intermediate + * operation. + * * @return a {@code DoubleStream} consisting of the elements of this stream, * converted to {@code double} */ @@ -631,6 +683,9 @@ public interface LongStream extends BaseStream { * Returns a {@code Stream} consisting of the elements of this stream, * each boxed to a {@code Long}. * + *

    This is an intermediate + * operation. + * * @return a {@code Stream} consistent of the elements of this stream, * each boxed to {@code Long} */ @@ -679,7 +734,7 @@ public interface LongStream extends BaseStream { } /** - * 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 +744,7 @@ public interface LongStream extends BaseStream { } /** - * 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 +782,9 @@ public interface LongStream extends BaseStream { } /** - * 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 +796,7 @@ public interface LongStream extends BaseStream { } /** - * 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 +829,7 @@ public interface LongStream extends BaseStream { } /** - * 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,16 +863,16 @@ public interface LongStream extends BaseStream { } /** - * 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. 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); @@ -832,9 +887,9 @@ public interface LongStream extends BaseStream { /** * A mutable builder for a {@code LongStream}. * - *

    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 + *

    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. diff --git a/jdk/src/share/classes/java/util/stream/PipelineHelper.java b/jdk/src/share/classes/java/util/stream/PipelineHelper.java index 6824e3b3179..f510131d6ec 100644 --- a/jdk/src/share/classes/java/util/stream/PipelineHelper.java +++ b/jdk/src/share/classes/java/util/stream/PipelineHelper.java @@ -28,7 +28,7 @@ import java.util.Spliterator; import java.util.function.IntFunction; /** - * Helper class for executing + * Helper class for executing * stream pipelines, capturing all of the information about a stream * pipeline (output shape, intermediate operations, stream flags, parallelism, * etc) in one place. diff --git a/jdk/src/share/classes/java/util/stream/ReferencePipeline.java b/jdk/src/share/classes/java/util/stream/ReferencePipeline.java index 42d711f4b2b..9d6aa59c8a7 100644 --- a/jdk/src/share/classes/java/util/stream/ReferencePipeline.java +++ b/jdk/src/share/classes/java/util/stream/ReferencePipeline.java @@ -170,6 +170,7 @@ abstract class ReferencePipeline } @Override + @SuppressWarnings("unchecked") public void accept(P_OUT u) { if (predicate.test(u)) downstream.accept(u); @@ -263,6 +264,7 @@ abstract class ReferencePipeline } @Override + @SuppressWarnings("unchecked") public void accept(P_OUT u) { try (Stream result = mapper.apply(u)) { // We can do better that this too; optimize for depth=0 case and just grab spliterator and forEach it @@ -360,16 +362,17 @@ abstract class ReferencePipeline } @Override - public final Stream peek(Consumer tee) { - Objects.requireNonNull(tee); + public final Stream peek(Consumer action) { + Objects.requireNonNull(action); return new StatelessOp(this, StreamShape.REFERENCE, 0) { @Override Sink opWrapSink(int flags, Sink sink) { return new Sink.ChainedReference(sink) { @Override + @SuppressWarnings("unchecked") public void accept(P_OUT u) { - tee.accept(u); + action.accept(u); downstream.accept(u); } }; @@ -515,10 +518,10 @@ abstract class ReferencePipeline } @Override - public final R collect(Supplier resultFactory, + public final R collect(Supplier supplier, BiConsumer accumulator, BiConsumer combiner) { - return evaluate(ReduceOps.makeRef(resultFactory, accumulator, combiner)); + return evaluate(ReduceOps.makeRef(supplier, accumulator, combiner)); } @Override diff --git a/jdk/src/share/classes/java/util/stream/Stream.java b/jdk/src/share/classes/java/util/stream/Stream.java index 715729f24a7..4a9f05f5103 100644 --- a/jdk/src/share/classes/java/util/stream/Stream.java +++ b/jdk/src/share/classes/java/util/stream/Stream.java @@ -24,13 +24,18 @@ */ package java.util.stream; +import java.nio.charset.Charset; +import java.nio.file.Files; +import java.nio.file.Path; 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 +49,90 @@ import java.util.function.ToIntFunction; 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 consumed 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}: * - *

    For sequential stream pipelines, all operations are performed in the - * encounter order of the pipeline - * source, if the pipeline source has a defined encounter order. + *

    {@code
    + *     int sum = widgets.stream()
    + *                      .filter(w -> w.getColor() == RED)
    + *                      .mapToInt(w -> w.getWeight())
    + *                      .sum();
    + * }
    * - *

    For parallel stream pipelines, unless otherwise specified, intermediate - * stream operations preserve the - * encounter order 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 non-interference - * requirements, 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. + * In this example, {@code widgets} is a {@code Collection}. 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. * - *

    Unless otherwise noted, passing a {@code null} argument to any stream - * method may result in a {@link NullPointerException}. + *

    To perform a computation, stream + * operations are composed into a + * stream pipeline. 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 intermediate operations (which transform a + * stream into another stream, such as {@link Stream#filter(Predicate)}), and a + * terminal operation (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. * - * @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. + *

    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 type of elements + *

    A stream pipeline, like the "widgets" example above, can be viewed as + * a query 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. + * + *

    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 functional interface 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 + * effectively stateless + * (their result should not depend on any state that might change during + * execution of the stream pipeline.) + * + *

    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. + * + *

    Streams have a {@link #close()} method and implement {@link AutoCloseable}, + * but nearly all stream instances do not actually need to be closed after use. + * Generally, only streams whose source is an IO channel (such as those returned + * by {@link Files#lines(Path, Charset)}) will require closing. Most streams + * are backed by collections, arrays, or generating functions, which require no + * special resource management. (If a stream does require closing, it can be + * declared as a resource in a {@code try}-with-resources statement.) + * + *

    Stream pipelines may execute either sequentially or in + * parallel. 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 the type of the stream elements * @since 1.8 * @see java.util.stream */ @@ -168,9 +212,9 @@ public interface Stream extends BaseStream> { /** * 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.) * *

    This is an intermediate * operation. @@ -197,9 +241,9 @@ public interface Stream extends BaseStream> { /** * 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.) * *

    This is an intermediate * operation. @@ -214,9 +258,9 @@ public interface Stream extends BaseStream> { /** * 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.) * *

    This is an intermediate * operation. @@ -231,9 +275,9 @@ public interface Stream extends BaseStream> { /** * 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.) * *

    This is an intermediate * operation. @@ -260,7 +304,7 @@ public interface Stream extends BaseStream> { * 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. * *

    This is a stateful * intermediate operation. @@ -301,18 +345,18 @@ public interface Stream extends BaseStream> { *

    {@code
          *     list.stream()
          *         .filter(filteringFunction)
    -     *         .peek(e -> {System.out.println("Filtered value: " + e); });
    +     *         .peek(e -> System.out.println("Filtered value: " + e));
          *         .map(mappingFunction)
    -     *         .peek(e -> {System.out.println("Mapped value: " + e); });
    +     *         .peek(e -> System.out.println("Mapped value: " + e));
          *         .collect(Collectors.intoList());
          * }
    * - * @param consumer a + * @param action a * non-interfering action to perform on the elements as * they are consumed from the stream * @return the new stream */ - Stream peek(Consumer consumer); + Stream peek(Consumer action); /** * Returns a stream consisting of the elements of this stream, truncated @@ -329,8 +373,8 @@ public interface Stream extends BaseStream> { /** * 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. * *

    This is a stateful @@ -344,10 +388,10 @@ public interface Stream extends BaseStream> { /** * 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. * *

    This is a short-circuiting * stateful intermediate operation. @@ -405,11 +449,23 @@ public interface Stream extends BaseStream> { /** * 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. * *

    This is a terminal * operation. * + * @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: + *

    {@code
    +     *     Person[] men = people.stream()
    +     *                          .filter(p -> p.getGender() == MALE)
    +     *                          .toArray(Person[]::new);
    +     * }
    + * * @param 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 +507,7 @@ public interface Stream extends BaseStream> { * Integer sum = integers.reduce(0, (a, b) -> a+b); * }
    * - * or more compactly: + * or: * *
    {@code
          *     Integer sum = integers.reduce(0, Integer::sum);
    @@ -501,7 +557,8 @@ public interface Stream extends BaseStream> {
          * @param accumulator an associative
          *                    non-interfering,
          *                    stateless function for combining two values
    -     * @return the result of the reduction
    +     * @return an {@link Optional} describing the result of the reduction
    +     * @throws NullPointerException if the result of the reduction is null
          * @see #reduce(Object, BinaryOperator)
          * @see #min(java.util.Comparator)
          * @see #max(java.util.Comparator)
    @@ -511,7 +568,7 @@ public interface Stream extends BaseStream> {
         /**
          * Performs a reduction 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:
          * 
    {@code
          *     U result = identity;
          *     for (T element : this stream)
    @@ -537,8 +594,8 @@ public interface Stream extends BaseStream> {
          * 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  The type of the result
          * @param identity the identity value for the combiner function
    @@ -561,12 +618,12 @@ public interface Stream extends BaseStream> {
         /**
          * Performs a mutable
          * reduction 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:
          * 
    {@code
    -     *     R result = resultFactory.get();
    +     *     R result = supplier.get();
          *     for (T element : this stream)
          *         accumulator.accept(result, element);
          *     return result;
    @@ -579,10 +636,11 @@ public interface Stream extends BaseStream> {
          * operation.
          *
          * @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}:
          * 
    {@code
    -     *     List asList = stringStream.collect(ArrayList::new, ArrayList::add, ArrayList::addAll);
    +     *     List asList = stringStream.collect(ArrayList::new, ArrayList::add,
    +     *                                                ArrayList::addAll);
          * }
    * *

    The following will take a stream of strings and concatenates them into a @@ -594,10 +652,9 @@ public interface Stream extends BaseStream> { * }

    * * @param type of the result - * @param resultFactory 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. + * @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. * @param accumulator an associative * non-interfering, * stateless function for incorporating an additional @@ -608,24 +665,24 @@ public interface Stream extends BaseStream> { * must be compatible with the accumulator function * @return the result of the reduction */ - R collect(Supplier resultFactory, + R collect(Supplier supplier, BiConsumer accumulator, BiConsumer combiner); /** * Performs a mutable * reduction 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. * *

    This is a terminal * operation. * *

    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 +695,16 @@ public interface Stream extends BaseStream> { * *

    The following will classify {@code Person} objects by city: *

    {@code
    -     *     Map> peopleByCity
    -     *         = personStream.collect(Collectors.groupBy(Person::getCity));
    +     *     Map> peopleByCity
    +     *         = personStream.collect(Collectors.groupingBy(Person::getCity));
          * }
    * *

    The following will classify {@code Person} objects by state and city, * cascading two {@code Collector}s together: *

    {@code
    -     *     Map>> peopleByStateAndCity
    -     *         = personStream.collect(Collectors.groupBy(Person::getState,
    -     *                                                   Collectors.groupBy(Person::getCity)));
    +     *     Map>> peopleByStateAndCity
    +     *         = personStream.collect(Collectors.groupingBy(Person::getState,
    +     *                                                      Collectors.groupingBy(Person::getCity)));
          * }
    * * @param the type of the result @@ -662,7 +719,7 @@ public interface Stream extends BaseStream> { /** * Returns the minimum element of this stream according to the provided * {@code Comparator}. This is a special case of a - * reduction. + * reduction. * *

    This is a terminal operation. * @@ -671,13 +728,14 @@ public interface Stream extends BaseStream> { * elements of this stream * @return an {@code Optional} describing the minimum element of this stream, * or an empty {@code Optional} if the stream is empty + * @throws NullPointerException if the minimum element is null */ Optional min(Comparator comparator); /** * Returns the maximum element of this stream according to the provided * {@code Comparator}. This is a special case of a - * reduction. + * reduction. * *

    This is a terminal * operation. @@ -687,12 +745,13 @@ public interface Stream extends BaseStream> { * elements of this stream * @return an {@code Optional} describing the maximum element of this stream, * or an empty {@code Optional} if the stream is empty + * @throws NullPointerException if the maximum element is null */ Optional max(Comparator comparator); /** * Returns the count of elements in this stream. This is a special case of - * a reduction and is + * a reduction and is * equivalent to: *

    {@code
          *     return mapToLong(e -> 1L).sum();
    @@ -753,10 +812,9 @@ public interface Stream extends BaseStream> {
         boolean noneMatch(Predicate 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.
          *
          * 

    This is a short-circuiting * terminal operation. @@ -777,8 +835,8 @@ public interface Stream extends BaseStream> { *

    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 +879,20 @@ public interface Stream extends BaseStream> { } /** - * Returns a sequential stream whose elements are the specified values. + * Returns a sequential ordered stream whose elements are the specified values. * * @param 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 + @SuppressWarnings("varargs") public static Stream 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 +930,8 @@ public interface Stream extends BaseStream> { } /** - * 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 the type of stream elements @@ -887,17 +945,16 @@ public interface Stream extends BaseStream> { } /** - * 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. When the resulting stream is closed, the close * handlers for both input streams are invoked. * * @param 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 Stream concat(Stream a, Stream b) { @@ -917,7 +974,7 @@ public interface Stream extends BaseStream> { * {@code Builder} (without the copying overhead that comes from using * an {@code ArrayList} as a temporary buffer.) * - *

    A {@code Stream.Builder} has a lifecycle, where it starts in a building + *

    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 diff --git a/jdk/src/share/classes/java/util/stream/StreamSpliterators.java b/jdk/src/share/classes/java/util/stream/StreamSpliterators.java index 4a62803b56b..f7b78422ebe 100644 --- a/jdk/src/share/classes/java/util/stream/StreamSpliterators.java +++ b/jdk/src/share/classes/java/util/stream/StreamSpliterators.java @@ -1456,4 +1456,5 @@ class StreamSpliterators { } } } -} \ No newline at end of file +} + diff --git a/jdk/src/share/classes/java/util/stream/StreamSupport.java b/jdk/src/share/classes/java/util/stream/StreamSupport.java index f6e04b0a51a..6feadd1db21 100644 --- a/jdk/src/share/classes/java/util/stream/StreamSupport.java +++ b/jdk/src/share/classes/java/util/stream/StreamSupport.java @@ -32,12 +32,8 @@ import java.util.function.Supplier; * Low-level utility methods for creating and manipulating streams. * *

    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}. - * - *

    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 @@ public final class StreamSupport { * {@code Supplier} of {@code Spliterator}. * *

    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. * *

    For spliterators that report a characteristic of {@code IMMUTABLE} @@ -88,7 +84,7 @@ public final class StreamSupport { * late-binding, 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 + *

    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 @@ public final class StreamSupport { * {@code Supplier} of {@code Spliterator.OfInt}. * *

    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. * *

    For spliterators that report a characteristic of {@code IMMUTABLE} @@ -156,7 +152,7 @@ public final class StreamSupport { * late-binding, 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 + *

    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 @@ public final class StreamSupport { * {@code Supplier} of {@code Spliterator.OfLong}. * *

    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. * *

    For spliterators that report a characteristic of {@code IMMUTABLE} @@ -223,7 +219,7 @@ public final class StreamSupport { * late-binding, 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 + *

    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 @@ public final class StreamSupport { * {@code Supplier} of {@code Spliterator.OfDouble}. * *

    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. * *

    For spliterators that report a characteristic of {@code IMMUTABLE} @@ -290,7 +286,7 @@ public final class StreamSupport { * late-binding, 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 + *

    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 diff --git a/jdk/src/share/classes/java/util/stream/package-info.java b/jdk/src/share/classes/java/util/stream/package-info.java index 46d033e38cd..2c01847ace3 100644 --- a/jdk/src/share/classes/java/util/stream/package-info.java +++ b/jdk/src/share/classes/java/util/stream/package-info.java @@ -24,347 +24,484 @@ */ /** - *

    java.util.stream

    - * - * Classes to support functional-style operations on streams of values, as in the following: + * Classes to support functional-style operations on streams of elements, such + * as map-reduce transformations on collections. For example: * *
    {@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();
      * }
    * - *

    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 reduction - * operation) on the stream to obtain the sum of the weights of the red blocks. + *

    Here we use {@code widgets}, a {@code Collection}, + * as a source for a stream, and then perform a filter-map-reduce on the stream + * to obtain the sum of the weights of the red widgets. (Summation is an + * example of a reduction + * operation.) * - *

    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: + *

    The key abstraction introduced in this package is stream. 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: * *

      - *
    • 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.
    • - *
    • 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.
    • - *
    • 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.
    • - *
    • 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.
    • + *
    • No storage. A stream is not a data structure that stores elements; + * instead, it conveys elements from a source such as a data structure, + * an array, a generator function, or an I/O channel, through a pipeline of + * computational operations.
    • + *
    • 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.
    • + *
    • 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.
    • + *
    • 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.
    • + *
    • Consumable. The elements of a stream are only 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. + *
    • *
    * - *

    Stream pipelines

    + * Streams can be obtained in a number of ways. Some examples include: + *
      + *
    • From a {@link java.util.Collection} via the {@code stream()} and + * {@code parallelStream()} methods;
    • + *
    • From an array via {@link java.util.Arrays#stream(Object[])};
    • + *
    • From static factory methods on the stream classes, such as + * {@link java.util.stream.Stream#of(Object[])}, + * {@link java.util.stream.IntStream#range(int, int)} + * or {@link java.util.stream.Stream#iterate(Object, UnaryOperator)};
    • + *
    • The lines of a file can be obtained from {@link java.io.BufferedReader#lines()};
    • + *
    • Streams of file paths can be obtained from methods in {@link java.nio.file.Files};
    • + *
    • Streams of random numbers can be obtained from {@link java.util.Random#ints()};
    • + *
    • 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()}.
    • + *
    * - *

    Streams are used to create pipelines of operations. 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 intermediate operations - * such as {@code Stream.filter} or {@code Stream.map}; and a terminal operation such - * as {@code Stream.forEach} or {@code java.util.stream.Stream.reduce}. Stream operations may take as parameters - * function values (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. + *

    Additional stream sources can be provided by third-party libraries using + * these techniques. * - *

    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. + *

    Stream operations and pipelines

    * - *

    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: - *

    {@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();
    - * }
    + *

    Stream operations are + * divided into intermediate and terminal operations, and are + * combined to form stream pipelines. 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 intermediate operations such + * as {@code Stream.filter} or {@code Stream.map}; and a terminal + * operation such as {@code Stream.forEach} or {@code Stream.reduce}. * - *

    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 + *

    Intermediate operations return a new stream. They are always + * lazy; executing an intermediate operation such as + * {@code filter()} does not actually perform any filtering, but instead + * creates a new stream that, when traversed, contains the elements of + * the initial stream that match the given predicate. Traversal + * of the pipeline source does not begin until the terminal operation of the + * pipeline is executed. * - *

    Stream operations

    + *

    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. In almost all cases, terminal operations are eager, + * completing their traversal of the data source and processing of the pipeline + * before returning. Only the terminal operations {@code iterator()} and + * {@code spliterator()} are not; these are provided as an "escape hatch" to enable + * arbitrary client-controlled pipeline traversals in the event that the + * existing operations are not sufficient to the task. * - *

    Intermediate stream operation (such as {@code filter} or {@code sorted}) always produce a - * new {@code Stream}, and are alwayslazy. 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.) + *

    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.) * - *

    Intermediate operations are further divided into stateless and stateful - * 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. + *

    Intermediate operations are further divided into stateless + * and stateful operations. Stateless operations, such as {@code filter} + * and {@code map}, retain no state from previously seen element when processing + * a new element -- each element can be processed + * independently of operations on other elements. Stateful operations, such as + * {@code distinct} and {@code sorted}, may incorporate state from previously + * seen elements when processing new elements. * - *

    Further, some operations are deemed short-circuiting 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.) + *

    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 may require multiple passes on the data 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. * - * 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. + *

    Further, some operations are deemed short-circuiting 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 in the pipeline + * is a necessary, but not sufficient, condition for the processing of an infinite + * stream to terminate normally in finite time. * *

    Parallelism

    * - *

    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 + *

    Processing elements with an explicit {@code for-}loop is inherently serial. + * Streams facilitate parallel execution by reframing the computation as a pipeline of + * aggregate operations, rather than as imperative operations on each individual + * element. All streams operations can execute either in serial or in parallel. + * 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 streams can be efficiently parallelized by + * invoking their {@link java.util.stream.BaseStream#parallel()} method. + * To execute the prior "sum of weights of widgets" query in parallel, we would + * do: * *

    {@code
    - *     int sumOfWeights = blocks.parallelStream().filter(b -> b.getColor() == RED)
    - *                                               .mapToInt(b -> b.getWeight())
    - *                                               .sum();
    + *     int sumOfWeights = widgets.}{@code parallelStream()}{@code .filter(b -> b.getColor() == RED)
    + *                                                .mapToInt(b -> b.getWeight())
    + *                                                .sum();
      * }
    * - *

    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.) + *

    The only difference between the serial and parallel versions of this + * example is the creation of the initial stream, using "{@code parallelStream()}" + * instead of "{@code stream()}". When the terminal operation is initiated, + * the stream pipeline is executed sequentially or in parallel depending on the + * orientation of the stream on which it is invoked. Whether a stream will execute in serial or + * parallel can be determined with the {@code isParallel()} method, and the + * orientation of a stream can be modified with 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. * - *

    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 stateless. + *

    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. * - *

    Ordering

    - * - *

    Streams may or may not have an encounter order. 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}. - * - *

    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. - * - *

    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.) - * - *

    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 - * improved parallel performance for some stateful or terminal operations. + *

    Most stream operations accept parameters that describe user-specified + * behavior, which are often lambda expressions. To preserve correct behavior, + * these behavioral parameters must be non-interfering, and in + * most cases must be stateless. Such parameters are always instances + * of a functional interface such + * as {@link java.util.function.Function}, and are often lambda expressions or + * method references. * *

    Non-interference

    * - * 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 interference 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 not modified at all during the execution - * of the stream pipeline. (Some data sources, such as concurrent collections, are - * specifically designed to handle concurrent modification.) + * 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 + * interference with the data source during the execution of a stream + * pipeline. Except for the escape-hatch operations {@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 + * not modified at all during the execution of the stream pipeline. + * The notable exception to this are streams whose sources are concurrent + * collections, which are specifically designed to handle concurrent modification. * - *

    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 interfere 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. + *

    Accordingly, behavioral parameters passed to stream methods should never + * modify the stream's data source. An implementation is said to + * interfere 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 behavior. + * + *

    Results may be nondeterministic or incorrect if the behavioral + * parameters of stream operations are stateful. 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: * - *

    Further, results may be nondeterministic or incorrect if the lambda expressions passed to - * stream operations are stateful. 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: *

    {@code
      *     Set seen = Collections.synchronizedSet(new HashSet<>());
      *     stream.parallel().map(e -> { if (seen.add(e)) return 0; else return e; })...
      * }
    - * 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. + * + * 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: + * + *
    {@code
    + *     List l = new ArrayList(Arrays.asList("one", "two"));
    + *     Stream sl = l.stream();
    + *     l.add("three");
    + *     String s = sl.collect(joining(" "));
    + * }
    + * + * 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 collections, and most other JDK classes, + * are well-behaved in this manner; for streams generated by other libraries, see + * Low-level stream + * construction for requirements for building well-behaved streams. + * + *

    Some streams, particularly those whose stream sources are concurrent, can + * tolerate concurrent modification during execution of a stream pipeline. + * However, in no case -- even if the stream source is concurrent -- should + * behavioral parameters to stream operations modify the stream source. Modifying + * the stream source from within the stream source may cause pipeline execution + * to fail to terminate, produce inaccurate results, or throw exceptions. + * The following example shows inappropriate interference with the source: + *

    {@code
    + *     // Don't do this!
    + *     List l = new ArrayList(Arrays.asList("one", "two"));
    + *     Stream sl = l.stream();
    + *     String s = sl.peek(s -> l.add("BAD LAMBDA")).collect(joining(" "));
    + * }
    * *

    Side-effects

    * + * 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 + * reduction instead of mutable + * accumulators. However, 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 operate only via side-effects; + * these should be used with care. + * + *

    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. + * + *

    {@code
    + *     ArrayList results = new ArrayList<>();
    + *     stream.filter(s -> pattern.matcher(s).matches())
    + *           .forEach(s -> results.add(s));  // Unnecessary use of side-effects!
    + * }
    + * + * This code unnecessarily uses side-effects. 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. Furthermore, using side-effects here is completely + * unnecessary; the {@code forEach()} can simply be replaced with a reduction + * operation that is safer, more efficient, and more amenable to + * parallelization: + * + *
    {@code
    + *     Listresults =
    + *         stream.filter(s -> pattern.matcher(s).matches())
    + *               .collect(Collectors.toList());  // No side-effects!
    + * }
    + * + *

    Ordering

    + * + *

    Streams may or may not have a defined encounter order. 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()}. + * + *

    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, then any permutation of the values {@code [2, 4, 6]} would be a valid + * result. + * + *

    For sequential streams, the presence or absence of an encounter order does + * not affect performance, only determinism. If a stream is ordered, repeated + * execution of identical stream pipelines on an identical source will produce + * an identical result; if it is not ordered, repeated execution might produce + * different results. + * + *

    For parallel streams, relaxing the ordering constraint can sometimes enable + * more efficient execution. Certain aggregate operations, + * such as filtering duplicates ({@code distinct()}) or grouped reductions + * ({@code Collectors.groupingBy()}) can be implemented more efficiently if ordering of elements + * is not relevant. Similarly, operations that are intrinsically tied to encounter order, + * such as {@code limit()}, may require + * buffering to ensure proper ordering, undermining the benefit of parallelism. + * In cases where the stream has an encounter order, but the user does not + * particularly care about that encounter order, explicitly de-ordering + * the stream with {@link java.util.stream.BaseStream#unordered() unordered()} may + * improve parallel performance for some stateful or terminal operations. + * However, most stream pipelines, such as the "sum of weight of blocks" example + * above, still parallelize efficiently even under ordering constraints. + * *

    Reduction operations

    * - * A reduction 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 reduction operation (also called a fold) 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 elements into a list. The streams classes have + * multiple forms of general 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()}, + * as well as multiple specialized reduction forms such as + * {@link java.util.stream.IntStream#sum() sum()}, {@link java.util.stream.IntStream#max() max()}, + * or {@link java.util.stream.IntStream#count() count()}. * - *

    Of course, such operations can be readily implemented as simple sequential loops, as in: + *

    Of course, such operations can be readily implemented as simple sequential + * loops, as in: *

    {@code
      *    int sum = 0;
      *    for (int x : numbers) {
      *       sum += x;
      *    }
      * }
    - * 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 - * associative. For example, given a - * stream of numbers for which we want to find the sum, we can write: + * However, there are good reasons 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 + * are associative and + * stateless. + * For example, given a stream of numbers for which we want to find the sum, we + * can write: *
    {@code
    - *    int sum = numbers.reduce(0, (x,y) -> x+y);
    + *    int sum = numbers.stream().reduce(0, (x,y) -> x+y);
      * }
    - * or more succinctly: + * or: *
    {@code
    - *    int sum = numbers.reduce(0, Integer::sum);
    + *    int sum = numbers.stream().reduce(0, Integer::sum);
      * }
    * - *

    (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.) - * - *

    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. - * - *

    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: + *

    These reduction operations can run safely in parallel with almost no + * modification: *

    {@code
    - *     OptionalInt heaviest = blocks.stream()
    - *                                  .mapToInt(Block::getWeight)
    - *                                  .reduce(Integer::max);
    + *    int sum = numbers.parallelStream().reduce(0, Integer::sum);
      * }
    * - *

    In its more general form, a {@code reduce} operation on elements of type {@code } - * yielding a result of type {@code } requires three parameters: + *

    Reduction parallellizes well because the implementation + * can operate on subsets of the data in parallel, and then combine the + * intermediate results to get the final correct answer. (Even if the language + * had a "parallel for-each" construct, the mutative accumulation approach would + * still required the developer to provide + * thread-safe updates to the shared accumulating variable {@code sum}, and + * the required synchronization would then likely eliminate any performance gain from + * parallelism.) Using {@code reduce()} instead removes all of the + * burden of parallelizing the reduction operation, and the library can provide + * an efficient parallel implementation with no additional synchronization + * required. + * + *

    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: + *

    {@code
    + *     OptionalInt heaviest = widgets.parallelStream()
    + *                                   .mapToInt(Widget::getWeight)
    + *                                   .max();
    + * }
    + * + *

    In its more general form, a {@code reduce} operation on elements of type + * {@code } yielding a result of type {@code } requires three parameters: *

    {@code
      *  U reduce(U identity,
    - *              BiFunction accumlator,
    + *              BiFunction accumulator,
      *              BinaryOperator combiner);
      * }
    - * Here, the identity element is both an initial seed for the reduction, and a default - * result if there are no elements. The accumulator function takes a partial result and - * the next element, and produce a new partial result. The combiner function combines - * the partial results of two accumulators to produce a new partial result, and eventually the - * final result. + * Here, the identity element is both an initial seed value for the reduction + * and a default result if there are no input elements. The accumulator + * function takes a partial result and the next element, and produces a new + * partial result. The combiner function combines two partial results + * to produce a new partial result. (The combiner is necessary in parallel + * reductions, where the input is partitioned, a partial accumulation computed + * for each partition, and then the partial results are combined to produce a + * final result.) * - *

    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: + *

    More formally, the {@code identity} value must be an identity 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 associative 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)}. + * + *

    The three-argument form is a generalization of the two-argument form, + * incorporating a mapping step into the accumulation step. We could + * re-cast the simple sum-of-weights example using the more general form as + * follows: *

    {@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);
      * }
    - * 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 explicit map-reduce form is more readable and therefore should + * usually be preferred. The generalized form is provided for cases where + * significant work can be optimized away by combining mapping and reducing + * into a single function. * - *

    More formally, the {@code identity} value must be an identity 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 - * associative and must be compatible with the {@code accumulator} - * function; for all {@code u} and {@code t}, the following must hold: - *

    {@code
    - *     combiner.apply(u, accumulator.apply(identity, t)) == accumulator.apply(u, t)
    - * }
    + *

    Mutable reduction

    * - *

    Mutable Reduction

    - * - * A mutable 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 result container, such as a {@code Collection} or {@code StringBuilder}, + * A mutable reduction operation accumulates input elements into a + * mutable result container, such as a {@code Collection} or {@code StringBuilder}, * as it processes the elements in the stream. * - *

    For example, if we wanted to take a stream of strings and concatenate them into a single - * long string, we could achieve this with ordinary reduction: + *

    If we wanted to take a stream of strings and concatenate them into a + * single long string, we could achieve this with ordinary reduction: *

    {@code
      *     String concatenated = strings.reduce("", String::concat)
      * }
    * - * 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 O(n^2) 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 O(n^2) 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. * - *

    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 + *

    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 a {@code Collection}. + * A {@code collect} operation requires three functions: + * a factory function to construct new instances of the result container, an + * accumulator function to incorporate an input element into a result + * container, and a combining function to merge the contents of one result + * container into another. The form of this is very similar to the general * form of ordinary reduction: *

    {@code
      *  R collect(Supplier resultFactory,
      *               BiConsumer accumulator,
      *               BiConsumer combiner);
      * }
    - * 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()}, a 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: *

    {@code
      *     ArrayList strings = new ArrayList<>();
      *     for (T element : stream) {
    @@ -377,92 +514,107 @@
      *                                                (c, e) -> c.add(e.toString()),
      *                                                (c1, c2) -> c1.addAll(c2));
      * }
    - * or, noting that we have buried a mapping operation inside the accumulator function, more - * succinctly as: + * or, pulling the mapping operation out of the accumulator function, we could + * express it more succinctly as: *
    {@code
    - *     ArrayList strings = stream.map(Object::toString)
    - *                                       .collect(ArrayList::new, ArrayList::add, ArrayList::addAll);
    + *     List strings = stream.map(Object::toString)
    + *                                  .collect(ArrayList::new, ArrayList::add, ArrayList::addAll);
      * }
    - * 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. * - *

    As with the regular reduction operation, the ability to parallelize only comes if an - * associativity condition is met. The {@code combiner} is associative - * if for result containers {@code r1}, {@code r2}, and {@code r3}: + *

    The three aspects of {@code collect} -- supplier, accumulator, and combiner -- + * are tightly coupled. We can use the abstraction of + * of a {@link java.util.stream.Collector} to capture all three aspects. + * The above example for collecting strings into a {@code List} can be rewritten + * using a standard {@code Collector} as: *

    {@code
    - *    combiner.accept(r1, r2);
    - *    combiner.accept(r1, r3);
    - * }
    - * is equivalent to - *
    {@code
    - *    combiner.accept(r2, r3);
    - *    combiner.accept(r1, r2);
    - * }
    - * 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 identity with respect to the {@code combiner} so that for any result - * container {@code r}: - *
    {@code
    - *     combiner.accept(r, resultFactory.get());
    - * }
    - * 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}: - *
    {@code
    - *    r2 = resultFactory.get();
    - *    accumulator.accept(r2, t);
    - *    combiner.accept(r, r2);
    - * }
    - * is equivalent to: - *
    {@code
    - *    accumulator.accept(r,t);
    - * }
    - * where equivalence means that {@code r} is left in the same state (again according to the - * meaning of {@link java.lang.Object#equals equals}). - * - *

    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: - *

    {@code
    - *     ArrayList strings = stream.map(Object::toString)
    - *                                       .collect(Collectors.toList());
    + *     List strings = stream.map(Object::toString)
    + *                                  .collect(Collectors.toList());
      * }
    * - *

    Reduction, Concurrency, and Ordering

    + *

    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 combinators + * that transform one collector into another. For example, suppose we have a + * collector that computes the sum of the salaries of a stream of + * employees, as follows: * - * With some complex reduction operations, for example a collect that produces a - * {@code Map}, such as: + *

    {@code
    + *     Collector summingSalaries
    + *         = Collectors.summingInt(Employee::getSalary);
    + * } 
    + * + * (The {@code ?} for the second type parameter merely indicates that we don't + * care about the intermediate representation used by this collector.) + * 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) groupingBy}: + * + *
    {@code
    + *     Map salariesByDept
    + *         = employees.stream().collect(Collectors.groupingBy(Employee::getDepartment,
    + *                                                            summingSalaries));
    + * } 
    + * + *

    As with the regular reduction operation, {@code collect()} operations can + * only be parallelized 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 p} that is the + * result of any series of accumulator and combiner invocations, {@code p} must + * be equivalent to {@code combiner.apply(p, supplier.get())}. + * + *

    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: + *

    {@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
    + * } 
    + * + *

    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. + * + *

    Reduction, concurrency, and ordering

    + * + * With some complex reduction operations, for example a {@code collect()} that + * produces a {@code Map}, such as: *
    {@code
      *     Map> salesByBuyer
      *         = txns.parallelStream()
      *               .collect(Collectors.groupingBy(Transaction::getBuyer));
      * }
    - * (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. * *

    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 concurrent 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 concurrent + * reduction. * - *

    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)} + *

    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 *

      *
    • The stream is parallel;
    • @@ -472,15 +624,16 @@ *
    • Either the stream is unordered, or the collector has the * {@link java.util.stream.Collector.Characteristics#UNORDERED} characteristic. *
    - * For example: + * You can ensure the stream is unordered by using the + * {@link java.util.stream.BaseStream#unordered()} method. For example: *
    {@code
      *     Map> salesByBuyer
      *         = txns.parallelStream()
      *               .unordered()
      *               .collect(groupingByConcurrent(Transaction::getBuyer));
      * }
    - * (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}). * *

    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 +641,77 @@ * be constrained to implement either a sequential reduction or a merge-based * parallel reduction. * - *

    Associativity

    + *

    Associativity

    * - * An operator or function {@code op} is associative if the following holds: + * An operator or function {@code op} is associative if the following + * holds: *
    {@code
      *     (a op b) op c == a op (b op c)
      * }
    - * 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: *
    {@code
      *     a op b op c op d == (a op b) op (c op d)
      * }
    - * 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. * - *

    Stream sources

    - * TODO where does this section go? + *

    Examples of associative operations include numeric addition, min, and max, + * and string concatenation. * - * 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 + *

    Low-level stream construction

    * - * XXX - the following is quite low-level but important aspect of stream constriction + * 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? * - *

    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. + *

    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. * - *

    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 - * late-binding and not bind to the elements it covers until traversed, split or queried for - * estimated size. + *

    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. * - *

    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 + *

    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. + * + *

    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 late-binding. + * 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. * - *

    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 - * Non-Interference for - * more details. + *

    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 Non-Interference + * for more details. * - * XXX - move the following to the non-interference section - * - *

    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. - * - *

    For example, consider the following code: - *

    {@code
    - *     List l = new ArrayList(Arrays.asList("one", "two"));
    - *     Stream sl = l.stream();
    - *     l.add("three");
    - *     String s = sl.collect(joining(" "));
    - * }
    - * 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: - *
    {@code
    - *     List l = new ArrayList(Arrays.asList("one", "two"));
    - *     Stream sl = l.stream();
    - *     String s = sl.peek(s -> l.add("BAD LAMBDA")).collect(joining(" "));
    - * }
    - * 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; + +import java.util.function.BinaryOperator; +import java.util.function.UnaryOperator; From 28d455529e7bc76985029e762442edd824125e10 Mon Sep 17 00:00:00 2001 From: Dmitry Nadezhin Date: Wed, 11 Sep 2013 17:07:35 -0700 Subject: [PATCH 215/218] 8010430: Math.round has surprising behavior for odd values of ulp 1 If the effective floating point exponent is zero return the significand including the implicit 1-bit. Reviewed-by: bpb, darcy, gls --- jdk/src/share/classes/java/lang/Math.java | 66 ++++++++++++++--- .../share/classes/java/lang/StrictMath.java | 4 +- jdk/test/java/lang/Math/RoundTests.java | 71 ++++++++++++++++++- 3 files changed, 126 insertions(+), 15 deletions(-) diff --git a/jdk/src/share/classes/java/lang/Math.java b/jdk/src/share/classes/java/lang/Math.java index ae83e4265ad..98e901ac942 100644 --- a/jdk/src/share/classes/java/lang/Math.java +++ b/jdk/src/share/classes/java/lang/Math.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -646,7 +646,7 @@ public final class Math { /** * Returns the closest {@code int} to the argument, with ties - * rounding up. + * rounding to positive infinity. * *

    * Special cases: @@ -665,15 +665,37 @@ public final class Math { * @see java.lang.Integer#MIN_VALUE */ public static int round(float a) { - if (a != 0x1.fffffep-2f) // greatest float value less than 0.5 - return (int)floor(a + 0.5f); - else - return 0; + int intBits = Float.floatToRawIntBits(a); + int biasedExp = (intBits & FloatConsts.EXP_BIT_MASK) + >> (FloatConsts.SIGNIFICAND_WIDTH - 1); + int shift = (FloatConsts.SIGNIFICAND_WIDTH - 2 + + FloatConsts.EXP_BIAS) - biasedExp; + if ((shift & -32) == 0) { // shift >= 0 && shift < 32 + // a is a finite number such that pow(2,-32) <= ulp(a) < 1 + int r = ((intBits & FloatConsts.SIGNIF_BIT_MASK) + | (FloatConsts.SIGNIF_BIT_MASK + 1)); + if (intBits < 0) { + r = -r; + } + // In the comments below each Java expression evaluates to the value + // the corresponding mathematical expression: + // (r) evaluates to a / ulp(a) + // (r >> shift) evaluates to floor(a * 2) + // ((r >> shift) + 1) evaluates to floor((a + 1/2) * 2) + // (((r >> shift) + 1) >> 1) evaluates to floor(a + 1/2) + return ((r >> shift) + 1) >> 1; + } else { + // a is either + // - a finite number with abs(a) < exp(2,FloatConsts.SIGNIFICAND_WIDTH-32) < 1/2 + // - a finite number with ulp(a) >= 1 and hence a is a mathematical integer + // - an infinity or NaN + return (int) a; + } } /** * Returns the closest {@code long} to the argument, with ties - * rounding up. + * rounding to positive infinity. * *

    Special cases: *

    • If the argument is NaN, the result is 0. @@ -692,10 +714,32 @@ public final class Math { * @see java.lang.Long#MIN_VALUE */ public static long round(double a) { - if (a != 0x1.fffffffffffffp-2) // greatest double value less than 0.5 - return (long)floor(a + 0.5d); - else - return 0; + long longBits = Double.doubleToRawLongBits(a); + long biasedExp = (longBits & DoubleConsts.EXP_BIT_MASK) + >> (DoubleConsts.SIGNIFICAND_WIDTH - 1); + long shift = (DoubleConsts.SIGNIFICAND_WIDTH - 2 + + DoubleConsts.EXP_BIAS) - biasedExp; + if ((shift & -64) == 0) { // shift >= 0 && shift < 64 + // a is a finite number such that pow(2,-64) <= ulp(a) < 1 + long r = ((longBits & DoubleConsts.SIGNIF_BIT_MASK) + | (DoubleConsts.SIGNIF_BIT_MASK + 1)); + if (longBits < 0) { + r = -r; + } + // In the comments below each Java expression evaluates to the value + // the corresponding mathematical expression: + // (r) evaluates to a / ulp(a) + // (r >> shift) evaluates to floor(a * 2) + // ((r >> shift) + 1) evaluates to floor((a + 1/2) * 2) + // (((r >> shift) + 1) >> 1) evaluates to floor(a + 1/2) + return ((r >> shift) + 1) >> 1; + } else { + // a is either + // - a finite number with abs(a) < exp(2,DoubleConsts.SIGNIFICAND_WIDTH-64) < 1/2 + // - a finite number with ulp(a) >= 1 and hence a is a mathematical integer + // - an infinity or NaN + return (long) a; + } } private static final class RandomNumberGeneratorHolder { diff --git a/jdk/src/share/classes/java/lang/StrictMath.java b/jdk/src/share/classes/java/lang/StrictMath.java index 52336484e75..ae4af2bcac8 100644 --- a/jdk/src/share/classes/java/lang/StrictMath.java +++ b/jdk/src/share/classes/java/lang/StrictMath.java @@ -633,7 +633,7 @@ public final class StrictMath { /** * Returns the closest {@code int} to the argument, with ties - * rounding up. + * rounding to positive infinity. * *

      Special cases: *

      • If the argument is NaN, the result is 0. @@ -656,7 +656,7 @@ public final class StrictMath { /** * Returns the closest {@code long} to the argument, with ties - * rounding up. + * rounding to positive infinity. * *

        Special cases: *

        • If the argument is NaN, the result is 0. diff --git a/jdk/test/java/lang/Math/RoundTests.java b/jdk/test/java/lang/Math/RoundTests.java index 9994e97df85..cae190f9770 100644 --- a/jdk/test/java/lang/Math/RoundTests.java +++ b/jdk/test/java/lang/Math/RoundTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 6430675 + * @bug 6430675 8010430 * @summary Check for correct implementation of {Math, StrictMath}.round */ public class RoundTests { @@ -32,6 +32,8 @@ public class RoundTests { failures += testNearFloatHalfCases(); failures += testNearDoubleHalfCases(); + failures += testUnityULPCases(); + failures += testSpecialCases(); if (failures > 0) { System.err.println("Testing {Math, StrictMath}.round incurred " @@ -95,4 +97,69 @@ public class RoundTests { return failures; } + + private static int testUnityULPCases() { + int failures = 0; + for (float sign : new float[]{-1, 1}) { + for (float v1 : new float[]{1 << 23, 1 << 24}) { + for (int k = -5; k <= 5; k++) { + float value = (v1 + k) * sign; + float actual = Math.round(value); + failures += Tests.test("Math.round", value, actual, value); + } + } + } + + if (failures != 0) { + System.out.println(); + } + + for (double sign : new double[]{-1, 1}) { + for (double v1 : new double[]{1L << 52, 1L << 53}) { + for (int k = -5; k <= 5; k++) { + double value = (v1 + k) * sign; + double actual = Math.round(value); + failures += Tests.test("Math.round", value, actual, value); + } + } + } + + return failures; + } + + private static int testSpecialCases() { + int failures = 0; + + failures += Tests.test("Math.round", Float.NaN, Math.round(Float.NaN), 0.0F); + failures += Tests.test("Math.round", Float.POSITIVE_INFINITY, + Math.round(Float.POSITIVE_INFINITY), Integer.MAX_VALUE); + failures += Tests.test("Math.round", Float.NEGATIVE_INFINITY, + Math.round(Float.NEGATIVE_INFINITY), Integer.MIN_VALUE); + failures += Tests.test("Math.round", -(float)Integer.MIN_VALUE, + Math.round(-(float)Integer.MIN_VALUE), Integer.MAX_VALUE); + failures += Tests.test("Math.round", (float) Integer.MIN_VALUE, + Math.round((float) Integer.MIN_VALUE), Integer.MIN_VALUE); + failures += Tests.test("Math.round", 0F, Math.round(0F), 0.0F); + failures += Tests.test("Math.round", Float.MIN_VALUE, + Math.round(Float.MIN_VALUE), 0.0F); + failures += Tests.test("Math.round", -Float.MIN_VALUE, + Math.round(-Float.MIN_VALUE), 0.0F); + + failures += Tests.test("Math.round", Double.NaN, Math.round(Double.NaN), 0.0); + failures += Tests.test("Math.round", Double.POSITIVE_INFINITY, + Math.round(Double.POSITIVE_INFINITY), Long.MAX_VALUE); + failures += Tests.test("Math.round", Double.NEGATIVE_INFINITY, + Math.round(Double.NEGATIVE_INFINITY), Long.MIN_VALUE); + failures += Tests.test("Math.round", -(double)Long.MIN_VALUE, + Math.round(-(double)Long.MIN_VALUE), Long.MAX_VALUE); + failures += Tests.test("Math.round", (double) Long.MIN_VALUE, + Math.round((double) Long.MIN_VALUE), Long.MIN_VALUE); + failures += Tests.test("Math.round", 0, Math.round(0), 0.0); + failures += Tests.test("Math.round", Double.MIN_VALUE, + Math.round(Double.MIN_VALUE), 0.0); + failures += Tests.test("Math.round", -Double.MIN_VALUE, + Math.round(-Double.MIN_VALUE), 0.0); + + return failures; + } } From f6e4c46294b1a9df3f613bd4f14d6a6fc6b7c30f Mon Sep 17 00:00:00 2001 From: Shanliang Jiang Date: Fri, 13 Sep 2013 10:48:12 +0200 Subject: [PATCH 216/218] 8023669: MBean*Info.hashCode : NPE Reviewed-by: dholmes, dfuchs, jbachorik --- .../javax/management/MBeanAttributeInfo.java | 3 +- .../management/MBeanConstructorInfo.java | 7 +- .../classes/javax/management/MBeanInfo.java | 20 +- .../javax/management/MBeanOperationInfo.java | 3 +- .../javax/management/MBeanParameterInfo.java | 3 +- .../MBeanInfo/MBeanInfoHashCodeNPETest.java | 176 ++++++++++++++++++ 6 files changed, 190 insertions(+), 22 deletions(-) create mode 100644 jdk/test/javax/management/MBeanInfo/MBeanInfoHashCodeNPETest.java diff --git a/jdk/src/share/classes/javax/management/MBeanAttributeInfo.java b/jdk/src/share/classes/javax/management/MBeanAttributeInfo.java index d99b9f7b8ad..a70fb3a3571 100644 --- a/jdk/src/share/classes/javax/management/MBeanAttributeInfo.java +++ b/jdk/src/share/classes/javax/management/MBeanAttributeInfo.java @@ -30,6 +30,7 @@ import java.security.AccessController; import com.sun.jmx.mbeanserver.GetPropertyAction; import com.sun.jmx.mbeanserver.Introspector; +import java.util.Objects; /** @@ -301,7 +302,7 @@ public class MBeanAttributeInfo extends MBeanFeatureInfo implements Cloneable { right and we needlessly hashed in the description and parameter array. */ public int hashCode() { - return getName().hashCode() ^ getType().hashCode(); + return Objects.hash(getName(), getType()); } private static boolean isIs(Method getter) { diff --git a/jdk/src/share/classes/javax/management/MBeanConstructorInfo.java b/jdk/src/share/classes/javax/management/MBeanConstructorInfo.java index c2bbe5ef886..ad2176367d2 100644 --- a/jdk/src/share/classes/javax/management/MBeanConstructorInfo.java +++ b/jdk/src/share/classes/javax/management/MBeanConstructorInfo.java @@ -29,6 +29,7 @@ import com.sun.jmx.mbeanserver.Introspector; import java.lang.annotation.Annotation; import java.lang.reflect.Constructor; import java.util.Arrays; +import java.util.Objects; /** * Describes a constructor exposed by an MBean. Instances of this @@ -203,11 +204,7 @@ public class MBeanConstructorInfo extends MBeanFeatureInfo implements Cloneable quite long and yet the same between constructors. Likewise for the descriptor. */ public int hashCode() { - int hash = getName().hashCode(); - MBeanParameterInfo[] sig = fastGetSignature(); - for (int i = 0; i < sig.length; i++) - hash ^= sig[i].hashCode(); - return hash; + return Objects.hash(getName()) ^ Arrays.hashCode(fastGetSignature()); } private static MBeanParameterInfo[] constructorSignature(Constructor cn) { diff --git a/jdk/src/share/classes/javax/management/MBeanInfo.java b/jdk/src/share/classes/javax/management/MBeanInfo.java index ed04c347b70..f4a9581c520 100644 --- a/jdk/src/share/classes/javax/management/MBeanInfo.java +++ b/jdk/src/share/classes/javax/management/MBeanInfo.java @@ -36,6 +36,7 @@ import java.util.Map; import java.util.WeakHashMap; import java.security.AccessController; import java.security.PrivilegedAction; +import java.util.Objects; import static javax.management.ImmutableDescriptor.nonNullDescriptor; @@ -515,24 +516,15 @@ public class MBeanInfo implements Cloneable, Serializable, DescriptorRead { if (hashCode != 0) return hashCode; - hashCode = - getClassName().hashCode() ^ - getDescriptor().hashCode() ^ - arrayHashCode(fastGetAttributes()) ^ - arrayHashCode(fastGetOperations()) ^ - arrayHashCode(fastGetConstructors()) ^ - arrayHashCode(fastGetNotifications()); + hashCode = Objects.hash(getClassName(), getDescriptor()) + ^ Arrays.hashCode(fastGetAttributes()) + ^ Arrays.hashCode(fastGetOperations()) + ^ Arrays.hashCode(fastGetConstructors()) + ^ Arrays.hashCode(fastGetNotifications()); return hashCode; } - private static int arrayHashCode(Object[] array) { - int hash = 0; - for (int i = 0; i < array.length; i++) - hash ^= array[i].hashCode(); - return hash; - } - /** * Cached results of previous calls to arrayGettersSafe. This is * a WeakHashMap so that we don't prevent a class from being diff --git a/jdk/src/share/classes/javax/management/MBeanOperationInfo.java b/jdk/src/share/classes/javax/management/MBeanOperationInfo.java index 66b13a94ef0..8effa04f8d8 100644 --- a/jdk/src/share/classes/javax/management/MBeanOperationInfo.java +++ b/jdk/src/share/classes/javax/management/MBeanOperationInfo.java @@ -29,6 +29,7 @@ import com.sun.jmx.mbeanserver.Introspector; import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.util.Arrays; +import java.util.Objects; /** * Describes a management operation exposed by an MBean. Instances of @@ -309,7 +310,7 @@ public class MBeanOperationInfo extends MBeanFeatureInfo implements Cloneable { parameter array. */ @Override public int hashCode() { - return getName().hashCode() ^ getReturnType().hashCode(); + return Objects.hash(getName(), getReturnType()); } private static MBeanParameterInfo[] methodSignature(Method method) { diff --git a/jdk/src/share/classes/javax/management/MBeanParameterInfo.java b/jdk/src/share/classes/javax/management/MBeanParameterInfo.java index ec5a31fc93e..df3d59087df 100644 --- a/jdk/src/share/classes/javax/management/MBeanParameterInfo.java +++ b/jdk/src/share/classes/javax/management/MBeanParameterInfo.java @@ -25,6 +25,7 @@ package javax.management; +import java.util.Objects; /** * Describes an argument of an operation exposed by an MBean. @@ -143,6 +144,6 @@ public class MBeanParameterInfo extends MBeanFeatureInfo implements Cloneable { } public int hashCode() { - return getName().hashCode() ^ getType().hashCode(); + return Objects.hash(getName(), getType()); } } diff --git a/jdk/test/javax/management/MBeanInfo/MBeanInfoHashCodeNPETest.java b/jdk/test/javax/management/MBeanInfo/MBeanInfoHashCodeNPETest.java new file mode 100644 index 00000000000..bb35da38ba6 --- /dev/null +++ b/jdk/test/javax/management/MBeanInfo/MBeanInfoHashCodeNPETest.java @@ -0,0 +1,176 @@ +/* + * 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 javax.management.MBeanAttributeInfo; +import javax.management.MBeanConstructorInfo; +import javax.management.MBeanInfo; +import javax.management.MBeanNotificationInfo; +import javax.management.MBeanOperationInfo; +import javax.management.MBeanParameterInfo; +import javax.management.modelmbean.DescriptorSupport; +import javax.management.openmbean.SimpleType; + +/* + * @test + * @bug 8023669 + * @summary Test that hashCode()throws NullPointerException + * @author Shanliang JIANG + * @run clean MBeanInfoHashCodeNPETest + * @run build MBeanInfoHashCodeNPETest + * @run main MBeanInfoHashCodeNPETest + */ +public class MBeanInfoHashCodeNPETest { + private static int failed = 0; + + public static void main(String[] args) throws Exception { + System.out.println("---MBeanInfoHashCodeNPETest-main ..."); + + // ---- + System.out.println("\n---Testing on MBeanAttributeInfo..."); + MBeanAttributeInfo mbeanAttributeInfo = new MBeanAttributeInfo( + null, SimpleType.INTEGER.getClassName(), "description", true, true, false); + test(mbeanAttributeInfo, "class name"); + + mbeanAttributeInfo = new MBeanAttributeInfo( + "name", null, "description", true, true, false); + test(mbeanAttributeInfo, "type"); + + mbeanAttributeInfo = new MBeanAttributeInfo( + "name", SimpleType.INTEGER.getClassName(), null, true, true, false); + test(mbeanAttributeInfo, "description"); + + // ---- + System.out.println("\n---Testing on MBeanConstructorInfo..."); + MBeanConstructorInfo mbeanConstructorInfo = new MBeanConstructorInfo( + null, "", new MBeanParameterInfo[]{}, new DescriptorSupport()); + test(mbeanConstructorInfo, "name"); + + mbeanConstructorInfo = new MBeanConstructorInfo( + "", null, new MBeanParameterInfo[]{}, new DescriptorSupport()); + test(mbeanConstructorInfo, "description"); + + mbeanConstructorInfo = new MBeanConstructorInfo( + "", "", null, new DescriptorSupport()); + test(mbeanConstructorInfo, "MBeanParameterInfo"); + + mbeanConstructorInfo = new MBeanConstructorInfo( + "", "", new MBeanParameterInfo[]{}, null); + test(mbeanConstructorInfo, "descriptor"); + + // ---- + System.out.println("\n---Testing on MBeanOperationInfo..."); + MBeanOperationInfo mbeanOperationInfo = new MBeanOperationInfo( + null, "description", new MBeanParameterInfo[]{}, "type", 1, new DescriptorSupport()); + test(mbeanOperationInfo, "name"); + + mbeanOperationInfo = new MBeanOperationInfo( + "name", null, new MBeanParameterInfo[]{}, "type", 1, new DescriptorSupport()); + test(mbeanOperationInfo, "description"); + + mbeanOperationInfo = new MBeanOperationInfo( + "name", "description", null, "type", 1, new DescriptorSupport()); + test(mbeanOperationInfo, "MBeanParameterInfo"); + + mbeanOperationInfo = new MBeanOperationInfo( + "name", "description", new MBeanParameterInfo[]{}, null, 1, new DescriptorSupport()); + test(mbeanOperationInfo, "type"); + + mbeanOperationInfo = new MBeanOperationInfo( + "name", "description", new MBeanParameterInfo[]{}, "type", -1, new DescriptorSupport()); + test(mbeanOperationInfo, "native impact"); + + mbeanOperationInfo = new MBeanOperationInfo( + "name", "description", new MBeanParameterInfo[]{}, "type", 1, null); + test(mbeanOperationInfo, "Descriptor"); + + // ---- + System.out.println("\n---Testing on MBeanParameterInfo..."); + MBeanParameterInfo mbeanParameterInfo = new MBeanParameterInfo( + null, "type", "description", new DescriptorSupport()); + test(mbeanParameterInfo, "name"); + + mbeanParameterInfo = new MBeanParameterInfo( + "name", null, "description", new DescriptorSupport()); + test(mbeanParameterInfo, "description"); + + mbeanParameterInfo = new MBeanParameterInfo( + "name", "type", null, new DescriptorSupport()); + test(mbeanParameterInfo, "description"); + + mbeanParameterInfo = new MBeanParameterInfo( + "name", "type", "description", null); + test(mbeanParameterInfo, "Descriptor"); + + // ---- + System.out.println("\n---Testing on MBeanInfo..."); + String className = "toto"; + String description = "titi"; + MBeanAttributeInfo[] attrInfos = new MBeanAttributeInfo[]{}; + MBeanConstructorInfo[] constrInfos = new MBeanConstructorInfo[]{}; + MBeanOperationInfo[] operaInfos = new MBeanOperationInfo[]{}; + MBeanNotificationInfo[] notifInfos = new MBeanNotificationInfo[]{}; + + MBeanInfo minfo = new MBeanInfo(null, description, attrInfos, constrInfos, operaInfos, notifInfos); + test(minfo, "class name"); + + minfo = new MBeanInfo(className, description, attrInfos, constrInfos, operaInfos, notifInfos); + test(minfo, "name"); + + minfo = new MBeanInfo(className, null, attrInfos, constrInfos, operaInfos, notifInfos); + test(minfo, "description"); + + minfo = new MBeanInfo(className, description, null, constrInfos, operaInfos, notifInfos); + test(minfo, "attrInfos"); + + minfo = new MBeanInfo(className, description, attrInfos, constrInfos, null, notifInfos); + test(minfo, "operaInfos"); + + minfo = new MBeanInfo(className, description, attrInfos, constrInfos, operaInfos, null); + test(minfo, "notifInfos"); + + Thread.sleep(100); + if (failed > 0) { + throw new RuntimeException("Test failed: "+failed); + } else { + System.out.println("---Test: PASSED"); + } + } + + private static void test(Object obj, String param) { + try { + obj.hashCode(); + System.out.println("OK: "+obj.getClass().getSimpleName()+".hashCode worked with a null "+param); + } catch (NullPointerException npe) { + System.out.println("--->KO!!! "+obj.getClass().getSimpleName()+".hashCode got NPE with a null "+param); + failed++; + } + + try { + obj.toString(); + System.out.println("OK: "+obj.getClass().getSimpleName()+".toString worked with a null "+param); + } catch (NullPointerException npe) { + System.out.println("--->KO!!! "+obj.getClass().getSimpleName()+".toString got NPE."); + failed++; + } + } +} From 276b809ff474d3655f6b3d9786dd20fc4a47664f Mon Sep 17 00:00:00 2001 From: Brent Christian Date: Thu, 12 Sep 2013 14:22:53 -0700 Subject: [PATCH 217/218] 8024009: Remove jdk.map.useRandomSeed system property Removed usage of hashSeed in Hashtable & WeakHashMap, and removed tests Reviewed-by: alanb, mduigou --- .../share/classes/java/util/Hashtable.java | 104 +++--------------- .../share/classes/java/util/WeakHashMap.java | 39 +------ .../java/util/Map/CheckRandomHashSeed.java | 91 --------------- jdk/test/java/util/Map/Collisions.java | 2 - 4 files changed, 19 insertions(+), 217 deletions(-) delete mode 100644 jdk/test/java/util/Map/CheckRandomHashSeed.java diff --git a/jdk/src/share/classes/java/util/Hashtable.java b/jdk/src/share/classes/java/util/Hashtable.java index 518bd17f5b7..dc50e9393ee 100644 --- a/jdk/src/share/classes/java/util/Hashtable.java +++ b/jdk/src/share/classes/java/util/Hashtable.java @@ -168,68 +168,6 @@ public class Hashtable /** use serialVersionUID from JDK 1.0.2 for interoperability */ private static final long serialVersionUID = 1421746759512286392L; - private static class Holder { - // Unsafe mechanics - /** - * - */ - static final sun.misc.Unsafe UNSAFE; - - /** - * Offset of "final" hashSeed field we must set in - * readObject() method. - */ - static final long HASHSEED_OFFSET; - - static final boolean USE_HASHSEED; - - static { - String hashSeedProp = java.security.AccessController.doPrivileged( - new sun.security.action.GetPropertyAction( - "jdk.map.useRandomSeed")); - boolean localBool = (null != hashSeedProp) - ? Boolean.parseBoolean(hashSeedProp) : false; - USE_HASHSEED = localBool; - - if (USE_HASHSEED) { - try { - UNSAFE = sun.misc.Unsafe.getUnsafe(); - HASHSEED_OFFSET = UNSAFE.objectFieldOffset( - Hashtable.class.getDeclaredField("hashSeed")); - } catch (NoSuchFieldException | SecurityException e) { - throw new InternalError("Failed to record hashSeed offset", e); - } - } else { - UNSAFE = null; - HASHSEED_OFFSET = 0; - } - } - } - - /** - * A randomizing value associated with this instance that is applied to - * hash code of keys to make hash collisions harder to find. - * - * Non-final so it can be set lazily, but be sure not to set more than once. - */ - transient final int hashSeed; - - /** - * Return an initial value for the hashSeed, or 0 if the random seed is not - * enabled. - */ - final int initHashSeed() { - if (sun.misc.VM.isBooted() && Holder.USE_HASHSEED) { - int seed = ThreadLocalRandom.current().nextInt(); - return (seed != 0) ? seed : 1; - } - return 0; - } - - private int hash(Object k) { - return hashSeed ^ k.hashCode(); - } - /** * Constructs a new, empty hashtable with the specified initial * capacity and the specified load factor. @@ -251,7 +189,6 @@ public class Hashtable this.loadFactor = loadFactor; table = new Entry[initialCapacity]; threshold = (int)Math.min(initialCapacity * loadFactor, MAX_ARRAY_SIZE + 1); - hashSeed = initHashSeed(); } /** @@ -395,7 +332,7 @@ public class Hashtable */ public synchronized boolean containsKey(Object key) { Entry tab[] = table; - int hash = hash(key); + int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length; for (Entry e = tab[index] ; e != null ; e = e.next) { if ((e.hash == hash) && e.key.equals(key)) { @@ -423,7 +360,7 @@ public class Hashtable @SuppressWarnings("unchecked") public synchronized V get(Object key) { Entry tab[] = table; - int hash = hash(key); + int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length; for (Entry e = tab[index] ; e != null ; e = e.next) { if ((e.hash == hash) && e.key.equals(key)) { @@ -488,7 +425,7 @@ public class Hashtable rehash(); tab = table; - hash = hash(key); + hash = key.hashCode(); index = (hash & 0x7FFFFFFF) % tab.length; } @@ -524,7 +461,7 @@ public class Hashtable // Makes sure the key is not already in the hashtable. Entry tab[] = table; - int hash = hash(key); + int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length; @SuppressWarnings("unchecked") Entry entry = (Entry)tab[index]; @@ -551,7 +488,7 @@ public class Hashtable */ public synchronized V remove(Object key) { Entry tab[] = table; - int hash = hash(key); + int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length; @SuppressWarnings("unchecked") Entry e = (Entry)tab[index]; @@ -760,7 +697,7 @@ public class Hashtable Map.Entry entry = (Map.Entry)o; Object key = entry.getKey(); Entry[] tab = table; - int hash = hash(key); + int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length; for (Entry e = tab[index]; e != null; e = e.next) @@ -775,7 +712,7 @@ public class Hashtable Map.Entry entry = (Map.Entry) o; Object key = entry.getKey(); Entry[] tab = table; - int hash = hash(key); + int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length; @SuppressWarnings("unchecked") @@ -975,7 +912,7 @@ public class Hashtable // Makes sure the key is not already in the hashtable. Entry tab[] = table; - int hash = hash(key); + int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length; @SuppressWarnings("unchecked") Entry entry = (Entry)tab[index]; @@ -998,7 +935,7 @@ public class Hashtable Objects.requireNonNull(value); Entry tab[] = table; - int hash = hash(key); + int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length; @SuppressWarnings("unchecked") Entry e = (Entry)tab[index]; @@ -1021,7 +958,7 @@ public class Hashtable @Override public synchronized boolean replace(K key, V oldValue, V newValue) { Entry tab[] = table; - int hash = hash(key); + int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length; @SuppressWarnings("unchecked") Entry e = (Entry)tab[index]; @@ -1041,7 +978,7 @@ public class Hashtable @Override public synchronized V replace(K key, V value) { Entry tab[] = table; - int hash = hash(key); + int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length; @SuppressWarnings("unchecked") Entry e = (Entry)tab[index]; @@ -1060,7 +997,7 @@ public class Hashtable Objects.requireNonNull(mappingFunction); Entry tab[] = table; - int hash = hash(key); + int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length; @SuppressWarnings("unchecked") Entry e = (Entry)tab[index]; @@ -1084,7 +1021,7 @@ public class Hashtable Objects.requireNonNull(remappingFunction); Entry tab[] = table; - int hash = hash(key); + int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length; @SuppressWarnings("unchecked") Entry e = (Entry)tab[index]; @@ -1113,7 +1050,7 @@ public class Hashtable Objects.requireNonNull(remappingFunction); Entry tab[] = table; - int hash = hash(key); + int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length; @SuppressWarnings("unchecked") Entry e = (Entry)tab[index]; @@ -1148,7 +1085,7 @@ public class Hashtable Objects.requireNonNull(remappingFunction); Entry tab[] = table; - int hash = hash(key); + int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length; @SuppressWarnings("unchecked") Entry e = (Entry)tab[index]; @@ -1228,13 +1165,6 @@ public class Hashtable // Read in the length, threshold, and loadfactor s.defaultReadObject(); - // set hashMask - if (Holder.USE_HASHSEED) { - int seed = ThreadLocalRandom.current().nextInt(); - Holder.UNSAFE.putIntVolatile(this, Holder.HASHSEED_OFFSET, - (seed != 0) ? seed : 1); - } - // Read the original length of the array and number of elements int origlength = s.readInt(); int elements = s.readInt(); @@ -1282,7 +1212,7 @@ public class Hashtable } // Makes sure the key is not already in the hashtable. // This should not happen in deserialized version. - int hash = hash(key); + int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length; for (Entry e = tab[index] ; e != null ; e = e.next) { if ((e.hash == hash) && e.key.equals(key)) { @@ -1347,7 +1277,7 @@ public class Hashtable } public int hashCode() { - return (Objects.hashCode(key) ^ Objects.hashCode(value)); + return hash ^ Objects.hashCode(value); } public String toString() { diff --git a/jdk/src/share/classes/java/util/WeakHashMap.java b/jdk/src/share/classes/java/util/WeakHashMap.java index 0299d296638..81f74be8e9e 100644 --- a/jdk/src/share/classes/java/util/WeakHashMap.java +++ b/jdk/src/share/classes/java/util/WeakHashMap.java @@ -190,39 +190,6 @@ public class WeakHashMap */ int modCount; - private static class Holder { - static final boolean USE_HASHSEED; - - static { - String hashSeedProp = java.security.AccessController.doPrivileged( - new sun.security.action.GetPropertyAction( - "jdk.map.useRandomSeed")); - boolean localBool = (null != hashSeedProp) - ? Boolean.parseBoolean(hashSeedProp) : false; - USE_HASHSEED = localBool; - } - } - - /** - * A randomizing value associated with this instance that is applied to - * hash code of keys to make hash collisions harder to find. - * - * Non-final so it can be set lazily, but be sure not to set more than once. - */ - transient int hashSeed; - - /** - * Initialize the hashing mask value. - */ - final void initHashSeed() { - if (sun.misc.VM.isBooted() && Holder.USE_HASHSEED) { - // Do not set hashSeed more than once! - // assert hashSeed == 0; - int seed = ThreadLocalRandom.current().nextInt(); - hashSeed = (seed != 0) ? seed : 1; - } - } - @SuppressWarnings("unchecked") private Entry[] newTable(int n) { return (Entry[]) new Entry[n]; @@ -253,7 +220,6 @@ public class WeakHashMap table = newTable(capacity); this.loadFactor = loadFactor; threshold = (int)(capacity * loadFactor); - initHashSeed(); } /** @@ -329,7 +295,7 @@ public class WeakHashMap * in lower bits. */ final int hash(Object k) { - int h = hashSeed ^ k.hashCode(); + int h = k.hashCode(); // This function ensures that hashCodes that differ only by // constant multiples at each bit position have a bounded @@ -783,8 +749,7 @@ public class WeakHashMap public int hashCode() { K k = getKey(); V v = getValue(); - return ((k==null ? 0 : k.hashCode()) ^ - (v==null ? 0 : v.hashCode())); + return Objects.hashCode(k) ^ Objects.hashCode(v); } public String toString() { diff --git a/jdk/test/java/util/Map/CheckRandomHashSeed.java b/jdk/test/java/util/Map/CheckRandomHashSeed.java deleted file mode 100644 index 2acf1bc8c9c..00000000000 --- a/jdk/test/java/util/Map/CheckRandomHashSeed.java +++ /dev/null @@ -1,91 +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. - * - * 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 8005698 - * @summary Check operation of jdk.map.useRandomSeed property - * @run main CheckRandomHashSeed - * @run main/othervm -Djdk.map.useRandomSeed=false CheckRandomHashSeed - * @run main/othervm -Djdk.map.useRandomSeed=bogus CheckRandomHashSeed - * @run main/othervm -Djdk.map.useRandomSeed=true CheckRandomHashSeed true - * @author Brent Christian - */ -import java.lang.reflect.Field; -import java.util.Map; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.Hashtable; -import java.util.WeakHashMap; - -public class CheckRandomHashSeed { - private final static String PROP_NAME = "jdk.map.useRandomSeed"; - static boolean expectRandom = false; - - public static void main(String[] args) { - if (args.length > 0 && args[0].equals("true")) { - expectRandom = true; - } - String hashSeedProp = System.getProperty(PROP_NAME); - boolean propSet = (null != hashSeedProp) - ? Boolean.parseBoolean(hashSeedProp) : false; - if (expectRandom != propSet) { - throw new Error("Error in test setup: " + (expectRandom ? "" : "not " ) + "expecting random hashSeed, but " + PROP_NAME + " is " + (propSet ? "" : "not ") + "enabled"); - } - - testMap(new WeakHashMap()); - testMap(new Hashtable()); - } - - private static void testMap(Map map) { - int hashSeed = getHashSeed(map); - boolean hashSeedIsZero = (hashSeed == 0); - - if (expectRandom != hashSeedIsZero) { - System.out.println("Test passed for " + map.getClass().getSimpleName() + " - expectRandom: " + expectRandom + ", hashSeed: " + hashSeed); - } else { - throw new Error ("Test FAILED for " + map.getClass().getSimpleName() + " - expectRandom: " + expectRandom + ", hashSeed: " + hashSeed); - } - } - - private static int getHashSeed(Map map) { - try { - if (map instanceof HashMap || map instanceof LinkedHashMap) { - map.put("Key", "Value"); - Field hashSeedField = HashMap.class.getDeclaredField("hashSeed"); - hashSeedField.setAccessible(true); - int hashSeed = hashSeedField.getInt(map); - return hashSeed; - } else { - map.put("Key", "Value"); - Field hashSeedField = map.getClass().getDeclaredField("hashSeed"); - hashSeedField.setAccessible(true); - int hashSeed = hashSeedField.getInt(map); - return hashSeed; - } - } catch(Exception e) { - e.printStackTrace(); - throw new Error(e); - } - } -} diff --git a/jdk/test/java/util/Map/Collisions.java b/jdk/test/java/util/Map/Collisions.java index b7170791777..05e9e1f95e0 100644 --- a/jdk/test/java/util/Map/Collisions.java +++ b/jdk/test/java/util/Map/Collisions.java @@ -25,8 +25,6 @@ * @test * @bug 7126277 * @run main Collisions -shortrun - * @run main/othervm -Djdk.map.althashing.threshold=0 Collisions -shortrun - * @run main/othervm -Djdk.map.useRandomSeed=true Collisions -shortrun * @summary Ensure Maps behave well with lots of hashCode() collisions. * @author Mike Duigou */ From 767ab8c9ae5c20f2be376b3b49768d000d37d8ae Mon Sep 17 00:00:00 2001 From: Mark Sheppard Date: Fri, 13 Sep 2013 12:20:53 +0100 Subject: [PATCH 218/218] 8024675: java/net/NetworkInterface/UniqueMacAddressesTest.java fails on Windows Amended test to add active, i.e. isUp(), NetworkInterfaces to test list Reviewed-by: alanb, chegar --- .../NetworkInterface/UniqueMacAddressesTest.java | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/jdk/test/java/net/NetworkInterface/UniqueMacAddressesTest.java b/jdk/test/java/net/NetworkInterface/UniqueMacAddressesTest.java index c2f5c495c73..4017c0702ed 100644 --- a/jdk/test/java/net/NetworkInterface/UniqueMacAddressesTest.java +++ b/jdk/test/java/net/NetworkInterface/UniqueMacAddressesTest.java @@ -118,11 +118,14 @@ public class UniqueMacAddressesTest { NetworkInterface netIf = null; while (nis.hasMoreElements()) { netIf = (NetworkInterface) nis.nextElement(); - macAddr = netIf.getHardwareAddress(); - if (macAddr != null) { - System.out - .println("Adding NetworkInterface " + netIf.getName()); - networkInterfaceList.add(netIf); + if (netIf.isUp()) { + macAddr = netIf.getHardwareAddress(); + if (macAddr != null) { + System.out.println("Adding NetworkInterface " + + netIf.getName() + " with mac address " + + createMacAddressString(netIf)); + networkInterfaceList.add(netIf); + } } } }