diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/CharacterNativeGenerator.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/CharacterNativeGenerator.java index 470eabf6e..614fb1d6b 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/CharacterNativeGenerator.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/CharacterNativeGenerator.java @@ -72,6 +72,6 @@ public class CharacterNativeGenerator implements Generator, DependencyPlugin { } private void achieveObtainDigitMapping(DependencyChecker checker, MethodReference method) { - checker.attachMethodGraph(method).getResultNode().propagate("java.lang.String"); + checker.attachMethodGraph(method).getResult().propagate("java.lang.String"); } } diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/ObjectNativeGenerator.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/ObjectNativeGenerator.java index cb112e5e1..1b2c9a466 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/ObjectNativeGenerator.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/ObjectNativeGenerator.java @@ -91,7 +91,7 @@ public class ObjectNativeGenerator implements Generator, Injector, DependencyPlu MethodReference initMethod = new MethodReference(classClass, new MethodDescriptor("createNew", ValueType.object(classClass))); checker.addEntryPoint(initMethod); - checker.attachMethodGraph(method).getResultNode().propagate("java.lang.Class"); + checker.attachMethodGraph(method).getResult().propagate("java.lang.Class"); } private void generateHashCode(GeneratorContext context, SourceWriter writer) throws IOException { @@ -109,7 +109,7 @@ public class ObjectNativeGenerator implements Generator, Injector, DependencyPlu private void achieveClone(DependencyChecker checker, MethodReference method) { MethodGraph graph = checker.attachMethodGraph(method); - graph.getVariableNode(0).connect(graph.getResultNode()); + graph.getVariable(0).connect(graph.getResult()); } private void generateWrap(InjectorContext context) throws IOException { @@ -118,6 +118,6 @@ public class ObjectNativeGenerator implements Generator, Injector, DependencyPlu private void achieveWrap(DependencyChecker checker, MethodReference method) { MethodGraph graph = checker.attachMethodGraph(method); - graph.getVariableNode(1).connect(graph.getResultNode()); + graph.getVariable(1).connect(graph.getResult()); } } diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/SystemNativeGenerator.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/SystemNativeGenerator.java index 9a4401d8c..65330d66a 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/SystemNativeGenerator.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/SystemNativeGenerator.java @@ -68,8 +68,8 @@ public class SystemNativeGenerator implements Generator, DependencyPlugin { private void achieveArrayCopy(DependencyChecker checker, MethodReference method) { MethodGraph graph = checker.attachMethodGraph(method); - DependencyNode src = graph.getVariableNode(1); - DependencyNode dest = graph.getVariableNode(3); - src.getArrayItemNode().connect(dest.getArrayItemNode()); + DependencyNode src = graph.getVariable(1); + DependencyNode dest = graph.getVariable(3); + src.getArrayItem().connect(dest.getArrayItem()); } } diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/reflect/ArrayNativeGenerator.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/reflect/ArrayNativeGenerator.java index bade26509..0f3e54a8d 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/reflect/ArrayNativeGenerator.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/reflect/ArrayNativeGenerator.java @@ -61,7 +61,7 @@ public class ArrayNativeGenerator implements Generator, DependencyPlugin { private void achieveGetLength(final DependencyChecker checker, MethodReference methodRef) { final MethodGraph graph = checker.attachMethodGraph(methodRef); - graph.getVariableNode(1).addConsumer(new DependencyConsumer() { + graph.getVariable(1).addConsumer(new DependencyConsumer() { @Override public void consume(String type) { if (!type.startsWith("[")) { MethodReference cons = new MethodReference("java.lang.IllegalArgumentException", diff --git a/teavm-core/src/main/java/org/teavm/codegen/DefaultNamingStrategy.java b/teavm-core/src/main/java/org/teavm/codegen/DefaultNamingStrategy.java index 93383ab79..225eeea3d 100644 --- a/teavm-core/src/main/java/org/teavm/codegen/DefaultNamingStrategy.java +++ b/teavm-core/src/main/java/org/teavm/codegen/DefaultNamingStrategy.java @@ -61,7 +61,7 @@ public class DefaultNamingStrategy implements NamingStrategy { if (method == null) { throw new NamingException("Can't provide name for method as it was not found: " + method); } - ClassHolder clsHolder = classSource.getClassHolder(method.getClassName()); + ClassHolder clsHolder = classSource.get(method.getClassName()); MethodHolder methodHolder = clsHolder.getMethod(method.getDescriptor()); if (methodHolder.getModifiers().contains(ElementModifier.STATIC) || method.getDescriptor().getName().equals("") || @@ -123,7 +123,7 @@ public class DefaultNamingStrategy implements NamingStrategy { private MethodReference getRealMethod(MethodReference methodRef) { String className = methodRef.getClassName(); while (className != null) { - ClassHolder cls = classSource.getClassHolder(className); + ClassHolder cls = classSource.get(className); if (cls == null) { return null; } @@ -142,7 +142,7 @@ public class DefaultNamingStrategy implements NamingStrategy { private String getRealFieldOwner(String cls, String field) { String initialCls = cls; while (!fieldExists(cls, field)) { - ClassHolder clsHolder = classSource.getClassHolder(cls); + ClassHolder clsHolder = classSource.get(cls); cls = clsHolder.getParent(); if (cls == null) { throw new NamingException("Can't provide name for field as the field not found: " + @@ -153,7 +153,7 @@ public class DefaultNamingStrategy implements NamingStrategy { } private boolean fieldExists(String cls, String field) { - ClassHolder classHolder = classSource.getClassHolder(cls); + ClassHolder classHolder = classSource.get(cls); return classHolder.getField(field) != null; } } diff --git a/teavm-core/src/main/java/org/teavm/common/ConcurrentCachedMapper.java b/teavm-core/src/main/java/org/teavm/common/ConcurrentCachedMapper.java index ecf1a475f..9ba058e3b 100644 --- a/teavm-core/src/main/java/org/teavm/common/ConcurrentCachedMapper.java +++ b/teavm-core/src/main/java/org/teavm/common/ConcurrentCachedMapper.java @@ -26,6 +26,11 @@ public class ConcurrentCachedMapper implements Mapper { this.innerMapper = innerMapper; } + public R getKnown(T preimage) { + Wrapper wrapper = cache.get(preimage); + return wrapper != null ? wrapper.value : null; + } + @Override public R map(T preimage) { Wrapper wrapper = cache.get(preimage); 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 b8a2c6ad2..fa1024b3c 100644 --- a/teavm-core/src/main/java/org/teavm/dependency/DependencyChecker.java +++ b/teavm-core/src/main/java/org/teavm/dependency/DependencyChecker.java @@ -27,7 +27,7 @@ import org.teavm.model.*; * * @author Alexey Andreev */ -public class DependencyChecker { +public class DependencyChecker implements DependencyInformation { private static Object dummyValue = new Object(); static final boolean shouldLog = System.getProperty("org.teavm.logDependencies", "false").equals("true"); private ClassHolderSource classSource; @@ -78,7 +78,7 @@ public class DependencyChecker { throw new IllegalArgumentException("argumentTypes length does not match the number of method's arguments"); } MethodGraph graph = attachMethodGraph(methodRef); - DependencyNode[] varNodes = graph.getVariableNodes(); + DependencyNode[] varNodes = graph.getVariables(); varNodes[0].propagate(methodRef.getClassName()); for (int i = 0; i < argumentTypes.length; ++i) { varNodes[i + 1].propagate(argumentTypes[i]); @@ -113,7 +113,7 @@ public class DependencyChecker { } achieveClass(className); achieveInterfaces(className); - ClassHolder cls = classSource.getClassHolder(className); + ClassHolder cls = classSource.get(className); if (cls == null) { throw new RuntimeException("Class not found: " + className); } @@ -125,7 +125,7 @@ public class DependencyChecker { } private void achieveInterfaces(String className) { - ClassHolder cls = classSource.getClassHolder(className); + ClassHolder cls = classSource.get(className); if (cls == null) { throw new RuntimeException("Class not found: " + className); } @@ -138,7 +138,7 @@ public class DependencyChecker { private MethodGraph createMethodGraph(final MethodReference methodRef) { initClass(methodRef.getClassName()); - ClassHolder cls = classSource.getClassHolder(methodRef.getClassName()); + ClassHolder cls = classSource.get(methodRef.getClassName()); MethodHolder method = cls.getMethod(methodRef.getDescriptor()); if (method == null) { while (cls != null) { @@ -146,7 +146,7 @@ public class DependencyChecker { if (method != null) { return methodCache.map(new MethodReference(cls.getName(), methodRef.getDescriptor())); } - cls = cls.getParent() != null ? classSource.getClassHolder(cls.getParent()) : null; + cls = cls.getParent() != null ? classSource.get(cls.getParent()) : null; } throw new RuntimeException("Method not found: " + methodRef); } @@ -169,7 +169,7 @@ public class DependencyChecker { resultNode.setTag(method.getOwnerName() + "#" + method.getDescriptor() + ":RESULT"); } } - final MethodGraph graph = new MethodGraph(parameterNodes, paramCount, resultNode, this); + final MethodGraph graph = new MethodGraph(parameterNodes, paramCount, resultNode); final MethodHolder currentMethod = method; executor.execute(new Runnable() { @Override public void run() { @@ -188,25 +188,29 @@ public class DependencyChecker { return abstractMethods.containsKey(methodRef); } + @Override public Collection getAchievableMethods() { return methodCache.getCachedPreimages(); } + @Override public Collection getAchievableFields() { return fieldCache.getCachedPreimages(); } + @Override public Collection getAchievableClasses() { return new HashSet<>(achievableClasses.keySet()); } - public DependencyNode getFieldNode(FieldReference fieldRef) { + @Override + public DependencyNode getField(FieldReference fieldRef) { return fieldCache.map(fieldRef); } private DependencyNode createFieldNode(FieldReference fieldRef) { initClass(fieldRef.getClassName()); - ClassHolder cls = classSource.getClassHolder(fieldRef.getClassName()); + ClassHolder cls = classSource.get(fieldRef.getClassName()); if (cls == null) { throw new RuntimeException("Class not found: " + fieldRef.getClassName()); } @@ -217,7 +221,7 @@ public class DependencyChecker { if (field != null) { return fieldCache.map(new FieldReference(cls.getName(), fieldRef.getFieldName())); } - cls = cls.getParent() != null ? classSource.getClassHolder(cls.getParent()) : null; + cls = cls.getParent() != null ? classSource.get(cls.getParent()) : null; } throw new RuntimeException("Field not found: " + fieldRef); } @@ -229,7 +233,7 @@ public class DependencyChecker { } private void activateDependencyPlugin(MethodReference methodRef) { - ClassHolder cls = classSource.getClassHolder(methodRef.getClassName()); + ClassHolder cls = classSource.get(methodRef.getClassName()); MethodHolder method = cls.getMethod(methodRef.getDescriptor()); if (method == null) { return; @@ -259,7 +263,7 @@ public class DependencyChecker { if (abstractMethods.putIfAbsent(methodRef, methodRef) == null) { String className = methodRef.getClassName(); while (className != null) { - ClassHolder cls = classSource.getClassHolder(className); + ClassHolder cls = classSource.get(className); if (cls == null) { return; } @@ -276,7 +280,7 @@ public class DependencyChecker { public ListableClassHolderSource cutUnachievableClasses() { MutableClassHolderSource cutClasses = new MutableClassHolderSource(); for (String className : achievableClasses.keySet()) { - ClassHolder classHolder = classSource.getClassHolder(className); + ClassHolder classHolder = classSource.get(className); cutClasses.putClassHolder(classHolder); for (MethodHolder method : classHolder.getMethods().toArray(new MethodHolder[0])) { MethodReference methodRef = new MethodReference(className, method.getDescriptor()); @@ -298,4 +302,9 @@ public class DependencyChecker { } return cutClasses; } + + @Override + public DependencyMethodInformation getMethod(MethodReference methodRef) { + return methodCache.getKnown(methodRef); + } } 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 cf0cd4938..734a66835 100644 --- a/teavm-core/src/main/java/org/teavm/dependency/DependencyGraphBuilder.java +++ b/teavm-core/src/main/java/org/teavm/dependency/DependencyGraphBuilder.java @@ -38,8 +38,8 @@ class DependencyGraphBuilder { return; } program = method.getProgram(); - resultNode = graph.getResultNode(); - nodes = graph.getVariableNodes(); + resultNode = graph.getResult(); + nodes = graph.getVariables(); for (int i = 0; i < program.basicBlockCount(); ++i) { BasicBlock block = program.basicBlockAt(i); for (Instruction insn : block.getInstructions()) { @@ -87,12 +87,12 @@ class DependencyGraphBuilder { if (targetGraph == null) { throw new RuntimeException("Method not found: " + methodRef); } - DependencyNode[] targetParams = targetGraph.getVariableNodes(); + DependencyNode[] targetParams = targetGraph.getVariables(); for (int i = 0; i < parameters.length; ++i) { parameters[i].connect(targetParams[i]); } - if (targetGraph.getResultNode() != null) { - targetGraph.getResultNode().connect(result); + if (targetGraph.getResult() != null) { + targetGraph.getResult().connect(result); } } } @@ -100,7 +100,7 @@ class DependencyGraphBuilder { private static MethodHolder findMethod(MethodReference methodRef, ClassHolderSource classSource) { String className = methodRef.getClassName(); while (className != null) { - ClassHolder cls = classSource.getClassHolder(className); + ClassHolder cls = classSource.get(className); if (cls == null) { break; } @@ -136,7 +136,7 @@ class DependencyGraphBuilder { private void invokeSpecial(InvokeInstruction insn) { MethodGraph targetGraph = dependencyChecker.attachMethodGraph(insn.getMethod()); - DependencyNode[] targetParams = targetGraph.getVariableNodes(); + DependencyNode[] targetParams = targetGraph.getVariables(); List arguments = insn.getArguments(); for (int i = 0; i < arguments.size(); ++i) { nodes[arguments.get(i).getIndex()].connect(targetParams[i + 1]); @@ -144,8 +144,8 @@ class DependencyGraphBuilder { if (insn.getInstance() != null) { nodes[insn.getInstance().getIndex()].connect(targetParams[0]); } - if (targetGraph.getResultNode() != null && insn.getReceiver() != null) { - targetGraph.getResultNode().connect(nodes[insn.getReceiver().getIndex()]); + if (targetGraph.getResult() != null && insn.getReceiver() != null) { + targetGraph.getResult().connect(nodes[insn.getReceiver().getIndex()]); } } @@ -167,14 +167,14 @@ class DependencyGraphBuilder { public void visit(PutElementInstruction insn) { DependencyNode valueNode = nodes[insn.getValue().getIndex()]; DependencyNode arrayNode = nodes[insn.getArray().getIndex()]; - valueNode.connect(arrayNode.getArrayItemNode()); + valueNode.connect(arrayNode.getArrayItem()); } @Override public void visit(GetElementInstruction insn) { DependencyNode arrayNode = nodes[insn.getArray().getIndex()]; DependencyNode receiverNode = nodes[insn.getReceiver().getIndex()]; - arrayNode.getArrayItemNode().connect(receiverNode); + arrayNode.getArrayItem().connect(receiverNode); } @Override @@ -194,7 +194,7 @@ class DependencyGraphBuilder { } }); - arrayNode.getArrayItemNode().connect(receiverNode.getArrayItemNode()); + arrayNode.getArrayItem().connect(receiverNode.getArrayItem()); } @Override @@ -203,14 +203,14 @@ class DependencyGraphBuilder { @Override public void visit(PutFieldInstruction insn) { - DependencyNode fieldNode = dependencyChecker.getFieldNode(insn.getField()); + DependencyNode fieldNode = dependencyChecker.getField(insn.getField()); DependencyNode valueNode = nodes[insn.getValue().getIndex()]; valueNode.connect(fieldNode); } @Override public void visit(GetFieldInstruction insn) { - DependencyNode fieldNode = dependencyChecker.getFieldNode(insn.getField()); + DependencyNode fieldNode = dependencyChecker.getField(insn.getField()); DependencyNode receiverNode = nodes[insn.getReceiver().getIndex()]; fieldNode.connect(receiverNode); } diff --git a/teavm-core/src/main/java/org/teavm/dependency/DependencyInformation.java b/teavm-core/src/main/java/org/teavm/dependency/DependencyInformation.java new file mode 100644 index 000000000..e5676a80a --- /dev/null +++ b/teavm-core/src/main/java/org/teavm/dependency/DependencyInformation.java @@ -0,0 +1,36 @@ +/* + * Copyright 2014 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.Collection; +import org.teavm.model.FieldReference; +import org.teavm.model.MethodReference; + +/** + * + * @author Alexey Andreev + */ +public interface DependencyInformation { + Collection getAchievableMethods(); + + Collection getAchievableFields(); + + Collection getAchievableClasses(); + + DependencyValueInformation getField(FieldReference fieldRef); + + DependencyMethodInformation getMethod(MethodReference methodRef); +} diff --git a/teavm-core/src/main/java/org/teavm/dependency/DependencyMethodInformation.java b/teavm-core/src/main/java/org/teavm/dependency/DependencyMethodInformation.java new file mode 100644 index 000000000..a9a455d2f --- /dev/null +++ b/teavm-core/src/main/java/org/teavm/dependency/DependencyMethodInformation.java @@ -0,0 +1,32 @@ +/* + * Copyright 2014 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; + +/** + * + * @author Alexey Andreev + */ +public interface DependencyMethodInformation { + DependencyValueInformation[] getVariables(); + + int getVariableCount(); + + DependencyValueInformation getVariable(int index); + + int getParameterCount(); + + DependencyNode getResult(); +} diff --git a/teavm-core/src/main/java/org/teavm/dependency/DependencyNode.java b/teavm-core/src/main/java/org/teavm/dependency/DependencyNode.java index d6dae6cf0..5aa734dc4 100644 --- a/teavm-core/src/main/java/org/teavm/dependency/DependencyNode.java +++ b/teavm-core/src/main/java/org/teavm/dependency/DependencyNode.java @@ -24,7 +24,7 @@ import java.util.concurrent.atomic.AtomicReference; * * @author Alexey Andreev */ -public class DependencyNode { +public class DependencyNode implements DependencyValueInformation { private DependencyChecker dependencyChecker; private static final Object mapValue = new Object(); private ConcurrentMap followers = new ConcurrentHashMap<>(); @@ -68,7 +68,8 @@ public class DependencyNode { connect(node, null); } - public DependencyNode getArrayItemNode() { + @Override + public DependencyNode getArrayItem() { DependencyNode result = arrayItemNode.get(); if (result == null) { result = new DependencyNode(dependencyChecker); @@ -91,14 +92,17 @@ public class DependencyNode { return result; } + @Override public boolean hasArrayType() { return arrayItemNode.get() != null && !arrayItemNode.get().types.isEmpty(); } + @Override public boolean hasType(String type) { return types.containsKey(type); } + @Override public String[] getTypes() { return types != null ? types.keySet().toArray(new String[types.size()]) : new String[0]; } diff --git a/teavm-core/src/main/java/org/teavm/dependency/DependencyNodeToNodeTransition.java b/teavm-core/src/main/java/org/teavm/dependency/DependencyNodeToNodeTransition.java index 84550d230..07b24320e 100644 --- a/teavm-core/src/main/java/org/teavm/dependency/DependencyNodeToNodeTransition.java +++ b/teavm-core/src/main/java/org/teavm/dependency/DependencyNodeToNodeTransition.java @@ -39,8 +39,8 @@ class DependencyNodeToNodeTransition implements DependencyConsumer { if (!destination.hasType(type)) { destination.propagate(type); if (type.startsWith("[")) { - source.getArrayItemNode().connect(destination.getArrayItemNode()); - destination.getArrayItemNode().connect(destination.getArrayItemNode()); + source.getArrayItem().connect(destination.getArrayItem()); + destination.getArrayItem().connect(destination.getArrayItem()); } } } diff --git a/teavm-core/src/main/java/org/teavm/dependency/DependencyValueInformation.java b/teavm-core/src/main/java/org/teavm/dependency/DependencyValueInformation.java new file mode 100644 index 000000000..b2166aeb5 --- /dev/null +++ b/teavm-core/src/main/java/org/teavm/dependency/DependencyValueInformation.java @@ -0,0 +1,30 @@ +/* + * Copyright 2014 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; + +/** + * + * @author Alexey Andreev + */ +public interface DependencyValueInformation { + String[] getTypes(); + + boolean hasType(String type); + + boolean hasArrayType(); + + DependencyNode getArrayItem(); +} diff --git a/teavm-core/src/main/java/org/teavm/dependency/MethodGraph.java b/teavm-core/src/main/java/org/teavm/dependency/MethodGraph.java index 020a4432f..344e91d6c 100644 --- a/teavm-core/src/main/java/org/teavm/dependency/MethodGraph.java +++ b/teavm-core/src/main/java/org/teavm/dependency/MethodGraph.java @@ -21,41 +21,39 @@ import java.util.Arrays; * * @author Alexey Andreev */ -public class MethodGraph { +public class MethodGraph implements DependencyMethodInformation { private DependencyNode[] variableNodes; private int parameterCount; private DependencyNode resultNode; - private DependencyNode sideEffectNode; - MethodGraph(DependencyNode[] variableNodes, int parameterCount, DependencyNode resultNode, - DependencyChecker checker) { + MethodGraph(DependencyNode[] variableNodes, int parameterCount, DependencyNode resultNode) { this.variableNodes = Arrays.copyOf(variableNodes, variableNodes.length); this.parameterCount = parameterCount; this.resultNode = resultNode; - this.sideEffectNode = checker.createNode(); } - public DependencyNode[] getVariableNodes() { + @Override + public DependencyNode[] getVariables() { return Arrays.copyOf(variableNodes, variableNodes.length); } - public int getVariableNodesCount() { + @Override + public int getVariableCount() { return variableNodes.length; } - public DependencyNode getVariableNode(int index) { + @Override + public DependencyNode getVariable(int index) { return variableNodes[index]; } + @Override public int getParameterCount() { return parameterCount; } - public DependencyNode getResultNode() { + @Override + public DependencyNode getResult() { return resultNode; } - - public DependencyNode getSideEffectNode() { - return sideEffectNode; - } } diff --git a/teavm-core/src/main/java/org/teavm/javascript/Decompiler.java b/teavm-core/src/main/java/org/teavm/javascript/Decompiler.java index 63cec5cb2..53392d15d 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/Decompiler.java +++ b/teavm-core/src/main/java/org/teavm/javascript/Decompiler.java @@ -82,7 +82,7 @@ public class Decompiler { executor.execute(new Runnable() { @Override public void run() { Decompiler copy = new Decompiler(classSource, classLoader, executor); - result.set(index, copy.decompile(classSource.getClassHolder(className))); + result.set(index, copy.decompile(classSource.get(className))); } }); } @@ -94,7 +94,7 @@ public class Decompiler { if (!visited.add(className)) { return; } - ClassHolder cls = classSource.getClassHolder(className); + ClassHolder cls = classSource.get(className); if (cls == null) { throw new IllegalArgumentException("Class not found: " + className); } diff --git a/teavm-core/src/main/java/org/teavm/javascript/JavascriptBuilder.java b/teavm-core/src/main/java/org/teavm/javascript/JavascriptBuilder.java index 93ab5f182..478e81d26 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/JavascriptBuilder.java +++ b/teavm-core/src/main/java/org/teavm/javascript/JavascriptBuilder.java @@ -23,10 +23,12 @@ import java.util.Set; import org.teavm.codegen.*; import org.teavm.common.FiniteExecutor; import org.teavm.dependency.DependencyChecker; +import org.teavm.dependency.DependencyInformation; import org.teavm.javascript.ast.ClassNode; import org.teavm.model.*; import org.teavm.model.util.*; import org.teavm.optimization.ClassSetOptimizer; +import org.teavm.optimization.Devirtualization; /** * @@ -103,7 +105,8 @@ public class JavascriptBuilder { executor.complete(); ListableClassHolderSource classSet = dependencyChecker.cutUnachievableClasses(); Decompiler decompiler = new Decompiler(classSet, classLoader, executor); - Renderer renderer = new Renderer(sourceWriter, classSet, classLoader); + devirtualize(classSet, dependencyChecker); + executor.complete(); ClassSetOptimizer optimizer = new ClassSetOptimizer(executor); optimizer.optimizeAll(classSet); executor.complete(); @@ -116,6 +119,7 @@ public class JavascriptBuilder { // Just don't do anything } } + Renderer renderer = new Renderer(sourceWriter, classSet, classLoader); renderer.renderRuntime(); List clsNodes = decompiler.decompile(classSet.getClassNames()); for (ClassNode clsNode : clsNodes) { @@ -135,9 +139,23 @@ public class JavascriptBuilder { } } + private void devirtualize(ListableClassHolderSource classes, DependencyInformation dependency) { + final Devirtualization devirtualization = new Devirtualization(dependency, classes); + for (String className : classes.getClassNames()) { + ClassHolder cls = classes.get(className); + for (final MethodHolder method : cls.getMethods()) { + executor.execute(new Runnable() { + @Override public void run() { + devirtualization.apply(method); + } + }); + } + } + } + private void allocateRegisters(ListableClassHolderSource classes) { for (String className : classes.getClassNames()) { - ClassHolder cls = classes.getClassHolder(className); + ClassHolder cls = classes.get(className); for (final MethodHolder method : cls.getMethods()) { if (method.getProgram() != null && method.getProgram().basicBlockCount() > 0) { executor.execute(new Runnable() { @@ -155,7 +173,7 @@ public class JavascriptBuilder { private void logBytecode(PrintWriter writer, ListableClassHolderSource classes) { for (String className : classes.getClassNames()) { - ClassHolder classHolder = classes.getClassHolder(className); + ClassHolder classHolder = classes.get(className); printModifiers(writer, classHolder); writer.println("class " + className); for (MethodHolder method : classHolder.getMethods()) { diff --git a/teavm-core/src/main/java/org/teavm/javascript/JavascriptEntryPoint.java b/teavm-core/src/main/java/org/teavm/javascript/JavascriptEntryPoint.java index 5f7f0f7a9..f97ffd858 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/JavascriptEntryPoint.java +++ b/teavm-core/src/main/java/org/teavm/javascript/JavascriptEntryPoint.java @@ -41,7 +41,7 @@ public class JavascriptEntryPoint { if (argument > reference.parameterCount()) { throw new IllegalArgumentException("Illegal argument #" + argument + " of " + reference.parameterCount()); } - graph.getVariableNode(argument).propagate(type); + graph.getVariable(argument).propagate(type); return this; } } diff --git a/teavm-core/src/main/java/org/teavm/javascript/JavascriptNativeProcessor.java b/teavm-core/src/main/java/org/teavm/javascript/JavascriptNativeProcessor.java index b4b49d7fc..55729c4be 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/JavascriptNativeProcessor.java +++ b/teavm-core/src/main/java/org/teavm/javascript/JavascriptNativeProcessor.java @@ -51,7 +51,7 @@ class JavascriptNativeProcessor { } private void addPreservedMethods(String ifaceName, Set methods) { - ClassHolder iface = classSource.getClassHolder(ifaceName); + ClassHolder iface = classSource.get(ifaceName); for (MethodHolder method : iface.getMethods()) { methods.add(method.getDescriptor()); } @@ -268,7 +268,7 @@ class JavascriptNativeProcessor { private Variable wrapArgument(Variable var, ValueType type) { if (type instanceof ValueType.Object) { String className = ((ValueType.Object)type).getClassName(); - ClassHolder cls = classSource.getClassHolder(className); + ClassHolder cls = classSource.get(className); if (cls.getAnnotations().get(JSFunctor.class.getName()) != null) { return wrapFunctor(var, cls); } @@ -313,7 +313,7 @@ class JavascriptNativeProcessor { } private MethodHolder getMethod(MethodReference ref) { - ClassHolder cls = classSource.getClassHolder(ref.getClassName()); + ClassHolder cls = classSource.get(ref.getClassName()); MethodHolder method = cls.getMethod(ref.getDescriptor()); if (method != null) { return method; diff --git a/teavm-core/src/main/java/org/teavm/javascript/JavascriptProcessedClassSource.java b/teavm-core/src/main/java/org/teavm/javascript/JavascriptProcessedClassSource.java index 60749f5c4..9c6bb6e8d 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/JavascriptProcessedClassSource.java +++ b/teavm-core/src/main/java/org/teavm/javascript/JavascriptProcessedClassSource.java @@ -32,8 +32,8 @@ public class JavascriptProcessedClassSource implements ClassHolderSource { } @Override - public ClassHolder getClassHolder(String name) { - ClassHolder cls = innerSource.getClassHolder(name); + public ClassHolder get(String name) { + ClassHolder cls = innerSource.get(name); if (cls != null) { transformClass(cls); } diff --git a/teavm-core/src/main/java/org/teavm/javascript/NativeJavascriptClassRepository.java b/teavm-core/src/main/java/org/teavm/javascript/NativeJavascriptClassRepository.java index 43e2635c1..e82fcf548 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/NativeJavascriptClassRepository.java +++ b/teavm-core/src/main/java/org/teavm/javascript/NativeJavascriptClassRepository.java @@ -45,7 +45,7 @@ class NativeJavascriptClassRepository { } private boolean figureOutIfJavaScriptClass(String className) { - ClassHolder cls = classSource.getClassHolder(className); + ClassHolder cls = classSource.get(className); if (cls == null || !cls.getModifiers().contains(ElementModifier.INTERFACE)) { return false; } diff --git a/teavm-core/src/main/java/org/teavm/javascript/Renderer.java b/teavm-core/src/main/java/org/teavm/javascript/Renderer.java index 3a8b36cd0..ba49534a5 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/Renderer.java +++ b/teavm-core/src/main/java/org/teavm/javascript/Renderer.java @@ -96,16 +96,16 @@ public class Renderer implements ExprVisitor, StatementVisitor { ValueType.object(classClass))); writer.append("cls").ws().append("=").ws().appendMethodBody(createMethodRef).append("();").softNewLine(); writer.append("cls.$data = clsProto;").softNewLine(); - if (classSource.getClassHolder(classClass).getField("name") != null) { + if (classSource.get(classClass).getField("name") != null) { writer.append("cls.").appendField(new FieldReference(classClass, "name")).ws().append("=").ws() .append("clsProto.$meta.name").ws().append("!==").ws().append("undefined").ws().append("?").ws() .append("$rt_str(clsProto.$meta.name)").ws().append(":").ws().append("null;").softNewLine(); } - if (classSource.getClassHolder(classClass).getField("primitive") != null) { + if (classSource.get(classClass).getField("primitive") != null) { writer.append("cls.").appendField(new FieldReference(classClass, "primitive")) .append(" = clsProto.$meta.primitive ? 1 : 0;").newLine(); } - if (classSource.getClassHolder(classClass).getField("array") != null) { + if (classSource.get(classClass).getField("array") != null) { writer.append("cls.").appendField(new FieldReference(classClass, "array")).ws() .append("=").ws().append("clsProto.$meta.item").ws().append("?").ws() .append("1").ws().append(":").ws().append("0;").softNewLine(); @@ -200,7 +200,7 @@ public class Renderer implements ExprVisitor, StatementVisitor { renderBody(method); stubNames.add(naming.getFullNameFor(method.getReference())); } - MethodHolder methodHolder = classSource.getClassHolder(cls.getName()).getMethod( + MethodHolder methodHolder = classSource.get(cls.getName()).getMethod( new MethodDescriptor("", ValueType.VOID)); if (methodHolder != null) { writer.appendMethodBody(new MethodReference(cls.getName(), methodHolder.getDescriptor())) @@ -1150,7 +1150,7 @@ public class Renderer implements ExprVisitor, StatementVisitor { try { if (expr.getType() instanceof ValueType.Object) { String clsName = ((ValueType.Object)expr.getType()).getClassName(); - ClassHolder cls = classSource.getClassHolder(clsName); + ClassHolder cls = classSource.get(clsName); if (!cls.getModifiers().contains(ElementModifier.INTERFACE)) { writer.append("("); expr.getExpr().acceptVisitor(this); @@ -1178,7 +1178,7 @@ public class Renderer implements ExprVisitor, StatementVisitor { private Injector getInjector(MethodReference ref) { InjectorHolder holder = injectorMap.get(ref); if (holder == null) { - MethodHolder method = classSource.getClassHolder(ref.getClassName()).getMethod(ref.getDescriptor()); + MethodHolder method = classSource.get(ref.getClassName()).getMethod(ref.getDescriptor()); AnnotationHolder injectedByAnnot = method.getAnnotations().get(InjectedBy.class.getName()); if (injectedByAnnot != null) { ValueType type = injectedByAnnot.getValues().get("value").getJavaClass(); 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 316d51d90..49726648e 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/StatementGenerator.java +++ b/teavm-core/src/main/java/org/teavm/javascript/StatementGenerator.java @@ -543,9 +543,9 @@ class StatementGenerator implements InstructionVisitor { } public MethodReference findDeclaringClass(MethodReference method) { - ClassHolder cls = classSource.getClassHolder(method.getClassName()); + ClassHolder cls = classSource.get(method.getClassName()); while (cls != null && cls.getMethod(method.getDescriptor()) == null) { - cls = cls.getParent() != null ? classSource.getClassHolder(cls.getParent()) : null; + cls = cls.getParent() != null ? classSource.get(cls.getParent()) : null; } return cls != null ? new MethodReference(cls.getName(), method.getDescriptor()) : null; } diff --git a/teavm-core/src/main/java/org/teavm/javascript/ni/JSNativeGenerator.java b/teavm-core/src/main/java/org/teavm/javascript/ni/JSNativeGenerator.java index 69a76dc4c..3bf126e99 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/ni/JSNativeGenerator.java +++ b/teavm-core/src/main/java/org/teavm/javascript/ni/JSNativeGenerator.java @@ -100,7 +100,7 @@ public class JSNativeGenerator implements Generator, Injector, DependencyPlugin public void methodAchieved(final DependencyChecker checker, MethodReference method) { MethodGraph graph = checker.attachMethodGraph(method); for (int i = 0; i < method.parameterCount(); ++i) { - graph.getVariableNode(i).addConsumer(new DependencyConsumer() { + graph.getVariable(i).addConsumer(new DependencyConsumer() { @Override public void consume(String type) { achieveFunctorMethods(checker, type); } @@ -109,7 +109,7 @@ public class JSNativeGenerator implements Generator, Injector, DependencyPlugin } private void achieveFunctorMethods(DependencyChecker checker, String type) { - ClassHolder cls = checker.getClassSource().getClassHolder(type); + ClassHolder cls = checker.getClassSource().get(type); if (cls != null) { for (MethodHolder method : cls.getMethods()) { checker.attachMethodGraph(method.getReference()); 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 4df111e58..792d15b0f 100644 --- a/teavm-core/src/main/java/org/teavm/model/ClassHolderSource.java +++ b/teavm-core/src/main/java/org/teavm/model/ClassHolderSource.java @@ -19,6 +19,7 @@ package org.teavm.model; * * @author konsoletyper */ -public interface ClassHolderSource { - ClassHolder getClassHolder(String name); +public interface ClassHolderSource extends ClassReaderSource { + @Override + ClassHolder get(String name); } \ 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 new file mode 100644 index 000000000..8cc4fa8b8 --- /dev/null +++ b/teavm-core/src/main/java/org/teavm/model/ClassReaderSource.java @@ -0,0 +1,24 @@ +/* + * Copyright 2014 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 interface ClassReaderSource { + ClassReader get(String name); +} diff --git a/teavm-core/src/main/java/org/teavm/model/CopyClassHolderSource.java b/teavm-core/src/main/java/org/teavm/model/CopyClassHolderSource.java index 7e17f1ecb..722a47608 100644 --- a/teavm-core/src/main/java/org/teavm/model/CopyClassHolderSource.java +++ b/teavm-core/src/main/java/org/teavm/model/CopyClassHolderSource.java @@ -39,12 +39,12 @@ public class CopyClassHolderSource implements ClassHolderSource { } @Override - public ClassHolder getClassHolder(String name) { - return mapperSource.getClassHolder(name); + public ClassHolder get(String name) { + return mapperSource.get(name); } private ClassHolder copyClass(String className) { - ClassHolder original = innerSource.getClassHolder(className); + ClassHolder original = innerSource.get(className); if (original == null) { return null; } diff --git a/teavm-core/src/main/java/org/teavm/model/MutableClassHolderSource.java b/teavm-core/src/main/java/org/teavm/model/MutableClassHolderSource.java index 2d55eb390..39dbb6262 100644 --- a/teavm-core/src/main/java/org/teavm/model/MutableClassHolderSource.java +++ b/teavm-core/src/main/java/org/teavm/model/MutableClassHolderSource.java @@ -32,7 +32,7 @@ public class MutableClassHolderSource implements ListableClassHolderSource { } @Override - public ClassHolder getClassHolder(String name) { + public ClassHolder get(String name) { return classes.get(name); } diff --git a/teavm-core/src/main/java/org/teavm/optimization/ClassSetOptimizer.java b/teavm-core/src/main/java/org/teavm/optimization/ClassSetOptimizer.java index 9e24f48a0..4c7073f0f 100644 --- a/teavm-core/src/main/java/org/teavm/optimization/ClassSetOptimizer.java +++ b/teavm-core/src/main/java/org/teavm/optimization/ClassSetOptimizer.java @@ -41,7 +41,7 @@ public class ClassSetOptimizer { public void optimizeAll(ListableClassHolderSource classSource) { for (String className : classSource.getClassNames()) { - ClassHolder cls = classSource.getClassHolder(className); + ClassHolder cls = classSource.get(className); for (final MethodHolder method : cls.getMethods()) { if (method.getProgram() != null && method.getProgram().basicBlockCount() > 0) { executor.execute(new Runnable() { diff --git a/teavm-core/src/main/java/org/teavm/optimization/Devirtualization.java b/teavm-core/src/main/java/org/teavm/optimization/Devirtualization.java new file mode 100644 index 000000000..88603164b --- /dev/null +++ b/teavm-core/src/main/java/org/teavm/optimization/Devirtualization.java @@ -0,0 +1,77 @@ +/* + * Copyright 2014 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.optimization; + +import java.util.HashSet; +import java.util.Set; +import org.teavm.dependency.DependencyInformation; +import org.teavm.dependency.DependencyMethodInformation; +import org.teavm.dependency.DependencyValueInformation; +import org.teavm.model.*; +import org.teavm.model.instructions.InvocationType; +import org.teavm.model.instructions.InvokeInstruction; + +/** + * + * @author Alexey Andreev + */ +public class Devirtualization { + private DependencyInformation dependency; + private ClassReaderSource classSource; + + public Devirtualization(DependencyInformation dependency, ClassReaderSource classSource) { + this.dependency = dependency; + this.classSource = classSource; + } + + public void apply(MethodHolder method) { + DependencyMethodInformation methodDep = dependency.getMethod(method.getReference()); + if (methodDep == null) { + return; + } + Program program = method.getProgram(); + for (int i = 0; i < program.basicBlockCount(); ++i) { + BasicBlock block = program.basicBlockAt(i); + for (Instruction insn : block.getInstructions()) { + if (!(insn instanceof InvokeInstruction)) { + continue; + } + InvokeInstruction invoke = (InvokeInstruction)insn; + if (invoke.getType() != InvocationType.VIRTUAL) { + continue; + } + DependencyValueInformation var = methodDep.getVariable(invoke.getInstance().getIndex()); + Set implementations = getImplementations(var.getTypes(), + invoke.getMethod().getDescriptor()); + if (implementations.size() == 1) { + invoke.setType(InvocationType.SPECIAL); + invoke.setMethod(implementations.iterator().next()); + } + } + } + } + + private Set getImplementations(String[] classNames, MethodDescriptor desc) { + Set methods = new HashSet<>(); + for (String className : classNames) { + ClassReader cls = classSource.get(className); + if (cls != null && cls.getMethod(desc) != null) { + methods.add(new MethodReference(className, desc)); + } + } + return methods; + } +} diff --git a/teavm-core/src/main/java/org/teavm/parsing/ClasspathClassHolderSource.java b/teavm-core/src/main/java/org/teavm/parsing/ClasspathClassHolderSource.java index c06ec6acd..39bfb877c 100644 --- a/teavm-core/src/main/java/org/teavm/parsing/ClasspathClassHolderSource.java +++ b/teavm-core/src/main/java/org/teavm/parsing/ClasspathClassHolderSource.java @@ -40,7 +40,7 @@ public class ClasspathClassHolderSource implements ClassHolderSource { } @Override - public ClassHolder getClassHolder(String name) { - return innerClassSource.getClassHolder(name); + public ClassHolder get(String name) { + return innerClassSource.get(name); } } diff --git a/teavm-core/src/main/java/org/teavm/resource/MapperClassHolderSource.java b/teavm-core/src/main/java/org/teavm/resource/MapperClassHolderSource.java index 0cc1856e2..77f661d0d 100644 --- a/teavm-core/src/main/java/org/teavm/resource/MapperClassHolderSource.java +++ b/teavm-core/src/main/java/org/teavm/resource/MapperClassHolderSource.java @@ -32,7 +32,7 @@ public class MapperClassHolderSource implements ClassHolderSource { } @Override - public ClassHolder getClassHolder(String name) { + public ClassHolder get(String name) { return mapper.map(name); } } diff --git a/teavm-maven-plugin/src/main/java/org/teavm/maven/BuildJavascriptJUnitMojo.java b/teavm-maven-plugin/src/main/java/org/teavm/maven/BuildJavascriptJUnitMojo.java index 64e7894aa..1539e1b38 100644 --- a/teavm-maven-plugin/src/main/java/org/teavm/maven/BuildJavascriptJUnitMojo.java +++ b/teavm-maven-plugin/src/main/java/org/teavm/maven/BuildJavascriptJUnitMojo.java @@ -114,7 +114,7 @@ public class BuildJavascriptJUnitMojo extends AbstractMojo { resourceToFile("org/teavm/maven/junit.html", "junit.html"); final ClassHolderSource classSource = new ClasspathClassHolderSource(classLoader); for (String testClass : testClasses) { - ClassHolder classHolder = classSource.getClassHolder(testClass); + ClassHolder classHolder = classSource.get(testClass); if (classHolder == null) { throw new MojoFailureException("Could not find class " + testClass); } @@ -142,7 +142,7 @@ public class BuildJavascriptJUnitMojo extends AbstractMojo { firstMethod = false; allTestsWriter.append("\n { name : \"" + methodRef.getName() + "\", script : \"" + scriptName + "\", expected : ["); - MethodHolder methodHolder = classSource.getClassHolder(testClass).getMethod( + MethodHolder methodHolder = classSource.get(testClass).getMethod( methodRef.getDescriptor()); AnnotationHolder annot = methodHolder.getAnnotations().get("org.junit.Test"); AnnotationValue expectedAnnot = annot.getValues().get("expected");