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;
|