From be25c66287ed0f252364c1e364fb105b99046051 Mon Sep 17 00:00:00 2001 From: badlogic Date: Tue, 21 Jul 2015 14:58:56 +0200 Subject: [PATCH] Initial bridge method support in lambda generator, lacks any kind of type conversion or cast checks --- .../plugin/lambda2/LambdaClassGenerator.java | 398 +++++++++--------- .../compiler/plugin/lambda2/LambdaPlugin.java | 59 ++- .../robovm/rt/lambdas/BridgeMethodTest.java | 39 ++ .../lambdas/test001/Test001_NoParameters.java | 15 + .../Test002_NoneCaptureParameters.java | 15 + .../test003/Test003_CaptureFieldsLocals.java | 15 + .../rt/lambdas/test004/Test04_Casting.java | 15 + 7 files changed, 349 insertions(+), 207 deletions(-) create mode 100644 tests/robovm/src/test/java/org/robovm/rt/lambdas/BridgeMethodTest.java diff --git a/compiler/src/main/java/org/robovm/compiler/plugin/lambda2/LambdaClassGenerator.java b/compiler/src/main/java/org/robovm/compiler/plugin/lambda2/LambdaClassGenerator.java index a486d0746..da01ca960 100644 --- a/compiler/src/main/java/org/robovm/compiler/plugin/lambda2/LambdaClassGenerator.java +++ b/compiler/src/main/java/org/robovm/compiler/plugin/lambda2/LambdaClassGenerator.java @@ -27,219 +27,219 @@ import static org.objectweb.asm.Opcodes.*; - -/** - * Created by badlogic on 09/07/15. - */ public class LambdaClassGenerator { - private static int CLASS_VERSION = 51; - private int counter = 1; - - public LambdaClass generate(SootClass caller, String invokedName, SootMethodRef invokedType, SootMethodType samMethodType, SootMethodHandle implMethod, SootMethodType instantiatedMethodType) { - ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES); - - String lambdaClassName = caller.getName().replace('.', '/') + "$$Lambda$" + (counter++); - String functionalInterface = invokedType.returnType().toString().replace('.', '/'); - - cw.visit(CLASS_VERSION, - ACC_FINAL + ACC_SUPER + ACC_SYNTHETIC, - lambdaClassName, - null, "java/lang/Object", - new String[]{ functionalInterface }); - - String targetMethod = ""; - createFieldsAndConstructor(lambdaClassName, cw, invokedType, samMethodType, implMethod, instantiatedMethodType); - - // if we perform capturing, we can't cache the - // lambda instance. We need to create a factory method - // that returns a new instance of the lambda - // every time the lambda is invoked. That method - // will be invoked instead of the method - // of the lambda by LambdaPlugin. - if(!invokedType.parameterTypes().isEmpty()) { - targetMethod = createFactory(lambdaClassName, cw, invokedType, samMethodType, implMethod, instantiatedMethodType); - } - createForwardingMethod(lambdaClassName, cw, invokedType, samMethodType, implMethod, instantiatedMethodType); - cw.visitEnd(); - - return new LambdaClass(lambdaClassName, cw.toByteArray(), targetMethod, invokedType.parameterTypes(), invokedType.returnType()); - } - - private void createForwardingMethod(String lambdaClassName, ClassWriter cw, SootMethodRef invokedType, SootMethodType samMethodType, SootMethodHandle implMethod, SootMethodType instantiatedMethodType) { - String descriptor = Types.getDescriptor(samMethodType.getParameterTypes(), samMethodType.getReturnType()); - String implClassName = implMethod.getMethodRef().declaringClass().getName().replace('.', '/'); - MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, invokedType.name(), descriptor, null, null); - mv.visitCode(); - - pushArguments(lambdaClassName, mv, invokedType, samMethodType, implMethod, instantiatedMethodType); - int invokeOpCode = INVOKESTATIC; - switch(implMethod.getReferenceKind()) { - case SootMethodHandle.REF_invokeInterface: - invokeOpCode = INVOKEINTERFACE; - break; - case SootMethodHandle.REF_invokeSpecial: - case SootMethodHandle.REF_newInvokeSpecial: - invokeOpCode = INVOKESPECIAL; - break; - case SootMethodHandle.REF_invokeStatic: - invokeOpCode = INVOKESTATIC; - break; - case SootMethodHandle.REF_invokeVirtual: - invokeOpCode = INVOKEVIRTUAL; - break; - default: - throw new CompilerException("Unknown invoke type: " + implMethod.getReferenceKind()); - } - String implDescriptor = null; - List paramTypes = new ArrayList(implMethod.getMethodType().getParameterTypes()); - // need to remove the first parameter (this) in case this - // is an instance method - if(invokeOpCode != INVOKESTATIC && !paramTypes.isEmpty()) { - paramTypes.remove(0); - } - implDescriptor = Types.getDescriptor(paramTypes, implMethod.getMethodType().getReturnType()); - mv.visitMethodInsn(invokeOpCode, implClassName, implMethod.getMethodRef().name(), implDescriptor, false); - createForwardingMethodReturn(mv, samMethodType, implMethod, instantiatedMethodType); - - mv.visitMaxs(-1, -1); - mv.visitEnd(); - } - - private void pushArguments(String lambdaClassName, MethodVisitor mv, SootMethodRef invokedType, SootMethodType samMethodType, - SootMethodHandle implMethod, SootMethodType instantiatedMethodType) { - int localIndex = 1; // we start at slot index 1, because this occupies slot 0 - - // push the captured arguments, may include - // the caller's this if the desugared lambda - // is a instance method - int i = 0; - for(Object obj: invokedType.parameterTypes()) { - Type captureType = (Type)obj; - mv.visitVarInsn(ALOAD, 0); - mv.visitFieldInsn(GETFIELD, lambdaClassName, "field" + i, Types.getDescriptor(captureType)); - i++; - } - - // push the functional interface parameters - for(Type arg: samMethodType.getParameterTypes()) { + private static int CLASS_VERSION = 51; + private int counter = 1; + + public LambdaClass generate(SootClass caller, String invokedName, SootMethodRef invokedType, + SootMethodType samMethodType, SootMethodHandle implMethod, SootMethodType instantiatedMethodType, + List markerInterfaces, List bridgeMethods) { + ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES); + + String lambdaClassName = caller.getName().replace('.', '/') + "$$Lambda$" + (counter++); + String functionalInterface = invokedType.returnType().toString().replace('.', '/'); + + cw.visit(CLASS_VERSION, ACC_FINAL + ACC_SUPER + ACC_SYNTHETIC, lambdaClassName, null, "java/lang/Object", + new String[] { functionalInterface }); + + String targetMethod = ""; + createFieldsAndConstructor(lambdaClassName, cw, invokedType, samMethodType, implMethod, instantiatedMethodType); + + // if we perform capturing, we can't cache the + // lambda instance. We need to create a factory method + // that returns a new instance of the lambda + // every time the lambda is invoked. That method + // will be invoked instead of the method + // of the lambda by LambdaPlugin. + if (!invokedType.parameterTypes().isEmpty()) { + targetMethod = createFactory(lambdaClassName, cw, invokedType, samMethodType, implMethod, + instantiatedMethodType); + } + + // forward the lambda method + createForwardingMethod(lambdaClassName, cw, invokedName, samMethodType.getParameterTypes(), samMethodType.getReturnType(), invokedType.parameterTypes(), samMethodType, implMethod, instantiatedMethodType, false); + + // create any bridge methods necessary + for(SootMethodType bridgeMethod: bridgeMethods) { + createForwardingMethod(lambdaClassName, cw, invokedName, bridgeMethod.getParameterTypes(), bridgeMethod.getReturnType(), invokedType.parameterTypes(), samMethodType, implMethod, instantiatedMethodType, true); + } + cw.visitEnd(); + + return new LambdaClass(lambdaClassName, cw.toByteArray(), targetMethod, invokedType.parameterTypes(), + invokedType.returnType()); + } + + private void createForwardingMethod(String lambdaClassName, ClassWriter cw, String name, List parameters, + Type returnType, List invokedParameters, SootMethodType samMethodType, SootMethodHandle implMethod, SootMethodType instantiatedMethodType, boolean isBridgeMethod) { + String descriptor = Types.getDescriptor(parameters, returnType); + String implClassName = implMethod.getMethodRef().declaringClass().getName().replace('.', '/'); + MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | (isBridgeMethod?ACC_BRIDGE:0), name, descriptor, null, null); + mv.visitCode(); + + pushArguments(lambdaClassName, mv, parameters, invokedParameters, implMethod, instantiatedMethodType); + int invokeOpCode = INVOKESTATIC; + switch (implMethod.getReferenceKind()) { + case SootMethodHandle.REF_invokeInterface: + invokeOpCode = INVOKEINTERFACE; + break; + case SootMethodHandle.REF_invokeSpecial: + case SootMethodHandle.REF_newInvokeSpecial: + invokeOpCode = INVOKESPECIAL; + break; + case SootMethodHandle.REF_invokeStatic: + invokeOpCode = INVOKESTATIC; + break; + case SootMethodHandle.REF_invokeVirtual: + invokeOpCode = INVOKEVIRTUAL; + break; + default: + throw new CompilerException("Unknown invoke type: " + implMethod.getReferenceKind()); + } + String implDescriptor = null; + List paramTypes = new ArrayList(implMethod.getMethodType().getParameterTypes()); + // need to remove the first parameter (this) in case this + // is an instance method + if (invokeOpCode != INVOKESTATIC && !paramTypes.isEmpty()) { + paramTypes.remove(0); + } + implDescriptor = Types.getDescriptor(paramTypes, implMethod.getMethodType().getReturnType()); + mv.visitMethodInsn(invokeOpCode, implClassName, implMethod.getMethodRef().name(), implDescriptor, false); + createForwardingMethodReturn(mv, returnType, samMethodType, implMethod, instantiatedMethodType); + + mv.visitMaxs(-1, -1); + mv.visitEnd(); + } + + private void pushArguments(String lambdaClassName, MethodVisitor mv, + List parameters, List invokedParameters, SootMethodHandle implMethod, SootMethodType instantiatedMethodType) { + int localIndex = 1; // we start at slot index 1, because this occupies + // slot 0 + + // push the captured arguments, may include + // the caller's this if the desugared lambda + // is a instance method + int i = 0; + for (Object obj : invokedParameters) { + Type captureType = (Type) obj; + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, lambdaClassName, "field" + i, Types.getDescriptor(captureType)); + i++; + } + + // push the functional interface parameters + for (Type arg : parameters) { mv.visitVarInsn(loadOpcodeForType(arg), localIndex); localIndex += slotsForType(arg); } } - private void createForwardingMethodReturn(MethodVisitor mv, SootMethodType samMethodType, SootMethodHandle implMethod, SootMethodType instantiatedMethodType) { - Type returnType = samMethodType.getReturnType(); - if(returnType.equals(VoidType.v())) { - mv.visitInsn(RETURN); - } else if(returnType instanceof PrimType) { - if(returnType.equals(LongType.v())) { - mv.visitInsn(LRETURN); - } else if(returnType.equals(FloatType.v())) { - mv.visitInsn(FRETURN); - } else if(returnType.equals(DoubleType.v())) { - mv.visitInsn(DRETURN); - } else { - mv.visitInsn(IRETURN); - } - } else { - mv.visitInsn(ARETURN); - } - } - - private void createFieldsAndConstructor(String lambdaClassName, ClassWriter cw, SootMethodRef invokedType, SootMethodType samMethodType, SootMethodHandle implMethod, SootMethodType instantiatedMethodType) { - StringBuffer constructorDescriptor = new StringBuffer(); - - // create the fields on the class - int i = 0; - for(Object obj: invokedType.parameterTypes()) { - Type captureType = (Type)obj; - String typeDesc = Types.getDescriptor(captureType); - cw.visitField(ACC_PRIVATE + ACC_FINAL, "field" + i, typeDesc, null, null); - constructorDescriptor.append(typeDesc); - i++; - } - - // create constructor - MethodVisitor mv = cw.visitMethod(0, "", "(" + constructorDescriptor.toString() + ")V", null, null); - mv.visitCode(); - - // calls super - mv.visitVarInsn(ALOAD, 0); - mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V", false); - - // store the captures into the fields - i = 0; - int localIndex = 1; // we start at slot 1, because this occupies slot 0 - for(Object obj: invokedType.parameterTypes()) { - Type captureType = (Type)obj; - - // load this for put field - mv.visitVarInsn(ALOAD, 0); - - // load capture from argument slot - mv.visitVarInsn(loadOpcodeForType(captureType), localIndex); + private void createForwardingMethodReturn(MethodVisitor mv, Type returnType, SootMethodType samMethodType, + SootMethodHandle implMethod, SootMethodType instantiatedMethodType) { + if (returnType.equals(VoidType.v())) { + mv.visitInsn(RETURN); + } else if (returnType instanceof PrimType) { + if (returnType.equals(LongType.v())) { + mv.visitInsn(LRETURN); + } else if (returnType.equals(FloatType.v())) { + mv.visitInsn(FRETURN); + } else if (returnType.equals(DoubleType.v())) { + mv.visitInsn(DRETURN); + } else { + mv.visitInsn(IRETURN); + } + } else { + mv.visitInsn(ARETURN); + } + } + + private void createFieldsAndConstructor(String lambdaClassName, ClassWriter cw, SootMethodRef invokedType, + SootMethodType samMethodType, SootMethodHandle implMethod, SootMethodType instantiatedMethodType) { + StringBuffer constructorDescriptor = new StringBuffer(); + + // create the fields on the class + int i = 0; + for (Object obj : invokedType.parameterTypes()) { + Type captureType = (Type) obj; + String typeDesc = Types.getDescriptor(captureType); + cw.visitField(ACC_PRIVATE + ACC_FINAL, "field" + i, typeDesc, null, null); + constructorDescriptor.append(typeDesc); + i++; + } + + // create constructor + MethodVisitor mv = cw.visitMethod(0, "", "(" + constructorDescriptor.toString() + ")V", null, null); + mv.visitCode(); + + // calls super + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V", false); + + // store the captures into the fields + i = 0; + int localIndex = 1; // we start at slot 1, because this occupies slot 0 + for (Object obj : invokedType.parameterTypes()) { + Type captureType = (Type) obj; + + // load this for put field + mv.visitVarInsn(ALOAD, 0); + + // load capture from argument slot + mv.visitVarInsn(loadOpcodeForType(captureType), localIndex); localIndex += slotsForType(captureType); - + // store the capture into the field mv.visitFieldInsn(PUTFIELD, lambdaClassName, "field" + i, Types.getDescriptor(captureType)); - - i++; - } - - mv.visitInsn(RETURN); - mv.visitMaxs(-1, -1); - mv.visitEnd(); - } - - private String createFactory(String lambdaClassName, ClassWriter cw, SootMethodRef invokedType, SootMethodType samMethodType, SootMethodHandle implMethod, SootMethodType instantiatedMethodType) { - MethodVisitor mv = cw.visitMethod(ACC_STATIC, "getLambdaInstance", Types.getDescriptor(invokedType.parameterTypes(), invokedType.returnType()), null, null); - mv.visitCode(); - mv.visitTypeInsn(NEW, lambdaClassName); - mv.visitInsn(DUP); - int i = 0; - for(Object obj: invokedType.parameterTypes()) { - Type captureType = (Type)obj; - mv.visitVarInsn(loadOpcodeForType(captureType), i); - i += slotsForType(captureType); - } - mv.visitMethodInsn(INVOKESPECIAL, lambdaClassName, "", Types.getDescriptor(invokedType.parameterTypes(), VoidType.v()), false); - mv.visitInsn(ARETURN); - mv.visitMaxs(-1, -1); - mv.visitEnd(); - return "getLambdaInstance"; - } - - public int loadOpcodeForType(Type type) { - if(type instanceof PrimType) { - if(type.equals(LongType.v())) { - return LLOAD; - } else if(type.equals(FloatType.v())) { - return FLOAD; - } else if(type.equals(DoubleType.v())) { - return DLOAD; - } else { - return ILOAD; - } + + i++; + } + + mv.visitInsn(RETURN); + mv.visitMaxs(-1, -1); + mv.visitEnd(); + } + + private String createFactory(String lambdaClassName, ClassWriter cw, SootMethodRef invokedType, + SootMethodType samMethodType, SootMethodHandle implMethod, SootMethodType instantiatedMethodType) { + MethodVisitor mv = cw.visitMethod(ACC_STATIC, "getLambdaInstance", + Types.getDescriptor(invokedType.parameterTypes(), invokedType.returnType()), null, null); + mv.visitCode(); + mv.visitTypeInsn(NEW, lambdaClassName); + mv.visitInsn(DUP); + int i = 0; + for (Object obj : invokedType.parameterTypes()) { + Type captureType = (Type) obj; + mv.visitVarInsn(loadOpcodeForType(captureType), i); + i += slotsForType(captureType); + } + mv.visitMethodInsn(INVOKESPECIAL, lambdaClassName, "", + Types.getDescriptor(invokedType.parameterTypes(), VoidType.v()), false); + mv.visitInsn(ARETURN); + mv.visitMaxs(-1, -1); + mv.visitEnd(); + return "getLambdaInstance"; + } + + public int loadOpcodeForType(Type type) { + if (type instanceof PrimType) { + if (type.equals(LongType.v())) { + return LLOAD; + } else if (type.equals(FloatType.v())) { + return FLOAD; + } else if (type.equals(DoubleType.v())) { + return DLOAD; + } else { + return ILOAD; + } } else { return ALOAD; } - } - - public int slotsForType(Type type) { - if(type.equals(LongType.v()) || type.equals(DoubleType.v())) { + } + + public int slotsForType(Type type) { + if (type.equals(LongType.v()) || type.equals(DoubleType.v())) { return 2; } else { return 1; } - } - - public static class A { - final LambdaClassGenerator gen; - final int a; - - public A(LambdaClassGenerator get, int a) { - this.gen = get; - this.a = a; - } - } + } } diff --git a/compiler/src/main/java/org/robovm/compiler/plugin/lambda2/LambdaPlugin.java b/compiler/src/main/java/org/robovm/compiler/plugin/lambda2/LambdaPlugin.java index 81e9e4e94..94a3c707c 100644 --- a/compiler/src/main/java/org/robovm/compiler/plugin/lambda2/LambdaPlugin.java +++ b/compiler/src/main/java/org/robovm/compiler/plugin/lambda2/LambdaPlugin.java @@ -16,21 +16,47 @@ */ package org.robovm.compiler.plugin.lambda2; +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + import org.apache.commons.io.FileUtils; import org.robovm.compiler.CompilerException; import org.robovm.compiler.ModuleBuilder; import org.robovm.compiler.clazz.Clazz; import org.robovm.compiler.config.Config; import org.robovm.compiler.plugin.AbstractCompilerPlugin; -import soot.*; -import soot.jimple.*; -import java.io.File; -import java.io.IOException; -import java.util.*; +import soot.Body; +import soot.Local; +import soot.Modifier; +import soot.PatchingChain; +import soot.Scene; +import soot.SootClass; +import soot.SootField; +import soot.SootMethod; +import soot.SootMethodHandle; +import soot.SootMethodRef; +import soot.SootMethodType; +import soot.SootResolver; +import soot.Type; +import soot.Unit; +import soot.Value; +import soot.jimple.DefinitionStmt; +import soot.jimple.DynamicInvokeExpr; +import soot.jimple.IntConstant; +import soot.jimple.Jimple; +import soot.jimple.NullConstant; public class LambdaPlugin extends AbstractCompilerPlugin { - + private static int FLAG_MARKERS = 4; + private static int FLAG_BRIDGES = 2; + final Map generators = new HashMap(); private static boolean isLambdaBootstrapMethod(SootMethodRef methodRef) { @@ -89,8 +115,25 @@ private void transformMethod(Config config, Clazz clazz, SootClass sootClass, try { LambdaClass callSite = null; - // TODO: handle altMetaFactory case - callSite = generator.generate(caller, invokedName, invokedType, samMethodType, implMethod, instantiatedMethodType); + List markerInterfaces = new ArrayList<>(); + List bridgeMethods = new ArrayList<>(); + if (expr.getBootstrapMethodRef().name().equals("altMetafactory")) { + int flags = ((IntConstant) bsmArgs.get(3)).value; + int bsmArgsIdx = 4; + if ((flags & FLAG_MARKERS) > 0) { + int count = ((IntConstant) bsmArgs.get(bsmArgsIdx++)).value; + for (int i = 0; i < count; i++) { + markerInterfaces.add((Type) bsmArgs.get(bsmArgsIdx++)); + } + } + if ((flags & FLAG_BRIDGES) > 0) { + int count = ((IntConstant) bsmArgs.get(bsmArgsIdx++)).value; + for (int i = 0; i < count; i++) { + bridgeMethods.add((SootMethodType) bsmArgs.get(bsmArgsIdx++)); + } + } + } + callSite = generator.generate(caller, invokedName, invokedType, samMethodType, implMethod, instantiatedMethodType, markerInterfaces, bridgeMethods); File f = clazz.getPath().getGeneratedClassFile(callSite.getLambdaClassName()); FileUtils.writeByteArrayToFile(f, callSite.getClassData()); diff --git a/tests/robovm/src/test/java/org/robovm/rt/lambdas/BridgeMethodTest.java b/tests/robovm/src/test/java/org/robovm/rt/lambdas/BridgeMethodTest.java new file mode 100644 index 000000000..477c4e874 --- /dev/null +++ b/tests/robovm/src/test/java/org/robovm/rt/lambdas/BridgeMethodTest.java @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2015 RoboVM AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.robovm.rt.lambdas; + +import static org.junit.Assert.*; + +import org.junit.Test; + +interface A { + T m(T t); +} + +interface B extends A { + String m(String s); +} + +public class BridgeMethodTest { + @Test + public void testBridgeMethods() { + B b = (s) -> { return "Hello " + s; }; + assertEquals("Hello there", b.m("there")); + + A a = b; + assertEquals("Hello there", a.m("there")); + } +} diff --git a/tests/robovm/src/test/java/org/robovm/rt/lambdas/test001/Test001_NoParameters.java b/tests/robovm/src/test/java/org/robovm/rt/lambdas/test001/Test001_NoParameters.java index 219c9f468..048ac90fc 100644 --- a/tests/robovm/src/test/java/org/robovm/rt/lambdas/test001/Test001_NoParameters.java +++ b/tests/robovm/src/test/java/org/robovm/rt/lambdas/test001/Test001_NoParameters.java @@ -1,3 +1,18 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.robovm.rt.lambdas.test001; import static org.junit.Assert.*; diff --git a/tests/robovm/src/test/java/org/robovm/rt/lambdas/test002/Test002_NoneCaptureParameters.java b/tests/robovm/src/test/java/org/robovm/rt/lambdas/test002/Test002_NoneCaptureParameters.java index 80fd4352d..2a48ce13b 100644 --- a/tests/robovm/src/test/java/org/robovm/rt/lambdas/test002/Test002_NoneCaptureParameters.java +++ b/tests/robovm/src/test/java/org/robovm/rt/lambdas/test002/Test002_NoneCaptureParameters.java @@ -1,3 +1,18 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.robovm.rt.lambdas.test002; import static org.junit.Assert.*; diff --git a/tests/robovm/src/test/java/org/robovm/rt/lambdas/test003/Test003_CaptureFieldsLocals.java b/tests/robovm/src/test/java/org/robovm/rt/lambdas/test003/Test003_CaptureFieldsLocals.java index 902e810e6..808450dec 100644 --- a/tests/robovm/src/test/java/org/robovm/rt/lambdas/test003/Test003_CaptureFieldsLocals.java +++ b/tests/robovm/src/test/java/org/robovm/rt/lambdas/test003/Test003_CaptureFieldsLocals.java @@ -1,3 +1,18 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.robovm.rt.lambdas.test003; import static org.junit.Assert.assertEquals; diff --git a/tests/robovm/src/test/java/org/robovm/rt/lambdas/test004/Test04_Casting.java b/tests/robovm/src/test/java/org/robovm/rt/lambdas/test004/Test04_Casting.java index e1411f724..8c9cb21a8 100644 --- a/tests/robovm/src/test/java/org/robovm/rt/lambdas/test004/Test04_Casting.java +++ b/tests/robovm/src/test/java/org/robovm/rt/lambdas/test004/Test04_Casting.java @@ -1,3 +1,18 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.robovm.rt.lambdas.test004; import static org.junit.Assert.assertEquals;