From 50b42ab092d9fa2aa350c9d4884bff286de25601 Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Sun, 26 Jul 2015 12:57:35 +0300 Subject: [PATCH 1/5] Implementing InvokeDynamic instruction --- .../org/teavm/cache/DiskProgramCache.java | 21 +- .../main/java/org/teavm/cache/ProgramIO.java | 192 ++++++++++++++++++ .../teavm/javascript/StatementGenerator.java | 5 + .../org/teavm/model/ClassHolderSource.java | 22 ++ .../org/teavm/model/ClassReaderSource.java | 86 ++++++++ .../teavm/model/InstructionReadVisitor.java | 7 + .../teavm/model/InvokeDynamicInstruction.java | 78 +++++++ .../java/org/teavm/model/MethodHandle.java | 174 ++++++++++++++++ .../org/teavm/model/MethodHandleType.java | 32 +++ .../java/org/teavm/model/RuntimeConstant.java | 108 ++++++++++ .../main/java/org/teavm/model/ValueType.java | 11 +- .../model/instructions/InstructionReader.java | 7 +- .../instructions/InstructionVisitor.java | 8 +- .../teavm/model/util/AsyncMethodFinder.java | 6 + .../teavm/model/util/BasicBlockMapper.java | 4 + .../teavm/model/util/DefinitionExtractor.java | 10 + .../model/util/InstructionStringifier.java | 67 ++++++ .../util/InstructionTransitionExtractor.java | 6 + .../model/util/InstructionVariableMapper.java | 22 +- .../model/util/MissingItemsProcessor.java | 4 + .../org/teavm/model/util/ProgramUtils.java | 16 ++ .../org/teavm/model/util/TypeInferer.java | 9 + .../org/teavm/model/util/UsageExtractor.java | 13 ++ .../optimization/GlobalValueNumbering.java | 19 +- .../optimization/LoopInvariantMotion.java | 8 + .../UnusedVariableElimination.java | 11 +- .../optimization/VariableEscapeAnalyzer.java | 15 +- .../VariableUsageGraphBuilder.java | 8 +- .../org/teavm/parsing/ClassRefsRenamer.java | 65 ++++++ .../java/org/teavm/parsing/ProgramParser.java | 83 +++++++- .../org/teavm/parsing/SSATransformer.java | 14 ++ .../tooling/InstructionLocationReader.java | 13 +- .../tooling/ProgramSourceAggregator.java | 15 +- 33 files changed, 1104 insertions(+), 55 deletions(-) create mode 100644 teavm-core/src/main/java/org/teavm/model/InvokeDynamicInstruction.java create mode 100644 teavm-core/src/main/java/org/teavm/model/MethodHandle.java create mode 100644 teavm-core/src/main/java/org/teavm/model/MethodHandleType.java create mode 100644 teavm-core/src/main/java/org/teavm/model/RuntimeConstant.java diff --git a/teavm-core/src/main/java/org/teavm/cache/DiskProgramCache.java b/teavm-core/src/main/java/org/teavm/cache/DiskProgramCache.java index 91f55b9b2..de6fc85ef 100644 --- a/teavm-core/src/main/java/org/teavm/cache/DiskProgramCache.java +++ b/teavm-core/src/main/java/org/teavm/cache/DiskProgramCache.java @@ -122,6 +122,15 @@ public class DiskProgramCache implements ProgramCache { @Override public void visit(InvokeInstruction insn) { dependencies.add(insn.getMethod().getClassName()); } + @Override + public void visit(InvokeDynamicInstruction insn) { + for (RuntimeConstant cst : insn.getBootstrapArguments()) { + if (cst.getKind() == RuntimeConstant.METHOD_HANDLE) { + MethodHandle handle = cst.getMethodHandle(); + dependencies.add(handle.getClassName()); + } + } + } @Override public void visit(EmptyInstruction insn) { } @Override public void visit(ClassConstantInstruction insn) { } @Override public void visit(NullConstantInstruction insn) { } @@ -153,15 +162,7 @@ public class DiskProgramCache implements ProgramCache { @Override public void visit(IsInstanceInstruction insn) { } @Override public void visit(InitClassInstruction insn) { } @Override public void visit(NullCheckInstruction insn) { } - - @Override - public void visit(MonitorEnterInstruction insn) { - - } - - @Override - public void visit(MonitorExitInstruction insn) { - - } + @Override public void visit(MonitorEnterInstruction insn) { } + @Override public void visit(MonitorExitInstruction insn) { } } } diff --git a/teavm-core/src/main/java/org/teavm/cache/ProgramIO.java b/teavm-core/src/main/java/org/teavm/cache/ProgramIO.java index ec0192edb..8f8787f60 100644 --- a/teavm-core/src/main/java/org/teavm/cache/ProgramIO.java +++ b/teavm-core/src/main/java/org/teavm/cache/ProgramIO.java @@ -562,6 +562,26 @@ public class ProgramIO { } } + @Override + public void visit(InvokeDynamicInstruction insn) { + try { + output.writeByte(41); + output.writeShort(insn.getReceiver() != null ? insn.getReceiver().getIndex() : -1); + output.writeShort(insn.getInstance().getIndex()); + output.writeInt(symbolTable.lookup(insn.getMethod().toString())); + for (int i = 0; i < insn.getArguments().size(); ++i) { + output.writeShort(insn.getArguments().get(i).getIndex()); + } + write(insn.getBootstrapMethod()); + output.writeByte(insn.getBootstrapArguments().size()); + for (int i = 0; i < insn.getBootstrapArguments().size(); ++i) { + write(insn.getBootstrapArguments().get(i)); + } + } catch (IOException e) { + throw new IOExceptionWrapper(e); + } + } + @Override public void visit(IsInstanceInstruction insn) { try { @@ -614,6 +634,89 @@ public class ProgramIO { throw new IOExceptionWrapper(e); } } + + private void write(MethodHandle handle) throws IOException { + switch (handle.getKind()) { + case GET_FIELD: + output.writeByte(0); + break; + case GET_STATIC_FIELD: + output.writeByte(1); + break; + case PUT_FIELD: + output.writeByte(2); + break; + case PUT_STATIC_FIELD: + output.writeByte(3); + break; + case INVOKE_VIRTUAL: + output.writeByte(4); + break; + case INVOKE_STATIC: + output.writeByte(5); + break; + case INVOKE_SPECIAL: + output.writeByte(6); + break; + case INVOKE_CONSTRUCTOR: + output.writeByte(7); + break; + case INVOKE_INTERFACE: + output.writeByte(8); + break; + } + output.writeInt(symbolTable.lookup(handle.getClassName())); + switch (handle.getKind()) { + case GET_FIELD: + case GET_STATIC_FIELD: + case PUT_FIELD: + case PUT_STATIC_FIELD: + output.writeInt(symbolTable.lookup(handle.getName())); + output.writeInt(symbolTable.lookup(handle.getValueType().toString())); + break; + default: + output.writeInt(symbolTable.lookup(new MethodDescriptor(handle.getName(), + handle.signature()).toString())); + break; + } + } + + private void write(RuntimeConstant cst) throws IOException { + switch (cst.getKind()) { + case RuntimeConstant.INT: + output.writeByte(0); + output.writeInt(cst.getInt()); + break; + case RuntimeConstant.LONG: + output.writeByte(1); + output.writeLong(cst.getLong()); + break; + case RuntimeConstant.FLOAT: + output.writeByte(2); + output.writeFloat(cst.getFloat()); + break; + case RuntimeConstant.DOUBLE: + output.writeByte(3); + output.writeDouble(cst.getDouble()); + break; + case RuntimeConstant.STRING: + output.writeByte(4); + output.writeUTF(cst.getString()); + break; + case RuntimeConstant.TYPE: + output.writeByte(5); + output.writeInt(symbolTable.lookup(cst.getValueType().toString())); + break; + case RuntimeConstant.METHOD: + output.writeByte(6); + output.writeInt(symbolTable.lookup(ValueType.methodTypeToString(cst.getMethodType()))); + break; + case RuntimeConstant.METHOD_HANDLE: + output.writeByte(7); + write(cst.getMethodHandle()); + break; + } + } } private static class IOExceptionWrapper extends RuntimeException { @@ -928,8 +1031,97 @@ public class ProgramIO { insn.setObjectRef(program.variableAt(input.readShort())); return insn; } + case 41: { + /* + output.writeByte(41); + output.writeShort(insn.getReceiver() != null ? insn.getReceiver().getIndex() : -1); + output.writeShort(insn.getInstance().getIndex()); + output.writeInt(symbolTable.lookup(insn.getMethod().toString())); + for (int i = 0; i < insn.getArguments().size(); ++i) { + output.writeShort(insn.getArguments().get(i).getIndex()); + } + write(insn.getBootstrapMethod()); + output.writeByte(insn.getBootstrapArguments().size()); + for (int i = 0; i < insn.getBootstrapArguments().size(); ++i) { + write(insn.getBootstrapArguments().get(i)); + */ + InvokeDynamicInstruction insn = new InvokeDynamicInstruction(); + short receiver = input.readShort(); + insn.setReceiver(receiver >= 0 ? program.variableAt(receiver) : null); + insn.setInstance(program.variableAt(input.readShort())); + insn.setMethod(MethodDescriptor.parse(symbolTable.at(input.readInt()))); + int argsCount = insn.getMethod().parameterCount(); + for (int i = 0; i < argsCount; ++i) { + insn.getArguments().add(program.variableAt(input.readShort())); + } + insn.setBootstrapMethod(readMethodHandle(input)); + int bootstrapArgsCount = input.readByte(); + for (int i = 0; i < bootstrapArgsCount; ++i) { + insn.getBootstrapArguments().add(readRuntimeConstant(input)); + } + return insn; + } default: throw new RuntimeException("Unknown instruction type: " + insnType); } } + + private MethodHandle readMethodHandle(DataInput input) throws IOException { + byte kind = input.readByte(); + switch (kind) { + case 0: + return MethodHandle.fieldGetter(symbolTable.at(input.readInt()), symbolTable.at(input.readInt()), + ValueType.parse(symbolTable.at(input.readInt()))); + case 1: + return MethodHandle.staticFieldGetter(symbolTable.at(input.readInt()), symbolTable.at(input.readInt()), + ValueType.parse(symbolTable.at(input.readInt()))); + case 2: + return MethodHandle.fieldSetter(symbolTable.at(input.readInt()), symbolTable.at(input.readInt()), + ValueType.parse(symbolTable.at(input.readInt()))); + case 3: + return MethodHandle.staticFieldSetter(symbolTable.at(input.readInt()), symbolTable.at(input.readInt()), + ValueType.parse(symbolTable.at(input.readInt()))); + case 4: + return MethodHandle.virtualCaller(symbolTable.at(input.readInt()), symbolTable.at(input.readInt()), + MethodDescriptor.parseSignature(symbolTable.at(input.readInt()))); + case 5: + return MethodHandle.staticCaller(symbolTable.at(input.readInt()), symbolTable.at(input.readInt()), + MethodDescriptor.parseSignature(symbolTable.at(input.readInt()))); + case 6: + return MethodHandle.specialCaller(symbolTable.at(input.readInt()), symbolTable.at(input.readInt()), + MethodDescriptor.parseSignature(symbolTable.at(input.readInt()))); + case 7: + return MethodHandle.constructorCaller(symbolTable.at(input.readInt()), symbolTable.at(input.readInt()), + MethodDescriptor.parseSignature(symbolTable.at(input.readInt()))); + case 8: + return MethodHandle.interfaceCaller(symbolTable.at(input.readInt()), symbolTable.at(input.readInt()), + MethodDescriptor.parseSignature(symbolTable.at(input.readInt()))); + default: + throw new IllegalArgumentException("Unexpected method handle type: " + kind); + } + } + + private RuntimeConstant readRuntimeConstant(DataInput input) throws IOException { + byte kind = input.readByte(); + switch (kind) { + case 0: + return new RuntimeConstant(input.readInt()); + case 1: + return new RuntimeConstant(input.readLong()); + case 2: + return new RuntimeConstant(input.readFloat()); + case 3: + return new RuntimeConstant(input.readDouble()); + case 4: + return new RuntimeConstant(input.readUTF()); + case 5: + return new RuntimeConstant(ValueType.parse(symbolTable.at(input.readInt()))); + case 6: + return new RuntimeConstant(MethodDescriptor.parseSignature(symbolTable.at(input.readInt()))); + case 7: + return new RuntimeConstant(readMethodHandle(input)); + default: + throw new IllegalArgumentException("Unexpected runtime constant type: " + kind); + } + } } diff --git a/teavm-core/src/main/java/org/teavm/javascript/StatementGenerator.java b/teavm-core/src/main/java/org/teavm/javascript/StatementGenerator.java index 1b4d59571..df9f464d9 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/StatementGenerator.java +++ b/teavm-core/src/main/java/org/teavm/javascript/StatementGenerator.java @@ -563,6 +563,11 @@ class StatementGenerator implements InstructionVisitor { statements.add(stmt); } + @Override + public void visit(InvokeDynamicInstruction insn) { + // InvokeDynamic should be eliminated at previous phases + } + @Override public void visit(IsInstanceInstruction insn) { assign(Expr.instanceOf(Expr.var(insn.getValue().getIndex()), insn.getType()), insn.getReceiver()); diff --git a/teavm-core/src/main/java/org/teavm/model/ClassHolderSource.java b/teavm-core/src/main/java/org/teavm/model/ClassHolderSource.java index 1995ee5a1..8e6d055f8 100644 --- a/teavm-core/src/main/java/org/teavm/model/ClassHolderSource.java +++ b/teavm-core/src/main/java/org/teavm/model/ClassHolderSource.java @@ -15,6 +15,8 @@ */ package org.teavm.model; +import java.util.stream.Stream; + /** * * @author Alexey Andreev @@ -22,4 +24,24 @@ package org.teavm.model; public interface ClassHolderSource extends ClassReaderSource { @Override ClassHolder get(String name); + + default Stream getMutableAncestors(String name) { + return getAncestors(name).map(cls -> (ClassHolder) cls); + } + + default Stream getMutableAncestorClasses(String name) { + return getAncestorClasses(name).map(cls -> (ClassHolder) cls); + } + + default MethodHolder resolveMutable(MethodReference method) { + return (MethodHolder) resolve(method); + } + + default FieldHolder resolveMutable(FieldReference field) { + return (FieldHolder) resolve(field); + } + + default Stream mutableOverridenMethods(MethodReference method) { + return overridenMethods(method).map(m -> (MethodHolder) m); + } } \ No newline at end of file diff --git a/teavm-core/src/main/java/org/teavm/model/ClassReaderSource.java b/teavm-core/src/main/java/org/teavm/model/ClassReaderSource.java index 597c5be5f..fc6291772 100644 --- a/teavm-core/src/main/java/org/teavm/model/ClassReaderSource.java +++ b/teavm-core/src/main/java/org/teavm/model/ClassReaderSource.java @@ -15,10 +15,96 @@ */ package org.teavm.model; +import java.util.*; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; + /** * * @author Alexey Andreev */ public interface ClassReaderSource { ClassReader get(String name); + + default Stream getAncestorClasses(String name) { + return StreamSupport.stream(((Iterable) () -> { + return new Iterator() { + ClassReader currentClass = get(name); + @Override public ClassReader next() { + ClassReader result = currentClass; + if (currentClass.getParent() != null && !currentClass.getName().equals(currentClass.getParent())) { + currentClass = get(currentClass.getParent()); + } else { + currentClass = null; + } + return result; + } + @Override public boolean hasNext() { + return currentClass != null; + } + }; + }).spliterator(), false); + } + + default Stream getAncestors(String name) { + return StreamSupport.stream(((Iterable) () -> { + return new Iterator() { + private Deque> state = new ArrayDeque<>(); + private Set visited = new HashSet<>(); + { + add(name); + } + @Override public ClassReader next() { + while (!state.isEmpty()) { + Deque level = state.peek(); + if (!level.isEmpty()) { + ClassReader result = level.removeFirst(); + follow(result); + return result; + } + state.pop(); + } + return null; + } + @Override public boolean hasNext() { + return !state.isEmpty(); + } + private void follow(ClassReader cls) { + state.push(new ArrayDeque<>()); + if (cls.getParent() != null) { + add(cls.getParent()); + } + for (String iface : cls.getInterfaces()) { + add(iface); + } + } + private void add(String name) { + ClassReader cls = get(name); + if (cls != null && visited.add(cls)) { + state.peek().addLast(cls); + } + } + }; + }).spliterator(), false); + } + + default MethodReader resolve(MethodReference method) { + return getAncestorClasses(method.getClassName()) + .map(cls -> cls.getMethod(method.getDescriptor())) + .filter(candidate -> candidate != null) + .findFirst().orElse(null); + } + + default FieldReader resolve(FieldReference field) { + return getAncestorClasses(field.getClassName()) + .map(cls -> cls.getField(field.getFieldName())) + .filter(candidate -> candidate != null) + .findFirst().orElse(null); + } + + default Stream overridenMethods(MethodReference method) { + return getAncestorClasses(method.getClassName()) + .map(cls -> cls.getMethod(method.getDescriptor())) + .filter(candidate -> candidate != null); + } } diff --git a/teavm-core/src/main/java/org/teavm/model/InstructionReadVisitor.java b/teavm-core/src/main/java/org/teavm/model/InstructionReadVisitor.java index b5a8ff811..236d63c2e 100644 --- a/teavm-core/src/main/java/org/teavm/model/InstructionReadVisitor.java +++ b/teavm-core/src/main/java/org/teavm/model/InstructionReadVisitor.java @@ -187,6 +187,13 @@ class InstructionReadVisitor implements InstructionVisitor { Collections.unmodifiableList(insn.getArguments()), insn.getType()); } + @Override + public void visit(InvokeDynamicInstruction insn) { + reader.invokeDynamic(insn.getReceiver(), insn.getInstance(), insn.getMethod(), + Collections.unmodifiableList(insn.getArguments()), insn.getBootstrapMethod(), + Collections.unmodifiableList(insn.getBootstrapArguments())); + } + @Override public void visit(IsInstanceInstruction insn) { reader.isInstance(insn.getReceiver(), insn.getValue(), insn.getType()); diff --git a/teavm-core/src/main/java/org/teavm/model/InvokeDynamicInstruction.java b/teavm-core/src/main/java/org/teavm/model/InvokeDynamicInstruction.java new file mode 100644 index 000000000..e728a7754 --- /dev/null +++ b/teavm-core/src/main/java/org/teavm/model/InvokeDynamicInstruction.java @@ -0,0 +1,78 @@ +/* + * Copyright 2015 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.model; + +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; + private List bootstrapArguments = new ArrayList<>(); + private Variable instance; + private List arguments = new ArrayList<>(); + private Variable receiver; + + public MethodDescriptor getMethod() { + return method; + } + + public void setMethod(MethodDescriptor method) { + this.method = method; + } + + public MethodHandle getBootstrapMethod() { + return bootstrapMethod; + } + + public void setBootstrapMethod(MethodHandle bootstrapMethod) { + this.bootstrapMethod = bootstrapMethod; + } + + public Variable getReceiver() { + return receiver; + } + + public void setReceiver(Variable receiver) { + this.receiver = receiver; + } + + public List getBootstrapArguments() { + return bootstrapArguments; + } + + public Variable getInstance() { + return instance; + } + + public void setInstance(Variable instance) { + this.instance = instance; + } + + public List getArguments() { + return arguments; + } + + @Override + public void acceptVisitor(InstructionVisitor visitor) { + visitor.visit(this); + } +} diff --git a/teavm-core/src/main/java/org/teavm/model/MethodHandle.java b/teavm-core/src/main/java/org/teavm/model/MethodHandle.java new file mode 100644 index 000000000..21afb3a35 --- /dev/null +++ b/teavm-core/src/main/java/org/teavm/model/MethodHandle.java @@ -0,0 +1,174 @@ +/* + * Copyright 2015 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.model; + +import java.util.Arrays; + +/** + * + * @author Alexey Andreev + */ +public class MethodHandle { + private MethodHandleType kind; + private String className; + private String name; + private ValueType valueType; + private ValueType[] argumentTypes; + + MethodHandle(MethodHandleType kind, String className, String name, ValueType valueType, + ValueType[] argumentTypes) { + this.kind = kind; + this.className = className; + this.name = name; + this.valueType = valueType; + this.argumentTypes = argumentTypes; + } + + public MethodHandleType getKind() { + return kind; + } + + public String getClassName() { + return className; + } + + public String getName() { + return name; + } + + public ValueType getValueType() { + return valueType; + } + + public ValueType[] getArgumentTypes() { + return argumentTypes != null ? argumentTypes.clone() : null; + } + + public int getArgumentCount() { + return argumentTypes != null ? argumentTypes.length : 0; + } + + public ValueType getArgumentType(int index) { + if (argumentTypes == null) { + throw new IllegalArgumentException("Can't get argument of non-parameterized method handle"); + } + return argumentTypes[index]; + } + + public ValueType[] signature() { + ValueType[] result = Arrays.copyOf(argumentTypes, argumentTypes.length + 1); + result[argumentTypes.length] = valueType; + return result; + } + + public static MethodHandle fieldGetter(String className, String name, ValueType valueType) { + if (valueType == ValueType.VOID) { + throw new IllegalArgumentException("Field can't be of void type"); + } + return new MethodHandle(MethodHandleType.GET_FIELD, className, name, valueType, null); + } + + public static MethodHandle staticFieldGetter(String className, String name, ValueType valueType) { + if (valueType == ValueType.VOID) { + throw new IllegalArgumentException("Field can't be of void type"); + } + return new MethodHandle(MethodHandleType.GET_STATIC_FIELD, className, name, valueType, null); + } + + public static MethodHandle fieldSetter(String className, String name, ValueType valueType) { + if (valueType == ValueType.VOID) { + throw new IllegalArgumentException("Field can't be of void type"); + } + return new MethodHandle(MethodHandleType.PUT_FIELD, className, name, valueType, null); + } + + public static MethodHandle staticFieldSetter(String className, String name, ValueType valueType) { + if (valueType == ValueType.VOID) { + throw new IllegalArgumentException("Field can't be of void type"); + } + return new MethodHandle(MethodHandleType.PUT_STATIC_FIELD, className, name, valueType, null); + } + + public static MethodHandle virtualCaller(String className, String name, ValueType... arguments) { + ValueType valueType = arguments[0]; + arguments = Arrays.copyOfRange(arguments, 1, arguments.length); + return new MethodHandle(MethodHandleType.INVOKE_VIRTUAL, className, name, valueType, arguments); + } + + public static MethodHandle virtualCaller(String className, MethodDescriptor desc) { + return virtualCaller(className, desc.getName(), desc.getSignature()); + } + + public static MethodHandle virtualCaller(MethodReference method) { + return virtualCaller(method.getClassName(), method.getDescriptor()); + } + + public static MethodHandle staticCaller(String className, String name, ValueType... arguments) { + ValueType valueType = arguments[0]; + arguments = Arrays.copyOfRange(arguments, 1, arguments.length); + return new MethodHandle(MethodHandleType.INVOKE_STATIC, className, name, valueType, arguments); + } + + public static MethodHandle staticCaller(String className, MethodDescriptor desc) { + return staticCaller(className, desc.getName(), desc.getSignature()); + } + + public static MethodHandle staticCaller(MethodReference method) { + return staticCaller(method.getClassName(), method.getDescriptor()); + } + + public static MethodHandle specialCaller(String className, String name, ValueType... arguments) { + ValueType valueType = arguments[0]; + arguments = Arrays.copyOfRange(arguments, 1, arguments.length); + return new MethodHandle(MethodHandleType.INVOKE_SPECIAL, className, name, valueType, arguments); + } + + public static MethodHandle specialCaller(String className, MethodDescriptor desc) { + return specialCaller(className, desc.getName(), desc.getSignature()); + } + + public static MethodHandle specialCaller(MethodReference method) { + return specialCaller(method.getClassName(), method.getDescriptor()); + } + + public static MethodHandle constructorCaller(String className, String name, ValueType... arguments) { + ValueType valueType = arguments[0]; + arguments = Arrays.copyOfRange(arguments, 1, arguments.length); + return new MethodHandle(MethodHandleType.INVOKE_CONSTRUCTOR, className, name, valueType, arguments); + } + + public static MethodHandle constructorCaller(String className, MethodDescriptor desc) { + return constructorCaller(className, desc.getName(), desc.getSignature()); + } + + public static MethodHandle constructorCaller(MethodReference method) { + return constructorCaller(method.getClassName(), method.getDescriptor()); + } + + public static MethodHandle interfaceCaller(String className, String name, ValueType... arguments) { + ValueType valueType = arguments[0]; + arguments = Arrays.copyOfRange(arguments, 1, arguments.length); + return new MethodHandle(MethodHandleType.INVOKE_INTERFACE, className, name, valueType, arguments); + } + + public static MethodHandle interfaceCaller(String className, MethodDescriptor desc) { + return interfaceCaller(className, desc.getName(), desc.getSignature()); + } + + public static MethodHandle interfaceCaller(MethodReference method) { + return interfaceCaller(method.getClassName(), method.getDescriptor()); + } +} diff --git a/teavm-core/src/main/java/org/teavm/model/MethodHandleType.java b/teavm-core/src/main/java/org/teavm/model/MethodHandleType.java new file mode 100644 index 000000000..69d24ca5e --- /dev/null +++ b/teavm-core/src/main/java/org/teavm/model/MethodHandleType.java @@ -0,0 +1,32 @@ +/* + * Copyright 2015 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.model; + +/** + * + * @author Alexey Andreev + */ +public enum MethodHandleType { + GET_FIELD, + GET_STATIC_FIELD, + PUT_FIELD, + PUT_STATIC_FIELD, + INVOKE_VIRTUAL, + INVOKE_STATIC, + INVOKE_SPECIAL, + INVOKE_CONSTRUCTOR, + INVOKE_INTERFACE +} diff --git a/teavm-core/src/main/java/org/teavm/model/RuntimeConstant.java b/teavm-core/src/main/java/org/teavm/model/RuntimeConstant.java new file mode 100644 index 000000000..3525ee485 --- /dev/null +++ b/teavm-core/src/main/java/org/teavm/model/RuntimeConstant.java @@ -0,0 +1,108 @@ +/* + * Copyright 2015 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.model; + +/** + * + * @author Alexey Andreev + */ +public final class RuntimeConstant { + public static final byte INT = 0; + public static final byte LONG = 1; + public static final byte FLOAT = 2; + public static final byte DOUBLE = 3; + public static final byte STRING = 4; + public static final byte TYPE = 5; + public static final byte METHOD = 6; + public static final byte METHOD_HANDLE = 7; + + private byte kind; + private Object value; + + RuntimeConstant(byte kind, Object value) { + super(); + this.kind = kind; + this.value = value; + } + + public RuntimeConstant(int value) { + this(INT, value); + } + + public RuntimeConstant(long value) { + this(LONG, value); + } + + public RuntimeConstant(float value) { + this(FLOAT, value); + } + + public RuntimeConstant(double value) { + this(FLOAT, value); + } + + public RuntimeConstant(String value) { + this(STRING, value); + } + + public RuntimeConstant(ValueType value) { + this(TYPE, value); + } + + public RuntimeConstant(ValueType[] methodType) { + this(METHOD, methodType.clone()); + } + + public RuntimeConstant(MethodHandle value) { + this(METHOD_HANDLE, value); + } + + public byte getKind() { + return kind; + } + + public int getInt() { + return (Integer) value; + } + + public long getLong() { + return (Long) value; + } + + public float getFloat() { + return (Float) value; + } + + public double getDouble() { + return (Double) value; + } + + public String getString() { + return (String) value; + } + + public ValueType getValueType() { + return (ValueType) value; + } + + public ValueType[] getMethodType() { + return ((ValueType[]) value).clone(); + } + + public MethodHandle getMethodHandle() { + return (MethodHandle) value; + } +} diff --git a/teavm-core/src/main/java/org/teavm/model/ValueType.java b/teavm-core/src/main/java/org/teavm/model/ValueType.java index 08f29f4b3..9cc6adacc 100644 --- a/teavm-core/src/main/java/org/teavm/model/ValueType.java +++ b/teavm-core/src/main/java/org/teavm/model/ValueType.java @@ -15,10 +15,8 @@ */ package org.teavm.model; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; +import java.util.stream.Collectors; /** @@ -260,6 +258,11 @@ public abstract class ValueType { return sb.toString(); } + public static String methodTypeToString(ValueType[] types) { + return "(" + Arrays.stream(types, 0, types.length - 1).map(ValueType::toString) + .collect(Collectors.joining()) + ")" + types[types.length - 1]; + } + public abstract boolean isObject(String cls); private static ValueType parseImpl(String string) { diff --git a/teavm-core/src/main/java/org/teavm/model/instructions/InstructionReader.java b/teavm-core/src/main/java/org/teavm/model/instructions/InstructionReader.java index afdea1647..2be0bd725 100644 --- a/teavm-core/src/main/java/org/teavm/model/instructions/InstructionReader.java +++ b/teavm-core/src/main/java/org/teavm/model/instructions/InstructionReader.java @@ -92,8 +92,11 @@ public interface InstructionReader { void putElement(VariableReader array, VariableReader index, VariableReader value); void invoke(VariableReader receiver, VariableReader instance, MethodReference method, - List arguments, - InvocationType type); + List arguments, InvocationType type); + + void invokeDynamic(VariableReader receiver, VariableReader instance, MethodDescriptor method, + List arguments, MethodHandle bootstrapMethod, + List bootstrapArguments); void isInstance(VariableReader receiver, VariableReader value, ValueType type); diff --git a/teavm-core/src/main/java/org/teavm/model/instructions/InstructionVisitor.java b/teavm-core/src/main/java/org/teavm/model/instructions/InstructionVisitor.java index 7a38d2306..f0a2b1c84 100644 --- a/teavm-core/src/main/java/org/teavm/model/instructions/InstructionVisitor.java +++ b/teavm-core/src/main/java/org/teavm/model/instructions/InstructionVisitor.java @@ -15,6 +15,8 @@ */ package org.teavm.model.instructions; +import org.teavm.model.InvokeDynamicInstruction; + /** * * @author Alexey Andreev @@ -82,13 +84,15 @@ public interface InstructionVisitor { void visit(InvokeInstruction insn); + void visit(InvokeDynamicInstruction insn); + void visit(IsInstanceInstruction insn); void visit(InitClassInstruction insn); void visit(NullCheckInstruction insn); - + void visit(MonitorEnterInstruction insn); - + void visit(MonitorExitInstruction insn); } diff --git a/teavm-core/src/main/java/org/teavm/model/util/AsyncMethodFinder.java b/teavm-core/src/main/java/org/teavm/model/util/AsyncMethodFinder.java index 1ed4b2c87..6ba1a3027 100644 --- a/teavm-core/src/main/java/org/teavm/model/util/AsyncMethodFinder.java +++ b/teavm-core/src/main/java/org/teavm/model/util/AsyncMethodFinder.java @@ -369,6 +369,12 @@ public class AsyncMethodFinder { List arguments, InvocationType type) { } + @Override + public void invokeDynamic(VariableReader receiver, VariableReader instance, MethodDescriptor method, + List arguments, MethodHandle bootstrapMethod, + List bootstrapArguments) { + } + @Override public void isInstance(VariableReader receiver, VariableReader value, ValueType type) { } diff --git a/teavm-core/src/main/java/org/teavm/model/util/BasicBlockMapper.java b/teavm-core/src/main/java/org/teavm/model/util/BasicBlockMapper.java index 6a9ab85c3..60842f50c 100644 --- a/teavm-core/src/main/java/org/teavm/model/util/BasicBlockMapper.java +++ b/teavm-core/src/main/java/org/teavm/model/util/BasicBlockMapper.java @@ -176,6 +176,10 @@ public abstract class BasicBlockMapper implements InstructionVisitor { public void visit(InvokeInstruction insn) { } + @Override + public void visit(InvokeDynamicInstruction insn) { + } + @Override public void visit(IsInstanceInstruction insn) { } diff --git a/teavm-core/src/main/java/org/teavm/model/util/DefinitionExtractor.java b/teavm-core/src/main/java/org/teavm/model/util/DefinitionExtractor.java index fec90ad2e..776c194e8 100644 --- a/teavm-core/src/main/java/org/teavm/model/util/DefinitionExtractor.java +++ b/teavm-core/src/main/java/org/teavm/model/util/DefinitionExtractor.java @@ -15,6 +15,7 @@ */ package org.teavm.model.util; +import org.teavm.model.InvokeDynamicInstruction; import org.teavm.model.Variable; import org.teavm.model.instructions.*; @@ -163,6 +164,15 @@ public class DefinitionExtractor implements InstructionVisitor { } } + @Override + public void visit(InvokeDynamicInstruction insn) { + if (insn.getReceiver() == null) { + definedVariables = new Variable[0]; + } else { + definedVariables = new Variable[] { insn.getReceiver() }; + } + } + @Override public void visit(IsInstanceInstruction insn) { definedVariables = new Variable[] { insn.getReceiver() }; diff --git a/teavm-core/src/main/java/org/teavm/model/util/InstructionStringifier.java b/teavm-core/src/main/java/org/teavm/model/util/InstructionStringifier.java index 812b354e7..475d94c53 100644 --- a/teavm-core/src/main/java/org/teavm/model/util/InstructionStringifier.java +++ b/teavm-core/src/main/java/org/teavm/model/util/InstructionStringifier.java @@ -15,7 +15,9 @@ */ package org.teavm.model.util; +import java.util.Arrays; import java.util.List; +import java.util.stream.Collectors; import org.teavm.model.*; import org.teavm.model.instructions.*; @@ -337,6 +339,71 @@ public class InstructionStringifier implements InstructionReader { sb.append(")"); } + @Override + public void invokeDynamic(VariableReader receiver, VariableReader instance, MethodDescriptor method, + List arguments, MethodHandle bootstrapMethod, + List bootstrapArguments) { + if (receiver != null) { + sb.append("@").append(receiver.getIndex()).append(" := "); + } + sb.append("@").append(instance.getIndex()); + sb.append(".").append(method.getName()).append("("); + sb.append(arguments.stream().map(arg -> "@" + arg.getIndex()).collect(Collectors.joining(", "))); + sb.append(") "); + sb.append("[").append(convert(bootstrapMethod)).append('('); + sb.append(bootstrapArguments.stream().map(arg -> convert(arg)).collect(Collectors.joining(", "))); + sb.append(")"); + } + + private String convert(MethodHandle handle) { + switch (handle.getKind()) { + case INVOKE_VIRTUAL: + case INVOKE_SPECIAL: + case INVOKE_INTERFACE: + return new MethodDescriptor(handle.getName(), handle.signature()).toString(); + case INVOKE_CONSTRUCTOR: + return "new" + handle.getClassName() + "." + new MethodDescriptor(handle.getName(), + handle.signature()).toString(); + case INVOKE_STATIC: + return handle.getClassName() + "." + new MethodDescriptor(handle.getName(), + handle.signature()).toString(); + case GET_FIELD: + return "GET " + handle.getName(); + case GET_STATIC_FIELD: + return "GET " + handle.getClassName() + "." + handle.getName(); + case PUT_FIELD: + return "PUT " + handle.getName(); + case PUT_STATIC_FIELD: + return "PUT " + handle.getClassName() + "." + handle.getName(); + } + throw new IllegalArgumentException("Unexpected handle type: " + handle.getKind()); + } + + private String convert(RuntimeConstant cst) { + switch (cst.getKind()) { + case RuntimeConstant.INT: + return String.valueOf(cst.getInt()); + case RuntimeConstant.LONG: + return String.valueOf(cst.getLong()); + case RuntimeConstant.FLOAT: + return String.valueOf(cst.getFloat()); + case RuntimeConstant.DOUBLE: + return String.valueOf(cst.getDouble()); + case RuntimeConstant.STRING: + return String.valueOf(cst.getString()); + case RuntimeConstant.TYPE: + return String.valueOf(cst.getValueType()); + case RuntimeConstant.METHOD: { + ValueType[] methodType = cst.getMethodType(); + return "(" + Arrays.stream(methodType, 0, methodType.length - 1).map(Object::toString) + .collect(Collectors.joining()) + ")" + methodType[methodType.length - 1]; + } + case RuntimeConstant.METHOD_HANDLE: + return convert(cst.getMethodHandle()); + } + throw new IllegalArgumentException("Unexpected runtime constant type: " + cst.getKind()); + } + @Override public void isInstance(VariableReader receiver, VariableReader value, ValueType type) { sb.append("@").append(receiver.getIndex()).append(" := @").append(value.getIndex()) diff --git a/teavm-core/src/main/java/org/teavm/model/util/InstructionTransitionExtractor.java b/teavm-core/src/main/java/org/teavm/model/util/InstructionTransitionExtractor.java index 6f6ef9856..3c9691a2a 100644 --- a/teavm-core/src/main/java/org/teavm/model/util/InstructionTransitionExtractor.java +++ b/teavm-core/src/main/java/org/teavm/model/util/InstructionTransitionExtractor.java @@ -17,6 +17,7 @@ package org.teavm.model.util; import java.util.List; import org.teavm.model.BasicBlock; +import org.teavm.model.InvokeDynamicInstruction; import org.teavm.model.instructions.*; /** @@ -160,6 +161,11 @@ public class InstructionTransitionExtractor implements InstructionVisitor { targets = null; } + @Override + public void visit(InvokeDynamicInstruction insn) { + targets = null; + } + @Override public void visit(IsInstanceInstruction insn) { targets = null; diff --git a/teavm-core/src/main/java/org/teavm/model/util/InstructionVariableMapper.java b/teavm-core/src/main/java/org/teavm/model/util/InstructionVariableMapper.java index 65da6ac85..4297c5131 100644 --- a/teavm-core/src/main/java/org/teavm/model/util/InstructionVariableMapper.java +++ b/teavm-core/src/main/java/org/teavm/model/util/InstructionVariableMapper.java @@ -15,6 +15,7 @@ */ package org.teavm.model.util; +import org.teavm.model.InvokeDynamicInstruction; import org.teavm.model.Variable; import org.teavm.model.instructions.*; @@ -213,6 +214,19 @@ public abstract class InstructionVariableMapper implements InstructionVisitor { } } + @Override + public void visit(InvokeDynamicInstruction insn) { + if (insn.getReceiver() != null) { + insn.setReceiver(map(insn.getReceiver())); + } + if (insn.getInstance() != null) { + insn.setInstance(map(insn.getInstance())); + } + for (int i = 0; i < insn.getArguments().size(); ++i) { + insn.getArguments().set(i, map(insn.getArguments().get(i))); + } + } + @Override public void visit(IsInstanceInstruction insn) { insn.setReceiver(map(insn.getReceiver())); @@ -238,8 +252,8 @@ public abstract class InstructionVariableMapper implements InstructionVisitor { public void visit(MonitorExitInstruction insn) { insn.setObjectRef(map(insn.getObjectRef())); } - - - - + + + + } diff --git a/teavm-core/src/main/java/org/teavm/model/util/MissingItemsProcessor.java b/teavm-core/src/main/java/org/teavm/model/util/MissingItemsProcessor.java index e811ced8b..de182f96e 100644 --- a/teavm-core/src/main/java/org/teavm/model/util/MissingItemsProcessor.java +++ b/teavm-core/src/main/java/org/teavm/model/util/MissingItemsProcessor.java @@ -191,6 +191,10 @@ public class MissingItemsProcessor { checkMethod(insn.getLocation(), insn.getMethod()); } + @Override + public void visit(InvokeDynamicInstruction insn) { + } + @Override public void visit(PutElementInstruction insn) { } diff --git a/teavm-core/src/main/java/org/teavm/model/util/ProgramUtils.java b/teavm-core/src/main/java/org/teavm/model/util/ProgramUtils.java index 357bb68d1..1c4fe6406 100644 --- a/teavm-core/src/main/java/org/teavm/model/util/ProgramUtils.java +++ b/teavm-core/src/main/java/org/teavm/model/util/ProgramUtils.java @@ -16,6 +16,7 @@ package org.teavm.model.util; import java.util.*; +import java.util.stream.Collectors; import org.teavm.common.Graph; import org.teavm.common.GraphBuilder; import org.teavm.model.*; @@ -471,6 +472,21 @@ public final class ProgramUtils { copy.setLocation(location); } + @Override + public void invokeDynamic(VariableReader receiver, VariableReader instance, MethodDescriptor method, + List arguments, MethodHandle bootstrapMethod, + List bootstrapArguments) { + InvokeDynamicInstruction insnCopy = new InvokeDynamicInstruction(); + insnCopy.setMethod(method); + insnCopy.setBootstrapMethod(bootstrapMethod); + insnCopy.getBootstrapArguments().addAll(bootstrapArguments); + insnCopy.setInstance(copyVar(instance)); + insnCopy.getArguments().addAll(arguments.stream().map(v -> copyVar(v)).collect(Collectors.toList())); + insnCopy.setReceiver(receiver != null ? copyVar(receiver) : null); + copy = insnCopy; + copy.setLocation(location); + } + @Override public void isInstance(VariableReader receiver, VariableReader value, ValueType type) { IsInstanceInstruction insnCopy = new IsInstanceInstruction(); diff --git a/teavm-core/src/main/java/org/teavm/model/util/TypeInferer.java b/teavm-core/src/main/java/org/teavm/model/util/TypeInferer.java index b8d026518..7f36e819f 100644 --- a/teavm-core/src/main/java/org/teavm/model/util/TypeInferer.java +++ b/teavm-core/src/main/java/org/teavm/model/util/TypeInferer.java @@ -296,6 +296,15 @@ public class TypeInferer { } } + @Override + public void invokeDynamic(VariableReader receiver, VariableReader instance, MethodDescriptor method, + List arguments, MethodHandle bootstrapMethod, + List bootstrapArguments) { + if (receiver != null) { + types[receiver.getIndex()] = convert(method.getResultType()); + } + } + @Override public void integerConstant(VariableReader receiver, int cst) { types[receiver.getIndex()] = VariableType.INT; diff --git a/teavm-core/src/main/java/org/teavm/model/util/UsageExtractor.java b/teavm-core/src/main/java/org/teavm/model/util/UsageExtractor.java index c3c607bbf..be56ecfdf 100644 --- a/teavm-core/src/main/java/org/teavm/model/util/UsageExtractor.java +++ b/teavm-core/src/main/java/org/teavm/model/util/UsageExtractor.java @@ -15,6 +15,7 @@ */ package org.teavm.model.util; +import org.teavm.model.InvokeDynamicInstruction; import org.teavm.model.Variable; import org.teavm.model.instructions.*; @@ -192,6 +193,18 @@ public class UsageExtractor implements InstructionVisitor { } } + @Override + public void visit(InvokeDynamicInstruction insn) { + if (insn.getInstance() != null) { + usedVariables = new Variable[insn.getArguments().size() + 1]; + insn.getArguments().toArray(usedVariables); + usedVariables[insn.getArguments().size()] = insn.getInstance(); + } else { + usedVariables = new Variable[insn.getArguments().size()]; + insn.getArguments().toArray(usedVariables); + } + } + @Override public void visit(IsInstanceInstruction insn) { usedVariables = new Variable[] { insn.getValue() }; diff --git a/teavm-core/src/main/java/org/teavm/optimization/GlobalValueNumbering.java b/teavm-core/src/main/java/org/teavm/optimization/GlobalValueNumbering.java index 676ebc053..f1c208372 100644 --- a/teavm-core/src/main/java/org/teavm/optimization/GlobalValueNumbering.java +++ b/teavm-core/src/main/java/org/teavm/optimization/GlobalValueNumbering.java @@ -15,10 +15,8 @@ */ package org.teavm.optimization; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; +import java.util.function.UnaryOperator; import org.teavm.common.DominatorTree; import org.teavm.common.Graph; import org.teavm.common.GraphUtils; @@ -395,12 +393,17 @@ public class GlobalValueNumbering implements MethodOptimization { int instance = map[insn.getInstance().getIndex()]; insn.setInstance(program.variableAt(instance)); } - for (int i = 0; i < insn.getArguments().size(); ++i) { - int arg = map[insn.getArguments().get(i).getIndex()]; - insn.getArguments().set(i, program.variableAt(arg)); - } + insn.getArguments().replaceAll(mapper); } + @Override + public void visit(InvokeDynamicInstruction insn) { + Optional.ofNullable(insn.getInstance()).map(mapper).ifPresent(var -> insn.setInstance(var)); + insn.getArguments().replaceAll(mapper); + } + + private UnaryOperator mapper = var -> program.variableAt(map[var.getIndex()]); + @Override public void visit(IsInstanceInstruction insn) { int val = map[insn.getValue().getIndex()]; diff --git a/teavm-core/src/main/java/org/teavm/optimization/LoopInvariantMotion.java b/teavm-core/src/main/java/org/teavm/optimization/LoopInvariantMotion.java index 60da5b551..9d8fc7c68 100644 --- a/teavm-core/src/main/java/org/teavm/optimization/LoopInvariantMotion.java +++ b/teavm-core/src/main/java/org/teavm/optimization/LoopInvariantMotion.java @@ -366,6 +366,10 @@ public class LoopInvariantMotion implements MethodOptimization { public void visit(InvokeInstruction insn) { } + @Override + public void visit(InvokeDynamicInstruction insn) { + } + @Override public void visit(IsInstanceInstruction insn) { canMove = true; @@ -560,6 +564,10 @@ public class LoopInvariantMotion implements MethodOptimization { public void visit(InvokeInstruction insn) { } + @Override + public void visit(InvokeDynamicInstruction insn) { + } + @Override public void visit(IsInstanceInstruction insn) { } diff --git a/teavm-core/src/main/java/org/teavm/optimization/UnusedVariableElimination.java b/teavm-core/src/main/java/org/teavm/optimization/UnusedVariableElimination.java index 0515ce36b..7585f8ea4 100644 --- a/teavm-core/src/main/java/org/teavm/optimization/UnusedVariableElimination.java +++ b/teavm-core/src/main/java/org/teavm/optimization/UnusedVariableElimination.java @@ -235,6 +235,13 @@ public class UnusedVariableElimination implements MethodOptimization { } } + @Override + public void visit(InvokeDynamicInstruction insn) { + if (insn.getReceiver() != null && !used[insn.getReceiver().getIndex()]) { + insn.setReceiver(null); + } + } + @Override public void visit(IsInstanceInstruction insn) { requestUsage(insn.getReceiver()); @@ -251,12 +258,12 @@ public class UnusedVariableElimination implements MethodOptimization { @Override public void visit(MonitorEnterInstruction insn) { - + } @Override public void visit(MonitorExitInstruction insn) { - + } } } diff --git a/teavm-core/src/main/java/org/teavm/optimization/VariableEscapeAnalyzer.java b/teavm-core/src/main/java/org/teavm/optimization/VariableEscapeAnalyzer.java index 7b79c36e3..ae8b048b5 100644 --- a/teavm-core/src/main/java/org/teavm/optimization/VariableEscapeAnalyzer.java +++ b/teavm-core/src/main/java/org/teavm/optimization/VariableEscapeAnalyzer.java @@ -15,10 +15,7 @@ */ package org.teavm.optimization; -import org.teavm.model.BasicBlock; -import org.teavm.model.Instruction; -import org.teavm.model.Program; -import org.teavm.model.Variable; +import org.teavm.model.*; import org.teavm.model.instructions.*; /** @@ -193,6 +190,16 @@ public final class VariableEscapeAnalyzer { } } + @Override + public void visit(InvokeDynamicInstruction insn) { + if (insn.getInstance() != null) { + escaping[insn.getInstance().getIndex()] = true; + } + for (Variable arg : insn.getArguments()) { + escaping[arg.getIndex()] = true; + } + } + @Override public void visit(IsInstanceInstruction insn) { } diff --git a/teavm-core/src/main/java/org/teavm/optimization/VariableUsageGraphBuilder.java b/teavm-core/src/main/java/org/teavm/optimization/VariableUsageGraphBuilder.java index 26ef1eee6..1fc0e5bc8 100644 --- a/teavm-core/src/main/java/org/teavm/optimization/VariableUsageGraphBuilder.java +++ b/teavm-core/src/main/java/org/teavm/optimization/VariableUsageGraphBuilder.java @@ -197,6 +197,10 @@ public final class VariableUsageGraphBuilder { public void visit(InvokeInstruction insn) { } + @Override + public void visit(InvokeDynamicInstruction insn) { + } + @Override public void visit(IsInstanceInstruction insn) { use(insn.getReceiver(), insn.getValue()); @@ -213,12 +217,12 @@ public final class VariableUsageGraphBuilder { @Override public void visit(MonitorEnterInstruction insn) { - + } @Override public void visit(MonitorExitInstruction insn) { - + } } } diff --git a/teavm-core/src/main/java/org/teavm/parsing/ClassRefsRenamer.java b/teavm-core/src/main/java/org/teavm/parsing/ClassRefsRenamer.java index 02faae7cf..b8b0e673c 100644 --- a/teavm-core/src/main/java/org/teavm/parsing/ClassRefsRenamer.java +++ b/teavm-core/src/main/java/org/teavm/parsing/ClassRefsRenamer.java @@ -15,6 +15,7 @@ */ package org.teavm.parsing; +import java.util.Arrays; import java.util.Map; import org.teavm.common.Mapper; import org.teavm.javascript.spi.Remove; @@ -101,6 +102,58 @@ public class ClassRefsRenamer implements InstructionVisitor { } } + private ValueType[] rename(ValueType[] types) { + return Arrays.stream(types).map(e -> rename(e)).toArray(sz -> new ValueType[sz]); + } + + private RuntimeConstant rename(RuntimeConstant cst) { + switch (cst.getKind()) { + case RuntimeConstant.TYPE: + return new RuntimeConstant(rename(cst.getValueType())); + case RuntimeConstant.METHOD: + return new RuntimeConstant(rename(cst.getMethodType())); + case RuntimeConstant.METHOD_HANDLE: + return new RuntimeConstant(rename(cst.getMethodHandle())); + default: + return cst; + } + } + + private MethodHandle rename(MethodHandle handle) { + switch (handle.getKind()) { + case GET_FIELD: + return MethodHandle.fieldGetter(classNameMapper.map(handle.getClassName()), handle.getName(), + rename(handle.getValueType())); + case GET_STATIC_FIELD: + return MethodHandle.staticFieldGetter(classNameMapper.map(handle.getClassName()), handle.getName(), + rename(handle.getValueType())); + case PUT_FIELD: + return MethodHandle.fieldSetter(classNameMapper.map(handle.getClassName()), handle.getName(), + rename(handle.getValueType())); + case PUT_STATIC_FIELD: + return MethodHandle.staticFieldSetter(classNameMapper.map(handle.getClassName()), handle.getName(), + rename(handle.getValueType())); + case INVOKE_VIRTUAL: + return MethodHandle.virtualCaller(classNameMapper.map(handle.getClassName()), handle.getName(), + rename(handle.signature())); + case INVOKE_STATIC: + return MethodHandle.staticCaller(classNameMapper.map(handle.getClassName()), handle.getName(), + rename(handle.signature())); + case INVOKE_SPECIAL: + return MethodHandle.specialCaller(classNameMapper.map(handle.getClassName()), handle.getName(), + rename(handle.signature())); + case INVOKE_CONSTRUCTOR: + return MethodHandle.constructorCaller(classNameMapper.map(handle.getClassName()), handle.getName(), + rename(handle.signature())); + case INVOKE_INTERFACE: + return MethodHandle.interfaceCaller(classNameMapper.map(handle.getClassName()), handle.getName(), + rename(handle.signature())); + default: + break; + } + throw new IllegalArgumentException("Unknown method handle type: " + handle.getKind()); + } + private void rename(AnnotationContainer source, AnnotationContainer target) { for (AnnotationHolder annot : source.all()) { if (!annot.getType().equals(Rename.class.getName()) @@ -271,6 +324,18 @@ public class ClassRefsRenamer implements InstructionVisitor { insn.setMethod(new MethodReference(className, new MethodDescriptor(insn.getMethod().getName(), signature))); } + @Override + public void visit(InvokeDynamicInstruction insn) { + ValueType[] signature = insn.getMethod().getSignature(); + for (int i = 0; i < signature.length; ++i) { + signature[i] = rename(signature[i]); + } + insn.setMethod(new MethodDescriptor(insn.getMethod().getName(), signature)); + for (int i = 0; i < insn.getBootstrapArguments().size(); ++i) { + insn.getBootstrapArguments().set(i, rename(insn.getBootstrapArguments().get(i))); + } + } + @Override public void visit(IsInstanceInstruction insn) { insn.setType(rename(insn.getType())); diff --git a/teavm-core/src/main/java/org/teavm/parsing/ProgramParser.java b/teavm-core/src/main/java/org/teavm/parsing/ProgramParser.java index a9d7d9350..c0427e946 100644 --- a/teavm-core/src/main/java/org/teavm/parsing/ProgramParser.java +++ b/teavm-core/src/main/java/org/teavm/parsing/ProgramParser.java @@ -486,7 +486,54 @@ public class ProgramParser implements VariableDebugInformation { @Override public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, Object... bsmArgs) { - throw new IllegalStateException("InvokeDynamic is not supported in TeaVM"); + InvokeDynamicInstruction insn = new InvokeDynamicInstruction(); + + insn.setInstance(getVariable(popSingle())); + Type[] types = Type.getArgumentTypes(desc); + Variable[] args = new Variable[types.length]; + int j = args.length; + for (int i = types.length - 1; i >= 0; --i) { + args[--j] = types[i].getSize() == 2 ? getVariable(popDouble()) : getVariable(popSingle()); + } + insn.getArguments().addAll(Arrays.asList(args)); + + Type returnType = Type.getReturnType(desc); + if (returnType.getSize() > 0) { + insn.setReceiver(getVariable(returnType.getSize() == 2 ? pushDouble() : pushSingle())); + } + + insn.setMethod(new MethodDescriptor(name, MethodDescriptor.parseSignature(desc))); + insn.setBootstrapMethod(parseHandle(bsm)); + for (int i = 0; i < bsmArgs.length; ++i) { + insn.getBootstrapArguments().add(convertConstant(bsmArgs[i])); + } + + addInstruction(insn); + } + + private RuntimeConstant convertConstant(Object value) { + if (value instanceof Integer) { + return new RuntimeConstant((Integer) value); + } else if (value instanceof Long) { + return new RuntimeConstant((Long) value); + } else if (value instanceof Float) { + return new RuntimeConstant((Float) value); + } else if (value instanceof Double) { + return new RuntimeConstant((Double) value); + } else if (value instanceof String) { + return new RuntimeConstant((String) value); + } else if (value instanceof Type) { + Type type = (Type) value; + if (type.getSort() == Type.METHOD) { + return new RuntimeConstant(MethodDescriptor.parseSignature(type.getDescriptor())); + } else { + return new RuntimeConstant(ValueType.parse(type.getDescriptor())); + } + } else if (value instanceof Handle) { + return new RuntimeConstant(parseHandle((Handle) value)); + } else { + throw new IllegalArgumentException("Unknown runtime constant: " + value); + } } @Override @@ -1673,4 +1720,38 @@ public class ProgramParser implements VariableDebugInformation { return null; } }; + + static MethodHandle parseHandle(Handle handle) { + switch (handle.getTag()) { + case Opcodes.H_GETFIELD: + return MethodHandle.fieldGetter(handle.getOwner(), handle.getName(), + ValueType.parse(handle.getDesc())); + case Opcodes.H_GETSTATIC: + return MethodHandle.staticFieldGetter(handle.getOwner(), handle.getName(), + ValueType.parse(handle.getDesc())); + case Opcodes.H_PUTFIELD: + return MethodHandle.fieldSetter(handle.getOwner(), handle.getName(), + ValueType.parse(handle.getDesc())); + case Opcodes.H_PUTSTATIC: + return MethodHandle.staticFieldSetter(handle.getOwner(), handle.getName(), + ValueType.parse(handle.getDesc())); + case Opcodes.H_INVOKEVIRTUAL: + return MethodHandle.virtualCaller(handle.getOwner(), handle.getName(), + MethodDescriptor.parseSignature(handle.getDesc())); + case Opcodes.H_INVOKESTATIC: + return MethodHandle.staticCaller(handle.getOwner(), handle.getName(), + MethodDescriptor.parseSignature(handle.getDesc())); + case Opcodes.H_INVOKESPECIAL: + return MethodHandle.specialCaller(handle.getOwner(), handle.getName(), + MethodDescriptor.parseSignature(handle.getDesc())); + case Opcodes.H_NEWINVOKESPECIAL: + return MethodHandle.constructorCaller(handle.getOwner(), handle.getName(), + MethodDescriptor.parseSignature(handle.getDesc())); + case Opcodes.H_INVOKEINTERFACE: + return MethodHandle.interfaceCaller(handle.getOwner(), handle.getName(), + MethodDescriptor.parseSignature(handle.getDesc())); + default: + throw new IllegalArgumentException("Unknown handle tag: " + handle.getTag()); + } + } } diff --git a/teavm-core/src/main/java/org/teavm/parsing/SSATransformer.java b/teavm-core/src/main/java/org/teavm/parsing/SSATransformer.java index 8cf41beec..e105df432 100644 --- a/teavm-core/src/main/java/org/teavm/parsing/SSATransformer.java +++ b/teavm-core/src/main/java/org/teavm/parsing/SSATransformer.java @@ -393,6 +393,20 @@ public class SSATransformer { } } + @Override + public void visit(InvokeDynamicInstruction insn) { + List args = insn.getArguments(); + for (int i = 0; i < args.size(); ++i) { + args.set(i, use(args.get(i))); + } + if (insn.getInstance() != null) { + insn.setInstance(use(insn.getInstance())); + } + if (insn.getReceiver() != null) { + insn.setReceiver(define(insn.getReceiver())); + } + } + @Override public void visit(IsInstanceInstruction insn) { insn.setValue(use(insn.getValue())); diff --git a/teavm-core/src/main/java/org/teavm/tooling/InstructionLocationReader.java b/teavm-core/src/main/java/org/teavm/tooling/InstructionLocationReader.java index 872200350..8876bb2c9 100644 --- a/teavm-core/src/main/java/org/teavm/tooling/InstructionLocationReader.java +++ b/teavm-core/src/main/java/org/teavm/tooling/InstructionLocationReader.java @@ -17,12 +17,7 @@ package org.teavm.tooling; import java.util.List; import java.util.Set; -import org.teavm.model.BasicBlockReader; -import org.teavm.model.FieldReference; -import org.teavm.model.InstructionLocation; -import org.teavm.model.MethodReference; -import org.teavm.model.ValueType; -import org.teavm.model.VariableReader; +import org.teavm.model.*; import org.teavm.model.instructions.ArrayElementType; import org.teavm.model.instructions.BinaryBranchingCondition; import org.teavm.model.instructions.BinaryOperation; @@ -183,6 +178,12 @@ class InstructionLocationReader implements InstructionReader { List arguments, InvocationType type) { } + @Override + public void invokeDynamic(VariableReader receiver, VariableReader instance, MethodDescriptor method, + List arguments, MethodHandle bootstrapMethod, + List bootstrapArguments) { + } + @Override public void isInstance(VariableReader receiver, VariableReader value, ValueType type) { } diff --git a/teavm-core/src/main/java/org/teavm/tooling/ProgramSourceAggregator.java b/teavm-core/src/main/java/org/teavm/tooling/ProgramSourceAggregator.java index c2e5fb3bc..fd8997642 100644 --- a/teavm-core/src/main/java/org/teavm/tooling/ProgramSourceAggregator.java +++ b/teavm-core/src/main/java/org/teavm/tooling/ProgramSourceAggregator.java @@ -86,17 +86,12 @@ class ProgramSourceAggregator implements InstructionReader { @Override public void putElement(VariableReader array, VariableReader index, VariableReader value) { } @Override public void invoke(VariableReader receiver, VariableReader instance, MethodReference method, List arguments, InvocationType type) { } + @Override public void invokeDynamic(VariableReader receiver, VariableReader instance, MethodDescriptor method, + List arguments, MethodHandle bootstrapMethod, + List bootstrapArguments) { } @Override public void isInstance(VariableReader receiver, VariableReader value, ValueType type) { } @Override public void initClass(String className) { } @Override public void nullCheck(VariableReader receiver, VariableReader value) { } - - @Override - public void monitorEnter(VariableReader objectRef) { - - } - - @Override - public void monitorExit(VariableReader objectRef) { - - } + @Override public void monitorEnter(VariableReader objectRef) { } + @Override public void monitorExit(VariableReader objectRef) { } } From d5f5e2633b6593b256992873dacc3098dd94f298 Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Sun, 26 Jul 2015 15:46:49 +0300 Subject: [PATCH 2/5] InvokeDynamic support --- .../BootstrapMethodSubstitutor.java | 28 ++++ .../dependency/DataFlowGraphBuilder.java | 7 + .../teavm/dependency/DependencyChecker.java | 76 ++++------- .../dependency/DependencyClassSource.java | 14 +- .../dependency/DependencyGraphBuilder.java | 124 +++++++++++++++++- .../org/teavm/dependency/DynamicCallSite.java | 84 ++++++++++++ .../teavm/dependency/MethodDependency.java | 5 +- .../org/teavm/model/ClassReaderSource.java | 11 +- .../java/org/teavm/model/MethodHandle.java | 16 +-- .../org/teavm/model/emit/ProgramEmitter.java | 4 + .../model/util/InstructionStringifier.java | 6 +- .../org/teavm/model/util/ProgramUtils.java | 4 +- .../java/org/teavm/parsing/ProgramParser.java | 13 +- .../teavm/classlib/java/lang/LambdaTest.java | 31 +++++ 14 files changed, 341 insertions(+), 82 deletions(-) create mode 100644 teavm-core/src/main/java/org/teavm/dependency/BootstrapMethodSubstitutor.java create mode 100644 teavm-core/src/main/java/org/teavm/dependency/DynamicCallSite.java create mode 100644 teavm-tests/src/test/java/org/teavm/classlib/java/lang/LambdaTest.java diff --git a/teavm-core/src/main/java/org/teavm/dependency/BootstrapMethodSubstitutor.java b/teavm-core/src/main/java/org/teavm/dependency/BootstrapMethodSubstitutor.java new file mode 100644 index 000000000..d84b20445 --- /dev/null +++ b/teavm-core/src/main/java/org/teavm/dependency/BootstrapMethodSubstitutor.java @@ -0,0 +1,28 @@ +/* + * Copyright 2015 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.dependency; + +import org.teavm.model.emit.ProgramEmitter; +import org.teavm.model.emit.ValueEmitter; + +/** + * + * @author Alexey Andreev + */ +@FunctionalInterface +public interface BootstrapMethodSubstitutor { + ValueEmitter substitute(DynamicCallSite callSite, ProgramEmitter pe); +} diff --git a/teavm-core/src/main/java/org/teavm/dependency/DataFlowGraphBuilder.java b/teavm-core/src/main/java/org/teavm/dependency/DataFlowGraphBuilder.java index 572744465..3e52c364d 100644 --- a/teavm-core/src/main/java/org/teavm/dependency/DataFlowGraphBuilder.java +++ b/teavm-core/src/main/java/org/teavm/dependency/DataFlowGraphBuilder.java @@ -307,6 +307,13 @@ public class DataFlowGraphBuilder implements InstructionReader { } } + @Override + public void invokeDynamic(VariableReader receiver, VariableReader instance, MethodDescriptor method, + List arguments, MethodHandle bootstrapMethod, + List bootstrapArguments) { + // Should be eliminated by bootstrap method substitutor + } + @Override public void isInstance(VariableReader receiver, VariableReader value, ValueType type) { } diff --git a/teavm-core/src/main/java/org/teavm/dependency/DependencyChecker.java b/teavm-core/src/main/java/org/teavm/dependency/DependencyChecker.java index ae451caa2..7608ae471 100644 --- a/teavm-core/src/main/java/org/teavm/dependency/DependencyChecker.java +++ b/teavm-core/src/main/java/org/teavm/dependency/DependencyChecker.java @@ -15,7 +15,16 @@ */ package org.teavm.dependency; -import java.util.*; +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.BitSet; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Queue; +import java.util.Set; import org.teavm.callgraph.CallGraph; import org.teavm.callgraph.DefaultCallGraph; import org.teavm.callgraph.DefaultCallGraphNode; @@ -29,10 +38,12 @@ import org.teavm.model.ClassHolder; import org.teavm.model.ClassHolderTransformer; import org.teavm.model.ClassReader; import org.teavm.model.ClassReaderSource; +import org.teavm.model.FieldHolder; import org.teavm.model.FieldReader; import org.teavm.model.FieldReference; import org.teavm.model.InstructionLocation; import org.teavm.model.MethodDescriptor; +import org.teavm.model.MethodHolder; import org.teavm.model.MethodReader; import org.teavm.model.MethodReference; import org.teavm.model.ValueType; @@ -47,8 +58,8 @@ public class DependencyChecker implements DependencyInfo { private int classNameSuffix; private DependencyClassSource classSource; private ClassLoader classLoader; - private Mapper methodReaderCache; - private Mapper fieldReaderCache; + private Mapper methodReaderCache; + private Mapper fieldReaderCache; private CachedMapper methodCache; private CachedMapper fieldCache; private CachedMapper classCache; @@ -64,6 +75,7 @@ public class DependencyChecker implements DependencyInfo { private DependencyAgent agent; List nodes = new ArrayList<>(); List typeBitSets = new ArrayList<>(); + Map bootstrapMethodSubstitutors = new HashMap<>(); public DependencyChecker(ClassReaderSource classSource, ClassLoader classLoader, ServiceRepository services, Diagnostics diagnostics) { @@ -71,10 +83,10 @@ public class DependencyChecker implements DependencyInfo { this.classSource = new DependencyClassSource(classSource, diagnostics); this.classLoader = classLoader; this.services = services; - methodReaderCache = new CachedMapper<>(preimage -> findMethodReader(preimage)); - fieldReaderCache = new CachedMapper<>(preimage -> findFieldReader(preimage)); + methodReaderCache = new CachedMapper<>(preimage -> this.classSource.resolveMutable(preimage)); + fieldReaderCache = new CachedMapper<>(preimage -> this.classSource.resolveMutable(preimage)); methodCache = new CachedMapper<>(preimage -> { - MethodReader method = methodReaderCache.map(preimage); + MethodHolder method = methodReaderCache.map(preimage); if (method != null && !method.getReference().equals(preimage)) { return methodCache.map(method.getReference()); } @@ -268,53 +280,7 @@ public class DependencyChecker implements DependencyInfo { } } - private MethodReader findMethodReader(MethodReference methodRef) { - String clsName = methodRef.getClassName(); - MethodDescriptor desc = methodRef.getDescriptor(); - ClassReader cls = classSource.get(clsName); - if (cls == null) { - return null; - } - MethodReader reader = cls.getMethod(desc); - if (reader != null) { - return reader; - } - if (cls.getParent() != null && cls.getParent().equals(cls.getParent())) { - reader = methodReaderCache.map(new MethodReference(cls.getParent(), desc)); - if (reader != null) { - return reader; - } - } - for (String ifaceName : cls.getInterfaces()) { - reader = methodReaderCache.map(new MethodReference(ifaceName, desc)); - if (reader != null) { - return reader; - } - } - return null; - } - - private FieldReader findFieldReader(FieldReference fieldRef) { - String clsName = fieldRef.getClassName(); - String name = fieldRef.getFieldName(); - while (clsName != null) { - ClassReader cls = classSource.get(clsName); - if (cls == null) { - return null; - } - FieldReader field = cls.getField(name); - if (field != null) { - return field; - } - if (clsName.equals(cls.getParent())) { - break; - } - clsName = cls.getParent(); - } - return null; - } - - private MethodDependency createMethodDep(MethodReference methodRef, MethodReader method) { + private MethodDependency createMethodDep(MethodReference methodRef, MethodHolder method) { ValueType[] arguments = methodRef.getParameterTypes(); int paramCount = arguments.length + 1; DependencyNode[] parameterNodes = new DependencyNode[arguments.length + 1]; @@ -482,4 +448,8 @@ public class DependencyChecker implements DependencyInfo { public CallGraph getCallGraph() { return callGraph; } + + public void addBootstrapMethodSubstitutor(MethodReference method, BootstrapMethodSubstitutor substitutor) { + bootstrapMethodSubstitutors.put(method, substitutor); + } } diff --git a/teavm-core/src/main/java/org/teavm/dependency/DependencyClassSource.java b/teavm-core/src/main/java/org/teavm/dependency/DependencyClassSource.java index 8e90d5dc8..0f85399c5 100644 --- a/teavm-core/src/main/java/org/teavm/dependency/DependencyClassSource.java +++ b/teavm-core/src/main/java/org/teavm/dependency/DependencyClassSource.java @@ -20,9 +20,9 @@ import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; -import org.teavm.common.CachedMapper; import org.teavm.diagnostics.Diagnostics; import org.teavm.model.ClassHolder; +import org.teavm.model.ClassHolderSource; import org.teavm.model.ClassHolderTransformer; import org.teavm.model.ClassReader; import org.teavm.model.ClassReaderSource; @@ -32,12 +32,12 @@ import org.teavm.model.util.ModelUtils; * * @author Alexey Andreev */ -class DependencyClassSource implements ClassReaderSource { +class DependencyClassSource implements ClassHolderSource { private ClassReaderSource innerSource; private Diagnostics diagnostics; private Map generatedClasses = new HashMap<>(); private List transformers = new ArrayList<>(); - private CachedMapper cache = new CachedMapper<>(preimage -> findAndTransformClass(preimage)); + private Map cache = new HashMap<>(); public DependencyClassSource(ClassReaderSource innerSource, Diagnostics diagnostics) { this.innerSource = innerSource; @@ -45,8 +45,8 @@ class DependencyClassSource implements ClassReaderSource { } @Override - public ClassReader get(String name) { - return cache.map(name); + public ClassHolder get(String name) { + return cache.computeIfAbsent(name, n -> findAndTransformClass(n)); } public void submit(ClassHolder cls) { @@ -54,10 +54,10 @@ class DependencyClassSource implements ClassReaderSource { throw new IllegalArgumentException("Class " + cls.getName() + " is already defined"); } generatedClasses.put(cls.getName(), cls); - cache.invalidate(cls.getName()); + cache.remove(cls.getName()); } - private ClassReader findAndTransformClass(String name) { + private ClassHolder findAndTransformClass(String name) { ClassHolder cls = findClass(name); if (cls != null && !transformers.isEmpty()) { for (ClassHolderTransformer transformer : transformers) { diff --git a/teavm-core/src/main/java/org/teavm/dependency/DependencyGraphBuilder.java b/teavm-core/src/main/java/org/teavm/dependency/DependencyGraphBuilder.java index 79f4191db..c02e6f54c 100644 --- a/teavm-core/src/main/java/org/teavm/dependency/DependencyGraphBuilder.java +++ b/teavm-core/src/main/java/org/teavm/dependency/DependencyGraphBuilder.java @@ -20,9 +20,45 @@ import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; +import java.util.stream.Collectors; import org.teavm.callgraph.DefaultCallGraphNode; -import org.teavm.model.*; -import org.teavm.model.instructions.*; +import org.teavm.model.BasicBlock; +import org.teavm.model.BasicBlockReader; +import org.teavm.model.CallLocation; +import org.teavm.model.ClassReader; +import org.teavm.model.ClassReaderSource; +import org.teavm.model.ElementModifier; +import org.teavm.model.FieldReference; +import org.teavm.model.Incoming; +import org.teavm.model.IncomingReader; +import org.teavm.model.Instruction; +import org.teavm.model.InstructionLocation; +import org.teavm.model.InvokeDynamicInstruction; +import org.teavm.model.MethodDescriptor; +import org.teavm.model.MethodHandle; +import org.teavm.model.MethodHolder; +import org.teavm.model.MethodReference; +import org.teavm.model.Phi; +import org.teavm.model.PhiReader; +import org.teavm.model.Program; +import org.teavm.model.RuntimeConstant; +import org.teavm.model.TryCatchBlockReader; +import org.teavm.model.ValueType; +import org.teavm.model.VariableReader; +import org.teavm.model.emit.ProgramEmitter; +import org.teavm.model.emit.ValueEmitter; +import org.teavm.model.instructions.ArrayElementType; +import org.teavm.model.instructions.AssignInstruction; +import org.teavm.model.instructions.BinaryBranchingCondition; +import org.teavm.model.instructions.BinaryOperation; +import org.teavm.model.instructions.BranchingCondition; +import org.teavm.model.instructions.CastIntegerDirection; +import org.teavm.model.instructions.InstructionReader; +import org.teavm.model.instructions.IntegerSubtype; +import org.teavm.model.instructions.InvocationType; +import org.teavm.model.instructions.NullConstantInstruction; +import org.teavm.model.instructions.NumericOperandType; +import org.teavm.model.instructions.SwitchTableEntryReader; import org.teavm.model.util.ListingBuilder; /** @@ -33,7 +69,7 @@ class DependencyGraphBuilder { private DependencyChecker dependencyChecker; private DependencyNode[] nodes; private DependencyNode resultNode; - private ProgramReader program; + private Program program; private DefaultCallGraphNode caller; private InstructionLocation currentLocation; private ExceptionConsumer currentExceptionConsumer; @@ -44,13 +80,15 @@ class DependencyGraphBuilder { public void buildGraph(MethodDependency dep) { caller = dependencyChecker.callGraph.getNode(dep.getReference()); - MethodReader method = dep.getMethod(); + MethodHolder method = dep.method; if (method.getProgram() == null || method.getProgram().basicBlockCount() == 0) { return; } program = method.getProgram(); resultNode = dep.getResult(); + processInvokeDynamic(); + DataFlowGraphBuilder dfgBuilder = new DataFlowGraphBuilder(); boolean[] significantParams = new boolean[dep.getParameterCount()]; significantParams[0] = true; @@ -146,6 +184,77 @@ class DependencyGraphBuilder { } } + private void processInvokeDynamic() { + if (program == null) { + return; + } + System.out.println(new ListingBuilder().buildListing(program, "")); + ProgramEmitter pe = ProgramEmitter.create(program); + for (int i = 0; i < program.basicBlockCount(); ++i) { + BasicBlock block = program.basicBlockAt(i); + for (int j = 0; j < block.getInstructions().size(); ++j) { + Instruction insn = block.getInstructions().get(j); + if (!(insn instanceof InvokeDynamicInstruction)) { + continue; + } + InvokeDynamicInstruction indy = (InvokeDynamicInstruction) insn; + MethodReference bootstrapMethod = new MethodReference(indy.getBootstrapMethod().getClassName(), + indy.getBootstrapMethod().getName(), indy.getBootstrapMethod().signature()); + BootstrapMethodSubstitutor substitutor = dependencyChecker.bootstrapMethodSubstitutors + .get(bootstrapMethod); + if (substitutor == null) { + NullConstantInstruction nullInsn = new NullConstantInstruction(); + nullInsn.setReceiver(indy.getReceiver()); + nullInsn.setLocation(indy.getLocation()); + block.getInstructions().set(j, nullInsn); + CallLocation location = new CallLocation(bootstrapMethod, indy.getLocation()); + dependencyChecker.getDiagnostics().error(location, "Substitutor for this dependency method " + + "was not found"); + continue; + } + + BasicBlock splitBlock = program.createBasicBlock(); + List splitInstructions = block.getInstructions().subList(j + 1, + block.getInstructions().size()); + splitBlock.getInstructions().addAll(splitInstructions); + splitInstructions.clear(); + + for (int k = 0; k < program.basicBlockCount() - 1; ++k) { + BasicBlock replaceBlock = program.basicBlockAt(k); + for (Phi phi : replaceBlock.getPhis()) { + for (Incoming incoming : phi.getIncomings()) { + if (incoming.getSource() == block) { + incoming.setSource(splitBlock); + } + } + } + } + + pe.setBlock(block); + pe.setCurrentLocation(indy.getLocation()); + block.getInstructions().remove(j); + + DynamicCallSite callSite = new DynamicCallSite( + indy.getMethod(), + indy.getInstance() != null ? pe.var(indy.getInstance()) : null, + indy.getArguments().stream().map(arg -> pe.var(arg)).collect(Collectors.toList()), + indy.getBootstrapMethod(), + indy.getBootstrapArguments(), + dependencyChecker.getAgent(), + indy.getInstance() != null ? nodes[indy.getInstance().getIndex()] : null, + indy.getArguments().stream().map(arg -> nodes[arg.getIndex()]).collect(Collectors.toList())); + ValueEmitter result = substitutor.substitute(callSite, pe); + if (result.getVariable() != null && result.getVariable() != indy.getReceiver()) { + AssignInstruction assign = new AssignInstruction(); + assign.setAssignee(result.getVariable()); + assign.setReceiver(indy.getReceiver()); + pe.addInstruction(insn); + } + pe.jump(splitBlock); + } + } + } + private ExceptionConsumer createExceptionConsumer(MethodDependency methodDep, BasicBlockReader block) { List tryCatchBlocks = block.readTryCatchBlocks(); ClassReader[] exceptions = new ClassReader[tryCatchBlocks.size()]; @@ -613,6 +722,13 @@ class DependencyGraphBuilder { } } + @Override + public void invokeDynamic(VariableReader receiver, VariableReader instance, MethodDescriptor method, + List arguments, MethodHandle bootstrapMethod, + List bootstrapArguments) { + // Should be eliminated by processInvokeDynamic method + } + @Override public void initClass(final String className) { CallLocation callLocation = new CallLocation(caller.getMethod(), currentLocation); diff --git a/teavm-core/src/main/java/org/teavm/dependency/DynamicCallSite.java b/teavm-core/src/main/java/org/teavm/dependency/DynamicCallSite.java new file mode 100644 index 000000000..35b9f0113 --- /dev/null +++ b/teavm-core/src/main/java/org/teavm/dependency/DynamicCallSite.java @@ -0,0 +1,84 @@ +/* + * Copyright 2015 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.dependency; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import org.teavm.model.MethodDescriptor; +import org.teavm.model.MethodHandle; +import org.teavm.model.RuntimeConstant; +import org.teavm.model.emit.ValueEmitter; + +/** + * + * @author Alexey Andreev + */ +public class DynamicCallSite { + private MethodDescriptor calledMethod; + private ValueEmitter instance; + private List arguments; + private MethodHandle bootstrapMethod; + private List bootstrapArguments; + private DependencyAgent agent; + private DependencyNode instanceNode; + private List argumentNodes = new ArrayList<>(); + + DynamicCallSite(MethodDescriptor calledMethod, ValueEmitter instance, List arguments, + MethodHandle bootstrapMethod, List bootstrapArguments, DependencyAgent agent, + DependencyNode instanceNode, List argumentNodes) { + this.calledMethod = calledMethod; + this.instance = instance; + this.arguments = Collections.unmodifiableList(new ArrayList<>(arguments)); + this.bootstrapMethod = bootstrapMethod; + this.bootstrapArguments = Collections.unmodifiableList(new ArrayList<>(bootstrapArguments)); + this.agent = agent; + this.instanceNode = instanceNode; + this.argumentNodes = Collections.unmodifiableList(new ArrayList<>(argumentNodes)); + } + + public MethodDescriptor getCalledMethod() { + return calledMethod; + } + + public MethodHandle getBootstrapMethod() { + return bootstrapMethod; + } + + public List getArguments() { + return arguments; + } + + public List getBootstrapArguments() { + return bootstrapArguments; + } + + public DependencyAgent getAgent() { + return agent; + } + + public ValueEmitter getInstance() { + return instance; + } + + public DependencyNode getInstanceNode() { + return instanceNode; + } + + public List getArgumentNodes() { + return argumentNodes; + } +} diff --git a/teavm-core/src/main/java/org/teavm/dependency/MethodDependency.java b/teavm-core/src/main/java/org/teavm/dependency/MethodDependency.java index 4b1b05931..7fb7a38c1 100644 --- a/teavm-core/src/main/java/org/teavm/dependency/MethodDependency.java +++ b/teavm-core/src/main/java/org/teavm/dependency/MethodDependency.java @@ -16,6 +16,7 @@ package org.teavm.dependency; import java.util.Arrays; +import org.teavm.model.MethodHolder; import org.teavm.model.MethodReader; import org.teavm.model.MethodReference; @@ -29,14 +30,14 @@ public class MethodDependency implements MethodDependencyInfo { private int parameterCount; private DependencyNode resultNode; private DependencyNode thrown; - private MethodReader method; + MethodHolder method; private MethodReference reference; private boolean used; DependencyPlugin dependencyPlugin; boolean dependencyPluginAttached; MethodDependency(DependencyChecker dependencyChecker, DependencyNode[] variableNodes, int parameterCount, - DependencyNode resultNode, DependencyNode thrown, MethodReader method, MethodReference reference) { + DependencyNode resultNode, DependencyNode thrown, MethodHolder method, MethodReference reference) { this.dependencyChecker = dependencyChecker; this.variableNodes = Arrays.copyOf(variableNodes, variableNodes.length); this.parameterCount = parameterCount; diff --git a/teavm-core/src/main/java/org/teavm/model/ClassReaderSource.java b/teavm-core/src/main/java/org/teavm/model/ClassReaderSource.java index fc6291772..a98f6de9f 100644 --- a/teavm-core/src/main/java/org/teavm/model/ClassReaderSource.java +++ b/teavm-core/src/main/java/org/teavm/model/ClassReaderSource.java @@ -15,7 +15,11 @@ */ package org.teavm.model; -import java.util.*; +import java.util.ArrayDeque; +import java.util.Deque; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; import java.util.stream.Stream; import java.util.stream.StreamSupport; @@ -52,6 +56,7 @@ public interface ClassReaderSource { private Deque> state = new ArrayDeque<>(); private Set visited = new HashSet<>(); { + state.push(new ArrayDeque<>()); add(name); } @Override public ClassReader next() { @@ -89,14 +94,14 @@ public interface ClassReaderSource { } default MethodReader resolve(MethodReference method) { - return getAncestorClasses(method.getClassName()) + return getAncestors(method.getClassName()) .map(cls -> cls.getMethod(method.getDescriptor())) .filter(candidate -> candidate != null) .findFirst().orElse(null); } default FieldReader resolve(FieldReference field) { - return getAncestorClasses(field.getClassName()) + return getAncestors(field.getClassName()) .map(cls -> cls.getField(field.getFieldName())) .filter(candidate -> candidate != null) .findFirst().orElse(null); diff --git a/teavm-core/src/main/java/org/teavm/model/MethodHandle.java b/teavm-core/src/main/java/org/teavm/model/MethodHandle.java index 21afb3a35..f311497ba 100644 --- a/teavm-core/src/main/java/org/teavm/model/MethodHandle.java +++ b/teavm-core/src/main/java/org/teavm/model/MethodHandle.java @@ -117,8 +117,8 @@ public class MethodHandle { } public static MethodHandle staticCaller(String className, String name, ValueType... arguments) { - ValueType valueType = arguments[0]; - arguments = Arrays.copyOfRange(arguments, 1, arguments.length); + ValueType valueType = arguments[arguments.length - 1]; + arguments = Arrays.copyOfRange(arguments, 0, arguments.length - 1); return new MethodHandle(MethodHandleType.INVOKE_STATIC, className, name, valueType, arguments); } @@ -131,8 +131,8 @@ public class MethodHandle { } public static MethodHandle specialCaller(String className, String name, ValueType... arguments) { - ValueType valueType = arguments[0]; - arguments = Arrays.copyOfRange(arguments, 1, arguments.length); + ValueType valueType = arguments[arguments.length - 1]; + arguments = Arrays.copyOfRange(arguments, 0, arguments.length - 1); return new MethodHandle(MethodHandleType.INVOKE_SPECIAL, className, name, valueType, arguments); } @@ -145,8 +145,8 @@ public class MethodHandle { } public static MethodHandle constructorCaller(String className, String name, ValueType... arguments) { - ValueType valueType = arguments[0]; - arguments = Arrays.copyOfRange(arguments, 1, arguments.length); + ValueType valueType = arguments[arguments.length - 1]; + arguments = Arrays.copyOfRange(arguments, 0, arguments.length - 1); return new MethodHandle(MethodHandleType.INVOKE_CONSTRUCTOR, className, name, valueType, arguments); } @@ -159,8 +159,8 @@ public class MethodHandle { } public static MethodHandle interfaceCaller(String className, String name, ValueType... arguments) { - ValueType valueType = arguments[0]; - arguments = Arrays.copyOfRange(arguments, 1, arguments.length); + ValueType valueType = arguments[arguments.length - 1]; + arguments = Arrays.copyOfRange(arguments, 0, arguments.length - 1); return new MethodHandle(MethodHandleType.INVOKE_INTERFACE, className, name, valueType, arguments); } diff --git a/teavm-core/src/main/java/org/teavm/model/emit/ProgramEmitter.java b/teavm-core/src/main/java/org/teavm/model/emit/ProgramEmitter.java index bc74736b4..07786c1ac 100644 --- a/teavm-core/src/main/java/org/teavm/model/emit/ProgramEmitter.java +++ b/teavm-core/src/main/java/org/teavm/model/emit/ProgramEmitter.java @@ -258,4 +258,8 @@ public final class ProgramEmitter { return new ProgramEmitter(program, block); } + + public static ProgramEmitter create(Program program) { + return new ProgramEmitter(program, null); + } } diff --git a/teavm-core/src/main/java/org/teavm/model/util/InstructionStringifier.java b/teavm-core/src/main/java/org/teavm/model/util/InstructionStringifier.java index 475d94c53..18a5695e7 100644 --- a/teavm-core/src/main/java/org/teavm/model/util/InstructionStringifier.java +++ b/teavm-core/src/main/java/org/teavm/model/util/InstructionStringifier.java @@ -346,8 +346,10 @@ public class InstructionStringifier implements InstructionReader { if (receiver != null) { sb.append("@").append(receiver.getIndex()).append(" := "); } - sb.append("@").append(instance.getIndex()); - sb.append(".").append(method.getName()).append("("); + if (instance != null) { + sb.append("@").append(instance.getIndex()).append("."); + } + sb.append(method.getName()).append("("); sb.append(arguments.stream().map(arg -> "@" + arg.getIndex()).collect(Collectors.joining(", "))); sb.append(") "); sb.append("[").append(convert(bootstrapMethod)).append('('); diff --git a/teavm-core/src/main/java/org/teavm/model/util/ProgramUtils.java b/teavm-core/src/main/java/org/teavm/model/util/ProgramUtils.java index 1c4fe6406..8107ebe96 100644 --- a/teavm-core/src/main/java/org/teavm/model/util/ProgramUtils.java +++ b/teavm-core/src/main/java/org/teavm/model/util/ProgramUtils.java @@ -480,7 +480,9 @@ public final class ProgramUtils { insnCopy.setMethod(method); insnCopy.setBootstrapMethod(bootstrapMethod); insnCopy.getBootstrapArguments().addAll(bootstrapArguments); - insnCopy.setInstance(copyVar(instance)); + if (instance != null) { + insnCopy.setInstance(copyVar(instance)); + } insnCopy.getArguments().addAll(arguments.stream().map(v -> copyVar(v)).collect(Collectors.toList())); insnCopy.setReceiver(receiver != null ? copyVar(receiver) : null); copy = insnCopy; diff --git a/teavm-core/src/main/java/org/teavm/parsing/ProgramParser.java b/teavm-core/src/main/java/org/teavm/parsing/ProgramParser.java index c0427e946..19a4495ae 100644 --- a/teavm-core/src/main/java/org/teavm/parsing/ProgramParser.java +++ b/teavm-core/src/main/java/org/teavm/parsing/ProgramParser.java @@ -487,8 +487,18 @@ public class ProgramParser implements VariableDebugInformation { @Override public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, Object... bsmArgs) { InvokeDynamicInstruction insn = new InvokeDynamicInstruction(); + insn.setBootstrapMethod(parseHandle(bsm)); - insn.setInstance(getVariable(popSingle())); + switch (insn.getBootstrapMethod().getKind()) { + case GET_STATIC_FIELD: + case PUT_STATIC_FIELD: + case INVOKE_STATIC: + case INVOKE_CONSTRUCTOR: + break; + default: + insn.setInstance(getVariable(popSingle())); + break; + } Type[] types = Type.getArgumentTypes(desc); Variable[] args = new Variable[types.length]; int j = args.length; @@ -503,7 +513,6 @@ public class ProgramParser implements VariableDebugInformation { } insn.setMethod(new MethodDescriptor(name, MethodDescriptor.parseSignature(desc))); - insn.setBootstrapMethod(parseHandle(bsm)); for (int i = 0; i < bsmArgs.length; ++i) { insn.getBootstrapArguments().add(convertConstant(bsmArgs[i])); } diff --git a/teavm-tests/src/test/java/org/teavm/classlib/java/lang/LambdaTest.java b/teavm-tests/src/test/java/org/teavm/classlib/java/lang/LambdaTest.java new file mode 100644 index 000000000..d96117932 --- /dev/null +++ b/teavm-tests/src/test/java/org/teavm/classlib/java/lang/LambdaTest.java @@ -0,0 +1,31 @@ +package org.teavm.classlib.java.lang; + +import static org.junit.Assert.assertArrayEquals; +import java.lang.reflect.Array; +import org.junit.Test; + +/** + * + * @author Alexey Andreev + */ +public class LambdaTest { + @Test + public void lambdaWorks() { + Integer[] src = { 1, 2, 3 }; + Integer[] array = map(src, (Integer n) -> n * 2 + src[0]); + assertArrayEquals(new Integer[] { 3, 5, 7 }, array); + } + + static T[] map(T[] array, Function f) { + @SuppressWarnings("unchecked") + T[] result = (T[])Array.newInstance(array.getClass().getComponentType(), array.length); + for (int i = 0; i < result.length; ++i) { + result[i] = f.apply(array[i]); + } + return result; + } + + interface Function { + T apply(T value); + } +} From 13353d0bdee9a22579646585a6bf9c550047ede1 Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Sun, 26 Jul 2015 18:47:37 +0300 Subject: [PATCH 3/5] LambdaMetafactory support --- .../org/teavm/classlib/impl/JCLPlugin.java | 9 + .../lambda/LambdaMetafactorySubstitutor.java | 314 ++++++++++++++++++ .../dependency/DependencyGraphBuilder.java | 16 +- .../org/teavm/dependency/DynamicCallSite.java | 15 +- .../org/teavm/model/ClassReaderSource.java | 25 +- .../org/teavm/model/emit/ValueEmitter.java | 3 + .../java/org/teavm/parsing/ProgramParser.java | 18 +- .../src/main/java/org/teavm/vm/TeaVM.java | 5 + .../main/java/org/teavm/vm/spi/TeaVMHost.java | 3 + 9 files changed, 374 insertions(+), 34 deletions(-) create mode 100644 teavm-classlib/src/main/java/org/teavm/classlib/impl/lambda/LambdaMetafactorySubstitutor.java diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/impl/JCLPlugin.java b/teavm-classlib/src/main/java/org/teavm/classlib/impl/JCLPlugin.java index cb2776abd..6df6aeaf1 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/impl/JCLPlugin.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/impl/JCLPlugin.java @@ -15,7 +15,13 @@ */ package org.teavm.classlib.impl; +import java.lang.invoke.CallSite; +import java.lang.invoke.LambdaMetafactory; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; import java.util.ServiceLoader; +import org.teavm.classlib.impl.lambda.LambdaMetafactorySubstitutor; import org.teavm.classlib.impl.unicode.CLDRReader; import org.teavm.classlib.java.lang.reflect.AnnotationDependencyListener; import org.teavm.model.MethodReference; @@ -41,5 +47,8 @@ public class JCLPlugin implements TeaVMPlugin { host.registerService(CLDRReader.class, new CLDRReader(host.getProperties(), host.getClassLoader())); host.add(new AnnotationDependencyListener()); + host.add(new MethodReference(LambdaMetafactory.class, "metafactory", MethodHandles.Lookup.class, + String.class, MethodType.class, MethodType.class, MethodHandle.class, MethodType.class, + CallSite.class), new LambdaMetafactorySubstitutor()); } } diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/impl/lambda/LambdaMetafactorySubstitutor.java b/teavm-classlib/src/main/java/org/teavm/classlib/impl/lambda/LambdaMetafactorySubstitutor.java new file mode 100644 index 000000000..9a28bc502 --- /dev/null +++ b/teavm-classlib/src/main/java/org/teavm/classlib/impl/lambda/LambdaMetafactorySubstitutor.java @@ -0,0 +1,314 @@ +package org.teavm.classlib.impl.lambda; + +import java.util.Arrays; +import org.teavm.dependency.BootstrapMethodSubstitutor; +import org.teavm.dependency.DynamicCallSite; +import org.teavm.model.AccessLevel; +import org.teavm.model.ClassHolder; +import org.teavm.model.ClassReader; +import org.teavm.model.ClassReaderSource; +import org.teavm.model.ElementModifier; +import org.teavm.model.FieldHolder; +import org.teavm.model.FieldReference; +import org.teavm.model.MethodHandle; +import org.teavm.model.MethodHolder; +import org.teavm.model.MethodReference; +import org.teavm.model.PrimitiveType; +import org.teavm.model.ValueType; +import org.teavm.model.emit.ProgramEmitter; +import org.teavm.model.emit.ValueEmitter; +import org.teavm.model.instructions.CastIntegerDirection; +import org.teavm.model.instructions.IntegerSubtype; +import org.teavm.model.instructions.NumericOperandType; + +/** + * + * @author Alexey Andreev + */ +public class LambdaMetafactorySubstitutor implements BootstrapMethodSubstitutor { + private int lambdaIndex = 0; + + @Override + public ValueEmitter substitute(DynamicCallSite callSite, ProgramEmitter callerPe) { + ValueType[] invokedType = callSite.getCalledMethod().getSignature(); + ValueType[] samMethodType = callSite.getBootstrapArguments().get(0).getMethodType(); + MethodHandle implMethod = callSite.getBootstrapArguments().get(1).getMethodHandle(); + ValueType[] instantiatedMethodType = callSite.getBootstrapArguments().get(2).getMethodType(); + + String samName = ((ValueType.Object) callSite.getCalledMethod().getResultType()).getClassName(); + ClassReaderSource classSource = callSite.getAgent().getClassSource(); + ClassReader samClass = classSource.get(samName); + + ClassHolder implementor = new ClassHolder("$$LAMBDA" + (lambdaIndex++) + "$$"); + implementor.setLevel(AccessLevel.PUBLIC); + if (samClass != null && samClass.hasModifier(ElementModifier.INTERFACE)) { + implementor.setParent("java.lang.Object"); + implementor.getInterfaces().add(samName); + } else { + implementor.setParent(samName); + } + + int capturedVarCount = callSite.getCalledMethod().parameterCount(); + MethodHolder ctor = createConstructor(implementor, Arrays.copyOfRange(invokedType, 0, capturedVarCount)); + createBridge(implementor, callSite.getCalledMethod().getName(), instantiatedMethodType, samMethodType); + + MethodHolder worker = new MethodHolder(callSite.getCalledMethod().getName(), instantiatedMethodType); + worker.setLevel(AccessLevel.PUBLIC); + ProgramEmitter pe = ProgramEmitter.create(worker); + ValueEmitter thisVar = pe.newVar(); + ValueEmitter[] arguments = new ValueEmitter[instantiatedMethodType.length - 1]; + for (int i = 0; i < arguments.length; ++i) { + arguments[i] = pe.newVar(); + } + + ValueType[] implementorSignature = getSignature(implMethod); + ValueEmitter[] passedArguments = new ValueEmitter[implementorSignature.length - 1]; + for (int i = 0; i < capturedVarCount; ++i) { + passedArguments[i] = thisVar.getField(new FieldReference(implementor.getName(), "_" + i), invokedType[i]); + } + for (int i = 0; i < instantiatedMethodType.length - 1; ++i) { + passedArguments[i + capturedVarCount] = tryConvertArgument(arguments[i], instantiatedMethodType[i], + implementorSignature[i + capturedVarCount]); + } + + ValueEmitter result = invoke(pe, implMethod, callSite.getInstance(), passedArguments); + if (result != null) { + ValueType actualResult = implementorSignature[implementorSignature.length - 1]; + ValueType expectedResult = instantiatedMethodType[instantiatedMethodType.length - 1]; + tryConvertArgument(result, actualResult, expectedResult).returnValue(); + } else { + pe.exit(); + } + + implementor.addMethod(worker); + + callSite.getAgent().submitClass(implementor); + return callerPe.construct(ctor.getReference(), callSite.getArguments().toArray(new ValueEmitter[0])); + } + + private ValueEmitter invoke(ProgramEmitter pe, MethodHandle handle, ValueEmitter instance, + ValueEmitter[] arguments) { + switch (handle.getKind()) { + case GET_FIELD: + return instance.getField(new FieldReference(handle.getClassName(), handle.getName()), + handle.getValueType()); + case GET_STATIC_FIELD: + return pe.getField(new FieldReference(handle.getClassName(), handle.getName()), + handle.getValueType()); + case PUT_FIELD: + instance.setField(new FieldReference(handle.getClassName(), handle.getName()), handle.getValueType(), + arguments[0]); + return null; + case PUT_STATIC_FIELD: + pe.setField(new FieldReference(handle.getClassName(), handle.getName()), handle.getValueType(), + arguments[0]); + return null; + case INVOKE_VIRTUAL: + case INVOKE_INTERFACE: + case INVOKE_SPECIAL: + return instance.invokeVirtual(new MethodReference(handle.getClassName(), handle.getName(), + handle.signature()), arguments); + case INVOKE_STATIC: + return pe.invoke(new MethodReference(handle.getClassName(), handle.getName(), + handle.signature()), arguments); + case INVOKE_CONSTRUCTOR: + return pe.construct(new MethodReference(handle.getClassName(), handle.getName(), + handle.signature()), arguments); + default: + throw new IllegalArgumentException("Unexpected handle type: " + handle.getKind()); + } + } + + private ValueEmitter tryConvertArgument(ValueEmitter arg, ValueType from, ValueType to) { + if (from.equals(to)) { + return arg; + } + if (from instanceof ValueType.Primitive && to instanceof ValueType.Primitive) { + PrimitiveType fromType = ((ValueType.Primitive) from).getKind(); + PrimitiveType toType = ((ValueType.Primitive) to).getKind(); + IntegerSubtype fromSubtype = convert(fromType); + if (fromSubtype != null) { + arg = arg.cast(fromSubtype, CastIntegerDirection.TO_INTEGER); + } + arg = arg.cast(convertNumeric(fromType), convertNumeric(toType)); + IntegerSubtype toSubtype = convert(toType); + if (toSubtype != null) { + arg = arg.cast(fromSubtype, CastIntegerDirection.FROM_INTEGER); + } + return arg; + } else if (from instanceof ValueType.Primitive && to instanceof ValueType.Object) { + String primitiveClass = ((ValueType.Object) to).getClassName(); + PrimitiveType toType = getWrappedPrimitive(primitiveClass); + if (toType == null) { + return arg; + } + arg = tryConvertArgument(arg, from, ValueType.primitive(toType)); + return arg.getProgramEmitter().invoke(new MethodReference(primitiveClass, "valueOf", + ValueType.primitive(toType), to), arg); + } else if (from instanceof ValueType.Object && to instanceof ValueType.Primitive) { + String primitiveClass = ((ValueType.Object) from).getClassName(); + PrimitiveType fromType = getWrappedPrimitive(primitiveClass); + if (fromType == null) { + return arg; + } + arg = arg.invokeVirtual(new MethodReference(primitiveClass, primitiveName(fromType) + "Value", + ValueType.primitive(fromType))); + return tryConvertArgument(arg, ValueType.primitive(fromType), to); + } else { + return arg.cast(to); + } + } + + private IntegerSubtype convert(PrimitiveType type) { + switch (type) { + case BOOLEAN: + case BYTE: + return IntegerSubtype.BYTE; + case SHORT: + return IntegerSubtype.SHORT; + case CHARACTER: + return IntegerSubtype.CHARACTER; + default: + return null; + } + } + + private NumericOperandType convertNumeric(PrimitiveType type) { + switch (type) { + case BOOLEAN: + case BYTE: + case SHORT: + case CHARACTER: + case INTEGER: + return NumericOperandType.INT; + case LONG: + return NumericOperandType.LONG; + case FLOAT: + return NumericOperandType.FLOAT; + case DOUBLE: + return NumericOperandType.DOUBLE; + default: + throw new IllegalArgumentException("Unexpected type " + type); + } + } + + private PrimitiveType getWrappedPrimitive(String name) { + switch (name) { + case "java.lang.Boolean": + return PrimitiveType.BOOLEAN; + case "java.lang.Byte": + return PrimitiveType.BYTE; + case "java.lang.Short": + return PrimitiveType.SHORT; + case "java.lang.Character": + return PrimitiveType.CHARACTER; + case "java.lang.Integer": + return PrimitiveType.INTEGER; + case "java.lang.Long": + return PrimitiveType.LONG; + case "java.lang.Float": + return PrimitiveType.FLOAT; + case "java.lang.Double": + return PrimitiveType.DOUBLE; + default: + return null; + } + } + + private String primitiveName(PrimitiveType type) { + switch (type) { + case BOOLEAN: + return "boolean"; + case BYTE: + return "byte"; + case SHORT: + return "short"; + case CHARACTER: + return "char"; + case INTEGER: + return "int"; + case LONG: + return "long"; + case FLOAT: + return "float"; + case DOUBLE: + return "double"; + default: + throw new IllegalArgumentException("Unexpected primitive " + type); + } + } + + private ValueType[] getSignature(MethodHandle handle) { + switch (handle.getKind()) { + case GET_FIELD: + case GET_STATIC_FIELD: + return new ValueType[] { handle.getValueType() }; + case PUT_FIELD: + case PUT_STATIC_FIELD: + return new ValueType[] { handle.getValueType(), ValueType.VOID }; + default: + return handle.signature(); + } + } + + private MethodHolder createConstructor(ClassHolder implementor, ValueType[] types) { + ValueType[] signature = Arrays.copyOf(types, types.length + 1); + signature[types.length] = ValueType.VOID; + MethodHolder ctor = new MethodHolder("", signature); + ctor.setLevel(AccessLevel.PUBLIC); + + ProgramEmitter pe = ProgramEmitter.create(ctor); + ValueEmitter thisVar = pe.newVar(); + thisVar.invokeSpecial(new MethodReference(implementor.getParent(), "", ValueType.VOID)); + + for (int i = 0; i < types.length; ++i) { + FieldHolder field = new FieldHolder("_" + i); + field.setLevel(AccessLevel.PRIVATE); + field.setType(types[i]); + implementor.addField(field); + thisVar.setField(field.getReference(), types[i], pe.newVar()); + } + + pe.exit(); + implementor.addMethod(ctor); + return ctor; + } + + private void createBridge(ClassHolder implementor, String name, ValueType[] types, ValueType[] bridgeTypes) { + if (Arrays.equals(types, bridgeTypes)) { + return; + } + + MethodHolder bridge = new MethodHolder(name, bridgeTypes); + bridge.setLevel(AccessLevel.PUBLIC); + bridge.getModifiers().add(ElementModifier.BRIDGE); + ProgramEmitter pe = ProgramEmitter.create(bridge); + ValueEmitter thisVar = pe.newVar(); + ValueEmitter[] arguments = new ValueEmitter[bridgeTypes.length - 1]; + for (int i = 0; i < arguments.length; ++i) { + arguments[i] = pe.newVar(); + } + + for (int i = 0; i < bridgeTypes.length - 1; ++i) { + ValueType type = types[i]; + ValueType bridgeType = types[i]; + if (type.equals(bridgeType)) { + continue; + } + arguments[i] = arguments[i].cast(type); + } + + ValueEmitter result = thisVar.invokeVirtual(new MethodReference(implementor.getName(), name, types), + arguments); + if (result != null) { + if (!types[types.length - 1].equals(bridgeTypes[bridgeTypes.length - 1])) { + result = result.cast(bridgeTypes[bridgeTypes.length - 1]); + } + result.returnValue(); + } else { + pe.exit(); + } + + implementor.addMethod(bridge); + } +} diff --git a/teavm-core/src/main/java/org/teavm/dependency/DependencyGraphBuilder.java b/teavm-core/src/main/java/org/teavm/dependency/DependencyGraphBuilder.java index c02e6f54c..3b7e205db 100644 --- a/teavm-core/src/main/java/org/teavm/dependency/DependencyGraphBuilder.java +++ b/teavm-core/src/main/java/org/teavm/dependency/DependencyGraphBuilder.java @@ -188,7 +188,6 @@ class DependencyGraphBuilder { if (program == null) { return; } - System.out.println(new ListingBuilder().buildListing(program, "")); ProgramEmitter pe = ProgramEmitter.create(program); for (int i = 0; i < program.basicBlockCount(); ++i) { BasicBlock block = program.basicBlockAt(i); @@ -207,17 +206,18 @@ class DependencyGraphBuilder { nullInsn.setReceiver(indy.getReceiver()); nullInsn.setLocation(indy.getLocation()); block.getInstructions().set(j, nullInsn); - CallLocation location = new CallLocation(bootstrapMethod, indy.getLocation()); - dependencyChecker.getDiagnostics().error(location, "Substitutor for this dependency method " - + "was not found"); + CallLocation location = new CallLocation(caller.getMethod(), currentLocation); + dependencyChecker.getDiagnostics().error(location, "Substitutor for bootstrap " + + "method {{m0}} was not found", bootstrapMethod); continue; } BasicBlock splitBlock = program.createBasicBlock(); List splitInstructions = block.getInstructions().subList(j + 1, block.getInstructions().size()); - splitBlock.getInstructions().addAll(splitInstructions); + List splitInstructionsBackup = new ArrayList<>(splitInstructions); splitInstructions.clear(); + splitBlock.getInstructions().addAll(splitInstructionsBackup); for (int k = 0; k < program.basicBlockCount() - 1; ++k) { BasicBlock replaceBlock = program.basicBlockAt(k); @@ -240,15 +240,13 @@ class DependencyGraphBuilder { indy.getArguments().stream().map(arg -> pe.var(arg)).collect(Collectors.toList()), indy.getBootstrapMethod(), indy.getBootstrapArguments(), - dependencyChecker.getAgent(), - indy.getInstance() != null ? nodes[indy.getInstance().getIndex()] : null, - indy.getArguments().stream().map(arg -> nodes[arg.getIndex()]).collect(Collectors.toList())); + dependencyChecker.getAgent()); ValueEmitter result = substitutor.substitute(callSite, pe); if (result.getVariable() != null && result.getVariable() != indy.getReceiver()) { AssignInstruction assign = new AssignInstruction(); assign.setAssignee(result.getVariable()); assign.setReceiver(indy.getReceiver()); - pe.addInstruction(insn); + pe.addInstruction(assign); } pe.jump(splitBlock); } diff --git a/teavm-core/src/main/java/org/teavm/dependency/DynamicCallSite.java b/teavm-core/src/main/java/org/teavm/dependency/DynamicCallSite.java index 35b9f0113..5e1268ec4 100644 --- a/teavm-core/src/main/java/org/teavm/dependency/DynamicCallSite.java +++ b/teavm-core/src/main/java/org/teavm/dependency/DynamicCallSite.java @@ -34,20 +34,15 @@ public class DynamicCallSite { private MethodHandle bootstrapMethod; private List bootstrapArguments; private DependencyAgent agent; - private DependencyNode instanceNode; - private List argumentNodes = new ArrayList<>(); DynamicCallSite(MethodDescriptor calledMethod, ValueEmitter instance, List arguments, - MethodHandle bootstrapMethod, List bootstrapArguments, DependencyAgent agent, - DependencyNode instanceNode, List argumentNodes) { + MethodHandle bootstrapMethod, List bootstrapArguments, DependencyAgent agent) { this.calledMethod = calledMethod; this.instance = instance; this.arguments = Collections.unmodifiableList(new ArrayList<>(arguments)); this.bootstrapMethod = bootstrapMethod; this.bootstrapArguments = Collections.unmodifiableList(new ArrayList<>(bootstrapArguments)); this.agent = agent; - this.instanceNode = instanceNode; - this.argumentNodes = Collections.unmodifiableList(new ArrayList<>(argumentNodes)); } public MethodDescriptor getCalledMethod() { @@ -73,12 +68,4 @@ public class DynamicCallSite { public ValueEmitter getInstance() { return instance; } - - public DependencyNode getInstanceNode() { - return instanceNode; - } - - public List getArgumentNodes() { - return argumentNodes; - } } diff --git a/teavm-core/src/main/java/org/teavm/model/ClassReaderSource.java b/teavm-core/src/main/java/org/teavm/model/ClassReaderSource.java index a98f6de9f..93d9089da 100644 --- a/teavm-core/src/main/java/org/teavm/model/ClassReaderSource.java +++ b/teavm-core/src/main/java/org/teavm/model/ClassReaderSource.java @@ -53,7 +53,7 @@ public interface ClassReaderSource { default Stream getAncestors(String name) { return StreamSupport.stream(((Iterable) () -> { return new Iterator() { - private Deque> state = new ArrayDeque<>(); + Deque> state = new ArrayDeque<>(); private Set visited = new HashSet<>(); { state.push(new ArrayDeque<>()); @@ -72,7 +72,7 @@ public interface ClassReaderSource { return null; } @Override public boolean hasNext() { - return !state.isEmpty(); + return !this.state.stream().allMatch(e -> e.isEmpty()); } private void follow(ClassReader cls) { state.push(new ArrayDeque<>()); @@ -112,4 +112,25 @@ public interface ClassReaderSource { .map(cls -> cls.getMethod(method.getDescriptor())) .filter(candidate -> candidate != null); } + + default boolean isSuperType(String superType, String subType) { + if (superType.equals(subType)) { + return true; + } + ClassReader cls = get(subType); + if (subType == null) { + return false; + } + if (cls.getParent() != null && !cls.getParent().equals(cls.getName())) { + if (isSuperType(superType, cls.getParent())) { + return true; + } + } + for (String iface : cls.getInterfaces()) { + if (isSuperType(superType, iface)) { + return true; + } + } + return false; + } } diff --git a/teavm-core/src/main/java/org/teavm/model/emit/ValueEmitter.java b/teavm-core/src/main/java/org/teavm/model/emit/ValueEmitter.java index deee5501d..a7089c16a 100644 --- a/teavm-core/src/main/java/org/teavm/model/emit/ValueEmitter.java +++ b/teavm-core/src/main/java/org/teavm/model/emit/ValueEmitter.java @@ -228,6 +228,9 @@ public class ValueEmitter { } public ValueEmitter cast(NumericOperandType from, NumericOperandType to) { + if (from == to) { + return this; + } Variable result = pe.getProgram().createVariable(); CastNumberInstruction insn = new CastNumberInstruction(from, to); insn.setValue(variable); diff --git a/teavm-core/src/main/java/org/teavm/parsing/ProgramParser.java b/teavm-core/src/main/java/org/teavm/parsing/ProgramParser.java index 19a4495ae..04978953c 100644 --- a/teavm-core/src/main/java/org/teavm/parsing/ProgramParser.java +++ b/teavm-core/src/main/java/org/teavm/parsing/ProgramParser.java @@ -1733,31 +1733,31 @@ public class ProgramParser implements VariableDebugInformation { static MethodHandle parseHandle(Handle handle) { switch (handle.getTag()) { case Opcodes.H_GETFIELD: - return MethodHandle.fieldGetter(handle.getOwner(), handle.getName(), + return MethodHandle.fieldGetter(handle.getOwner().replace('/', '.'), handle.getName(), ValueType.parse(handle.getDesc())); case Opcodes.H_GETSTATIC: - return MethodHandle.staticFieldGetter(handle.getOwner(), handle.getName(), + return MethodHandle.staticFieldGetter(handle.getOwner().replace('/', '.'), handle.getName(), ValueType.parse(handle.getDesc())); case Opcodes.H_PUTFIELD: - return MethodHandle.fieldSetter(handle.getOwner(), handle.getName(), + return MethodHandle.fieldSetter(handle.getOwner().replace('/', '.'), handle.getName(), ValueType.parse(handle.getDesc())); case Opcodes.H_PUTSTATIC: - return MethodHandle.staticFieldSetter(handle.getOwner(), handle.getName(), + return MethodHandle.staticFieldSetter(handle.getOwner().replace('/', '.'), handle.getName(), ValueType.parse(handle.getDesc())); case Opcodes.H_INVOKEVIRTUAL: - return MethodHandle.virtualCaller(handle.getOwner(), handle.getName(), + return MethodHandle.virtualCaller(handle.getOwner().replace('/', '.'), handle.getName(), MethodDescriptor.parseSignature(handle.getDesc())); case Opcodes.H_INVOKESTATIC: - return MethodHandle.staticCaller(handle.getOwner(), handle.getName(), + return MethodHandle.staticCaller(handle.getOwner().replace('/', '.'), handle.getName(), MethodDescriptor.parseSignature(handle.getDesc())); case Opcodes.H_INVOKESPECIAL: - return MethodHandle.specialCaller(handle.getOwner(), handle.getName(), + return MethodHandle.specialCaller(handle.getOwner().replace('/', '.'), handle.getName(), MethodDescriptor.parseSignature(handle.getDesc())); case Opcodes.H_NEWINVOKESPECIAL: - return MethodHandle.constructorCaller(handle.getOwner(), handle.getName(), + return MethodHandle.constructorCaller(handle.getOwner().replace('/', '.'), handle.getName(), MethodDescriptor.parseSignature(handle.getDesc())); case Opcodes.H_INVOKEINTERFACE: - return MethodHandle.interfaceCaller(handle.getOwner(), handle.getName(), + return MethodHandle.interfaceCaller(handle.getOwner().replace('/', '.'), handle.getName(), MethodDescriptor.parseSignature(handle.getDesc())); default: throw new IllegalArgumentException("Unknown handle tag: " + handle.getTag()); diff --git a/teavm-core/src/main/java/org/teavm/vm/TeaVM.java b/teavm-core/src/main/java/org/teavm/vm/TeaVM.java index e60a8378f..1892901eb 100644 --- a/teavm-core/src/main/java/org/teavm/vm/TeaVM.java +++ b/teavm-core/src/main/java/org/teavm/vm/TeaVM.java @@ -127,6 +127,11 @@ public class TeaVM implements TeaVMHost, ServiceRepository { methodInjectors.put(methodRef, injector); } + @Override + public void add(MethodReference methodRef, BootstrapMethodSubstitutor substitutor) { + dependencyChecker.addBootstrapMethodSubstitutor(methodRef, substitutor); + } + @Override public void add(RendererListener listener) { rendererListeners.add(listener); diff --git a/teavm-core/src/main/java/org/teavm/vm/spi/TeaVMHost.java b/teavm-core/src/main/java/org/teavm/vm/spi/TeaVMHost.java index d76709353..e4877202e 100644 --- a/teavm-core/src/main/java/org/teavm/vm/spi/TeaVMHost.java +++ b/teavm-core/src/main/java/org/teavm/vm/spi/TeaVMHost.java @@ -16,6 +16,7 @@ package org.teavm.vm.spi; import java.util.Properties; +import org.teavm.dependency.BootstrapMethodSubstitutor; import org.teavm.dependency.DependencyListener; import org.teavm.javascript.spi.Generator; import org.teavm.javascript.spi.Injector; @@ -39,6 +40,8 @@ public interface TeaVMHost { void add(MethodReference methodRef, Injector injector); + void add(MethodReference methodRef, BootstrapMethodSubstitutor substitutor); + void add(RendererListener listener); void registerService(Class type, T instance); From c67f493187aaa89cf7014973c90a7bb6c0622f01 Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Sun, 26 Jul 2015 23:11:14 +0300 Subject: [PATCH 4/5] Remove retrolambda --- teavm-html4j/pom.xml | 14 -------------- teavm-jso/pom.xml | 14 -------------- teavm-samples/teavm-samples-async/pom.xml | 14 -------------- teavm-samples/teavm-samples-hello/pom.xml | 14 -------------- .../java/org/teavm/samples/hello/Client.java | 17 ++++------------- teavm-samples/teavm-samples-storage/pom.xml | 14 -------------- teavm-samples/teavm-samples-video/pom.xml | 14 -------------- 7 files changed, 4 insertions(+), 97 deletions(-) diff --git a/teavm-html4j/pom.xml b/teavm-html4j/pom.xml index 0941950de..bffacb498 100644 --- a/teavm-html4j/pom.xml +++ b/teavm-html4j/pom.xml @@ -66,20 +66,6 @@ - - net.orfjackal.retrolambda - retrolambda-maven-plugin - 1.8.1 - - - retrolambda - process-classes - - process-main - - - - org.teavm teavm-maven-plugin diff --git a/teavm-jso/pom.xml b/teavm-jso/pom.xml index 26b0cdb7f..aaffeb282 100644 --- a/teavm-jso/pom.xml +++ b/teavm-jso/pom.xml @@ -43,20 +43,6 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xs - - net.orfjackal.retrolambda - retrolambda-maven-plugin - 1.8.1 - - - retrolambda - process-classes - - process-main - - - - org.apache.maven.plugins maven-checkstyle-plugin diff --git a/teavm-samples/teavm-samples-async/pom.xml b/teavm-samples/teavm-samples-async/pom.xml index 36f0db545..001e04006 100644 --- a/teavm-samples/teavm-samples-async/pom.xml +++ b/teavm-samples/teavm-samples-async/pom.xml @@ -39,20 +39,6 @@ - - net.orfjackal.retrolambda - retrolambda-maven-plugin - 1.8.1 - - - retrolambda - process-classes - - process-main - - - - maven-war-plugin 2.4 diff --git a/teavm-samples/teavm-samples-hello/pom.xml b/teavm-samples/teavm-samples-hello/pom.xml index a5a198335..ed8128e63 100644 --- a/teavm-samples/teavm-samples-hello/pom.xml +++ b/teavm-samples/teavm-samples-hello/pom.xml @@ -58,20 +58,6 @@ - - net.orfjackal.retrolambda - retrolambda-maven-plugin - 1.8.1 - - - retrolambda - process-classes - - process-main - - - - maven-war-plugin 2.4 diff --git a/teavm-samples/teavm-samples-hello/src/main/java/org/teavm/samples/hello/Client.java b/teavm-samples/teavm-samples-hello/src/main/java/org/teavm/samples/hello/Client.java index 4d8368ccb..e4c85b7b6 100644 --- a/teavm-samples/teavm-samples-hello/src/main/java/org/teavm/samples/hello/Client.java +++ b/teavm-samples/teavm-samples-hello/src/main/java/org/teavm/samples/hello/Client.java @@ -15,11 +15,8 @@ */ package org.teavm.samples.hello; -import org.teavm.dom.ajax.ReadyStateChangeHandler; import org.teavm.dom.ajax.XMLHttpRequest; import org.teavm.dom.browser.Window; -import org.teavm.dom.events.EventListener; -import org.teavm.dom.events.MouseEvent; import org.teavm.dom.html.HTMLButtonElement; import org.teavm.dom.html.HTMLDocument; import org.teavm.dom.html.HTMLElement; @@ -36,22 +33,16 @@ public final class Client { } public static void main(String[] args) { - helloButton.addEventListener("click", new EventListener() { - @Override public void handleEvent(MouseEvent evt) { - sayHello(); - } - }); + helloButton.addEventListener("click", evt -> sayHello()); } private static void sayHello() { helloButton.setDisabled(true); thinkingPanel.getStyle().setProperty("display", ""); final XMLHttpRequest xhr = window.createXMLHttpRequest(); - xhr.setOnReadyStateChange(new ReadyStateChangeHandler() { - @Override public void stateChanged() { - if (xhr.getReadyState() == XMLHttpRequest.DONE) { - receiveResponse(xhr.getResponseText()); - } + xhr.setOnReadyStateChange(() -> { + if (xhr.getReadyState() == XMLHttpRequest.DONE) { + receiveResponse(xhr.getResponseText()); } }); xhr.open("GET", "hello"); diff --git a/teavm-samples/teavm-samples-storage/pom.xml b/teavm-samples/teavm-samples-storage/pom.xml index 5115be250..70d0cc0bc 100644 --- a/teavm-samples/teavm-samples-storage/pom.xml +++ b/teavm-samples/teavm-samples-storage/pom.xml @@ -58,20 +58,6 @@ - - net.orfjackal.retrolambda - retrolambda-maven-plugin - 1.8.1 - - - retrolambda - process-classes - - process-main - - - - maven-war-plugin 2.4 diff --git a/teavm-samples/teavm-samples-video/pom.xml b/teavm-samples/teavm-samples-video/pom.xml index b512c2bfb..1f64bc021 100644 --- a/teavm-samples/teavm-samples-video/pom.xml +++ b/teavm-samples/teavm-samples-video/pom.xml @@ -58,20 +58,6 @@ - - net.orfjackal.retrolambda - retrolambda-maven-plugin - 1.8.1 - - - retrolambda - process-classes - - process-main - - - - maven-war-plugin 2.4 From 5aa526bc348d3a99facb44e2e2d9ac2af74b47f0 Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Sun, 26 Jul 2015 23:14:08 +0300 Subject: [PATCH 5/5] Remove unnecessary plugin executions --- teavm-maven/teavm-maven-plugin/pom.xml | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/teavm-maven/teavm-maven-plugin/pom.xml b/teavm-maven/teavm-maven-plugin/pom.xml index 019d13541..143dd1213 100644 --- a/teavm-maven/teavm-maven-plugin/pom.xml +++ b/teavm-maven/teavm-maven-plugin/pom.xml @@ -81,19 +81,6 @@ process-classes - - help-descriptor - - helpmojo - - process-classes - - - mojo-descriptor - - descriptor - -