Translating lambda expressions as Synthetic static methods: Capturing final or effectively final states from multiple scopes
Ali Ebrahimi
ali.ebrahimi1781 at gmail.com
Sat Jun 25 03:16:44 PDT 2011
Hi all,
This post is first one from series of Translating lambda expressions
as *Synthetic
*(static) methods
scenario 1:Capturing final or effectively final states from multiple scopes
The used approach in this case is to construct the signature of the lowered
method by prepending all the captured finals to the free variables.
static class D {
public void foo() {
int[] grandTotal = {0};
MList<Department> departments = new MList.MListImpl<>();
departments.add(new Department("dep1"));
departments.add(new Department("dep2"));
MList<Employee> employees = new MList.MListImpl<>();
for (int i = 0; i < 100; i++) {
employees.add(new Employee(departments.get(i%2),i+100));
}
departments.forEach( #{Department d ->
int[] deptTotal = {0};
employees.filter(#{Employee e -> e.dept == d
}).forEach(#{Employee e ->
deptTotal[0] += e.salary;
grandTotal[0] += e.salary;
});
System.out.printf("Total for dept %s = %d \n",
d.name, deptTotal[0]);
});
System.out.printf("Grant total = %d \n", grandTotal[0]);
}
}
Translated to:
static class D {
int[] grandTotal = {0};
public void foo() {
MList<Department> departments = new MList.MListImpl<>();
departments.add(new Department("dep1"));
departments.add(new Department("dep2"));
MList<Employee> employees = new MList.MListImpl<>();
for (int i = 0; i < 100; i++) {
employees.add(new Employee(departments.get(i % 2),i+100));
}
Block<Department> block =
LambdaHelper.asSam(lambda$1mh,Block.class,employees,grandTotal,null);
departments
.forEach( block);
System.out.printf("Grant total = %d ", grandTotal[0]);
}
static final MethodHandle
lambda$1mh=LambdaHelper.createStaticMH(D3.class, "lambda$1",
MethodType.methodType(void.class,MList.class, int[].class,Department.class))
; //LDC bytecode
static final MethodHandle
lambda$2mh=LambdaHelper.createStaticMH(D3.class, "lambda$2",
MethodType.methodType(boolean.class,Department.class,Employee.class)); //LDC
bytecode
static final MethodHandle
lambda$3mh=LambdaHelper.createStaticMH(D3.class, "lambda$3",
MethodType.methodType(void.class,int[].class, int[].class,Employee.class));
//LDC bytecode
private static void lambda$1(MList<Employee> employees, int[]
grandTotal, Department d) {
int[] deptTotal = {0};
employees
.filter(LambdaHelper.asSam(lambda$2mh,Predicate.class,d,null))
.forEach(LambdaHelper.asSam(lambda$3mh,Block.class,grandTotal,deptTotal,null));
System.out.printf("Total for dept %s = %d \n",
d.name, deptTotal[0]);
}
private static boolean lambda$2(Department d, Employee e) {
return e.dept == d;
}
private static void lambda$3(int[] deptTotal,int[] grandTotal,
Employee e) {
deptTotal[0] += e.salary;
grandTotal[0] += e.salary;
}
}
And helper class LambdaHelper : this class will be used in next posts
public class LambdaHelper {
public static MethodHandle createStaticMH(Class clazz, String method,
MethodType methodType) {
MethodHandle mh = null;
try {
mh = MethodHandles.lookup().findStatic(clazz, method,
methodType);
} catch (Throwable e) {
}
return mh;
}
public static MethodHandle createVirtualMH(Class clazz, String method,
MethodType methodType) {
MethodHandle mh = null;
try {
mh = MethodHandles.lookup().findVirtual(clazz, method,
methodType);
} catch (Throwable e) {
}
return mh;
}
public static <T> T asSam(final MethodHandle target, final Class<T>
smType) {
final Method sm = getSingleMethod(smType);
if (sm == null)
throw new IllegalArgumentException("not a single-method
interface: " + smType.getName());
MethodType smMT = MethodType.methodType(sm.getReturnType(),
sm.getParameterTypes());
MethodHandle checkTarget = target.asType(smMT); // make throw WMT
checkTarget =
checkTarget.asType(checkTarget.type().changeReturnType(Object.class));
final MethodHandle vaTarget = checkTarget.asSpreader(Object[].class,
smMT.parameterCount());
return smType.cast(Proxy.newProxyInstance(
smType.getClassLoader(),
new Class[]{smType, WrapperInstance.class},
new InvocationHandler() {
private Object getArg(String name) {
if ((Object) name == "getWrapperInstanceTarget")
return target;
if ((Object) name == "getWrapperInstanceType")
return smType;
throw new AssertionError();
}
public Object invoke(Object proxy, Method method,
Object[] args) throws Throwable {
if (method.getDeclaringClass() ==
WrapperInstance.class)
return getArg(method.getName());
if (method.equals(sm))
return vaTarget.invokeExact(args);
if (isObjectMethod(method))
return callObjectMethod(this, method, args);
throw new InternalError();
}
}));
}
public static <T> T asSam(final MethodHandle target, final Class<T>
smType,final Object... capturedArgsPlusSamArgsPlaceHolders) {
final Method sm = getSingleMethod(smType);
if (sm == null)
throw new IllegalArgumentException("not a single-method
interface: " + smType.getName());
MethodType smMT = MethodType.methodType(sm.getReturnType(),
target.type().parameterArray());
MethodHandle checkTarget =
target.asType(target.type().changeReturnType(Object.class));
final MethodHandle vaTarget = checkTarget.asSpreader(Object[].class,
smMT.parameterCount());
return smType.cast(Proxy.newProxyInstance(
smType.getClassLoader(),
new Class[]{smType, WrapperInstance.class},
new InvocationHandler() {
private Object getArg(String name) {
if ((Object) name == "getWrapperInstanceTarget")
return target;
if ((Object) name == "getWrapperInstanceType")
return smType;
throw new AssertionError();
}
public Object invoke(Object proxy, Method method,
Object[] args) throws Throwable {
if (method.getDeclaringClass() ==
WrapperInstance.class)
return getArg(method.getName());
if (method.equals(sm)) {
System.arraycopy(args,0,capturedArgsPlusSamArgs,capturedArgsPlusSamArgs.length-args.length,args.length);
return
vaTarget.invokeExact(capturedArgsPlusSamArgs);
}
if (isObjectMethod(method))
return callObjectMethod(this, method, args);
throw new InternalError();
}
}));
}
private static Method getSingleMethod(Class<?> smType) {...
}
private static Constructor getSingleConstructor(Class<?> smType) {...
}
private static boolean isObjectMethod(Method m) {...
}
private static Object callObjectMethod(Object self, Method m, Object[]
args) {...
}
}
Best Regards,
Ali Ebrahimi
More information about the lambda-dev
mailing list