< prev index next >

src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptFunction.java

Print this page




 718         }
 719     }
 720 
 721     /**
 722      * Length getter - ECMA 15.3.3.2: Function.length
 723      *
 724      * @param self self reference
 725      * @return length
 726      */
 727     public static int G$length(final Object self) {
 728         if (self instanceof ScriptFunction) {
 729             return ((ScriptFunction) self).data.getArity();
 730         }
 731 
 732         return 0;
 733     }
 734 
 735     /**
 736      * Name getter - ECMA Function.name
 737      *
 738      * @param self self refence
 739      * @return the name, or undefined if none
 740      */
 741     public static Object G$name(final Object self) {
 742         if (self instanceof ScriptFunction) {
 743             return ((ScriptFunction) self).getName();
 744         }
 745 
 746         return UNDEFINED;
 747     }
 748 
 749     /**
 750      * Get the prototype for this ScriptFunction
 751      *
 752      * @param constructor constructor
 753      * @return prototype, or null if given constructor is not a ScriptFunction
 754      */
 755     public static ScriptObject getPrototype(final ScriptFunction constructor) {
 756         if (constructor != null) {
 757             final Object proto = constructor.getPrototype();
 758             if (proto instanceof ScriptObject) {


1103                 }
1104             } else if (isFailedApplyToCall) {
1105                 appliedArgs[2] = ScriptRuntime.EMPTY_ARRAY;
1106             }
1107         }
1108 
1109         // Ask the linker machinery for an invocation of the target function
1110         final LinkRequest appliedRequest = request.replaceArguments(appliedDesc, appliedArgs);
1111 
1112         GuardedInvocation appliedInvocation;
1113         try {
1114             appliedInvocation = Bootstrap.getLinkerServices().getGuardedInvocation(appliedRequest);
1115         } catch (final RuntimeException | Error e) {
1116             throw e;
1117         } catch (final Exception e) {
1118             throw new RuntimeException(e);
1119         }
1120         assert appliedRequest != null; // Bootstrap.isCallable() returned true for args[1], so it must produce a linkage.
1121 
1122         final Class<?> applyFnType = descType.parameterType(0);
1123         MethodHandle inv = appliedInvocation.getInvocation(); //method handle from apply invocation. the applied function invocation


1124 
1125         if (isApply && !isFailedApplyToCall) {
1126             if (passesArgs) {
1127                 // Make sure that the passed argArray is converted to Object[] the same way NativeFunction.apply() would do it.
1128                 inv = MH.filterArguments(inv, 2, NativeFunction.TO_APPLY_ARGS);





1129             } else {
1130                 // If the original call site doesn't pass argArray, pass in an empty array
1131                 inv = MH.insertArguments(inv, 2, (Object) ScriptRuntime.EMPTY_ARRAY);
1132             }
1133         }
1134 
1135         if (isApplyToCall) {
1136             if (isFailedApplyToCall) {
1137                 //take the real arguments that were passed to a call and force them into the apply instead
1138                 Context.getContextTrusted().getLogger(ApplySpecialization.class).info("Collection arguments to revert call to apply in " + appliedFn);
1139                 inv = MH.asCollector(inv, Object[].class, realArgCount);
1140             } else {
1141                 appliedInvocation = appliedInvocation.addSwitchPoint(applyToCallSwitchPoint);
1142             }
1143         }
1144 
1145         if (!passesThis) {
1146             // If the original call site doesn't pass in a thisArg, pass in Global/undefined as needed
1147             inv = bindImplicitThis(appliedFn, inv);




1148         } else if (appliedFnNeedsWrappedThis) {
1149             // target function needs a wrapped this, so make sure we filter for that
1150             inv = MH.filterArguments(inv, 1, WRAP_THIS);



1151         }





1152         inv = MH.dropArguments(inv, 0, applyFnType);

1153 
1154         /*
1155          * Dropargs can only be non-()V in the case of isApply && !isFailedApplyToCall, which
1156          * is when we need to add arguments to the callsite to catch and ignore the synthetic
1157          * extra args that someone has added to the command line.
1158          */
1159         for (int i = 0; i < dropArgs.parameterCount(); i++) {
1160             inv = MH.dropArguments(inv, 4 + i, dropArgs.parameterType(i));
1161         }
1162 
1163         MethodHandle guard = appliedInvocation.getGuard();
1164         // If the guard checks the value of "this" but we aren't passing thisArg, insert the default one
1165         if (!passesThis && guard.type().parameterCount() > 1) {
1166             guard = bindImplicitThis(appliedFn, guard);
1167         }
1168         final MethodType guardType = guard.type();
1169 
1170         // We need to account for the dropped (apply|call) function argument.
1171         guard = MH.dropArguments(guard, 0, descType.parameterType(0));
1172         // Take the "isApplyFunction" guard, and bind it to this function.
1173         MethodHandle applyFnGuard = MH.insertArguments(IS_APPLY_FUNCTION, 2, this); //TODO replace this with switchpoint
1174         // Adapt the guard to receive all the arguments that the original guard does.
1175         applyFnGuard = MH.dropArguments(applyFnGuard, 2, guardType.parameterArray());
1176         // Fold the original function guard into our apply guard.
1177         guard = MH.foldArguments(applyFnGuard, guard);
1178 
1179         return appliedInvocation.replaceMethods(inv, guard);
1180     }
1181 
1182     /*
1183      * This method is used for linking nested apply. Specialized apply and call linking will create a variable arity
1184      * call site for an apply call; when createApplyOrCallCall sees a linking request for apply or call with
1185      * Nashorn-style variable arity call site (last argument type is Object[]) it'll delegate to this method.
1186      * This method converts the link request from a vararg to a non-vararg one (unpacks the array), then delegates back
1187      * to createApplyOrCallCall (with which it is thus mutually recursive), and adds appropriate argument spreaders to
1188      * invocation and the guard of whatever createApplyOrCallCall returned to adapt it back into a variable arity
1189      * invocation. It basically reduces the problem of vararg call site linking of apply and call back to the (already
1190      * solved by createApplyOrCallCall) non-vararg call site linking.
1191      */


1227         final int descParamCount = descType.parameterCount();
1228         final int spreadCount = guardParamCount - descParamCount + 1;
1229         if (spreadCount <= 0) {
1230             // Guard doesn't dip into the varargs
1231             return guard;
1232         }
1233 
1234         final MethodHandle arrayConvertingGuard;
1235         // If the last parameter type of the guard is an array, then it is already itself a guard for a vararg apply
1236         // invocation. We must filter the last argument with toApplyArgs otherwise deeper levels of nesting will fail
1237         // with ClassCastException of NativeArray to Object[].
1238         if (guardType.parameterType(guardParamCount - 1).isArray()) {
1239             arrayConvertingGuard = MH.filterArguments(guard, guardParamCount - 1, NativeFunction.TO_APPLY_ARGS);
1240         } else {
1241             arrayConvertingGuard = guard;
1242         }
1243 
1244         return ScriptObject.adaptHandleToVarArgCallSite(arrayConvertingGuard, descParamCount);
1245     }
1246 
1247     private static MethodHandle bindImplicitThis(final Object fn, final MethodHandle mh) {
1248         final MethodHandle bound;
1249         if (fn instanceof ScriptFunction && ((ScriptFunction) fn).needsWrappedThis()) {
1250             bound = MH.filterArguments(mh, 1, SCRIPTFUNCTION_GLOBALFILTER);
1251         } else {
1252             bound = mh;
1253         }
1254         return MH.insertArguments(bound, 1, ScriptRuntime.UNDEFINED);
1255     }
1256 
1257     /**
1258      * Used for noSuchMethod/noSuchProperty and JSAdapter hooks.
1259      *
1260      * These don't want a callee parameter, so bind that. Name binding is
1261      * optional.
1262      */
1263     MethodHandle getCallMethodHandle(final MethodType type, final String bindName) {
1264         return pairArguments(bindToNameIfNeeded(bindToCalleeIfNeeded(data.getGenericInvoker(scope)), bindName), type);
1265     }
1266 
1267     private static MethodHandle bindToNameIfNeeded(final MethodHandle methodHandle, final String bindName) {
1268         if (bindName == null) {
1269             return methodHandle;




 718         }
 719     }
 720 
 721     /**
 722      * Length getter - ECMA 15.3.3.2: Function.length
 723      *
 724      * @param self self reference
 725      * @return length
 726      */
 727     public static int G$length(final Object self) {
 728         if (self instanceof ScriptFunction) {
 729             return ((ScriptFunction) self).data.getArity();
 730         }
 731 
 732         return 0;
 733     }
 734 
 735     /**
 736      * Name getter - ECMA Function.name
 737      *
 738      * @param self self reference
 739      * @return the name, or undefined if none
 740      */
 741     public static Object G$name(final Object self) {
 742         if (self instanceof ScriptFunction) {
 743             return ((ScriptFunction) self).getName();
 744         }
 745 
 746         return UNDEFINED;
 747     }
 748 
 749     /**
 750      * Get the prototype for this ScriptFunction
 751      *
 752      * @param constructor constructor
 753      * @return prototype, or null if given constructor is not a ScriptFunction
 754      */
 755     public static ScriptObject getPrototype(final ScriptFunction constructor) {
 756         if (constructor != null) {
 757             final Object proto = constructor.getPrototype();
 758             if (proto instanceof ScriptObject) {


1103                 }
1104             } else if (isFailedApplyToCall) {
1105                 appliedArgs[2] = ScriptRuntime.EMPTY_ARRAY;
1106             }
1107         }
1108 
1109         // Ask the linker machinery for an invocation of the target function
1110         final LinkRequest appliedRequest = request.replaceArguments(appliedDesc, appliedArgs);
1111 
1112         GuardedInvocation appliedInvocation;
1113         try {
1114             appliedInvocation = Bootstrap.getLinkerServices().getGuardedInvocation(appliedRequest);
1115         } catch (final RuntimeException | Error e) {
1116             throw e;
1117         } catch (final Exception e) {
1118             throw new RuntimeException(e);
1119         }
1120         assert appliedRequest != null; // Bootstrap.isCallable() returned true for args[1], so it must produce a linkage.
1121 
1122         final Class<?> applyFnType = descType.parameterType(0);
1123         // Invocation and guard handles from apply invocation.
1124         MethodHandle inv = appliedInvocation.getInvocation();
1125         MethodHandle guard = appliedInvocation.getGuard();
1126 
1127         if (isApply && !isFailedApplyToCall) {
1128             if (passesArgs) {
1129                 // Make sure that the passed argArray is converted to Object[] the same way NativeFunction.apply() would do it.
1130                 inv = MH.filterArguments(inv, 2, NativeFunction.TO_APPLY_ARGS);
1131                 // Some guards (non-strict functions with non-primitive this) have a this-object parameter, so we
1132                 // need to apply this transformations to them as well.
1133                 if (guard.type().parameterCount() > 2) {
1134                     guard = MH.filterArguments(guard, 2, NativeFunction.TO_APPLY_ARGS);
1135                 }
1136             } else {
1137                 // If the original call site doesn't pass argArray, pass in an empty array
1138                 inv = MH.insertArguments(inv, 2, (Object) ScriptRuntime.EMPTY_ARRAY);
1139             }
1140         }
1141 
1142         if (isApplyToCall) {
1143             if (isFailedApplyToCall) {
1144                 //take the real arguments that were passed to a call and force them into the apply instead
1145                 Context.getContextTrusted().getLogger(ApplySpecialization.class).info("Collection arguments to revert call to apply in " + appliedFn);
1146                 inv = MH.asCollector(inv, Object[].class, realArgCount);
1147             } else {
1148                 appliedInvocation = appliedInvocation.addSwitchPoint(applyToCallSwitchPoint);
1149             }
1150         }
1151 
1152         if (!passesThis) {
1153             // If the original call site doesn't pass in a thisArg, pass in Global/undefined as needed
1154             inv = bindImplicitThis(appliedFnNeedsWrappedThis, inv);
1155             // guard may have this-parameter that needs to be inserted
1156             if (guard.type().parameterCount() > 1) {
1157                 guard = bindImplicitThis(appliedFnNeedsWrappedThis, guard);
1158             }
1159         } else if (appliedFnNeedsWrappedThis) {
1160             // target function needs a wrapped this, so make sure we filter for that
1161             inv = MH.filterArguments(inv, 1, WRAP_THIS);
1162             // guard may have this-parameter that needs to be wrapped
1163             if (guard.type().parameterCount() > 1) {
1164                 guard = MH.filterArguments(guard, 1, WRAP_THIS);
1165             }
1166         }
1167 
1168         final MethodType guardType = guard.type(); // Needed for combining guards below
1169 
1170         // We need to account for the dropped (apply|call) function argument.
1171         inv = MH.dropArguments(inv, 0, applyFnType);
1172         guard = MH.dropArguments(guard, 0, applyFnType);
1173 
1174         /*
1175          * Dropargs can only be non-()V in the case of isApply && !isFailedApplyToCall, which
1176          * is when we need to add arguments to the callsite to catch and ignore the synthetic
1177          * extra args that someone has added to the command line.
1178          */
1179         for (int i = 0; i < dropArgs.parameterCount(); i++) {
1180             inv = MH.dropArguments(inv, 4 + i, dropArgs.parameterType(i));
1181         }
1182 









1183         // Take the "isApplyFunction" guard, and bind it to this function.
1184         MethodHandle applyFnGuard = MH.insertArguments(IS_APPLY_FUNCTION, 2, this); //TODO replace this with switchpoint
1185         // Adapt the guard to receive all the arguments that the original guard does.
1186         applyFnGuard = MH.dropArguments(applyFnGuard, 2, guardType.parameterArray());
1187         // Fold the original function guard into our apply guard.
1188         guard = MH.foldArguments(applyFnGuard, guard);
1189 
1190         return appliedInvocation.replaceMethods(inv, guard);
1191     }
1192 
1193     /*
1194      * This method is used for linking nested apply. Specialized apply and call linking will create a variable arity
1195      * call site for an apply call; when createApplyOrCallCall sees a linking request for apply or call with
1196      * Nashorn-style variable arity call site (last argument type is Object[]) it'll delegate to this method.
1197      * This method converts the link request from a vararg to a non-vararg one (unpacks the array), then delegates back
1198      * to createApplyOrCallCall (with which it is thus mutually recursive), and adds appropriate argument spreaders to
1199      * invocation and the guard of whatever createApplyOrCallCall returned to adapt it back into a variable arity
1200      * invocation. It basically reduces the problem of vararg call site linking of apply and call back to the (already
1201      * solved by createApplyOrCallCall) non-vararg call site linking.
1202      */


1238         final int descParamCount = descType.parameterCount();
1239         final int spreadCount = guardParamCount - descParamCount + 1;
1240         if (spreadCount <= 0) {
1241             // Guard doesn't dip into the varargs
1242             return guard;
1243         }
1244 
1245         final MethodHandle arrayConvertingGuard;
1246         // If the last parameter type of the guard is an array, then it is already itself a guard for a vararg apply
1247         // invocation. We must filter the last argument with toApplyArgs otherwise deeper levels of nesting will fail
1248         // with ClassCastException of NativeArray to Object[].
1249         if (guardType.parameterType(guardParamCount - 1).isArray()) {
1250             arrayConvertingGuard = MH.filterArguments(guard, guardParamCount - 1, NativeFunction.TO_APPLY_ARGS);
1251         } else {
1252             arrayConvertingGuard = guard;
1253         }
1254 
1255         return ScriptObject.adaptHandleToVarArgCallSite(arrayConvertingGuard, descParamCount);
1256     }
1257 
1258     private static MethodHandle bindImplicitThis(final boolean needsWrappedThis, final MethodHandle mh) {
1259         final MethodHandle bound;
1260         if (needsWrappedThis) {
1261             bound = MH.filterArguments(mh, 1, SCRIPTFUNCTION_GLOBALFILTER);
1262         } else {
1263             bound = mh;
1264         }
1265         return MH.insertArguments(bound, 1, ScriptRuntime.UNDEFINED);
1266     }
1267 
1268     /**
1269      * Used for noSuchMethod/noSuchProperty and JSAdapter hooks.
1270      *
1271      * These don't want a callee parameter, so bind that. Name binding is
1272      * optional.
1273      */
1274     MethodHandle getCallMethodHandle(final MethodType type, final String bindName) {
1275         return pairArguments(bindToNameIfNeeded(bindToCalleeIfNeeded(data.getGenericInvoker(scope)), bindName), type);
1276     }
1277 
1278     private static MethodHandle bindToNameIfNeeded(final MethodHandle methodHandle, final String bindName) {
1279         if (bindName == null) {
1280             return methodHandle;


< prev index next >