Merge
diff --git a/.hgtags b/.hgtags
index 0204d6b..fc07f2d 100644
--- a/.hgtags
+++ b/.hgtags
@@ -375,3 +375,6 @@
e3b11296395b39bfeb3364f26c2ef77fa652e300 jdk-9+139
785843878cf78d50cc2959ea2c5a4202bbe885b4 jdk-9+140
a46b7d3867957a868a6cc8ee66c05079b883733a jdk-9+141
+d3f5d7311a1aec3152b17d75046d5d298245a0b4 jdk-9+142
+b4e57ead3fae4939b70dd345d1f6744a1dedfa21 jdk-9+143
+a7f21ee6ed30695a6de14e74035d2857a754f62b jdk-9+144
diff --git a/samples/dynalink/ArrayStreamLinkerExporter.java b/samples/dynalink/ArrayStreamLinkerExporter.java
index 309f1e6..348ef3f 100644
--- a/samples/dynalink/ArrayStreamLinkerExporter.java
+++ b/samples/dynalink/ArrayStreamLinkerExporter.java
@@ -38,9 +38,10 @@
import java.util.stream.LongStream;
import java.util.stream.Stream;
import jdk.dynalink.CallSiteDescriptor;
-import jdk.dynalink.CompositeOperation;
import jdk.dynalink.NamedOperation;
+import jdk.dynalink.NamespaceOperation;
import jdk.dynalink.Operation;
+import jdk.dynalink.StandardNamespace;
import jdk.dynalink.StandardOperation;
import jdk.dynalink.linker.GuardedInvocation;
import jdk.dynalink.linker.GuardingDynamicLinker;
@@ -104,9 +105,9 @@
final CallSiteDescriptor desc = request.getCallSiteDescriptor();
final Operation op = desc.getOperation();
final Object name = NamedOperation.getName(op);
- final boolean getProp = CompositeOperation.contains(
+ final boolean getProp = NamespaceOperation.contains(
NamedOperation.getBaseOperation(op),
- StandardOperation.GET_PROPERTY);
+ StandardOperation.GET, StandardNamespace.PROPERTY);
if (getProp && "stream".equals(name)) {
return new GuardedInvocation(ARRAY_TO_STREAM,
Guards.isOfClass(self.getClass(), GUARD_TYPE));
diff --git a/samples/dynalink/BufferIndexingLinkerExporter.java b/samples/dynalink/BufferIndexingLinkerExporter.java
index 9f49a0c..8fb99c1 100644
--- a/samples/dynalink/BufferIndexingLinkerExporter.java
+++ b/samples/dynalink/BufferIndexingLinkerExporter.java
@@ -29,6 +29,11 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+import static jdk.dynalink.StandardNamespace.ELEMENT;
+import static jdk.dynalink.StandardNamespace.PROPERTY;
+import static jdk.dynalink.StandardOperation.GET;
+import static jdk.dynalink.StandardOperation.SET;
+
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodType;
import java.nio.Buffer;
@@ -42,10 +47,10 @@
import java.util.ArrayList;
import java.util.List;
import jdk.dynalink.CallSiteDescriptor;
-import jdk.dynalink.CompositeOperation;
import jdk.dynalink.NamedOperation;
+import jdk.dynalink.NamespaceOperation;
import jdk.dynalink.Operation;
-import jdk.dynalink.StandardOperation;
+import jdk.dynalink.StandardNamespace;
import jdk.dynalink.linker.GuardedInvocation;
import jdk.dynalink.linker.GuardingDynamicLinker;
import jdk.dynalink.linker.GuardingDynamicLinkerExporter;
@@ -135,23 +140,6 @@
IS_DOUBLEBUFFER = Guards.isInstance(DoubleBuffer.class, GUARD_TYPE);
}
- // locate the first standard operation from the call descriptor
- private static StandardOperation getFirstStandardOperation(final CallSiteDescriptor desc) {
- final Operation base = NamedOperation.getBaseOperation(desc.getOperation());
- if (base instanceof StandardOperation) {
- return (StandardOperation)base;
- } else if (base instanceof CompositeOperation) {
- final CompositeOperation cop = (CompositeOperation)base;
- for(int i = 0; i < cop.getOperationCount(); ++i) {
- final Operation op = cop.getOperation(i);
- if (op instanceof StandardOperation) {
- return (StandardOperation)op;
- }
- }
- }
- return null;
- }
-
@Override
public List<GuardingDynamicLinker> get() {
final ArrayList<GuardingDynamicLinker> linkers = new ArrayList<>();
@@ -170,22 +158,25 @@
}
final CallSiteDescriptor desc = request.getCallSiteDescriptor();
- final StandardOperation op = getFirstStandardOperation(desc);
- if (op == null) {
+ final Operation namedOp = desc.getOperation();
+ final Operation namespaceOp = NamedOperation.getBaseOperation(namedOp);
+ final Operation op = NamespaceOperation.getBaseOperation(namespaceOp);
+ final StandardNamespace ns = StandardNamespace.findFirst(namespaceOp);
+ if (ns == null) {
return null;
}
- switch (op) {
- case GET_ELEMENT:
+ if (op == GET) {
+ if (ns == ELEMENT) {
return linkGetElement(self);
- case SET_ELEMENT:
- return linkSetElement(self);
- case GET_PROPERTY: {
+ } else if (ns == PROPERTY) {
final Object name = NamedOperation.getName(desc.getOperation());
if ("length".equals(name)) {
return linkLength();
}
}
+ } else if (op == SET && ns == ELEMENT) {
+ return linkSetElement(self);
}
return null;
diff --git a/samples/dynalink/DOMLinkerExporter.java b/samples/dynalink/DOMLinkerExporter.java
index 7724fd5..c544c9b 100644
--- a/samples/dynalink/DOMLinkerExporter.java
+++ b/samples/dynalink/DOMLinkerExporter.java
@@ -35,9 +35,10 @@
import java.util.ArrayList;
import java.util.List;
import jdk.dynalink.CallSiteDescriptor;
-import jdk.dynalink.CompositeOperation;
import jdk.dynalink.NamedOperation;
+import jdk.dynalink.NamespaceOperation;
import jdk.dynalink.Operation;
+import jdk.dynalink.StandardNamespace;
import jdk.dynalink.StandardOperation;
import jdk.dynalink.linker.GuardedInvocation;
import jdk.dynalink.linker.GuardingDynamicLinker;
@@ -132,9 +133,9 @@
final CallSiteDescriptor desc = request.getCallSiteDescriptor();
final Operation op = desc.getOperation();
final Object name = NamedOperation.getName(op);
- final boolean getProp = CompositeOperation.contains(
+ final boolean getProp = NamespaceOperation.contains(
NamedOperation.getBaseOperation(op),
- StandardOperation.GET_PROPERTY);
+ StandardOperation.GET, StandardNamespace.PROPERTY);
if (getProp && name instanceof String) {
final String nameStr = (String)name;
diff --git a/samples/dynalink/MissingMethodLinkerExporter.java b/samples/dynalink/MissingMethodLinkerExporter.java
index e68b8d7..2ebb78b 100644
--- a/samples/dynalink/MissingMethodLinkerExporter.java
+++ b/samples/dynalink/MissingMethodLinkerExporter.java
@@ -35,9 +35,10 @@
import java.util.ArrayList;
import java.util.List;
import jdk.dynalink.CallSiteDescriptor;
-import jdk.dynalink.CompositeOperation;
import jdk.dynalink.NamedOperation;
+import jdk.dynalink.NamespaceOperation;
import jdk.dynalink.Operation;
+import jdk.dynalink.StandardNamespace;
import jdk.dynalink.StandardOperation;
import jdk.dynalink.beans.BeansLinker;
import jdk.dynalink.linker.GuardedInvocation;
@@ -99,23 +100,6 @@
"getName", MethodType.methodType(String.class));
}
- // locate the first standard operation from the call descriptor
- private static StandardOperation getFirstStandardOperation(final CallSiteDescriptor desc) {
- final Operation base = NamedOperation.getBaseOperation(desc.getOperation());
- if (base instanceof StandardOperation) {
- return (StandardOperation)base;
- } else if (base instanceof CompositeOperation) {
- final CompositeOperation cop = (CompositeOperation)base;
- for(int i = 0; i < cop.getOperationCount(); ++i) {
- final Operation op = cop.getOperation(i);
- if (op instanceof StandardOperation) {
- return (StandardOperation)op;
- }
- }
- }
- return null;
- }
-
@Override
public List<GuardingDynamicLinker> get() {
final ArrayList<GuardingDynamicLinker> linkers = new ArrayList<>();
@@ -140,8 +124,12 @@
// we return that method object. If not, we return a MissingMethod object.
if (self instanceof MissingMethodHandler) {
// Check if this is a named GET_METHOD first.
- final boolean isGetMethod = getFirstStandardOperation(desc) == StandardOperation.GET_METHOD;
- final Object name = NamedOperation.getName(desc.getOperation());
+ final Operation namedOp = desc.getOperation();
+ final Operation namespaceOp = NamedOperation.getBaseOperation(namedOp);
+ final Operation op = NamespaceOperation.getBaseOperation(namespaceOp);
+
+ final boolean isGetMethod = op == StandardOperation.GET && StandardNamespace.findFirst(namespaceOp) == StandardNamespace.METHOD;
+ final Object name = NamedOperation.getName(namedOp);
if (isGetMethod && name instanceof String) {
final GuardingDynamicLinker javaLinker = beansLinker.getLinkerForClass(self.getClass());
GuardedInvocation inv;
@@ -166,7 +154,7 @@
} else if (self instanceof MissingMethod) {
// This is step (2). We call MissingMethodHandler.doesNotUnderstand here
// Check if this is this a CALL first.
- final boolean isCall = getFirstStandardOperation(desc) == StandardOperation.CALL;
+ final boolean isCall = NamedOperation.getBaseOperation(desc.getOperation()) == StandardOperation.CALL;
if (isCall) {
MethodHandle mh = DOES_NOT_UNDERSTAND;
diff --git a/samples/dynalink/UnderscoreNameLinkerExporter.java b/samples/dynalink/UnderscoreNameLinkerExporter.java
index 6025183..fe60aae 100644
--- a/samples/dynalink/UnderscoreNameLinkerExporter.java
+++ b/samples/dynalink/UnderscoreNameLinkerExporter.java
@@ -34,9 +34,10 @@
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import jdk.dynalink.CallSiteDescriptor;
-import jdk.dynalink.CompositeOperation;
import jdk.dynalink.NamedOperation;
+import jdk.dynalink.NamespaceOperation;
import jdk.dynalink.Operation;
+import jdk.dynalink.StandardNamespace;
import jdk.dynalink.StandardOperation;
import jdk.dynalink.linker.GuardedInvocation;
import jdk.dynalink.linker.GuardingDynamicLinker;
@@ -68,23 +69,6 @@
return buf.toString();
}
- // locate the first standard operation from the call descriptor
- private static StandardOperation getFirstStandardOperation(final CallSiteDescriptor desc) {
- final Operation base = NamedOperation.getBaseOperation(desc.getOperation());
- if (base instanceof StandardOperation) {
- return (StandardOperation)base;
- } else if (base instanceof CompositeOperation) {
- final CompositeOperation cop = (CompositeOperation)base;
- for(int i = 0; i < cop.getOperationCount(); ++i) {
- final Operation op = cop.getOperation(i);
- if (op instanceof StandardOperation) {
- return (StandardOperation)op;
- }
- }
- }
- return null;
- }
-
@Override
public List<GuardingDynamicLinker> get() {
final ArrayList<GuardingDynamicLinker> linkers = new ArrayList<>();
@@ -92,12 +76,14 @@
@Override
public GuardedInvocation getGuardedInvocation(final LinkRequest request,
final LinkerServices linkerServices) throws Exception {
- final Object self = request.getReceiver();
final CallSiteDescriptor desc = request.getCallSiteDescriptor();
final Operation op = desc.getOperation();
final Object name = NamedOperation.getName(op);
+ final Operation namespaceOp = NamedOperation.getBaseOperation(op);
// is this a named GET_METHOD?
- final boolean isGetMethod = getFirstStandardOperation(desc) == StandardOperation.GET_METHOD;
+ final boolean isGetMethod =
+ NamespaceOperation.getBaseOperation(namespaceOp) == StandardOperation.GET
+ && StandardNamespace.findFirst(namespaceOp) == StandardNamespace.METHOD;
if (isGetMethod && name instanceof String) {
final String str = (String)name;
if (str.indexOf('_') == -1) {
@@ -106,13 +92,9 @@
final String nameStr = translateToCamelCase(str);
// create a new call descriptor to use translated name
- final CallSiteDescriptor newDesc = new CallSiteDescriptor(
- desc.getLookup(),
- new NamedOperation(NamedOperation.getBaseOperation(op), nameStr),
- desc.getMethodType());
+ final CallSiteDescriptor newDesc = desc.changeOperation(((NamedOperation)op).changeName(nameStr));
// create a new Link request to link the call site with translated name
- final LinkRequest newRequest = new SimpleLinkRequest(newDesc,
- request.isCallSiteUnstable(), request.getArguments());
+ final LinkRequest newRequest = request.replaceArguments(newDesc, request.getArguments());
// return guarded invocation linking the translated request
return linkerServices.getGuardedInvocation(newRequest);
}
diff --git a/samples/dynalink/underscore_linker.js b/samples/dynalink/underscore_linker.js
index 98acd9e..82ad554 100644
--- a/samples/dynalink/underscore_linker.js
+++ b/samples/dynalink/underscore_linker.js
@@ -46,5 +46,6 @@
// but make sure classpath points to the pluggable linker jar!
`jjs -cp underscore_linker.jar underscore.js`
+print($ERR)
print($OUT)
diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/CallSiteDescriptor.java b/src/jdk.dynalink/share/classes/jdk/dynalink/CallSiteDescriptor.java
index 96a8269..e5ada58 100644
--- a/src/jdk.dynalink/share/classes/jdk/dynalink/CallSiteDescriptor.java
+++ b/src/jdk.dynalink/share/classes/jdk/dynalink/CallSiteDescriptor.java
@@ -83,9 +83,11 @@
package jdk.dynalink;
+import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodHandles.Lookup;
import java.lang.invoke.MethodType;
import java.util.Objects;
+import java.util.function.Supplier;
/**
* Call site descriptors contain all the information necessary for linking a
@@ -148,44 +150,82 @@
}
/**
- * Creates a new call site descriptor from this descriptor, which is
- * identical to this, except it changes the method type. Invokes
- * {@link #changeMethodTypeInternal(MethodType)} and checks that it returns
- * a descriptor of the same class as this descriptor.
+ * Finds or creates a call site descriptor that only differs in its
+ * method type from this descriptor.
+ * Invokes {@link #changeMethodTypeInternal(MethodType)}.
*
* @param newMethodType the new method type
- * @return a new call site descriptor, with the method type changed.
- * @throws RuntimeException if {@link #changeMethodTypeInternal(MethodType)}
- * returned a descriptor of different class than this object.
- * @throws NullPointerException if {@link #changeMethodTypeInternal(MethodType)}
- * returned null.
+ * @return a call site descriptor with changed method type.
+ * @throws NullPointerException if {@code newMethodType} is null.
*/
public final CallSiteDescriptor changeMethodType(final MethodType newMethodType) {
- final CallSiteDescriptor changed = Objects.requireNonNull(
- changeMethodTypeInternal(newMethodType),
- "changeMethodTypeInternal() must not return null.");
+ final CallSiteDescriptor changed = changeMethodTypeInternal(newMethodType);
- if (getClass() != changed.getClass()) {
- throw new RuntimeException(
- "changeMethodTypeInternal() must return an object of the same class it is invoked on.");
+ if (getClass() != CallSiteDescriptor.class) {
+ assertChangeInvariants(changed, "changeMethodTypeInternal");
+ alwaysAssert(operation == changed.operation, () -> "changeMethodTypeInternal must not change the descriptor's operation");
+ alwaysAssert(newMethodType == changed.methodType, () -> "changeMethodTypeInternal didn't set the correct new method type");
}
-
return changed;
}
/**
- * Creates a new call site descriptor from this descriptor, which is
- * identical to this, except it changes the method type. Subclasses must
- * override this method to return an object of their exact class.
+ * Finds or creates a call site descriptor that only differs in its
+ * method type from this descriptor. Subclasses must override this method
+ * to return an object of their exact class. If an overridden method changes
+ * something other than the method type in the descriptor (its class, lookup,
+ * or operation), or returns null, an {@code AssertionError} will be thrown
+ * from {@link #changeMethodType(MethodType)}.
*
* @param newMethodType the new method type
- * @return a new call site descriptor, with the method type changed.
+ * @return a call site descriptor with the changed method type.
*/
protected CallSiteDescriptor changeMethodTypeInternal(final MethodType newMethodType) {
return new CallSiteDescriptor(getLookupPrivileged(), operation, newMethodType);
}
/**
+ * Finds or creates a call site descriptor that only differs in its
+ * operation from this descriptor.
+ * Invokes {@link #changeOperationInternal(Operation)}.
+ *
+ * @param newOperation the new operation
+ * @return a call site descriptor with the changed operation.
+ * @throws NullPointerException if {@code newOperation} is null.
+ * @throws SecurityException if the descriptor's lookup isn't the
+ * {@link MethodHandles#publicLookup()}, and a security manager is present,
+ * and a check for {@code RuntimePermission("dynalink.getLookup")} fails.
+ * This is necessary as changing the operation in the call site descriptor
+ * allows fabrication of descriptors for arbitrary operations with the lookup.
+ */
+ public final CallSiteDescriptor changeOperation(final Operation newOperation) {
+ getLookup(); // force security check
+ final CallSiteDescriptor changed = changeOperationInternal(newOperation);
+
+ if (getClass() != CallSiteDescriptor.class) {
+ assertChangeInvariants(changed, "changeOperationInternal");
+ alwaysAssert(methodType == changed.methodType, () -> "changeOperationInternal must not change the descriptor's method type");
+ alwaysAssert(newOperation == changed.operation, () -> "changeOperationInternal didn't set the correct new operation");
+ }
+ return changed;
+ }
+
+ /**
+ * Finds or creates a call site descriptor that only differs in its
+ * operation from this descriptor. Subclasses must override this method
+ * to return an object of their exact class. If an overridden method changes
+ * something other than the operation in the descriptor (its class, lookup,
+ * or method type), or returns null, an {@code AssertionError} will be thrown
+ * from {@link #changeOperation(Operation)}.
+ *
+ * @param newOperation the new operation
+ * @return a call site descriptor with the changed operation.
+ */
+ protected CallSiteDescriptor changeOperationInternal(final Operation newOperation) {
+ return new CallSiteDescriptor(getLookupPrivileged(), newOperation, methodType);
+ }
+
+ /**
* Returns true if this call site descriptor is equal to the passed object.
* It is considered equal if the other object is of the exact same class,
* their operations and method types are equal, and their lookups have the
@@ -255,4 +295,16 @@
final StringBuilder b = new StringBuilder(o.length() + mt.length() + 1 + l.length());
return b.append(o).append(mt).append('@').append(l).toString();
}
+
+ private void assertChangeInvariants(final CallSiteDescriptor changed, final String caller) {
+ alwaysAssert(changed != null, () -> caller + " must not return null.");
+ alwaysAssert(getClass() == changed.getClass(), () -> caller + " must not change the descriptor's class");
+ alwaysAssert(lookupsEqual(getLookupPrivileged(), changed.getLookupPrivileged()), () -> caller + " must not change the descriptor's lookup");
+ }
+
+ private static void alwaysAssert(final boolean cond, final Supplier<String> errorMessage) {
+ if (!cond) {
+ throw new AssertionError(errorMessage.get());
+ }
+ }
}
diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/CompositeOperation.java b/src/jdk.dynalink/share/classes/jdk/dynalink/CompositeOperation.java
deleted file mode 100644
index 94581f4..0000000
--- a/src/jdk.dynalink/share/classes/jdk/dynalink/CompositeOperation.java
+++ /dev/null
@@ -1,297 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * 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 2015 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.dynalink;
-
-import java.util.Arrays;
-import java.util.Objects;
-
-/**
- * Describes an operation that is composed of at least two other operations. The
- * component operations are treated as alternatives to each other in order of
- * preference. The semantics of the composite operation is "first successful".
- * That is, a composite of {@code GET_PROPERTY|GET_ELEMENT:color} should be
- * interpreted as <i>get the property named "color" on the object, but if the
- * property does not exist, then get the collection element named "color"
- * instead</i>.
- * <p>
- * Composite operations are helpful in implementation of languages that
- * don't distinguish between one or more of the property, method, and element
- * namespaces, or when expressing operations against objects that can be
- * considered both ordinary objects and collections, e.g. Java
- * {@link java.util.Map} objects. A composite operation
- * {@code GET_PROPERTY|GET_ELEMENT:empty} against a Java map will always match
- * the {@link java.util.Map#isEmpty()} property, but
- * {@code GET_ELEMENT|GET_PROPERTY:empty} will actually match a map element with
- * key {@code "empty"} if the map contains that key, and only fall back to the
- * {@code isEmpty()} property getter if the map does not contain the key. If
- * the source language mandates this semantics, it can be easily achieved using
- * composite operations.
- * <p>
- * Even if the language itself doesn't distinguish between some of the
- * namespaces, it can be helpful to map different syntaxes to different
- * compositions. E.g. the source expression {@code obj.color} could map to
- * {@code GET_PROPERTY|GET_ELEMENT|GET_METHOD:color}, but a different source
- * expression that looks like collection element access {@code obj[key]} could
- * be expressed instead as {@code GET_ELEMENT|GET_PROPERTY|GET_METHOD}.
- * Finally, if the retrieved value is subsequently called, then it makes sense
- * to bring {@code GET_METHOD} to the front of the list: the getter part of the
- * source expression {@code obj.color()} should be
- * {@code GET_METHOD|GET_PROPERTY|GET_ELEMENT:color} and the one for
- * {@code obj[key]()} should be {@code GET_METHOD|GET_ELEMENT|GET_PROPERTY}.
- * <p>
- * The elements of a composite operation can not be composites or named
- * operations, but rather simple operations such are elements of
- * {@link StandardOperation}. A composite operation itself can serve as the base
- * operation of a named operation, though; a typical way to construct e.g. the
- * {@code GET_ELEMENT|GET_PROPERTY:empty} from above would be:
- * <pre>
- * Operation getElementOrPropertyEmpty = new NamedOperation(
- * new CompositeOperation(
- * StandardOperation.GET_ELEMENT,
- * StandardOperation.GET_PROPERTY),
- * "empty");
- * </pre>
- * <p>
- * Not all compositions make sense. Typically, any combination in any order of
- * standard getter operations {@code GET_PROPERTY}, {@code GET_ELEMENT}, and
- * {@code GET_METHOD} make sense, as do combinations of {@code SET_PROPERTY} and
- * {@code SET_ELEMENT}; other standard operations should not be combined. The
- * constructor will allow any combination of operations, though.
- */
-public final class CompositeOperation implements Operation {
- private final Operation[] operations;
-
- /**
- * Constructs a new composite operation.
- * @param operations the components for this composite operation. The passed
- * array will be cloned.
- * @throws IllegalArgumentException if less than two components are
- * specified, or any component is itself a {@link CompositeOperation} or a
- * {@link NamedOperation}.
- * @throws NullPointerException if either the operations array or any of its
- * elements are {@code null}.
- */
- public CompositeOperation(final Operation... operations) {
- Objects.requireNonNull(operations, "operations array is null");
- if (operations.length < 2) {
- throw new IllegalArgumentException("Must have at least two operations");
- }
- final Operation[] clonedOps = operations.clone();
- for(int i = 0; i < clonedOps.length; ++i) {
- final Operation op = clonedOps[i];
- if (op == null) {
- throw new NullPointerException("operations[" + i + "] is null");
- } else if (op instanceof NamedOperation) {
- throw new IllegalArgumentException("operations[" + i + "] is a NamedOperation");
- } else if (op instanceof CompositeOperation) {
- throw new IllegalArgumentException("operations[" + i + "] is a CompositeOperation");
- }
- }
- this.operations = clonedOps;
- }
-
- /**
- * Returns the component operations in this composite operation. The
- * returned array is a copy and changes to it don't have effect on this
- * object.
- * @return the component operations in this composite operation.
- */
- public Operation[] getOperations() {
- return operations.clone();
- }
-
- /**
- * Returns the number of component operations in this composite operation.
- * @return the number of component operations in this composite operation.
- */
- public int getOperationCount() {
- return operations.length;
- }
-
- /**
- * Returns the i-th component operation in this composite operation.
- * @param i the operation index
- * @return the i-th component operation in this composite operation.
- * @throws IndexOutOfBoundsException if the index is out of range.
- */
- public Operation getOperation(final int i) {
- try {
- return operations[i];
- } catch (final ArrayIndexOutOfBoundsException e) {
- throw new IndexOutOfBoundsException(Integer.toString(i));
- }
- }
-
- /**
- * Returns true if this composite operation contains an operation equal to
- * the specified operation.
- * @param operation the operation being searched for. Must not be null.
- * @return true if the if this composite operation contains an operation
- * equal to the specified operation.
- */
- public boolean contains(final Operation operation) {
- Objects.requireNonNull(operation);
- for(final Operation component: operations) {
- if (component.equals(operation)) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Returns true if the other object is also a composite operation and their
- * component operations are equal.
- * @param obj the object to compare to
- * @return true if this object is equal to the other one, false otherwise.
- */
- @Override
- public boolean equals(final Object obj) {
- if (obj instanceof CompositeOperation) {
- return Arrays.equals(operations, ((CompositeOperation)obj).operations);
- }
- return false;
- }
-
- /**
- * Returns the hash code of this composite operation. Defined to be equal
- * to {@code java.util.Arrays.hashCode(operations)}.
- */
- @Override
- public int hashCode() {
- return Arrays.hashCode(operations);
- };
-
- /**
- * Returns the string representation of this composite operation. Defined to
- * be the {@code toString} of its component operations, each separated by
- * the vertical line character (e.g. {@code "GET_PROPERTY|GET_ELEMENT"}).
- * @return the string representation of this composite operation.
- */
- @Override
- public String toString() {
- final StringBuilder b = new StringBuilder();
- b.append(operations[0]);
- for(int i = 1; i < operations.length; ++i) {
- b.append('|').append(operations[i]);
- }
- return b.toString();
- }
-
- /**
- * Returns the components of the passed operation if it is a composite
- * operation, otherwise returns an array containing the operation itself.
- * This allows for returning an array of component even if it is not known
- * whether the operation is itself a composite (treating a non-composite
- * operation as if it were a single-element composite of itself).
- * @param op the operation whose components are retrieved.
- * @return if the passed operation is a composite operation, returns its
- * {@link #getOperations()}, otherwise returns the operation itself.
- */
- public static Operation[] getOperations(final Operation op) {
- return op instanceof CompositeOperation
- ? ((CompositeOperation)op).operations.clone()
- : new Operation[] { op };
- }
-
- /**
- * Returns true if the specified potentially composite operation is a
- * {@link CompositeOperation} and contains an operation equal to the
- * specified operation. If {@code composite} is not a
- * {@link CompositeOperation}, then the two operations are compared for
- * equality.
- * @param composite the potentially composite operation. Must not be null.
- * @param operation the operation being searched for. Must not be null.
- * @return true if the if the passed operation is a
- * {@link CompositeOperation} and contains a component operation equal to
- * the specified operation, or if it is not a {@link CompositeOperation} and
- * is equal to {@code operation}.
- */
- public static boolean contains(final Operation composite, final Operation operation) {
- if (composite instanceof CompositeOperation) {
- return ((CompositeOperation)composite).contains(operation);
- }
- return composite.equals(Objects.requireNonNull(operation));
- }
-}
diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/NamedOperation.java b/src/jdk.dynalink/share/classes/jdk/dynalink/NamedOperation.java
index 8eaa42f..d2b2336 100644
--- a/src/jdk.dynalink/share/classes/jdk/dynalink/NamedOperation.java
+++ b/src/jdk.dynalink/share/classes/jdk/dynalink/NamedOperation.java
@@ -88,15 +88,47 @@
/**
* Operation that associates a name with another operation. Typically used with
* operations that normally take a name or an index to bind them to a fixed
- * name. E.g. {@code new NamedOperation(StandardOperation.GET_PROPERTY, "color")}
+ * name. E.g.
+ * <pre>
+ * new NamedOperation(
+ * new NamespaceOperation(
+ * StandardOperation.GET,
+ * StandardNamespace.PROPERTY),
+ * "color")
+ * </pre>
* will be a named operation for getting the property named "color" on the
* object it is applied to, and
- * {@code new NamedOperation(StandardOperation.GET_ELEMENT, 3)} will be a named
- * operation for getting the element at index 3 from the collection it is
- * applied to. In these cases, the expected signature of the call site for the
+ * <pre>
+ * new NamedOperation(
+ * new NamespaceOperation(
+ * StandardOperation.GET,
+ * StandardNamespace.ELEMENT),
+ * 3)
+ * </pre>
+ * will be a named operation for getting the element at index 3 from the collection
+ * it is applied to ("name" in this context is akin to "address" and encompasses both
+ * textual names, numeric indices, or any other kinds of addressing that linkers can
+ * understand). In these cases, the expected signature of the call site for the
* operation will change to no longer include the name parameter. Specifically,
* the documentation for all {@link StandardOperation} members describes how
* they are affected by being incorporated into a named operation.
+ * <p>While {@code NamedOperation} can be constructed directly, it is often convenient
+ * to use the {@link Operation#named(Object)} factory method instead, e.g.:
+ * <pre>
+ * StandardOperation.GET
+ * .withNamespace(StandardNamespace.ELEMENT),
+ * .named(3)
+ * )
+ * </pre>
+ * <p>
+ * Even though {@code NamedOperation} is most often used with {@link NamespaceOperation} as
+ * its base, it can have other operations as its base too (except another named operation).
+ * Specifically, {@link StandardOperation#CALL} as well as {@link StandardOperation#NEW} can
+ * both be used with {@code NamedOperation} directly. The contract for these operations is such
+ * that when they are used as named operations, their name is only used for diagnostic messages,
+ * usually containing the textual representation of the source expression that retrieved the
+ * callee, e.g. {@code StandardOperation.CALL.named("window.open")}.
+ * </p>
*/
public final class NamedOperation implements Operation {
private final Operation baseOperation;
@@ -116,7 +148,7 @@
*/
public NamedOperation(final Operation baseOperation, final Object name) {
if (baseOperation instanceof NamedOperation) {
- throw new IllegalArgumentException("baseOperation is a named operation");
+ throw new IllegalArgumentException("baseOperation is a NamedOperation");
}
this.baseOperation = Objects.requireNonNull(baseOperation, "baseOperation is null");
this.name = Objects.requireNonNull(name, "name is null");
@@ -139,6 +171,16 @@
}
/**
+ * Finds or creates a named operation that differs from this one only in the name.
+ * @param newName the new name to replace the old name with.
+ * @return a named operation with the changed name.
+ * @throws NullPointerException if the name is null.
+ */
+ public final NamedOperation changeName(final String newName) {
+ return new NamedOperation(baseOperation, newName);
+ }
+
+ /**
* Compares this named operation to another object. Returns true if the
* other object is also a named operation, and both their base operations
* and name are equal.
diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/Namespace.java b/src/jdk.dynalink/share/classes/jdk/dynalink/Namespace.java
new file mode 100644
index 0000000..0785f64
--- /dev/null
+++ b/src/jdk.dynalink/share/classes/jdk/dynalink/Namespace.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * 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 2016 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.dynalink;
+
+/**
+ * An object that describes a namespace that is the target of a dynamic operation
+ * on an object. Every object can have one or more namespaces. Dynalink defines a
+ * set of standard namespaces with the {@link StandardNamespace} enum. Operations
+ * that need to specify a namespace they operate on can be expressed using
+ * {@link NamespaceOperation}.
+ */
+public interface Namespace {
+}
diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/NamespaceOperation.java b/src/jdk.dynalink/share/classes/jdk/dynalink/NamespaceOperation.java
new file mode 100644
index 0000000..26173c8
--- /dev/null
+++ b/src/jdk.dynalink/share/classes/jdk/dynalink/NamespaceOperation.java
@@ -0,0 +1,331 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * 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 2016 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.dynalink;
+
+import java.util.Arrays;
+import java.util.Objects;
+
+/**
+ * Describes an operation that operates on at least one {@link Namespace} of
+ * an object. E.g. a property getter would be described as
+ * <pre>
+ * Operation propertyGetter = new NamespaceOperation(
+ * StandardOperation.GET,
+ * StandardNamespace.PROPERTY);
+ * </pre>
+ * They are often combined with {@link NamedOperation}, e.g. to express a
+ * property getter for a property named "color", you would construct:
+ * <pre>
+ * Operation colorPropertyGetter = new NamedOperation(
+ * new NamespaceOperation(
+ * StandardOperation.GET,
+ * StandardNamespace.PROPERTY),
+ * "color");
+ * </pre>
+ * <p>While {@code NamespaceOperation} can be constructed directly, it is often convenient
+ * to use the {@link Operation#withNamespace(Namespace)} and {@link Operation#withNamespaces(Namespace...)} factory
+ * methods instead, e.g.:
+ * <pre>
+ * Operation getElementOrPropertyEmpty =
+ * StandardOperation.GET
+ * .withNamespace(StandardNamespace.PROPERTY)
+ * .named("color");
+ * </pre>
+ * <h3>Operations on multiple namespaces</h3>
+ * If multiple namespaces are specified, the namespaces are treated as
+ * alternatives to each other in order of preference. The semantics of
+ * such operation is "first applicable".
+ * That is, a composite of {@code GET:PROPERTY|ELEMENT:color} should be
+ * interpreted as <i>get the property named "color" on the object, but if the
+ * property does not exist, then get the collection element named "color"
+ * instead</i>.
+ * <p>
+ * Operations with multiple namespaces are helpful in implementation of languages that
+ * don't distinguish between one or more of the namespaces, or when expressing operations
+ * against objects that can be considered both ordinary objects and collections, e.g. Java
+ * {@link java.util.Map} objects. A {@code GET:PROPERTY|ELEMENT:empty} operation
+ * against a Java map will always match
+ * the {@link java.util.Map#isEmpty()} property, but
+ * {@code GET:ELEMENT|PROPERTY:empty} will actually match a map element with
+ * key {@code "empty"} if the map contains that key, and only fall back to the
+ * {@code isEmpty()} property getter if the map does not contain the key. If
+ * the source language mandates this semantics, it can be easily achieved using
+ * operations on multiple namespaces.
+ * <p>
+ * Even if the language itself doesn't distinguish between some of the
+ * namespaces, it can be helpful to map different syntaxes to different namespace orderings.
+ * E.g. the source expression {@code obj.color} could map to
+ * {@code GET:PROPERTY|ELEMENT|METHOD:color}, but a different source
+ * expression that looks like collection element access {@code obj[key]} could
+ * be expressed instead as {@code GET:ELEMENT|PROPERTY|METHOD} in order to favor the
+ * element semantics. Finally, if the retrieved value is subsequently called, then it makes sense
+ * to bring {@code METHOD} to the front of the namespace list: the getter part of the
+ * source expression {@code obj.color()} could be
+ * {@code GET:METHOD|PROPERTY|ELEMENT:color} and the one for
+ * {@code obj[key]()} could be {@code GET:METHOD|ELEMENT|PROPERTY}.
+ * <p>
+ * The base operation of a namespace operation can not itself be a namespace or named
+ * operation, but rather one of simple operations such are elements of
+ * {@link StandardOperation}. A namespace operation itself can serve as the base
+ * operation of a named operation, though; a typical way to construct e.g. the
+ * {@code GET:ELEMENT|PROPERTY:empty} from above would be:
+ * <pre>
+ * Operation getElementOrPropertyEmpty = StandardOperation.GET
+ * .withNamespaces(
+ * StandardNamespace.ELEMENT,
+ * StandardNamespace.PROPERTY)
+ * .named("empty");
+ * </pre>
+ */
+public final class NamespaceOperation implements Operation {
+ private final Operation baseOperation;
+ private final Namespace[] namespaces;
+
+ /**
+ * Constructs a new namespace operation.
+ * @param baseOperation the base operation that operates on one or more namespaces.
+ * @param namespaces one or more namespaces this operation operates on.
+ * @throws IllegalArgumentException if less than one namespace is
+ * specified, or the base operation is itself a {@link NamespaceOperation} or a
+ * {@link NamedOperation}.
+ * @throws NullPointerException if either the {@code namespaces} array or any of its
+ * elements are {@code null}, or if {@code baseOperation} is {@code null}.
+ */
+ public NamespaceOperation(final Operation baseOperation, final Namespace... namespaces) {
+ this.baseOperation = Objects.requireNonNull(baseOperation, "baseOperation is null");
+ if (baseOperation instanceof NamedOperation) {
+ throw new IllegalArgumentException("baseOperation is a NamedOperation");
+ } else if (baseOperation instanceof NamespaceOperation) {
+ throw new IllegalArgumentException("baseOperation is a NamespaceOperation");
+ }
+
+ this.namespaces = Objects.requireNonNull(namespaces, "namespaces array is null").clone();
+ if (namespaces.length < 1) {
+ throw new IllegalArgumentException("Must specify at least one namespace");
+ }
+ for(int i = 0; i < namespaces.length; ++i) {
+ final int fi = i;
+ Objects.requireNonNull(namespaces[i], () -> "operations[" + fi + "] is null");
+ }
+ }
+
+ /**
+ * Returns the base operation of this named operation.
+ * @return the base operation of this named operation.
+ */
+ public Operation getBaseOperation() {
+ return baseOperation;
+ }
+
+ /**
+ * Returns the namespaces in this namespace operation. The returned
+ * array is a copy and changes to it don't have effect on this
+ * object.
+ * @return the namespaces in this namespace operation.
+ */
+ public Namespace[] getNamespaces() {
+ return namespaces.clone();
+ }
+
+ /**
+ * Returns the number of namespaces in this namespace operation.
+ * @return the number of namespaces in this namespace operation.
+ */
+ public int getNamespaceCount() {
+ return namespaces.length;
+ }
+
+ /**
+ * Returns the i-th namespace in this namespace operation.
+ * @param i the namespace index
+ * @return the i-th namespace in this namespace operation.
+ * @throws IndexOutOfBoundsException if the index is out of range.
+ */
+ public Namespace getNamespace(final int i) {
+ try {
+ return namespaces[i];
+ } catch (final ArrayIndexOutOfBoundsException e) {
+ throw new IndexOutOfBoundsException(Integer.toString(i));
+ }
+ }
+
+ /**
+ * Returns true if this namespace operation contains a namespace equal to
+ * the specified namespace.
+ * @param namespace the namespace being searched for. Must not be null.
+ * @return true if the if this namespace operation contains a namespace
+ * equal to the specified namespace.
+ */
+ public boolean contains(final Namespace namespace) {
+ Objects.requireNonNull(namespace);
+ for(final Namespace component: namespaces) {
+ if (component.equals(namespace)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns true if the other object is also a namespace operation and their
+ * base operation and namespaces are equal.
+ * @param obj the object to compare to
+ * @return true if this object is equal to the other one, false otherwise.
+ */
+ @Override
+ public boolean equals(final Object obj) {
+ if (obj instanceof NamespaceOperation) {
+ final NamespaceOperation other = (NamespaceOperation)obj;
+ return baseOperation.equals(other.baseOperation) && Arrays.equals(namespaces, other.namespaces);
+ }
+ return false;
+ }
+
+ /**
+ * Returns the hash code of this namespace operation. Defined to be equal
+ * to {@code baseOperation.hashCode() + 31 * Arrays.hashCode(namespaces)}.
+ */
+ @Override
+ public int hashCode() {
+ return baseOperation.hashCode() + 31 * Arrays.hashCode(namespaces);
+ };
+
+ /**
+ * Returns the string representation of this namespace operation. Defined to
+ * be the {@code toString} of its base operation, followed by a colon character,
+ * followed with the list of its namespaces separated with the vertical line
+ * character (e.g. {@code "GET:PROPERTY|ELEMENT"}).
+ * @return the string representation of this namespace operation.
+ */
+ @Override
+ public String toString() {
+ final StringBuilder b = new StringBuilder();
+ b.append(baseOperation).append(':');
+ b.append(namespaces[0]);
+ for(int i = 1; i < namespaces.length; ++i) {
+ b.append('|').append(namespaces[i]);
+ }
+ return b.toString();
+ }
+
+ /**
+ * If the passed operation is a namespace operation, returns its
+ * {@link #getBaseOperation()}, otherwise returns the operation as is.
+ * @param op the operation
+ * @return the base operation of the passed operation.
+ */
+ public static Operation getBaseOperation(final Operation op) {
+ return op instanceof NamespaceOperation ? ((NamespaceOperation )op).getBaseOperation() : op;
+ }
+
+ /**
+ * If the passed operation is a namespace operation, returns its
+ * {@link #getNamespaces()}, otherwise returns an empty array.
+ * @param op the operation
+ * @return the namespaces of the passed operation.
+ */
+ public static Namespace[] getNamespaces(final Operation op) {
+ return op instanceof NamespaceOperation ? ((NamespaceOperation)op).getNamespaces() : new Namespace[0];
+ }
+
+ /**
+ * Returns true if the specified operation is a {@link NamespaceOperation}
+ * and its base operation is equal to the specified operation, and it
+ * contains the specified namespace. If it is not a {@link NamespaceOperation},
+ * then it returns false.
+ * @param op the operation. Must not be null.
+ * @param baseOperation the base operation being searched for. Must not be null.
+ * @param namespace the namespace being searched for. Must not be null.
+ * @return true if the if the passed operation is a {@link NamespaceOperation},
+ * its base operation equals the searched base operation, and contains a namespace
+ * equal to the searched namespace.
+ */
+ public static boolean contains(final Operation op, final Operation baseOperation, final Namespace namespace) {
+ if (op instanceof NamespaceOperation) {
+ final NamespaceOperation no = (NamespaceOperation)op;
+ return no.baseOperation.equals(baseOperation) && no.contains(namespace);
+ }
+ return false;
+ }
+}
diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/Operation.java b/src/jdk.dynalink/share/classes/jdk/dynalink/Operation.java
index 1afdd6e..e73e88f 100644
--- a/src/jdk.dynalink/share/classes/jdk/dynalink/Operation.java
+++ b/src/jdk.dynalink/share/classes/jdk/dynalink/Operation.java
@@ -86,14 +86,51 @@
/**
* An object that describes a dynamic operation. Dynalink defines a set of
* standard operations with the {@link StandardOperation} class, as well as a
- * way to attach a fixed name to an operation using {@link NamedOperation} and
- * to express a set of alternative operations using {@link CompositeOperation}.
+ * way to express the target {@link Namespace namespace(s)} of an operation
+ * on an object using {@link NamespaceOperation} and finally a way to attach
+ * a fixed target name to an operation using {@link NamedOperation}.
* When presenting examples in this documentation, we will refer to standard
- * operations using their name (e.g. {@code GET_PROPERTY}), to composite
- * operations by separating their components with the vertical line character
- * (e.g. {@code GET_PROPERTY|GET_ELEMENT}), and finally to named operations by
- * separating the base operation and the name with the colon character (e.g.
- * {@code GET_PROPERTY|GET_ELEMENT:color}).
+ * operations using their name (e.g. {@code GET}), to namespace operations
+ * by separating their base operation with a colon from their namespace
+ * (e.g. {@code GET:PROPERTY}), or in case of multiple namespaces we will
+ * further separate those with the vertical line character (e.g.
+ * {@code GET:PROPERTY|ELEMENT}), and finally we will refer to named operations
+ * by separating the base operation and the name with the colon character (e.g.
+ * {@code GET:PROPERTY|ELEMENT:color}).
*/
public interface Operation {
+ /**
+ * Returns a {@link NamespaceOperation} using this operation as its base.
+ * @param namespace the namespace that is the target of the namespace operation.
+ * @return a {@link NamespaceOperation} with this operation as its base and the specified
+ * namespace as its target.
+ * @throws IllegalArgumentException if this operation is already a namespace operation or a named operation.
+ * @throws NullPointerException if {@code namespace} is null.
+ */
+ default NamespaceOperation withNamespace(final Namespace namespace) {
+ return withNamespaces(namespace);
+ }
+
+ /**
+ * Returns a {@link NamespaceOperation} using this operation as its base.
+ * @param namespaces the namespaces that are the target of the namespace operation.
+ * @return a {@link NamespaceOperation} with this operation as its base and the specified
+ * namespaces as its targets.
+ * @throws IllegalArgumentException if this operation is already a namespace operation or a named operation.
+ * @throws NullPointerException if {@code namespace} or any of its elements is null.
+ */
+ default NamespaceOperation withNamespaces(final Namespace... namespaces) {
+ return new NamespaceOperation(this, namespaces);
+ }
+
+ /**
+ * Returns a {@link NamedOperation} using this operation as its base.
+ * @param name the name that is the target of the named operation.
+ * @return a {@link NamedOperation} with this operation as its base and the specified name.
+ * @throws IllegalArgumentException if this operation is already a named operation.
+ * @throws NullPointerException if {@code name} is null.
+ */
+ default NamedOperation named(final Object name) {
+ return new NamedOperation(this, name);
+ }
}
diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/StandardNamespace.java b/src/jdk.dynalink/share/classes/jdk/dynalink/StandardNamespace.java
new file mode 100644
index 0000000..af0b25b
--- /dev/null
+++ b/src/jdk.dynalink/share/classes/jdk/dynalink/StandardNamespace.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * 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 2016 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.dynalink;
+
+/**
+ * An enumeration of standard namespaces defined by Dynalink.
+ */
+public enum StandardNamespace implements Namespace {
+ /**
+ * Standard namespace for properties of an object.
+ */
+ PROPERTY,
+ /**
+ * Standard namespace for elements of a collection object.
+ */
+ ELEMENT,
+ /**
+ * Standard namespace for methods of an object. The method objects retrieved
+ * through a {@link StandardOperation#GET} on this namespace can be (and where
+ * object semantics allows they should be) unbound, that is: not bound to the
+ * object they were retrieved through. When they are used with
+ * {@link StandardOperation#CALL} an explicit "this" receiver argument is always
+ * passed to them. Of course bound methods can be returned if the object semantics
+ * requires them and such methods are free to ignore the receiver passed in the
+ * {@code CALL} operation or even raise an error when it is different from the one
+ * the method is bound to, or exhibit any other behavior their semantics requires
+ * in such case.
+ */
+ METHOD;
+
+ /**
+ * If the passed in operation is a {@link NamespaceOperation}, or a
+ * {@link NamedOperation} wrapping a {@link NamespaceOperation}, then it
+ * returns the first (if any) {@link StandardNamespace} in its namespace
+ * list. If the passed operation is not a namespace operation (optionally
+ * wrapped in a named operation), or if it doesn't have any standard
+ * namespaces in it, returns {@code null}.
+ * @param op the operation
+ * @return the first standard namespace in the operation's namespace list
+ */
+ public static StandardNamespace findFirst(final Operation op) {
+ for(final Namespace ns: NamespaceOperation.getNamespaces(NamedOperation.getBaseOperation(op))) {
+ if (ns instanceof StandardNamespace) {
+ return (StandardNamespace)ns;
+ }
+ }
+ return null;
+ }
+}
diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/StandardOperation.java b/src/jdk.dynalink/share/classes/jdk/dynalink/StandardOperation.java
index 7fbc943..e5acb1b 100644
--- a/src/jdk.dynalink/share/classes/jdk/dynalink/StandardOperation.java
+++ b/src/jdk.dynalink/share/classes/jdk/dynalink/StandardOperation.java
@@ -84,79 +84,40 @@
package jdk.dynalink;
/**
- * Defines the standard dynamic operations. Getter and setter operations defined
- * in this enumeration can be composed into a {@link CompositeOperation}, and
- * {@link NamedOperation} can be used to bind the name parameter of operations
- * that take one, in which case it disappears from the type signature.
+ * Defines the standard dynamic operations. The operations {@link #GET} and {@link #SET} must
+ * be used as part of a {@link NamespaceOperation}. {@link NamedOperation} can then be further used on these
+ * {@link NamespaceOperation}s to bind the name parameter of {@link #GET} and {@link #SET} operations, in which case it
+ * disappears from their type signature.
+ * {@link NamedOperation} can also be used to decorate {@link #CALL} and {@link #NEW} operations with a
+ * diagnostic name, and as such it does not affect their type signature.
*/
public enum StandardOperation implements Operation {
/**
- * Get the value of a property defined on an object. Call sites with this
+ * Get the value from a namespace defined on an object. Call sites with this
* operation should have a signature of
- * <tt>(receiver, propertyName)→value</tt> or
+ * <tt>(receiver, name)→value</tt> or
* <tt>(receiver)→value</tt> when used with {@link NamedOperation}, with
* all parameters and return type being of any type (either primitive or
- * reference).
+ * reference). This operation must always be used as part of a {@link NamespaceOperation}.
*/
- GET_PROPERTY,
+ GET,
/**
- * Set the value of a property defined on an object. Call sites with this
+ * Set the value in a namespace defined on an object. Call sites with this
* operation should have a signature of
- * <tt>(receiver, propertyName, value)→void</tt> or
+ * <tt>(receiver, name, value)→void</tt> or
* <tt>(receiver, value)→void</tt> when used with {@link NamedOperation},
* with all parameters and return type being of any type (either primitive
- * or reference).
+ * or reference). This operation must always be used as part of a {@link NamespaceOperation}.
*/
- SET_PROPERTY,
+ SET,
/**
- * Get the value of an element of a collection. Call sites with this
- * operation should have a signature of
- * <tt>(receiver, index)→value</tt> or
- * <tt>(receiver)→value</tt> when used with {@link NamedOperation}, with
- * all parameters and return type being of any type (either primitive or
- * reference).
- */
- GET_ELEMENT,
- /**
- * Set the value of an element of a collection. Call sites with this
- * operation should have a signature of
- * <tt>(receiver, index, value)→void</tt> or
- * <tt>(receiver, value)→void</tt> when used with {@link NamedOperation},
- * with all parameters and return type being of any type (either primitive
- * or reference).
- */
- SET_ELEMENT,
- /**
- * Get the length of an array or size of a collection. Call sites with
- * this operation should have a signature of <tt>(receiver)→value</tt>,
- * with all parameters and return type being of any type (either primitive
- * or reference).
- */
- GET_LENGTH,
- /**
- * Gets an object representing a method defined on an object. Call sites
- * with this operation should have a signature of
- * <tt>(receiver, methodName)→value</tt>, or
- * <tt>(receiver)→value</tt> when used with {@link NamedOperation}
- * with all parameters and return type being of any type (either primitive
- * or reference).
- */
- GET_METHOD,
- /**
- * Calls a method defined on an object. Call sites with this
- * operation should have a signature of
- * <tt>(receiver, methodName, arguments...)→value</tt> or
- * <tt>(receiver, arguments...)→value</tt> when used with {@link NamedOperation},
- * with all parameters and return type being of any type (either primitive
- * or reference).
- */
- CALL_METHOD,
- /**
- * Calls a callable object. Call sites with this operation should have a
- * signature of <tt>(receiver, arguments...)→value</tt>, with all
- * parameters and return type being of any type (either primitive or
- * reference). Typically, if the callable is a method of an object, the
- * first argument will act as the "this" value passed to the called method.
+ * Call a callable object. Call sites with this operation should have a
+ * signature of <tt>(callable, receiver, arguments...)→value</tt>,
+ * with all parameters and return type being of any type (either primitive or
+ * reference). Typically, the callables are presumed to be methods of an object, so
+ * an explicit receiver value is always passed to the callable before the arguments.
+ * If a callable has no concept of a receiver, it is free to ignore the value of the
+ * receiver argument.
* The <tt>CALL</tt> operation is allowed to be used with a
* {@link NamedOperation} even though it does not take a name. Using it with
* a named operation won't affect its signature; the name is solely meant to
@@ -164,8 +125,8 @@
*/
CALL,
/**
- * Calls a constructor object. Call sites with this operation should have a
- * signature of <tt>(receiver, arguments...)→value</tt>, with all
+ * Call a constructor object. Call sites with this operation should have a
+ * signature of <tt>(constructor, arguments...)→value</tt>, with all
* parameters and return type being of any type (either primitive or
* reference). The <tt>NEW</tt> operation is allowed to be used with a
* {@link NamedOperation} even though it does not take a name. Using it with
diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/beans/AbstractJavaLinker.java b/src/jdk.dynalink/share/classes/jdk/dynalink/beans/AbstractJavaLinker.java
index 75c5065..f648a81 100644
--- a/src/jdk.dynalink/share/classes/jdk/dynalink/beans/AbstractJavaLinker.java
+++ b/src/jdk.dynalink/share/classes/jdk/dynalink/beans/AbstractJavaLinker.java
@@ -99,9 +99,11 @@
import java.util.Map;
import java.util.Set;
import jdk.dynalink.CallSiteDescriptor;
-import jdk.dynalink.CompositeOperation;
import jdk.dynalink.NamedOperation;
+import jdk.dynalink.Namespace;
+import jdk.dynalink.NamespaceOperation;
import jdk.dynalink.Operation;
+import jdk.dynalink.StandardNamespace;
import jdk.dynalink.StandardOperation;
import jdk.dynalink.beans.GuardedInvocationComponent.ValidationType;
import jdk.dynalink.internal.InternalTypeUtilities;
@@ -360,22 +362,6 @@
directLinkerServices = linkerServices;
}
- // Handle NamedOperation(CALL_METHOD, name) separately
- final Operation operation = callSiteDescriptor.getOperation();
- if (operation instanceof NamedOperation) {
- final NamedOperation namedOperation = (NamedOperation)operation;
- if (namedOperation.getBaseOperation() == StandardOperation.CALL_METHOD) {
- final GuardedInvocation inv =
- createGuardedDynamicMethodInvocation(callSiteDescriptor,
- directLinkerServices, namedOperation.getName().toString(), methods);
- if (inv == null) {
- return createNoSuchMemberHandler(missingMemberHandlerFactory,
- request, directLinkerServices).getGuardedInvocation();
- }
- return inv;
- }
- }
-
final GuardedInvocationComponent gic = getGuardedInvocationComponent(
new ComponentLinkRequest(request, directLinkerServices,
missingMemberHandlerFactory));
@@ -386,7 +372,8 @@
final LinkRequest linkRequest;
final LinkerServices linkerServices;
final MissingMemberHandlerFactory missingMemberHandlerFactory;
- final List<Operation> operations;
+ final Operation baseOperation;
+ final List<Namespace> namespaces;
final Object name;
ComponentLinkRequest(final LinkRequest linkRequest,
@@ -395,21 +382,22 @@
this.linkRequest = linkRequest;
this.linkerServices = linkerServices;
this.missingMemberHandlerFactory = missingMemberHandlerFactory;
- final Operation operation = linkRequest.getCallSiteDescriptor().getOperation();
- this.operations = Arrays.asList(
- CompositeOperation.getOperations(
- NamedOperation.getBaseOperation(operation)));
- this.name = NamedOperation.getName(operation);
+ final Operation namedOp = linkRequest.getCallSiteDescriptor().getOperation();
+ this.name = NamedOperation.getName(namedOp);
+ final Operation namespaceOp = NamedOperation.getBaseOperation(namedOp);
+ this.baseOperation = NamespaceOperation.getBaseOperation(namespaceOp);
+ this.namespaces = Arrays.asList(NamespaceOperation.getNamespaces(namespaceOp));
}
private ComponentLinkRequest(final LinkRequest linkRequest,
final LinkerServices linkerServices,
final MissingMemberHandlerFactory missingMemberHandlerFactory,
- final List<Operation> operations, final Object name) {
+ final Operation baseOperation, final List<Namespace> namespaces, final Object name) {
this.linkRequest = linkRequest;
this.linkerServices = linkerServices;
this.missingMemberHandlerFactory = missingMemberHandlerFactory;
- this.operations = operations;
+ this.baseOperation = baseOperation;
+ this.namespaces = namespaces;
this.name = name;
}
@@ -417,29 +405,33 @@
return linkRequest.getCallSiteDescriptor();
}
- ComponentLinkRequest popOperations() {
+ ComponentLinkRequest popNamespace() {
return new ComponentLinkRequest(linkRequest, linkerServices,
- missingMemberHandlerFactory,
- operations.subList(1, operations.size()), name);
+ missingMemberHandlerFactory, baseOperation,
+ namespaces.subList(1, namespaces.size()), name);
}
}
protected GuardedInvocationComponent getGuardedInvocationComponent(final ComponentLinkRequest req)
throws Exception {
- final Operation op = req.operations.get(0);
- if (op instanceof StandardOperation) {
- switch((StandardOperation)op) {
- case GET_PROPERTY: return getPropertyGetter(req.popOperations());
- case SET_PROPERTY: return getPropertySetter(req.popOperations());
- case GET_METHOD: return getMethodGetter(req.popOperations());
- default:
+ if (!req.namespaces.isEmpty()) {
+ final Namespace ns = req.namespaces.get(0);
+ final Operation op = req.baseOperation;
+ if (op == StandardOperation.GET) {
+ if (ns == StandardNamespace.PROPERTY) {
+ return getPropertyGetter(req.popNamespace());
+ } else if (ns == StandardNamespace.METHOD) {
+ return getMethodGetter(req.popNamespace());
+ }
+ } else if (op == StandardOperation.SET && ns == StandardNamespace.PROPERTY) {
+ return getPropertySetter(req.popNamespace());
}
}
return null;
}
GuardedInvocationComponent getNextComponent(final ComponentLinkRequest req) throws Exception {
- if (req.operations.isEmpty()) {
+ if (req.namespaces.isEmpty()) {
return createNoSuchMemberHandler(req.missingMemberHandlerFactory,
req.linkRequest, req.linkerServices);
}
@@ -447,7 +439,7 @@
if (gic != null) {
return gic;
}
- return getNextComponent(req.popOperations());
+ return getNextComponent(req.popNamespace());
}
private GuardedInvocationComponent createNoSuchMemberHandler(
@@ -626,8 +618,7 @@
if(gi != null) {
return new GuardedInvocationComponent(gi, clazz, ValidationType.EXACT_CLASS);
}
- // If we don't have a property setter with this name, always fall back to the next operation in the
- // composite (if any)
+ // If we don't have a property setter with this name, always fall back to the next namespace (if any).
return getNextComponent(req);
}
@@ -808,8 +799,8 @@
// We have no such method, always delegate to the next component
return getNextComponent(req);
}
- // No delegation to the next component of the composite operation; if we have a method with that name,
- // we'll always return it at this point.
+ // No delegation to the next namespace; if we have a method with that name, we'll always return it at
+ // this point.
final MethodType type = getMethodGetterType(req);
return getClassGuardedInvocationComponent(req.linkerServices.asType(MethodHandles.dropArguments(
MethodHandles.constant(Object.class, method), 0, type.parameterType(0)), type), type);
@@ -880,7 +871,7 @@
@SuppressWarnings("unused")
// This method is marked to return Object instead of DynamicMethod as it's used as a linking component and we don't
// want to make the DynamicMethod type observable externally (e.g. as the return type of a MethodHandle returned for
- // GET_METHOD linking).
+ // GET:METHOD linking).
private Object getDynamicMethod(final Object name) {
return getDynamicMethod(String.valueOf(name), methods);
}
diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/beans/BeanLinker.java b/src/jdk.dynalink/share/classes/jdk/dynalink/beans/BeanLinker.java
index 3f98c2b..d865ec5 100644
--- a/src/jdk.dynalink/share/classes/jdk/dynalink/beans/BeanLinker.java
+++ b/src/jdk.dynalink/share/classes/jdk/dynalink/beans/BeanLinker.java
@@ -92,7 +92,9 @@
import java.util.List;
import java.util.Map;
import jdk.dynalink.CallSiteDescriptor;
+import jdk.dynalink.Namespace;
import jdk.dynalink.Operation;
+import jdk.dynalink.StandardNamespace;
import jdk.dynalink.StandardOperation;
import jdk.dynalink.beans.GuardedInvocationComponent.ValidationType;
import jdk.dynalink.linker.GuardedInvocation;
@@ -112,10 +114,11 @@
if(clazz.isArray()) {
// Some languages won't have a notion of manipulating collections. Exposing "length" on arrays as an
// explicit property is beneficial for them.
- // REVISIT: is it maybe a code smell that StandardOperation.GET_LENGTH is not needed?
setPropertyGetter("length", MethodHandles.arrayLength(clazz), ValidationType.EXACT_CLASS);
- } else if(List.class.isAssignableFrom(clazz)) {
+ } else if(Collection.class.isAssignableFrom(clazz)) {
setPropertyGetter("length", GET_COLLECTION_LENGTH, ValidationType.INSTANCE_OF);
+ } else if(Map.class.isAssignableFrom(clazz)) {
+ setPropertyGetter("length", GET_MAP_LENGTH, ValidationType.INSTANCE_OF);
}
}
@@ -135,14 +138,14 @@
if(superGic != null) {
return superGic;
}
- if (!req.operations.isEmpty()) {
- final Operation op = req.operations.get(0);
- if (op instanceof StandardOperation) {
- switch ((StandardOperation)op) {
- case GET_ELEMENT: return getElementGetter(req.popOperations());
- case SET_ELEMENT: return getElementSetter(req.popOperations());
- case GET_LENGTH: return getLengthGetter(req.getDescriptor());
- default:
+ if (!req.namespaces.isEmpty()) {
+ final Operation op = req.baseOperation;
+ final Namespace ns = req.namespaces.get(0);
+ if (ns == StandardNamespace.ELEMENT) {
+ if (op == StandardOperation.GET) {
+ return getElementGetter(req.popNamespace());
+ } else if (op == StandardOperation.SET) {
+ return getElementSetter(req.popNamespace());
}
}
}
@@ -524,38 +527,6 @@
private static final MethodHandle GET_MAP_LENGTH = Lookup.PUBLIC.findVirtual(Map.class, "size",
MethodType.methodType(int.class));
- private static final MethodHandle COLLECTION_GUARD = Guards.getInstanceOfGuard(Collection.class);
-
- private GuardedInvocationComponent getLengthGetter(final CallSiteDescriptor callSiteDescriptor) {
- assertParameterCount(callSiteDescriptor, 1);
- final MethodType callSiteType = callSiteDescriptor.getMethodType();
- final Class<?> declaredType = callSiteType.parameterType(0);
- // If declared type of receiver at the call site is already an array, collection, or map, bind without guard.
- // Thing is, it'd be quite stupid of a call site creator to go though invokedynamic when it knows in advance
- // they're dealing with an array, collection, or map, but hey...
- if(declaredType.isArray()) {
- return new GuardedInvocationComponent(MethodHandles.arrayLength(declaredType).asType(callSiteType));
- } else if(Collection.class.isAssignableFrom(declaredType)) {
- return new GuardedInvocationComponent(GET_COLLECTION_LENGTH.asType(callSiteType));
- } else if(Map.class.isAssignableFrom(declaredType)) {
- return new GuardedInvocationComponent(GET_MAP_LENGTH.asType(callSiteType));
- }
-
- // Otherwise, create a binding based on the actual type of the argument with an appropriate guard.
- if(clazz.isArray()) {
- return new GuardedInvocationComponent(MethodHandles.arrayLength(clazz).asType(callSiteType),
- Guards.isArray(0, callSiteType), ValidationType.EXACT_CLASS);
- } if(Collection.class.isAssignableFrom(clazz)) {
- return new GuardedInvocationComponent(GET_COLLECTION_LENGTH.asType(callSiteType), Guards.asType(
- COLLECTION_GUARD, callSiteType), Collection.class, ValidationType.INSTANCE_OF);
- } if(Map.class.isAssignableFrom(clazz)) {
- return new GuardedInvocationComponent(GET_MAP_LENGTH.asType(callSiteType), Guards.asType(MAP_GUARD,
- callSiteType), Map.class, ValidationType.INSTANCE_OF);
- }
- // Can't retrieve length for objects that are neither arrays, nor collections, nor maps.
- return null;
- }
-
private static void assertParameterCount(final CallSiteDescriptor descriptor, final int paramCount) {
if(descriptor.getMethodType().parameterCount() != paramCount) {
throw new BootstrapMethodError(descriptor.getOperation() + " must have exactly " + paramCount + " parameters.");
diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/beans/BeansLinker.java b/src/jdk.dynalink/share/classes/jdk/dynalink/beans/BeansLinker.java
index 4ea49f2..5ba5626 100644
--- a/src/jdk.dynalink/share/classes/jdk/dynalink/beans/BeansLinker.java
+++ b/src/jdk.dynalink/share/classes/jdk/dynalink/beans/BeansLinker.java
@@ -87,6 +87,7 @@
import java.util.Collections;
import java.util.Set;
import jdk.dynalink.DynamicLinkerFactory;
+import jdk.dynalink.StandardNamespace;
import jdk.dynalink.StandardOperation;
import jdk.dynalink.linker.GuardedInvocation;
import jdk.dynalink.linker.GuardingDynamicLinker;
@@ -102,21 +103,18 @@
* <ul>
* <li>expose all public methods of form {@code setXxx()}, {@code getXxx()},
* and {@code isXxx()} as property setters and getters for
- * {@link StandardOperation#SET_PROPERTY} and {@link StandardOperation#GET_PROPERTY}
- * operations;</li>
- * <li>expose all public methods for invocation through
- * {@link StandardOperation#CALL_METHOD} operation;</li>
+ * {@link StandardOperation#SET} and {@link StandardOperation#GET} operations in the
+ * {@link StandardNamespace#PROPERTY} namespace;</li>
* <li>expose all public methods for retrieval for
- * {@link StandardOperation#GET_METHOD} operation; the methods thus retrieved
- * can then be invoked using {@link StandardOperation#CALL}.</li>
+ * {@link StandardOperation#GET} operation in the {@link StandardNamespace#METHOD} namespace;
+ * the methods thus retrieved can then be invoked using {@link StandardOperation#CALL}.</li>
* <li>expose all public fields as properties, unless there are getters or
* setters for the properties of the same name;</li>
- * <li>expose {@link StandardOperation#GET_LENGTH},
- * {@link StandardOperation#GET_ELEMENT} and {@link StandardOperation#SET_ELEMENT}
- * on native Java arrays, as well as {@link java.util.List} and
- * {@link java.util.Map} objects; ({@link StandardOperation#GET_LENGTH} works on
- * any {@link java.util.Collection});</li>
- * <li>expose a virtual property named {@code length} on Java arrays;</li>
+ * <li> expose elements of native Java arrays, {@link java.util.List} and {@link java.util.Map} objects as
+ * {@link StandardOperation#GET} and {@link StandardOperation#SET} operations in the
+ * {@link StandardNamespace#ELEMENT} namespace;</li>
+ * <li>expose a virtual property named {@code length} on Java arrays, {@link java.util.Collection} and
+ * {@link java.util.Map} objects;</li>
* <li>expose {@link StandardOperation#NEW} on instances of {@link StaticClass}
* as calls to constructors, including those static class objects that represent
* Java arrays (their constructors take a single {@code int} parameter
@@ -130,10 +128,10 @@
* <p><strong>Overloaded method resolution</strong> is performed automatically
* for property setters, methods, and constructors. Additionally, manual
* overloaded method selection is supported by having a call site specify a name
- * for a method that contains an explicit signature, i.e.
- * {@code NamedMethod(GET_METHOD, "parseInt(String,int)")}. You can use
- * non-qualified class names in such signatures regardless of those classes'
- * packages, they will match any class with the same non-qualified name. You
+ * for a method that contains an explicit signature, e.g.
+ * {@code StandardOperation.GET.withNamespace(METHOD).named("parseInt(String,int)")}
+ * You can use non-qualified class names in such signatures regardless of those
+ * classes' packages, they will match any class with the same non-qualified name. You
* only have to use a fully qualified class name in case non-qualified class
* names would cause selection ambiguity (that is extremely rare). Overloaded
* resolution for constructors is not automatic as there is no logical place to
@@ -235,7 +233,7 @@
/**
* Returns true if the object is a Java dynamic method (e.g., one
- * obtained through a {@code GET_METHOD} operation on a Java object or
+ * obtained through a {@code GET:METHOD} operation on a Java object or
* {@link StaticClass} or through
* {@link #getConstructorMethod(Class, String)}.
*
diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/beans/DynamicMethodLinker.java b/src/jdk.dynalink/share/classes/jdk/dynalink/beans/DynamicMethodLinker.java
index 9f1cf1c..3e79926 100644
--- a/src/jdk.dynalink/share/classes/jdk/dynalink/beans/DynamicMethodLinker.java
+++ b/src/jdk.dynalink/share/classes/jdk/dynalink/beans/DynamicMethodLinker.java
@@ -88,6 +88,7 @@
import jdk.dynalink.CallSiteDescriptor;
import jdk.dynalink.NamedOperation;
import jdk.dynalink.Operation;
+import jdk.dynalink.StandardNamespace;
import jdk.dynalink.StandardOperation;
import jdk.dynalink.linker.GuardedInvocation;
import jdk.dynalink.linker.LinkRequest;
@@ -98,7 +99,8 @@
/**
* Simple linker that implements the {@link StandardOperation#CALL} operation
* for {@link DynamicMethod} objects - the objects returned by
- * {@link StandardOperation#GET_METHOD} through {@link AbstractJavaLinker}.
+ * {@link StandardOperation#GET} on {@link StandardNamespace#METHOD} namespace through
+ * {@link AbstractJavaLinker}.
*/
class DynamicMethodLinker implements TypeBasedGuardingDynamicLinker {
@Override
diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/beans/GuardedInvocationComponent.java b/src/jdk.dynalink/share/classes/jdk/dynalink/beans/GuardedInvocationComponent.java
index 8a3e48a..0e3f832 100644
--- a/src/jdk.dynalink/share/classes/jdk/dynalink/beans/GuardedInvocationComponent.java
+++ b/src/jdk.dynalink/share/classes/jdk/dynalink/beans/GuardedInvocationComponent.java
@@ -87,7 +87,7 @@
import jdk.dynalink.linker.GuardedInvocation;
/**
- * Represents one component for a GuardedInvocation of a potentially composite operation of an
+ * Represents one component for a GuardedInvocation of a potentially multi-namespace operation of an
* {@link AbstractJavaLinker}. In addition to holding a guarded invocation, it holds semantic information about its
* guard. All guards produced in the AbstractJavaLinker are either "Class.isInstance()" or "getClass() == clazz"
* expressions. This allows choosing the most restrictive guard as the guard for the composition of two components.
diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/beans/StaticClass.java b/src/jdk.dynalink/share/classes/jdk/dynalink/beans/StaticClass.java
index 432b18a..748885a 100644
--- a/src/jdk.dynalink/share/classes/jdk/dynalink/beans/StaticClass.java
+++ b/src/jdk.dynalink/share/classes/jdk/dynalink/beans/StaticClass.java
@@ -92,7 +92,7 @@
* methods, properties, and fields), as well as construction of instances using
* {@link StandardOperation#NEW} operation. In Dynalink, {@link Class} objects
* are not treated specially and act as ordinary Java objects; you can use e.g.
- * {@code NamedOperation(GET_PROPERTY, "superclass")} as a property getter to
+ * {@code GET:PROPERTY:superclass} as a property getter to
* invoke {@code clazz.getSuperclass()}. On the other hand, you can not use
* {@code Class} objects to access static members of a class, nor to create new
* instances of the class using {@code NEW}. This is consistent with how
diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/beans/StaticClassLinker.java b/src/jdk.dynalink/share/classes/jdk/dynalink/beans/StaticClassLinker.java
index c81e8d1..94d8eb8 100644
--- a/src/jdk.dynalink/share/classes/jdk/dynalink/beans/StaticClassLinker.java
+++ b/src/jdk.dynalink/share/classes/jdk/dynalink/beans/StaticClassLinker.java
@@ -91,7 +91,7 @@
import java.util.Set;
import jdk.dynalink.CallSiteDescriptor;
import jdk.dynalink.NamedOperation;
-import jdk.dynalink.Operation;
+import jdk.dynalink.StandardNamespace;
import jdk.dynalink.StandardOperation;
import jdk.dynalink.beans.GuardedInvocationComponent.ValidationType;
import jdk.dynalink.linker.GuardedInvocation;
@@ -168,17 +168,12 @@
if (superGic != null) {
return superGic;
}
- if (!req.operations.isEmpty()) {
- final Operation op = req.operations.get(0);
- if (op instanceof StandardOperation) {
- switch ((StandardOperation)op) {
- case GET_ELEMENT:
- case SET_ELEMENT:
- // StaticClass doesn't behave as a collection
- return getNextComponent(req.popOperations());
- default:
- }
- }
+ if (!req.namespaces.isEmpty()
+ && req.namespaces.get(0) == StandardNamespace.ELEMENT
+ && (req.baseOperation == StandardOperation.GET || req.baseOperation == StandardOperation.SET))
+ {
+ // StaticClass doesn't behave as a collection
+ return getNextComponent(req.popNamespace());
}
return null;
}
diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/package-info.java b/src/jdk.dynalink/share/classes/jdk/dynalink/package-info.java
index e68bf14..b89f4c2 100644
--- a/src/jdk.dynalink/share/classes/jdk/dynalink/package-info.java
+++ b/src/jdk.dynalink/share/classes/jdk/dynalink/package-info.java
@@ -129,7 +129,7 @@
* bytecode would look something like this:
* <pre>
* aload 2 // load "obj" on stack
- * invokedynamic "GET_PROPERTY:color"(Object)Object // invoke property getter on object of unknown type
+ * invokedynamic "GET:PROPERTY:color"(Object)Object // invoke property getter on object of unknown type
* astore 3 // store the return value into local variable "color"
* </pre>
* In order to link the {@code invokedynamic} instruction, we need a bootstrap
@@ -175,9 +175,9 @@
* dynamic operations. It does not prescribe how would you encode the operations
* in your call site, though. That is why in the above example the
* {@code parseOperation} function is left empty, and you would be expected to
- * provide the code to parse the string {@code "GET_PROPERTY:color"}
+ * provide the code to parse the string {@code "GET:PROPERTY:color"}
* in the call site's name into a named property getter operation object as
- * {@code new NamedOperation(StandardOperation.GET_PROPERTY), "color")}.
+ * {@code StandardOperation.GET.withNamespace(StandardNamespace.PROPERTY).named("color")}.
* </ul>
* <p>What can you already do with the above setup? {@code DynamicLinkerFactory}
* by default creates a {@code DynamicLinker} that can link Java objects with the
@@ -231,18 +231,20 @@
* Dynalink defines several standard operations in its
* {@link jdk.dynalink.StandardOperation} class. The linker for Java
* objects can link all of these operations, and you are encouraged to at
- * minimum support and use these operations in your language too. To associate
- * a fixed name with an operation, you can use
- * {@link jdk.dynalink.NamedOperation} as in the above example where
- * {@code StandardOperation.GET_PROPERTY} was combined with the name
- * {@code "color"} in a {@code NamedOperation} to form a property getter for the
- * property named "color".
- * <h2>Composite operations</h2>
+ * minimum support and use these operations in your language too. The
+ * standard operations {@code GET} and {@code SET} need to be combined with
+ * at least one {@link jdk.dynalink.Namespace} to be useful, e.g. to express a
+ * property getter, you'd use {@code StandardOperation.GET.withNamespace(StandardNamespace.PROPERTY)}.
+ * Dynalink defines three standard namespaces in the {@link jdk.dynalink.StandardNamespace} class.
+ * To associate a fixed name with an operation, you can use
+ * {@link jdk.dynalink.NamedOperation} as in the previous example:
+ * {@code StandardOperation.GET.withNamespace(StandardNamespace.PROPERTY).named("color")}
+ * expresses a getter for the property named "color".
+ * <h2>Operations on multiple namespaces</h2>
* Some languages might not have separate namespaces on objects for
* properties, elements, and methods, and a source language construct might
- * address two or three of them. Dynalink supports specifying composite
- * operations for this purpose using the
- * {@link jdk.dynalink.CompositeOperation} class.
+ * address several of them at once. Dynalink supports specifying multiple
+ * {@link jdk.dynalink.Namespace} objects with {@link jdk.dynalink.NamespaceOperation}.
* <h2>Language-specific linkers</h2>
* Languages that define their own object model different than the JVM
* class-based model and/or use their own type conversions will need to create
diff --git a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/IRTranslator.java b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/IRTranslator.java
index 974f56c..041ab61 100644
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/IRTranslator.java
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/IRTranslator.java
@@ -384,7 +384,7 @@
final List<CatchTreeImpl> catchTrees = new ArrayList<>(catchNodes.size());
for (final CatchNode catchNode : catchNodes) {
catchTrees.add(new CatchTreeImpl(catchNode,
- translateIdent(catchNode.getException()),
+ translateExpr(catchNode.getException()),
(BlockTree) translateBlock(catchNode.getBody()),
translateExpr(catchNode.getExceptionCondition())));
}
diff --git a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/AssignSymbols.java b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/AssignSymbols.java
index e0785e6..3bb44b5 100644
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/AssignSymbols.java
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/AssignSymbols.java
@@ -343,7 +343,7 @@
symbol = null;
} else if (symbol.isParam()) {
// Duplicate parameter. Null return will force an error.
- throw new AssertionError("duplicate parameter");
+ throwParserException(ECMAErrors.getMessage("syntax.error.duplicate.parameter", name), origin);
}
} else if (isVar) {
if (isBlockScope) {
@@ -462,7 +462,7 @@
@Override
public boolean enterCatchNode(final CatchNode catchNode) {
- final IdentNode exception = catchNode.getException();
+ final IdentNode exception = catchNode.getExceptionIdentifier();
final Block block = lc.getCurrentBlock();
start(catchNode);
diff --git a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java
index f04f895..c4053bc 100644
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java
@@ -3255,7 +3255,7 @@
enterBlock(catchBlock);
final CatchNode catchNode = (CatchNode)catchBlocks.get(i).getStatements().get(0);
- final IdentNode exception = catchNode.getException();
+ final IdentNode exception = catchNode.getExceptionIdentifier();
final Expression exceptionCondition = catchNode.getExceptionCondition();
final Block catchBody = catchNode.getBody();
diff --git a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java
index cf92047..f484440 100644
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java
@@ -33,6 +33,7 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.Deque;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.Iterator;
@@ -122,9 +123,9 @@
private final List<JumpOrigin> origins = new LinkedList<>();
private Map<Symbol, LvarType> types = Collections.emptyMap();
- void addOrigin(final JoinPredecessor originNode, final Map<Symbol, LvarType> originTypes) {
+ void addOrigin(final JoinPredecessor originNode, final Map<Symbol, LvarType> originTypes, final LocalVariableTypesCalculator calc) {
origins.add(new JumpOrigin(originNode, originTypes));
- this.types = getUnionTypes(this.types, originTypes);
+ this.types = calc.getUnionTypes(this.types, originTypes);
}
}
private enum LvarType {
@@ -185,12 +186,15 @@
}
@SuppressWarnings("unchecked")
- private static IdentityHashMap<Symbol, LvarType> cloneMap(final Map<Symbol, LvarType> map) {
- return (IdentityHashMap<Symbol, LvarType>)((IdentityHashMap<?,?>)map).clone();
+ private static HashMap<Symbol, LvarType> cloneMap(final Map<Symbol, LvarType> map) {
+ return (HashMap<Symbol, LvarType>)((HashMap<?,?>)map).clone();
}
private LocalVariableConversion createConversion(final Symbol symbol, final LvarType branchLvarType,
final Map<Symbol, LvarType> joinLvarTypes, final LocalVariableConversion next) {
+ if (invalidatedSymbols.contains(symbol)) {
+ return next;
+ }
final LvarType targetType = joinLvarTypes.get(symbol);
assert targetType != null;
if(targetType == branchLvarType) {
@@ -208,7 +212,7 @@
return new LocalVariableConversion(symbol, branchLvarType.type, targetType.type, next);
}
- private static Map<Symbol, LvarType> getUnionTypes(final Map<Symbol, LvarType> types1, final Map<Symbol, LvarType> types2) {
+ private Map<Symbol, LvarType> getUnionTypes(final Map<Symbol, LvarType> types1, final Map<Symbol, LvarType> types2) {
if(types1 == types2 || types1.isEmpty()) {
return types2;
} else if(types2.isEmpty()) {
@@ -261,6 +265,11 @@
final LvarType type2 = types2.get(symbol);
union.put(symbol, widestLvarType(type1, type2));
}
+ // If the two sets of symbols differ, there's a good chance that some of
+ // symbols only appearing in one of the sets are lexically invalidated,
+ // so we remove them from further consideration.
+ // This is not strictly necessary, just a working set size optimization.
+ union.keySet().removeAll(invalidatedSymbols);
return union;
}
@@ -359,8 +368,6 @@
if(t1.ordinal() < LvarType.INT.ordinal() || t2.ordinal() < LvarType.INT.ordinal()) {
return LvarType.OBJECT;
}
- // NOTE: we allow "widening" of long to double even though it can lose precision. ECMAScript doesn't have an
- // Int64 type anyway, so this loss of precision is actually more conformant to the specification...
return LvarType.values()[Math.max(t1.ordinal(), t2.ordinal())];
}
private final Compiler compiler;
@@ -368,7 +375,10 @@
// Local variable type mapping at the currently evaluated point. No map instance is ever modified; setLvarType() always
// allocates a new map. Immutability of maps allows for cheap snapshots by just keeping the reference to the current
// value.
- private Map<Symbol, LvarType> localVariableTypes = new IdentityHashMap<>();
+ private Map<Symbol, LvarType> localVariableTypes = Collections.emptyMap();
+ // Set of symbols whose lexical scope has already ended.
+ private final Set<Symbol> invalidatedSymbols = new HashSet<>();
+
// Stack for evaluated expression types.
private final Deque<LvarType> typeStack = new ArrayDeque<>();
@@ -464,9 +474,19 @@
@Override
public boolean enterBlock(final Block block) {
+ boolean cloned = false;
for(final Symbol symbol: block.getSymbols()) {
- if(symbol.isBytecodeLocal() && getLocalVariableTypeOrNull(symbol) == null) {
- setType(symbol, LvarType.UNDEFINED);
+ if(symbol.isBytecodeLocal()) {
+ if (getLocalVariableTypeOrNull(symbol) == null) {
+ if (!cloned) {
+ cloneOrNewLocalVariableTypes();
+ cloned = true;
+ }
+ localVariableTypes.put(symbol, LvarType.UNDEFINED);
+ }
+ // In case we're repeating analysis of a lexical scope (e.g. it's in a loop),
+ // make sure all symbols lexically scoped by the block become valid again.
+ invalidatedSymbols.remove(symbol);
}
}
return true;
@@ -1033,7 +1053,7 @@
joinOnLabel(catchLabel);
for(final CatchNode catchNode: tryNode.getCatches()) {
- final IdentNode exception = catchNode.getException();
+ final IdentNode exception = catchNode.getExceptionIdentifier();
onAssignment(exception, LvarType.OBJECT);
final Expression condition = catchNode.getExceptionCondition();
if(condition != null) {
@@ -1046,15 +1066,11 @@
// throw an exception.
reachable = true;
catchBody.accept(this);
- final Symbol exceptionSymbol = exception.getSymbol();
if(reachable) {
- localVariableTypes = cloneMap(localVariableTypes);
- localVariableTypes.remove(exceptionSymbol);
jumpToLabel(catchBody, endLabel);
canExit = true;
}
- localVariableTypes = cloneMap(afterConditionTypes);
- localVariableTypes.remove(exceptionSymbol);
+ localVariableTypes = afterConditionTypes;
}
// NOTE: if we had one or more conditional catch blocks with no unconditional catch block following them, then
// there will be an unconditional rethrow, so the join point can never be reached from the last
@@ -1204,7 +1220,7 @@
}
private void jumpToLabel(final JoinPredecessor jumpOrigin, final Label label, final Map<Symbol, LvarType> types) {
- getOrCreateJumpTarget(label).addOrigin(jumpOrigin, types);
+ getOrCreateJumpTarget(label).addOrigin(jumpOrigin, types, this);
}
@Override
@@ -1226,16 +1242,18 @@
boolean cloned = false;
for(final Symbol symbol: block.getSymbols()) {
- // Undefine the symbol outside the block
- if(localVariableTypes.containsKey(symbol)) {
- if(!cloned) {
- localVariableTypes = cloneMap(localVariableTypes);
- cloned = true;
- }
- localVariableTypes.remove(symbol);
- }
-
if(symbol.hasSlot()) {
+ // Invalidate the symbol when its defining block ends
+ if (symbol.isBytecodeLocal()) {
+ if(localVariableTypes.containsKey(symbol)) {
+ if(!cloned) {
+ localVariableTypes = cloneMap(localVariableTypes);
+ cloned = true;
+ }
+ }
+ invalidateSymbol(symbol);
+ }
+
final SymbolConversions conversions = symbolConversions.get(symbol);
if(conversions != null) {
// Potentially make some currently dead types live if they're needed as a source of a type
@@ -1605,10 +1623,19 @@
}
assert symbol.hasSlot();
assert !symbol.isGlobal();
- localVariableTypes = localVariableTypes.isEmpty() ? new IdentityHashMap<Symbol, LvarType>() : cloneMap(localVariableTypes);
+ cloneOrNewLocalVariableTypes();
localVariableTypes.put(symbol, type);
}
+ private void cloneOrNewLocalVariableTypes() {
+ localVariableTypes = localVariableTypes.isEmpty() ? new HashMap<Symbol, LvarType>() : cloneMap(localVariableTypes);
+ }
+
+ private void invalidateSymbol(final Symbol symbol) {
+ localVariableTypes.remove(symbol);
+ invalidatedSymbols.add(symbol);
+ }
+
/**
* Set a flag in the symbol marking it as needing to be able to store a value of a particular type. Every symbol for
* a local variable will be assigned between 1 and 6 local variable slots for storing all types it is known to need
diff --git a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Lower.java b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Lower.java
index 06ffe2d..634b537 100644
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Lower.java
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Lower.java
@@ -45,6 +45,7 @@
import jdk.nashorn.internal.ir.CallNode;
import jdk.nashorn.internal.ir.CaseNode;
import jdk.nashorn.internal.ir.CatchNode;
+import jdk.nashorn.internal.ir.ClassNode;
import jdk.nashorn.internal.ir.ContinueNode;
import jdk.nashorn.internal.ir.DebuggerNode;
import jdk.nashorn.internal.ir.EmptyNode;
@@ -60,9 +61,11 @@
import jdk.nashorn.internal.ir.LabelNode;
import jdk.nashorn.internal.ir.LexicalContext;
import jdk.nashorn.internal.ir.LiteralNode;
+import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode;
import jdk.nashorn.internal.ir.LiteralNode.PrimitiveLiteralNode;
import jdk.nashorn.internal.ir.LoopNode;
import jdk.nashorn.internal.ir.Node;
+import jdk.nashorn.internal.ir.ObjectNode;
import jdk.nashorn.internal.ir.ReturnNode;
import jdk.nashorn.internal.ir.RuntimeNode;
import jdk.nashorn.internal.ir.Statement;
@@ -70,6 +73,7 @@
import jdk.nashorn.internal.ir.Symbol;
import jdk.nashorn.internal.ir.ThrowNode;
import jdk.nashorn.internal.ir.TryNode;
+import jdk.nashorn.internal.ir.UnaryNode;
import jdk.nashorn.internal.ir.VarNode;
import jdk.nashorn.internal.ir.WhileNode;
import jdk.nashorn.internal.ir.WithNode;
@@ -78,6 +82,8 @@
import jdk.nashorn.internal.parser.Token;
import jdk.nashorn.internal.parser.TokenType;
import jdk.nashorn.internal.runtime.Context;
+import jdk.nashorn.internal.runtime.ECMAErrors;
+import jdk.nashorn.internal.runtime.ErrorManager;
import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.Source;
import jdk.nashorn.internal.runtime.logging.DebugLogger;
@@ -98,6 +104,7 @@
private final DebugLogger log;
private final boolean es6;
+ private final Source source;
// Conservative pattern to test if element names consist of characters valid for identifiers.
// This matches any non-zero length alphanumeric string including _ and $ and not starting with a digit.
@@ -146,6 +153,7 @@
this.log = initLogger(compiler.getContext());
this.es6 = compiler.getScriptEnvironment()._es6;
+ this.source = compiler.getSource();
}
@Override
@@ -170,6 +178,15 @@
}
@Override
+ public boolean enterCatchNode(final CatchNode catchNode) {
+ Expression exception = catchNode.getException();
+ if ((exception != null) && !(exception instanceof IdentNode)) {
+ throwNotImplementedYet("es6.destructuring", exception);
+ }
+ return true;
+ }
+
+ @Override
public Node leaveCatchNode(final CatchNode catchNode) {
return addStatement(catchNode);
}
@@ -241,6 +258,10 @@
}
}
+ if (es6 && expressionStatement.destructuringDeclarationType() != null) {
+ throwNotImplementedYet("es6.destructuring", expressionStatement);
+ }
+
return addStatement(node);
}
@@ -250,6 +271,14 @@
}
@Override
+ public boolean enterForNode(final ForNode forNode) {
+ if (es6 && (forNode.getInit() instanceof ObjectNode || forNode.getInit() instanceof ArrayLiteralNode)) {
+ throwNotImplementedYet("es6.destructuring", forNode);
+ }
+ return super.enterForNode(forNode);
+ }
+
+ @Override
public Node leaveForNode(final ForNode forNode) {
ForNode newForNode = forNode;
@@ -270,6 +299,37 @@
}
@Override
+ public boolean enterFunctionNode(final FunctionNode functionNode) {
+ if (es6) {
+ if (functionNode.getKind() == FunctionNode.Kind.MODULE) {
+ throwNotImplementedYet("es6.module", functionNode);
+ }
+
+ if (functionNode.getKind() == FunctionNode.Kind.GENERATOR) {
+ throwNotImplementedYet("es6.generator", functionNode);
+ }
+ if (functionNode.usesSuper()) {
+ throwNotImplementedYet("es6.super", functionNode);
+ }
+
+ final int numParams = functionNode.getNumOfParams();
+ if (numParams > 0) {
+ final IdentNode lastParam = functionNode.getParameter(numParams - 1);
+ if (lastParam.isRestParameter()) {
+ throwNotImplementedYet("es6.rest.param", lastParam);
+ }
+ }
+ for (final IdentNode param : functionNode.getParameters()) {
+ if (param.isDestructuredParameter()) {
+ throwNotImplementedYet("es6.destructuring", functionNode);
+ }
+ }
+ }
+
+ return super.enterFunctionNode(functionNode);
+ }
+
+ @Override
public Node leaveFunctionNode(final FunctionNode functionNode) {
log.info("END FunctionNode: ", functionNode.getName());
return functionNode;
@@ -578,6 +638,29 @@
}
@Override
+ public boolean enterUnaryNode(final UnaryNode unaryNode) {
+ if (es6) {
+ if (unaryNode.isTokenType(TokenType.YIELD) ||
+ unaryNode.isTokenType(TokenType.YIELD_STAR)) {
+ throwNotImplementedYet("es6.yield", unaryNode);
+ } else if (unaryNode.isTokenType(TokenType.SPREAD_ARGUMENT) ||
+ unaryNode.isTokenType(TokenType.SPREAD_ARRAY)) {
+ throwNotImplementedYet("es6.spread", unaryNode);
+ }
+ }
+
+ return super.enterUnaryNode(unaryNode);
+ }
+
+ @Override
+ public boolean enterASSIGN(BinaryNode binaryNode) {
+ if (es6 && (binaryNode.lhs() instanceof ObjectNode || binaryNode.lhs() instanceof ArrayLiteralNode)) {
+ throwNotImplementedYet("es6.destructuring", binaryNode);
+ }
+ return super.enterASSIGN(binaryNode);
+ }
+
+ @Override
public Node leaveVarNode(final VarNode varNode) {
addStatement(varNode);
if (varNode.getFlag(VarNode.IS_LAST_FUNCTION_DECLARATION)
@@ -608,6 +691,12 @@
return addStatement(withNode);
}
+ @Override
+ public boolean enterClassNode(final ClassNode classNode) {
+ throwNotImplementedYet("es6.class", classNode);
+ return super.enterClassNode(classNode);
+ }
+
/**
* Given a function node that is a callee in a CallNode, replace it with
* the appropriate marker function. This is used by {@link CodeGenerator}
@@ -766,4 +855,13 @@
}
return false;
}
+
+ private void throwNotImplementedYet(final String msgId, final Node node) {
+ final long token = node.getToken();
+ final int line = source.getLine(node.getStart());
+ final int column = source.getColumn(node.getStart());
+ final String message = ECMAErrors.getMessage("unimplemented." + msgId);
+ final String formatted = ErrorManager.format(message, source, line, column, token);
+ throw new RuntimeException(formatted);
+ }
}
diff --git a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/CatchNode.java b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/CatchNode.java
index 80ca3a5..9431f3b 100644
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/CatchNode.java
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/CatchNode.java
@@ -35,8 +35,8 @@
public final class CatchNode extends Statement {
private static final long serialVersionUID = 1L;
- /** Exception identifier. */
- private final IdentNode exception;
+ /** Exception binding identifier or binding pattern. */
+ private final Expression exception;
/** Exception condition. */
private final Expression exceptionCondition;
@@ -52,21 +52,27 @@
* @param lineNumber lineNumber
* @param token token
* @param finish finish
- * @param exception variable name of exception
+ * @param exception variable name or pattern of exception
* @param exceptionCondition exception condition
* @param body catch body
* @param isSyntheticRethrow true if this node is a synthetically generated rethrow node.
*/
- public CatchNode(final int lineNumber, final long token, final int finish, final IdentNode exception,
+ public CatchNode(final int lineNumber, final long token, final int finish, final Expression exception,
final Expression exceptionCondition, final Block body, final boolean isSyntheticRethrow) {
super(lineNumber, token, finish);
- this.exception = exception == null ? null : exception.setIsInitializedHere();
+ if (exception instanceof IdentNode) {
+ this.exception = ((IdentNode) exception).setIsInitializedHere();
+ } else if ((exception instanceof LiteralNode.ArrayLiteralNode) || (exception instanceof ObjectNode)) {
+ this.exception = exception;
+ } else {
+ throw new IllegalArgumentException("invalid catch parameter");
+ }
this.exceptionCondition = exceptionCondition;
- this.body = body;
+ this.body = body;
this.isSyntheticRethrow = isSyntheticRethrow;
}
- private CatchNode(final CatchNode catchNode, final IdentNode exception, final Expression exceptionCondition,
+ private CatchNode(final CatchNode catchNode, final Expression exception, final Expression exceptionCondition,
final Block body, final boolean isSyntheticRethrow) {
super(catchNode);
this.exception = exception;
@@ -83,11 +89,10 @@
public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
if (visitor.enterCatchNode(this)) {
return visitor.leaveCatchNode(
- setException((IdentNode)exception.accept(visitor)).
- setExceptionCondition(exceptionCondition == null ? null : (Expression)exceptionCondition.accept(visitor)).
- setBody((Block)body.accept(visitor)));
+ setException((Expression) exception.accept(visitor)).
+ setExceptionCondition(exceptionCondition == null ? null : (Expression) exceptionCondition.accept(visitor)).
+ setBody((Block) body.accept(visitor)));
}
-
return this;
}
@@ -109,14 +114,25 @@
}
/**
- * Get the identifier representing the exception thrown
- * @return the exception identifier
+ * Get the binding pattern representing the exception thrown
+ *
+ * @return the exception binding pattern
*/
- public IdentNode getException() {
+ public Expression getException() {
return exception;
}
/**
+ * Get the identifier representing the exception thrown
+ *
+ * @return the exception identifier
+ * @throws ClassCastException if exception set is not binding identifier
+ */
+ public IdentNode getExceptionIdentifier() {
+ return (IdentNode) exception;
+ }
+
+ /**
* Get the exception condition for this catch block
* @return the exception condition
*/
@@ -146,13 +162,19 @@
/**
* Resets the exception of a catch block
- * @param exception new exception
+ *
+ * @param exception new exception which can be binding identifier or binding
+ * pattern
* @return new catch node if changed, same otherwise
*/
- public CatchNode setException(final IdentNode exception) {
+ public CatchNode setException(final Expression exception) {
if (this.exception == exception) {
return this;
}
+ /*check if exception is legitimate*/
+ if (!((exception instanceof IdentNode) || (exception instanceof LiteralNode.ArrayLiteralNode) || (exception instanceof ObjectNode))) {
+ throw new IllegalArgumentException("invalid catch parameter");
+ }
return new CatchNode(this, exception, exceptionCondition, body, isSyntheticRethrow);
}
diff --git a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/debug/PrintVisitor.java b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/debug/PrintVisitor.java
index bb8d61a..fccad15 100644
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/debug/PrintVisitor.java
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/debug/PrintVisitor.java
@@ -397,7 +397,7 @@
@Override
public boolean enterVarNode(final VarNode varNode) {
- sb.append("var ");
+ sb.append(varNode.isConst() ? "const " : varNode.isLet() ? "let " : "var ");
varNode.getName().toString(sb, printTypes);
printLocalVariableConversion(varNode.getName());
final Node init = varNode.getInit();
diff --git a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/visitor/NodeOperatorVisitor.java b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/visitor/NodeOperatorVisitor.java
index 136e5e0..e3b1edb 100644
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/visitor/NodeOperatorVisitor.java
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/visitor/NodeOperatorVisitor.java
@@ -45,7 +45,7 @@
}
@Override
- public final boolean enterUnaryNode(final UnaryNode unaryNode) {
+ public boolean enterUnaryNode(final UnaryNode unaryNode) {
switch (unaryNode.tokenType()) {
case ADD:
return enterADD(unaryNode);
diff --git a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/ArrayIterator.java b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/ArrayIterator.java
index 6b890db..1d600df 100644
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/ArrayIterator.java
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/ArrayIterator.java
@@ -47,13 +47,25 @@
private final Global global;
- ArrayIterator(final Object iteratedObject, final IterationKind iterationKind, final Global global) {
+ private ArrayIterator(final Object iteratedObject, final IterationKind iterationKind, final Global global) {
super(global.getArrayIteratorPrototype(), $nasgenmap$);
this.iteratedObject = iteratedObject instanceof ScriptObject ? (ScriptObject) iteratedObject : null;
this.iterationKind = iterationKind;
this.global = global;
}
+ static ArrayIterator newArrayValueIterator(final Object iteratedObject) {
+ return new ArrayIterator(Global.toObject(iteratedObject), IterationKind.VALUE, Global.instance());
+ }
+
+ static ArrayIterator newArrayKeyIterator(final Object iteratedObject) {
+ return new ArrayIterator(Global.toObject(iteratedObject), IterationKind.KEY, Global.instance());
+ }
+
+ static ArrayIterator newArrayKeyValueIterator(final Object iteratedObject) {
+ return new ArrayIterator(Global.toObject(iteratedObject), IterationKind.KEY_VALUE, Global.instance());
+ }
+
/**
* 22.1.5.2.1 %ArrayIteratorPrototype%.next()
*
diff --git a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/Global.java b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/Global.java
index 0d318ad..dc172a8 100644
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/Global.java
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/Global.java
@@ -48,7 +48,6 @@
import javax.script.ScriptContext;
import javax.script.ScriptEngine;
import jdk.dynalink.CallSiteDescriptor;
-import jdk.dynalink.StandardOperation;
import jdk.dynalink.linker.GuardedInvocation;
import jdk.dynalink.linker.LinkRequest;
import jdk.nashorn.api.scripting.ClassFilter;
@@ -2449,17 +2448,17 @@
}
@Override
- public GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request, final StandardOperation operation) {
+ public GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request) {
final String name = NashornCallSiteDescriptor.getOperand(desc);
final boolean isScope = NashornCallSiteDescriptor.isScope(desc);
if (lexicalScope != null && isScope && !NashornCallSiteDescriptor.isApplyToCall(desc)) {
if (lexicalScope.hasOwnProperty(name)) {
- return lexicalScope.findGetMethod(desc, request, operation);
+ return lexicalScope.findGetMethod(desc, request);
}
}
- final GuardedInvocation invocation = super.findGetMethod(desc, request, operation);
+ final GuardedInvocation invocation = super.findGetMethod(desc, request);
// We want to avoid adding our generic lexical scope switchpoint to global constant invocations,
// because those are invalidated per-key in the addBoundProperties method above.
@@ -3061,8 +3060,8 @@
}
@Override
- protected GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request, final StandardOperation operation) {
- return filterInvocation(super.findGetMethod(desc, request, operation));
+ protected GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request) {
+ return filterInvocation(super.findGetMethod(desc, request));
}
@Override
diff --git a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeArray.java b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeArray.java
index b469cf7..357689a 100644
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeArray.java
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeArray.java
@@ -1726,7 +1726,7 @@
*/
@Function(attributes = Attribute.NOT_ENUMERABLE)
public static Object entries(final Object self) {
- return new ArrayIterator(Global.toObject(self), AbstractIterator.IterationKind.KEY_VALUE, Global.instance());
+ return ArrayIterator.newArrayKeyValueIterator(self);
}
/**
@@ -1737,7 +1737,7 @@
*/
@Function(attributes = Attribute.NOT_ENUMERABLE)
public static Object keys(final Object self) {
- return new ArrayIterator(Global.toObject(self), AbstractIterator.IterationKind.KEY, Global.instance());
+ return ArrayIterator.newArrayKeyIterator(self);
}
/**
@@ -1748,7 +1748,7 @@
*/
@Function(attributes = Attribute.NOT_ENUMERABLE)
public static Object values(final Object self) {
- return new ArrayIterator(Global.toObject(self), AbstractIterator.IterationKind.VALUE, Global.instance());
+ return ArrayIterator.newArrayValueIterator(self);
}
/**
@@ -1759,7 +1759,7 @@
*/
@Function(attributes = Attribute.NOT_ENUMERABLE, name = "@@iterator")
public static Object getIterator(final Object self) {
- return new ArrayIterator(Global.toObject(self), AbstractIterator.IterationKind.VALUE, Global.instance());
+ return ArrayIterator.newArrayValueIterator(self);
}
/**
diff --git a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeFloat32Array.java b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeFloat32Array.java
index 0f67ec4..bf5f68c 100644
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeFloat32Array.java
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeFloat32Array.java
@@ -232,6 +232,17 @@
return (NativeFloat32Array)ArrayBufferView.subarrayImpl(self, begin, end);
}
+ /**
+ * ECMA 6 22.2.3.30 %TypedArray%.prototype [ @@iterator ] ( )
+ *
+ * @param self the self reference
+ * @return an iterator over the array's values
+ */
+ @Function(attributes = Attribute.NOT_ENUMERABLE, name = "@@iterator")
+ public static Object getIterator(final Object self) {
+ return ArrayIterator.newArrayValueIterator(self);
+ }
+
@Override
protected ScriptObject getPrototype(final Global global) {
return global.getFloat32ArrayPrototype();
diff --git a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeFloat64Array.java b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeFloat64Array.java
index de3d0f0..0a46907 100644
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeFloat64Array.java
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeFloat64Array.java
@@ -232,6 +232,17 @@
return (NativeFloat64Array)ArrayBufferView.subarrayImpl(self, begin, end);
}
+ /**
+ * ECMA 6 22.2.3.30 %TypedArray%.prototype [ @@iterator ] ( )
+ *
+ * @param self the self reference
+ * @return an iterator over the array's values
+ */
+ @Function(attributes = Attribute.NOT_ENUMERABLE, name = "@@iterator")
+ public static Object getIterator(final Object self) {
+ return ArrayIterator.newArrayValueIterator(self);
+ }
+
@Override
protected ScriptObject getPrototype(final Global global) {
return global.getFloat64ArrayPrototype();
diff --git a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeInt16Array.java b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeInt16Array.java
index 735e6a3..4700e27 100644
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeInt16Array.java
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeInt16Array.java
@@ -225,6 +225,17 @@
return (NativeInt16Array)ArrayBufferView.subarrayImpl(self, begin, end);
}
+ /**
+ * ECMA 6 22.2.3.30 %TypedArray%.prototype [ @@iterator ] ( )
+ *
+ * @param self the self reference
+ * @return an iterator over the array's values
+ */
+ @Function(attributes = Attribute.NOT_ENUMERABLE, name = "@@iterator")
+ public static Object getIterator(final Object self) {
+ return ArrayIterator.newArrayValueIterator(self);
+ }
+
@Override
protected ScriptObject getPrototype(final Global global) {
return global.getInt16ArrayPrototype();
diff --git a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeInt32Array.java b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeInt32Array.java
index 7eacedc..4292985 100644
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeInt32Array.java
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeInt32Array.java
@@ -224,6 +224,17 @@
return (NativeInt32Array)ArrayBufferView.subarrayImpl(self, begin, end);
}
+ /**
+ * ECMA 6 22.2.3.30 %TypedArray%.prototype [ @@iterator ] ( )
+ *
+ * @param self the self reference
+ * @return an iterator over the array's values
+ */
+ @Function(attributes = Attribute.NOT_ENUMERABLE, name = "@@iterator")
+ public static Object getIterator(final Object self) {
+ return ArrayIterator.newArrayValueIterator(self);
+ }
+
@Override
protected ScriptObject getPrototype(final Global global) {
return global.getInt32ArrayPrototype();
diff --git a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeInt8Array.java b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeInt8Array.java
index 75fde20..13f0058 100644
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeInt8Array.java
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeInt8Array.java
@@ -224,6 +224,17 @@
return (NativeInt8Array)ArrayBufferView.subarrayImpl(self, begin, end);
}
+ /**
+ * ECMA 6 22.2.3.30 %TypedArray%.prototype [ @@iterator ] ( )
+ *
+ * @param self the self reference
+ * @return an iterator over the array's values
+ */
+ @Function(attributes = Attribute.NOT_ENUMERABLE, name = "@@iterator")
+ public static Object getIterator(final Object self) {
+ return ArrayIterator.newArrayValueIterator(self);
+ }
+
@Override
protected ScriptObject getPrototype(final Global global) {
return global.getInt8ArrayPrototype();
diff --git a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeJSAdapter.java b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeJSAdapter.java
index 39ff22f..ac90b8b 100644
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeJSAdapter.java
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeJSAdapter.java
@@ -37,7 +37,6 @@
import java.util.Iterator;
import java.util.List;
import jdk.dynalink.CallSiteDescriptor;
-import jdk.dynalink.StandardOperation;
import jdk.dynalink.linker.GuardedInvocation;
import jdk.dynalink.linker.LinkRequest;
import jdk.nashorn.internal.lookup.Lookup;
@@ -365,7 +364,7 @@
Object obj;
if (func instanceof ScriptFunction) {
- obj = ScriptRuntime.apply((ScriptFunction)func, adaptee);
+ obj = ScriptRuntime.apply((ScriptFunction)func, this);
} else {
obj = new NativeArray(0);
}
@@ -473,11 +472,11 @@
}
@Override
- protected GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request, final StandardOperation operation) {
+ protected GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request) {
final String name = NashornCallSiteDescriptor.getOperand(desc);
if (overrides && super.hasOwnProperty(name)) {
try {
- final GuardedInvocation inv = super.findGetMethod(desc, request, operation);
+ final GuardedInvocation inv = super.findGetMethod(desc, request);
if (inv != null) {
return inv;
}
@@ -486,11 +485,9 @@
}
}
- switch(operation) {
- case GET_PROPERTY:
- case GET_ELEMENT:
+ if (!NashornCallSiteDescriptor.isMethodFirstOperation(desc)) {
return findHook(desc, __get__);
- case GET_METHOD:
+ } else {
final FindProperty find = adaptee.findProperty(__call__, true);
if (find != null) {
final Object value = find.getObjectValue();
@@ -505,11 +502,7 @@
}
}
throw typeError("no.such.function", name, ScriptRuntime.safeToString(this));
- default:
- break;
}
-
- throw new AssertionError("should not reach here");
}
@Override
@@ -544,7 +537,7 @@
private Object callAdaptee(final Object retValue, final String name, final Object... args) {
final Object func = adaptee.get(name);
if (func instanceof ScriptFunction) {
- return ScriptRuntime.apply((ScriptFunction)func, adaptee, args);
+ return ScriptRuntime.apply((ScriptFunction)func, this, args);
}
return retValue;
}
diff --git a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeObject.java b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeObject.java
index de0cabf..72d144f 100644
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeObject.java
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeObject.java
@@ -25,6 +25,10 @@
package jdk.nashorn.internal.objects;
+import static jdk.dynalink.StandardNamespace.METHOD;
+import static jdk.dynalink.StandardNamespace.PROPERTY;
+import static jdk.dynalink.StandardOperation.GET;
+import static jdk.dynalink.StandardOperation.SET;
import static jdk.nashorn.internal.lookup.Lookup.MH;
import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
@@ -40,9 +44,7 @@
import java.util.Set;
import java.util.concurrent.Callable;
import jdk.dynalink.CallSiteDescriptor;
-import jdk.dynalink.NamedOperation;
import jdk.dynalink.Operation;
-import jdk.dynalink.StandardOperation;
import jdk.dynalink.beans.BeansLinker;
import jdk.dynalink.beans.StaticClass;
import jdk.dynalink.linker.GuardedInvocation;
@@ -97,6 +99,10 @@
});
}
+ private static final Operation GET_METHOD = GET.withNamespace(METHOD);
+ private static final Operation GET_PROPERTY = GET.withNamespace(PROPERTY);
+ private static final Operation SET_PROPERTY = SET.withNamespace(PROPERTY);
+
@SuppressWarnings("unused")
private static ScriptObject get__proto__(final Object self) {
// See ES6 draft spec: B.2.2.1.1 get Object.prototype.__proto__
@@ -782,7 +788,7 @@
for(final String methodName: methodNames) {
final MethodHandle method;
try {
- method = getBeanOperation(linker, StandardOperation.GET_METHOD, methodName, getterType, source);
+ method = getBeanOperation(linker, GET_METHOD, methodName, getterType, source);
} catch(final IllegalAccessError e) {
// Presumably, this was a caller sensitive method. Ignore it and carry on.
continue;
@@ -794,7 +800,7 @@
MethodHandle getter;
if(readablePropertyNames.contains(propertyName)) {
try {
- getter = getBeanOperation(linker, StandardOperation.GET_PROPERTY, propertyName, getterType, source);
+ getter = getBeanOperation(linker, GET_PROPERTY, propertyName, getterType, source);
} catch(final IllegalAccessError e) {
// Presumably, this was a caller sensitive method. Ignore it and carry on.
getter = Lookup.EMPTY_GETTER;
@@ -806,7 +812,7 @@
MethodHandle setter;
if(isWritable) {
try {
- setter = getBeanOperation(linker, StandardOperation.SET_PROPERTY, propertyName, setterType, source);
+ setter = getBeanOperation(linker, SET_PROPERTY, propertyName, setterType, source);
} catch(final IllegalAccessError e) {
// Presumably, this was a caller sensitive method. Ignore it and carry on.
setter = Lookup.EMPTY_SETTER;
@@ -836,11 +842,11 @@
}
}
- private static MethodHandle getBeanOperation(final GuardingDynamicLinker linker, final StandardOperation operation,
+ private static MethodHandle getBeanOperation(final GuardingDynamicLinker linker, final Operation operation,
final String name, final MethodType methodType, final Object source) {
final GuardedInvocation inv;
try {
- inv = NashornBeansLinker.getGuardedInvocation(linker, createLinkRequest(new NamedOperation(operation, name), methodType, source), Bootstrap.getLinkerServices());
+ inv = NashornBeansLinker.getGuardedInvocation(linker, createLinkRequest(operation.named(name), methodType, source), Bootstrap.getLinkerServices());
assert passesGuard(source, inv.getGuard());
} catch(RuntimeException|Error e) {
throw e;
diff --git a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeRegExp.java b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeRegExp.java
index 3bf1663..5dd1403 100644
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeRegExp.java
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeRegExp.java
@@ -701,13 +701,9 @@
}
thisIndex = matcher.end();
- if (thisIndex == string.length() && matcher.start() == matcher.end()) {
- // Avoid getting empty match at end of string twice
- break;
- }
- // ECMA 15.5.4.10 String.prototype.match(regexp)
- if (thisIndex == previousLastIndex) {
+ // ECMA6 21.2.5.6 step 8.g.iv.5: If matchStr is empty advance index by one
+ if (matcher.start() == matcher.end()) {
setLastIndex(thisIndex + 1);
previousLastIndex = thisIndex + 1;
} else {
diff --git a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeString.java b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeString.java
index ec1619e..d91ffa4 100644
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeString.java
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeString.java
@@ -42,7 +42,6 @@
import java.util.Locale;
import java.util.Set;
import jdk.dynalink.CallSiteDescriptor;
-import jdk.dynalink.StandardOperation;
import jdk.dynalink.linker.GuardedInvocation;
import jdk.dynalink.linker.LinkRequest;
import jdk.nashorn.internal.lookup.MethodHandleFactory.LookupException;
@@ -127,15 +126,15 @@
// This is to support length as method call as well.
@Override
- protected GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request, final StandardOperation operation) {
+ protected GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request) {
final String name = NashornCallSiteDescriptor.getOperand(desc);
// if str.length(), then let the bean linker handle it
- if ("length".equals(name) && operation == StandardOperation.GET_METHOD) {
+ if ("length".equals(name) && NashornCallSiteDescriptor.isMethodFirstOperation(desc)) {
return null;
}
- return super.findGetMethod(desc, request, operation);
+ return super.findGetMethod(desc, request);
}
// This is to provide array-like access to string characters without creating a NativeString wrapper.
diff --git a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeUint16Array.java b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeUint16Array.java
index fb3a667..0dfd275 100644
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeUint16Array.java
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeUint16Array.java
@@ -229,6 +229,17 @@
return (NativeUint16Array)ArrayBufferView.subarrayImpl(self, begin, end);
}
+ /**
+ * ECMA 6 22.2.3.30 %TypedArray%.prototype [ @@iterator ] ( )
+ *
+ * @param self the self reference
+ * @return an iterator over the array's values
+ */
+ @Function(attributes = Attribute.NOT_ENUMERABLE, name = "@@iterator")
+ public static Object getIterator(final Object self) {
+ return ArrayIterator.newArrayValueIterator(self);
+ }
+
@Override
protected ScriptObject getPrototype(final Global global) {
return global.getUint16ArrayPrototype();
diff --git a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeUint32Array.java b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeUint32Array.java
index 4d691b2..7b91eb2 100644
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeUint32Array.java
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeUint32Array.java
@@ -244,6 +244,17 @@
return (NativeUint32Array)ArrayBufferView.subarrayImpl(self, begin, end);
}
+ /**
+ * ECMA 6 22.2.3.30 %TypedArray%.prototype [ @@iterator ] ( )
+ *
+ * @param self the self reference
+ * @return an iterator over the array's values
+ */
+ @Function(attributes = Attribute.NOT_ENUMERABLE, name = "@@iterator")
+ public static Object getIterator(final Object self) {
+ return ArrayIterator.newArrayValueIterator(self);
+ }
+
@Override
protected ScriptObject getPrototype(final Global global) {
return global.getUint32ArrayPrototype();
diff --git a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeUint8Array.java b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeUint8Array.java
index 229099e..3b11a54 100644
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeUint8Array.java
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeUint8Array.java
@@ -230,6 +230,17 @@
return (NativeUint8Array)ArrayBufferView.subarrayImpl(self, begin, end);
}
+ /**
+ * ECMA 6 22.2.3.30 %TypedArray%.prototype [ @@iterator ] ( )
+ *
+ * @param self the self reference
+ * @return an iterator over the array's values
+ */
+ @Function(attributes = Attribute.NOT_ENUMERABLE, name = "@@iterator")
+ public static Object getIterator(final Object self) {
+ return ArrayIterator.newArrayValueIterator(self);
+ }
+
@Override
protected ScriptObject getPrototype(final Global global) {
return global.getUint8ArrayPrototype();
diff --git a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeUint8ClampedArray.java b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeUint8ClampedArray.java
index 905d99f..2edf2a7 100644
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeUint8ClampedArray.java
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeUint8ClampedArray.java
@@ -82,7 +82,6 @@
private static final MethodHandle SET_ELEM = specialCall(MethodHandles.lookup(), Uint8ClampedArrayData.class, "setElem", void.class, int.class, int.class).methodHandle();
private static final MethodHandle RINT_D = staticCall(MethodHandles.lookup(), Uint8ClampedArrayData.class, "rint", double.class, double.class).methodHandle();
private static final MethodHandle RINT_O = staticCall(MethodHandles.lookup(), Uint8ClampedArrayData.class, "rint", Object.class, Object.class).methodHandle();
- private static final MethodHandle CLAMP_LONG = staticCall(MethodHandles.lookup(), Uint8ClampedArrayData.class, "clampLong", long.class, long.class).methodHandle();
private Uint8ClampedArrayData(final ByteBuffer nb, final int start, final int end) {
super((nb.position(start).limit(end)).slice(), end - start);
@@ -124,8 +123,6 @@
return MH.filterArguments(setter, 2, RINT_O);
} else if (elementType == double.class) {
return MH.filterArguments(setter, 2, RINT_D);
- } else if (elementType == long.class) {
- return MH.filterArguments(setter, 2, CLAMP_LONG);
}
}
return setter;
@@ -195,7 +192,7 @@
@Override
public ArrayData set(final int index, final double value, final boolean strict) {
- return set(index, rint(value), strict);
+ return set(index, (int) rint(value), strict);
}
private static double rint(final double rint) {
@@ -207,15 +204,6 @@
return rint(JSType.toNumber(rint));
}
- @SuppressWarnings("unused")
- private static long clampLong(final long l) {
- if(l < 0L) {
- return 0L;
- } else if(l > 0xffL) {
- return 0xffL;
- }
- return l;
- }
}
/**
@@ -278,6 +266,17 @@
return (NativeUint8ClampedArray)ArrayBufferView.subarrayImpl(self, begin, end);
}
+ /**
+ * ECMA 6 22.2.3.30 %TypedArray%.prototype [ @@iterator ] ( )
+ *
+ * @param self the self reference
+ * @return an iterator over the array's values
+ */
+ @Function(attributes = Attribute.NOT_ENUMERABLE, name = "@@iterator")
+ public static Object getIterator(final Object self) {
+ return ArrayIterator.newArrayValueIterator(self);
+ }
+
@Override
protected ScriptObject getPrototype(final Global global) {
return global.getUint8ClampedArrayPrototype();
diff --git a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Lexer.java b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Lexer.java
index 3b43249..2451822 100644
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Lexer.java
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Lexer.java
@@ -102,19 +102,9 @@
private int templateExpressionOpenBraces;
- private static final String SPACETAB = " \t"; // ASCII space and tab
- private static final String LFCR = "\n\r"; // line feed and carriage return (ctrl-m)
-
- private static final String JAVASCRIPT_WHITESPACE_EOL =
- LFCR +
+ private static final String JAVASCRIPT_OTHER_WHITESPACE =
"\u2028" + // line separator
- "\u2029" // paragraph separator
- ;
- private static final String JAVASCRIPT_WHITESPACE =
- SPACETAB +
- JAVASCRIPT_WHITESPACE_EOL +
- "\u000b" + // tabulation line
- "\u000c" + // ff (ctrl-l)
+ "\u2029" + // paragraph separator
"\u00a0" + // Latin-1 space
"\u1680" + // Ogham space mark
"\u180e" + // separator, Mongolian vowel
@@ -384,7 +374,13 @@
* @return true if valid JavaScript whitespace
*/
public static boolean isJSWhitespace(final char ch) {
- return JAVASCRIPT_WHITESPACE.indexOf(ch) != -1;
+ return ch == ' ' // space
+ || ch >= '\t' && ch <= '\r' // 0x09..0x0d: tab, line feed, tabulation line, ff, carriage return
+ || ch >= 160 && isOtherJSWhitespace(ch);
+ }
+
+ private static boolean isOtherJSWhitespace(final char ch) {
+ return JAVASCRIPT_OTHER_WHITESPACE.indexOf(ch) != -1;
}
/**
@@ -393,7 +389,10 @@
* @return true if valid JavaScript end of line
*/
public static boolean isJSEOL(final char ch) {
- return JAVASCRIPT_WHITESPACE_EOL.indexOf(ch) != -1;
+ return ch == '\n' // line feed
+ || ch == '\r' // carriage return (ctrl-m)
+ || ch == '\u2028' // line separator
+ || ch == '\u2029'; // paragraph separator
}
/**
diff --git a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Parser.java b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Parser.java
index 5dfa469..fb4fd43 100644
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Parser.java
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Parser.java
@@ -1962,6 +1962,18 @@
switch (type) {
case SEMICOLON:
// for (init; test; modify)
+ if (varDeclList != null) {
+ assert init == null;
+ init = varDeclList.init;
+ // late check for missing assignment, now we know it's a for (init; test; modify) loop
+ if (varDeclList.missingAssignment != null) {
+ if (varDeclList.missingAssignment instanceof IdentNode) {
+ throw error(AbstractParser.message("missing.const.assignment", ((IdentNode)varDeclList.missingAssignment).getName()));
+ } else {
+ throw error(AbstractParser.message("missing.destructuring.assignment"), varDeclList.missingAssignment.getToken());
+ }
+ }
+ }
// for each (init; test; modify) is invalid
if ((flags & ForNode.IS_FOR_EACH) != 0) {
@@ -2607,13 +2619,23 @@
next();
expect(LPAREN);
- // FIXME: ES6 catch parameter can be a BindingIdentifier or a BindingPattern
- // We need to generalize this here!
+ // ES6 catch parameter can be a BindingIdentifier or a BindingPattern
// http://www.ecma-international.org/ecma-262/6.0/
- final IdentNode exception = getIdent();
+ final String contextString = "catch argument";
+ final Expression exception = bindingIdentifierOrPattern(contextString);
+ final boolean isDestructuring = !(exception instanceof IdentNode);
+ if (isDestructuring) {
+ verifyDestructuringBindingPattern(exception, new Consumer<IdentNode>() {
+ @Override
+ public void accept(final IdentNode identNode) {
+ verifyIdent(identNode, contextString);
+ }
+ });
+ } else {
+ // ECMA 12.4.1 strict mode restrictions
+ verifyStrictIdent((IdentNode) exception, "catch argument");
+ }
- // ECMA 12.4.1 strict mode restrictions
- verifyStrictIdent(exception, "catch argument");
// Nashorn extension: catch clause can have optional
// condition. So, a single try can have more than one
diff --git a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptObject.java b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptObject.java
index 71f7728..3a238dc 100644
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptObject.java
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptObject.java
@@ -67,7 +67,6 @@
import java.util.concurrent.atomic.LongAdder;
import jdk.dynalink.CallSiteDescriptor;
import jdk.dynalink.NamedOperation;
-import jdk.dynalink.StandardOperation;
import jdk.dynalink.linker.GuardedInvocation;
import jdk.dynalink.linker.LinkRequest;
import jdk.nashorn.internal.codegen.CompilerConstants.Call;
@@ -1858,23 +1857,16 @@
* @return GuardedInvocation for the callsite
*/
public GuardedInvocation lookup(final CallSiteDescriptor desc, final LinkRequest request) {
- // NOTE: we support GET_ELEMENT and SET_ELEMENT as JavaScript doesn't distinguish items from properties. Nashorn itself
- // emits "GET_PROPERTY|GET_ELEMENT|GET_METHOD:identifier" for "<expr>.<identifier>" and "GET_ELEMENT|GET_PROPERTY|GET_METHOD" for "<expr>[<expr>]", but we are
+ // NOTE: we support GET:ELEMENT and SET:ELEMENT as JavaScript doesn't distinguish items from properties. Nashorn itself
+ // emits "GET:PROPERTY|ELEMENT|METHOD:identifier" for "<expr>.<identifier>" and "GET:ELEMENT|PROPERTY|METHOD" for "<expr>[<expr>]", but we are
// more flexible here and dispatch not on operation name (getProp vs. getElem), but rather on whether the
// operation has an associated name or not.
- final StandardOperation op = NashornCallSiteDescriptor.getFirstStandardOperation(desc);
- if (op == null) {
- return null;
- }
- switch (op) {
- case GET_PROPERTY:
- case GET_ELEMENT:
- case GET_METHOD:
+ switch (NashornCallSiteDescriptor.getStandardOperation(desc)) {
+ case GET:
return desc.getOperation() instanceof NamedOperation
- ? findGetMethod(desc, request, op)
+ ? findGetMethod(desc, request)
: findGetIndexMethod(desc, request);
- case SET_PROPERTY:
- case SET_ELEMENT:
+ case SET:
return desc.getOperation() instanceof NamedOperation
? findSetMethod(desc, request)
: findSetIndexMethod(desc, request);
@@ -1883,8 +1875,8 @@
case NEW:
return findNewMethod(desc, request);
default:
+ return null;
}
- return null;
}
/**
@@ -1952,11 +1944,10 @@
*
* @param desc the call site descriptor
* @param request the link request
- * @param operation operation for get: getProp, getMethod, getElem etc
*
* @return GuardedInvocation to be invoked at call site.
*/
- protected GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request, final StandardOperation operation) {
+ protected GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request) {
final boolean explicitInstanceOfCheck = explicitInstanceOfCheck(desc, request);
String name = NashornCallSiteDescriptor.getOperand(desc);
@@ -1967,21 +1958,17 @@
}
if (request.isCallSiteUnstable() || hasWithScope()) {
- return findMegaMorphicGetMethod(desc, name, operation == StandardOperation.GET_METHOD);
+ return findMegaMorphicGetMethod(desc, name, NashornCallSiteDescriptor.isMethodFirstOperation(desc));
}
final FindProperty find = findProperty(name, true, NashornCallSiteDescriptor.isScope(desc), this);
MethodHandle mh;
if (find == null) {
- switch (operation) {
- case GET_ELEMENT: // getElem only gets here if element name is constant, so treat it like a property access
- case GET_PROPERTY:
+ if (!NashornCallSiteDescriptor.isMethodFirstOperation(desc)) {
return noSuchProperty(desc, request);
- case GET_METHOD:
+ } else {
return noSuchMethod(desc, request);
- default:
- throw new AssertionError(operation); // never invoked with any other operation
}
}
diff --git a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Undefined.java b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Undefined.java
index ac1aca5..48a9f92 100644
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Undefined.java
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Undefined.java
@@ -32,7 +32,6 @@
import java.lang.invoke.MethodHandles;
import jdk.dynalink.CallSiteDescriptor;
import jdk.dynalink.NamedOperation;
-import jdk.dynalink.StandardOperation;
import jdk.dynalink.linker.GuardedInvocation;
import jdk.dynalink.linker.support.Guards;
import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
@@ -93,29 +92,22 @@
* @return GuardedInvocation to be invoked at call site.
*/
public static GuardedInvocation lookup(final CallSiteDescriptor desc) {
- final StandardOperation op = NashornCallSiteDescriptor.getFirstStandardOperation(desc);
- if (op == null) {
- return null;
- }
- switch (op) {
+ switch (NashornCallSiteDescriptor.getStandardOperation(desc)) {
case CALL:
case NEW:
final String name = NashornCallSiteDescriptor.getOperand(desc);
final String msg = name != null? "not.a.function" : "cant.call.undefined";
throw typeError(msg, name);
- case GET_PROPERTY:
- case GET_ELEMENT:
- case GET_METHOD:
- // NOTE: we support GET_ELEMENT and SET_ELEMENT as JavaScript doesn't distinguish items from properties. Nashorn itself
- // emits "GET_PROPERTY|GET_ELEMENT|GET_METHOD:identifier" for "<expr>.<identifier>" and "GET_ELEMENT|GET_PROPERTY|GET_METHOD" for "<expr>[<expr>]", but we are
+ case GET:
+ // NOTE: we support GET:ELEMENT and SET:ELEMENT as JavaScript doesn't distinguish items from properties. Nashorn itself
+ // emits "GET:PROPERTY|ELEMENT|METHOD:identifier" for "<expr>.<identifier>" and "GET:ELEMENT|PROPERTY|METHOD" for "<expr>[<expr>]", but we are
// more flexible here and dispatch not on operation name (getProp vs. getElem), but rather on whether the
// operation has an associated name or not.
if (!(desc.getOperation() instanceof NamedOperation)) {
return findGetIndexMethod(desc);
}
return findGetMethod(desc);
- case SET_PROPERTY:
- case SET_ELEMENT:
+ case SET:
if (!(desc.getOperation() instanceof NamedOperation)) {
return findSetIndexMethod(desc);
}
diff --git a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/WithObject.java b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/WithObject.java
index 8caa260..f58fc7d 100644
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/WithObject.java
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/WithObject.java
@@ -97,9 +97,6 @@
return super.lookup(desc, request);
}
- // With scopes can never be observed outside of Nashorn code, so all call sites that can address it will of
- // necessity have a Nashorn descriptor - it is safe to cast.
- final NashornCallSiteDescriptor ndesc = (NashornCallSiteDescriptor)desc;
GuardedInvocation link = null;
final Operation op = desc.getOperation();
@@ -111,7 +108,7 @@
if (find != null) {
link = expression.lookup(desc, request);
if (link != null) {
- return fixExpressionCallSite(ndesc, link);
+ return fixExpressionCallSite(desc, link);
}
}
@@ -126,39 +123,30 @@
// __noSuchProperty__ and __noSuchMethod__ in expression
final String fallBack;
- final StandardOperation firstOp = ndesc.getFirstOperation();
- switch (firstOp) {
- case GET_METHOD:
- fallBack = NO_SUCH_METHOD_NAME;
- break;
- case GET_PROPERTY:
- case GET_ELEMENT:
- fallBack = NO_SUCH_PROPERTY_NAME;
- break;
- default:
+ final Operation firstOp = NashornCallSiteDescriptor.getBaseOperation(desc);
+ if (firstOp == StandardOperation.GET) {
+ if (NashornCallSiteDescriptor.isMethodFirstOperation(desc)) {
+ fallBack = NO_SUCH_METHOD_NAME;
+ } else {
+ fallBack = NO_SUCH_PROPERTY_NAME;
+ }
+ } else {
fallBack = null;
- break;
}
if (fallBack != null) {
find = expression.findProperty(fallBack, true);
if (find != null) {
- switch (firstOp) {
- case GET_METHOD:
+ if (NO_SUCH_METHOD_NAME.equals(fallBack)) {
link = expression.noSuchMethod(desc, request);
- break;
- case GET_PROPERTY:
- case GET_ELEMENT:
+ } else if (NO_SUCH_PROPERTY_NAME.equals(fallBack)) {
link = expression.noSuchProperty(desc, request);
- break;
- default:
- break;
}
}
}
if (link != null) {
- return fixExpressionCallSite(ndesc, link);
+ return fixExpressionCallSite(desc, link);
}
// still not found, may be scope can handle with it's own
@@ -245,10 +233,10 @@
return link.asType(newInvType);
}
- private static GuardedInvocation fixExpressionCallSite(final NashornCallSiteDescriptor desc, final GuardedInvocation link) {
+ private static GuardedInvocation fixExpressionCallSite(final CallSiteDescriptor desc, final GuardedInvocation link) {
// If it's not a getMethod, just add an expression filter that converts WithObject in "this" position to its
// expression.
- if (desc.getFirstOperation() != StandardOperation.GET_METHOD) {
+ if (NashornCallSiteDescriptor.getBaseOperation(desc) != StandardOperation.GET || !NashornCallSiteDescriptor.isMethodFirstOperation(desc)) {
return fixReceiverType(link, WITHEXPRESSIONFILTER).filterArguments(0, WITHEXPRESSIONFILTER);
}
diff --git a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/BrowserJSObjectLinker.java b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/BrowserJSObjectLinker.java
index 621f789..3578ed8 100644
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/BrowserJSObjectLinker.java
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/BrowserJSObjectLinker.java
@@ -35,7 +35,6 @@
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import jdk.dynalink.CallSiteDescriptor;
-import jdk.dynalink.StandardOperation;
import jdk.dynalink.linker.GuardedInvocation;
import jdk.dynalink.linker.LinkRequest;
import jdk.dynalink.linker.LinkerServices;
@@ -91,24 +90,17 @@
inv = null;
}
- final StandardOperation op = NashornCallSiteDescriptor.getFirstStandardOperation(desc);
- if (op == null) {
- return inv;
- }
final String name = NashornCallSiteDescriptor.getOperand(desc);
- switch (op) {
- case GET_PROPERTY:
- case GET_ELEMENT:
- case GET_METHOD:
+ switch (NashornCallSiteDescriptor.getStandardOperation(desc)) {
+ case GET:
return name != null ? findGetMethod(name, inv) : findGetIndexMethod(inv);
- case SET_PROPERTY:
- case SET_ELEMENT:
+ case SET:
return name != null ? findSetMethod(name, inv) : findSetIndexMethod();
case CALL:
return findCallMethod(desc);
default:
+ return null;
}
- return null;
}
private static GuardedInvocation findGetMethod(final String name, final GuardedInvocation inv) {
diff --git a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java
index 7471cc4..af6de32 100644
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java
@@ -33,6 +33,7 @@
import java.util.Map;
import javax.script.Bindings;
import jdk.dynalink.CallSiteDescriptor;
+import jdk.dynalink.Operation;
import jdk.dynalink.StandardOperation;
import jdk.dynalink.linker.GuardedInvocation;
import jdk.dynalink.linker.LinkRequest;
@@ -92,29 +93,31 @@
}
private GuardedInvocation lookup(final CallSiteDescriptor desc, final LinkRequest request, final LinkerServices linkerServices) throws Exception {
- final StandardOperation op = NashornCallSiteDescriptor.getFirstStandardOperation(desc);
- if (op == null) {
- return null;
- }
- final String name = NashornCallSiteDescriptor.getOperand(desc);
- switch (op) {
- case GET_PROPERTY:
- case GET_ELEMENT:
- case GET_METHOD:
- if (name != null) {
- return findGetMethod(name);
+ final Operation op = NashornCallSiteDescriptor.getBaseOperation(desc);
+ if (op instanceof StandardOperation) {
+ final String name = NashornCallSiteDescriptor.getOperand(desc);
+ switch ((StandardOperation)op) {
+ case GET:
+ if (NashornCallSiteDescriptor.hasStandardNamespace(desc)) {
+ if (name != null) {
+ return findGetMethod(name);
+ }
+ // For indexed get, we want get GuardedInvocation beans linker and pass it.
+ // JSObjectLinker.get uses this fallback getter for explicit signature method access.
+ return findGetIndexMethod(nashornBeansLinker.getGuardedInvocation(request, linkerServices));
+ }
+ break;
+ case SET:
+ if (NashornCallSiteDescriptor.hasStandardNamespace(desc)) {
+ return name != null ? findSetMethod(name) : findSetIndexMethod();
+ }
+ break;
+ case CALL:
+ return findCallMethod(desc);
+ case NEW:
+ return findNewMethod(desc);
+ default:
}
- // For indexed get, we want get GuardedInvocation beans linker and pass it.
- // JSObjectLinker.get uses this fallback getter for explicit signature method access.
- return findGetIndexMethod(nashornBeansLinker.getGuardedInvocation(request, linkerServices));
- case SET_PROPERTY:
- case SET_ELEMENT:
- return name != null ? findSetMethod(name) : findSetIndexMethod();
- case CALL:
- return findCallMethod(desc);
- case NEW:
- return findNewMethod(desc);
- default:
}
return null;
}
diff --git a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/JavaSuperAdapterLinker.java b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/JavaSuperAdapterLinker.java
index 6629b1a..8d525a7 100644
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/JavaSuperAdapterLinker.java
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/JavaSuperAdapterLinker.java
@@ -25,15 +25,15 @@
package jdk.nashorn.internal.runtime.linker;
+import static jdk.dynalink.StandardNamespace.METHOD;
+import static jdk.dynalink.StandardOperation.GET;
import static jdk.nashorn.internal.runtime.linker.JavaAdapterBytecodeGenerator.SUPER_PREFIX;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import jdk.dynalink.CallSiteDescriptor;
-import jdk.dynalink.NamedOperation;
import jdk.dynalink.Operation;
-import jdk.dynalink.StandardOperation;
import jdk.dynalink.beans.BeansLinker;
import jdk.dynalink.linker.GuardedInvocation;
import jdk.dynalink.linker.LinkRequest;
@@ -61,6 +61,8 @@
IS_ADAPTER_OF_CLASS = lookup.findOwnStatic("isAdapterOfClass", boolean.class, Class.class, Object.class);
}
+ private static final Operation GET_METHOD = GET.withNamespace(METHOD);
+
private final BeansLinker beansLinker;
JavaSuperAdapterLinker(final BeansLinker beansLinker) {
@@ -82,8 +84,8 @@
final CallSiteDescriptor descriptor = linkRequest.getCallSiteDescriptor();
- if(!NashornCallSiteDescriptor.contains(descriptor, StandardOperation.GET_METHOD)) {
- // We only handle GET_METHOD
+ if(!NashornCallSiteDescriptor.contains(descriptor, GET, METHOD)) {
+ // We only handle GET:METHOD
return null;
}
@@ -97,8 +99,7 @@
final MethodType type = descriptor.getMethodType();
final Class<?> adapterClass = adapter.getClass();
final String name = NashornCallSiteDescriptor.getOperand(descriptor);
- final Operation newOp = name == null ? StandardOperation.GET_METHOD :
- new NamedOperation(StandardOperation.GET_METHOD, SUPER_PREFIX + name);
+ final Operation newOp = name == null ? GET_METHOD : GET_METHOD.named(SUPER_PREFIX + name);
final CallSiteDescriptor newDescriptor = new CallSiteDescriptor(
NashornCallSiteDescriptor.getLookupInternal(descriptor), newOp,
diff --git a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornBeansLinker.java b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornBeansLinker.java
index d2a46ea..ac2f7cb 100644
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornBeansLinker.java
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornBeansLinker.java
@@ -35,7 +35,9 @@
import java.util.function.Supplier;
import jdk.dynalink.CallSiteDescriptor;
import jdk.dynalink.NamedOperation;
+import jdk.dynalink.Operation;
import jdk.dynalink.SecureLookupSupplier;
+import jdk.dynalink.StandardNamespace;
import jdk.dynalink.StandardOperation;
import jdk.dynalink.beans.BeansLinker;
import jdk.dynalink.linker.ConversionComparator.Comparison;
@@ -46,6 +48,7 @@
import jdk.dynalink.linker.MethodHandleTransformer;
import jdk.dynalink.linker.support.DefaultInternalObjectFilter;
import jdk.dynalink.linker.support.Lookup;
+import jdk.dynalink.linker.support.SimpleLinkRequest;
import jdk.nashorn.api.scripting.ScriptUtils;
import jdk.nashorn.internal.runtime.ConsString;
import jdk.nashorn.internal.runtime.Context;
@@ -68,6 +71,9 @@
// Object type arguments of Java method calls, field set and array set.
private static final boolean MIRROR_ALWAYS = Options.getBooleanProperty("nashorn.mirror.always", true);
+ private static final Operation GET_METHOD = StandardOperation.GET.withNamespace(StandardNamespace.METHOD);
+ private static final MethodType GET_METHOD_TYPE = MethodType.methodType(Object.class, Object.class);
+
private static final MethodHandle EXPORT_ARGUMENT;
private static final MethodHandle IMPORT_RESULT;
private static final MethodHandle FILTER_CONSSTRING;
@@ -114,20 +120,38 @@
// those are script functions.
final String name = getFunctionalInterfaceMethodName(self.getClass());
if (name != null) {
- final MethodType callType = desc.getMethodType();
- // drop callee (Undefined ScriptFunction) and change the request to be CALL_METHOD:<name>
- final CallSiteDescriptor newDesc = new CallSiteDescriptor(
+ // Obtain the method
+ final CallSiteDescriptor getMethodDesc = new CallSiteDescriptor(
NashornCallSiteDescriptor.getLookupInternal(desc),
- new NamedOperation(StandardOperation.CALL_METHOD, name),
- desc.getMethodType().dropParameterTypes(1, 2));
- final GuardedInvocation gi = getGuardedInvocation(beansLinker,
- linkRequest.replaceArguments(newDesc, linkRequest.getArguments()),
+ GET_METHOD.named(name), GET_METHOD_TYPE);
+ final GuardedInvocation getMethodInv = linkerServices.getGuardedInvocation(
+ new SimpleLinkRequest(getMethodDesc, false, self));
+ final Object method;
+ try {
+ method = getMethodInv.getInvocation().invokeExact(self);
+ } catch (final Exception|Error e) {
+ throw e;
+ } catch (final Throwable t) {
+ throw new RuntimeException(t);
+ }
+
+ final Object[] args = linkRequest.getArguments();
+ args[1] = args[0]; // callee (the functional object) becomes this
+ args[0] = method; // the method becomes the callee
+
+ final MethodType callType = desc.getMethodType();
+
+ final CallSiteDescriptor newDesc = desc.changeMethodType(
+ desc.getMethodType().changeParameterType(0, Object.class).changeParameterType(1, callType.parameterType(0)));
+ final GuardedInvocation gi = getGuardedInvocation(beansLinker, linkRequest.replaceArguments(newDesc, args),
new NashornBeansLinkerServices(linkerServices));
- // drop 'thiz' passed from the script.
- return gi.replaceMethods(
- MH.dropArguments(linkerServices.filterInternalObjects(gi.getInvocation()), 1, callType.parameterType(1)),
- gi.getGuard());
+ // Bind to the method, drop the original "this" and use original "callee" as this:
+ final MethodHandle inv = linkerServices.filterInternalObjects(gi
+ .getInvocation() // (method, this, args...)
+ .bindTo(method)); // (this, args...)
+ final MethodHandle calleeToThis = MH.dropArguments(inv, 1, callType.parameterType(1)); // (callee->this, <drop>, args...)
+ return gi.replaceMethods(calleeToThis, gi.getGuard());
}
}
return getGuardedInvocation(beansLinker, linkRequest, linkerServices);
diff --git a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornBottomLinker.java b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornBottomLinker.java
index d977129..bd4ab24 100644
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornBottomLinker.java
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornBottomLinker.java
@@ -38,7 +38,6 @@
import jdk.dynalink.CallSiteDescriptor;
import jdk.dynalink.NamedOperation;
import jdk.dynalink.Operation;
-import jdk.dynalink.StandardOperation;
import jdk.dynalink.beans.BeansLinker;
import jdk.dynalink.linker.GuardedInvocation;
import jdk.dynalink.linker.GuardingDynamicLinker;
@@ -98,7 +97,7 @@
private static GuardedInvocation linkBean(final LinkRequest linkRequest) throws Exception {
final CallSiteDescriptor desc = linkRequest.getCallSiteDescriptor();
final Object self = linkRequest.getReceiver();
- switch (NashornCallSiteDescriptor.getFirstStandardOperation(desc)) {
+ switch (NashornCallSiteDescriptor.getStandardOperation(desc)) {
case NEW:
if(BeansLinker.isDynamicConstructor(self)) {
throw typeError("no.constructor.matches.args", ScriptRuntime.safeToString(self));
@@ -124,35 +123,26 @@
static MethodHandle linkMissingBeanMember(final LinkRequest linkRequest, final LinkerServices linkerServices) throws Exception {
final CallSiteDescriptor desc = linkRequest.getCallSiteDescriptor();
- final StandardOperation op = NashornCallSiteDescriptor.getFirstStandardOperation(desc);
- if (op != null) {
- final String operand = NashornCallSiteDescriptor.getOperand(desc);
- switch (op) {
- case GET_METHOD:
- case GET_PROPERTY:
- case GET_ELEMENT: {
- if (NashornCallSiteDescriptor.isOptimistic(desc)) {
- return adaptThrower(MethodHandles.insertArguments(THROW_OPTIMISTIC_UNDEFINED, 0, NashornCallSiteDescriptor.getProgramPoint(desc)), desc);
- }
- if (NashornCallSiteDescriptor.getOperand(desc) != null) {
- return getInvocation(EMPTY_PROP_GETTER, linkerServices, desc);
- }
- return getInvocation(EMPTY_ELEM_GETTER, linkerServices, desc);
+ final String operand = NashornCallSiteDescriptor.getOperand(desc);
+ switch (NashornCallSiteDescriptor.getStandardOperation(desc)) {
+ case GET:
+ if (NashornCallSiteDescriptor.isOptimistic(desc)) {
+ return adaptThrower(MethodHandles.insertArguments(THROW_OPTIMISTIC_UNDEFINED, 0, NashornCallSiteDescriptor.getProgramPoint(desc)), desc);
+ } else if (operand != null) {
+ return getInvocation(EMPTY_PROP_GETTER, linkerServices, desc);
}
- case SET_PROPERTY:
- case SET_ELEMENT:
- final boolean strict = NashornCallSiteDescriptor.isStrict(desc);
- if (strict) {
- return adaptThrower(bindOperand(THROW_STRICT_PROPERTY_SETTER, operand), desc);
- }
- if (NashornCallSiteDescriptor.getOperand(desc) != null) {
- return getInvocation(EMPTY_PROP_SETTER, linkerServices, desc);
- }
- return getInvocation(EMPTY_ELEM_SETTER, linkerServices, desc);
- default:
+ return getInvocation(EMPTY_ELEM_GETTER, linkerServices, desc);
+ case SET:
+ final boolean strict = NashornCallSiteDescriptor.isStrict(desc);
+ if (strict) {
+ return adaptThrower(bindOperand(THROW_STRICT_PROPERTY_SETTER, operand), desc);
+ } else if (operand != null) {
+ return getInvocation(EMPTY_PROP_SETTER, linkerServices, desc);
}
+ return getInvocation(EMPTY_ELEM_SETTER, linkerServices, desc);
+ default:
+ throw new AssertionError("unknown call type " + desc);
}
- throw new AssertionError("unknown call type " + desc);
}
private static MethodHandle bindOperand(final MethodHandle handle, final String operand) {
@@ -217,17 +207,13 @@
private static GuardedInvocation linkNull(final LinkRequest linkRequest) {
final CallSiteDescriptor desc = linkRequest.getCallSiteDescriptor();
- switch (NashornCallSiteDescriptor.getFirstStandardOperation(desc)) {
+ switch (NashornCallSiteDescriptor.getStandardOperation(desc)) {
case NEW:
case CALL:
throw typeError("not.a.function", "null");
- case GET_METHOD:
- throw typeError("no.such.function", getArgument(linkRequest), "null");
- case GET_PROPERTY:
- case GET_ELEMENT:
- throw typeError("cant.get.property", getArgument(linkRequest), "null");
- case SET_PROPERTY:
- case SET_ELEMENT:
+ case GET:
+ throw typeError(NashornCallSiteDescriptor.isMethodFirstOperation(desc) ? "no.such.function" : "cant.get.property", getArgument(linkRequest), "null");
+ case SET:
throw typeError("cant.set.property", getArgument(linkRequest), "null");
default:
throw new AssertionError("unknown call type " + desc);
diff --git a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornCallSiteDescriptor.java b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornCallSiteDescriptor.java
index 25999d1..71f9f47 100644
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornCallSiteDescriptor.java
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornCallSiteDescriptor.java
@@ -25,6 +25,12 @@
package jdk.nashorn.internal.runtime.linker;
+import static jdk.dynalink.StandardNamespace.ELEMENT;
+import static jdk.dynalink.StandardNamespace.METHOD;
+import static jdk.dynalink.StandardNamespace.PROPERTY;
+import static jdk.dynalink.StandardOperation.GET;
+import static jdk.dynalink.StandardOperation.SET;
+
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodHandles.Lookup;
import java.lang.invoke.MethodType;
@@ -40,10 +46,11 @@
import java.util.concurrent.ConcurrentMap;
import java.util.stream.Stream;
import jdk.dynalink.CallSiteDescriptor;
-import jdk.dynalink.CompositeOperation;
import jdk.dynalink.NamedOperation;
+import jdk.dynalink.NamespaceOperation;
import jdk.dynalink.Operation;
import jdk.dynalink.SecureLookupSupplier;
+import jdk.dynalink.StandardNamespace;
import jdk.dynalink.StandardOperation;
import jdk.nashorn.internal.ir.debug.NashornTextifier;
import jdk.nashorn.internal.runtime.AccessControlContextFactory;
@@ -78,12 +85,12 @@
// Correspond to the operation indices above.
private static final Operation[] OPERATIONS = new Operation[] {
- new CompositeOperation(StandardOperation.GET_PROPERTY, StandardOperation.GET_ELEMENT, StandardOperation.GET_METHOD),
- new CompositeOperation(StandardOperation.GET_ELEMENT, StandardOperation.GET_PROPERTY, StandardOperation.GET_METHOD),
- new CompositeOperation(StandardOperation.GET_METHOD, StandardOperation.GET_PROPERTY, StandardOperation.GET_ELEMENT),
- new CompositeOperation(StandardOperation.GET_METHOD, StandardOperation.GET_ELEMENT, StandardOperation.GET_PROPERTY),
- new CompositeOperation(StandardOperation.SET_PROPERTY, StandardOperation.SET_ELEMENT),
- new CompositeOperation(StandardOperation.SET_ELEMENT, StandardOperation.SET_PROPERTY),
+ GET.withNamespaces(PROPERTY, ELEMENT, METHOD),
+ GET.withNamespaces(ELEMENT, PROPERTY, METHOD),
+ GET.withNamespaces(METHOD, PROPERTY, ELEMENT),
+ GET.withNamespaces(METHOD, ELEMENT, PROPERTY),
+ SET.withNamespaces(PROPERTY, ELEMENT),
+ SET.withNamespaces(ELEMENT, PROPERTY),
StandardOperation.CALL,
StandardOperation.NEW
};
@@ -248,7 +255,7 @@
return existing;
}
}
- final NamedOperation newOp = new NamedOperation(baseOp, name);
+ final NamedOperation newOp = baseOp.named(name);
namedOps.put(name, new WeakReference<>(newOp));
return newOp;
}
@@ -288,16 +295,6 @@
}
/**
- * Returns the named operand in this descriptor's operation. Equivalent to
- * {@code ((NamedOperation)getOperation()).getName().toString()} for call
- * sites with a named operand. For call sites without named operands returns null.
- * @return the named operand in this descriptor's operation.
- */
- public String getOperand() {
- return getOperand(this);
- }
-
- /**
* Returns the named operand in the passed descriptor's operation.
* Equivalent to
* {@code ((NamedOperation)desc.getOperation()).getName().toString()} for
@@ -311,70 +308,63 @@
return operation instanceof NamedOperation ? ((NamedOperation)operation).getName().toString() : null;
}
- /**
- * Returns the first operation in this call site descriptor's potentially
- * composite operation. E.g. if this call site descriptor has a composite
- * operation {@code GET_PROPERTY|GET_METHOD|GET_ELEM}, it will return
- * {@code GET_PROPERTY}. Nashorn - being a ECMAScript engine - does not
- * distinguish between property, element, and method namespace; ECMAScript
- * objects just have one single property namespace for all these, therefore
- * it is largely irrelevant what the composite operation is structured like;
- * if the first operation can't be satisfied, neither can the others. The
- * first operation is however sometimes used to slightly alter the
- * semantics; for example, a distinction between {@code GET_PROPERTY} and
- * {@code GET_METHOD} being the first operation can translate into whether
- * {@code "__noSuchProperty__"} or {@code "__noSuchMethod__"} will be
- * executed in case the property is not found. Note that if a call site
- * descriptor comes from outside of Nashorn, its class will be different,
- * and there is no guarantee about the way it composes its operations. For
- * that reason, for potentially foreign call site descriptors you should use
- * {@link #getFirstStandardOperation(CallSiteDescriptor)} instead.
- * @return the first operation in this call site descriptor. Note this will
- * always be a {@code StandardOperation} as Nashorn internally only uses
- * standard operations.
- */
- public StandardOperation getFirstOperation() {
- final Operation base = NamedOperation.getBaseOperation(getOperation());
- if (base instanceof CompositeOperation) {
- return (StandardOperation)((CompositeOperation)base).getOperation(0);
- }
- return (StandardOperation)base;
+ private static StandardNamespace findFirstStandardNamespace(final CallSiteDescriptor desc) {
+ return StandardNamespace.findFirst(desc.getOperation());
}
/**
- * Returns the first standard operation in the (potentially composite)
- * operation of the passed call site descriptor.
+ * Returns true if the operation of the call descriptor is operating on the method namespace first.
+ * @param desc the call descriptor in question.
+ * @return true if the operation of the call descriptor is operating on the method namespace first.
+ */
+ public static boolean isMethodFirstOperation(final CallSiteDescriptor desc) {
+ return findFirstStandardNamespace(desc) == StandardNamespace.METHOD;
+ }
+
+ /**
+ * Returns true if there's a namespace operation in the call descriptor and it is operating on at least
+ * one {@link StandardNamespace}. This method is only needed for exported linkers, since internal linkers
+ * always operate on Nashorn-generated call sites, and they always operate on standard namespaces only.
+ * @param desc the call descriptor in question.
+ * @return true if the operation of the call descriptor is operating on at least one standard namespace.
+ */
+ public static boolean hasStandardNamespace(final CallSiteDescriptor desc) {
+ return findFirstStandardNamespace(desc) != null;
+ }
+
+ /**
+ * Returns the base operation in this call site descriptor after unwrapping it from both a named operation
+ * and a namespace operation.
* @param desc the call site descriptor.
- * @return Returns the first standard operation in the (potentially
- * composite) operation of the passed call site descriptor. Can return null
- * if the call site contains no standard operations.
+ * @return the base operation in this call site descriptor.
*/
- public static StandardOperation getFirstStandardOperation(final CallSiteDescriptor desc) {
- final Operation base = NamedOperation.getBaseOperation(desc.getOperation());
- if (base instanceof StandardOperation) {
- return (StandardOperation)base;
- } else if (base instanceof CompositeOperation) {
- final CompositeOperation cop = (CompositeOperation)base;
- for(int i = 0; i < cop.getOperationCount(); ++i) {
- final Operation op = cop.getOperation(i);
- if (op instanceof StandardOperation) {
- return (StandardOperation)op;
- }
- }
- }
- return null;
+ public static Operation getBaseOperation(final CallSiteDescriptor desc) {
+ return NamespaceOperation.getBaseOperation(NamedOperation.getBaseOperation(desc.getOperation()));
}
/**
- * Returns true if the passed call site descriptor's operation contains (or
- * is) the specified standard operation.
+ * Returns the standard operation that is the base operation in this call site descriptor.
+ * @param desc the call site descriptor.
+ * @return the standard operation that is the base operation in this call site descriptor.
+ * @throws ClassCastException if the base operation is not a standard operation. This method is only
+ * safe to use when the base operation is known to be a standard operation (e.g. all Nashorn call sites
+ * are such, so it's safe to use from internal linkers).
+ */
+ public static StandardOperation getStandardOperation(final CallSiteDescriptor desc) {
+ return (StandardOperation)getBaseOperation(desc);
+ }
+
+ /**
+ * Returns true if the passed call site descriptor contains the specified standard operation on the
+ * specified standard namespace.
* @param desc the call site descriptor.
* @param operation the operation whose presence is tested.
- * @return Returns true if the call site descriptor's operation contains (or
- * is) the specified standard operation.
+ * @param namespace the namespace on which the operation operates.
+ * @return Returns true if the call site descriptor contains the specified standard operation on the
+ * specified standard namespace.
*/
- public static boolean contains(final CallSiteDescriptor desc, final StandardOperation operation) {
- return CompositeOperation.contains(NamedOperation.getBaseOperation(desc.getOperation()), operation);
+ public static boolean contains(final CallSiteDescriptor desc, final StandardOperation operation, final StandardNamespace namespace) {
+ return NamespaceOperation.contains(NamedOperation.getBaseOperation(desc.getOperation()), operation, namespace);
}
/**
@@ -383,8 +373,8 @@
* @param obj object on which CALL or NEW is used
* @return error message
*/
- public String getFunctionErrorMessage(final Object obj) {
- final String funcDesc = getOperand();
+ private String getFunctionErrorMessage(final Object obj) {
+ final String funcDesc = getOperand(this);
return funcDesc != null? funcDesc : ScriptRuntime.safeToString(obj);
}
@@ -552,4 +542,9 @@
public CallSiteDescriptor changeMethodTypeInternal(final MethodType newMethodType) {
return get(getLookupPrivileged(), getOperation(), newMethodType, flags);
}
+
+ @Override
+ protected CallSiteDescriptor changeOperationInternal(final Operation newOperation) {
+ return get(getLookupPrivileged(), newOperation, getMethodType(), flags);
+ }
}
diff --git a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java
index 4a7c8d7..5a321d0 100644
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java
@@ -99,10 +99,8 @@
final String name = NashornCallSiteDescriptor.getOperand(desc);
final FindProperty find = name != null ? wrappedReceiver.findProperty(name, true) : null;
- switch (NashornCallSiteDescriptor.getFirstStandardOperation(desc)) {
- case GET_PROPERTY:
- case GET_ELEMENT:
- case GET_METHOD:
+ switch (NashornCallSiteDescriptor.getStandardOperation(desc)) {
+ case GET:
//checks whether the property name is hard-coded in the call-site (i.e. a getProp vs a getElem, or setProp vs setElem)
//if it is we can make assumptions on the property: that if it is not defined on primitive wrapper itself it never will be.
//so in that case we can skip creation of primitive wrapper and start our search with the prototype.
@@ -133,8 +131,7 @@
}
}
break;
- case SET_PROPERTY:
- case SET_ELEMENT:
+ case SET:
return getPrimitiveSetter(name, guard, wrapFilter, NashornCallSiteDescriptor.isStrict(desc));
default:
break;
diff --git a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/ReflectionCheckLinker.java b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/ReflectionCheckLinker.java
index 7c94ebc..a168fe1 100644
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/ReflectionCheckLinker.java
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/ReflectionCheckLinker.java
@@ -30,6 +30,7 @@
import java.lang.reflect.Modifier;
import java.lang.reflect.Proxy;
import jdk.dynalink.CallSiteDescriptor;
+import jdk.dynalink.StandardNamespace;
import jdk.dynalink.StandardOperation;
import jdk.dynalink.linker.GuardedInvocation;
import jdk.dynalink.linker.LinkRequest;
@@ -129,9 +130,9 @@
// allow 'static' access on Class objects representing public classes of non-restricted packages
if ((self instanceof Class) && Modifier.isPublic(((Class<?>)self).getModifiers())) {
final CallSiteDescriptor desc = request.getCallSiteDescriptor();
- if ("static".equals(NashornCallSiteDescriptor.getOperand(desc)) && NashornCallSiteDescriptor.contains(desc, StandardOperation.GET_PROPERTY)) {
+ if ("static".equals(NashornCallSiteDescriptor.getOperand(desc)) && NashornCallSiteDescriptor.contains(desc, StandardOperation.GET, StandardNamespace.PROPERTY)) {
if (Context.isAccessibleClass((Class<?>)self) && !isReflectionClass((Class<?>)self)) {
- // If "GET_PROPERTY:static" passes access checks, allow access.
+ // If "GET:PROPERTY:static" passes access checks, allow access.
return;
}
}
diff --git a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/resources/Messages.properties b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/resources/Messages.properties
index 0116fb4..2c84781 100644
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/resources/Messages.properties
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/resources/Messages.properties
@@ -214,6 +214,7 @@
syntax.error.strict.cant.delete=cannot delete "{0}" in strict mode
syntax.error.redeclare.variable=Variable "{0}" has already been declared
syntax.error.unprotected.switch.declaration=Unsupported {0} declaration in unprotected switch statement
+syntax.error.duplicate.parameter=Duplicate parameter name "{0}"
io.error.cant.write=cannot write "{0}"
@@ -222,3 +223,12 @@
uri.error.bad.uri=Bad URI "{0}" near offset {1}
list.adapter.null.global=Attempted to create the adapter from outside a JavaScript execution context.
+
+unimplemented.es6.module=ES6 modules are not yet implemented
+unimplemented.es6.rest.param=ES6 function rest parameter declaration is not yet implemented
+unimplemented.es6.yield=ES6 yield and yield* are not yet implemented
+unimplemented.es6.spread=ES6 spread operator is not yet implemented
+unimplemented.es6.class=ES6 class declarations and expressions are not yet implemented
+unimplemented.es6.destructuring=ES6 destructuring is not yet implemented
+unimplemented.es6.generator=ES6 generator is not yet implemented
+unimplemented.es6.super=ES6 super keyword is not yet implemented
diff --git a/test/script/basic/JDK-8164708.js b/test/script/basic/JDK-8164708.js
new file mode 100644
index 0000000..d477d9c
--- /dev/null
+++ b/test/script/basic/JDK-8164708.js
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * 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-8164708: String.prototype.replace replaces empty match twice
+ *
+ * @test
+ * @run
+ */
+
+Assert.assertEquals("4005".replace(/\B(?=(\d{3})+(?!\d))/g, ","), "4,005");
+
diff --git a/test/script/basic/JDK-8168146.js b/test/script/basic/JDK-8168146.js
new file mode 100644
index 0000000..dc96e96
--- /dev/null
+++ b/test/script/basic/JDK-8168146.js
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * 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-8168146: Infinite recursion in Uint8ClampedArray.set
+ *
+ * @test
+ * @run
+ */
+
+
+var a = new Uint8ClampedArray(10);
+
+for (var i = 0; i < 10; i++) {
+ a[i] = i;
+ Assert.assertTrue(a[i] === i);
+}
diff --git a/test/script/basic/es6/JDK-8168140.js b/test/script/basic/es6/JDK-8168140.js
new file mode 100644
index 0000000..c94c704
--- /dev/null
+++ b/test/script/basic/es6/JDK-8168140.js
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * 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-8168140: TypedArrays should implement ES6 iterator protocol
+ *
+ * @test
+ * @run
+ * @option --language=es6
+ */
+
+let TypedArrayTypes = [
+ Int8Array,
+ Uint8Array,
+ Uint8ClampedArray,
+ Int16Array,
+ Uint16Array,
+ Int32Array,
+ Uint32Array,
+ Float32Array,
+ Float64Array
+];
+
+let arrays = [];
+let sum = 0;
+
+TypedArrayTypes.forEach(function(ArrayType) {
+ var a = new ArrayType(10);
+ for (let i = 0; i < a.length; i++) {
+ a[i] = i;
+ }
+ arrays.push(a);
+});
+
+Assert.assertTrue(arrays.length === 9);
+
+for (let array of arrays) {
+
+ Assert.assertTrue(array.length === 10);
+ let count = 0;
+
+ for (let value of array) {
+ Assert.assertTrue(value === count++);
+ sum += value;
+ }
+}
+
+Assert.assertTrue(sum === 405);
diff --git a/test/script/basic/es6/JDK-8168373.js b/test/script/basic/es6/JDK-8168373.js
new file mode 100644
index 0000000..af26e73
--- /dev/null
+++ b/test/script/basic/es6/JDK-8168373.js
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2016 Oracle and/or its affiliates. All rights reserved.
+ * 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-8168373: don't emit conversions for symbols outside their lexical scope
+ *
+ * @test
+ * @run
+ * @option --language=es6
+ */
+
+function p() { return false } // "predicate"
+function r(x) { return x } // "read"
+
+(function() {
+ try { // Try creates control flow edges from assignments into catch blocks.
+ // Lexically scoped, never read int variable (undefined at catch block) but still with a cf edge into catch block.
+ // Since it's never read, it's not written either (Nashorn optimizes some dead writes).
+ let x = 0;
+ if (p()) { throw {}; } // We need `p()` so this block doesn't get optimized away, for possibility of a `throw`
+ x = 0.0; // change the type of x to double
+ r(x); // read x otherwise it's optimized away
+ } catch (e) {} // under the bug, "throw" will try to widen unwritten int x to double for here and cause a verifier error
+})()
diff --git a/test/script/basic/es6/class.js b/test/script/basic/es6/class.js
new file mode 100644
index 0000000..8897e25
--- /dev/null
+++ b/test/script/basic/es6/class.js
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * Class declaration is not implemented
+ *
+ * @test
+ * @run
+ * @option --language=es6
+ */
+
+try {
+ eval("class Foo {}");
+} catch (e) {
+ print(String(e).replace(/\\/g, "/"))
+}
diff --git a/test/script/basic/es6/class.js.EXPECTED b/test/script/basic/es6/class.js.EXPECTED
new file mode 100644
index 0000000..0d457c9
--- /dev/null
+++ b/test/script/basic/es6/class.js.EXPECTED
@@ -0,0 +1,3 @@
+java.lang.RuntimeException: test/script/basic/es6/class.js#33:3<eval>:1:0 ES6 class declarations and expressions are not yet implemented
+class Foo {}
+^
diff --git a/test/script/basic/es6/destructuring.js b/test/script/basic/es6/destructuring.js
new file mode 100644
index 0000000..d2b2a1b
--- /dev/null
+++ b/test/script/basic/es6/destructuring.js
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * 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.
+ */
+
+/**
+ * Destructuring is not implemented
+ *
+ * @test
+ * @run
+ * @option --language=es6
+ */
+
+
+function check(code) {
+ try {
+ eval(code);
+ } catch (e) {
+ print(String(e).replace(/\\/g, "/"))
+ }
+}
+
+check("var { x: y } = obj;");
+check("let { x: y } = obj;");
+check("const { x: y } = obj;");
+check("({ x: y }) = obj;");
+check("for (var { x: y } of obj) ;");
+check("for (let { x: y } of obj) ;");
+check("var { x, y } = obj;");
+check("let { x, y } = obj;");
+check("const { x, y } = obj;");
+check("({ x, y }) = obj;");
+check("for (var { x, y } of obj) ;");
+check("for (let { x, y } of obj) ;");
+check("var [a, b] = obj;");
+check("let [a, b] = obj;");
+check("const [a, b] = obj;");
+check("[a, b] = obj;");
+check("for ([a, b] of obj) ;");
+check("for (var [a, b] of obj) ;");
+check("for (let [a, b] of obj) ;");
+check("(function({ x: y }) { return x; })()");
+check("(function({ x }) { return x; })()");
+check("(function([x]) { return x; })()");
+check("for (var [[x, y, z] = [4, 5, 6]] = [7, 8, 9]; iterCount < 1; ) ;");
+check("for ([ arrow = () => {} ] of [[]]) ;");
+check("try { throw null;} catch({}) { }");
+check("try { throw {} } catch ({}) { }");
+check("try { throw [] } catch ([,]) { }");
+check("try { throw { w: [7, undefined, ] }} catch ({ w: [x, y, z] = [4, 5, 6] }) { }");
+check("try { throw { a: 2, b: 3} } catch ({a, b}) { }");
+check("try { throw [null] } catch ([[x]]) { }");
+check("try { throw { w: undefined } } catch ({ w: { x, y, z } = { x: 4, y: 5, z: 6 } }) { }");
+
diff --git a/test/script/basic/es6/destructuring.js.EXPECTED b/test/script/basic/es6/destructuring.js.EXPECTED
new file mode 100644
index 0000000..54ecd96
--- /dev/null
+++ b/test/script/basic/es6/destructuring.js.EXPECTED
@@ -0,0 +1,93 @@
+java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6<eval>:1:4 ES6 destructuring is not yet implemented
+var { x: y } = obj;
+ ^
+java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6<eval>:1:4 ES6 destructuring is not yet implemented
+let { x: y } = obj;
+ ^
+java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6<eval>:1:6 ES6 destructuring is not yet implemented
+const { x: y } = obj;
+ ^
+java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6<eval>:1:1 ES6 destructuring is not yet implemented
+({ x: y }) = obj;
+ ^
+java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6<eval>:1:0 ES6 destructuring is not yet implemented
+for (var { x: y } of obj) ;
+^
+java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6<eval>:1:0 ES6 destructuring is not yet implemented
+for (let { x: y } of obj) ;
+^
+java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6<eval>:1:4 ES6 destructuring is not yet implemented
+var { x, y } = obj;
+ ^
+java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6<eval>:1:4 ES6 destructuring is not yet implemented
+let { x, y } = obj;
+ ^
+java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6<eval>:1:6 ES6 destructuring is not yet implemented
+const { x, y } = obj;
+ ^
+java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6<eval>:1:1 ES6 destructuring is not yet implemented
+({ x, y }) = obj;
+ ^
+java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6<eval>:1:0 ES6 destructuring is not yet implemented
+for (var { x, y } of obj) ;
+^
+java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6<eval>:1:0 ES6 destructuring is not yet implemented
+for (let { x, y } of obj) ;
+^
+java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6<eval>:1:4 ES6 destructuring is not yet implemented
+var [a, b] = obj;
+ ^
+java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6<eval>:1:4 ES6 destructuring is not yet implemented
+let [a, b] = obj;
+ ^
+java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6<eval>:1:6 ES6 destructuring is not yet implemented
+const [a, b] = obj;
+ ^
+java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6<eval>:1:0 ES6 destructuring is not yet implemented
+[a, b] = obj;
+^
+java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6<eval>:1:0 ES6 destructuring is not yet implemented
+for ([a, b] of obj) ;
+^
+java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6<eval>:1:0 ES6 destructuring is not yet implemented
+for (var [a, b] of obj) ;
+^
+java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6<eval>:1:0 ES6 destructuring is not yet implemented
+for (let [a, b] of obj) ;
+^
+java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6<eval>:1:9 ES6 destructuring is not yet implemented
+(function({ x: y }) { return x; })()
+ ^
+java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6<eval>:1:9 ES6 destructuring is not yet implemented
+(function({ x }) { return x; })()
+ ^
+java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6<eval>:1:9 ES6 destructuring is not yet implemented
+(function([x]) { return x; })()
+ ^
+java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6<eval>:1:9 ES6 destructuring is not yet implemented
+for (var [[x, y, z] = [4, 5, 6]] = [7, 8, 9]; iterCount < 1; ) ;
+ ^
+java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6<eval>:1:0 ES6 destructuring is not yet implemented
+for ([ arrow = () => {} ] of [[]]) ;
+^
+java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6<eval>:1:25 ES6 destructuring is not yet implemented
+try { throw null;} catch({}) { }
+ ^
+java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6<eval>:1:24 ES6 destructuring is not yet implemented
+try { throw {} } catch ({}) { }
+ ^
+java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6<eval>:1:24 ES6 destructuring is not yet implemented
+try { throw [] } catch ([,]) { }
+ ^
+java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6<eval>:1:44 ES6 destructuring is not yet implemented
+try { throw { w: [7, undefined, ] }} catch ({ w: [x, y, z] = [4, 5, 6] }) { }
+ ^
+java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6<eval>:1:35 ES6 destructuring is not yet implemented
+try { throw { a: 2, b: 3} } catch ({a, b}) { }
+ ^
+java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6<eval>:1:28 ES6 destructuring is not yet implemented
+try { throw [null] } catch ([[x]]) { }
+ ^
+java.lang.RuntimeException: test/script/basic/es6/destructuring.js#35:6<eval>:1:38 ES6 destructuring is not yet implemented
+try { throw { w: undefined } } catch ({ w: { x, y, z } = { x: 4, y: 5, z: 6 } }) { }
+ ^
diff --git a/test/script/basic/es6/generator.js b/test/script/basic/es6/generator.js
new file mode 100644
index 0000000..88d8a0f
--- /dev/null
+++ b/test/script/basic/es6/generator.js
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * 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.
+ */
+
+/**
+ * Generators are not implemented
+ *
+ * @test
+ * @run
+ * @option --language=es6
+ */
+
+function check(code) {
+ try {
+ eval(code);
+ } catch (e) {
+ print(String(e).replace(/\\/g, "/"))
+ }
+}
+
+check("function* func() { yield 1; }");
+check("({ * generatorMethod() { yield 1; } })");
+check("var func = function*() { yield 1; }");
diff --git a/test/script/basic/es6/generator.js.EXPECTED b/test/script/basic/es6/generator.js.EXPECTED
new file mode 100644
index 0000000..fe4b850
--- /dev/null
+++ b/test/script/basic/es6/generator.js.EXPECTED
@@ -0,0 +1,9 @@
+java.lang.RuntimeException: test/script/basic/es6/generator.js#34:6<eval>:1:17 ES6 generator is not yet implemented
+function* func() { yield 1; }
+ ^
+java.lang.RuntimeException: test/script/basic/es6/generator.js#34:6<eval>:1:23 ES6 generator is not yet implemented
+({ * generatorMethod() { yield 1; } })
+ ^
+java.lang.RuntimeException: test/script/basic/es6/generator.js#34:6<eval>:1:23 ES6 generator is not yet implemented
+var func = function*() { yield 1; }
+ ^
diff --git a/test/script/basic/es6/restparam.js b/test/script/basic/es6/restparam.js
new file mode 100644
index 0000000..5db7f0b
--- /dev/null
+++ b/test/script/basic/es6/restparam.js
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * 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.
+ */
+
+/**
+ * ES6 rest params are not implemented
+ *
+ * @test
+ * @run
+ * @option --language=es6
+ */
+
+
+function check(code) {
+ try {
+ eval(code);
+ } catch (e) {
+ print(String(e).replace(/\\/g, "/"))
+ }
+}
+
+check("function func(...args) {}");
+check("function func(x, y, ...args) {}");
+check("({ meth(...args) {} })");
+check("({ meth(x, y, ...args) {} })");
+check("({ meth(x = 0, x) {} })");
+
diff --git a/test/script/basic/es6/restparam.js.EXPECTED b/test/script/basic/es6/restparam.js.EXPECTED
new file mode 100644
index 0000000..9ccc374
--- /dev/null
+++ b/test/script/basic/es6/restparam.js.EXPECTED
@@ -0,0 +1,15 @@
+java.lang.RuntimeException: test/script/basic/es6/restparam.js#35:6<eval>:1:17 ES6 function rest parameter declaration is not yet implemented
+function func(...args) {}
+ ^
+java.lang.RuntimeException: test/script/basic/es6/restparam.js#35:6<eval>:1:23 ES6 function rest parameter declaration is not yet implemented
+function func(x, y, ...args) {}
+ ^
+java.lang.RuntimeException: test/script/basic/es6/restparam.js#35:6<eval>:1:11 ES6 function rest parameter declaration is not yet implemented
+({ meth(...args) {} })
+ ^
+java.lang.RuntimeException: test/script/basic/es6/restparam.js#35:6<eval>:1:17 ES6 function rest parameter declaration is not yet implemented
+({ meth(x, y, ...args) {} })
+ ^
+SyntaxError: test/script/basic/es6/restparam.js#35:6<eval>:1:15 Duplicate parameter name "x"
+({ meth(x = 0, x) {} })
+ ^
diff --git a/test/script/basic/es6/spread.js b/test/script/basic/es6/spread.js
new file mode 100644
index 0000000..d90236e
--- /dev/null
+++ b/test/script/basic/es6/spread.js
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * 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.
+ */
+
+/**
+ * ES6 spread operator is not implemented
+ *
+ * @test
+ * @run
+ * @option --language=es6
+ */
+
+function check(code) {
+ try {
+ eval(code);
+ } catch (e) {
+ print(String(e).replace(/\\/g, "/"))
+ }
+}
+
+check("var x = [...args]");
+check("var x = [1, 2, ...args]");
+check("var x = [...args, 3, 5]");
+check("var r = func(...arr)");
diff --git a/test/script/basic/es6/spread.js.EXPECTED b/test/script/basic/es6/spread.js.EXPECTED
new file mode 100644
index 0000000..635f705
--- /dev/null
+++ b/test/script/basic/es6/spread.js.EXPECTED
@@ -0,0 +1,12 @@
+java.lang.RuntimeException: test/script/basic/es6/spread.js#34:8<eval>:1:9 ES6 spread operator is not yet implemented
+var x = [...args]
+ ^
+java.lang.RuntimeException: test/script/basic/es6/spread.js#34:8<eval>:1:15 ES6 spread operator is not yet implemented
+var x = [1, 2, ...args]
+ ^
+java.lang.RuntimeException: test/script/basic/es6/spread.js#34:8<eval>:1:9 ES6 spread operator is not yet implemented
+var x = [...args, 3, 5]
+ ^
+java.lang.RuntimeException: test/script/basic/es6/spread.js#34:8<eval>:1:13 ES6 spread operator is not yet implemented
+var r = func(...arr)
+ ^
diff --git a/test/script/basic/es6/super.js b/test/script/basic/es6/super.js
new file mode 100644
index 0000000..612d6cf
--- /dev/null
+++ b/test/script/basic/es6/super.js
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * 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.
+ */
+
+/**
+ * ES6 super keyword is not implemented
+ *
+ * @test
+ * @run
+ * @option --language=es6
+ */
+
+function check(code) {
+ try {
+ eval(code);
+ } catch (e) {
+ print(String(e).replace(/\\/g, "/"))
+ }
+}
+
+check("({ meth() { x = super.x } })");
+check("({ meth() { x = super.x() } })");
+check("({ meth() { x = super['x'] } })");
diff --git a/test/script/basic/es6/super.js.EXPECTED b/test/script/basic/es6/super.js.EXPECTED
new file mode 100644
index 0000000..2569857
--- /dev/null
+++ b/test/script/basic/es6/super.js.EXPECTED
@@ -0,0 +1,9 @@
+java.lang.RuntimeException: test/script/basic/es6/super.js#34:8<eval>:1:10 ES6 super keyword is not yet implemented
+({ meth() { x = super.x } })
+ ^
+java.lang.RuntimeException: test/script/basic/es6/super.js#34:8<eval>:1:10 ES6 super keyword is not yet implemented
+({ meth() { x = super.x() } })
+ ^
+java.lang.RuntimeException: test/script/basic/es6/super.js#34:8<eval>:1:10 ES6 super keyword is not yet implemented
+({ meth() { x = super['x'] } })
+ ^
diff --git a/test/script/basic/jsadapter-ids.js b/test/script/basic/jsadapter-ids.js
index fa2f1a0..9631f4c 100644
--- a/test/script/basic/jsadapter-ids.js
+++ b/test/script/basic/jsadapter-ids.js
@@ -30,6 +30,7 @@
var obj = new JSAdapter() {
__getIds__: function() {
+ Assert.assertTrue(this === obj);
print("__getIds__ called");
return [ "foo", "bar" ];
}
diff --git a/test/script/basic/jsadapter.js b/test/script/basic/jsadapter.js
index b487572..6755ffa 100644
--- a/test/script/basic/jsadapter.js
+++ b/test/script/basic/jsadapter.js
@@ -30,39 +30,81 @@
var obj = new JSAdapter() {
__get__: function(name) {
+ Assert.assertTrue(this === obj);
print("getter called for '" + name + "'"); return name;
},
__put__: function(name, value) {
+ Assert.assertTrue(this === obj);
print("setter called for '" + name + "' with " + value);
},
__call__: function(name, arg1, arg2) {
+ Assert.assertTrue(this === obj);
print("method '" + name + "' called with " + arg1 + ", " + arg2);
},
__new__: function(arg1, arg2) {
+ Assert.assertTrue(this === obj);
print("new with " + arg1 + ", " + arg2);
},
__getKeys__: function() {
+ Assert.assertTrue(this === obj);
print("__getKeys__ called");
return [ "foo", "bar" ];
},
__getValues__: function() {
+ Assert.assertTrue(this === obj);
print("__getValues__ called");
return [ "fooval", "barval" ];
},
__has__: function(name) {
+ Assert.assertTrue(this === obj);
print("__has__ called with '" + name + "'");
return name == "js";
},
__delete__: function(name) {
+ Assert.assertTrue(this === obj);
print("__delete__ called with '" + name + "'");
return true;
+ },
+
+ __preventExtensions__ : function() {
+ Assert.assertTrue(this === obj);
+ print("__preventExtensions__ called");
+ },
+
+ __freeze__ : function() {
+ Assert.assertTrue(this === obj);
+ print("__freeze__ called");
+
+ },
+
+ __isFrozen__ : function() {
+ Assert.assertTrue(this === obj);
+ print("__isFrozen__ called");
+ return false;
+ },
+
+ __seal__ : function() {
+ Assert.assertTrue(this === obj);
+ print("__seal__ called");
+ },
+
+ __isSealed__ : function() {
+ Assert.assertTrue(this === obj);
+ print("__isSealed__ called");
+ return false;
+ },
+
+ __isExtensible__ : function() {
+ Assert.assertTrue(this === obj);
+ print("__isExtensible__ called");
+ return true;
}
};
@@ -103,3 +145,13 @@
print(obj["js"]);
obj["js"] = "javascript";
print(obj["javascript"]);
+
+// call __isExtensible__, __isSealed__, __isFrozen__
+print(Object.isExtensible(obj));
+print(Object.isSealed(obj));
+print(Object.isFrozen(obj));
+
+// call __freeze__, __seal__, __preventExtensions__
+Object.freeze(obj);
+Object.seal(obj);
+Object.preventExtensions(obj);
diff --git a/test/script/basic/jsadapter.js.EXPECTED b/test/script/basic/jsadapter.js.EXPECTED
index 081048a..691cbf3 100644
--- a/test/script/basic/jsadapter.js.EXPECTED
+++ b/test/script/basic/jsadapter.js.EXPECTED
@@ -20,3 +20,12 @@
setter called for 'js' with javascript
getter called for 'javascript'
javascript
+__isExtensible__ called
+true
+__isSealed__ called
+false
+__isFrozen__ called
+false
+__freeze__ called
+__seal__ called
+__preventExtensions__ called
diff --git a/test/script/basic/jsadapterlink.js b/test/script/basic/jsadapterlink.js
index ed44d61..df9148f 100644
--- a/test/script/basic/jsadapterlink.js
+++ b/test/script/basic/jsadapterlink.js
@@ -31,18 +31,21 @@
var js1 = new JSAdapter() {
__get__: function(name) {
+ Assert.assertTrue(this === js1);
return "js1->" + name;
}
};
var js2 = new JSAdapter() {
__get__: function(name) {
+ Assert.assertTrue(this === js2);
return "js2->" + name;
}
};
var js3 = new JSAdapter() {
__get__: function(name) {
+ Assert.assertTrue(this === js3);
return "js3->" + name;
}
};
diff --git a/test/script/nosecurity/treeapi/destructuring_catch.js b/test/script/nosecurity/treeapi/destructuring_catch.js
new file mode 100644
index 0000000..ff399fe
--- /dev/null
+++ b/test/script/nosecurity/treeapi/destructuring_catch.js
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * 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.
+ */
+
+/**
+ * Tests to check representation of ES6 catch parameter as binding pattern.
+ *
+ * @test
+ * @option -scripting
+ * @run
+ */
+
+load(__DIR__ + "utils.js")
+
+var code = <<EOF
+
+try { throw null;} catch({}) { }
+try { throw {} } catch ({}) { }
+try { throw [] } catch ([,]) { }
+try { throw { w: [7, undefined, ] }} catch ({ w: [x, y, z] = [4, 5, 6] }) { }
+try { throw { a: 2, b: 3} } catch ({a, b}) { }
+try { throw [null] } catch ([[x]]) { }
+try { throw { w: undefined } } catch ({ w: { x, y, z } = { x: 4, y: 5, z: 6 } }) { }
+
+EOF
+
+parse("destructuring_catch.js", code, "--language=es6", new (Java.extend(visitor_es6, {
+ visitCatch : function (node, obj) {
+ obj.push(convert(node))
+ }
+})))
+
diff --git a/test/script/nosecurity/treeapi/destructuring_catch.js.EXPECTED b/test/script/nosecurity/treeapi/destructuring_catch.js.EXPECTED
new file mode 100644
index 0000000..6389aeb
--- /dev/null
+++ b/test/script/nosecurity/treeapi/destructuring_catch.js.EXPECTED
@@ -0,0 +1,399 @@
+[
+ {
+ "condition": "null",
+ "endPosition": "33",
+ "kind": "CATCH",
+ "parameter": {
+ "endPosition": "28",
+ "kind": "OBJECT_LITERAL",
+ "startPosition": "26",
+ "properties": []
+ },
+ "block": {
+ "endPosition": "33",
+ "kind": "BLOCK",
+ "statements": [],
+ "startPosition": "30"
+ },
+ "startPosition": "20"
+ },
+ {
+ "condition": "null",
+ "endPosition": "65",
+ "kind": "CATCH",
+ "parameter": {
+ "endPosition": "60",
+ "kind": "OBJECT_LITERAL",
+ "startPosition": "58",
+ "properties": []
+ },
+ "block": {
+ "endPosition": "65",
+ "kind": "BLOCK",
+ "statements": [],
+ "startPosition": "62"
+ },
+ "startPosition": "51"
+ },
+ {
+ "condition": "null",
+ "endPosition": "98",
+ "kind": "CATCH",
+ "parameter": {
+ "endPosition": "93",
+ "kind": "ARRAY_LITERAL",
+ "elements": [
+ null
+ ],
+ "startPosition": "90"
+ },
+ "block": {
+ "endPosition": "98",
+ "kind": "BLOCK",
+ "statements": [],
+ "startPosition": "95"
+ },
+ "startPosition": "83"
+ },
+ {
+ "condition": "null",
+ "endPosition": "176",
+ "kind": "CATCH",
+ "parameter": {
+ "endPosition": "171",
+ "kind": "OBJECT_LITERAL",
+ "startPosition": "143",
+ "properties": [
+ {
+ "getter": "null",
+ "endPosition": "169",
+ "kind": "PROPERTY",
+ "setter": "null",
+ "value": {
+ "expression": {
+ "endPosition": "169",
+ "kind": "ARRAY_LITERAL",
+ "elements": [
+ {
+ "endPosition": "162",
+ "kind": "NUMBER_LITERAL",
+ "value": "4",
+ "startPosition": "161"
+ },
+ {
+ "endPosition": "165",
+ "kind": "NUMBER_LITERAL",
+ "value": "5",
+ "startPosition": "164"
+ },
+ {
+ "endPosition": "168",
+ "kind": "NUMBER_LITERAL",
+ "value": "6",
+ "startPosition": "167"
+ }
+ ],
+ "startPosition": "160"
+ },
+ "endPosition": "169",
+ "kind": "ASSIGNMENT",
+ "variable": {
+ "endPosition": "157",
+ "kind": "ARRAY_LITERAL",
+ "elements": [
+ {
+ "endPosition": "150",
+ "kind": "IDENTIFIER",
+ "name": "x",
+ "startPosition": "149"
+ },
+ {
+ "endPosition": "153",
+ "kind": "IDENTIFIER",
+ "name": "y",
+ "startPosition": "152"
+ },
+ {
+ "endPosition": "156",
+ "kind": "IDENTIFIER",
+ "name": "z",
+ "startPosition": "155"
+ }
+ ],
+ "startPosition": "148"
+ },
+ "startPosition": "148"
+ },
+ "startPosition": "145",
+ "key": {
+ "endPosition": "146",
+ "kind": "IDENTIFIER",
+ "name": "w",
+ "startPosition": "145"
+ }
+ }
+ ]
+ },
+ "block": {
+ "endPosition": "176",
+ "kind": "BLOCK",
+ "statements": [],
+ "startPosition": "173"
+ },
+ "startPosition": "136"
+ },
+ {
+ "condition": "null",
+ "endPosition": "223",
+ "kind": "CATCH",
+ "parameter": {
+ "endPosition": "218",
+ "kind": "OBJECT_LITERAL",
+ "startPosition": "212",
+ "properties": [
+ {
+ "getter": "null",
+ "endPosition": "214",
+ "kind": "PROPERTY",
+ "setter": "null",
+ "value": {
+ "endPosition": "214",
+ "kind": "IDENTIFIER",
+ "name": "a",
+ "startPosition": "213"
+ },
+ "startPosition": "213",
+ "key": {
+ "endPosition": "214",
+ "kind": "IDENTIFIER",
+ "name": "a",
+ "startPosition": "213"
+ }
+ },
+ {
+ "getter": "null",
+ "endPosition": "217",
+ "kind": "PROPERTY",
+ "setter": "null",
+ "value": {
+ "endPosition": "217",
+ "kind": "IDENTIFIER",
+ "name": "b",
+ "startPosition": "216"
+ },
+ "startPosition": "216",
+ "key": {
+ "endPosition": "217",
+ "kind": "IDENTIFIER",
+ "name": "b",
+ "startPosition": "216"
+ }
+ }
+ ]
+ },
+ "block": {
+ "endPosition": "223",
+ "kind": "BLOCK",
+ "statements": [],
+ "startPosition": "220"
+ },
+ "startPosition": "205"
+ },
+ {
+ "condition": "null",
+ "endPosition": "262",
+ "kind": "CATCH",
+ "parameter": {
+ "endPosition": "257",
+ "kind": "ARRAY_LITERAL",
+ "elements": [
+ {
+ "endPosition": "256",
+ "kind": "ARRAY_LITERAL",
+ "elements": [
+ {
+ "endPosition": "255",
+ "kind": "IDENTIFIER",
+ "name": "x",
+ "startPosition": "254"
+ }
+ ],
+ "startPosition": "253"
+ }
+ ],
+ "startPosition": "252"
+ },
+ "block": {
+ "endPosition": "262",
+ "kind": "BLOCK",
+ "statements": [],
+ "startPosition": "259"
+ },
+ "startPosition": "245"
+ },
+ {
+ "condition": "null",
+ "endPosition": "347",
+ "kind": "CATCH",
+ "parameter": {
+ "endPosition": "342",
+ "kind": "OBJECT_LITERAL",
+ "startPosition": "301",
+ "properties": [
+ {
+ "getter": "null",
+ "endPosition": "340",
+ "kind": "PROPERTY",
+ "setter": "null",
+ "value": {
+ "expression": {
+ "endPosition": "340",
+ "kind": "OBJECT_LITERAL",
+ "startPosition": "320",
+ "properties": [
+ {
+ "getter": "null",
+ "endPosition": "326",
+ "kind": "PROPERTY",
+ "setter": "null",
+ "value": {
+ "endPosition": "326",
+ "kind": "NUMBER_LITERAL",
+ "value": "4",
+ "startPosition": "325"
+ },
+ "startPosition": "322",
+ "key": {
+ "endPosition": "323",
+ "kind": "IDENTIFIER",
+ "name": "x",
+ "startPosition": "322"
+ }
+ },
+ {
+ "getter": "null",
+ "endPosition": "332",
+ "kind": "PROPERTY",
+ "setter": "null",
+ "value": {
+ "endPosition": "332",
+ "kind": "NUMBER_LITERAL",
+ "value": "5",
+ "startPosition": "331"
+ },
+ "startPosition": "328",
+ "key": {
+ "endPosition": "329",
+ "kind": "IDENTIFIER",
+ "name": "y",
+ "startPosition": "328"
+ }
+ },
+ {
+ "getter": "null",
+ "endPosition": "338",
+ "kind": "PROPERTY",
+ "setter": "null",
+ "value": {
+ "endPosition": "338",
+ "kind": "NUMBER_LITERAL",
+ "value": "6",
+ "startPosition": "337"
+ },
+ "startPosition": "334",
+ "key": {
+ "endPosition": "335",
+ "kind": "IDENTIFIER",
+ "name": "z",
+ "startPosition": "334"
+ }
+ }
+ ]
+ },
+ "endPosition": "340",
+ "kind": "ASSIGNMENT",
+ "variable": {
+ "endPosition": "317",
+ "kind": "OBJECT_LITERAL",
+ "startPosition": "306",
+ "properties": [
+ {
+ "getter": "null",
+ "endPosition": "309",
+ "kind": "PROPERTY",
+ "setter": "null",
+ "value": {
+ "endPosition": "309",
+ "kind": "IDENTIFIER",
+ "name": "x",
+ "startPosition": "308"
+ },
+ "startPosition": "308",
+ "key": {
+ "endPosition": "309",
+ "kind": "IDENTIFIER",
+ "name": "x",
+ "startPosition": "308"
+ }
+ },
+ {
+ "getter": "null",
+ "endPosition": "312",
+ "kind": "PROPERTY",
+ "setter": "null",
+ "value": {
+ "endPosition": "312",
+ "kind": "IDENTIFIER",
+ "name": "y",
+ "startPosition": "311"
+ },
+ "startPosition": "311",
+ "key": {
+ "endPosition": "312",
+ "kind": "IDENTIFIER",
+ "name": "y",
+ "startPosition": "311"
+ }
+ },
+ {
+ "getter": "null",
+ "endPosition": "315",
+ "kind": "PROPERTY",
+ "setter": "null",
+ "value": {
+ "endPosition": "315",
+ "kind": "IDENTIFIER",
+ "name": "z",
+ "startPosition": "314"
+ },
+ "startPosition": "314",
+ "key": {
+ "endPosition": "315",
+ "kind": "IDENTIFIER",
+ "name": "z",
+ "startPosition": "314"
+ }
+ }
+ ]
+ },
+ "startPosition": "306"
+ },
+ "startPosition": "303",
+ "key": {
+ "endPosition": "304",
+ "kind": "IDENTIFIER",
+ "name": "w",
+ "startPosition": "303"
+ }
+ }
+ ]
+ },
+ "block": {
+ "endPosition": "347",
+ "kind": "BLOCK",
+ "statements": [],
+ "startPosition": "344"
+ },
+ "startPosition": "294"
+ }
+]
diff --git a/test/src/META-INF/services/jdk.dynalink.linker.GuardingDynamicLinkerExporter b/test/src/META-INF/services/jdk.dynalink.linker.GuardingDynamicLinkerExporter
index f3139f7..b3f34fe 100644
--- a/test/src/META-INF/services/jdk.dynalink.linker.GuardingDynamicLinkerExporter
+++ b/test/src/META-INF/services/jdk.dynalink.linker.GuardingDynamicLinkerExporter
@@ -1,2 +1,3 @@
jdk.dynalink.test.UntrustedGuardingDynamicLinkerExporter
jdk.dynalink.test.TrustedGuardingDynamicLinkerExporter
+jdk.dynalink.test.TrustedUnderscoreNameLinkerExporter
diff --git a/test/src/jdk/dynalink/beans/test/BeanLinkerTest.java b/test/src/jdk/dynalink/beans/test/BeanLinkerTest.java
index b74f6cc..44c009f 100644
--- a/test/src/jdk/dynalink/beans/test/BeanLinkerTest.java
+++ b/test/src/jdk/dynalink/beans/test/BeanLinkerTest.java
@@ -24,14 +24,13 @@
*/
package jdk.dynalink.beans.test;
+import static jdk.dynalink.StandardNamespace.ELEMENT;
+import static jdk.dynalink.StandardNamespace.METHOD;
+import static jdk.dynalink.StandardNamespace.PROPERTY;
import static jdk.dynalink.StandardOperation.CALL;
-import static jdk.dynalink.StandardOperation.CALL_METHOD;
-import static jdk.dynalink.StandardOperation.GET_ELEMENT;
-import static jdk.dynalink.StandardOperation.GET_LENGTH;
-import static jdk.dynalink.StandardOperation.GET_METHOD;
-import static jdk.dynalink.StandardOperation.GET_PROPERTY;
+import static jdk.dynalink.StandardOperation.GET;
import static jdk.dynalink.StandardOperation.NEW;
-import static jdk.dynalink.StandardOperation.SET_ELEMENT;
+import static jdk.dynalink.StandardOperation.SET;
import java.lang.invoke.CallSite;
import java.lang.invoke.MethodHandle;
@@ -39,7 +38,6 @@
import java.lang.invoke.MethodType;
import java.security.AccessControlException;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.Date;
import java.util.List;
import jdk.dynalink.CallSiteDescriptor;
@@ -78,12 +76,21 @@
}
private CallSite createCallSite(final boolean publicLookup, final Operation op, final Object name, final MethodType mt) {
- return createCallSite(publicLookup, new NamedOperation(op, name), mt);
+ return createCallSite(publicLookup, op.named(name), mt);
+ }
+
+ private CallSite createGetMethodCallSite(final boolean publicLookup, final String name) {
+ return createCallSite(publicLookup, GET_METHOD, name, MethodType.methodType(Object.class, Object.class));
}
private static final MethodHandle throwArrayIndexOutOfBounds = findThrower("throwArrayIndexOutOfBounds");
private static final MethodHandle throwIndexOutOfBounds = findThrower("throwIndexOutOfBounds");
+ private static final Operation GET_PROPERTY = GET.withNamespace(PROPERTY);
+ private static final Operation GET_ELEMENT = GET.withNamespace(ELEMENT);
+ private static final Operation GET_METHOD = GET.withNamespace(METHOD);
+ private static final Operation SET_ELEMENT = SET.withNamespace(ELEMENT);
+
private static final MethodHandle findThrower(final String name) {
try {
return MethodHandles.lookup().findStatic(BeanLinkerTest.class, name,
@@ -209,26 +216,6 @@
}
@Test(dataProvider = "flags")
- public void getlengthTest(final boolean publicLookup) throws Throwable {
- final MethodType mt = MethodType.methodType(int.class, Object.class);
- final CallSite cs = createCallSite(publicLookup, GET_LENGTH, mt);
-
- final int[] arr = {23, 42};
- Assert.assertEquals((int) cs.getTarget().invoke((Object) arr), 2);
- Assert.assertEquals((int) cs.getTarget().invoke(Collections.EMPTY_LIST), 0);
-
- final List<String> list = new ArrayList<>();
- list.add("hello");
- list.add("world");
- list.add("dynalink");
- Assert.assertEquals((int) cs.getTarget().invoke(list), 3);
- list.add("nashorn");
- Assert.assertEquals((int) cs.getTarget().invoke(list), 4);
- list.clear();
- Assert.assertEquals((int) cs.getTarget().invoke(list), 0);
- }
-
- @Test(dataProvider = "flags")
public void getElementTest(final boolean publicLookup) throws Throwable {
final MethodType mt = MethodType.methodType(int.class, Object.class, int.class);
final CallSite cs = createCallSite(publicLookup, GET_ELEMENT, mt);
@@ -364,8 +351,7 @@
@Test(dataProvider = "flags")
public void instanceMethodCallTest(final boolean publicLookup) {
- final MethodType mt = MethodType.methodType(Object.class, Object.class);
- final CallSite cs = createCallSite(publicLookup, GET_METHOD, "getClass", mt);
+ final CallSite cs = createGetMethodCallSite(publicLookup, "getClass");
final MethodType mt2 = MethodType.methodType(Class.class, Object.class, Object.class);
final CallSite cs2 = createCallSite(publicLookup, CALL, mt2);
@@ -389,23 +375,8 @@
}
@Test(dataProvider = "flags")
- public void instanceMethodCallTest2(final boolean publicLookup) {
- final MethodType mt = MethodType.methodType(Class.class, Object.class);
- final CallSite cs = createCallSite(publicLookup, CALL_METHOD, "getClass", mt);
- Class clz = null;
- try {
- clz = (Class) cs.getTarget().invoke(new Date());
- } catch (final Throwable th) {
- throw new RuntimeException(th);
- }
-
- Assert.assertEquals(clz, Date.class);
- }
-
- @Test(dataProvider = "flags")
public void staticMethodCallTest(final boolean publicLookup) {
- final MethodType mt = MethodType.methodType(Object.class, StaticClass.class);
- final CallSite cs = createCallSite(publicLookup, GET_METHOD, "getProperty", mt);
+ final CallSite cs = createGetMethodCallSite(publicLookup, "getProperty");
final MethodType mt2 = MethodType.methodType(String.class, Object.class, Object.class, String.class);
final CallSite cs2 = createCallSite(publicLookup, CALL, mt2);
@@ -428,28 +399,15 @@
Assert.assertEquals(str, System.getProperty("os.name"));
}
- @Test(dataProvider = "flags")
- public void staticMethodCallTest2(final boolean publicLookup) {
- final MethodType mt = MethodType.methodType(String.class, Object.class, String.class);
- final CallSite cs = createCallSite(publicLookup, CALL_METHOD, "getProperty", mt);
-
- String str = null;
- try {
- str = (String) cs.getTarget().invoke(StaticClass.forClass(System.class), "os.name");
- } catch (final Throwable th) {
- throw new RuntimeException(th);
- }
- Assert.assertEquals(str, System.getProperty("os.name"));
- }
-
// try calling System.getenv and expect security exception
@Test(dataProvider = "flags")
public void systemGetenvTest(final boolean publicLookup) {
- final MethodType mt = MethodType.methodType(Object.class, Object.class);
- final CallSite cs = createCallSite(publicLookup, CALL_METHOD, "getenv", mt);
+ final CallSite cs1 = createGetMethodCallSite(publicLookup, "getenv");
+ final CallSite cs2 = createCallSite(publicLookup, CALL, MethodType.methodType(Object.class, Object.class, Object.class));
try {
- cs.getTarget().invoke(StaticClass.forClass(System.class));
+ final Object method = cs1.getTarget().invoke(StaticClass.forClass(System.class));
+ cs2.getTarget().invoke(method, StaticClass.forClass(System.class));
throw new RuntimeException("should not reach here in any case!");
} catch (final Throwable th) {
Assert.assertTrue(th instanceof SecurityException);
@@ -459,11 +417,12 @@
// try getting a specific sensitive System property and expect security exception
@Test(dataProvider = "flags")
public void systemGetPropertyTest(final boolean publicLookup) {
- final MethodType mt = MethodType.methodType(String.class, Object.class, String.class);
- final CallSite cs = createCallSite(publicLookup, CALL_METHOD, "getProperty", mt);
+ final CallSite cs1 = createGetMethodCallSite(publicLookup, "getProperty");
+ final CallSite cs2 = createCallSite(publicLookup, CALL, MethodType.methodType(String.class, Object.class, Object.class, String.class));
try {
- cs.getTarget().invoke(StaticClass.forClass(System.class), "java.home");
+ final Object method = cs1.getTarget().invoke(StaticClass.forClass(System.class));
+ cs2.getTarget().invoke(method, StaticClass.forClass(System.class), "java.home");
throw new RuntimeException("should not reach here in any case!");
} catch (final Throwable th) {
Assert.assertTrue(th instanceof SecurityException);
@@ -473,11 +432,12 @@
// check a @CallerSensitive API and expect appropriate access check exception
@Test(dataProvider = "flags")
public void systemLoadLibraryTest(final boolean publicLookup) {
- final MethodType mt = MethodType.methodType(void.class, Object.class, String.class);
- final CallSite cs = createCallSite(publicLookup, CALL_METHOD, "loadLibrary", mt);
+ final CallSite cs1 = createGetMethodCallSite(publicLookup, "loadLibrary");
+ final CallSite cs2 = createCallSite(publicLookup, CALL, MethodType.methodType(void.class, Object.class, Object.class, String.class));
try {
- cs.getTarget().invoke(StaticClass.forClass(System.class), "foo");
+ final Object method = cs1.getTarget().invoke(StaticClass.forClass(System.class));
+ cs2.getTarget().invoke(method, StaticClass.forClass(System.class), "foo");
throw new RuntimeException("should not reach here in any case!");
} catch (final Throwable th) {
if (publicLookup) {
diff --git a/test/src/jdk/dynalink/beans/test/BeansLinkerTest.java b/test/src/jdk/dynalink/beans/test/BeansLinkerTest.java
index 8ef147f..c5d2862 100644
--- a/test/src/jdk/dynalink/beans/test/BeansLinkerTest.java
+++ b/test/src/jdk/dynalink/beans/test/BeansLinkerTest.java
@@ -24,12 +24,12 @@
*/
package jdk.dynalink.beans.test;
+import static jdk.dynalink.StandardNamespace.ELEMENT;
+import static jdk.dynalink.StandardNamespace.METHOD;
+import static jdk.dynalink.StandardNamespace.PROPERTY;
import static jdk.dynalink.StandardOperation.CALL;
-import static jdk.dynalink.StandardOperation.GET_ELEMENT;
-import static jdk.dynalink.StandardOperation.GET_METHOD;
-import static jdk.dynalink.StandardOperation.GET_PROPERTY;
-import static jdk.dynalink.StandardOperation.SET_ELEMENT;
-import static jdk.dynalink.StandardOperation.SET_PROPERTY;
+import static jdk.dynalink.StandardOperation.GET;
+import static jdk.dynalink.StandardOperation.SET;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
@@ -42,12 +42,11 @@
import java.util.regex.Pattern;
import java.util.stream.Stream;
import jdk.dynalink.CallSiteDescriptor;
-import jdk.dynalink.CompositeOperation;
import jdk.dynalink.DynamicLinkerFactory;
-import jdk.dynalink.NamedOperation;
+import jdk.dynalink.Namespace;
+import jdk.dynalink.NamespaceOperation;
import jdk.dynalink.NoSuchDynamicMethodException;
import jdk.dynalink.Operation;
-import jdk.dynalink.StandardOperation;
import jdk.dynalink.support.SimpleRelinkableCallSite;
import org.testng.Assert;
import org.testng.annotations.Test;
@@ -67,32 +66,32 @@
@Test
public static void testPublicFieldPropertyUnnamedGetter() {
- testGetterPermutations(GET_PROPERTY, (op) -> Assert.assertEquals(42, call(op, new Bean1(), "answer")));
+ testGetterPermutations(PROPERTY, (op) -> Assert.assertEquals(42, call(op, new Bean1(), "answer")));
}
@Test
public static void testPublicFieldPropertyNamedGetter() {
- testGetterPermutations(GET_PROPERTY, (op) -> Assert.assertEquals(42, call(named("answer", op), new Bean1())));
+ testGetterPermutations(PROPERTY, (op) -> Assert.assertEquals(42, call(op.named("answer"), new Bean1())));
}
@Test
public static void testGetterPropertyUnnamedGetter() {
- testGetterPermutations(GET_PROPERTY, (op) -> Assert.assertEquals("bean1", call(op, new Bean1(), "name")));
+ testGetterPermutations(PROPERTY, (op) -> Assert.assertEquals("bean1", call(op, new Bean1(), "name")));
}
@Test
public static void testGetterPropertyNamedGetter() {
- testGetterPermutations(GET_PROPERTY, (op) -> Assert.assertEquals("bean1", call(named("name", op), new Bean1())));
+ testGetterPermutations(PROPERTY, (op) -> Assert.assertEquals("bean1", call(op.named("name"), new Bean1())));
}
@Test
public static void testMethodUnnamedGetter() {
- testGetterPermutations(GET_METHOD, (op) -> Assert.assertEquals("bar-foo", call(call(op, new Bean1(), "someMethod"), new Bean1(), "bar")));
+ testGetterPermutations(METHOD, (op) -> Assert.assertEquals("bar-foo", call(call(op, new Bean1(), "someMethod"), new Bean1(), "bar")));
}
@Test
public static void testMethodNamedGetter() {
- testGetterPermutations(GET_METHOD, (op) -> Assert.assertEquals("bar-foo", call(call(named("someMethod", op), new Bean1()), new Bean1(), "bar")));
+ testGetterPermutations(METHOD, (op) -> Assert.assertEquals("bar-foo", call(call(op.named("someMethod"), new Bean1()), new Bean1(), "bar")));
}
private static final Map<String, String> MAP1 = new HashMap<>();
@@ -102,12 +101,12 @@
@Test
public static void testElementUnnamedGetter() {
- testGetterPermutations(GET_ELEMENT, (op) -> Assert.assertEquals("bar", call(op, MAP1, "foo")));
+ testGetterPermutations(ELEMENT, (op) -> Assert.assertEquals("bar", call(op, MAP1, "foo")));
}
@Test
public static void testElementNamedGetter() {
- testGetterPermutations(GET_ELEMENT, (op) -> Assert.assertEquals("bar", call(named("foo", op), MAP1)));
+ testGetterPermutations(ELEMENT, (op) -> Assert.assertEquals("bar", call(op.named("foo"), MAP1)));
}
public static class Bean2 {
@@ -121,7 +120,7 @@
@Test
public static void testUnnamedFieldSetter() {
- testSetterPermutations(SET_PROPERTY, (op) -> {
+ testSetterPermutations(PROPERTY, (op) -> {
final Bean2 bean2 = new Bean2();
call(op, bean2, "answer", 12);
Assert.assertEquals(bean2.answer, 12);
@@ -130,16 +129,16 @@
@Test
public static void testNamedFieldSetter() {
- testSetterPermutations(SET_PROPERTY, (op) -> {
+ testSetterPermutations(PROPERTY, (op) -> {
final Bean2 bean2 = new Bean2();
- call(named("answer", op), bean2, 14);
+ call(op.named("answer"), bean2, 14);
Assert.assertEquals(bean2.answer, 14);
});
}
@Test
public static void testUnnamedPropertySetter() {
- testSetterPermutations(SET_PROPERTY, (op) -> {
+ testSetterPermutations(PROPERTY, (op) -> {
final Bean2 bean2 = new Bean2();
call(op, bean2, "name", "boo");
Assert.assertEquals(bean2.name, "boo");
@@ -148,14 +147,14 @@
@Test
public static void testNamedPropertySetter() {
- testSetterPermutations(SET_PROPERTY, (op) -> {
+ testSetterPermutations(PROPERTY, (op) -> {
final Bean2 bean2 = new Bean2();
- call(named("name", op), bean2, "blah");
+ call(op.named("name"), bean2, "blah");
Assert.assertEquals(bean2.name, "blah");
});
}
- private static final Pattern GET_ELEMENT_THEN_PROPERTY_PATTERN = Pattern.compile(".*GET_ELEMENT.*GET_PROPERTY.*");
+ private static final Pattern GET_ELEMENT_THEN_PROPERTY_PATTERN = Pattern.compile(".*ELEMENT.*PROPERTY.*");
@Test
public static void testUnnamedElementAndPropertyGetter() {
@@ -168,10 +167,10 @@
public static void testNamedElementAndPropertyGetter() {
final Map<String, Object> map = new HashMap<>();
map.put("empty", true);
- testGetterPermutations(GET_ELEMENT_THEN_PROPERTY_PATTERN, 4, (op) -> Assert.assertEquals(true, call(named("empty", op), map)));
+ testGetterPermutations(GET_ELEMENT_THEN_PROPERTY_PATTERN, 4, (op) -> Assert.assertEquals(true, call(op.named("empty"), map)));
}
- private static final Pattern GET_PROPERTY_THEN_ELEMENT_PATTERN = Pattern.compile(".*GET_PROPERTY.*GET_ELEMENT.*");
+ private static final Pattern GET_PROPERTY_THEN_ELEMENT_PATTERN = Pattern.compile(".*PROPERTY.*ELEMENT.*");
@Test
public static void testUnnamedPropertyAndElementGetter() {
@@ -184,7 +183,7 @@
public static void testNamedPropertyAndElementGetter() {
final Map<String, Object> map = new HashMap<>();
map.put("empty", true);
- testGetterPermutations(GET_PROPERTY_THEN_ELEMENT_PATTERN, 4, (op) -> Assert.assertEquals(false, call(named("empty", op), map)));
+ testGetterPermutations(GET_PROPERTY_THEN_ELEMENT_PATTERN, 4, (op) -> Assert.assertEquals(false, call(op.named("empty"), map)));
}
public static class MapWithProperty extends HashMap<String, Object> {
@@ -200,24 +199,24 @@
final MapWithProperty map = new MapWithProperty();
map.put("name", "element");
- call(ops(SET_PROPERTY, SET_ELEMENT), map, "name", "property");
+ call(SET.withNamespaces(PROPERTY, ELEMENT), map, "name", "property");
Assert.assertEquals("property", map.name);
Assert.assertEquals("element", map.get("name"));
- call(ops(SET_ELEMENT, SET_PROPERTY), map, "name", "element2");
+ call(SET.withNamespaces(ELEMENT, PROPERTY), map, "name", "element2");
Assert.assertEquals("property", map.name);
Assert.assertEquals("element2", map.get("name"));
}
@Test
public static void testMissingMembersAtLinkTime() {
- testPermutations(GETTER_PERMUTATIONS, (op) -> expectNoSuchDynamicMethodException(()-> call(named("foo", op), new Object())));
- testPermutations(SETTER_PERMUTATIONS, (op) -> expectNoSuchDynamicMethodException(()-> call(named("foo", op), new Object(), "newValue")));
+ testPermutations(GETTER_PERMUTATIONS, (op) -> expectNoSuchDynamicMethodException(()-> call(op.named("foo"), new Object())));
+ testPermutations(SETTER_PERMUTATIONS, (op) -> expectNoSuchDynamicMethodException(()-> call(op.named("foo"), new Object(), "newValue")));
}
@Test
public static void testMissingMembersAtRunTime() {
- call(GET_ELEMENT, new ArrayList<>(), "foo");
+ call(GET.withNamespace(ELEMENT), new ArrayList<>(), "foo");
Stream.of(new HashMap(), new ArrayList(), new Object[0]).forEach((receiver) -> {
testPermutations(GETTER_PERMUTATIONS, (op) -> { System.err.println(op + " " + receiver.getClass().getName()); Assert.assertNull(call(op, receiver, "foo"));});
// No assertion for the setter; we just expect it to silently succeed
@@ -233,59 +232,59 @@
}
}
- private static Operation[] GETTER_PERMUTATIONS = new Operation[] {
- GET_PROPERTY,
- GET_METHOD,
- GET_ELEMENT,
- ops(GET_PROPERTY, GET_ELEMENT),
- ops(GET_PROPERTY, GET_METHOD),
- ops(GET_ELEMENT, GET_PROPERTY),
- ops(GET_ELEMENT, GET_METHOD),
- ops(GET_METHOD, GET_PROPERTY),
- ops(GET_METHOD, GET_ELEMENT),
- ops(GET_PROPERTY, GET_ELEMENT, GET_METHOD),
- ops(GET_PROPERTY, GET_METHOD, GET_ELEMENT),
- ops(GET_ELEMENT, GET_PROPERTY, GET_METHOD),
- ops(GET_ELEMENT, GET_METHOD, GET_PROPERTY),
- ops(GET_METHOD, GET_PROPERTY, GET_ELEMENT),
- ops(GET_METHOD, GET_ELEMENT, GET_PROPERTY),
+ private static NamespaceOperation[] GETTER_PERMUTATIONS = new NamespaceOperation[] {
+ GET.withNamespaces(PROPERTY),
+ GET.withNamespaces(METHOD),
+ GET.withNamespaces(ELEMENT),
+ GET.withNamespaces(PROPERTY, ELEMENT),
+ GET.withNamespaces(PROPERTY, METHOD),
+ GET.withNamespaces(ELEMENT, PROPERTY),
+ GET.withNamespaces(ELEMENT, METHOD),
+ GET.withNamespaces(METHOD, PROPERTY),
+ GET.withNamespaces(METHOD, ELEMENT),
+ GET.withNamespaces(PROPERTY, ELEMENT, METHOD),
+ GET.withNamespaces(PROPERTY, METHOD, ELEMENT),
+ GET.withNamespaces(ELEMENT, PROPERTY, METHOD),
+ GET.withNamespaces(ELEMENT, METHOD, PROPERTY),
+ GET.withNamespaces(METHOD, PROPERTY, ELEMENT),
+ GET.withNamespaces(METHOD, ELEMENT, PROPERTY)
};
- private static Operation[] SETTER_PERMUTATIONS = new Operation[] {
- SET_PROPERTY,
- SET_ELEMENT,
- ops(SET_PROPERTY, SET_ELEMENT),
- ops(SET_ELEMENT, SET_PROPERTY)
+ private static NamespaceOperation[] SETTER_PERMUTATIONS = new NamespaceOperation[] {
+ SET.withNamespaces(PROPERTY),
+ SET.withNamespaces(ELEMENT),
+ SET.withNamespaces(PROPERTY, ELEMENT),
+ SET.withNamespaces(ELEMENT, PROPERTY)
};
- private static void testPermutations(final Operation[] ops, final StandardOperation requiredOp, final int expectedCount, final Consumer<Operation> test) {
- testPermutationsWithFilter(ops, (op)->CompositeOperation.contains(op, requiredOp), expectedCount, test);
+ private static void testPermutations(final NamespaceOperation[] ops, final Operation requiredOp, final Namespace requiredNamespace, final int expectedCount, final Consumer<NamespaceOperation> test) {
+ testPermutationsWithFilter(ops, (op)->NamespaceOperation.contains(op, requiredOp, requiredNamespace), expectedCount, test);
}
- private static void testPermutations(final Operation[] ops, final Pattern regex, final int expectedCount, final Consumer<Operation> test) {
+ private static void testPermutations(final NamespaceOperation[] ops, final Pattern regex, final int expectedCount, final Consumer<NamespaceOperation> test) {
testPermutationsWithFilter(ops, (op)->regex.matcher(op.toString()).matches(), expectedCount, test);
}
- private static void testPermutations(final Operation[] ops, final Consumer<Operation> test) {
+ private static void testPermutations(final NamespaceOperation[] ops, final Consumer<NamespaceOperation> test) {
testPermutationsWithFilter(ops, (op)->true, ops.length, test);
}
- private static void testPermutationsWithFilter(final Operation[] ops, final Predicate<Operation> filter, final int expectedCount, final Consumer<Operation> test) {
+ private static void testPermutationsWithFilter(final NamespaceOperation[] ops, final Predicate<NamespaceOperation> filter, final int expectedCount, final Consumer<NamespaceOperation> test) {
final int[] counter = new int[1];
Stream.of(ops).filter(filter).forEach((op)-> { counter[0]++; test.accept(op); });
Assert.assertEquals(counter[0], expectedCount);
}
- private static void testGetterPermutations(final StandardOperation requiredOp, final Consumer<Operation> test) {
- testPermutations(GETTER_PERMUTATIONS, requiredOp, 11, test);
+ private static void testGetterPermutations(final Namespace requiredNamespace, final Consumer<NamespaceOperation> test) {
+ testPermutations(GETTER_PERMUTATIONS, GET, requiredNamespace, 11, test);
}
- private static void testGetterPermutations(final Pattern regex, final int expectedCount, final Consumer<Operation> test) {
+ private static void testGetterPermutations(final Pattern regex, final int expectedCount, final Consumer<NamespaceOperation> test) {
testPermutations(GETTER_PERMUTATIONS, regex, expectedCount, test);
}
- private static void testSetterPermutations(final StandardOperation requiredOp, final Consumer<Operation> test) {
- testPermutations(SETTER_PERMUTATIONS, requiredOp, 3, test);
+ private static void testSetterPermutations(final Namespace requiredNamespace, final Consumer<NamespaceOperation> test) {
+ testPermutations(SETTER_PERMUTATIONS, SET, requiredNamespace, 3, test);
}
private static Object call(final Operation op, final Object... args) {
@@ -305,14 +304,6 @@
return call(CALL, args);
}
- private static Operation named(final Object name, final Operation... ops) {
- return new NamedOperation(ops(ops), name);
- }
-
- private static Operation ops(final Operation... ops) {
- return ops.length == 1 ? ops[0] : new CompositeOperation(ops);
- }
-
private static MethodType t(final int argCount) {
return MethodType.methodType(Object.class, Collections.nCopies(argCount, Object.class));
}
diff --git a/test/src/jdk/dynalink/support/test/CallSiteTest.java b/test/src/jdk/dynalink/support/test/CallSiteTest.java
index d33aa0a..2649a99 100644
--- a/test/src/jdk/dynalink/support/test/CallSiteTest.java
+++ b/test/src/jdk/dynalink/support/test/CallSiteTest.java
@@ -25,6 +25,9 @@
package jdk.dynalink.support.test;
+import static jdk.dynalink.StandardNamespace.PROPERTY;
+import static jdk.dynalink.StandardOperation.GET;
+
import java.lang.invoke.CallSite;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
@@ -33,14 +36,15 @@
import jdk.dynalink.CallSiteDescriptor;
import jdk.dynalink.DynamicLinker;
import jdk.dynalink.DynamicLinkerFactory;
-import jdk.dynalink.NamedOperation;
-import jdk.dynalink.StandardOperation;
+import jdk.dynalink.Operation;
import jdk.dynalink.linker.GuardedInvocation;
import jdk.dynalink.support.SimpleRelinkableCallSite;
import org.testng.Assert;
import org.testng.annotations.Test;
public class CallSiteTest {
+ private static final Operation GET_PROPERTY = GET.withNamespace(PROPERTY);
+
@Test
public void testInitialize() {
final DynamicLinkerFactory factory = new DynamicLinkerFactory();
@@ -48,7 +52,7 @@
final MethodType mt = MethodType.methodType(Object.class, Object.class);
final boolean[] initializeCalled = { Boolean.FALSE };
linker.link(new SimpleRelinkableCallSite(new CallSiteDescriptor(
- MethodHandles.publicLookup(), new NamedOperation(StandardOperation.GET_PROPERTY, "DO_NOT_CARE"), mt)) {
+ MethodHandles.publicLookup(), GET_PROPERTY.named("DO_NOT_CARE"), mt)) {
@Override
public void initialize(final MethodHandle relinkAndInvoke) {
initializeCalled[0] = Boolean.TRUE;
@@ -66,7 +70,7 @@
final MethodType mt = MethodType.methodType(Object.class, Object.class);
final boolean[] relinkCalled = { Boolean.FALSE };
final CallSite cs = linker.link(new SimpleRelinkableCallSite(new CallSiteDescriptor(
- MethodHandles.publicLookup(), new NamedOperation(StandardOperation.GET_PROPERTY, "class"), mt)) {
+ MethodHandles.publicLookup(), GET_PROPERTY.named("class"), mt)) {
@Override
public void relink(final GuardedInvocation guardedInvocation, final MethodHandle relinkAndInvoke) {
relinkCalled[0] = Boolean.TRUE;
@@ -90,7 +94,7 @@
final MethodType mt = MethodType.methodType(Object.class, Object.class);
final boolean[] resetAndRelinkCalled = { Boolean.FALSE };
final CallSite cs = linker.link(new SimpleRelinkableCallSite(new CallSiteDescriptor(
- MethodHandles.publicLookup(), new NamedOperation(StandardOperation.GET_PROPERTY, "length"), mt)) {
+ MethodHandles.publicLookup(), GET_PROPERTY.named("length"), mt)) {
@Override
public void resetAndRelink(final GuardedInvocation guardedInvocation, final MethodHandle relinkAndInvoke) {
resetAndRelinkCalled[0] = Boolean.TRUE;
diff --git a/test/src/jdk/dynalink/test/DynamicLinkerFactoryTest.java b/test/src/jdk/dynalink/test/DynamicLinkerFactoryTest.java
index 2addefb..4199da2 100644
--- a/test/src/jdk/dynalink/test/DynamicLinkerFactoryTest.java
+++ b/test/src/jdk/dynalink/test/DynamicLinkerFactoryTest.java
@@ -24,6 +24,9 @@
*/
package jdk.dynalink.test;
+import static jdk.dynalink.StandardNamespace.PROPERTY;
+import static jdk.dynalink.StandardOperation.GET;
+
import java.lang.invoke.CallSite;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
@@ -35,9 +38,9 @@
import jdk.dynalink.CallSiteDescriptor;
import jdk.dynalink.DynamicLinker;
import jdk.dynalink.DynamicLinkerFactory;
-import jdk.dynalink.NamedOperation;
import jdk.dynalink.NoSuchDynamicMethodException;
import jdk.dynalink.Operation;
+import jdk.dynalink.StandardNamespace;
import jdk.dynalink.StandardOperation;
import jdk.dynalink.beans.StaticClass;
import jdk.dynalink.linker.GuardedInvocation;
@@ -52,6 +55,8 @@
@SuppressWarnings("javadoc")
public class DynamicLinkerFactoryTest {
+ private static final Operation GET_PROPERTY = GET.withNamespace(PROPERTY);
+
private static DynamicLinkerFactory newDynamicLinkerFactory(final boolean resetClassLoader) {
final DynamicLinkerFactory factory = new DynamicLinkerFactory();
if (resetClassLoader) {
@@ -190,7 +195,7 @@
final MethodType mt = MethodType.methodType(Object.class, Object.class, String.class);
final DynamicLinker linker = factory.createLinker();
final CallSite cs = linker.link(new SimpleRelinkableCallSite(new CallSiteDescriptor(
- MethodHandles.publicLookup(), StandardOperation.GET_PROPERTY, mt)));
+ MethodHandles.publicLookup(), GET_PROPERTY, mt)));
Assert.assertFalse(reachedPrelinkTransformer[0]);
Assert.assertEquals(cs.getTarget().invoke(new Object(), "class"), Object.class);
Assert.assertTrue(reachedPrelinkTransformer[0]);
@@ -209,7 +214,7 @@
final MethodType mt = MethodType.methodType(Object.class, Object.class, String.class);
final DynamicLinker linker = factory.createLinker();
final CallSite cs = linker.link(new SimpleRelinkableCallSite(new CallSiteDescriptor(
- MethodHandles.publicLookup(), StandardOperation.GET_PROPERTY, mt)));
+ MethodHandles.publicLookup(), GET_PROPERTY, mt)));
Assert.assertFalse(reachedInternalObjectsFilter[0]);
Assert.assertEquals(cs.getTarget().invoke(new Object(), "class"), Object.class);
Assert.assertTrue(reachedInternalObjectsFilter[0]);
@@ -252,7 +257,7 @@
final MethodType mt = MethodType.methodType(Object.class, Object.class);
final CallSiteDescriptor testDescriptor = new CallSiteDescriptor(MethodHandles.publicLookup(),
- new NamedOperation(StandardOperation.GET_METHOD, methodName), mt);
+ GET.withNamespace(StandardNamespace.METHOD).named(methodName), mt);
final CallSite cs = linker.link(new SimpleRelinkableCallSite(testDescriptor));
TrustedGuardingDynamicLinkerExporter.enable();
@@ -274,7 +279,7 @@
final DynamicLinker linker = factory.createLinker();
final MethodType mt = MethodType.methodType(Object.class, Object.class);
- final NamedOperation op = new NamedOperation(StandardOperation.GET_PROPERTY, "foo");
+ final Operation op = GET_PROPERTY.named("foo");
final CallSite cs = linker.link(new SimpleRelinkableCallSite(new CallSiteDescriptor(
MethodHandles.publicLookup(), op, mt)));
final boolean[] reachedGetMember = new boolean[1];
@@ -306,7 +311,7 @@
// check that the nashorn exported linker can be used for ScriptObjectMirror
final ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
final MethodType mt = MethodType.methodType(Object.class, Object.class);
- final NamedOperation op = new NamedOperation(StandardOperation.GET_PROPERTY, "foo");
+ final Operation op = GET_PROPERTY.named("foo");
final CallSite cs = linker.link(new SimpleRelinkableCallSite(new CallSiteDescriptor(
MethodHandles.publicLookup(), op, mt)));
Object value = null;
diff --git a/test/src/jdk/dynalink/test/LinkedCallSiteLocationTest.java b/test/src/jdk/dynalink/test/LinkedCallSiteLocationTest.java
index 8e2b03b..00b56ba 100644
--- a/test/src/jdk/dynalink/test/LinkedCallSiteLocationTest.java
+++ b/test/src/jdk/dynalink/test/LinkedCallSiteLocationTest.java
@@ -24,20 +24,21 @@
*/
package jdk.dynalink.test;
-import static jdk.dynalink.StandardOperation.CALL_METHOD;
-
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import jdk.dynalink.CallSiteDescriptor;
import jdk.dynalink.DynamicLinker;
import jdk.dynalink.DynamicLinkerFactory;
-import jdk.dynalink.NamedOperation;
+import jdk.dynalink.Operation;
+import jdk.dynalink.StandardNamespace;
+import jdk.dynalink.StandardOperation;
import jdk.dynalink.linker.GuardingDynamicLinker;
import jdk.dynalink.support.SimpleRelinkableCallSite;
import org.testng.Assert;
import org.testng.annotations.Test;
public class LinkedCallSiteLocationTest {
+ private static final Operation GET_METHOD = StandardOperation.GET.withNamespace(StandardNamespace.METHOD);
@Test
public void testLinkedCallSiteLocation() throws Throwable {
final StackTraceElement[] lastLinked = new StackTraceElement[1];
@@ -51,7 +52,7 @@
final SimpleRelinkableCallSite callSite = new SimpleRelinkableCallSite(
new CallSiteDescriptor(
MethodHandles.lookup(),
- new NamedOperation(CALL_METHOD, "foo"),
+ GET_METHOD.named("foo"),
MethodType.methodType(void.class, Object.class)));
linker.link(callSite);
diff --git a/test/src/jdk/dynalink/test/TrustedUnderscoreNameLinkerExporter.java b/test/src/jdk/dynalink/test/TrustedUnderscoreNameLinkerExporter.java
new file mode 100644
index 0000000..9b21da5
--- /dev/null
+++ b/test/src/jdk/dynalink/test/TrustedUnderscoreNameLinkerExporter.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ *
+ * 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 Oracle nor the names of its
+ * 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 THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS 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.dynalink.test;
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import jdk.dynalink.CallSiteDescriptor;
+import jdk.dynalink.NamedOperation;
+import jdk.dynalink.NamespaceOperation;
+import jdk.dynalink.Operation;
+import jdk.dynalink.StandardNamespace;
+import jdk.dynalink.StandardOperation;
+import jdk.dynalink.linker.GuardedInvocation;
+import jdk.dynalink.linker.GuardingDynamicLinker;
+import jdk.dynalink.linker.GuardingDynamicLinkerExporter;
+import jdk.dynalink.linker.LinkRequest;
+import jdk.dynalink.linker.LinkerServices;
+import jdk.dynalink.linker.support.SimpleLinkRequest;
+
+/**
+ * This is a dynalink pluggable linker (see http://openjdk.java.net/jeps/276).
+ * This linker translater underscore_separated method names to CamelCase names
+ * used in Java APIs.
+ */
+public final class TrustedUnderscoreNameLinkerExporter extends GuardingDynamicLinkerExporter {
+ private static final Pattern UNDERSCORE_NAME = Pattern.compile("_(.)");
+
+ // translate underscore_separated name as a CamelCase name
+ private static String translateToCamelCase(final String name) {
+ final Matcher m = UNDERSCORE_NAME.matcher(name);
+ final StringBuilder buf = new StringBuilder();
+ while (m.find()) {
+ m.appendReplacement(buf, m.group(1).toUpperCase());
+ }
+ m.appendTail(buf);
+ return buf.toString();
+ }
+
+ @Override
+ public List<GuardingDynamicLinker> get() {
+ final ArrayList<GuardingDynamicLinker> linkers = new ArrayList<>();
+ linkers.add(new GuardingDynamicLinker() {
+ @Override
+ public GuardedInvocation getGuardedInvocation(final LinkRequest request,
+ final LinkerServices linkerServices) throws Exception {
+ final CallSiteDescriptor desc = request.getCallSiteDescriptor();
+ final Operation op = desc.getOperation();
+ final Object name = NamedOperation.getName(op);
+ final Operation namespaceOp = NamedOperation.getBaseOperation(op);
+ // is this a named GET_METHOD?
+ final boolean isGetMethod =
+ NamespaceOperation.getBaseOperation(namespaceOp) == StandardOperation.GET
+ && StandardNamespace.findFirst(namespaceOp) == StandardNamespace.METHOD;
+ if (isGetMethod && name instanceof String) {
+ final String str = (String)name;
+ if (str.indexOf('_') == -1) {
+ return null;
+ }
+
+ final String nameStr = translateToCamelCase(str);
+ // create a new call descriptor to use translated name
+ final CallSiteDescriptor newDesc = AccessController.doPrivileged(
+ new PrivilegedAction<CallSiteDescriptor>() {
+ @Override
+ public CallSiteDescriptor run() {
+ return desc.changeOperation(((NamedOperation)op).changeName(nameStr));
+ }
+ });
+ // create a new Link request to link the call site with translated name
+ final LinkRequest newRequest = request.replaceArguments(newDesc, request.getArguments());
+ // return guarded invocation linking the translated request
+ return linkerServices.getGuardedInvocation(newRequest);
+ }
+
+ return null;
+ }
+ });
+ return linkers;
+ }
+}
diff --git a/test/src/jdk/nashorn/api/javaaccess/test/ArrayConversionTest.java b/test/src/jdk/nashorn/api/javaaccess/test/ArrayConversionTest.java
index 45d1264..56ed51e 100644
--- a/test/src/jdk/nashorn/api/javaaccess/test/ArrayConversionTest.java
+++ b/test/src/jdk/nashorn/api/javaaccess/test/ArrayConversionTest.java
@@ -104,11 +104,11 @@
@Test
public void testVarArgs() throws ScriptException {
// Sole NativeArray in vararg position becomes vararg array itself
- runTest("assertVarArg_42_17", "[42, 17]");
+ runTest("assertVarArgWith42And17", "[42, 17]");
// NativeArray in vararg position becomes an argument if there are more arguments
- runTest("assertVarArg_array_17", "[42], 18");
+ runTest("assertVarArgArray7", "[42], 18");
// Only NativeArray is converted to vararg array, other objects (e.g. a function) aren't
- runTest("assertVarArg_function", "function() { return 'Hello' }");
+ runTest("assertVarArgFunction", "function() { return 'Hello' }");
}
private static void runTest(final String testMethodName, final String argument) throws ScriptException {
@@ -209,20 +209,20 @@
assertEquals(Arrays.asList("apple", "orange"), array[1]);
}
- public static void assertVarArg_42_17(final Object... args) {
+ public static void assertVarArgWith42And17(final Object... args) {
assertEquals(2, args.length);
assertEquals(42, ((Number)args[0]).intValue());
assertEquals(17, ((Number)args[1]).intValue());
}
- public static void assertVarArg_array_17(final Object... args) throws ScriptException {
+ public static void assertVarArgArray7(final Object... args) throws ScriptException {
assertEquals(2, args.length);
e.getBindings(ScriptContext.ENGINE_SCOPE).put("arr", args[0]);
assertTrue((Boolean)e.eval("arr instanceof Array && arr.length == 1 && arr[0] == 42"));
assertEquals(18, ((Number)args[1]).intValue());
}
- public static void assertVarArg_function(final Object... args) throws ScriptException {
+ public static void assertVarArgFunction(final Object... args) throws ScriptException {
assertEquals(1, args.length);
e.getBindings(ScriptContext.ENGINE_SCOPE).put("fn", args[0]);
assertEquals("Hello", e.eval("fn()"));
diff --git a/test/src/jdk/nashorn/api/scripting/test/JDK_8169050_Test.java b/test/src/jdk/nashorn/api/scripting/test/JDK_8169050_Test.java
new file mode 100644
index 0000000..357b7c4
--- /dev/null
+++ b/test/src/jdk/nashorn/api/scripting/test/JDK_8169050_Test.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * 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.api.scripting.test;
+
+import javax.script.ScriptEngine;
+import javax.script.ScriptEngineManager;
+import javax.script.ScriptException;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+/**
+ * @bug 8169050
+ * @summary underscore_linker.js sample fails after dynalink changes for JDK-8168005
+ */
+public class JDK_8169050_Test {
+ private ScriptEngine engine;
+
+ @BeforeClass
+ public void setupTest() {
+ engine = new ScriptEngineManager().getEngineByName("js");
+ }
+
+ @Test
+ public void testUndersoreName() throws ScriptException {
+ engine.eval("var S = java.util.stream.Stream, v = 0;");
+ // The underscore name 'for_each' exercises pluggable dynalink linker
+ engine.eval("S.of(4, 5, 9).for_each(function(x) { v += x })");
+ assertEquals(18, ((Number)engine.get("v")).intValue());
+ }
+}