SpecializedFunction.java revision 1040:cc3000241e57
1/* 2 * Copyright (c) 2010, 2014, 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.objects.annotations; 27 28import java.lang.annotation.ElementType; 29import java.lang.annotation.Retention; 30import java.lang.annotation.RetentionPolicy; 31import java.lang.annotation.Target; 32import java.lang.invoke.MethodHandle; 33import java.lang.invoke.SwitchPoint; 34import jdk.internal.dynalink.CallSiteDescriptor; 35import jdk.internal.dynalink.linker.LinkRequest; 36import jdk.nashorn.internal.runtime.ScriptFunction; 37 38/** 39 * The SpecializedFunction annotation is used to flag more type specific 40 * functions than the standard one in the native objects 41 */ 42@Retention(RetentionPolicy.RUNTIME) 43@Target(ElementType.METHOD) 44public @interface SpecializedFunction { 45 46 /** 47 * Functionality for testing if we are allowed to link a specialized 48 * function the first time we encounter it. Then the guard will handle the 49 * rest of the invocations 50 * 51 * This is the same for all callsites in Nashorn, the first time callsite is 52 * linked, we have to manually check that the linkage is OK. Even if we add 53 * a guard and it fails upon the first try, this is not good enough. 54 * (Symmetrical to how it works everywhere else in the Nashorn runtime). 55 * 56 * Here we abstract out a few of the most common link guard checks. 57 */ 58 public static abstract class LinkLogic { 59 /** 60 * Empty link logic instance - this is the default 61 * "no special linking or runtime guard behavior" 62 */ 63 public static final LinkLogic EMPTY_INSTANCE = new Empty(); 64 65 private static final SwitchPoint[] INVALIDATED_SWITCHPOINTS = new SwitchPoint[0]; 66 67 private SwitchPoint[] modificationSwitchPoints; //cache 68 69 /** Empty link logic class - allow all linking, no guards */ 70 private static final class Empty extends LinkLogic { 71 @Override 72 public boolean canLink(final Object self, final CallSiteDescriptor desc, final LinkRequest request) { 73 return true; 74 } 75 76 @Override 77 public boolean isEmpty() { 78 return true; 79 } 80 } 81 82 /** 83 * Get the class representing the empty link logic 84 * @return class representing empty link logic 85 */ 86 public static Class<? extends LinkLogic> getEmptyLinkLogicClass() { 87 return Empty.class; 88 } 89 90 /** 91 * Should this callsite relink when an exception is thrown 92 * 93 * @return the relink exception, or null if none 94 */ 95 public Class<? extends Throwable> getRelinkException() { 96 return null; 97 } 98 99 /** 100 * Is this link logic class empty - i.e. no special linking logic 101 * supplied 102 * 103 * @param clazz class to check 104 * 105 * @return true if this link logic is empty 106 */ 107 public static boolean isEmpty(final Class<? extends LinkLogic> clazz) { 108 return clazz == Empty.class; 109 } 110 111 /** 112 * Is this link logic instance empty - i.e. no special linking logic 113 * supplied 114 * 115 * @return true if this link logic instance is empty 116 */ 117 public boolean isEmpty() { 118 return false; 119 } 120 121 /** 122 * Given a callsite, can we link this method based on the receiver and 123 * parameters? 124 * 125 * @param self receiver 126 * @param desc callsite descriptor 127 * @param request link request 128 * 129 * @return true if we can link this callsite at this time 130 */ 131 public abstract boolean canLink(final Object self, final CallSiteDescriptor desc, final LinkRequest request); 132 133 /** 134 * Given a callsite, do we require an extra guard for specialization to 135 * go through? 136 * 137 * @param self receiver 138 * 139 * @return true if a guard is to be woven into the callsite 140 */ 141 public boolean needsGuard(final Object self) { 142 return true; 143 } 144 145 /** 146 * Given a callsite, and optional arguments, do we need an extra guard 147 * for specialization to go through - this guard can be a function of 148 * the arguments too 149 * 150 * @param self receiver 151 * @param args arguments 152 * 153 * @return true if a guard is to be woven into the callsite 154 */ 155 public boolean needsGuard(final Object self, final Object... args) { 156 return true; 157 } 158 159 /** 160 * Given a callsite, and optional arguments, return any extra guard we 161 * might need for specialization as a method handle. 162 * 163 * @return methodhandle for guard, or null if no guard is needed 164 */ 165 public MethodHandle getGuard() { 166 return null; 167 } 168 169 /** 170 * Return the modification SwitchPoint of a particular index from this OptimisticBuiltins 171 * If none exists, one is created and that one is return. 172 * 173 * The implementor must map indexes to specific SwitchPoints for specific events and keep 174 * track of what they mean, for example NativeArray.LENGTH_NOT_WRITABLE_SWITCHPOINT 175 * might be a useful index mapping 176 * 177 * @param index index for SwitchPoint to get or create 178 * @return modification SwitchPoint of particular index for the receiver 179 */ 180 public SwitchPoint getOrCreateModificationSwitchPoint(final int index) { 181 return null; 182 } 183 184 /** 185 * Return the modification SwitchPoint from this OptimisticBuiltins. If none 186 * exists, one is created and that one is return. 187 * 188 * @return modification SwitchPoint for the receiver 189 */ 190 public SwitchPoint[] getOrCreateModificationSwitchPoints() { 191 return null; 192 } 193 194 /** 195 * Hook to invalidate a modification SwitchPoint by index. 196 * 197 * @param index index for SwitchPoint to invalidate 198 */ 199 public void invalidateModificationSwitchPoint(final int index) { 200 //empty 201 } 202 203 /** 204 * Hook to invalidate all modification SwitchPoints for a receiver 205 */ 206 public void invalidateModificationSwitchPoints() { 207 //empty 208 } 209 210 /** 211 * Check whether the receiver has an invalidated modification SwitchPoint. 212 * 213 * @param index index for the modification SwitchPoint 214 * @return true if the particular SwitchPoint at the index is invalidated 215 */ 216 public boolean hasInvalidatedModificationSwitchPoint(final int index) { 217 return false; 218 } 219 220 /** 221 * Check whether at least one of the modification SwitchPoints has been 222 * invalidated 223 * @return true if one of the SwitchPoints has been invalidated 224 */ 225 public boolean hasInvalidatedModificationSwitchPoints() { 226 return false; 227 } 228 229 /** 230 * Check whether this OptimisticBuiltins has a SwitchPoints of particular 231 * index. 232 * 233 * As creation overhead for a SwitchPoint is non-zero, we have to create them lazily instead of, 234 * e.g. in the constructor of every subclass. 235 * 236 * @param index index for the modification SwitchPoint 237 * @return true if a modification SwitchPoint exists, no matter if it has been invalidated or not 238 */ 239 public boolean hasModificationSwitchPoint(final int index) { 240 return false; 241 } 242 243 /** 244 * Check whether this OptimisticBuiltins has SwitchPoints. 245 * 246 * As creation overhead for a SwitchPoint is non-zero, we have to create them lazily instead of, 247 * e.g. in the constructor of every subclass. 248 * 249 * @return true if a modification SwitchPoint exists, no matter if it has been invalidated or not 250 */ 251 public boolean hasModificationSwitchPoints() { 252 return false; 253 } 254 255 /** 256 * Check, given a link request and a receiver, if this specialization 257 * fits This is used by the linker in {@link ScriptFunction} to figure 258 * out if an optimistic builtin can be linked when first discovered 259 * 260 * @param self receiver 261 * @param desc callsite descriptor 262 * @param request link request 263 264 * @return true if we can link, false otherwise - that means we have to 265 * pick a non specialized target 266 */ 267 public boolean checkLinkable(final Object self, final CallSiteDescriptor desc, final LinkRequest request) { 268 // no matter what the modification switchpoints are, if any of them are invalidated, 269 // we can't link. Side effect is that if it's the first time we see this callsite, 270 // we have to create the SwitchPoint(s) so future modification switchpoint invalidations 271 // relink it 272 final SwitchPoint[] sps = getOrCreateModificationSwitchPoints(self); 273 if (sps == INVALIDATED_SWITCHPOINTS) { 274 // nope, can't do the fast link as this assumption 275 // has been invalidated already, e.g. length of an 276 // array set to not writable 277 return false; 278 } 279 modificationSwitchPoints = sps; //cache 280 281 // check the link guard, if it says we can link, go ahead 282 return canLink(self, desc, request); 283 } 284 285 private SwitchPoint[] getOrCreateModificationSwitchPoints(final Object self) { 286 final SwitchPoint[] sps = getOrCreateModificationSwitchPoints(); //ask for all my switchpoints 287 if (sps != null) { //switchpoint exists, but some may be invalidated 288 for (final SwitchPoint sp : sps) { 289 if (sp.hasBeenInvalidated()) { 290 return INVALIDATED_SWITCHPOINTS; 291 } 292 } 293 } 294 return sps; 295 } 296 297 /** 298 * Get the cached modification switchpoints. Only possible to do after a link 299 * check call has been performed, one that has answered "true", or you will get the 300 * wrong information. 301 * 302 * Should be used only from {@link ScriptFunction#findCallMethod} 303 * 304 * @return cached modification switchpoints for this callsite, null if none 305 */ 306 public SwitchPoint[] getModificationSwitchPoints() { 307 return modificationSwitchPoints == null ? null : modificationSwitchPoints.clone(); 308 } 309 } 310 311 /** 312 * name override for return value polymorphism, for example we can't have 313 * pop(V)I and pop(V)D in the same Java class, so they need to be named, 314 * e.g. popInt(V)I and popDouble(V)D for disambiguation, however, their 315 * names still need to resolve to "pop" to JavaScript so we can still 316 * specialize on return values and so that the linker can find them 317 * 318 * @return name, "" means no override, use the Java function name, e.g. 319 * "push" 320 */ 321 String name() default ""; 322 323 /** 324 * Return the guard for this specialized function. The default is no guard. 325 * 326 * @return guard 327 */ 328 Class<?> linkLogic() default LinkLogic.Empty.class; 329 330 /** 331 * Is this a specialized constructor? 332 */ 333 boolean isConstructor() default false; 334 335 /** 336 * Can this function throw UnwarrantedOptimismExceptions? This works just 337 * like the normal functions, but we need the function to be 338 * immutable/non-state modifying, as we can't generate continuations for 339 * native code. Luckily a lot of the methods we want to specialize have this 340 * property 341 */ 342 boolean isOptimistic() default false; 343} 344