Translating lambda expressions as Synthetic static methods: Capturing final or effectively final states from multiple scopes

Brian Goetz brian.goetz at oracle.com
Sat Jun 25 13:05:32 PDT 2011


I know you're trying to show a technique for translating lambdas to 
bytecode that is slightly different to what has already been discussed, 
and that's great.  (I need also to post the latest version of the 
translation document, which has been updated since it was last posted 
here, and I'll do that soon.)

Can I suggest you start first with simpler examples and build up?  Also, 
so people understand what you're getting at, outline the principles and 
goals behind the translation strategy, in addition to just the generated 
code?


On 6/25/2011 6:16 AM, Ali Ebrahimi wrote:
> 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