NashornCallSiteDescriptor.java revision 1494:c7ef0fb26eff
1/*
2 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package jdk.nashorn.internal.runtime.linker;
27
28import java.lang.invoke.MethodHandles;
29import java.lang.invoke.MethodHandles.Lookup;
30import java.lang.invoke.MethodType;
31import java.security.AccessControlContext;
32import java.security.AccessController;
33import java.security.PrivilegedAction;
34import java.util.concurrent.ConcurrentHashMap;
35import java.util.concurrent.ConcurrentMap;
36import jdk.internal.dynalink.CallSiteDescriptor;
37import jdk.internal.dynalink.CompositeOperation;
38import jdk.internal.dynalink.NamedOperation;
39import jdk.internal.dynalink.Operation;
40import jdk.internal.dynalink.StandardOperation;
41import jdk.nashorn.internal.ir.debug.NashornTextifier;
42import jdk.nashorn.internal.runtime.AccessControlContextFactory;
43import jdk.nashorn.internal.runtime.ScriptRuntime;
44
45/**
46 * Nashorn-specific implementation of Dynalink's {@link CallSiteDescriptor}.
47 * The reason we have our own subclass is that we're storing flags in an
48 * additional primitive field. The class also exposes some useful utilities in
49 * form of static methods.
50 */
51public final class NashornCallSiteDescriptor extends CallSiteDescriptor {
52    // Lowest three bits describe the operation
53    /** Property getter operation {@code obj.prop} */
54    public static final int GET_PROPERTY        = 0;
55    /** Element getter operation {@code obj[index]} */
56    public static final int GET_ELEMENT         = 1;
57    /** Property getter operation, subsequently invoked {@code obj.prop()} */
58    public static final int GET_METHOD_PROPERTY = 2;
59    /** Element getter operation, subsequently invoked {@code obj[index]()} */
60    public static final int GET_METHOD_ELEMENT  = 3;
61    /** Property setter operation {@code obj.prop = value} */
62    public static final int SET_PROPERTY        = 4;
63    /** Element setter operation {@code obj[index] = value} */
64    public static final int SET_ELEMENT         = 5;
65    /** Call operation {@code fn(args...)} */
66    public static final int CALL                = 6;
67    /** New operation {@code new Constructor(args...)} */
68    public static final int NEW                 = 7;
69
70    private static final int OPERATION_MASK = 7;
71
72    // Correspond to the operation indices above.
73    private static final Operation[] OPERATIONS = new Operation[] {
74        new CompositeOperation(StandardOperation.GET_PROPERTY, StandardOperation.GET_ELEMENT, StandardOperation.GET_METHOD),
75        new CompositeOperation(StandardOperation.GET_ELEMENT, StandardOperation.GET_PROPERTY, StandardOperation.GET_METHOD),
76        new CompositeOperation(StandardOperation.GET_METHOD, StandardOperation.GET_PROPERTY, StandardOperation.GET_ELEMENT),
77        new CompositeOperation(StandardOperation.GET_METHOD, StandardOperation.GET_ELEMENT, StandardOperation.GET_PROPERTY),
78        new CompositeOperation(StandardOperation.SET_PROPERTY, StandardOperation.SET_ELEMENT),
79        new CompositeOperation(StandardOperation.SET_ELEMENT, StandardOperation.SET_PROPERTY),
80        StandardOperation.CALL,
81        StandardOperation.NEW
82    };
83
84    /** Flags that the call site references a scope variable (it's an identifier reference or a var declaration, not a
85     * property access expression. */
86    public static final int CALLSITE_SCOPE         = 1 << 3;
87    /** Flags that the call site is in code that uses ECMAScript strict mode. */
88    public static final int CALLSITE_STRICT        = 1 << 4;
89    /** Flags that a property getter or setter call site references a scope variable that is located at a known distance
90     * in the scope chain. Such getters and setters can often be linked more optimally using these assumptions. */
91    public static final int CALLSITE_FAST_SCOPE    = 1 << 5;
92    /** Flags that a callsite type is optimistic, i.e. we might get back a wider return value than encoded in the
93     * descriptor, and in that case we have to throw an UnwarrantedOptimismException */
94    public static final int CALLSITE_OPTIMISTIC    = 1 << 6;
95    /** Is this really an apply that we try to call as a call? */
96    public static final int CALLSITE_APPLY_TO_CALL = 1 << 7;
97    /** Does this a callsite for a variable declaration? */
98    public static final int CALLSITE_DECLARE       = 1 << 8;
99
100    /** Flags that the call site is profiled; Contexts that have {@code "profile.callsites"} boolean property set emit
101     * code where call sites have this flag set. */
102    public static final int CALLSITE_PROFILE         = 1 << 9;
103    /** Flags that the call site is traced; Contexts that have {@code "trace.callsites"} property set emit code where
104     * call sites have this flag set. */
105    public static final int CALLSITE_TRACE           = 1 << 10;
106    /** Flags that the call site linkage miss (and thus, relinking) is traced; Contexts that have the keyword
107     * {@code "miss"} in their {@code "trace.callsites"} property emit code where call sites have this flag set. */
108    public static final int CALLSITE_TRACE_MISSES    = 1 << 11;
109    /** Flags that entry/exit to/from the method linked at call site are traced; Contexts that have the keyword
110     * {@code "enterexit"} in their {@code "trace.callsites"} property emit code where call sites have this flag set. */
111    public static final int CALLSITE_TRACE_ENTEREXIT = 1 << 12;
112    /** Flags that values passed as arguments to and returned from the method linked at call site are traced; Contexts
113     * that have the keyword {@code "values"} in their {@code "trace.callsites"} property emit code where call sites
114     * have this flag set. */
115    public static final int CALLSITE_TRACE_VALUES    = 1 << 13;
116
117    //we could have more tracing flags here, for example CALLSITE_TRACE_SCOPE, but bits are a bit precious
118    //right now given the program points
119
120    /**
121     * Number of bits the program point is shifted to the left in the flags (lowest bit containing a program point).
122     * Always one larger than the largest flag shift. Note that introducing a new flag halves the number of program
123     * points we can have.
124     * TODO: rethink if we need the various profile/trace flags or the linker can use the Context instead to query its
125     * trace/profile settings.
126     */
127    public static final int CALLSITE_PROGRAM_POINT_SHIFT = 14;
128
129    /**
130     * Maximum program point value. We have 18 bits left over after flags, and
131     * it should be plenty. Program points are local to a single function. Every
132     * function maps to a single JVM bytecode method that can have at most 65535
133     * bytes. (Large functions are synthetically split into smaller functions.)
134     * A single invokedynamic is 5 bytes; even if a method consists of only
135     * invokedynamic instructions that leaves us with at most 65535/5 = 13107
136     * program points for the largest single method; those can be expressed on
137     * 14 bits. It is true that numbering of program points is independent of
138     * bytecode representation, but if a function would need more than ~14 bits
139     * for the program points, then it is reasonable to presume splitter
140     * would've split it into several smaller functions already.
141     */
142    public static final int MAX_PROGRAM_POINT_VALUE = (1 << 32 - CALLSITE_PROGRAM_POINT_SHIFT) - 1;
143
144    /**
145     * Flag mask to get the program point flags
146     */
147    public static final int FLAGS_MASK = (1 << CALLSITE_PROGRAM_POINT_SHIFT) - 1;
148
149    private static final ClassValue<ConcurrentMap<NashornCallSiteDescriptor, NashornCallSiteDescriptor>> canonicals =
150            new ClassValue<ConcurrentMap<NashornCallSiteDescriptor,NashornCallSiteDescriptor>>() {
151        @Override
152        protected ConcurrentMap<NashornCallSiteDescriptor, NashornCallSiteDescriptor> computeValue(final Class<?> type) {
153            return new ConcurrentHashMap<>();
154        }
155    };
156
157    private static final AccessControlContext GET_LOOKUP_PERMISSION_CONTEXT =
158            AccessControlContextFactory.createAccessControlContext(CallSiteDescriptor.GET_LOOKUP_PERMISSION_NAME);
159
160    private final int flags;
161
162    /**
163     * Function used by {@link NashornTextifier} to represent call site flags in
164     * human readable form
165     * @param flags call site flags
166     * @return human readable form of this callsite descriptor
167     */
168    public static String toString(final int flags) {
169        final StringBuilder sb = new StringBuilder();
170        if ((flags & CALLSITE_SCOPE) != 0) {
171            if ((flags & CALLSITE_FAST_SCOPE) != 0) {
172                sb.append("fastscope ");
173            } else {
174                assert (flags & CALLSITE_FAST_SCOPE) == 0 : "can't be fastscope without scope";
175                sb.append("scope ");
176            }
177            if ((flags & CALLSITE_DECLARE) != 0) {
178                sb.append("declare ");
179            }
180        }
181        if ((flags & CALLSITE_APPLY_TO_CALL) != 0) {
182            sb.append("apply2call ");
183        }
184        if ((flags & CALLSITE_STRICT) != 0) {
185            sb.append("strict ");
186        }
187        return sb.length() == 0 ? "" : " " + sb.toString().trim();
188    }
189
190    /**
191     * Given call site flags, returns the operation name encoded in them.
192     * @param flags flags
193     * @return the operation name
194     */
195    public static String getOperationName(final int flags) {
196        switch(flags & OPERATION_MASK) {
197        case 0: return "GET_PROPERTY";
198        case 1: return "GET_ELEMENT";
199        case 2: return "GET_METHOD_PROPERTY";
200        case 3: return "GET_METHOD_ELEMENT";
201        case 4: return "SET_PROPERTY";
202        case 5: return "SET_ELEMENT";
203        case 6: return "CALL";
204        case 7: return "NEW";
205        default: throw new AssertionError();
206        }
207    }
208
209    /**
210     * Retrieves a Nashorn call site descriptor with the specified values. Since call site descriptors are immutable
211     * this method is at liberty to retrieve canonicalized instances (although it is not guaranteed it will do so).
212     * @param lookup the lookup describing the script
213     * @param name the name at the call site. Can not be null, but it can be empty.
214     * @param methodType the method type at the call site
215     * @param flags Nashorn-specific call site flags
216     * @return a call site descriptor with the specified values.
217     */
218    public static NashornCallSiteDescriptor get(final MethodHandles.Lookup lookup, final String name,
219            final MethodType methodType, final int flags) {
220        final Operation baseOp = OPERATIONS[flags & OPERATION_MASK];
221        final String decodedName = NameCodec.decode(name);
222        // TODO: introduce caching of NamedOperation
223        final Operation op = decodedName.isEmpty() ? baseOp : new NamedOperation(baseOp, decodedName);
224        return get(lookup, op, methodType, flags);
225    }
226
227    private static NashornCallSiteDescriptor get(final MethodHandles.Lookup lookup, final Operation operation, final MethodType methodType, final int flags) {
228        final NashornCallSiteDescriptor csd = new NashornCallSiteDescriptor(lookup, operation, methodType, flags);
229        // Many of these call site descriptors are identical (e.g. every getter for a property color will be
230        // "GET_PROPERTY:color(Object)Object", so it makes sense canonicalizing them.
231        final ConcurrentMap<NashornCallSiteDescriptor, NashornCallSiteDescriptor> classCanonicals = canonicals.get(lookup.lookupClass());
232        final NashornCallSiteDescriptor canonical = classCanonicals.putIfAbsent(csd, csd);
233        return canonical != null ? canonical : csd;
234    }
235
236    private NashornCallSiteDescriptor(final MethodHandles.Lookup lookup, final Operation operation, final MethodType methodType, final int flags) {
237        super(lookup, operation, methodType);
238        this.flags = flags;
239    }
240
241    static Lookup getLookupInternal(final CallSiteDescriptor csd) {
242        if (csd instanceof NashornCallSiteDescriptor) {
243            return ((NashornCallSiteDescriptor)csd).getLookupPrivileged();
244        }
245        return AccessController.doPrivileged((PrivilegedAction<Lookup>)()->csd.getLookup(), GET_LOOKUP_PERMISSION_CONTEXT);
246    }
247
248    @Override
249    public boolean equals(final Object obj) {
250        return super.equals(obj) && flags == ((NashornCallSiteDescriptor)obj).flags;
251    }
252
253    @Override
254    public int hashCode() {
255        return super.hashCode() ^ flags;
256    }
257
258    /**
259     * Returns the named operand in this descriptor's operation. Equivalent to
260     * {@code ((NamedOperation)getOperation()).getName().toString()} for call
261     * sites with a named operand. For call sites without named operands returns null.
262     * @return the named operand in this descriptor's operation.
263     */
264    public String getOperand() {
265        return getOperand(this);
266    }
267
268    /**
269     * Returns the named operand in the passed descriptor's operation.
270     * Equivalent to
271     * {@code ((NamedOperation)desc.getOperation()).getName().toString()} for
272     * descriptors with a named operand. For descriptors without named operands
273     * returns null.
274     * @param desc the call site descriptors
275     * @return the named operand in this descriptor's operation.
276     */
277    public static String getOperand(final CallSiteDescriptor desc) {
278        final Operation operation = desc.getOperation();
279        return operation instanceof NamedOperation ? ((NamedOperation)operation).getName().toString() : null;
280    }
281
282    /**
283     * Returns the first operation in this call site descriptor's potentially
284     * composite operation. E.g. if this call site descriptor has a composite
285     * operation {@code GET_PROPERTY|GET_METHOD|GET_ELEM}, it will return
286     * {@code GET_PROPERTY}. Nashorn - being a ECMAScript engine - does not
287     * distinguish between property, element, and method namespace; ECMAScript
288     * objects just have one single property namespace for all these, therefore
289     * it is largely irrelevant what the composite operation is structured like;
290     * if the first operation can't be satisfied, neither can the others. The
291     * first operation is however sometimes used to slightly alter the
292     * semantics; for example, a distinction between {@code GET_PROPERTY} and
293     * {@code GET_METHOD} being the first operation can translate into whether
294     * {@code "__noSuchProperty__"} or {@code "__noSuchMethod__"} will be
295     * executed in case the property is not found. Note that if a call site
296     * descriptor comes from outside of Nashorn, its class will be different,
297     * and there is no guarantee about the way it composes its operations. For
298     * that reason, for potentially foreign call site descriptors you should use
299     * {@link #getFirstStandardOperation(CallSiteDescriptor)} instead.
300     * @return the first operation in this call site descriptor. Note this will
301     * always be a {@code StandardOperation} as Nashorn internally only uses
302     * standard operations.
303     */
304    public StandardOperation getFirstOperation() {
305        final Operation base = NamedOperation.getBaseOperation(getOperation());
306        if (base instanceof CompositeOperation) {
307            return (StandardOperation)((CompositeOperation)base).getOperation(0);
308        }
309        return (StandardOperation)base;
310    }
311
312    /**
313     * Returns the first standard operation in the (potentially composite)
314     * operation of the passed call site descriptor.
315     * @param desc the call site descriptor.
316     * @return Returns the first standard operation in the (potentially
317     * composite) operation of the passed call site descriptor. Can return null
318     * if the call site contains no standard operations.
319     */
320    public static StandardOperation getFirstStandardOperation(final CallSiteDescriptor desc) {
321        final Operation base = NamedOperation.getBaseOperation(desc.getOperation());
322        if (base instanceof StandardOperation) {
323            return (StandardOperation)base;
324        } else if (base instanceof CompositeOperation) {
325            final CompositeOperation cop = (CompositeOperation)base;
326            for(int i = 0; i < cop.getOperationCount(); ++i) {
327                final Operation op = cop.getOperation(i);
328                if (op instanceof StandardOperation) {
329                    return (StandardOperation)op;
330                }
331            }
332        }
333        return null;
334    }
335
336    /**
337     * Returns true if the passed call site descriptor's operation contains (or
338     * is) the specified standard operation.
339     * @param desc the call site descriptor.
340     * @param operation the operation whose presence is tested.
341     * @return Returns true if the call site descriptor's operation contains (or
342     * is) the specified standard operation.
343     */
344    public static boolean contains(final CallSiteDescriptor desc, final StandardOperation operation) {
345        return CompositeOperation.contains(NamedOperation.getBaseOperation(desc.getOperation()), operation);
346    }
347
348    /**
349     * Returns the error message to be used when CALL or NEW is used on a non-function.
350     *
351     * @param obj object on which CALL or NEW is used
352     * @return error message
353     */
354    public String getFunctionErrorMessage(final Object obj) {
355        final String funcDesc = getOperand();
356        return funcDesc != null? funcDesc : ScriptRuntime.safeToString(obj);
357    }
358
359    /**
360     * Returns the error message to be used when CALL or NEW is used on a non-function.
361     *
362     * @param desc call site descriptor
363     * @param obj object on which CALL or NEW is used
364     * @return error message
365     */
366    public static String getFunctionErrorMessage(final CallSiteDescriptor desc, final Object obj) {
367        return desc instanceof NashornCallSiteDescriptor ?
368                ((NashornCallSiteDescriptor)desc).getFunctionErrorMessage(obj) :
369                ScriptRuntime.safeToString(obj);
370    }
371
372    /**
373     * Returns the Nashorn-specific flags for this call site descriptor.
374     * @param desc the descriptor. It can be any kind of a call site descriptor, not necessarily a
375     * {@code NashornCallSiteDescriptor}. This allows for graceful interoperability when linking Nashorn with code
376     * generated outside of Nashorn.
377     * @return the Nashorn-specific flags for the call site, or 0 if the passed descriptor is not a Nashorn call site
378     * descriptor.
379     */
380    public static int getFlags(final CallSiteDescriptor desc) {
381        return desc instanceof NashornCallSiteDescriptor ? ((NashornCallSiteDescriptor)desc).flags : 0;
382    }
383
384    /**
385     * Returns true if this descriptor has the specified flag set, see {@code CALLSITE_*} constants in this class.
386     * @param flag the tested flag
387     * @return true if the flag is set, false otherwise
388     */
389    private boolean isFlag(final int flag) {
390        return (flags & flag) != 0;
391    }
392
393    /**
394     * Returns true if this descriptor has the specified flag set, see {@code CALLSITE_*} constants in this class.
395     * @param desc the descriptor. It can be any kind of a call site descriptor, not necessarily a
396     * {@code NashornCallSiteDescriptor}. This allows for graceful interoperability when linking Nashorn with code
397     * generated outside of Nashorn.
398     * @param flag the tested flag
399     * @return true if the flag is set, false otherwise (it will be false if the descriptor is not a Nashorn call site
400     * descriptor).
401     */
402    private static boolean isFlag(final CallSiteDescriptor desc, final int flag) {
403        return (getFlags(desc) & flag) != 0;
404    }
405
406    /**
407     * Returns true if this descriptor is a Nashorn call site descriptor and has the {@link  #CALLSITE_SCOPE} flag set.
408     * @param desc the descriptor. It can be any kind of a call site descriptor, not necessarily a
409     * {@code NashornCallSiteDescriptor}. This allows for graceful interoperability when linking Nashorn with code
410     * generated outside of Nashorn.
411     * @return true if the descriptor is a Nashorn call site descriptor, and the flag is set, false otherwise.
412     */
413    public static boolean isScope(final CallSiteDescriptor desc) {
414        return isFlag(desc, CALLSITE_SCOPE);
415    }
416
417    /**
418     * Returns true if this descriptor is a Nashorn call site descriptor and has the {@link  #CALLSITE_FAST_SCOPE} flag set.
419     * @param desc the descriptor. It can be any kind of a call site descriptor, not necessarily a
420     * {@code NashornCallSiteDescriptor}. This allows for graceful interoperability when linking Nashorn with code
421     * generated outside of Nashorn.
422     * @return true if the descriptor is a Nashorn call site descriptor, and the flag is set, false otherwise.
423     */
424    public static boolean isFastScope(final CallSiteDescriptor desc) {
425        return isFlag(desc, CALLSITE_FAST_SCOPE);
426    }
427
428    /**
429     * Returns true if this descriptor is a Nashorn call site descriptor and has the {@link  #CALLSITE_STRICT} flag set.
430     * @param desc the descriptor. It can be any kind of a call site descriptor, not necessarily a
431     * {@code NashornCallSiteDescriptor}. This allows for graceful interoperability when linking Nashorn with code
432     * generated outside of Nashorn.
433     * @return true if the descriptor is a Nashorn call site descriptor, and the flag is set, false otherwise.
434     */
435    public static boolean isStrict(final CallSiteDescriptor desc) {
436        return isFlag(desc, CALLSITE_STRICT);
437    }
438
439    /**
440     * Returns true if this is an apply call that we try to call as
441     * a "call"
442     * @param desc descriptor
443     * @return true if apply to call
444     */
445    public static boolean isApplyToCall(final CallSiteDescriptor desc) {
446        return isFlag(desc, CALLSITE_APPLY_TO_CALL);
447    }
448
449    /**
450     * Is this an optimistic call site
451     * @param desc descriptor
452     * @return true if optimistic
453     */
454    public static boolean isOptimistic(final CallSiteDescriptor desc) {
455        return isFlag(desc, CALLSITE_OPTIMISTIC);
456    }
457
458    /**
459     * Does this callsite contain a declaration for its target?
460     * @param desc descriptor
461     * @return true if contains declaration
462     */
463    public static boolean isDeclaration(final CallSiteDescriptor desc) {
464        return isFlag(desc, CALLSITE_DECLARE);
465    }
466
467    /**
468     * Returns true if {@code flags} has the {@link  #CALLSITE_STRICT} bit set.
469     * @param flags the flags
470     * @return true if the flag is set, false otherwise.
471     */
472    public static boolean isStrictFlag(final int flags) {
473        return (flags & CALLSITE_STRICT) != 0;
474    }
475
476    /**
477     * Returns true if {@code flags} has the {@link  #CALLSITE_SCOPE} bit set.
478     * @param flags the flags
479     * @return true if the flag is set, false otherwise.
480     */
481    public static boolean isScopeFlag(final int flags) {
482        return (flags & CALLSITE_SCOPE) != 0;
483    }
484
485    /**
486     * Get a program point from a descriptor (must be optimistic)
487     * @param desc descriptor
488     * @return program point
489     */
490    public static int getProgramPoint(final CallSiteDescriptor desc) {
491        assert isOptimistic(desc) : "program point requested from non-optimistic descriptor " + desc;
492        return getFlags(desc) >> CALLSITE_PROGRAM_POINT_SHIFT;
493    }
494
495    boolean isProfile() {
496        return isFlag(CALLSITE_PROFILE);
497    }
498
499    boolean isTrace() {
500        return isFlag(CALLSITE_TRACE);
501    }
502
503    boolean isTraceMisses() {
504        return isFlag(CALLSITE_TRACE_MISSES);
505    }
506
507    boolean isTraceEnterExit() {
508        return isFlag(CALLSITE_TRACE_ENTEREXIT);
509    }
510
511    boolean isTraceObjects() {
512        return isFlag(CALLSITE_TRACE_VALUES);
513    }
514
515    boolean isOptimistic() {
516        return isFlag(CALLSITE_OPTIMISTIC);
517    }
518
519    @Override
520    public CallSiteDescriptor changeMethodTypeInternal(final MethodType newMethodType) {
521        return get(getLookupPrivileged(), getOperation(), newMethodType, flags);
522    }
523}
524