Tue, 12 Mar 2013 15:30:53 +0100
8009718: Lazy execution architecture continued - ScriptFunctionData is either final or recompilable. Moved ScriptFunctionData creation logic away from runtime to compile time. Prepared for method generation/specialization. Got rid of ScriptFunctionImplTrampoline whose semantics could be done as part of the relinking anyway. Merge with the lookup package change.
Reviewed-by: attila, jlaskey
1 /*
2 * Copyright (c) 2010, 2013, 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 */
26 package jdk.nashorn.internal.runtime;
28 import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
29 import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
30 import static jdk.nashorn.internal.lookup.Lookup.MH;
32 import java.lang.invoke.MethodHandle;
33 import java.lang.invoke.MethodHandles;
34 import java.lang.invoke.MethodType;
36 import jdk.nashorn.internal.runtime.linker.JavaAdapterFactory;
38 /**
39 * A container for data needed to instantiate a specific {@link ScriptFunction} at runtime.
40 * Instances of this class are created during codegen and stored in script classes'
41 * constants array to reduce function instantiation overhead during runtime.
42 */
43 public abstract class ScriptFunctionData {
45 /** Name of the function or "" for anonynous functions */
46 protected final String name;
48 /** All versions of this function that have been generated to code */
49 protected final CompiledFunctions code;
51 private int arity;
53 private final boolean isStrict;
55 private final boolean isBuiltin;
57 private final boolean isConstructor;
59 private static final MethodHandle NEWFILTER = findOwnMH("newFilter", Object.class, Object.class, Object.class);
60 private static final MethodHandle BIND_VAR_ARGS = findOwnMH("bindVarArgs", Object[].class, Object[].class, Object[].class);
62 /**
63 * Constructor
64 *
65 * @param name script function name
66 * @param arity arity
67 * @param isStrict is the function strict
68 * @param isBuiltin is the function built in
69 * @param isConstructor is the function a constructor
70 */
71 protected ScriptFunctionData(final String name, final int arity, final boolean isStrict, final boolean isBuiltin, final boolean isConstructor) {
72 this.name = name;
73 this.arity = arity;
74 this.code = new CompiledFunctions();
75 this.isStrict = isStrict;
76 this.isBuiltin = isBuiltin;
77 this.isConstructor = isConstructor;
78 }
80 final int getArity() {
81 return arity;
82 }
84 /**
85 * Used from e.g. Native*$Constructors as an explicit call. TODO - make arity immutable and final
86 * @param arity new arity
87 */
88 void setArity(final int arity) {
89 this.arity = arity;
90 }
92 CompiledFunction bind(final CompiledFunction originalInv, final ScriptFunction fn, final Object self, final Object[] args) {
93 final MethodHandle boundInvoker = bindInvokeHandle(originalInv.getInvoker(), fn, self, args);
95 if (isConstructor()) {
96 ensureConstructor(originalInv);
97 return new CompiledFunction(boundInvoker, bindConstructHandle(originalInv.getConstructor(), fn, args));
98 }
100 return new CompiledFunction(boundInvoker);
101 }
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 }
111 boolean isBuiltin() {
112 return isBuiltin;
113 }
115 boolean isConstructor() {
116 return isConstructor;
117 }
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 }
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 }
134 String toSource() {
135 return "function " + (name == null ? "" : name) + "() { [native code] }";
136 }
138 String getName() {
139 return name;
140 }
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();
152 sb.append("name='").
153 append(name.isEmpty() ? "<anonymous>" : name).
154 append("' ").
155 append(code.size()).
156 append(" invokers=").
157 append(code);
159 return sb.toString();
160 }
162 /**
163 * Pick the best invoker, i.e. the one version of this method with as narrow and specific
164 * types as possible. If the call site arguments are objects, but boxed primitives we can
165 * also try to get a primitive version of the method and do an unboxing filter, but then
166 * we need to insert a guard that checks the argument is really always a boxed primitive
167 * and not suddenly a "real" object
168 *
169 * @param callSiteType callsite type
170 * @param args arguments at callsite on first trampoline invocation
171 * @return method handle to best invoker
172 */
173 MethodHandle getBestInvoker(final MethodType callSiteType, final Object[] args) {
174 return getBest(callSiteType).getInvoker();
175 }
177 MethodHandle getBestInvoker(final MethodType callSiteType) {
178 return getBestInvoker(callSiteType, null);
179 }
181 MethodHandle getBestConstructor(final MethodType callSiteType, final Object[] args) {
182 if (!isConstructor()) {
183 throw typeError("not.a.constructor", toSource());
184 }
185 ensureCodeGenerated();
187 final CompiledFunction best = getBest(callSiteType);
188 ensureConstructor(best);
189 return best.getConstructor();
190 }
192 MethodHandle getBestConstructor(final MethodType callSiteType) {
193 return getBestConstructor(callSiteType, null);
194 }
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 }
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 composeGenericMethod(code.mostGeneric().getInvoker());
217 }
219 private CompiledFunction getBest(final MethodType callSiteType) {
220 ensureCodeGenerated();
221 return code.best(callSiteType);
222 }
224 /**
225 * Allocates an object using this function's allocator.
226 * @return the object allocated using this function's allocator, or null if the function doesn't have an allocator.
227 */
228 ScriptObject allocate() {
229 return null;
230 }
232 /**
233 * This method is used to create the immutable portion of a bound function.
234 * See {@link ScriptFunction#makeBoundFunction(Object, Object[])}
235 *
236 * @param fn the original function being bound
237 * @param self this reference to bind. Can be null.
238 * @param args additional arguments to bind. Can be null.
239 */
240 ScriptFunctionData makeBoundFunctionData(final ScriptFunction fn, final Object self, final Object[] args) {
241 ensureCodeGenerated();
243 final Object[] allArgs = args == null ? ScriptRuntime.EMPTY_ARRAY : args;
244 final int length = args == null ? 0 : args.length;
246 CompiledFunctions boundList = new CompiledFunctions();
247 for (final CompiledFunction inv : code) {
248 boundList.add(bind(inv, fn, self, allArgs));
249 }
250 ScriptFunctionData boundData = new FinalScriptFunctionData(name, arity == -1 ? -1 : Math.max(0, arity - length), boundList, isStrict(), isBuiltin(), isConstructor());
251 return boundData;
252 }
254 /**
255 * Compose a constructor given a primordial constructor handle
256 *
257 * @param ctor primordial constructor handle
258 * @param needsCallee do we need to pass a callee
259 *
260 * @return the composed constructor
261 */
262 protected MethodHandle composeConstructor(final MethodHandle ctor, final boolean needsCallee) {
263 // If it was (callee, this, args...), permute it to (this, callee, args...). We're doing this because having
264 // "this" in the first argument position is what allows the elegant folded composition of
265 // (newFilter x constructor x allocator) further down below in the code. Also, ensure the composite constructor
266 // always returns Object.
267 MethodHandle composedCtor = needsCallee ? swapCalleeAndThis(ctor) : ctor;
269 composedCtor = changeReturnTypeToObject(composedCtor);
271 final MethodType ctorType = composedCtor.type();
273 // Construct a dropping type list for NEWFILTER, but don't include constructor "this" into it, so it's actually
274 // captured as "allocation" parameter of NEWFILTER after we fold the constructor into it.
275 // (this, [callee, ]args...) => ([callee, ]args...)
276 final Class<?>[] ctorArgs = ctorType.dropParameterTypes(0, 1).parameterArray();
278 // Fold constructor into newFilter that replaces the return value from the constructor with the originally
279 // allocated value when the originally allocated value is a primitive.
280 // (result, this, [callee, ]args...) x (this, [callee, ]args...) => (this, [callee, ]args...)
281 composedCtor = MH.foldArguments(MH.dropArguments(NEWFILTER, 2, ctorArgs), composedCtor);
283 // allocate() takes a ScriptFunction and returns a newly allocated ScriptObject...
284 if (needsCallee) {
285 // ...we either fold it into the previous composition, if we need both the ScriptFunction callee object and
286 // the newly allocated object in the arguments, so (this, callee, args...) x (callee) => (callee, args...),
287 // or...
288 return MH.foldArguments(composedCtor, ScriptFunction.ALLOCATE);
289 }
291 // ...replace the ScriptFunction argument with the newly allocated object, if it doesn't need the callee
292 // (this, args...) filter (callee) => (callee, args...)
293 return MH.filterArguments(composedCtor, 0, ScriptFunction.ALLOCATE);
294 }
296 /**
297 * If this function's method handles need a callee parameter, swap the order of first two arguments for the passed
298 * method handle. If this function's method handles don't need a callee parameter, returns the original method
299 * handle unchanged.
300 *
301 * @param mh a method handle with order of arguments {@code (callee, this, args...)}
302 *
303 * @return a method handle with order of arguments {@code (this, callee, args...)}
304 */
305 private static MethodHandle swapCalleeAndThis(final MethodHandle mh) {
306 final MethodType type = mh.type();
307 assert type.parameterType(0) == ScriptFunction.class : type;
308 assert type.parameterType(1) == Object.class : type;
309 final MethodType newType = type.changeParameterType(0, Object.class).changeParameterType(1, ScriptFunction.class);
310 final int[] reorder = new int[type.parameterCount()];
311 reorder[0] = 1;
312 assert reorder[1] == 0;
313 for (int i = 2; i < reorder.length; ++i) {
314 reorder[i] = i;
315 }
316 return MethodHandles.permuteArguments(mh, newType, reorder);
317 }
319 /**
320 * Convert this argument for non-strict functions according to ES 10.4.3
321 *
322 * @param thiz the this argument
323 *
324 * @return the converted this object
325 */
326 private Object convertThisObject(final Object thiz) {
327 if (!(thiz instanceof ScriptObject) && needsWrappedThis()) {
328 if (JSType.nullOrUndefined(thiz)) {
329 return Context.getGlobalTrusted();
330 }
332 if (isPrimitiveThis(thiz)) {
333 return ((GlobalObject)Context.getGlobalTrusted()).wrapAsObject(thiz);
334 }
335 }
337 return thiz;
338 }
340 static boolean isPrimitiveThis(final Object obj) {
341 return obj instanceof String || obj instanceof ConsString ||
342 obj instanceof Number || obj instanceof Boolean;
343 }
345 /**
346 * Creates an invoker method handle for a bound function.
347 *
348 * @param targetFn the function being bound
349 * @param originalInvoker an original invoker method handle for the function. This can be its generic invoker or
350 * any of its specializations.
351 * @param self the "this" value being bound
352 * @param args additional arguments being bound
353 *
354 * @return a bound invoker method handle that will bind the self value and the specified arguments. The resulting
355 * invoker never needs a callee; if the original invoker needed it, it will be bound to {@code fn}. The resulting
356 * invoker still takes an initial {@code this} parameter, but it is always dropped and the bound {@code self} passed
357 * to the original invoker on invocation.
358 */
359 private MethodHandle bindInvokeHandle(final MethodHandle originalInvoker, final ScriptFunction targetFn, final Object self, final Object[] args) {
360 // Is the target already bound? If it is, we won't bother binding either callee or self as they're already bound
361 // in the target and will be ignored anyway.
362 final boolean isTargetBound = targetFn.isBoundFunction();
364 final boolean needsCallee = needsCallee(originalInvoker);
365 assert needsCallee == needsCallee() : "callee contract violation 2";
366 assert !(isTargetBound && needsCallee); // already bound functions don't need a callee
368 final Object boundSelf = isTargetBound ? null : convertThisObject(self);
369 final MethodHandle boundInvoker;
371 if (isVarArg(originalInvoker)) {
372 // First, bind callee and this without arguments
373 final MethodHandle noArgBoundInvoker;
375 if (isTargetBound) {
376 // Don't bind either callee or this
377 noArgBoundInvoker = originalInvoker;
378 } else if (needsCallee) {
379 // Bind callee and this
380 noArgBoundInvoker = MH.insertArguments(originalInvoker, 0, targetFn, boundSelf);
381 } else {
382 // Only bind this
383 noArgBoundInvoker = MH.bindTo(originalInvoker, boundSelf);
384 }
385 // Now bind arguments
386 if (args.length > 0) {
387 boundInvoker = varArgBinder(noArgBoundInvoker, args);
388 } else {
389 boundInvoker = noArgBoundInvoker;
390 }
391 } else {
392 final Object[] boundArgs = new Object[Math.min(originalInvoker.type().parameterCount(), args.length + (isTargetBound ? 0 : (needsCallee ? 2 : 1)))];
393 int next = 0;
394 if (!isTargetBound) {
395 if (needsCallee) {
396 boundArgs[next++] = targetFn;
397 }
398 boundArgs[next++] = boundSelf;
399 }
400 // If more bound args were specified than the function can take, we'll just drop those.
401 System.arraycopy(args, 0, boundArgs, next, boundArgs.length - next);
402 // If target is already bound, insert additional bound arguments after "this" argument, at position 1;
403 // "this" will get dropped anyway by the target invoker. We previously asserted that already bound functions
404 // don't take a callee parameter, so we can know that the signature is (this[, args...]) therefore args
405 // start at position 1. If the function is not bound, we start inserting arguments at position 0.
406 boundInvoker = MH.insertArguments(originalInvoker, isTargetBound ? 1 : 0, boundArgs);
407 }
409 if (isTargetBound) {
410 return boundInvoker;
411 }
413 // If the target is not already bound, add a dropArguments that'll throw away the passed this
414 return MH.dropArguments(boundInvoker, 0, Object.class);
415 }
417 /**
418 * Creates a constructor method handle for a bound function using the passed constructor handle.
419 *
420 * @param originalConstructor the constructor handle to bind. It must be a composed constructor.
421 * @param fn the function being bound
422 * @param args arguments being bound
423 *
424 * @return a bound constructor method handle that will bind the specified arguments. The resulting constructor never
425 * needs a callee; if the original constructor needed it, it will be bound to {@code fn}. The resulting constructor
426 * still takes an initial {@code this} parameter and passes it to the underlying original constructor. Finally, if
427 * this script function data object has no constructor handle, null is returned.
428 */
429 private static MethodHandle bindConstructHandle(final MethodHandle originalConstructor, final ScriptFunction fn, final Object[] args) {
430 assert originalConstructor != null;
432 // If target function is already bound, don't bother binding the callee.
433 final MethodHandle calleeBoundConstructor = fn.isBoundFunction() ? originalConstructor :
434 MH.dropArguments(MH.bindTo(originalConstructor, fn), 0, ScriptFunction.class);
436 if (args.length == 0) {
437 return calleeBoundConstructor;
438 }
440 if (isVarArg(calleeBoundConstructor)) {
441 return varArgBinder(calleeBoundConstructor, args);
442 }
444 final Object[] boundArgs;
446 final int maxArgCount = calleeBoundConstructor.type().parameterCount() - 1;
447 if (args.length <= maxArgCount) {
448 boundArgs = args;
449 } else {
450 boundArgs = new Object[maxArgCount];
451 System.arraycopy(args, 0, boundArgs, 0, maxArgCount);
452 }
454 return MH.insertArguments(calleeBoundConstructor, 1, boundArgs);
455 }
457 /**
458 * Takes a method handle, and returns a potentially different method handle that can be used in
459 * {@code ScriptFunction#invoke(Object, Object...)} or {code ScriptFunction#construct(Object, Object...)}.
460 * The returned method handle will be sure to return {@code Object}, and will have all its parameters turned into
461 * {@code Object} as well, except for the following ones:
462 * <ul>
463 * <li>a last parameter of type {@code Object[]} which is used for vararg functions,</li>
464 * <li>the first argument, which is forced to be {@link ScriptFunction}, in case the function receives itself
465 * (callee) as an argument.</li>
466 * </ul>
467 *
468 * @param mh the original method handle
469 *
470 * @return the new handle, conforming to the rules above.
471 */
472 protected MethodHandle composeGenericMethod(final MethodHandle mh) {
473 final MethodType type = mh.type();
474 MethodType newType = type.generic();
475 if (isVarArg(mh)) {
476 newType = newType.changeParameterType(type.parameterCount() - 1, Object[].class);
477 }
478 if (needsCallee(mh)) {
479 newType = newType.changeParameterType(0, ScriptFunction.class);
480 }
481 return type.equals(newType) ? mh : mh.asType(newType);
482 }
484 /**
485 * Execute this script function.
486 *
487 * @param self Target object.
488 * @param arguments Call arguments.
489 * @return ScriptFunction result.
490 *
491 * @throws Throwable if there is an exception/error with the invocation or thrown from it
492 */
493 Object invoke(final ScriptFunction fn, final Object self, final Object... arguments) throws Throwable {
494 final MethodHandle mh = getGenericInvoker();
496 final Object selfObj = convertThisObject(self);
497 final Object[] args = arguments == null ? ScriptRuntime.EMPTY_ARRAY : arguments;
499 if (isVarArg(mh)) {
500 if (needsCallee(mh)) {
501 return mh.invokeExact(fn, selfObj, args);
502 }
503 return mh.invokeExact(selfObj, args);
504 }
506 final int paramCount = mh.type().parameterCount();
507 if (needsCallee(mh)) {
508 switch (paramCount) {
509 case 2:
510 return mh.invokeExact(fn, selfObj);
511 case 3:
512 return mh.invokeExact(fn, selfObj, getArg(args, 0));
513 case 4:
514 return mh.invokeExact(fn, selfObj, getArg(args, 0), getArg(args, 1));
515 case 5:
516 return mh.invokeExact(fn, selfObj, getArg(args, 0), getArg(args, 1), getArg(args, 2));
517 default:
518 return mh.invokeWithArguments(withArguments(fn, selfObj, paramCount, args));
519 }
520 }
522 switch (paramCount) {
523 case 1:
524 return mh.invokeExact(selfObj);
525 case 2:
526 return mh.invokeExact(selfObj, getArg(args, 0));
527 case 3:
528 return mh.invokeExact(selfObj, getArg(args, 0), getArg(args, 1));
529 case 4:
530 return mh.invokeExact(selfObj, getArg(args, 0), getArg(args, 1), getArg(args, 2));
531 default:
532 return mh.invokeWithArguments(withArguments(null, selfObj, paramCount, args));
533 }
534 }
536 private static Object getArg(final Object[] args, final int i) {
537 return i < args.length ? args[i] : UNDEFINED;
538 }
540 private static Object[] withArguments(final ScriptFunction fn, final Object self, final int argCount, final Object[] args) {
541 final Object[] finalArgs = new Object[argCount];
543 int nextArg = 0;
544 if (fn != null) {
545 //needs callee
546 finalArgs[nextArg++] = fn;
547 }
548 finalArgs[nextArg++] = self;
550 // Don't add more args that there is argCount in the handle (including self and callee).
551 for (int i = 0; i < args.length && nextArg < argCount;) {
552 finalArgs[nextArg++] = args[i++];
553 }
555 // If we have fewer args than argCount, pad with undefined.
556 while (nextArg < argCount) {
557 finalArgs[nextArg++] = UNDEFINED;
558 }
560 return finalArgs;
561 }
562 /**
563 * Takes a variable-arity method and binds a variable number of arguments in it. The returned method will filter the
564 * vararg array and pass a different array that prepends the bound arguments in front of the arguments passed on
565 * invocation
566 *
567 * @param mh the handle
568 * @param args the bound arguments
569 *
570 * @return the bound method handle
571 */
572 private static MethodHandle varArgBinder(final MethodHandle mh, final Object[] args) {
573 assert args != null;
574 assert args.length > 0;
575 return MH.filterArguments(mh, mh.type().parameterCount() - 1, MH.bindTo(BIND_VAR_ARGS, args));
576 }
578 /**
579 * Adapts the method handle so its return type is {@code Object}. If the handle's return type is already
580 * {@code Object}, the handle is returned unchanged.
581 *
582 * @param mh the handle to adapt
583 * @return the adapted handle
584 */
585 private static MethodHandle changeReturnTypeToObject(final MethodHandle mh) {
586 return MH.asType(mh, mh.type().changeReturnType(Object.class));
587 }
589 private void ensureConstructor(final CompiledFunction inv) {
590 if (!inv.hasConstructor()) {
591 inv.setConstructor(composeConstructor(inv.getInvoker(), needsCallee(inv.getInvoker())));
592 }
593 }
595 /**
596 * Heuristic to figure out if the method handle has a callee argument. If it's type is either
597 * {@code (boolean, Object, ScriptFunction, ...)} or {@code (Object, ScriptFunction, ...)}, then we'll assume it has
598 * a callee argument. We need this as the constructor above is not passed this information, and can't just blindly
599 * assume it's false (notably, it's being invoked for creation of new scripts, and scripts have scopes, therefore
600 * they also always receive a callee).
601 *
602 * @param mh the examined method handle
603 *
604 * @return true if the method handle expects a callee, false otherwise
605 */
606 protected static boolean needsCallee(final MethodHandle mh) {
607 final MethodType type = mh.type();
608 final int length = type.parameterCount();
610 if (length == 0) {
611 return false;
612 }
614 if (type.parameterType(0) == boolean.class) {
615 return length > 1 && type.parameterType(1) == ScriptFunction.class;
616 }
618 return type.parameterType(0) == ScriptFunction.class;
619 }
621 /**
622 * Check if a javascript function methodhandle is a vararg handle
623 *
624 * @param mh method handle to check
625 *
626 * @return true if vararg
627 */
628 protected static boolean isVarArg(final MethodHandle mh) {
629 final MethodType type = mh.type();
630 return type.parameterType(type.parameterCount() - 1).isArray();
631 }
633 @SuppressWarnings("unused")
634 private static Object[] bindVarArgs(final Object[] array1, final Object[] array2) {
635 if (array2 == null) {
636 // Must clone it, as we can't allow the receiving method to alter the array
637 return array1.clone();
638 }
640 final int l2 = array2.length;
641 if (l2 == 0) {
642 return array1.clone();
643 }
645 final int l1 = array1.length;
646 final Object[] concat = new Object[l1 + l2];
647 System.arraycopy(array1, 0, concat, 0, l1);
648 System.arraycopy(array2, 0, concat, l1, l2);
650 return concat;
651 }
653 @SuppressWarnings("unused")
654 private static Object newFilter(final Object result, final Object allocation) {
655 return (result instanceof ScriptObject || !JSType.isPrimitive(result))? result : allocation;
656 }
658 private static MethodHandle findOwnMH(final String name, final Class<?> rtype, final Class<?>... types) {
659 return MH.findStatic(MethodHandles.lookup(), ScriptFunctionData.class, name, MH.type(rtype, types));
660 }
661 }