nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/CallSiteDescriptor.java
changeset 33333 0bad500ce4e0
parent 33331 273e6a10de22
child 33339 334cd3ebfa5e
equal deleted inserted replaced
33332:f180be6368d8 33333:0bad500ce4e0
    81        ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    81        ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    82 */
    82 */
    83 
    83 
    84 package jdk.internal.dynalink;
    84 package jdk.internal.dynalink;
    85 
    85 
       
    86 import java.lang.invoke.CallSite;
    86 import java.lang.invoke.MethodHandles;
    87 import java.lang.invoke.MethodHandles;
    87 import java.lang.invoke.MethodHandles.Lookup;
    88 import java.lang.invoke.MethodHandles.Lookup;
    88 import java.lang.invoke.MethodType;
    89 import java.lang.invoke.MethodType;
    89 import java.util.Arrays;
    90 import java.util.Arrays;
    90 import java.util.Collections;
    91 import java.util.Collections;
    91 import java.util.List;
    92 import java.util.List;
    92 import java.util.StringTokenizer;
    93 import java.util.StringTokenizer;
    93 import jdk.internal.dynalink.support.NameCodec;
    94 import jdk.internal.dynalink.support.NameCodec;
    94 
    95 
    95 /**
    96 /**
    96  * An immutable descriptor of a call site. It is an immutable object that contains all the information about a call
    97  * Interface for objects describing a call site. A call site descriptor contains
    97  * site: the class performing the lookups, the name of the method being invoked, and the method signature. Call site descriptors are used in this library in place of passing a real call site to
    98  * all the information about a call site necessary for linking it: the class
    98  * guarding linkers so they aren't tempted to directly manipulate the call sites. The constructors of built-in
    99  * performing the lookups, the name of the method being invoked, and the method
    99  * {@link RelinkableCallSite} implementations all need a call site descriptor. Even if you create your own call site
   100  * signature. Call site descriptors are used in Dynalink in place of passing
   100  * descriptors consider using {@link CallSiteDescriptor#tokenizeName(String)} in your implementation.
   101  * {@link CallSite} objects to linkers so they can't directly manipulate them.
       
   102  * The constructors of built-in {@link RelinkableCallSite} implementations all
       
   103  * take a call site descriptor. Call site descriptors must be immutable.
   101  */
   104  */
   102 public interface CallSiteDescriptor {
   105 public interface CallSiteDescriptor {
   103     /**
   106     /**
   104      * A permission to invoke the {@link #getLookup()} method. It is named {@code "dynalink.getLookup"}.
   107      * A runtime permission to invoke the {@link #getLookup()} method. It is
   105      */
   108      * named {@code "dynalink.getLookup"}.
   106     public static final RuntimePermission GET_LOOKUP_PERMISSION = new RuntimePermission("dynalink.getLookup");
   109      */
   107 
   110     public static final RuntimePermission GET_LOOKUP_PERMISSION =
   108     /**
   111             new RuntimePermission("dynalink.getLookup");
   109      * The index of the name token that will carry the operation scheme prefix (usually, "dyn").
   112 
       
   113     /**
       
   114      * The index of the name token that will carry the operation scheme prefix,
       
   115      * e.g. {@code "dyn"} for operations specified by Dynalink itself.
   110      */
   116      */
   111     public static final int SCHEME = 0;
   117     public static final int SCHEME = 0;
   112     /**
   118 
   113      * The index of the name token that will usually carry the operation name.
   119     /**
   114      */
   120      * The index of the name token that carries the operation name, at least
   115 
   121      * when using the {@code "dyn"} scheme.
   116     public static final int OPERATOR=1;
   122      */
   117     /**
   123 
   118      * The index of the name token that will usually carry a name of an operand (of a property, method, etc.)
   124     public static final int OPERATOR = 1;
   119      */
   125 
   120 
   126     /**
   121     public static final int NAME_OPERAND=2;
   127      * The index of the name token that carries the name of an operand (e.g. a
   122 
   128      * property or a method), at least when using the {@code "dyn"} scheme.
   123     /**
   129      */
   124      * Character used to delimit tokens in an call site name.
   130     public static final int NAME_OPERAND = 2;
       
   131 
       
   132     /**
       
   133      * String used to delimit tokens in a call site name; its value is
       
   134      * {@code ":"}, that is the colon character.
   125      */
   135      */
   126     public static final String TOKEN_DELIMITER = ":";
   136     public static final String TOKEN_DELIMITER = ":";
   127 
   137 
   128     /**
   138     /**
   129      * Character used to delimit operation names in a composite operation specification.
   139      * String used to delimit operation names in a composite operation name;
       
   140      * its value is {@code "|"}, that is the pipe character.
   130      */
   141      */
   131     public static final String OPERATOR_DELIMITER = "|";
   142     public static final String OPERATOR_DELIMITER = "|";
   132 
   143 
   133     /**
   144     /**
   134      * Returns the number of tokens in the name of the method at the call site. Method names are tokenized with the
   145      * Returns the number of tokens in the name of the method at the call site.
   135      * colon ":" character, i.e. "dyn:getProp:color" would be the name used to describe a method that retrieves the
   146      * Method names are tokenized with the {@link #TOKEN_DELIMITER} character
   136      * property named "color" on the object it is invoked on.
   147      * character, e.g. {@code "dyn:getProp:color"} would be the name used to
       
   148      * describe a method that retrieves the property named "color" on the object
       
   149      * it is invoked on.
   137      * @return the number of tokens in the name of the method at the call site.
   150      * @return the number of tokens in the name of the method at the call site.
   138      */
   151      */
   139     public int getNameTokenCount();
   152     public int getNameTokenCount();
   140 
   153 
   141     /**
   154     /**
   142      * Returns the <i>i<sup>th</sup></i> token in the method name at the call site. Method names are tokenized with the
   155      * Returns the <i>i<sup>th</sup></i> token in the method name at the call
   143      * colon ":" character.
   156      * site. Method names are tokenized with the {@link #TOKEN_DELIMITER}
   144      * @param i the index of the token. Must be between 0 (inclusive) and {@link #getNameTokenCount()} (exclusive)
   157      * character.
   145      * @throws IllegalArgumentException if the index is outside the allowed range.
   158      * @param i the index of the token. Must be between 0 (inclusive) and
   146      * @return the <i>i<sup>th</sup></i> token in the method name at the call site. The returned strings are interned.
   159      * {@link #getNameTokenCount()} (exclusive).
       
   160      * @throws IllegalArgumentException if the index is outside the allowed
       
   161      * range.
       
   162      * @return the <i>i<sup>th</sup></i> token in the method name at the call
       
   163      * site.
   147      */
   164      */
   148     public String getNameToken(int i);
   165     public String getNameToken(int i);
   149 
   166 
   150     /**
   167     /**
   151      * Returns the name of the method at the call site. Note that the object internally only stores the tokenized name,
   168      * Returns the full (untokenized) name of the method at the call site.
   152      * and has to reconstruct the full name from tokens on each invocation.
   169      * @return the full (untokenized) name of the method at the call site.
   153      * @return the name of the method at the call site.
       
   154      */
   170      */
   155     public String getName();
   171     public String getName();
   156 
   172 
   157     /**
   173     /**
   158      * The type of the method at the call site.
   174      * The type of the method at the call site.
   160      * @return type of the method at the call site.
   176      * @return type of the method at the call site.
   161      */
   177      */
   162     public MethodType getMethodType();
   178     public MethodType getMethodType();
   163 
   179 
   164     /**
   180     /**
   165      * Returns the lookup passed to the bootstrap method.
   181      * Returns the lookup that should be used to find method handles to set as
   166      * @return the lookup passed to the bootstrap method.
   182      * targets of the call site described by this descriptor. When creating
   167      * @throws SecurityException if the lookup isn't the {@link MethodHandles#publicLookup()} and a security
   183      * descriptors from a {@link java.lang.invoke} bootstrap method, it should
   168      * manager is present, and a check for {@code RuntimePermission("dynalink.getLookup")} (available as
   184      * be the lookup passed to the bootstrap. An implementation should use
       
   185      * {@link #checkLookup(MethodHandles.Lookup)} to ensure the necessary
       
   186      * security properties.
       
   187      * @return the lookup that should be used to find method handles to set as
       
   188      * targets of the call site described by this descriptor.
       
   189      * @throws SecurityException if the lookup isn't the
       
   190      * {@link MethodHandles#publicLookup()} and a security manager is present,
       
   191      * and a check for {@code RuntimePermission("dynalink.getLookup")}
       
   192      * (a canonical instance of which is available as
   169      * {@link #GET_LOOKUP_PERMISSION}) fails.
   193      * {@link #GET_LOOKUP_PERMISSION}) fails.
   170      */
   194      */
   171     public Lookup getLookup();
   195     public Lookup getLookup();
   172 
   196 
   173     /**
   197     /**
   174      * Creates a new call site descriptor from this descriptor, which is identical to this, except it changes the method
   198      * Creates a new call site descriptor from this descriptor, which is
   175      * type.
   199      * identical to this, except it changes the method type.
   176      *
   200      *
   177      * @param newMethodType the new method type
   201      * @param newMethodType the new method type
   178      * @return a new call site descriptor, with the method type changed.
   202      * @return a new call site descriptor, with the method type changed.
   179      */
   203      */
   180     public CallSiteDescriptor changeMethodType(MethodType newMethodType);
   204     public CallSiteDescriptor changeMethodType(MethodType newMethodType);
   181 
   205 
   182 
   206 
   183     /**
   207     /**
   184      * Tokenizes a composite operation name along pipe characters. I.e. if you have a "dyn:getElem|getProp|getMethod"
   208      * Tokenizes a composite operation name of this descriptor along
   185      * operation, returns a list of ["getElem", "getProp", "getMethod"]. The tokens are not interned.
   209      * {@link #OPERATOR_DELIMITER} characters. E.g. if this descriptor's name is
   186      * @return a list of tokens
   210      * {@code "dyn:getElem|getProp|getMethod"}, then it returns a list of
       
   211      * {@code ["getElem", "getProp", "getMethod"]}.
       
   212      * @return a list of operator tokens.
   187      */
   213      */
   188     public default List<String> tokenizeOperators() {
   214     public default List<String> tokenizeOperators() {
   189         final String ops = getNameToken(CallSiteDescriptor.OPERATOR);
   215         final String ops = getNameToken(CallSiteDescriptor.OPERATOR);
   190         final StringTokenizer tok = new StringTokenizer(ops, CallSiteDescriptor.OPERATOR_DELIMITER);
   216         final StringTokenizer tok = new StringTokenizer(ops, CallSiteDescriptor.OPERATOR_DELIMITER);
   191         final int count = tok.countTokens();
   217         final int count = tok.countTokens();
   198         }
   224         }
   199         return Arrays.asList(tokens);
   225         return Arrays.asList(tokens);
   200     }
   226     }
   201 
   227 
   202     /**
   228     /**
   203      * Checks if the current access context is granted the {@code RuntimePermission("dynalink.getLookup")}
   229      * Checks if the current access context is granted the
   204      * permission, if the system contains a security manager, and the passed lookup is not the
   230      * {@code RuntimePermission("dynalink.getLookup")} permission, if the
   205      * {@link MethodHandles#publicLookup()}.
   231      * system contains a security manager, and the passed lookup is not the
       
   232      * {@link MethodHandles#publicLookup()}. This method should be used in all
       
   233      * implementations of {@link #getLookup()} method to ensure that only
       
   234      * code with permission can retrieve the lookup object.
   206      * @param lookup the lookup being checked for access
   235      * @param lookup the lookup being checked for access
   207      * @return the passed in lookup if there's either no security manager in the system, or the passed lookup
   236      * @return the passed in lookup if there's either no security manager in
   208      * is the public lookup, or the current access context is granted the relevant permission.
   237      * the system, or the passed lookup is the public lookup, or the current
   209      * @throws SecurityException if the system contains a security manager, and the passed lookup is not the
   238      * access context is granted the relevant permission.
   210      * {@link MethodHandles#publicLookup()}, and the current access context is not granted the relevant
   239      * @throws SecurityException if the system contains a security manager, and
   211      * permission.
   240      * the passed lookup is not the public lookup, and the current access
       
   241      * context is not granted the relevant permission.
   212      */
   242      */
   213     public static Lookup checkLookup(final Lookup lookup) {
   243     public static Lookup checkLookup(final Lookup lookup) {
   214         final SecurityManager sm = System.getSecurityManager();
   244         final SecurityManager sm = System.getSecurityManager();
   215         if (sm != null && lookup != MethodHandles.publicLookup()) {
   245         if (sm != null && lookup != MethodHandles.publicLookup()) {
   216             sm.checkPermission(GET_LOOKUP_PERMISSION);
   246             sm.checkPermission(GET_LOOKUP_PERMISSION);
   217         }
   247         }
   218         return lookup;
   248         return lookup;
   219     }
   249     }
   220 
   250 
   221     /**
   251     /**
   222      * Tokenizes the composite name along colons, as well as {@link NameCodec#decode(String) demangles} and interns
   252      * Tokenizes the composite name along {@link #TOKEN_DELIMITER} characters,
   223      * the tokens. The first two tokens are not demangled as they are supposed to be the naming scheme and the name of
   253      * as well as {@link NameCodec#decode(String) demangles} and interns the
   224      * the operation which can be expected to consist of just alphabetical characters.
   254      * tokens. The first two tokens are not demangled as they are supposed to
   225      * @param name the composite name consisting of colon-separated, possibly mangled tokens.
   255      * be the naming scheme and the name of the operation which can be expected
   226      * @return an array of tokens
   256      * to consist of just alphabetical characters.
       
   257      * @param name the composite name consisting of
       
   258      * {@link #TOKEN_DELIMITER}-separated, possibly mangled tokens.
       
   259      * @return an array of unmangled, interned tokens.
   227      */
   260      */
   228     public static String[] tokenizeName(final String name) {
   261     public static String[] tokenizeName(final String name) {
   229         final StringTokenizer tok = new StringTokenizer(name, CallSiteDescriptor.TOKEN_DELIMITER);
   262         final StringTokenizer tok = new StringTokenizer(name, CallSiteDescriptor.TOKEN_DELIMITER);
   230         final String[] tokens = new String[tok.countTokens()];
   263         final String[] tokens = new String[tok.countTokens()];
   231         for(int i = 0; i < tokens.length; ++i) {
   264         for(int i = 0; i < tokens.length; ++i) {