/**
* Copyright (c) 2012-2016 André Bargull
* Alle Rechte vorbehalten / All Rights Reserved. Use is subject to license terms.
*
* <https://github.com/anba/es6draft>
*/
package com.github.anba.es6draft.runtime.types.builtins;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import com.github.anba.es6draft.runtime.ExecutionContext;
import com.github.anba.es6draft.runtime.Realm;
import com.github.anba.es6draft.runtime.internal.TailCallInvocation;
/**
* <h1>9 Ordinary and Exotic Objects Behaviours</h1>
* <ul>
* <li>9.3 Built-in Function Objects
* </ul>
*/
public final class NativeTailCallFunction extends BuiltinFunction {
// (ExecutionContext, ExecutionContext, Object, Object[]) -> Object
private final MethodHandle mh;
// (ExecutionContext, ExecutionContext, Object, Object[]) -> Object
private final MethodHandle tmh;
/**
* Constructs a new native tail-calling function.
*
* @param realm
* the realm object
* @param name
* the function name
* @param arity
* the function arity
* @param mh
* the method handle to the function code
*/
public NativeTailCallFunction(Realm realm, String name, int arity, MethodHandle mh) {
super(realm, name, arity);
this.mh = tailCallAdapter(mh);
this.tmh = mh;
createDefaultFunctionProperties();
}
private NativeTailCallFunction(NativeTailCallFunction original) {
super(original.getRealm(), original.getName(), original.getArity());
this.mh = original.mh;
this.tmh = original.tmh;
}
@Override
public NativeTailCallFunction clone() {
return new NativeTailCallFunction(this);
}
@Override
public MethodHandle getCallMethod() {
MethodHandle mh = MethodHandles.insertArguments(this.mh, 0, getRealm().defaultContext());
return MethodHandles.dropArguments(mh, 0, NativeTailCallFunction.class);
}
/**
* 9.3.1 [[Call]] (thisArgument, argumentsList)
*/
@Override
public Object call(ExecutionContext callerContext, Object thisValue, Object... args) {
try {
return mh.invokeExact(getRealm().defaultContext(), callerContext, thisValue, args);
} catch (Throwable e) {
throw NativeTailCallFunction.<RuntimeException> rethrow(e);
}
}
/**
* 9.3.1 [[Call]] (thisArgument, argumentsList)
*/
@Override
public Object tailCall(ExecutionContext callerContext, Object thisValue, Object... args) throws Throwable {
return tmh.invokeExact(getRealm().defaultContext(), callerContext, thisValue, args);
}
private static MethodHandle tailCallAdapter(MethodHandle mh) {
MethodHandle result = TailCallInvocation.getTailCallHandler();
result = MethodHandles.dropArguments(result, 2, Object.class, Object[].class);
result = MethodHandles.dropArguments(result, 1, ExecutionContext.class);
result = MethodHandles.foldArguments(result, mh);
return result;
}
@SuppressWarnings("unchecked")
private static <E extends Throwable> E rethrow(Throwable e) throws E {
throw (E) e;
}
}