# HG changeset patch
# User attila
# Date 1445448838 -7200
# Node ID 23abd10384a505c9f7aa595f868614da87d05581
# Parent 86b4260bb17ad1f3a3dad6ea16af4cca14149410
8139931: Introduce Operation objects in Dynalink instead of string encoding
Reviewed-by: hannesw, sundar
diff -r 86b4260bb17a -r 23abd10384a5 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/CallSiteDescriptor.java
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/CallSiteDescriptor.java Wed Oct 21 10:42:20 2015 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/CallSiteDescriptor.java Wed Oct 21 19:33:58 2015 +0200
@@ -86,19 +86,13 @@
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodHandles.Lookup;
import java.lang.invoke.MethodType;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import java.util.NoSuchElementException;
import java.util.Objects;
-import java.util.StringTokenizer;
-import jdk.internal.dynalink.support.NameCodec;
/**
* Call site descriptors contain all the information necessary for linking a
* call site. This information is normally passed as parameters to bootstrap
* methods and consists of the {@code MethodHandles.Lookup} object on the caller
- * class in which the call site occurs, the method name mentioned in the call
+ * class in which the call site occurs, the dynamic operation at the call
* site, and the method type of the call site. {@code CallSiteDescriptor}
* objects are used in Dynalink to capture and store these parameters for
* subsequent use by the {@link DynamicLinker}.
@@ -109,13 +103,12 @@
* Call site descriptors must be immutable. You can use this class as-is or you
* can subclass it, especially if you need to add further information to the
* descriptors (typically, values passed in additional parameters to the
- * bootstrap method) or want to cache results of name tokenization. Since the
- * descriptors must be immutable, you can set up a cache for equivalent
- * descriptors to have the call sites share them.
+ * bootstrap method. Since the descriptors must be immutable, you can set up a
+ * cache for equivalent descriptors to have the call sites share them.
*/
public class CallSiteDescriptor {
private final MethodHandles.Lookup lookup;
- private final String name;
+ private final Operation operation;
private final MethodType methodType;
/**
@@ -127,98 +120,23 @@
private static final RuntimePermission GET_LOOKUP_PERMISSION = new RuntimePermission(GET_LOOKUP_PERMISSION_NAME);
/**
- * The index of the name token that will carry the operation scheme prefix,
- * e.g. {@code "dyn"} for operations specified by Dynalink itself.
- */
- public static final int SCHEME = 0;
-
- /**
- * The index of the name token that carries the operation name, at least
- * when using the {@code "dyn"} scheme.
- */
-
- public static final int OPERATOR = 1;
-
- /**
- * The index of the name token that carries the name of an operand (e.g. a
- * property or a method), at least when using the {@code "dyn"} scheme.
- */
- public static final int NAME_OPERAND = 2;
-
- /**
- * String used to delimit tokens in a call site name; its value is
- * {@code ":"}, that is the colon character.
- */
- public static final String TOKEN_DELIMITER = ":";
-
- /**
- * String used to delimit operation names in a composite operation name;
- * its value is {@code "|"}, that is the pipe character.
- */
- public static final String OPERATOR_DELIMITER = "|";
-
- /**
* Creates a new call site descriptor.
* @param lookup the lookup object describing the class the call site belongs to.
- * @param name the name of the method at the call site.
+ * @param operation the dynamic operation at the call site.
* @param methodType the method type of the call site.
*/
- public CallSiteDescriptor(final Lookup lookup, final String name, final MethodType methodType) {
+ public CallSiteDescriptor(final Lookup lookup, final Operation operation, final MethodType methodType) {
this.lookup = Objects.requireNonNull(lookup, "lookup");
- this.name = Objects.requireNonNull(name, "name");
+ this.operation = Objects.requireNonNull(operation, "name");
this.methodType = Objects.requireNonNull(methodType, "methodType");
}
/**
- * Returns the number of tokens in the name of the method at the call site.
- * Method names are tokenized with the {@link #TOKEN_DELIMITER} character
- * character, e.g. {@code "dyn:getProp:color"} would be the name used to
- * describe a method that retrieves the property named "color" on the object
- * it is invoked on. This method will count the tokens in the name on every
- * invocation. Subclasses can override this method with a more efficient
- * implementation that caches the tokens.
- * @return the number of tokens in the name of the method at the call site.
+ * Returns the operation at the call site.
+ * @return the operation at the call site.
*/
- public int getNameTokenCount() {
- return getNameTokenizer().countTokens();
- }
-
- /**
- * Returns the ith token in the method name at the call
- * site. Method names are tokenized with the {@link #TOKEN_DELIMITER}
- * character. This method will tokenize the name on every invocation.
- * Subclasses can override this method with a more efficient implementation
- * that caches the tokens.
- * @param i the index of the token. Must be between 0 (inclusive) and
- * {@link #getNameTokenCount()} (exclusive).
- * @throws NoSuchElementException if the index is outside the allowed
- * range.
- * @return the ith token in the method name at the call
- * site.
- */
- public String getNameToken(final int i) {
- final StringTokenizer tok = getNameTokenizer();
- for (int j = 0; j < i; ++j) {
- tok.nextToken();
- }
- final String token = tok.nextToken();
- return (i > 1 ? NameCodec.decode(token) : token).intern();
- }
-
- private StringTokenizer getNameTokenizer() {
- return getNameTokenizer(name);
- }
-
- private static StringTokenizer getNameTokenizer(final String name) {
- return new StringTokenizer(name, CallSiteDescriptor.TOKEN_DELIMITER);
- }
-
- /**
- * Returns the full (untokenized) name of the method at the call site.
- * @return the full (untokenized) name of the method at the call site.
- */
- public final String getName() {
- return name;
+ public final Operation getOperation() {
+ return operation;
}
/**
@@ -260,11 +178,16 @@
/**
* Creates a new call site descriptor from this descriptor, which is
- * identical to this, except it changes the method type. Subclasses must
- * override the
+ * 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.
*
* @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.
*/
public final CallSiteDescriptor changeMethodType(final MethodType newMethodType) {
final CallSiteDescriptor changed = Objects.requireNonNull(
@@ -288,53 +211,16 @@
* @return a new call site descriptor, with the method type changed.
*/
protected CallSiteDescriptor changeMethodTypeInternal(final MethodType newMethodType) {
- return new CallSiteDescriptor(lookup, name, newMethodType);
+ return new CallSiteDescriptor(lookup, operation, newMethodType);
}
/**
- * Tokenizes a composite operation name of this descriptor along
- * {@link #OPERATOR_DELIMITER} characters. E.g. if this descriptor's name is
- * {@code "dyn:getElem|getProp|getMethod"}, then it returns a list of
- * {@code ["getElem", "getProp", "getMethod"]}.
- * @return a list of operator tokens.
+ * 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
+ * same {@link java.lang.invoke.MethodHandles.Lookup#lookupClass()} and
+ * {@link java.lang.invoke.MethodHandles.Lookup#lookupModes()}.
*/
- public final List tokenizeOperators() {
- final String ops = getNameToken(CallSiteDescriptor.OPERATOR);
- final StringTokenizer tok = new StringTokenizer(ops, CallSiteDescriptor.OPERATOR_DELIMITER);
- final int count = tok.countTokens();
- if(count == 1) {
- return Collections.singletonList(ops);
- }
- final String[] tokens = new String[count];
- for(int i = 0; i < count; ++i) {
- tokens[i] = tok.nextToken();
- }
- return Arrays.asList(tokens);
- }
-
- /**
- * Tokenizes the composite name along {@link #TOKEN_DELIMITER} characters,
- * as well as {@link NameCodec#decode(String) demangles} and interns the
- * tokens. The first two tokens are not demangled as they are supposed to
- * be the naming scheme and the name of the operation which can be expected
- * to consist of just alphabetical characters.
- * @param name the composite name consisting of
- * {@link #TOKEN_DELIMITER}-separated, possibly mangled tokens.
- * @return an array of unmangled, interned tokens.
- */
- public static String[] tokenizeName(final String name) {
- final StringTokenizer tok = getNameTokenizer(name);
- final String[] tokens = new String[tok.countTokens()];
- for(int i = 0; i < tokens.length; ++i) {
- String token = tok.nextToken();
- if(i > 1) {
- token = NameCodec.decode(token);
- }
- tokens[i] = token.intern();
- }
- return tokens;
- }
-
@Override
public boolean equals(final Object obj) {
if (obj == this) {
@@ -345,8 +231,9 @@
return false;
}
final CallSiteDescriptor other = (CallSiteDescriptor)obj;
- return name.equals(other.name) && methodType.equals(other.methodType) &&
- lookupsEqual(lookup, other.lookup);
+ return operation.equals(other.operation) &&
+ methodType.equals(other.methodType) &&
+ lookupsEqual(lookup, other.lookup);
}
/**
@@ -362,9 +249,15 @@
return l1.lookupClass() == l2.lookupClass() && l1.lookupModes() == l2.lookupModes();
}
+ /**
+ * Returns a value-based hash code of this call site descriptor computed
+ * from its operation, method type, and lookup object's lookup class and
+ * lookup modes.
+ * @return value-based hash code for this call site descriptor.
+ */
@Override
public int hashCode() {
- return name.hashCode() + 31 * methodType.hashCode() + 31 * 31 * lookupHashCode(lookup);
+ return operation.hashCode() + 31 * methodType.hashCode() + 31 * 31 * lookupHashCode(lookup);
}
/**
@@ -375,7 +268,7 @@
* @param lookup the lookup object.
* @return a hash code for the object..
*/
- protected static int lookupHashCode(final Lookup lookup) {
+ private static int lookupHashCode(final Lookup lookup) {
return lookup.lookupClass().hashCode() + 31 * lookup.lookupModes();
}
@@ -387,7 +280,8 @@
public String toString() {
final String mt = methodType.toString();
final String l = lookup.toString();
- final StringBuilder b = new StringBuilder(name.length() + mt.length() + 1 + l.length());
- return b.append(name).append(mt).append("@").append(l).toString();
+ final String o = operation.toString();
+ final StringBuilder b = new StringBuilder(o.length() + mt.length() + 1 + l.length());
+ return b.append(o).append(mt).append('@').append(l).toString();
}
}
diff -r 86b4260bb17a -r 23abd10384a5 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/CompositeOperation.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/CompositeOperation.java Wed Oct 21 19:33:58 2015 +0200
@@ -0,0 +1,260 @@
+/*
+ * 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.internal.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 get the property named "color" on the object, but if the
+ * property does not exist, then get the collection element named "color"
+ * instead.
+ *
+ * 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.
+ *
+ * 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}.
+ *
+ * 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:
+ *
+ * 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 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 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 == null || obj.getClass() != CompositeOperation.class) {
+ return false;
+ }
+ return Arrays.equals(operations, ((CompositeOperation)obj).operations);
+ }
+
+ /**
+ * 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 };
+ }
+}
diff -r 86b4260bb17a -r 23abd10384a5 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/NamedOperation.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/NamedOperation.java Wed Oct 21 19:33:58 2015 +0200
@@ -0,0 +1,197 @@
+/*
+ * 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.internal.dynalink;
+
+import java.util.Objects;
+
+/**
+ * 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")}
+ * 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
+ * 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.
+ */
+public class NamedOperation implements Operation {
+ private final Operation baseOperation;
+ private final Object name;
+
+ /**
+ * Creates a new named operation.
+ * @param baseOperation the base operation that is associated with a name.
+ * @param name the name associated with the base operation. Note that the
+ * name is not necessarily a string, but can be an arbitrary object. As the
+ * name is used for addressing, it can be an {@link Integer} when meant
+ * to be used as an index into an array or list etc.
+ * @throws NullPointerException if either {@code baseOperation} or
+ * {@code name} is null.
+ * @throws IllegalArgumentException if {@code baseOperation} is itself a
+ * {@code NamedOperation}.
+ */
+ public NamedOperation(final Operation baseOperation, final Object name) {
+ if (baseOperation instanceof NamedOperation) {
+ throw new IllegalArgumentException("baseOperation is a named operation");
+ }
+ this.baseOperation = Objects.requireNonNull(baseOperation, "baseOperation is null");
+ this.name = Objects.requireNonNull(name, "name 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 name of this named operation.
+ * @return the name of this named operation.
+ */
+ public Object getName() {
+ return name;
+ }
+
+ /**
+ * 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.
+ */
+ @Override
+ public boolean equals(final Object obj) {
+ if (obj == null) {
+ return false;
+ } else if(obj.getClass() != NamedOperation.class) {
+ return false;
+ }
+ final NamedOperation other = (NamedOperation)obj;
+ return baseOperation.equals(other.baseOperation) && name.equals(other.name);
+ }
+
+ /**
+ * Returns the hash code of this named operation. It is defined to be equal
+ * to {@code baseOperation.hashCode() + 31 * name.hashCode()}.
+ */
+ @Override
+ public int hashCode() {
+ return baseOperation.hashCode() + 31 * name.hashCode();
+ }
+
+ /**
+ * Returns the string representation of this named operation. It is defined
+ * to be equal to {@code baseOperation.toString() + ":" + name.toString()}.
+ */
+ @Override
+ public String toString() {
+ return baseOperation.toString() + ":" + name.toString();
+ }
+
+ /**
+ * If the passed operation is a named 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 NamedOperation ? ((NamedOperation)op).baseOperation : op;
+ }
+
+ /**
+ * If the passed operation is a named operation, returns its
+ * {@link #getName()}, otherwise returns null. Note that a named operation
+ * object can never have a null name, therefore returning null is indicative
+ * that the passed operation is not, in fact, a named operation.
+ * @param op the operation
+ * @return the name in the passed operation, or null if it is not a named
+ * operation.
+ */
+ public static Object getName(final Operation op) {
+ return op instanceof NamedOperation ? ((NamedOperation)op).name : null;
+ }
+}
diff -r 86b4260bb17a -r 23abd10384a5 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/Operation.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/Operation.java Wed Oct 21 19:33:58 2015 +0200
@@ -0,0 +1,99 @@
+/*
+ * 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.internal.dynalink;
+
+/**
+ * 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}.
+ * 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}).
+ */
+public interface Operation {
+}
diff -r 86b4260bb17a -r 23abd10384a5 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/StandardOperation.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/StandardOperation.java Wed Oct 21 19:33:58 2015 +0200
@@ -0,0 +1,176 @@
+/*
+ * 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.internal.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.
+ */
+public enum StandardOperation implements Operation {
+ /**
+ * Get the value of a property defined on an object. Call sites with this
+ * operation should have a signature of
+ * (receiver, propertyName)→value or
+ * (receiver)→value when used with {@link NamedOperation}, with
+ * all parameters and return type being of any type (either primitive or
+ * reference).
+ */
+ GET_PROPERTY,
+ /**
+ * Set the value of a property defined on an object. Call sites with this
+ * operation should have a signature of
+ * (receiver, propertyName, value)→void or
+ * (receiver, value)→void when used with {@link NamedOperation},
+ * with all parameters and return type being of any type (either primitive
+ * or reference).
+ */
+ SET_PROPERTY,
+ /**
+ * Get the value of an element of a collection. Call sites with this
+ * operation should have a signature of
+ * (receiver, index)→value or
+ * (receiver)→value 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
+ * (receiver, index, value)→void or
+ * (receiver, value)→void when used with {@link NamedOperation},
+ * with all parameters and return type being of any type (either primitive
+ * or reference).
+ */
+ SET_ELEMENT,
+ /**
+ * Get the length of an array of size of a collection. Call sites with
+ * this operation should have a signature of (receiver)→value,
+ * with all parameters and return type being of any type (either primitive
+ * or reference).
+ */
+ GET_LENGTH,
+ /**
+ * Gets an object representing a method defined on an object. Call sites
+ * with this operation should have a signature of
+ * (receiver, methodName)→value, or
+ * (receiver)→value 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
+ * (receiver, methodName, arguments...)→value or
+ * (receiver, arguments...)→value 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 (receiver, arguments...)→value, 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.
+ * The CALL 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
+ * be used as a diagnostic description for error messages.
+ */
+ CALL,
+ /**
+ * Calls a constructor object. Call sites with this operation should have a
+ * signature of (receiver, arguments...)→value, with all
+ * parameters and return type being of any type (either primitive or
+ * reference). The NEW 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
+ * be used as a diagnostic description for error messages.
+ */
+ NEW
+}
diff -r 86b4260bb17a -r 23abd10384a5 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/AbstractJavaLinker.java
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/AbstractJavaLinker.java Wed Oct 21 10:42:20 2015 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/AbstractJavaLinker.java Wed Oct 21 19:33:58 2015 +0200
@@ -92,12 +92,17 @@
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
+import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import jdk.internal.dynalink.CallSiteDescriptor;
+import jdk.internal.dynalink.CompositeOperation;
+import jdk.internal.dynalink.NamedOperation;
+import jdk.internal.dynalink.Operation;
+import jdk.internal.dynalink.StandardOperation;
import jdk.internal.dynalink.beans.GuardedInvocationComponent.ValidationType;
import jdk.internal.dynalink.internal.InternalTypeUtilities;
import jdk.internal.dynalink.linker.GuardedInvocation;
@@ -342,17 +347,27 @@
@Override
public GuardedInvocation getGuardedInvocation(final LinkRequest request, final LinkerServices linkerServices)
throws Exception {
- // BeansLinker already checked that the name is at least 2 elements long and the first element is "dyn".
final CallSiteDescriptor callSiteDescriptor = request.getCallSiteDescriptor();
- final String op = callSiteDescriptor.getNameToken(CallSiteDescriptor.OPERATOR);
- // Either dyn:callMethod:name(this[,args]) or dyn:callMethod(this,name[,args]).
- if("callMethod" == op) {
- return getCallPropWithThis(callSiteDescriptor, 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) {
+ return createGuardedDynamicMethodInvocation(callSiteDescriptor,
+ linkerServices, namedOperation.getName().toString(), methods);
+ }
}
- List operations = callSiteDescriptor.tokenizeOperators();
+
+ List operations = Arrays.asList(
+ CompositeOperation.getOperations(
+ NamedOperation.getBaseOperation(operation)));
+ final Object name = NamedOperation.getName(operation);
+
while(!operations.isEmpty()) {
- final GuardedInvocationComponent gic = getGuardedInvocationComponent(callSiteDescriptor, linkerServices,
- operations);
+ final GuardedInvocationComponent gic =
+ getGuardedInvocationComponent(callSiteDescriptor,
+ linkerServices, operations, name);
if(gic != null) {
return gic.getGuardedInvocation();
}
@@ -361,23 +376,26 @@
return null;
}
- protected GuardedInvocationComponent getGuardedInvocationComponent(final CallSiteDescriptor callSiteDescriptor,
- final LinkerServices linkerServices, final List operations) throws Exception {
+ protected GuardedInvocationComponent getGuardedInvocationComponent(
+ final CallSiteDescriptor callSiteDescriptor,
+ final LinkerServices linkerServices,
+ final List operations, final Object name)
+ throws Exception {
if(operations.isEmpty()) {
return null;
}
- final String op = operations.get(0);
- // Either dyn:getProp:name(this) or dyn:getProp(this, name)
- if("getProp".equals(op)) {
- return getPropertyGetter(callSiteDescriptor, linkerServices, pop(operations));
+ final Operation op = operations.get(0);
+ // Either GET_PROPERTY:name(this) or GET_PROPERTY(this, name)
+ if(op == StandardOperation.GET_PROPERTY) {
+ return getPropertyGetter(callSiteDescriptor, linkerServices, pop(operations), name);
}
- // Either dyn:setProp:name(this, value) or dyn:setProp(this, name, value)
- if("setProp".equals(op)) {
- return getPropertySetter(callSiteDescriptor, linkerServices, pop(operations));
+ // Either SET_PROPERTY:name(this, value) or SET_PROPERTY(this, name, value)
+ if(op == StandardOperation.SET_PROPERTY) {
+ return getPropertySetter(callSiteDescriptor, linkerServices, pop(operations), name);
}
- // Either dyn:getMethod:name(this), or dyn:getMethod(this, name)
- if("getMethod".equals(op)) {
- return getMethodGetter(callSiteDescriptor, linkerServices, pop(operations));
+ // Either GET_METHOD:name(this), or GET_METHOD(this, name)
+ if(op == StandardOperation.GET_METHOD) {
+ return getMethodGetter(callSiteDescriptor, linkerServices, pop(operations), name);
}
return null;
}
@@ -406,18 +424,6 @@
return Guards.asType(assignableGuard, type);
}
- private GuardedInvocation getCallPropWithThis(final CallSiteDescriptor callSiteDescriptor, final LinkerServices linkerServices) {
- switch(callSiteDescriptor.getNameTokenCount()) {
- case 3: {
- return createGuardedDynamicMethodInvocation(callSiteDescriptor, linkerServices,
- callSiteDescriptor.getNameToken(CallSiteDescriptor.NAME_OPERAND), methods);
- }
- default: {
- return null;
- }
- }
- }
-
private GuardedInvocation createGuardedDynamicMethodInvocation(final CallSiteDescriptor callSiteDescriptor,
final LinkerServices linkerServices, final String methodName, final Map methodMap){
final MethodHandle inv = getDynamicMethodInvocation(callSiteDescriptor, linkerServices, methodName, methodMap);
@@ -480,84 +486,86 @@
MethodHandles.constant(Object.class, null), 0, MethodHandle.class);
private GuardedInvocationComponent getPropertySetter(final CallSiteDescriptor callSiteDescriptor,
- final LinkerServices linkerServices, final List operations) throws Exception {
- switch(callSiteDescriptor.getNameTokenCount()) {
- case 2: {
- // Must have three arguments: target object, property name, and property value.
- assertParameterCount(callSiteDescriptor, 3);
+ final LinkerServices linkerServices, final List operations, final Object name) throws Exception {
+ if (name == null) {
+ return getUnnamedPropertySetter(callSiteDescriptor, linkerServices, operations);
+ }
+ return getNamedPropertySetter(callSiteDescriptor, linkerServices, operations, name);
+ }
- // We want setters that conform to "Object(O, V)". Note, we aren't doing "R(O, V)" as it might not be
- // valid for us to convert return values proactively. Also, since we don't know what setters will be
- // invoked, we'll conservatively presume Object return type. The one exception is void return.
- final MethodType origType = callSiteDescriptor.getMethodType();
- final MethodType type = origType.returnType() == void.class ? origType : origType.changeReturnType(Object.class);
+ private GuardedInvocationComponent getUnnamedPropertySetter(final CallSiteDescriptor callSiteDescriptor,
+ final LinkerServices linkerServices, final List operations) throws Exception {
+ // Must have three arguments: target object, property name, and property value.
+ assertParameterCount(callSiteDescriptor, 3);
+
+ // We want setters that conform to "Object(O, V)". Note, we aren't doing "R(O, V)" as it might not be
+ // valid for us to convert return values proactively. Also, since we don't know what setters will be
+ // invoked, we'll conservatively presume Object return type. The one exception is void return.
+ final MethodType origType = callSiteDescriptor.getMethodType();
+ final MethodType type = origType.returnType() == void.class ? origType : origType.changeReturnType(Object.class);
- // What's below is basically:
- // foldArguments(guardWithTest(isNotNull, invoke, null|nextComponent.invocation),
- // get_setter_handle(type, linkerServices))
- // only with a bunch of method signature adjustments. Basically, retrieve method setter
- // MethodHandle; if it is non-null, invoke it, otherwise either return null, or delegate to next
- // component's invocation.
+ // What's below is basically:
+ // foldArguments(guardWithTest(isNotNull, invoke, null|nextComponent.invocation),
+ // get_setter_handle(type, linkerServices))
+ // only with a bunch of method signature adjustments. Basically, retrieve method setter
+ // MethodHandle; if it is non-null, invoke it, otherwise either return null, or delegate to next
+ // component's invocation.
- // Call site type is "ret_type(object_type,property_name_type,property_value_type)", which we'll
- // abbreviate to R(O, N, V) going forward, although we don't really use R here (see above about using
- // Object return type).
- final MethodType setterType = type.dropParameterTypes(1, 2);
- // Bind property setter handle to the expected setter type and linker services. Type is
- // MethodHandle(Object, String, Object)
- final MethodHandle boundGetter = MethodHandles.insertArguments(getPropertySetterHandle, 0,
- callSiteDescriptor.changeMethodType(setterType), linkerServices);
+ // Call site type is "ret_type(object_type,property_name_type,property_value_type)", which we'll
+ // abbreviate to R(O, N, V) going forward, although we don't really use R here (see above about using
+ // Object return type).
+ final MethodType setterType = type.dropParameterTypes(1, 2);
+ // Bind property setter handle to the expected setter type and linker services. Type is
+ // MethodHandle(Object, String, Object)
+ final MethodHandle boundGetter = MethodHandles.insertArguments(getPropertySetterHandle, 0,
+ callSiteDescriptor.changeMethodType(setterType), linkerServices);
- // Cast getter to MethodHandle(O, N, V)
- final MethodHandle typedGetter = linkerServices.asType(boundGetter, type.changeReturnType(
- MethodHandle.class));
+ // Cast getter to MethodHandle(O, N, V)
+ final MethodHandle typedGetter = linkerServices.asType(boundGetter, type.changeReturnType(
+ MethodHandle.class));
- // Handle to invoke the setter R(MethodHandle, O, V)
- final MethodHandle invokeHandle = MethodHandles.exactInvoker(setterType);
- // Handle to invoke the setter, dropping unnecessary fold arguments R(MethodHandle, O, N, V)
- final MethodHandle invokeHandleFolded = MethodHandles.dropArguments(invokeHandle, 2, type.parameterType(
- 1));
- final GuardedInvocationComponent nextComponent = getGuardedInvocationComponent(callSiteDescriptor,
- linkerServices, operations);
+ // Handle to invoke the setter R(MethodHandle, O, V)
+ final MethodHandle invokeHandle = MethodHandles.exactInvoker(setterType);
+ // Handle to invoke the setter, dropping unnecessary fold arguments R(MethodHandle, O, N, V)
+ final MethodHandle invokeHandleFolded = MethodHandles.dropArguments(invokeHandle, 2, type.parameterType(
+ 1));
+ final GuardedInvocationComponent nextComponent = getGuardedInvocationComponent(callSiteDescriptor,
+ linkerServices, operations, null);
- final MethodHandle fallbackFolded;
- if(nextComponent == null) {
- // Object(MethodHandle)->Object(MethodHandle, O, N, V); returns constant null
- fallbackFolded = MethodHandles.dropArguments(CONSTANT_NULL_DROP_METHOD_HANDLE, 1,
- type.parameterList()).asType(type.insertParameterTypes(0, MethodHandle.class));
- } else {
- // Object(O, N, V)->Object(MethodHandle, O, N, V); adapts the next component's invocation to drop the
- // extra argument resulting from fold
- fallbackFolded = MethodHandles.dropArguments(nextComponent.getGuardedInvocation().getInvocation(),
- 0, MethodHandle.class);
- }
+ final MethodHandle fallbackFolded;
+ if(nextComponent == null) {
+ // Object(MethodHandle)->Object(MethodHandle, O, N, V); returns constant null
+ fallbackFolded = MethodHandles.dropArguments(CONSTANT_NULL_DROP_METHOD_HANDLE, 1,
+ type.parameterList()).asType(type.insertParameterTypes(0, MethodHandle.class));
+ } else {
+ // Object(O, N, V)->Object(MethodHandle, O, N, V); adapts the next component's invocation to drop the
+ // extra argument resulting from fold
+ fallbackFolded = MethodHandles.dropArguments(nextComponent.getGuardedInvocation().getInvocation(),
+ 0, MethodHandle.class);
+ }
- // fold(R(MethodHandle, O, N, V), MethodHandle(O, N, V))
- final MethodHandle compositeSetter = MethodHandles.foldArguments(MethodHandles.guardWithTest(
- IS_METHOD_HANDLE_NOT_NULL, invokeHandleFolded, fallbackFolded), typedGetter);
- if(nextComponent == null) {
- return getClassGuardedInvocationComponent(compositeSetter, type);
- }
- return nextComponent.compose(compositeSetter, getClassGuard(type), clazz, ValidationType.EXACT_CLASS);
- }
- case 3: {
- // Must have two arguments: target object and property value
- assertParameterCount(callSiteDescriptor, 2);
- final GuardedInvocation gi = createGuardedDynamicMethodInvocation(callSiteDescriptor, linkerServices,
- callSiteDescriptor.getNameToken(CallSiteDescriptor.NAME_OPERAND), propertySetters);
- // If we have a property setter with this name, this composite operation will always stop here
- 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)
- return getGuardedInvocationComponent(callSiteDescriptor, linkerServices, operations);
- }
- default: {
- // More than two name components; don't know what to do with it.
- return null;
- }
+ // fold(R(MethodHandle, O, N, V), MethodHandle(O, N, V))
+ final MethodHandle compositeSetter = MethodHandles.foldArguments(MethodHandles.guardWithTest(
+ IS_METHOD_HANDLE_NOT_NULL, invokeHandleFolded, fallbackFolded), typedGetter);
+ if(nextComponent == null) {
+ return getClassGuardedInvocationComponent(compositeSetter, type);
}
+ return nextComponent.compose(compositeSetter, getClassGuard(type), clazz, ValidationType.EXACT_CLASS);
+ }
+
+ private GuardedInvocationComponent getNamedPropertySetter(final CallSiteDescriptor callSiteDescriptor,
+ final LinkerServices linkerServices, final List operations, final Object name) throws Exception {
+ // Must have two arguments: target object and property value
+ assertParameterCount(callSiteDescriptor, 2);
+ final GuardedInvocation gi = createGuardedDynamicMethodInvocation(callSiteDescriptor, linkerServices,
+ name.toString(), propertySetters);
+ // If we have a property setter with this name, this composite operation will always stop here
+ 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)
+ return getGuardedInvocationComponent(callSiteDescriptor, linkerServices, operations, name);
}
private static final Lookup privateLookup = new Lookup(MethodHandles.lookup());
@@ -571,87 +579,89 @@
private static final MethodHandle GETTER_INVOKER = MethodHandles.invoker(MethodType.methodType(Object.class, Object.class));
private GuardedInvocationComponent getPropertyGetter(final CallSiteDescriptor callSiteDescriptor,
- final LinkerServices linkerServices, final List ops) throws Exception {
- switch(callSiteDescriptor.getNameTokenCount()) {
- case 2: {
- // Since we can't know what kind of a getter we'll get back on different invocations, we'll just
- // conservatively presume Object. Note we can't just coerce to a narrower call site type as the linking
- // runtime might not allow coercing at that call site.
- final MethodType type = callSiteDescriptor.getMethodType().changeReturnType(Object.class);
- // Must have exactly two arguments: receiver and name
- assertParameterCount(callSiteDescriptor, 2);
+ final LinkerServices linkerServices, final List ops, final Object name) throws Exception {
+ if (name == null) {
+ return getUnnamedPropertyGetter(callSiteDescriptor, linkerServices, ops);
+ }
+
+ return getNamedPropertyGetter(callSiteDescriptor, linkerServices, ops, name);
+ }
- // What's below is basically:
- // foldArguments(guardWithTest(isNotNull, invoke(get_handle), null|nextComponent.invocation), get_getter_handle)
- // only with a bunch of method signature adjustments. Basically, retrieve method getter
- // AnnotatedDynamicMethod; if it is non-null, invoke its "handle" field, otherwise either return null,
- // or delegate to next component's invocation.
+ private GuardedInvocationComponent getUnnamedPropertyGetter(final CallSiteDescriptor callSiteDescriptor,
+ final LinkerServices linkerServices, final List ops) throws Exception {
+ // Since we can't know what kind of a getter we'll get back on different invocations, we'll just
+ // conservatively presume Object. Note we can't just coerce to a narrower call site type as the linking
+ // runtime might not allow coercing at that call site.
+ final MethodType type = callSiteDescriptor.getMethodType().changeReturnType(Object.class);
+ // Must have exactly two arguments: receiver and name
+ assertParameterCount(callSiteDescriptor, 2);
- final MethodHandle typedGetter = linkerServices.asType(getPropertyGetterHandle, type.changeReturnType(
- AnnotatedDynamicMethod.class));
- final MethodHandle callSiteBoundMethodGetter = MethodHandles.insertArguments(
- GET_ANNOTATED_METHOD, 1, callSiteDescriptor, linkerServices);
- final MethodHandle callSiteBoundInvoker = MethodHandles.filterArguments(GETTER_INVOKER, 0,
- callSiteBoundMethodGetter);
- // Object(AnnotatedDynamicMethod, Object)->Object(AnnotatedDynamicMethod, T0)
- final MethodHandle invokeHandleTyped = linkerServices.asType(callSiteBoundInvoker,
- MethodType.methodType(type.returnType(), AnnotatedDynamicMethod.class, type.parameterType(0)));
- // Since it's in the target of a fold, drop the unnecessary second argument
- // Object(AnnotatedDynamicMethod, T0)->Object(AnnotatedDynamicMethod, T0, T1)
- final MethodHandle invokeHandleFolded = MethodHandles.dropArguments(invokeHandleTyped, 2,
- type.parameterType(1));
- final GuardedInvocationComponent nextComponent = getGuardedInvocationComponent(callSiteDescriptor,
- linkerServices, ops);
+ // What's below is basically:
+ // foldArguments(guardWithTest(isNotNull, invoke(get_handle), null|nextComponent.invocation), get_getter_handle)
+ // only with a bunch of method signature adjustments. Basically, retrieve method getter
+ // AnnotatedDynamicMethod; if it is non-null, invoke its "handle" field, otherwise either return null,
+ // or delegate to next component's invocation.
+
+ final MethodHandle typedGetter = linkerServices.asType(getPropertyGetterHandle, type.changeReturnType(
+ AnnotatedDynamicMethod.class));
+ final MethodHandle callSiteBoundMethodGetter = MethodHandles.insertArguments(
+ GET_ANNOTATED_METHOD, 1, callSiteDescriptor, linkerServices);
+ final MethodHandle callSiteBoundInvoker = MethodHandles.filterArguments(GETTER_INVOKER, 0,
+ callSiteBoundMethodGetter);
+ // Object(AnnotatedDynamicMethod, Object)->Object(AnnotatedDynamicMethod, T0)
+ final MethodHandle invokeHandleTyped = linkerServices.asType(callSiteBoundInvoker,
+ MethodType.methodType(type.returnType(), AnnotatedDynamicMethod.class, type.parameterType(0)));
+ // Since it's in the target of a fold, drop the unnecessary second argument
+ // Object(AnnotatedDynamicMethod, T0)->Object(AnnotatedDynamicMethod, T0, T1)
+ final MethodHandle invokeHandleFolded = MethodHandles.dropArguments(invokeHandleTyped, 2,
+ type.parameterType(1));
+ final GuardedInvocationComponent nextComponent = getGuardedInvocationComponent(callSiteDescriptor,
+ linkerServices, ops, null);
- final MethodHandle fallbackFolded;
- if(nextComponent == null) {
- // Object(AnnotatedDynamicMethod)->Object(AnnotatedDynamicMethod, T0, T1); returns constant null
- fallbackFolded = MethodHandles.dropArguments(CONSTANT_NULL_DROP_ANNOTATED_METHOD, 1,
- type.parameterList()).asType(type.insertParameterTypes(0, AnnotatedDynamicMethod.class));
- } else {
- // Object(T0, T1)->Object(AnnotatedDynamicMethod, T0, T1); adapts the next component's invocation to
- // drop the extra argument resulting from fold and to change its return type to Object.
- final MethodHandle nextInvocation = nextComponent.getGuardedInvocation().getInvocation();
- final MethodType nextType = nextInvocation.type();
- fallbackFolded = MethodHandles.dropArguments(nextInvocation.asType(
- nextType.changeReturnType(Object.class)), 0, AnnotatedDynamicMethod.class);
- }
+ final MethodHandle fallbackFolded;
+ if(nextComponent == null) {
+ // Object(AnnotatedDynamicMethod)->Object(AnnotatedDynamicMethod, T0, T1); returns constant null
+ fallbackFolded = MethodHandles.dropArguments(CONSTANT_NULL_DROP_ANNOTATED_METHOD, 1,
+ type.parameterList()).asType(type.insertParameterTypes(0, AnnotatedDynamicMethod.class));
+ } else {
+ // Object(T0, T1)->Object(AnnotatedDynamicMethod, T0, T1); adapts the next component's invocation to
+ // drop the extra argument resulting from fold and to change its return type to Object.
+ final MethodHandle nextInvocation = nextComponent.getGuardedInvocation().getInvocation();
+ final MethodType nextType = nextInvocation.type();
+ fallbackFolded = MethodHandles.dropArguments(nextInvocation.asType(
+ nextType.changeReturnType(Object.class)), 0, AnnotatedDynamicMethod.class);
+ }
- // fold(Object(AnnotatedDynamicMethod, T0, T1), AnnotatedDynamicMethod(T0, T1))
- final MethodHandle compositeGetter = MethodHandles.foldArguments(MethodHandles.guardWithTest(
- IS_ANNOTATED_METHOD_NOT_NULL, invokeHandleFolded, fallbackFolded), typedGetter);
- if(nextComponent == null) {
- return getClassGuardedInvocationComponent(compositeGetter, type);
- }
- return nextComponent.compose(compositeGetter, getClassGuard(type), clazz, ValidationType.EXACT_CLASS);
- }
- case 3: {
- // Must have exactly one argument: receiver
- assertParameterCount(callSiteDescriptor, 1);
- // Fixed name
- final AnnotatedDynamicMethod annGetter = propertyGetters.get(callSiteDescriptor.getNameToken(
- CallSiteDescriptor.NAME_OPERAND));
- if(annGetter == null) {
- // We have no such property, always delegate to the next component operation
- return getGuardedInvocationComponent(callSiteDescriptor, linkerServices, ops);
- }
- final MethodHandle getter = annGetter.getInvocation(callSiteDescriptor, linkerServices);
- // NOTE: since property getters (not field getters!) are no-arg, we don't have to worry about them being
- // overloaded in a subclass. Therefore, we can discover the most abstract superclass that has the
- // method, and use that as the guard with Guards.isInstance() for a more stably linked call site. If
- // we're linking against a field getter, don't make the assumption.
- // NOTE: No delegation to the next component operation if we have a property with this name, even if its
- // value is null.
- final ValidationType validationType = annGetter.validationType;
- // TODO: we aren't using the type that declares the most generic getter here!
- return new GuardedInvocationComponent(getter, getGuard(validationType,
- callSiteDescriptor.getMethodType()), clazz, validationType);
- }
- default: {
- // Can't do anything with more than 3 name components
- return null;
- }
+ // fold(Object(AnnotatedDynamicMethod, T0, T1), AnnotatedDynamicMethod(T0, T1))
+ final MethodHandle compositeGetter = MethodHandles.foldArguments(MethodHandles.guardWithTest(
+ IS_ANNOTATED_METHOD_NOT_NULL, invokeHandleFolded, fallbackFolded), typedGetter);
+ if(nextComponent == null) {
+ return getClassGuardedInvocationComponent(compositeGetter, type);
}
+ return nextComponent.compose(compositeGetter, getClassGuard(type), clazz, ValidationType.EXACT_CLASS);
+ }
+
+ private GuardedInvocationComponent getNamedPropertyGetter(final CallSiteDescriptor callSiteDescriptor,
+ final LinkerServices linkerServices, final List ops, final Object name) throws Exception {
+ // Must have exactly one argument: receiver
+ assertParameterCount(callSiteDescriptor, 1);
+ // Fixed name
+ final AnnotatedDynamicMethod annGetter = propertyGetters.get(name.toString());
+ if(annGetter == null) {
+ // We have no such property, always delegate to the next component operation
+ return getGuardedInvocationComponent(callSiteDescriptor, linkerServices, ops, name);
+ }
+ final MethodHandle getter = annGetter.getInvocation(callSiteDescriptor, linkerServices);
+ // NOTE: since property getters (not field getters!) are no-arg, we don't have to worry about them being
+ // overloaded in a subclass. Therefore, we can discover the most abstract superclass that has the
+ // method, and use that as the guard with Guards.isInstance() for a more stably linked call site. If
+ // we're linking against a field getter, don't make the assumption.
+ // NOTE: No delegation to the next component operation if we have a property with this name, even if its
+ // value is null.
+ final ValidationType validationType = annGetter.validationType;
+ // TODO: we aren't using the type that declares the most generic getter here!
+ return new GuardedInvocationComponent(getter, getGuard(validationType,
+ callSiteDescriptor.getMethodType()), clazz, validationType);
}
private MethodHandle getGuard(final ValidationType validationType, final MethodType methodType) {
@@ -679,64 +689,67 @@
private static final MethodHandle OBJECT_IDENTITY = MethodHandles.identity(Object.class);
private GuardedInvocationComponent getMethodGetter(final CallSiteDescriptor callSiteDescriptor,
- final LinkerServices linkerServices, final List ops) throws Exception {
+ final LinkerServices linkerServices, final List ops, final Object name) throws Exception {
// The created method handle will always return a DynamicMethod (or null), but since we don't want that type to
// be visible outside of this linker, declare it to return Object.
final MethodType type = callSiteDescriptor.getMethodType().changeReturnType(Object.class);
- switch(callSiteDescriptor.getNameTokenCount()) {
- case 2: {
- // Must have exactly two arguments: receiver and name
- assertParameterCount(callSiteDescriptor, 2);
- final GuardedInvocationComponent nextComponent = getGuardedInvocationComponent(callSiteDescriptor,
- linkerServices, ops);
- if(nextComponent == null || !InternalTypeUtilities.areAssignable(DynamicMethod.class,
- nextComponent.getGuardedInvocation().getInvocation().type().returnType())) {
- // No next component operation, or it can never produce a dynamic method; just return a component
- // for this operation.
- return getClassGuardedInvocationComponent(linkerServices.asType(getDynamicMethod, type), type);
- }
+ if (name == null) {
+ return getUnnamedMethodGetter(callSiteDescriptor, linkerServices, ops, type);
+ }
+
+ return getNamedMethodGetter(callSiteDescriptor, linkerServices, ops, name, type);
+ }
- // What's below is basically:
- // foldArguments(guardWithTest(isNotNull, identity, nextComponent.invocation), getter) only with a
- // bunch of method signature adjustments. Basically, execute method getter; if it returns a non-null
- // DynamicMethod, use identity to return it, otherwise delegate to nextComponent's invocation.
+ private GuardedInvocationComponent getUnnamedMethodGetter(final CallSiteDescriptor callSiteDescriptor,
+ final LinkerServices linkerServices, final List ops, final MethodType type) throws Exception {
+ // Must have exactly two arguments: receiver and name
+ assertParameterCount(callSiteDescriptor, 2);
+ final GuardedInvocationComponent nextComponent = getGuardedInvocationComponent(callSiteDescriptor,
+ linkerServices, ops, null);
+ if(nextComponent == null || !InternalTypeUtilities.areAssignable(DynamicMethod.class,
+ nextComponent.getGuardedInvocation().getInvocation().type().returnType())) {
+ // No next component operation, or it can never produce a dynamic method; just return a component
+ // for this operation.
+ return getClassGuardedInvocationComponent(linkerServices.asType(getDynamicMethod, type), type);
+ }
+
+ // What's below is basically:
+ // foldArguments(guardWithTest(isNotNull, identity, nextComponent.invocation), getter) only with a
+ // bunch of method signature adjustments. Basically, execute method getter; if it returns a non-null
+ // DynamicMethod, use identity to return it, otherwise delegate to nextComponent's invocation.
- final MethodHandle typedGetter = linkerServices.asType(getDynamicMethod, type);
- // Since it is part of the foldArgument() target, it will have extra args that we need to drop.
- final MethodHandle returnMethodHandle = linkerServices.asType(MethodHandles.dropArguments(
- OBJECT_IDENTITY, 1, type.parameterList()), type.insertParameterTypes(0, Object.class));
- final MethodHandle nextComponentInvocation = nextComponent.getGuardedInvocation().getInvocation();
- // The assumption is that getGuardedInvocationComponent() already asType()'d it correctly modulo the
- // return type.
- assert nextComponentInvocation.type().changeReturnType(type.returnType()).equals(type);
- // Since it is part of the foldArgument() target, we have to drop an extra arg it receives.
- final MethodHandle nextCombinedInvocation = MethodHandles.dropArguments(nextComponentInvocation, 0,
- Object.class);
- // Assemble it all into a fold(guard(isNotNull, identity, nextInvocation), get)
- final MethodHandle compositeGetter = MethodHandles.foldArguments(MethodHandles.guardWithTest(
- IS_DYNAMIC_METHOD, returnMethodHandle, nextCombinedInvocation), typedGetter);
+ final MethodHandle typedGetter = linkerServices.asType(getDynamicMethod, type);
+ // Since it is part of the foldArgument() target, it will have extra args that we need to drop.
+ final MethodHandle returnMethodHandle = linkerServices.asType(MethodHandles.dropArguments(
+ OBJECT_IDENTITY, 1, type.parameterList()), type.insertParameterTypes(0, Object.class));
+ final MethodHandle nextComponentInvocation = nextComponent.getGuardedInvocation().getInvocation();
+ // The assumption is that getGuardedInvocationComponent() already asType()'d it correctly modulo the
+ // return type.
+ assert nextComponentInvocation.type().changeReturnType(type.returnType()).equals(type);
+ // Since it is part of the foldArgument() target, we have to drop an extra arg it receives.
+ final MethodHandle nextCombinedInvocation = MethodHandles.dropArguments(nextComponentInvocation, 0,
+ Object.class);
+ // Assemble it all into a fold(guard(isNotNull, identity, nextInvocation), get)
+ final MethodHandle compositeGetter = MethodHandles.foldArguments(MethodHandles.guardWithTest(
+ IS_DYNAMIC_METHOD, returnMethodHandle, nextCombinedInvocation), typedGetter);
- return nextComponent.compose(compositeGetter, getClassGuard(type), clazz, ValidationType.EXACT_CLASS);
- }
- case 3: {
- // Must have exactly one argument: receiver
- assertParameterCount(callSiteDescriptor, 1);
- final DynamicMethod method = getDynamicMethod(callSiteDescriptor.getNameToken(
- CallSiteDescriptor.NAME_OPERAND));
- if(method == null) {
- // We have no such method, always delegate to the next component
- return getGuardedInvocationComponent(callSiteDescriptor, linkerServices, ops);
- }
- // 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.
- return getClassGuardedInvocationComponent(linkerServices.asType(MethodHandles.dropArguments(
- MethodHandles.constant(Object.class, method), 0, type.parameterType(0)), type), type);
- }
- default: {
- // Can't do anything with more than 3 name components
- return null;
- }
+ return nextComponent.compose(compositeGetter, getClassGuard(type), clazz, ValidationType.EXACT_CLASS);
+ }
+
+ private GuardedInvocationComponent getNamedMethodGetter(final CallSiteDescriptor callSiteDescriptor,
+ final LinkerServices linkerServices, final List ops, final Object name, final MethodType type)
+ throws Exception {
+ // Must have exactly one argument: receiver
+ assertParameterCount(callSiteDescriptor, 1);
+ final DynamicMethod method = getDynamicMethod(name.toString());
+ if(method == null) {
+ // We have no such method, always delegate to the next component
+ return getGuardedInvocationComponent(callSiteDescriptor, linkerServices, ops, name);
}
+ // 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.
+ return getClassGuardedInvocationComponent(linkerServices.asType(MethodHandles.dropArguments(
+ MethodHandles.constant(Object.class, method), 0, type.parameterType(0)), type), type);
}
static class MethodPair {
@@ -765,7 +778,7 @@
private static void assertParameterCount(final CallSiteDescriptor descriptor, final int paramCount) {
if(descriptor.getMethodType().parameterCount() != paramCount) {
- throw new BootstrapMethodError(descriptor.getName() + " must have exactly " + paramCount + " parameters.");
+ throw new BootstrapMethodError(descriptor.getOperation() + " must have exactly " + paramCount + " parameters.");
}
}
@@ -804,7 +817,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
- // "dyn:getMethod" linking).
+ // GET_METHOD linking).
private Object getDynamicMethod(final Object name) {
return getDynamicMethod(String.valueOf(name), methods);
}
diff -r 86b4260bb17a -r 23abd10384a5 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/BeanLinker.java
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/BeanLinker.java Wed Oct 21 10:42:20 2015 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/BeanLinker.java Wed Oct 21 19:33:58 2015 +0200
@@ -91,6 +91,8 @@
import java.util.List;
import java.util.Map;
import jdk.internal.dynalink.CallSiteDescriptor;
+import jdk.internal.dynalink.Operation;
+import jdk.internal.dynalink.StandardOperation;
import jdk.internal.dynalink.beans.GuardedInvocationComponent.ValidationType;
import jdk.internal.dynalink.linker.GuardedInvocation;
import jdk.internal.dynalink.linker.LinkerServices;
@@ -109,7 +111,7 @@
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 "dyn:getLength" is not needed?
+ // REVISIT: is it maybe a code smell that StandardOperation.GET_LENGTH is not needed?
setPropertyGetter("length", GET_ARRAY_LENGTH, ValidationType.IS_ARRAY);
} else if(List.class.isAssignableFrom(clazz)) {
setPropertyGetter("length", GET_COLLECTION_LENGTH, ValidationType.INSTANCE_OF);
@@ -128,27 +130,23 @@
@Override
protected GuardedInvocationComponent getGuardedInvocationComponent(final CallSiteDescriptor callSiteDescriptor,
- final LinkerServices linkerServices, final List operations) throws Exception {
+ final LinkerServices linkerServices, final List operations, final Object name) throws Exception {
final GuardedInvocationComponent superGic = super.getGuardedInvocationComponent(callSiteDescriptor,
- linkerServices, operations);
+ linkerServices, operations, name);
if(superGic != null) {
return superGic;
}
if(operations.isEmpty()) {
return null;
}
- final String op = operations.get(0);
- // dyn:getElem(this, id)
- // id is typically either an int (for arrays and lists) or an object (for maps). linkerServices can provide
- // conversion from call site argument type though.
- if("getElem".equals(op)) {
- return getElementGetter(callSiteDescriptor, linkerServices, pop(operations));
+ final Operation op = operations.get(0);
+ if(op == StandardOperation.GET_ELEMENT) {
+ return getElementGetter(callSiteDescriptor, linkerServices, pop(operations), name);
}
- if("setElem".equals(op)) {
- return getElementSetter(callSiteDescriptor, linkerServices, pop(operations));
+ if(op == StandardOperation.SET_ELEMENT) {
+ return getElementSetter(callSiteDescriptor, linkerServices, pop(operations), name);
}
- // dyn:getLength(this) (works on Java arrays, collections, and maps)
- if("getLength".equals(op)) {
+ if(op == StandardOperation.GET_LENGTH) {
return getLengthGetter(callSiteDescriptor);
}
return null;
@@ -168,11 +166,11 @@
};
private GuardedInvocationComponent getElementGetter(final CallSiteDescriptor callSiteDescriptor,
- final LinkerServices linkerServices, final List operations) throws Exception {
+ final LinkerServices linkerServices, final List operations, final Object name) throws Exception {
final MethodType callSiteType = callSiteDescriptor.getMethodType();
final Class> declaredType = callSiteType.parameterType(0);
final GuardedInvocationComponent nextComponent = getGuardedInvocationComponent(callSiteDescriptor,
- linkerServices, operations);
+ linkerServices, operations, name);
// If declared type of receiver at the call site is already an array, a list 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
@@ -206,22 +204,20 @@
return nextComponent;
}
- // We can have "dyn:getElem:foo", especially in composites, i.e. "dyn:getElem|getProp|getMethod:foo"
- final String fixedKey = getFixedKey(callSiteDescriptor);
// Convert the key to a number if we're working with a list or array
- final Object typedFixedKey;
- if(collectionType != CollectionType.MAP && fixedKey != null) {
- typedFixedKey = convertKeyToInteger(fixedKey, linkerServices);
- if(typedFixedKey == null) {
+ final Object typedName;
+ if(collectionType != CollectionType.MAP && name != null) {
+ typedName = convertKeyToInteger(name, linkerServices);
+ if(typedName == null) {
// key is not numeric, it can never succeed
return nextComponent;
}
} else {
- typedFixedKey = fixedKey;
+ typedName = name;
}
final GuardedInvocation gi = gic.getGuardedInvocation();
- final Binder binder = new Binder(linkerServices, callSiteType, typedFixedKey);
+ final Binder binder = new Binder(linkerServices, callSiteType, typedName);
final MethodHandle invocation = gi.getInvocation();
if(nextComponent == null) {
@@ -263,40 +259,50 @@
validatorClass, validationType);
}
- private static String getFixedKey(final CallSiteDescriptor callSiteDescriptor) {
- return callSiteDescriptor.getNameTokenCount() == 2 ? null : callSiteDescriptor.getNameToken(
- CallSiteDescriptor.NAME_OPERAND);
- }
+ private static Integer convertKeyToInteger(final Object fixedKey, final LinkerServices linkerServices) throws Exception {
+ if (fixedKey instanceof Integer) {
+ return (Integer)fixedKey;
+ }
- private static Object convertKeyToInteger(final String fixedKey, final LinkerServices linkerServices) throws Exception {
- try {
- if(linkerServices.canConvert(String.class, Number.class)) {
+ final Number n;
+ if (fixedKey instanceof Number) {
+ n = (Number)fixedKey;
+ } else {
+ final Class> keyClass = fixedKey.getClass();
+ if(linkerServices.canConvert(keyClass, Number.class)) {
+ final Object val;
try {
- final Object val = linkerServices.getTypeConverter(String.class, Number.class).invoke(fixedKey);
- if(!(val instanceof Number)) {
- return null; // not a number
- }
- final Number n = (Number)val;
- if(n instanceof Integer) {
- return n;
- }
- final int intIndex = n.intValue();
- final double doubleValue = n.doubleValue();
- if(intIndex != doubleValue && !Double.isInfinite(doubleValue)) { // let infinites trigger IOOBE
- return null; // not an exact integer
- }
- return intIndex;
+ val = linkerServices.getTypeConverter(keyClass, Number.class).invoke(fixedKey);
} catch(Exception|Error e) {
throw e;
} catch(final Throwable t) {
throw new RuntimeException(t);
}
+ if(!(val instanceof Number)) {
+ return null; // not a number
+ }
+ n = (Number)val;
+ } else if (fixedKey instanceof String){
+ try {
+ return Integer.valueOf((String)fixedKey);
+ } catch(final NumberFormatException e) {
+ // key is not a number
+ return null;
+ }
+ } else {
+ return null;
}
- return Integer.valueOf(fixedKey);
- } catch(final NumberFormatException e) {
- // key is not a number
- return null;
+ }
+
+ if(n instanceof Integer) {
+ return (Integer)n;
}
+ final int intIndex = n.intValue();
+ final double doubleValue = n.doubleValue();
+ if(intIndex != doubleValue && !Double.isInfinite(doubleValue)) { // let infinites trigger IOOBE
+ return null; // not an exact integer
+ }
+ return intIndex;
}
private static MethodHandle convertArgToInt(final MethodHandle mh, final LinkerServices ls, final CallSiteDescriptor desc) {
@@ -389,7 +395,7 @@
MethodType.methodType(Object.class, Object.class, Object.class));
private GuardedInvocationComponent getElementSetter(final CallSiteDescriptor callSiteDescriptor,
- final LinkerServices linkerServices, final List operations) throws Exception {
+ final LinkerServices linkerServices, final List operations, final Object name) throws Exception {
final MethodType callSiteType = callSiteDescriptor.getMethodType();
final Class> declaredType = callSiteType.parameterType(0);
@@ -431,27 +437,25 @@
// as maps will always succeed in setting the element and will never need to fall back to the next component
// operation.
final GuardedInvocationComponent nextComponent = collectionType == CollectionType.MAP ? null : getGuardedInvocationComponent(
- callSiteDescriptor, linkerServices, operations);
+ callSiteDescriptor, linkerServices, operations, name);
if(gic == null) {
return nextComponent;
}
- // We can have "dyn:setElem:foo", especially in composites, i.e. "dyn:setElem|setProp:foo"
- final String fixedKey = getFixedKey(callSiteDescriptor);
// Convert the key to a number if we're working with a list or array
- final Object typedFixedKey;
- if(collectionType != CollectionType.MAP && fixedKey != null) {
- typedFixedKey = convertKeyToInteger(fixedKey, linkerServices);
- if(typedFixedKey == null) {
+ final Object typedName;
+ if(collectionType != CollectionType.MAP && name != null) {
+ typedName = convertKeyToInteger(name, linkerServices);
+ if(typedName == null) {
// key is not numeric, it can never succeed
return nextComponent;
}
} else {
- typedFixedKey = fixedKey;
+ typedName = name;
}
final GuardedInvocation gi = gic.getGuardedInvocation();
- final Binder binder = new Binder(linkerServices, callSiteType, typedFixedKey);
+ final Binder binder = new Binder(linkerServices, callSiteType, typedName);
final MethodHandle invocation = gi.getInvocation();
if(nextComponent == null) {
@@ -510,7 +514,7 @@
private static void assertParameterCount(final CallSiteDescriptor descriptor, final int paramCount) {
if(descriptor.getMethodType().parameterCount() != paramCount) {
- throw new BootstrapMethodError(descriptor.getName() + " must have exactly " + paramCount + " parameters.");
+ throw new BootstrapMethodError(descriptor.getOperation() + " must have exactly " + paramCount + " parameters.");
}
}
}
diff -r 86b4260bb17a -r 23abd10384a5 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/BeansLinker.java
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/BeansLinker.java Wed Oct 21 10:42:20 2015 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/BeansLinker.java Wed Oct 21 19:33:58 2015 +0200
@@ -86,8 +86,8 @@
import java.lang.invoke.MethodHandles.Lookup;
import java.util.Collection;
import java.util.Collections;
-import jdk.internal.dynalink.CallSiteDescriptor;
import jdk.internal.dynalink.DynamicLinkerFactory;
+import jdk.internal.dynalink.StandardOperation;
import jdk.internal.dynalink.linker.GuardedInvocation;
import jdk.internal.dynalink.linker.GuardingDynamicLinker;
import jdk.internal.dynalink.linker.LinkRequest;
@@ -101,24 +101,26 @@
* linker will:
*
*
expose all public methods of form {@code setXxx()}, {@code getXxx()},
- * and {@code isXxx()} as property setters and getters for {@code dyn:setProp}
- * and {@code dyn:getProp} operations;
- *
expose all public methods for invocation through {@code dyn:callMethod}
- * operation;
- *
expose all public methods for retrieval for {@code dyn:getMethod}
- * operation; the methods thus retrieved can then be invoked using
- * {@code dyn:call};
+ * and {@code isXxx()} as property setters and getters for
+ * {@link StandardOperation#SET_PROPERTY} and {@link StandardOperation#GET_PROPERTY}
+ * operations;
+ *
expose all public methods for invocation through
+ * {@link StandardOperation#CALL_METHOD} operation;
+ *
expose all public methods for retrieval for
+ * {@link StandardOperation#GET_METHOD} operation; the methods thus retrieved
+ * can then be invoked using {@link StandardOperation#CALL}.
*
expose all public fields as properties, unless there are getters or
* setters for the properties of the same name;
- *
expose {@code dyn:getLength}, {@code dyn:getElem} and
- * {@code dyn:setElem} on native Java arrays, as well as {@link java.util.List}
- * and {@link java.util.Map} objects; ({@code dyn:getLength} works on any
- * {@link java.util.Collection});
+ *
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});
*
expose a virtual property named {@code length} on Java arrays;
- *
expose {@code dyn: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 representing the
- * length of the array to create);
+ *
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
+ * representing the length of the array to create);
*
expose static methods, fields, and properties of classes in a similar
* manner to how instance method, fields, and properties are exposed, on
* {@link StaticClass} objects.
@@ -129,15 +131,15 @@
* 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 dyn:getMethod: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 attach that
- * functionality to but if a language wishes to provide this functionality, it
- * can use {@link #getConstructorMethod(Class, String)} as a useful building
- * block for it.
+ * {@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
+ * 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
+ * attach that functionality to but if a language wishes to provide this
+ * functionality, it can use {@link #getConstructorMethod(Class, String)} as a
+ * useful building block for it.
*
Variable argument invocation is handled for both methods
* and constructors.
*
Caller sensitive methods can be linked as long as they
@@ -182,7 +184,7 @@
/**
* Returns true if the object is a Java dynamic method (e.g., one
- * obtained through a {@code dyn:getMethod} call 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)}.
*
@@ -295,13 +297,6 @@
@Override
public GuardedInvocation getGuardedInvocation(final LinkRequest request, final LinkerServices linkerServices)
throws Exception {
- final CallSiteDescriptor callSiteDescriptor = request.getCallSiteDescriptor();
- final int l = callSiteDescriptor.getNameTokenCount();
- // All names conforming to the dynalang MOP should have at least two tokens, the first one being "dyn"
- if(l < 2 || "dyn" != callSiteDescriptor.getNameToken(CallSiteDescriptor.SCHEME)) {
- return null;
- }
-
final Object receiver = request.getReceiver();
if(receiver == null) {
// Can't operate on null
diff -r 86b4260bb17a -r 23abd10384a5 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/DynamicMethodLinker.java
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/DynamicMethodLinker.java Wed Oct 21 10:42:20 2015 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/DynamicMethodLinker.java Wed Oct 21 19:33:58 2015 +0200
@@ -86,6 +86,9 @@
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import jdk.internal.dynalink.CallSiteDescriptor;
+import jdk.internal.dynalink.NamedOperation;
+import jdk.internal.dynalink.Operation;
+import jdk.internal.dynalink.StandardOperation;
import jdk.internal.dynalink.linker.GuardedInvocation;
import jdk.internal.dynalink.linker.LinkRequest;
import jdk.internal.dynalink.linker.LinkerServices;
@@ -93,8 +96,9 @@
import jdk.internal.dynalink.linker.support.Guards;
/**
- * Simple linker that implements the "dyn:call" operation for {@link DynamicMethod} objects - the objects returned by
- * "dyn:getMethod" from {@link AbstractJavaLinker}.
+ * Simple linker that implements the {@link StandardOperation#CALL} operation
+ * for {@link DynamicMethod} objects - the objects returned by
+ * {@link StandardOperation#GET_METHOD} through {@link AbstractJavaLinker}.
*/
class DynamicMethodLinker implements TypeBasedGuardingDynamicLinker {
@Override
@@ -108,19 +112,16 @@
if(!(receiver instanceof DynamicMethod)) {
return null;
}
- final CallSiteDescriptor desc = linkRequest.getCallSiteDescriptor();
- if(desc.getNameTokenCount() != 2 && desc.getNameToken(CallSiteDescriptor.SCHEME) != "dyn") {
- return null;
- }
- final String operator = desc.getNameToken(CallSiteDescriptor.OPERATOR);
final DynamicMethod dynMethod = (DynamicMethod)receiver;
final boolean constructor = dynMethod.isConstructor();
final MethodHandle invocation;
- if (operator == "call" && !constructor) {
+ final CallSiteDescriptor desc = linkRequest.getCallSiteDescriptor();
+ final Operation op = NamedOperation.getBaseOperation(desc.getOperation());
+ if (op == StandardOperation.CALL && !constructor) {
invocation = dynMethod.getInvocation(desc.changeMethodType(
desc.getMethodType().dropParameterTypes(0, 1)), linkerServices);
- } else if (operator == "new" && constructor) {
+ } else if (op == StandardOperation.NEW && constructor) {
final MethodHandle ctorInvocation = dynMethod.getInvocation(desc, linkerServices);
if(ctorInvocation == null) {
return null;
diff -r 86b4260bb17a -r 23abd10384a5 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/StaticClass.java
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/StaticClass.java Wed Oct 21 10:42:20 2015 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/StaticClass.java Wed Oct 21 19:33:58 2015 +0200
@@ -85,16 +85,17 @@
import java.io.Serializable;
import java.util.Objects;
+import jdk.internal.dynalink.StandardOperation;
/**
* Object that allows access to the static members of a class (its static
* methods, properties, and fields), as well as construction of instances using
- * {@code "dyn:new"} operation. In Dynalink, {@link Class} objects are not
- * treated specially and act as ordinary Java objects; you can use e.g. {@code
- * "dyn:getProp:superclass"} as a property getter to invoke
- * {@code clazz.getSuperclass()}. On the other hand, you can not use
+ * {@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
+ * 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 "dyn:new"}. This is consistent with how
+ * instances of the class using {@code NEW}. This is consistent with how
* {@code Class} objects behave in Java: in Java, you write e.g.
* {@code new BitSet()} instead of {@code new BitSet.class()}. Similarly, you
* write {@code System.out} and not {@code System.class.out}. It is this aspect
@@ -119,10 +120,10 @@
* constructors taking a single int argument and create an array of the
* specified size.
*
- * If the class has several constructors, {@code dyn:new} on {@code StaticClass}
- * will try to select the most specific applicable constructor. You might want
- * to expose a mechanism in your language for selecting a constructor with an
- * explicit signature through
+ * If the class has several constructors, {@link StandardOperation#NEW} on
+ * {@code StaticClass} will try to select the most specific applicable
+ * constructor. You might want to expose a mechanism in your language for
+ * selecting a constructor with an explicit signature through
* {@link BeansLinker#getConstructorMethod(Class, String)}.
*/
public final class StaticClass implements Serializable {
diff -r 86b4260bb17a -r 23abd10384a5 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/StaticClassLinker.java
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/StaticClassLinker.java Wed Oct 21 10:42:20 2015 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/StaticClassLinker.java Wed Oct 21 19:33:58 2015 +0200
@@ -90,6 +90,8 @@
import java.util.Arrays;
import java.util.Collection;
import jdk.internal.dynalink.CallSiteDescriptor;
+import jdk.internal.dynalink.NamedOperation;
+import jdk.internal.dynalink.StandardOperation;
import jdk.internal.dynalink.beans.GuardedInvocationComponent.ValidationType;
import jdk.internal.dynalink.linker.GuardedInvocation;
import jdk.internal.dynalink.linker.LinkRequest;
@@ -150,8 +152,7 @@
return gi;
}
final CallSiteDescriptor desc = request.getCallSiteDescriptor();
- final String op = desc.getNameToken(CallSiteDescriptor.OPERATOR);
- if("new" == op && constructor != null) {
+ if(NamedOperation.getBaseOperation(desc.getOperation()) == StandardOperation.NEW && constructor != null) {
final MethodHandle ctorInvocation = constructor.getInvocation(desc, linkerServices);
if(ctorInvocation != null) {
return new GuardedInvocation(ctorInvocation, getClassGuard(desc.getMethodType()));
diff -r 86b4260bb17a -r 23abd10384a5 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/package-info.java
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/package-info.java Wed Oct 21 10:42:20 2015 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/package-info.java Wed Oct 21 19:33:58 2015 +0200
@@ -129,7 +129,7 @@
* bytecode would look something like this:
*
* aload 2 // load "obj" on stack
- * invokedynamic "dyn:getProp: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"
*
* In order to link the {@code invokedynamic} instruction, we need a bootstrap
@@ -145,7 +145,11 @@
* public static CallSite bootstrap(MethodHandles.Lookup lookup, String name, MethodType type) {
* return dynamicLinker.link(
* new SimpleRelinkableCallSite(
- * new CallSiteDescriptor(lookup, name, type)));
+ * new CallSiteDescriptor(lookup, parseOperation(name), type)));
+ * }
+ *
+ * private static Operation parseOperation(String name) {
+ * ...
* }
* }
*
@@ -164,9 +168,16 @@
* type. {@link jdk.internal.dynalink.support.SimpleRelinkableCallSite} and
* {@link jdk.internal.dynalink.support.ChainedCallSite} (not used in the above example)
* are two implementations already provided by the library.
- *
Finally, Dynalink uses {@link jdk.internal.dynalink.CallSiteDescriptor} objects to
- * preserve the parameters to the bootstrap method as it will need them whenever
- * it needs to relink a call site.
+ *
Dynalink uses {@link jdk.internal.dynalink.CallSiteDescriptor} objects to
+ * preserve the parameters to the bootstrap method: the lookup and the method type,
+ * as it will need them whenever it needs to relink a call site.
+ *
Dynalink uses {@link jdk.internal.dynalink.Operation} objects to express
+ * 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"}
+ * in the call site's name into a named property getter operation object as
+ * {@code new NamedOperation(StandardOperation.GET_PROPERTY), "color")}.
*
*
What can you already do with the above setup? {@code DynamicLinkerFactory}
* by default creates a {@code DynamicLinker} that can link Java objects with the
@@ -217,158 +228,21 @@
* them with representations of dynamic operations in the interpreted program
* (e.g. a typical representation would be some node objects in a syntax tree).
*
Available operations
- * The table below contains all operations defined by Dynalink. All of them have
- * the prefix {@code "dyn:"} and this prefix is reserved for Dynalink use, with
- * potential of future extensions. Elements of the name are separated with the
- * COLON character. {@code $id} is used as a placeholder for an identifier for
- * those operations that contain an identifier as part of their name.
- * Identifiers in operation names need to be
- * {@link jdk.internal.dynalink.support.NameCodec#encode(String) encoded}. Signatures are
- * expressed in the usual JVM
- * {@code (parameter-type1, parameter-type2, ...)return-type} format. The type
- * "any" means that any type, either primitive or reference can be used (with
- * obvious JVM limitation that {@code void} is disallowed as a parameter type
- * but allowed as a return type.
- *
- *
- *
- *
- *
Name
- *
Signature
- *
Semantics
- *
- *
- *
- *
- *
{@code dyn:getProp:$id}
- *
(any)any
- *
Retrieve the value of a named property on the object, with the
- * receiver being passed as the argument, and the property identifier
- * encoded in the operation name as {@code $id}.
- *
- *
- *
{@code dyn:getProp}
- *
(any, any)any
- *
Retrieve the value of a named property on the object, with the
- * receiver being passed as the first, and the property identifier
- * being passed as the second argument.
- *
- *
- *
{@code dyn:setProp:$id}
- *
(any, any)void
- *
Set the value of a named property on the object, with the
- * receiver being passed as the first, and the value to set being
- * passed as the second argument, with the property identifier
- * encoded in the operation name as {@code $id}.
- *
- *
- *
{@code dyn:setProp}
- *
(any, any, any)void
- *
Set the value of a named property on the object, with the
- * receiver being passed as the first, the property identifier as the
- * second, and the value to set as the third argument.
- *
- *
- *
{@code dyn:getElem:$id}
- *
(any)any
- *
Retrieve an element of a collection object (array, list, map,
- * etc.) with a fixed key encoded in the operation name as {@code $id}.
- * In this form, the key is necessarily a string as it is part of the
- * operation name, but runtimes are allowed to parse it as a number
- * literal when linking to a collection using numeric indices.
- *
- *
- *
{@code dyn:getElem}
- *
(any, any)any
- *
Retrieve an element of a collection object (array, list, map,
- * etc.) with the receiver being passed as the first and the index
- * passed as the second argument.
- *
- *
- *
{@code dyn:setElem:$id}
- *
(any, any)void
- *
Set an element of a collection object (array, list, map,
- * etc.) with a fixed key encoded in the operation name as {@code $id}.
- * The receiver is passed as the first, and the new element value as
- * the second argument. In this form, the key is necessarily a string
- * as it is part of the operation name, but runtimes are allowed to
- * parse it as a number literal when linking to a collection using
- * numeric indices.
- *
- *
- *
{@code dyn:setElem}
- *
(any, any, any)void
- *
Set an element of a collection object (array, list, map,
- * etc.) with the receiver being passed as the first, the index
- * passed as the second, and the new element value as the third argument.
- *
- *
- *
{@code dyn:getMethod:$id}
- *
(any)any
- *
Retrieve a named method on the object, identified by {@code $id}.
- * It is expected that at least the {@code "dyn:call"} operation is
- * applicable to the returned value.
- *
- *
- *
{@code dyn:getMethod}
- *
(any, any)any
- *
Retrieve a named method on the object, with the receiver passed as
- * the first and the name of the method passed as the second argument.
- * It is expected that {@code "dyn:call"} operation is applicable to
- * the returned value.
- *
- *
- *
{@code dyn:call}
- *
(any[, any, any,...])any
- *
Call a callable (method, function, etc.). The first argument
- * is the callable itself, and the rest are arguments passed to the
- * call. If the callable is an instance method, the {@code this}
- * argument should be the second argument, immediately following the
- * callable.
- *
- *
- *
{@code dyn:callMethod:$id}
- *
(any[, any, any,...])any
- *
Call a named instance method on an object. The first argument
- * is the object on which the method is invoked, and the rest are
- * arguments passed to the call. Note that this method is not strictly
- * necessary, as it can be implemented as a composition of
- * {@code dyn:getMethod:$id} and {@code dyn:call}. It is a frequent
- * enough object-oriented pattern so it is convenient to provide it as
- * a separate operation.
- *
- *
- *
{@code dyn:new}
- *
(any[, any, any,...])any
- *
Call a constructor. The first argument is the constructor itself,
- * and the rest are arguments passed to the constructor call.
- *
- *
- *
+ * Dynalink defines several standard operations in its
+ * {@link jdk.internal.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.internal.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".
*
Composite operations
* Some languages might not have separate namespaces on objects for
- * properties, elements, and methods. Dynalink supports specifying composite
- * operations for this purpose using the VERTICAL LINE character as the
- * separator. Typical syntax would be e.g.
- * {@code "dyn:getProp|getElem|getMethod:color"}. Any combination of
- * {@code "getProp"}, {@code "getElem"}, and {@code "getMethod"} in any order can be
- * specified. The semantics of this is "return the first matching member, trying
- * them in the specified order". Similarly, {@code "setProp"} and {@code "setElem"}
- * can be combined too in both orders. Only compositions consisting of getter
- * operations only and setter operations only are allowed. They can either have
- * an identifier encoded in the name or not.
- *
- * Even if the language itself doesn't distinguish some of the namespaces, it
- * can be helpful to map different syntaxes to different compositions. E.g.
- * source expression {@code obj.color} could map to
- * {@code "dyn:getProp|getElem|getMethod:color"}, but a different source
- * expression that looks like collection element access {@code obj[key]} could
- * be expressed instead as {@code "dyn:getElem|getProp|getMethod"}. Finally, if
- * the retrieved value is subsequently called, then it makes sense to bring
- * {@code getMethod} to the front of the list: the getter part of the source
- * expression {@code obj.color()} should be
- * {@code "dyn:getMethod|getProp|getElem:color"} and the one for
- * {@code obj[key]()} should be {@code "dyn:getMethod|getElem|getProp"}.
+ * 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.internal.dynalink.CompositeOperation} class.
*
Language-specific linkers
* Languages that define their own object model different than the JVM
* class-based model and/or use their own type conversions will need to create
diff -r 86b4260bb17a -r 23abd10384a5 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/NameCodec.java
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/NameCodec.java Wed Oct 21 10:42:20 2015 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/NameCodec.java Wed Oct 21 19:33:58 2015 +0200
@@ -83,27 +83,13 @@
package jdk.internal.dynalink.support;
-import jdk.internal.dynalink.CallSiteDescriptor;
/**
* Implements the name mangling and demangling as specified by John Rose's
* "Symbolic Freedom in the VM" article. It is recommended
- * that implementers of languages on the JVM uniformly adopt this for symbolic
- * interoperability between languages. Normally, you would mangle the names as
- * you're generating bytecode, and then demangle them when you're creating
- * {@link CallSiteDescriptor} objects. Note that you are expected to mangle
- * individual tokens, and not the whole name at the call site, i.e. the colon
- * character normally separating the tokens is never mangled. I.e. you wouldn't
- * mangle {@code dyn:getProp:color} into {@code dyn\!getProp\!color}, but you
- * would mangle {@code dyn:getProp:color$} into {@code dyn:getProp:\=color\%}
- * (only mangling the individual token containing the symbol {@code color$}).
- * {@link CallSiteDescriptor#tokenizeName(String)} already uses
- * {@link #decode(String)} to perform demangling on the passed names. If you use
- * that method when creating call site descriptors, (it is recommended that you
- * do), then you have demangling handled for you already, and only need to
- * ensure that you mangle the names using {@link #encode(String)} when you're
- * emitting them in the bytecode.
+ * target="_blank">"Symbolic Freedom in the VM" article. Normally, you would
+ * mangle the names in the call sites as you're generating bytecode, and then
+ * demangle them when you receive them in bootstrap methods.
*/
public final class NameCodec {
private static final char ESCAPE_CHAR = '\\';
@@ -180,7 +166,7 @@
* @return the demangled form of the symbolic name.
*/
public static String decode(final String name) {
- if(name.charAt(0) != ESCAPE_CHAR) {
+ if(name.isEmpty() || name.charAt(0) != ESCAPE_CHAR) {
return name;
}
final int l = name.length();
diff -r 86b4260bb17a -r 23abd10384a5 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java Wed Oct 21 10:42:20 2015 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java Wed Oct 21 19:33:58 2015 +0200
@@ -683,9 +683,9 @@
// (in)equality operators need the specialized JSType.toNumberFor[Strict]Equals. E.g. in the code snippet
// "i < obj.size" (where i is primitive and obj.size is statically an object), ".size" will thus be allowed
// to compile as:
- // invokedynamic dyn:getProp|getElem|getMethod:size(Object;)D
+ // invokedynamic GET_PROPERTY:size(Object;)D
// instead of the more costly:
- // invokedynamic dyn:getProp|getElem|getMethod:size(Object;)Object
+ // invokedynamic GET_PROPERTY:size(Object;)Object
// invokestatic JSType.toNumber(Object)D
// Note also that even if this is allowed, we're only using it on operands that are non-optimistic, as
// otherwise the logic for determining effective optimistic-ness would turn an optimistic double return
@@ -1494,11 +1494,11 @@
void loadStack() {
/*
* We want to load 'eval' to check if it is indeed global builtin eval.
- * If this eval call is inside a 'with' statement, dyn:getMethod|getProp|getElem
+ * If this eval call is inside a 'with' statement, GET_METHOD_PROPERTY
* would be generated if ident is a "isFunction". But, that would result in a
* bound function from WithObject. We don't want that as bound function as that
* won't be detected as builtin eval. So, we make ident as "not a function" which
- * results in "dyn:getProp|getElem|getMethod" being generated and so WithObject
+ * results in GET_PROPERTY being generated and so WithObject
* would return unbounded eval function.
*
* Example:
@@ -1525,7 +1525,7 @@
method._goto(invoke_direct_eval);
method.label(is_not_eval);
- // load this time but with dyn:getMethod|getProp|getElem
+ // load this time but with GET_METHOD_PROPERTY
loadExpressionAsObject(ident); // Type.OBJECT as foo() makes no sense if foo == 3
// This is some scope 'eval' or global eval replaced by user
// but not the built-in ECMAScript 'eval' function call
diff -r 86b4260bb17a -r 23abd10384a5 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/MethodEmitter.java
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/MethodEmitter.java Wed Oct 21 10:42:20 2015 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/MethodEmitter.java Wed Oct 21 19:33:58 2015 +0200
@@ -107,6 +107,7 @@
import jdk.nashorn.internal.runtime.ScriptRuntime;
import jdk.nashorn.internal.runtime.UnwarrantedOptimismException;
import jdk.nashorn.internal.runtime.linker.Bootstrap;
+import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
import jdk.nashorn.internal.runtime.logging.DebugLogger;
import jdk.nashorn.internal.runtime.options.Options;
@@ -124,6 +125,8 @@
* including bytecode stack contents
*/
public class MethodEmitter {
+ private static final String EMPTY_NAME = NameCodec.encode("");
+
/** The ASM MethodVisitor we are plugged into */
private final MethodVisitor method;
@@ -2148,8 +2151,8 @@
debug("dynamic_new", "argcount=", argCount);
final String signature = getDynamicSignature(Type.OBJECT, argCount);
method.visitInvokeDynamicInsn(
- msg != null && msg.length() < LARGE_STRING_THRESHOLD? "dyn:new:" + NameCodec.encode(msg) : "dyn:new",
- signature, LINKERBOOTSTRAP, flags);
+ msg != null && msg.length() < LARGE_STRING_THRESHOLD? NameCodec.encode(msg) : EMPTY_NAME,
+ signature, LINKERBOOTSTRAP, flags | NashornCallSiteDescriptor.NEW);
pushType(Type.OBJECT); //TODO fix result type
return this;
}
@@ -2182,8 +2185,8 @@
final String signature = getDynamicSignature(returnType, argCount); // +1 because the function itself is the 1st parameter for dynamic calls (what you call - call target)
debug(" signature", signature);
method.visitInvokeDynamicInsn(
- msg != null && msg.length() < LARGE_STRING_THRESHOLD? "dyn:call:" + NameCodec.encode(msg) : "dyn:call",
- signature, LINKERBOOTSTRAP, flags);
+ msg != null && msg.length() < LARGE_STRING_THRESHOLD? NameCodec.encode(msg) : EMPTY_NAME,
+ signature, LINKERBOOTSTRAP, flags | NashornCallSiteDescriptor.CALL);
pushType(returnType);
return this;
@@ -2220,8 +2223,8 @@
}
popType(Type.SCOPE);
- method.visitInvokeDynamicInsn(dynGetOperation(isMethod, isIndex) + ':' + NameCodec.encode(name),
- Type.getMethodDescriptor(type, Type.OBJECT), LINKERBOOTSTRAP, flags);
+ method.visitInvokeDynamicInsn(NameCodec.encode(name),
+ Type.getMethodDescriptor(type, Type.OBJECT), LINKERBOOTSTRAP, flags | dynGetOperation(isMethod, isIndex));
pushType(type);
convert(valueType); //most probably a nop
@@ -2253,8 +2256,8 @@
popType(type);
popType(Type.SCOPE);
- method.visitInvokeDynamicInsn(dynSetOperation(isIndex) + ':' + NameCodec.encode(name),
- methodDescriptor(void.class, Object.class, type.getTypeClass()), LINKERBOOTSTRAP, flags);
+ method.visitInvokeDynamicInsn(NameCodec.encode(name),
+ methodDescriptor(void.class, Object.class, type.getTypeClass()), LINKERBOOTSTRAP, flags | dynSetOperation(isIndex));
}
/**
@@ -2287,7 +2290,7 @@
final String signature = Type.getMethodDescriptor(resultType, Type.OBJECT /*e.g STRING->OBJECT*/, index);
- method.visitInvokeDynamicInsn(dynGetOperation(isMethod, true), signature, LINKERBOOTSTRAP, flags);
+ method.visitInvokeDynamicInsn(EMPTY_NAME, signature, LINKERBOOTSTRAP, flags | dynGetOperation(isMethod, true));
pushType(resultType);
if (result.isBoolean()) {
@@ -2331,7 +2334,9 @@
final Type receiver = popType(Type.OBJECT);
assert receiver.isObject();
- method.visitInvokeDynamicInsn("dyn:setElem|setProp", methodDescriptor(void.class, receiver.getTypeClass(), index.getTypeClass(), value.getTypeClass()), LINKERBOOTSTRAP, flags);
+ method.visitInvokeDynamicInsn(EMPTY_NAME,
+ methodDescriptor(void.class, receiver.getTypeClass(), index.getTypeClass(), value.getTypeClass()),
+ LINKERBOOTSTRAP, flags | NashornCallSiteDescriptor.SET_ELEMENT);
}
/**
@@ -2501,16 +2506,16 @@
}
}
- private static String dynGetOperation(final boolean isMethod, final boolean isIndex) {
+ private static int dynGetOperation(final boolean isMethod, final boolean isIndex) {
if (isMethod) {
- return isIndex ? "dyn:getMethod|getElem|getProp" : "dyn:getMethod|getProp|getElem";
+ return isIndex ? NashornCallSiteDescriptor.GET_METHOD_ELEMENT : NashornCallSiteDescriptor.GET_METHOD_PROPERTY;
} else {
- return isIndex ? "dyn:getElem|getProp|getMethod" : "dyn:getProp|getElem|getMethod";
+ return isIndex ? NashornCallSiteDescriptor.GET_ELEMENT : NashornCallSiteDescriptor.GET_PROPERTY;
}
}
- private static String dynSetOperation(final boolean isIndex) {
- return isIndex ? "dyn:setElem|setProp" : "dyn:setProp|setElem";
+ private static int dynSetOperation(final boolean isIndex) {
+ return isIndex ? NashornCallSiteDescriptor.SET_ELEMENT : NashornCallSiteDescriptor.SET_PROPERTY;
}
private Type emitLocalVariableConversion(final LocalVariableConversion conversion, final boolean onlySymbolLiveValue) {
diff -r 86b4260bb17a -r 23abd10384a5 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/FunctionCall.java
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/FunctionCall.java Wed Oct 21 10:42:20 2015 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/FunctionCall.java Wed Oct 21 19:33:58 2015 +0200
@@ -25,14 +25,16 @@
package jdk.nashorn.internal.ir;
+import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
+
/**
* Interface used by AccessNodes, IndexNodes and IdentNodes to signal that when evaluated, their value will be treated
* as a function and immediately invoked, e.g. {@code foo()}, {@code foo.bar()} or {@code foo[bar]()}. Used to customize
* the priority of composite dynamic operations when emitting {@code INVOKEDYNAMIC} instructions that implement them,
* namely prioritize {@code getMethod} over {@code getElem} or {@code getProp}. An access or ident node with isFunction
- * set to true will be emitted as {@code dyn:getMethod|getProp|getElem} while one with it set to false will be emitted
- * as {@code dyn:getProp|getElem|getMethod}. Similarly, an index node with isFunction set to true will be emitted as
- * {@code dyn:getMethod|getElem|getProp} while the one set to false will be emitted as {@code dyn:getElem|getProp|getMethod}.
+ * set to true will be emitted as {@link NashornCallSiteDescriptor#GET_METHOD_PROPERTY} while one with it set to false will be emitted
+ * as {@link NashornCallSiteDescriptor#GET_PROPERTY}. Similarly, an index node with isFunction set to true will be emitted as
+ * {@link NashornCallSiteDescriptor#GET_METHOD_ELEMENT} while the one set to false will be emitted as {@link NashornCallSiteDescriptor#GET_ELEMENT}.
*/
public interface FunctionCall {
/**
diff -r 86b4260bb17a -r 23abd10384a5 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/debug/NashornTextifier.java
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/debug/NashornTextifier.java Wed Oct 21 10:42:20 2015 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/debug/NashornTextifier.java Wed Oct 21 19:33:58 2015 +0200
@@ -39,6 +39,7 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
+import jdk.internal.dynalink.support.NameCodec;
import jdk.internal.org.objectweb.asm.Attribute;
import jdk.internal.org.objectweb.asm.Handle;
import jdk.internal.org.objectweb.asm.Label;
@@ -48,6 +49,7 @@
import jdk.internal.org.objectweb.asm.util.Printer;
import jdk.internal.org.objectweb.asm.util.TraceSignatureVisitor;
import jdk.nashorn.internal.runtime.ScriptEnvironment;
+import jdk.nashorn.internal.runtime.linker.Bootstrap;
import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
/**
@@ -55,6 +57,7 @@
* Also supports dot formats if --print-code has arguments
*/
public final class NashornTextifier extends Printer {
+ private static final String BOOTSTRAP_CLASS_NAME = Bootstrap.class.getName().replace('.', '/');
private String currentClassName;
private Iterator