src/jdk/nashorn/internal/runtime/ScriptFunctionData.java

Print this page




  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