From 40b29cdfa1cac2dc0ec43f2111070610d213255d Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Sun, 18 Jun 2017 21:22:44 +0300 Subject: [PATCH] Add support for altMetafactory --- .../org/teavm/classlib/impl/JCLPlugin.java | 7 ++- .../lambda/LambdaMetafactorySubstitutor.java | 30 ++++++++++++ .../teavm/model/InvokeDynamicInstruction.java | 4 -- .../java/org/teavm/model/RuntimeConstant.java | 4 -- .../test/java/org/teavm/vm/LambdaTest.java | 46 +++++++++++++++++++ 5 files changed, 82 insertions(+), 9 deletions(-) create mode 100644 tests/src/test/java/org/teavm/vm/LambdaTest.java diff --git a/classlib/src/main/java/org/teavm/classlib/impl/JCLPlugin.java b/classlib/src/main/java/org/teavm/classlib/impl/JCLPlugin.java index 38b6a87dd..dcb56f7df 100644 --- a/classlib/src/main/java/org/teavm/classlib/impl/JCLPlugin.java +++ b/classlib/src/main/java/org/teavm/classlib/impl/JCLPlugin.java @@ -49,9 +49,14 @@ public class JCLPlugin implements TeaVMPlugin { host.add(new ClassForNameTransformer()); host.add(new AnnotationDependencyListener()); + + LambdaMetafactorySubstitutor lms = new LambdaMetafactorySubstitutor(); host.add(new MethodReference(LambdaMetafactory.class, "metafactory", MethodHandles.Lookup.class, String.class, MethodType.class, MethodType.class, MethodHandle.class, MethodType.class, - CallSite.class), new LambdaMetafactorySubstitutor()); + CallSite.class), lms); + host.add(new MethodReference(LambdaMetafactory.class, "altMetafactory", MethodHandles.Lookup.class, + String.class, MethodType.class, Object[].class, CallSite.class), lms); + host.add(new ScalaHacks()); host.add(new NumericClassTransformer()); diff --git a/classlib/src/main/java/org/teavm/classlib/impl/lambda/LambdaMetafactorySubstitutor.java b/classlib/src/main/java/org/teavm/classlib/impl/lambda/LambdaMetafactorySubstitutor.java index 9c5513db8..7fcfdf25f 100644 --- a/classlib/src/main/java/org/teavm/classlib/impl/lambda/LambdaMetafactorySubstitutor.java +++ b/classlib/src/main/java/org/teavm/classlib/impl/lambda/LambdaMetafactorySubstitutor.java @@ -34,6 +34,9 @@ import org.teavm.model.emit.ProgramEmitter; import org.teavm.model.emit.ValueEmitter; public class LambdaMetafactorySubstitutor implements BootstrapMethodSubstitutor { + private static final int FLAG_SERIALIZABLE = 1; + private static final int FLAG_MARKERS = 2; + private static final int FLAG_BRIDGES = 4; private int lambdaIndex; @Override @@ -94,6 +97,33 @@ public class LambdaMetafactorySubstitutor implements BootstrapMethodSubstitutor implementor.addMethod(worker); + // Handle altMetafactory case + if (callSite.getBootstrapArguments().size() > 3) { + int flags = callSite.getBootstrapArguments().get(3).getInt(); + + if ((flags & FLAG_SERIALIZABLE) != 0) { + implementor.getInterfaces().add("java.io.Serializable"); + } + + int bootstrapArgIndex = 4; + if ((flags & FLAG_MARKERS) != 0) { + int markerCount = callSite.getBootstrapArguments().get(bootstrapArgIndex++).getInt(); + for (int i = 0; i < markerCount; ++i) { + ValueType markerType = callSite.getBootstrapArguments().get(bootstrapArgIndex++).getValueType(); + implementor.getInterfaces().add(((ValueType.Object) markerType).getClassName()); + } + } + + if ((flags & FLAG_BRIDGES) != 0) { + int bridgeCount = callSite.getBootstrapArguments().get(bootstrapArgIndex++).getInt(); + for (int i = 0; i < bridgeCount; ++i) { + ValueType[] bridgeType = callSite.getBootstrapArguments().get(bootstrapArgIndex++).getMethodType(); + createBridge(classSource, implementor, callSite.getCalledMethod().getName(), instantiatedMethodType, + bridgeType); + } + } + } + callSite.getAgent().submitClass(implementor); return callerPe.construct(ctor.getOwnerName(), callSite.getArguments().toArray(new ValueEmitter[0])); } diff --git a/core/src/main/java/org/teavm/model/InvokeDynamicInstruction.java b/core/src/main/java/org/teavm/model/InvokeDynamicInstruction.java index e728a7754..404872676 100644 --- a/core/src/main/java/org/teavm/model/InvokeDynamicInstruction.java +++ b/core/src/main/java/org/teavm/model/InvokeDynamicInstruction.java @@ -19,10 +19,6 @@ import java.util.ArrayList; import java.util.List; import org.teavm.model.instructions.InstructionVisitor; -/** - * - * @author Alexey Andreev - */ public class InvokeDynamicInstruction extends Instruction { private MethodDescriptor method; private MethodHandle bootstrapMethod; diff --git a/core/src/main/java/org/teavm/model/RuntimeConstant.java b/core/src/main/java/org/teavm/model/RuntimeConstant.java index 3525ee485..001f7aceb 100644 --- a/core/src/main/java/org/teavm/model/RuntimeConstant.java +++ b/core/src/main/java/org/teavm/model/RuntimeConstant.java @@ -15,10 +15,6 @@ */ package org.teavm.model; -/** - * - * @author Alexey Andreev - */ public final class RuntimeConstant { public static final byte INT = 0; public static final byte LONG = 1; diff --git a/tests/src/test/java/org/teavm/vm/LambdaTest.java b/tests/src/test/java/org/teavm/vm/LambdaTest.java new file mode 100644 index 000000000..f8e476f76 --- /dev/null +++ b/tests/src/test/java/org/teavm/vm/LambdaTest.java @@ -0,0 +1,46 @@ +/* + * Copyright 2017 Alexey Andreev. + * + * 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.teavm.vm; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import java.io.Serializable; +import java.util.function.Supplier; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.teavm.junit.TeaVMTestRunner; + +@RunWith(TeaVMTestRunner.class) +public class LambdaTest { + @Test + public void lambdaWithMarkers() { + Supplier supplier = (Supplier & A) () -> "OK"; + + assertEquals("OK", supplier.get()); + assertTrue("Supplier is expected to implement A", supplier instanceof A); + } + + @Test + public void serializableLambda() { + Supplier supplier = (Supplier & Serializable) () -> "OK"; + + assertEquals("OK", supplier.get()); + assertTrue("Supplier is expected to implement Serializable", supplier instanceof Serializable); + } + + interface A { + } +}