30 import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED; 31 32 import java.lang.invoke.MethodHandle; 33 import java.lang.invoke.MethodHandles; 34 import java.lang.invoke.MethodType; 35 import jdk.nashorn.internal.runtime.linker.JavaAdapterFactory; 36 37 /** 38 * A container for data needed to instantiate a specific {@link ScriptFunction} at runtime. 39 * Instances of this class are created during codegen and stored in script classes' 40 * constants array to reduce function instantiation overhead during runtime. 41 */ 42 public abstract class ScriptFunctionData { 43 44 /** Name of the function or "" for anonynous functions */ 45 protected final String name; 46 47 /** All versions of this function that have been generated to code */ 48 protected final CompiledFunctions code; 49 50 private int arity; 51 52 private final boolean isStrict; 53 54 private final boolean isBuiltin; 55 56 private final boolean isConstructor; 57 58 private static final MethodHandle NEWFILTER = findOwnMH("newFilter", Object.class, Object.class, Object.class); 59 private static final MethodHandle BIND_VAR_ARGS = findOwnMH("bindVarArgs", Object[].class, Object[].class, Object[].class); 60 61 /** 62 * Constructor 63 * 64 * @param name script function name 65 * @param arity arity 66 * @param isStrict is the function strict 67 * @param isBuiltin is the function built in 68 * @param isConstructor is the function a constructor 69 */ 70 ScriptFunctionData(final String name, final int arity, final boolean isStrict, final boolean isBuiltin, final boolean isConstructor) { 71 this.name = name; 72 this.arity = arity; 73 this.code = new CompiledFunctions(); 74 this.isStrict = isStrict; 75 this.isBuiltin = isBuiltin; 76 this.isConstructor = isConstructor; 77 } 78 79 final int getArity() { 80 return arity; 81 } 82 83 /** 84 * Used from e.g. Native*$Constructors as an explicit call. TODO - make arity immutable and final 85 * @param arity new arity 86 */ 87 void setArity(final int arity) { 88 this.arity = arity; 89 } 90 91 CompiledFunction bind(final CompiledFunction originalInv, final ScriptFunction fn, final Object self, final Object[] args) { 92 final MethodHandle boundInvoker = bindInvokeHandle(originalInv.getInvoker(), fn, self, args); 93 94 //TODO the boundinvoker.type() could actually be more specific here 95 if (isConstructor()) { 96 ensureConstructor(originalInv); 97 return new CompiledFunction(boundInvoker.type(), boundInvoker, bindConstructHandle(originalInv.getConstructor(), fn, args)); 98 } 99 100 return new CompiledFunction(boundInvoker.type(), boundInvoker); 101 } 102 103 /** 104 * Is this a ScriptFunction generated with strict semantics? 105 * @return true if strict, false otherwise 106 */ 107 public boolean isStrict() { 108 return isStrict; 109 } 110 111 boolean isBuiltin() { 112 return isBuiltin; 113 } 114 115 boolean isConstructor() { 116 return isConstructor; 117 } 118 119 boolean needsCallee() { 120 // we don't know if we need a callee or not unless we are generated 121 ensureCodeGenerated(); 122 return code.needsCallee(); 123 } 124 125 /** 126 * Returns true if this is a non-strict, non-built-in function that requires non-primitive this argument 127 * according to ECMA 10.4.3. 128 * @return true if this argument must be an object 129 */ 130 boolean needsWrappedThis() { 131 return !isStrict && !isBuiltin; 132 } 133 134 String toSource() { 135 return "function " + (name == null ? "" : name) + "() { [native code] }"; 136 } 137 138 String getName() { 139 return name; 140 } 141 142 /** 143 * Get this function as a String containing its source code. If no source code 144 * exists in this ScriptFunction, its contents will be displayed as {@code [native code]} 145 * 146 * @return string representation of this function 147 */ 148 @Override 149 public String toString() { 150 final StringBuilder sb = new StringBuilder(); 151 185 ensureCodeGenerated(); 186 187 final CompiledFunction best = getBest(callSiteType); 188 ensureConstructor(best); 189 return best.getConstructor(); 190 } 191 192 MethodHandle getBestConstructor(final MethodType callSiteType) { 193 return getBestConstructor(callSiteType, null); 194 } 195 196 /** 197 * Subclass responsibility. If we can have lazy code generation, this is a hook to ensure that 198 * code exists before performing an operation. 199 */ 200 protected void ensureCodeGenerated() { 201 //empty 202 } 203 204 /** 205 * Return a generic Object/Object invoker for this method. It will ensure code 206 * is generated, get the most generic of all versions of this function and adapt it 207 * to Objects. 208 * 209 * TODO this is only public because {@link JavaAdapterFactory} can't supply us with 210 * a MethodType that we can use for lookup due to boostrapping problems. Can be fixed 211 * 212 * @return generic invoker of this script function 213 */ 214 public final MethodHandle getGenericInvoker() { 215 ensureCodeGenerated(); 216 return code.generic().getInvoker(); 217 } 218 219 final MethodHandle getGenericConstructor() { 220 ensureCodeGenerated(); 221 ensureConstructor(code.generic()); 222 return code.generic().getConstructor(); 223 } 224 242 * 243 * @return the property map for allocated objects. 244 */ 245 PropertyMap getAllocatorMap() { 246 return null; 247 } 248 249 /** 250 * This method is used to create the immutable portion of a bound function. 251 * See {@link ScriptFunction#makeBoundFunction(Object, Object[])} 252 * 253 * @param fn the original function being bound 254 * @param self this reference to bind. Can be null. 255 * @param args additional arguments to bind. Can be null. 256 */ 257 ScriptFunctionData makeBoundFunctionData(final ScriptFunction fn, final Object self, final Object[] args) { 258 ensureCodeGenerated(); 259 260 final Object[] allArgs = args == null ? ScriptRuntime.EMPTY_ARRAY : args; 261 final int length = args == null ? 0 : args.length; 262 263 CompiledFunctions boundList = new CompiledFunctions(); 264 if (code.size() == 1) { 265 // only one variant - bind that 266 boundList.add(bind(code.first(), fn, self, allArgs)); 267 } else { 268 // There are specialized versions. Get the most generic one. 269 // This is to avoid ambiguous overloaded versions of bound and 270 // specialized variants and choosing wrong overload. 271 final MethodHandle genInvoker = getGenericInvoker(); 272 final CompiledFunction inv = new CompiledFunction(genInvoker.type(), genInvoker, getGenericConstructor()); 273 boundList.add(bind(inv, fn, self, allArgs)); 274 } 275 276 ScriptFunctionData boundData = new FinalScriptFunctionData(name, arity == -1 ? -1 : Math.max(0, arity - length), boundList, isStrict(), isBuiltin(), isConstructor()); 277 return boundData; 278 } 279 280 /** 281 * Compose a constructor given a primordial constructor handle. 282 * 283 * @param ctor primordial constructor handle 284 * @return the composed constructor 285 */ 286 protected MethodHandle composeConstructor(final MethodHandle ctor) { 287 // If it was (callee, this, args...), permute it to (this, callee, args...). We're doing this because having 288 // "this" in the first argument position is what allows the elegant folded composition of 289 // (newFilter x constructor x allocator) further down below in the code. Also, ensure the composite constructor 290 // always returns Object. 291 final boolean needsCallee = needsCallee(ctor); 292 MethodHandle composedCtor = needsCallee ? swapCalleeAndThis(ctor) : ctor; 293 294 composedCtor = changeReturnTypeToObject(composedCtor); 295 296 final MethodType ctorType = composedCtor.type(); 297 | 30 import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED; 31 32 import java.lang.invoke.MethodHandle; 33 import java.lang.invoke.MethodHandles; 34 import java.lang.invoke.MethodType; 35 import jdk.nashorn.internal.runtime.linker.JavaAdapterFactory; 36 37 /** 38 * A container for data needed to instantiate a specific {@link ScriptFunction} at runtime. 39 * Instances of this class are created during codegen and stored in script classes' 40 * constants array to reduce function instantiation overhead during runtime. 41 */ 42 public abstract class ScriptFunctionData { 43 44 /** Name of the function or "" for anonynous functions */ 45 protected final String name; 46 47 /** All versions of this function that have been generated to code */ 48 protected final CompiledFunctions code; 49 50 /** Function flags */ 51 protected int flags; 52 53 private int arity; 54 55 private static final MethodHandle NEWFILTER = findOwnMH("newFilter", Object.class, Object.class, Object.class); 56 private static final MethodHandle BIND_VAR_ARGS = findOwnMH("bindVarArgs", Object[].class, Object[].class, Object[].class); 57 58 /** Is this a strict mode function? */ 59 public static final int IS_STRICT = 0b0000_0001; 60 /** Is this a built-in function? */ 61 public static final int IS_BUILTIN = 0b0000_0010; 62 /** Is this a constructor function? */ 63 public static final int IS_CONSTRUCTOR = 0b0000_0100; 64 /** Does this function expect a callee argument? */ 65 public static final int NEEDS_CALLEE = 0b0000_1000; 66 /** Does this function make use of the this-object argument? */ 67 public static final int USES_THIS = 0b0001_0000; 68 69 /** Flag for strict or built-in functions */ 70 public static final int IS_STRICT_OR_BUILTIN = IS_STRICT | IS_BUILTIN; 71 /** Flag for built-in constructors */ 72 public static final int IS_BUILTIN_CONSTRUCTOR = IS_BUILTIN | IS_CONSTRUCTOR; 73 /** Flag for strict constructors */ 74 public static final int IS_STRICT_CONSTRUCTOR = IS_STRICT | IS_CONSTRUCTOR; 75 76 77 /** 78 * Constructor 79 * 80 * @param name script function name 81 * @param arity arity 82 * @param flags the function flags 83 */ 84 ScriptFunctionData(final String name, final int arity, final int flags) { 85 this.name = name; 86 this.arity = arity; 87 this.code = new CompiledFunctions(); 88 this.flags = flags; 89 } 90 91 final int getArity() { 92 return arity; 93 } 94 95 /** 96 * Used from e.g. Native*$Constructors as an explicit call. TODO - make arity immutable and final 97 * @param arity new arity 98 */ 99 void setArity(final int arity) { 100 this.arity = arity; 101 } 102 103 CompiledFunction bind(final CompiledFunction originalInv, final ScriptFunction fn, final Object self, final Object[] args) { 104 final MethodHandle boundInvoker = bindInvokeHandle(originalInv.getInvoker(), fn, self, args); 105 106 //TODO the boundinvoker.type() could actually be more specific here 107 if (isConstructor()) { 108 ensureConstructor(originalInv); 109 return new CompiledFunction(boundInvoker.type(), boundInvoker, bindConstructHandle(originalInv.getConstructor(), fn, args)); 110 } 111 112 return new CompiledFunction(boundInvoker.type(), boundInvoker); 113 } 114 115 /** 116 * Is this a ScriptFunction generated with strict semantics? 117 * @return true if strict, false otherwise 118 */ 119 public boolean isStrict() { 120 return (flags & IS_STRICT) != 0; 121 } 122 123 boolean isBuiltin() { 124 return (flags & IS_BUILTIN) != 0; 125 } 126 127 boolean isConstructor() { 128 return (flags & IS_CONSTRUCTOR) != 0; 129 } 130 131 boolean needsCallee() { 132 // we don't know if we need a callee or not unless code has been compiled 133 ensureCompiled(); 134 return (flags & NEEDS_CALLEE) != 0; 135 } 136 137 /** 138 * Returns true if this is a non-strict, non-built-in function that requires non-primitive this argument 139 * according to ECMA 10.4.3. 140 * @return true if this argument must be an object 141 */ 142 boolean needsWrappedThis() { 143 return (flags & USES_THIS) != 0 && (flags & IS_STRICT_OR_BUILTIN) == 0; 144 } 145 146 String toSource() { 147 return "function " + (name == null ? "" : name) + "() { [native code] }"; 148 } 149 150 String getName() { 151 return name; 152 } 153 154 /** 155 * Get this function as a String containing its source code. If no source code 156 * exists in this ScriptFunction, its contents will be displayed as {@code [native code]} 157 * 158 * @return string representation of this function 159 */ 160 @Override 161 public String toString() { 162 final StringBuilder sb = new StringBuilder(); 163 197 ensureCodeGenerated(); 198 199 final CompiledFunction best = getBest(callSiteType); 200 ensureConstructor(best); 201 return best.getConstructor(); 202 } 203 204 MethodHandle getBestConstructor(final MethodType callSiteType) { 205 return getBestConstructor(callSiteType, null); 206 } 207 208 /** 209 * Subclass responsibility. If we can have lazy code generation, this is a hook to ensure that 210 * code exists before performing an operation. 211 */ 212 protected void ensureCodeGenerated() { 213 //empty 214 } 215 216 /** 217 * If we can have lazy code generation, this is a hook to ensure that the code has been compiled. 218 * This does not guarantee the code been installed in this {@code ScriptFunctionData} instance; 219 * use {@link #ensureCodeGenerated()} to install the actual method handles. 220 */ 221 protected void ensureCompiled() { 222 //empty 223 } 224 225 /** 226 * Return a generic Object/Object invoker for this method. It will ensure code 227 * is generated, get the most generic of all versions of this function and adapt it 228 * to Objects. 229 * 230 * TODO this is only public because {@link JavaAdapterFactory} can't supply us with 231 * a MethodType that we can use for lookup due to boostrapping problems. Can be fixed 232 * 233 * @return generic invoker of this script function 234 */ 235 public final MethodHandle getGenericInvoker() { 236 ensureCodeGenerated(); 237 return code.generic().getInvoker(); 238 } 239 240 final MethodHandle getGenericConstructor() { 241 ensureCodeGenerated(); 242 ensureConstructor(code.generic()); 243 return code.generic().getConstructor(); 244 } 245 263 * 264 * @return the property map for allocated objects. 265 */ 266 PropertyMap getAllocatorMap() { 267 return null; 268 } 269 270 /** 271 * This method is used to create the immutable portion of a bound function. 272 * See {@link ScriptFunction#makeBoundFunction(Object, Object[])} 273 * 274 * @param fn the original function being bound 275 * @param self this reference to bind. Can be null. 276 * @param args additional arguments to bind. Can be null. 277 */ 278 ScriptFunctionData makeBoundFunctionData(final ScriptFunction fn, final Object self, final Object[] args) { 279 ensureCodeGenerated(); 280 281 final Object[] allArgs = args == null ? ScriptRuntime.EMPTY_ARRAY : args; 282 final int length = args == null ? 0 : args.length; 283 // Clear the callee and this flags 284 final int boundFlags = flags & ~NEEDS_CALLEE & ~USES_THIS; 285 286 CompiledFunctions boundList = new CompiledFunctions(); 287 if (code.size() == 1) { 288 // only one variant - bind that 289 boundList.add(bind(code.first(), fn, self, allArgs)); 290 } else { 291 // There are specialized versions. Get the most generic one. 292 // This is to avoid ambiguous overloaded versions of bound and 293 // specialized variants and choosing wrong overload. 294 final MethodHandle genInvoker = getGenericInvoker(); 295 final CompiledFunction inv = new CompiledFunction(genInvoker.type(), genInvoker, getGenericConstructor()); 296 boundList.add(bind(inv, fn, self, allArgs)); 297 } 298 299 return new FinalScriptFunctionData(name, arity == -1 ? -1 : Math.max(0, arity - length), boundList, boundFlags); 300 } 301 302 /** 303 * Compose a constructor given a primordial constructor handle. 304 * 305 * @param ctor primordial constructor handle 306 * @return the composed constructor 307 */ 308 protected MethodHandle composeConstructor(final MethodHandle ctor) { 309 // If it was (callee, this, args...), permute it to (this, callee, args...). We're doing this because having 310 // "this" in the first argument position is what allows the elegant folded composition of 311 // (newFilter x constructor x allocator) further down below in the code. Also, ensure the composite constructor 312 // always returns Object. 313 final boolean needsCallee = needsCallee(ctor); 314 MethodHandle composedCtor = needsCallee ? swapCalleeAndThis(ctor) : ctor; 315 316 composedCtor = changeReturnTypeToObject(composedCtor); 317 318 final MethodType ctorType = composedCtor.type(); 319 |