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 
  26 package jdk.nashorn.internal.runtime.linker;
  27 
  28 import static jdk.dynalink.StandardNamespace.ELEMENT;
  29 import static jdk.dynalink.StandardNamespace.METHOD;
  30 import static jdk.dynalink.StandardNamespace.PROPERTY;
  31 import static jdk.dynalink.StandardOperation.GET;
  32 import static jdk.dynalink.StandardOperation.SET;
  33 
  34 import java.lang.invoke.MethodHandles;
  35 import java.lang.invoke.MethodHandles.Lookup;
  36 import java.lang.invoke.MethodType;
  37 import java.lang.ref.Reference;
  38 import java.lang.ref.WeakReference;
  39 import java.security.AccessControlContext;
  40 import java.security.AccessController;
  41 import java.security.PrivilegedAction;
  42 import java.util.Collections;
  43 import java.util.Map;
  44 import java.util.WeakHashMap;
  45 import java.util.concurrent.ConcurrentHashMap;
  46 import java.util.concurrent.ConcurrentMap;
  47 import java.util.stream.Stream;
  48 import jdk.dynalink.CallSiteDescriptor;
  49 import jdk.dynalink.NamedOperation;
  50 import jdk.dynalink.NamespaceOperation;
  51 import jdk.dynalink.Operation;
  52 import jdk.dynalink.SecureLookupSupplier;
  53 import jdk.dynalink.StandardNamespace;
  54 import jdk.dynalink.StandardOperation;
  55 import jdk.nashorn.internal.ir.debug.NashornTextifier;
  56 import jdk.nashorn.internal.runtime.AccessControlContextFactory;
  57 import jdk.nashorn.internal.runtime.ScriptRuntime;
  58 
  59 /**
  60  * Nashorn-specific implementation of Dynalink's {@link CallSiteDescriptor}.
  61  * The reason we have our own subclass is that we're storing flags in an
  62  * additional primitive field. The class also exposes some useful utilities in
  63  * form of static methods.
  64  */
  65 public final class NashornCallSiteDescriptor extends CallSiteDescriptor {
  66     // Lowest three bits describe the operation
  67     /** Property getter operation {@code obj.prop} */
  68     public static final int GET_PROPERTY        = 0;
  69     /** Element getter operation {@code obj[index]} */
  70     public static final int GET_ELEMENT         = 1;
  71     /** Property getter operation, subsequently invoked {@code obj.prop()} */
  72     public static final int GET_METHOD_PROPERTY = 2;
  73     /** Element getter operation, subsequently invoked {@code obj[index]()} */
  74     public static final int GET_METHOD_ELEMENT  = 3;
  75     /** Property setter operation {@code obj.prop = value} */
  76     public static final int SET_PROPERTY        = 4;
  77     /** Element setter operation {@code obj[index] = value} */
  78     public static final int SET_ELEMENT         = 5;
  79     /** Call operation {@code fn(args...)} */
  80     public static final int CALL                = 6;
  81     /** New operation {@code new Constructor(args...)} */
  82     public static final int NEW                 = 7;
  83 
  84     private static final int OPERATION_MASK = 7;
  85 
  86     // Correspond to the operation indices above.
  87     private static final Operation[] OPERATIONS = new Operation[] {
  88         GET.withNamespaces(PROPERTY, ELEMENT, METHOD),
  89         GET.withNamespaces(ELEMENT, PROPERTY, METHOD),
  90         GET.withNamespaces(METHOD, PROPERTY, ELEMENT),
  91         GET.withNamespaces(METHOD, ELEMENT, PROPERTY),
  92         SET.withNamespaces(PROPERTY, ELEMENT),
  93         SET.withNamespaces(ELEMENT, PROPERTY),
  94         StandardOperation.CALL,
  95         StandardOperation.NEW
  96     };
  97 
  98     /** Flags that the call site references a scope variable (it's an identifier reference or a var declaration, not a
  99      * property access expression. */
 100     public static final int CALLSITE_SCOPE         = 1 << 3;
 101     /** Flags that the call site is in code that uses ECMAScript strict mode. */
 102     public static final int CALLSITE_STRICT        = 1 << 4;
 103     /** Flags that a property getter or setter call site references a scope variable that is located at a known distance
 104      * in the scope chain. Such getters and setters can often be linked more optimally using these assumptions. */
 105     public static final int CALLSITE_FAST_SCOPE    = 1 << 5;
 106     /** Flags that a callsite type is optimistic, i.e. we might get back a wider return value than encoded in the
 107      * descriptor, and in that case we have to throw an UnwarrantedOptimismException */
 108     public static final int CALLSITE_OPTIMISTIC    = 1 << 6;
 109     /** Is this really an apply that we try to call as a call? */
 110     public static final int CALLSITE_APPLY_TO_CALL = 1 << 7;
 111     /** Does this a callsite for a variable declaration? */
 112     public static final int CALLSITE_DECLARE       = 1 << 8;
 113 
 114     /** Flags that the call site is profiled; Contexts that have {@code "profile.callsites"} boolean property set emit
 115      * code where call sites have this flag set. */
 116     public static final int CALLSITE_PROFILE         = 1 << 9;
 117     /** Flags that the call site is traced; Contexts that have {@code "trace.callsites"} property set emit code where
 118      * call sites have this flag set. */
 119     public static final int CALLSITE_TRACE           = 1 << 10;
 120     /** Flags that the call site linkage miss (and thus, relinking) is traced; Contexts that have the keyword
 121      * {@code "miss"} in their {@code "trace.callsites"} property emit code where call sites have this flag set. */
 122     public static final int CALLSITE_TRACE_MISSES    = 1 << 11;
 123     /** Flags that entry/exit to/from the method linked at call site are traced; Contexts that have the keyword
 124      * {@code "enterexit"} in their {@code "trace.callsites"} property emit code where call sites have this flag set. */
 125     public static final int CALLSITE_TRACE_ENTEREXIT = 1 << 12;
 126     /** Flags that values passed as arguments to and returned from the method linked at call site are traced; Contexts
 127      * that have the keyword {@code "values"} in their {@code "trace.callsites"} property emit code where call sites
 128      * have this flag set. */
 129     public static final int CALLSITE_TRACE_VALUES    = 1 << 13;
 130 
 131     //we could have more tracing flags here, for example CALLSITE_TRACE_SCOPE, but bits are a bit precious
 132     //right now given the program points
 133 
 134     /**
 135      * Number of bits the program point is shifted to the left in the flags (lowest bit containing a program point).
 136      * Always one larger than the largest flag shift. Note that introducing a new flag halves the number of program
 137      * points we can have.
 138      * TODO: rethink if we need the various profile/trace flags or the linker can use the Context instead to query its
 139      * trace/profile settings.
 140      */
 141     public static final int CALLSITE_PROGRAM_POINT_SHIFT = 14;
 142 
 143     /**
 144      * Maximum program point value. We have 18 bits left over after flags, and
 145      * it should be plenty. Program points are local to a single function. Every
 146      * function maps to a single JVM bytecode method that can have at most 65535
 147      * bytes. (Large functions are synthetically split into smaller functions.)
 148      * A single invokedynamic is 5 bytes; even if a method consists of only
 149      * invokedynamic instructions that leaves us with at most 65535/5 = 13107
 150      * program points for the largest single method; those can be expressed on
 151      * 14 bits. It is true that numbering of program points is independent of
 152      * bytecode representation, but if a function would need more than ~14 bits
 153      * for the program points, then it is reasonable to presume splitter
 154      * would've split it into several smaller functions already.
 155      */
 156     public static final int MAX_PROGRAM_POINT_VALUE = (1 << 32 - CALLSITE_PROGRAM_POINT_SHIFT) - 1;
 157 
 158     /**
 159      * Flag mask to get the program point flags
 160      */
 161     public static final int FLAGS_MASK = (1 << CALLSITE_PROGRAM_POINT_SHIFT) - 1;
 162 
 163     private static final ClassValue<ConcurrentMap<NashornCallSiteDescriptor, NashornCallSiteDescriptor>> canonicals =
 164             new ClassValue<ConcurrentMap<NashornCallSiteDescriptor,NashornCallSiteDescriptor>>() {
 165         @Override
 166         protected ConcurrentMap<NashornCallSiteDescriptor, NashornCallSiteDescriptor> computeValue(final Class<?> type) {
 167             return new ConcurrentHashMap<>();
 168         }
 169     };
 170 
 171     private static final AccessControlContext GET_LOOKUP_PERMISSION_CONTEXT =
 172             AccessControlContextFactory.createAccessControlContext(SecureLookupSupplier.GET_LOOKUP_PERMISSION_NAME);
 173 
 174     @SuppressWarnings("unchecked")
 175     private static final Map<String, Reference<NamedOperation>>[] NAMED_OPERATIONS =
 176             Stream.generate(() -> Collections.synchronizedMap(new WeakHashMap<>()))
 177             .limit(OPERATIONS.length).toArray(Map[]::new);
 178 
 179     private final int flags;
 180 
 181     /**
 182      * Function used by {@link NashornTextifier} to represent call site flags in
 183      * human readable form
 184      * @param flags call site flags
 185      * @param sb the string builder
 186      */
 187     public static void appendFlags(final int flags, final StringBuilder sb) {
 188         final int pp = flags >> CALLSITE_PROGRAM_POINT_SHIFT;
 189         if (pp != 0) {
 190             sb.append(" pp=").append(pp);
 191         }
 192         if ((flags & CALLSITE_SCOPE) != 0) {
 193             if ((flags & CALLSITE_FAST_SCOPE) != 0) {
 194                 sb.append(" fastscope");
 195             } else {
 196                 sb.append(" scope");
 197             }
 198             if ((flags & CALLSITE_DECLARE) != 0) {
 199                 sb.append(" declare");
 200             }
 201         } else {
 202             assert (flags & CALLSITE_FAST_SCOPE) == 0 : "can't be fastscope without scope";
 203         }
 204         if ((flags & CALLSITE_APPLY_TO_CALL) != 0) {
 205             sb.append(" apply2call");
 206         }
 207         if ((flags & CALLSITE_STRICT) != 0) {
 208             sb.append(" strict");
 209         }
 210     }
 211 
 212     /**
 213      * Given call site flags, returns the operation name encoded in them.
 214      * @param flags flags
 215      * @return the operation name
 216      */
 217     public static String getOperationName(final int flags) {
 218         switch(flags & OPERATION_MASK) {
 219         case 0: return "GET_PROPERTY";
 220         case 1: return "GET_ELEMENT";
 221         case 2: return "GET_METHOD_PROPERTY";
 222         case 3: return "GET_METHOD_ELEMENT";
 223         case 4: return "SET_PROPERTY";
 224         case 5: return "SET_ELEMENT";
 225         case 6: return "CALL";
 226         case 7: return "NEW";
 227         default: throw new AssertionError();
 228         }
 229     }
 230 
 231     /**
 232      * Retrieves a Nashorn call site descriptor with the specified values. Since call site descriptors are immutable
 233      * this method is at liberty to retrieve canonicalized instances (although it is not guaranteed it will do so).
 234      * @param lookup the lookup describing the script
 235      * @param name the name at the call site. Can not be null, but it can be empty.
 236      * @param methodType the method type at the call site
 237      * @param flags Nashorn-specific call site flags
 238      * @return a call site descriptor with the specified values.
 239      */
 240     public static NashornCallSiteDescriptor get(final MethodHandles.Lookup lookup, final String name,
 241             final MethodType methodType, final int flags) {
 242         final int opIndex = flags & OPERATION_MASK;
 243         final Operation baseOp = OPERATIONS[opIndex];
 244         final String decodedName = NameCodec.decode(name);
 245         final Operation op = decodedName.isEmpty() ? baseOp : getNamedOperation(decodedName, opIndex, baseOp);
 246         return get(lookup, op, methodType, flags);
 247     }
 248 
 249     private static NamedOperation getNamedOperation(final String name, final int opIndex, final Operation baseOp) {
 250         final Map<String, Reference<NamedOperation>> namedOps = NAMED_OPERATIONS[opIndex];
 251         final Reference<NamedOperation> ref = namedOps.get(name);
 252         if (ref != null) {
 253             final NamedOperation existing = ref.get();
 254             if (existing != null) {
 255                 return existing;
 256             }
 257         }
 258         final NamedOperation newOp = baseOp.named(name);
 259         namedOps.put(name, new WeakReference<>(newOp));
 260         return newOp;
 261     }
 262 
 263     private static NashornCallSiteDescriptor get(final MethodHandles.Lookup lookup, final Operation operation, final MethodType methodType, final int flags) {
 264         final NashornCallSiteDescriptor csd = new NashornCallSiteDescriptor(lookup, operation, methodType, flags);
 265         // Many of these call site descriptors are identical (e.g. every getter for a property color will be
 266         // "GET_PROPERTY:color(Object)Object", so it makes sense canonicalizing them. Make an exception for
 267         // optimistic call site descriptors, as they also carry a program point making them unique.
 268         if (csd.isOptimistic()) {
 269             return csd;
 270         }
 271         final NashornCallSiteDescriptor canonical = canonicals.get(lookup.lookupClass()).putIfAbsent(csd, csd);
 272         return canonical != null ? canonical : csd;
 273     }
 274 
 275     private NashornCallSiteDescriptor(final MethodHandles.Lookup lookup, final Operation operation, final MethodType methodType, final int flags) {
 276         super(lookup, operation, methodType);
 277         this.flags = flags;
 278     }
 279 
 280     static Lookup getLookupInternal(final CallSiteDescriptor csd) {
 281         if (csd instanceof NashornCallSiteDescriptor) {
 282             return ((NashornCallSiteDescriptor)csd).getLookupPrivileged();
 283         }
 284         return AccessController.doPrivileged((PrivilegedAction<Lookup>)()->csd.getLookup(), GET_LOOKUP_PERMISSION_CONTEXT);
 285     }
 286 
 287     @Override
 288     public boolean equals(final Object obj) {
 289         return super.equals(obj) && flags == ((NashornCallSiteDescriptor)obj).flags;
 290     }
 291 
 292     @Override
 293     public int hashCode() {
 294         return super.hashCode() ^ flags;
 295     }
 296 
 297     /**
 298      * Returns the named operand in the passed descriptor's operation.
 299      * Equivalent to
 300      * {@code ((NamedOperation)desc.getOperation()).getName().toString()} for
 301      * descriptors with a named operand. For descriptors without named operands
 302      * returns null.
 303      * @param desc the call site descriptors
 304      * @return the named operand in this descriptor's operation.
 305      */
 306     public static String getOperand(final CallSiteDescriptor desc) {
 307         final Operation operation = desc.getOperation();
 308         return operation instanceof NamedOperation ? ((NamedOperation)operation).getName().toString() : null;
 309     }
 310 
 311     private static StandardNamespace findFirstStandardNamespace(final CallSiteDescriptor desc) {
 312         return StandardNamespace.findFirst(desc.getOperation());
 313     }
 314 
 315     /**
 316      * Returns true if the operation of the call descriptor is operating on the method namespace first.
 317      * @param desc the call descriptor in question.
 318      * @return true if the operation of the call descriptor is operating on the method namespace first.
 319      */
 320     public static boolean isMethodFirstOperation(final CallSiteDescriptor desc) {
 321         return findFirstStandardNamespace(desc) == StandardNamespace.METHOD;
 322     }
 323 
 324     /**
 325      * Returns true if there's a namespace operation in the call descriptor and it is operating on at least
 326      * one {@link StandardNamespace}. This method is only needed for exported linkers, since internal linkers
 327      * always operate on Nashorn-generated call sites, and they always operate on standard namespaces only.
 328      * @param desc the call descriptor in question.
 329      * @return true if the operation of the call descriptor is operating on at least one standard namespace.
 330      */
 331     public static boolean hasStandardNamespace(final CallSiteDescriptor desc) {
 332         return findFirstStandardNamespace(desc) != null;
 333     }
 334 
 335     /**
 336      * Returns the base operation in this call site descriptor after unwrapping it from both a named operation
 337      * and a namespace operation.
 338      * @param desc the call site descriptor.
 339      * @return the base operation in this call site descriptor.
 340      */
 341     public static Operation getBaseOperation(final CallSiteDescriptor desc) {
 342         return NamespaceOperation.getBaseOperation(NamedOperation.getBaseOperation(desc.getOperation()));
 343     }
 344 
 345     /**
 346      * Returns the standard operation that is the base operation in this call site descriptor.
 347      * @param desc the call site descriptor.
 348      * @return the standard operation that is the base operation in this call site descriptor.
 349      * @throws ClassCastException if the base operation is not a standard operation. This method is only
 350      * safe to use when the base operation is known to be a standard operation (e.g. all Nashorn call sites
 351      * are such, so it's safe to use from internal linkers).
 352      */
 353     public static StandardOperation getStandardOperation(final CallSiteDescriptor desc) {
 354         return (StandardOperation)getBaseOperation(desc);
 355     }
 356 
 357     /**
 358      * Returns true if the passed call site descriptor contains the specified standard operation on the
 359      * specified standard namespace.
 360      * @param desc the call site descriptor.
 361      * @param operation the operation whose presence is tested.
 362      * @param namespace the namespace on which the operation operates.
 363      * @return Returns true if the call site descriptor contains the specified standard operation on the
 364      * specified standard namespace.
 365      */
 366     public static boolean contains(final CallSiteDescriptor desc, final StandardOperation operation, final StandardNamespace namespace) {
 367         return NamespaceOperation.contains(NamedOperation.getBaseOperation(desc.getOperation()), operation, namespace);
 368     }
 369 
 370     /**
 371      * Returns the error message to be used when CALL or NEW is used on a non-function.
 372      *
 373      * @param obj object on which CALL or NEW is used
 374      * @return error message
 375      */
 376     private String getFunctionErrorMessage(final Object obj) {
 377         final String funcDesc = getOperand(this);
 378         return funcDesc != null? funcDesc : ScriptRuntime.safeToString(obj);
 379     }
 380 
 381     /**
 382      * Returns the error message to be used when CALL or NEW is used on a non-function.
 383      *
 384      * @param desc call site descriptor
 385      * @param obj object on which CALL or NEW is used
 386      * @return error message
 387      */
 388     public static String getFunctionErrorMessage(final CallSiteDescriptor desc, final Object obj) {
 389         return desc instanceof NashornCallSiteDescriptor ?
 390                 ((NashornCallSiteDescriptor)desc).getFunctionErrorMessage(obj) :
 391                 ScriptRuntime.safeToString(obj);
 392     }
 393 
 394     /**
 395      * Returns the Nashorn-specific flags for this call site descriptor.
 396      * @param desc the descriptor. It can be any kind of a call site descriptor, not necessarily a
 397      * {@code NashornCallSiteDescriptor}. This allows for graceful interoperability when linking Nashorn with code
 398      * generated outside of Nashorn.
 399      * @return the Nashorn-specific flags for the call site, or 0 if the passed descriptor is not a Nashorn call site
 400      * descriptor.
 401      */
 402     public static int getFlags(final CallSiteDescriptor desc) {
 403         return desc instanceof NashornCallSiteDescriptor ? ((NashornCallSiteDescriptor)desc).flags : 0;
 404     }
 405 
 406     /**
 407      * Returns true if this descriptor has the specified flag set, see {@code CALLSITE_*} constants in this class.
 408      * @param flag the tested flag
 409      * @return true if the flag is set, false otherwise
 410      */
 411     private boolean isFlag(final int flag) {
 412         return (flags & flag) != 0;
 413     }
 414 
 415     /**
 416      * Returns true if this descriptor has the specified flag set, see {@code CALLSITE_*} constants in this class.
 417      * @param desc the descriptor. It can be any kind of a call site descriptor, not necessarily a
 418      * {@code NashornCallSiteDescriptor}. This allows for graceful interoperability when linking Nashorn with code
 419      * generated outside of Nashorn.
 420      * @param flag the tested flag
 421      * @return true if the flag is set, false otherwise (it will be false if the descriptor is not a Nashorn call site
 422      * descriptor).
 423      */
 424     private static boolean isFlag(final CallSiteDescriptor desc, final int flag) {
 425         return (getFlags(desc) & flag) != 0;
 426     }
 427 
 428     /**
 429      * Returns true if this descriptor is a Nashorn call site descriptor and has the {@link  #CALLSITE_SCOPE} 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 isScope(final CallSiteDescriptor desc) {
 436         return isFlag(desc, CALLSITE_SCOPE);
 437     }
 438 
 439     /**
 440      * Returns true if this descriptor is a Nashorn call site descriptor and has the {@link  #CALLSITE_FAST_SCOPE} flag set.
 441      * @param desc the descriptor. It can be any kind of a call site descriptor, not necessarily a
 442      * {@code NashornCallSiteDescriptor}. This allows for graceful interoperability when linking Nashorn with code
 443      * generated outside of Nashorn.
 444      * @return true if the descriptor is a Nashorn call site descriptor, and the flag is set, false otherwise.
 445      */
 446     public static boolean isFastScope(final CallSiteDescriptor desc) {
 447         return isFlag(desc, CALLSITE_FAST_SCOPE);
 448     }
 449 
 450     /**
 451      * Returns true if this descriptor is a Nashorn call site descriptor and has the {@link  #CALLSITE_STRICT} flag set.
 452      * @param desc the descriptor. It can be any kind of a call site descriptor, not necessarily a
 453      * {@code NashornCallSiteDescriptor}. This allows for graceful interoperability when linking Nashorn with code
 454      * generated outside of Nashorn.
 455      * @return true if the descriptor is a Nashorn call site descriptor, and the flag is set, false otherwise.
 456      */
 457     public static boolean isStrict(final CallSiteDescriptor desc) {
 458         return isFlag(desc, CALLSITE_STRICT);
 459     }
 460 
 461     /**
 462      * Returns true if this is an apply call that we try to call as
 463      * a "call"
 464      * @param desc descriptor
 465      * @return true if apply to call
 466      */
 467     public static boolean isApplyToCall(final CallSiteDescriptor desc) {
 468         return isFlag(desc, CALLSITE_APPLY_TO_CALL);
 469     }
 470 
 471     /**
 472      * Is this an optimistic call site
 473      * @param desc descriptor
 474      * @return true if optimistic
 475      */
 476     public static boolean isOptimistic(final CallSiteDescriptor desc) {
 477         return isFlag(desc, CALLSITE_OPTIMISTIC);
 478     }
 479 
 480     /**
 481      * Does this callsite contain a declaration for its target?
 482      * @param desc descriptor
 483      * @return true if contains declaration
 484      */
 485     public static boolean isDeclaration(final CallSiteDescriptor desc) {
 486         return isFlag(desc, CALLSITE_DECLARE);
 487     }
 488 
 489     /**
 490      * Returns true if {@code flags} has the {@link  #CALLSITE_STRICT} bit set.
 491      * @param flags the flags
 492      * @return true if the flag is set, false otherwise.
 493      */
 494     public static boolean isStrictFlag(final int flags) {
 495         return (flags & CALLSITE_STRICT) != 0;
 496     }
 497 
 498     /**
 499      * Returns true if {@code flags} has the {@link  #CALLSITE_SCOPE} bit set.
 500      * @param flags the flags
 501      * @return true if the flag is set, false otherwise.
 502      */
 503     public static boolean isScopeFlag(final int flags) {
 504         return (flags & CALLSITE_SCOPE) != 0;
 505     }
 506 
 507     /**
 508      * Get a program point from a descriptor (must be optimistic)
 509      * @param desc descriptor
 510      * @return program point
 511      */
 512     public static int getProgramPoint(final CallSiteDescriptor desc) {
 513         assert isOptimistic(desc) : "program point requested from non-optimistic descriptor " + desc;
 514         return getFlags(desc) >> CALLSITE_PROGRAM_POINT_SHIFT;
 515     }
 516 
 517     boolean isProfile() {
 518         return isFlag(CALLSITE_PROFILE);
 519     }
 520 
 521     boolean isTrace() {
 522         return isFlag(CALLSITE_TRACE);
 523     }
 524 
 525     boolean isTraceMisses() {
 526         return isFlag(CALLSITE_TRACE_MISSES);
 527     }
 528 
 529     boolean isTraceEnterExit() {
 530         return isFlag(CALLSITE_TRACE_ENTEREXIT);
 531     }
 532 
 533     boolean isTraceObjects() {
 534         return isFlag(CALLSITE_TRACE_VALUES);
 535     }
 536 
 537     boolean isOptimistic() {
 538         return isFlag(CALLSITE_OPTIMISTIC);
 539     }
 540 
 541     @Override
 542     public CallSiteDescriptor changeMethodTypeInternal(final MethodType newMethodType) {
 543         return get(getLookupPrivileged(), getOperation(), newMethodType, flags);
 544     }
 545 
 546     @Override
 547     protected CallSiteDescriptor changeOperationInternal(final Operation newOperation) {
 548         return get(getLookupPrivileged(), newOperation, getMethodType(), flags);
 549     }
 550 }