remove arity restriction (as def call incorporates all lambdas and all their captures)
This commit is contained in:
parent
b53d735602
commit
4d78be5b9e
|
@ -28,6 +28,7 @@ import java.lang.invoke.MethodHandle;
|
|||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodHandles.Lookup;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.util.BitSet;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
@ -222,19 +223,25 @@ public final class Def {
|
|||
*/
|
||||
static MethodHandle lookupMethod(Lookup lookup, MethodType callSiteType,
|
||||
Class<?> receiverClass, String name, Object args[]) throws Throwable {
|
||||
long recipe = (Long) args[0];
|
||||
String recipeString = (String) args[0];
|
||||
int numArguments = callSiteType.parameterCount();
|
||||
// simple case: no lambdas
|
||||
if (recipe == 0) {
|
||||
if (recipeString.isEmpty()) {
|
||||
return lookupMethodInternal(receiverClass, name, numArguments - 1).handle;
|
||||
}
|
||||
|
||||
// convert recipe string to a bitset for convenience (the code below should be refactored...)
|
||||
BitSet lambdaArgs = new BitSet();
|
||||
for (int i = 0; i < recipeString.length(); i++) {
|
||||
lambdaArgs.set(recipeString.charAt(i));
|
||||
}
|
||||
|
||||
// otherwise: first we have to compute the "real" arity. This is because we have extra arguments:
|
||||
// e.g. f(a, g(x), b, h(y), i()) looks like f(a, g, x, b, h, y, i).
|
||||
int arity = callSiteType.parameterCount() - 1;
|
||||
int upTo = 1;
|
||||
for (int i = 0; i < numArguments; i++) {
|
||||
if ((recipe & (1L << (i - 1))) != 0) {
|
||||
for (int i = 1; i < numArguments; i++) {
|
||||
if (lambdaArgs.get(i - 1)) {
|
||||
String signature = (String) args[upTo++];
|
||||
int numCaptures = Integer.parseInt(signature.substring(signature.indexOf(',')+1));
|
||||
arity -= numCaptures;
|
||||
|
@ -250,7 +257,7 @@ public final class Def {
|
|||
upTo = 1;
|
||||
for (int i = 1; i < numArguments; i++) {
|
||||
// its a functional reference, replace the argument with an impl
|
||||
if ((recipe & (1L << (i - 1))) != 0) {
|
||||
if (lambdaArgs.get(i - 1)) {
|
||||
// decode signature of form 'type.call,2'
|
||||
String signature = (String) args[upTo++];
|
||||
int separator = signature.indexOf('.');
|
||||
|
|
|
@ -397,11 +397,11 @@ public final class DefBootstrap {
|
|||
if (args.length == 0) {
|
||||
throw new BootstrapMethodError("Invalid number of parameters for method call");
|
||||
}
|
||||
if (args[0] instanceof Long == false) {
|
||||
if (args[0] instanceof String == false) {
|
||||
throw new BootstrapMethodError("Illegal parameter for method call: " + args[0]);
|
||||
}
|
||||
long recipe = (Long) args[0];
|
||||
int numLambdas = Long.bitCount(recipe);
|
||||
String recipe = (String) args[0];
|
||||
int numLambdas = recipe.length();
|
||||
if (numLambdas > type.parameterCount()) {
|
||||
throw new BootstrapMethodError("Illegal recipe for method call: too many bits");
|
||||
}
|
||||
|
|
|
@ -41,7 +41,7 @@ final class LDefCall extends ALink implements IDefLink {
|
|||
|
||||
final String name;
|
||||
final List<AExpression> arguments;
|
||||
long recipe;
|
||||
StringBuilder recipe;
|
||||
List<String> pointers = new ArrayList<>();
|
||||
|
||||
LDefCall(Location location, String name, List<AExpression> arguments) {
|
||||
|
@ -60,14 +60,7 @@ final class LDefCall extends ALink implements IDefLink {
|
|||
|
||||
@Override
|
||||
ALink analyze(Locals locals) {
|
||||
if (arguments.size() > 63) {
|
||||
// technically, the limitation is just methods with > 63 params, containing method references.
|
||||
// this is because we are lazy and use a long as a bitset. we can always change to a "string" if need be.
|
||||
// but NEED NOT BE. nothing with this many parameters is in the whitelist and we do not support varargs.
|
||||
throw new UnsupportedOperationException("methods with > 63 arguments are currently not supported");
|
||||
}
|
||||
|
||||
recipe = 0;
|
||||
recipe = new StringBuilder();
|
||||
int totalCaptures = 0;
|
||||
for (int argument = 0; argument < arguments.size(); ++argument) {
|
||||
AExpression expression = arguments.get(argument);
|
||||
|
@ -78,7 +71,9 @@ final class LDefCall extends ALink implements IDefLink {
|
|||
if (expression instanceof ILambda) {
|
||||
ILambda lambda = (ILambda) expression;
|
||||
pointers.add(lambda.getPointer());
|
||||
recipe |= (1L << (argument + totalCaptures)); // mark argument as deferred reference
|
||||
// encode this parameter as a deferred reference
|
||||
char ch = (char) (argument + totalCaptures);
|
||||
recipe.append(ch);
|
||||
totalCaptures += lambda.getCaptureCount();
|
||||
}
|
||||
|
||||
|
@ -124,7 +119,7 @@ final class LDefCall extends ALink implements IDefLink {
|
|||
|
||||
List<Object> args = new ArrayList<>();
|
||||
args.add(DefBootstrap.METHOD_CALL);
|
||||
args.add(recipe);
|
||||
args.add(recipe.toString());
|
||||
args.addAll(pointers);
|
||||
writer.invokeDynamic(name, signature.toString(), DEF_BOOTSTRAP_HANDLE, args.toArray());
|
||||
}
|
||||
|
|
|
@ -36,7 +36,7 @@ public class DefBootstrapTests extends ESTestCase {
|
|||
CallSite site = DefBootstrap.bootstrap(MethodHandles.publicLookup(),
|
||||
"toString",
|
||||
MethodType.methodType(String.class, Object.class),
|
||||
DefBootstrap.METHOD_CALL, 0L);
|
||||
DefBootstrap.METHOD_CALL, "");
|
||||
MethodHandle handle = site.dynamicInvoker();
|
||||
assertDepthEquals(site, 0);
|
||||
|
||||
|
@ -53,7 +53,7 @@ public class DefBootstrapTests extends ESTestCase {
|
|||
CallSite site = DefBootstrap.bootstrap(MethodHandles.publicLookup(),
|
||||
"toString",
|
||||
MethodType.methodType(String.class, Object.class),
|
||||
DefBootstrap.METHOD_CALL, 0L);
|
||||
DefBootstrap.METHOD_CALL, "");
|
||||
MethodHandle handle = site.dynamicInvoker();
|
||||
assertDepthEquals(site, 0);
|
||||
|
||||
|
@ -75,7 +75,7 @@ public class DefBootstrapTests extends ESTestCase {
|
|||
CallSite site = DefBootstrap.bootstrap(MethodHandles.publicLookup(),
|
||||
"toString",
|
||||
MethodType.methodType(String.class, Object.class),
|
||||
DefBootstrap.METHOD_CALL, 0L);
|
||||
DefBootstrap.METHOD_CALL, "");
|
||||
MethodHandle handle = site.dynamicInvoker();
|
||||
assertDepthEquals(site, 0);
|
||||
|
||||
|
@ -98,7 +98,7 @@ public class DefBootstrapTests extends ESTestCase {
|
|||
DefBootstrap.PIC site = (DefBootstrap.PIC) DefBootstrap.bootstrap(MethodHandles.publicLookup(),
|
||||
"size",
|
||||
MethodType.methodType(int.class, Object.class),
|
||||
DefBootstrap.METHOD_CALL, 0L);
|
||||
DefBootstrap.METHOD_CALL, "");
|
||||
site.depth = DefBootstrap.PIC.MAX_DEPTH; // mark megamorphic
|
||||
MethodHandle handle = site.dynamicInvoker();
|
||||
assertEquals(2, (int)handle.invokeExact((Object) Arrays.asList("1", "2")));
|
||||
|
|
Loading…
Reference in New Issue