8168005: Introduce namespaces for GET, SET Dynalink operations
Reviewed-by: hannesw, sundar
--- a/nashorn/samples/dynalink/ArrayStreamLinkerExporter.java Fri Oct 28 16:52:20 2016 +0200
+++ b/nashorn/samples/dynalink/ArrayStreamLinkerExporter.java Tue Nov 01 15:31:44 2016 +0100
@@ -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));
--- a/nashorn/samples/dynalink/BufferIndexingLinkerExporter.java Fri Oct 28 16:52:20 2016 +0200
+++ b/nashorn/samples/dynalink/BufferIndexingLinkerExporter.java Tue Nov 01 15:31:44 2016 +0100
@@ -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;
--- a/nashorn/samples/dynalink/DOMLinkerExporter.java Fri Oct 28 16:52:20 2016 +0200
+++ b/nashorn/samples/dynalink/DOMLinkerExporter.java Tue Nov 01 15:31:44 2016 +0100
@@ -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;
--- a/nashorn/samples/dynalink/MissingMethodLinkerExporter.java Fri Oct 28 16:52:20 2016 +0200
+++ b/nashorn/samples/dynalink/MissingMethodLinkerExporter.java Tue Nov 01 15:31:44 2016 +0100
@@ -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;
--- a/nashorn/samples/dynalink/UnderscoreNameLinkerExporter.java Fri Oct 28 16:52:20 2016 +0200
+++ b/nashorn/samples/dynalink/UnderscoreNameLinkerExporter.java Tue Nov 01 15:31:44 2016 +0100
@@ -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);
}
--- a/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/CallSiteDescriptor.java Fri Oct 28 16:52:20 2016 +0200
+++ b/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/CallSiteDescriptor.java Tue Nov 01 15:31:44 2016 +0100
@@ -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());
+ }
+ }
}
--- a/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/CompositeOperation.java Fri Oct 28 16:52:20 2016 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -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));
- }
-}
--- a/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/NamedOperation.java Fri Oct 28 16:52:20 2016 +0200
+++ b/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/NamedOperation.java Tue Nov 01 15:31:44 2016 +0100
@@ -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.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/Namespace.java Tue Nov 01 15:31:44 2016 +0100
@@ -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 {
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/NamespaceOperation.java Tue Nov 01 15:31:44 2016 +0100
@@ -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;
+ }
+}
--- a/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/Operation.java Fri Oct 28 16:52:20 2016 +0200
+++ b/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/Operation.java Tue Nov 01 15:31:44 2016 +0100
@@ -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);
+ }
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/StandardNamespace.java Tue Nov 01 15:31:44 2016 +0100
@@ -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;
+ }
+}
--- a/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/StandardOperation.java Fri Oct 28 16:52:20 2016 +0200
+++ b/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/StandardOperation.java Tue Nov 01 15:31:44 2016 +0100
@@ -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,
- /**
- * Set the value of a property defined on an object. Call sites with this
- * operation should have a signature of
- * <tt>(receiver, propertyName, 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_PROPERTY,
+ GET,
/**
- * Get the value of an element of a collection. 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, 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, 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_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,
+ SET,
/**
- * 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
--- a/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/AbstractJavaLinker.java Fri Oct 28 16:52:20 2016 +0200
+++ b/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/AbstractJavaLinker.java Tue Nov 01 15:31:44 2016 +0100
@@ -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);
}
--- a/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/BeanLinker.java Fri Oct 28 16:52:20 2016 +0200
+++ b/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/BeanLinker.java Tue Nov 01 15:31:44 2016 +0100
@@ -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.");
--- a/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/BeansLinker.java Fri Oct 28 16:52:20 2016 +0200
+++ b/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/BeansLinker.java Tue Nov 01 15:31:44 2016 +0100
@@ -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)}.
*
--- a/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/DynamicMethodLinker.java Fri Oct 28 16:52:20 2016 +0200
+++ b/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/DynamicMethodLinker.java Tue Nov 01 15:31:44 2016 +0100
@@ -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
--- a/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/GuardedInvocationComponent.java Fri Oct 28 16:52:20 2016 +0200
+++ b/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/GuardedInvocationComponent.java Tue Nov 01 15:31:44 2016 +0100
@@ -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.
--- a/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/StaticClass.java Fri Oct 28 16:52:20 2016 +0200
+++ b/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/StaticClass.java Tue Nov 01 15:31:44 2016 +0100
@@ -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
--- a/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/StaticClassLinker.java Fri Oct 28 16:52:20 2016 +0200
+++ b/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/beans/StaticClassLinker.java Tue Nov 01 15:31:44 2016 +0100
@@ -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;
}
--- a/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/package-info.java Fri Oct 28 16:52:20 2016 +0200
+++ b/nashorn/src/jdk.dynalink/share/classes/jdk/dynalink/package-info.java Tue Nov 01 15:31:44 2016 +0100
@@ -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
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/Global.java Fri Oct 28 16:52:20 2016 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/Global.java Tue Nov 01 15:31:44 2016 +0100
@@ -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
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeJSAdapter.java Fri Oct 28 16:52:20 2016 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeJSAdapter.java Tue Nov 01 15:31:44 2016 +0100
@@ -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;
@@ -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
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeObject.java Fri Oct 28 16:52:20 2016 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeObject.java Tue Nov 01 15:31:44 2016 +0100
@@ -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;
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeString.java Fri Oct 28 16:52:20 2016 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeString.java Tue Nov 01 15:31:44 2016 +0100
@@ -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.
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptObject.java Fri Oct 28 16:52:20 2016 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptObject.java Tue Nov 01 15:31:44 2016 +0100
@@ -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
}
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Undefined.java Fri Oct 28 16:52:20 2016 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Undefined.java Tue Nov 01 15:31:44 2016 +0100
@@ -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);
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/WithObject.java Fri Oct 28 16:52:20 2016 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/WithObject.java Tue Nov 01 15:31:44 2016 +0100
@@ -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);
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/BrowserJSObjectLinker.java Fri Oct 28 16:52:20 2016 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/BrowserJSObjectLinker.java Tue Nov 01 15:31:44 2016 +0100
@@ -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) {
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java Fri Oct 28 16:52:20 2016 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java Tue Nov 01 15:31:44 2016 +0100
@@ -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;
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/JavaSuperAdapterLinker.java Fri Oct 28 16:52:20 2016 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/JavaSuperAdapterLinker.java Tue Nov 01 15:31:44 2016 +0100
@@ -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,
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornBeansLinker.java Fri Oct 28 16:52:20 2016 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornBeansLinker.java Tue Nov 01 15:31:44 2016 +0100
@@ -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);
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornBottomLinker.java Fri Oct 28 16:52:20 2016 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornBottomLinker.java Tue Nov 01 15:31:44 2016 +0100
@@ -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);
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornCallSiteDescriptor.java Fri Oct 28 16:52:20 2016 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornCallSiteDescriptor.java Tue Nov 01 15:31:44 2016 +0100
@@ -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;
}
+ private static StandardNamespace findFirstStandardNamespace(final CallSiteDescriptor desc) {
+ return StandardNamespace.findFirst(desc.getOperation());
+ }
+
/**
- * 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.
+ * 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 StandardOperation getFirstOperation() {
- final Operation base = NamedOperation.getBaseOperation(getOperation());
- if (base instanceof CompositeOperation) {
- return (StandardOperation)((CompositeOperation)base).getOperation(0);
- }
- return (StandardOperation)base;
+ 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 first standard operation in the (potentially composite)
- * operation of the passed call site descriptor.
+ * 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);
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java Fri Oct 28 16:52:20 2016 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java Tue Nov 01 15:31:44 2016 +0100
@@ -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;
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/ReflectionCheckLinker.java Fri Oct 28 16:52:20 2016 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/ReflectionCheckLinker.java Tue Nov 01 15:31:44 2016 +0100
@@ -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;
}
}
--- a/nashorn/test/src/jdk/dynalink/beans/test/BeanLinkerTest.java Fri Oct 28 16:52:20 2016 +0200
+++ b/nashorn/test/src/jdk/dynalink/beans/test/BeanLinkerTest.java Tue Nov 01 15:31:44 2016 +0100
@@ -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) {
--- a/nashorn/test/src/jdk/dynalink/beans/test/BeansLinkerTest.java Fri Oct 28 16:52:20 2016 +0200
+++ b/nashorn/test/src/jdk/dynalink/beans/test/BeansLinkerTest.java Tue Nov 01 15:31:44 2016 +0100
@@ -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));
}
--- a/nashorn/test/src/jdk/dynalink/support/test/CallSiteTest.java Fri Oct 28 16:52:20 2016 +0200
+++ b/nashorn/test/src/jdk/dynalink/support/test/CallSiteTest.java Tue Nov 01 15:31:44 2016 +0100
@@ -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;
--- a/nashorn/test/src/jdk/dynalink/test/DynamicLinkerFactoryTest.java Fri Oct 28 16:52:20 2016 +0200
+++ b/nashorn/test/src/jdk/dynalink/test/DynamicLinkerFactoryTest.java Tue Nov 01 15:31:44 2016 +0100
@@ -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;
--- a/nashorn/test/src/jdk/dynalink/test/LinkedCallSiteLocationTest.java Fri Oct 28 16:52:20 2016 +0200
+++ b/nashorn/test/src/jdk/dynalink/test/LinkedCallSiteLocationTest.java Tue Nov 01 15:31:44 2016 +0100
@@ -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);