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 }