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 ec929a6ab..62260ae6a 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 @@ -21,7 +21,7 @@ import org.teavm.classlib.impl.unicode.UnicodeSupport; import org.teavm.codegen.SourceWriter; import org.teavm.dependency.DependencyChecker; import org.teavm.dependency.DependencyPlugin; -import org.teavm.dependency.MethodGraph; +import org.teavm.dependency.MethodDependency; import org.teavm.javascript.ni.Generator; import org.teavm.javascript.ni.GeneratorContext; import org.teavm.model.MethodReference; @@ -49,7 +49,7 @@ public class CharacterNativeGenerator implements Generator, DependencyPlugin { } @Override - public void methodAchieved(DependencyChecker checker, MethodGraph graph) { + public void methodAchieved(DependencyChecker checker, MethodDependency graph) { switch (graph.getReference().getName()) { case "obtainDigitMapping": achieveObtainDigitMapping(graph); @@ -72,7 +72,7 @@ public class CharacterNativeGenerator implements Generator, DependencyPlugin { .append("\");").softNewLine(); } - private void achieveObtainDigitMapping(MethodGraph graph) { + private void achieveObtainDigitMapping(MethodDependency graph) { graph.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 4b15c4545..ee05eee51 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 @@ -19,7 +19,7 @@ import java.io.IOException; import org.teavm.codegen.SourceWriter; import org.teavm.dependency.DependencyChecker; import org.teavm.dependency.DependencyPlugin; -import org.teavm.dependency.MethodGraph; +import org.teavm.dependency.MethodDependency; import org.teavm.javascript.ni.Generator; import org.teavm.javascript.ni.GeneratorContext; import org.teavm.javascript.ni.Injector; @@ -40,6 +40,7 @@ public class ObjectNativeGenerator implements Generator, Injector, DependencyPlu generateInit(context, writer); break; case "hashCode": + case "identity": generateHashCode(context, writer); break; case "clone": @@ -61,7 +62,7 @@ public class ObjectNativeGenerator implements Generator, Injector, DependencyPlu } @Override - public void methodAchieved(DependencyChecker checker, MethodGraph graph) { + public void methodAchieved(DependencyChecker checker, MethodDependency graph) { switch (graph.getReference().getName()) { case "clone": achieveClone(graph); @@ -86,7 +87,7 @@ public class ObjectNativeGenerator implements Generator, Injector, DependencyPlu writer.append(".constructor)"); } - private void achieveGetClass(DependencyChecker checker, MethodGraph graph) { + private void achieveGetClass(DependencyChecker checker, MethodDependency graph) { String classClass = "java.lang.Class"; MethodReference initMethod = new MethodReference(classClass, new MethodDescriptor("createNew", ValueType.object(classClass))); @@ -107,7 +108,7 @@ public class ObjectNativeGenerator implements Generator, Injector, DependencyPlu writer.append("return copy;").softNewLine(); } - private void achieveClone(MethodGraph graph) { + private void achieveClone(MethodDependency graph) { graph.getVariable(0).connect(graph.getResult()); } @@ -115,7 +116,7 @@ public class ObjectNativeGenerator implements Generator, Injector, DependencyPlu context.writeExpr(context.getArgument(0)); } - private void achieveWrap(MethodGraph graph) { + private void achieveWrap(MethodDependency graph) { 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 bb079b05f..876b66329 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 @@ -20,7 +20,7 @@ import org.teavm.codegen.SourceWriter; import org.teavm.dependency.DependencyChecker; import org.teavm.dependency.DependencyNode; import org.teavm.dependency.DependencyPlugin; -import org.teavm.dependency.MethodGraph; +import org.teavm.dependency.MethodDependency; import org.teavm.javascript.ni.Generator; import org.teavm.javascript.ni.GeneratorContext; import org.teavm.model.MethodReference; @@ -43,7 +43,7 @@ public class SystemNativeGenerator implements Generator, DependencyPlugin { } @Override - public void methodAchieved(DependencyChecker checker, MethodGraph graph) { + public void methodAchieved(DependencyChecker checker, MethodDependency graph) { switch (graph.getReference().getName()) { case "doArrayCopy": achieveArrayCopy(graph); @@ -66,7 +66,7 @@ public class SystemNativeGenerator implements Generator, DependencyPlugin { writer.append("return Long_fromNumber(new Date().getTime());").softNewLine(); } - private void achieveArrayCopy(MethodGraph graph) { + private void achieveArrayCopy(MethodDependency graph) { 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/TClass.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TClass.java index 3388305c3..36decfd3a 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TClass.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TClass.java @@ -23,7 +23,7 @@ import org.teavm.javascript.ni.InjectedBy; * @author Alexey Andreev */ public class TClass extends TObject { - String name; + TString name; boolean primitive; boolean array; private TClass componentType; @@ -39,7 +39,7 @@ public class TClass extends TObject { @InjectedBy(ClassNativeGenerator.class) public native boolean isAssignableFrom(TClass obj); - public String getName() { + public TString getName() { return name; } diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TObject.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TObject.java index 84835371a..c44cfec52 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TObject.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TObject.java @@ -49,7 +49,12 @@ public class TObject { } @Rename("toString") - public native TString toString0(); + public TString toString0() { + return TString.wrap(getClass().getName() + "@" + identity()); + } + + @GeneratedBy(ObjectNativeGenerator.class) + native int identity(); @Override @GeneratedBy(ObjectNativeGenerator.class) 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 1fb4204e4..8dc752ed3 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 @@ -20,7 +20,7 @@ import org.teavm.codegen.SourceWriter; import org.teavm.dependency.DependencyChecker; import org.teavm.dependency.DependencyConsumer; import org.teavm.dependency.DependencyPlugin; -import org.teavm.dependency.MethodGraph; +import org.teavm.dependency.MethodDependency; import org.teavm.javascript.ni.Generator; import org.teavm.javascript.ni.GeneratorContext; import org.teavm.model.MethodDescriptor; @@ -33,7 +33,7 @@ import org.teavm.model.ValueType; */ public class ArrayNativeGenerator implements Generator, DependencyPlugin { @Override - public void methodAchieved(DependencyChecker checker, MethodGraph graph) { + public void methodAchieved(DependencyChecker checker, MethodDependency graph) { if (graph.getReference().getName().equals("getLength")) { achieveGetLength(checker, graph); } @@ -59,7 +59,7 @@ public class ArrayNativeGenerator implements Generator, DependencyPlugin { writer.append("return " + array + ".data.length;").softNewLine(); } - private void achieveGetLength(final DependencyChecker checker, final MethodGraph graph) { + private void achieveGetLength(final DependencyChecker checker, final MethodDependency graph) { graph.getVariable(1).addConsumer(new DependencyConsumer() { @Override public void consume(String type) { if (!type.startsWith("[")) { 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 9957f5c9b..de37a8918 100644 --- a/teavm-core/src/main/java/org/teavm/dependency/DependencyChecker.java +++ b/teavm-core/src/main/java/org/teavm/dependency/DependencyChecker.java @@ -29,14 +29,16 @@ import org.teavm.model.*; 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; + private ClassReaderSource classSource; private ClassLoader classLoader; private FiniteExecutor executor; + private Mapper methodReaderCache; + private Mapper fieldReaderCache; private ConcurrentMap abstractMethods = new ConcurrentHashMap<>(); private ConcurrentMap stacks = new ConcurrentHashMap<>(); private ConcurrentMap fieldStacks = new ConcurrentHashMap<>(); private ConcurrentMap classStacks = new ConcurrentHashMap<>(); - private ConcurrentCachedMapper methodCache; + private ConcurrentCachedMapper methodCache; private ConcurrentCachedMapper fieldCache; private ConcurrentMap achievableClasses = new ConcurrentHashMap<>(); private ConcurrentMap initializedClasses = new ConcurrentHashMap<>(); @@ -45,28 +47,48 @@ public class DependencyChecker implements DependencyInformation { ConcurrentMap missingClasses = new ConcurrentHashMap<>(); ConcurrentMap missingFields = new ConcurrentHashMap<>(); - public DependencyChecker(ClassHolderSource classSource, ClassLoader classLoader) { + public DependencyChecker(ClassReaderSource classSource, ClassLoader classLoader) { this(classSource, classLoader, new SimpleFiniteExecutor()); } - public DependencyChecker(ClassHolderSource classSource, ClassLoader classLoader, FiniteExecutor executor) { + public DependencyChecker(ClassReaderSource classSource, ClassLoader classLoader, FiniteExecutor executor) { this.classSource = classSource; this.classLoader = classLoader; this.executor = executor; - methodCache = new ConcurrentCachedMapper<>(new Mapper() { - @Override public MethodGraph map(MethodReference preimage) { - return createMethodGraph(preimage, stacks.get(preimage)); + methodReaderCache = new ConcurrentCachedMapper<>(new Mapper() { + @Override public MethodReader map(MethodReference preimage) { + return findMethodReader(preimage); + } + }); + fieldReaderCache = new ConcurrentCachedMapper<>(new Mapper() { + @Override public FieldReader map(FieldReference preimage) { + return findFieldReader(preimage); + } + }); + methodCache = new ConcurrentCachedMapper<>(new Mapper() { + @Override public MethodDependency map(MethodReference preimage) { + MethodReader method = methodReaderCache.map(preimage); + if (method != null && !method.getReference().equals(preimage)) { + stacks.put(method.getReference(), stacks.get(preimage)); + return methodCache.map(method.getReference()); + } + return createMethodDep(preimage, method, stacks.get(preimage)); } }); fieldCache = new ConcurrentCachedMapper<>(new Mapper() { @Override public DependencyNode map(FieldReference preimage) { - return createFieldNode(preimage, fieldStacks.get(preimage)); + FieldReader field = fieldReaderCache.map(preimage); + if (field != null && !field.getReference().equals(preimage)) { + fieldStacks.put(field.getReference(), fieldStacks.get(preimage)); + return fieldCache.map(field.getReference()); + } + return createFieldNode(preimage, field, fieldStacks.get(preimage)); } }); methodCache.addKeyListener(new KeyListener() { @Override public void keyAdded(MethodReference key) { - MethodGraph graph = methodCache.getKnown(key); - if (!missingMethods.containsKey(key) && !missingClasses.containsKey(key.getClassName())) { + MethodDependency graph = methodCache.getKnown(key); + if (!graph.isMissing()) { for (DependencyListener listener : listeners) { listener.methodAchieved(DependencyChecker.this, graph); } @@ -90,7 +112,7 @@ public class DependencyChecker implements DependencyInformation { return new DependencyNode(this); } - public ClassHolderSource getClassSource() { + public ClassReaderSource getClassSource() { return classSource; } @@ -109,7 +131,7 @@ public class DependencyChecker implements DependencyInformation { if (parameters.length != argumentTypes.length) { throw new IllegalArgumentException("argumentTypes length does not match the number of method's arguments"); } - MethodGraph graph = attachMethodGraph(methodRef, DependencyStack.ROOT); + MethodDependency graph = linkMethod(methodRef, DependencyStack.ROOT); DependencyNode[] varNodes = graph.getVariables(); varNodes[0].propagate(methodRef.getClassName()); for (int i = 0; i < argumentTypes.length; ++i) { @@ -140,7 +162,7 @@ public class DependencyChecker implements DependencyInformation { return result; } - public MethodGraph attachMethodGraph(MethodReference methodRef, DependencyStack stack) { + public MethodDependency linkMethod(MethodReference methodRef, DependencyStack stack) { stacks.putIfAbsent(methodRef, stack); return methodCache.map(methodRef); } @@ -154,14 +176,14 @@ public class DependencyChecker implements DependencyInformation { } achieveClass(className, stack); achieveInterfaces(className, stack); - ClassHolder cls = classSource.get(className); + ClassReader cls = classSource.get(className); if (cls == null) { missingClasses.put(className, stack); return; } if (cls.getMethod(clinitDesc) != null) { MethodReference methodRef = new MethodReference(className, clinitDesc); - attachMethodGraph(methodRef, new DependencyStack(methodRef, stack)); + linkMethod(methodRef, new DependencyStack(methodRef, stack)); } className = cls.getParent(); } @@ -169,7 +191,7 @@ public class DependencyChecker implements DependencyInformation { private void achieveInterfaces(String className, DependencyStack stack) { classStacks.putIfAbsent(className, stack); - ClassHolder cls = classSource.get(className); + ClassReader cls = classSource.get(className); if (cls == null) { missingClasses.put(className, stack); return; @@ -181,29 +203,44 @@ public class DependencyChecker implements DependencyInformation { } } - private MethodGraph createMethodGraph(final MethodReference methodRef, DependencyStack stack) { + private MethodReader findMethodReader(MethodReference methodRef) { + String clsName = methodRef.getClassName(); + MethodDescriptor desc = methodRef.getDescriptor(); + while (clsName != null) { + ClassReader cls = classSource.get(clsName); + if (cls == null) { + return null; + } + MethodReader method = cls.getMethod(desc); + if (method != null) { + return method; + } + clsName = cls.getParent(); + } + 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; + } + clsName = cls.getParent(); + } + return null; + } + + private MethodDependency createMethodDep(MethodReference methodRef, MethodReader method, DependencyStack stack) { if (stack == null) { stack = DependencyStack.ROOT; } - initClass(methodRef.getClassName(), stack); - ClassHolder cls = classSource.get(methodRef.getClassName()); - MethodHolder method; - if (cls == null) { - missingClasses.put(methodRef.getClassName(), stack); - method = null; - } else { - method = cls.getMethod(methodRef.getDescriptor()); - if (method == null) { - while (cls != null) { - method = cls.getMethod(methodRef.getDescriptor()); - if (method != null) { - return attachMethodGraph(method.getReference(), stack); - } - cls = cls.getParent() != null ? classSource.get(cls.getParent()) : null; - } - missingMethods.put(methodRef, stack); - } - } ValueType[] arguments = methodRef.getParameterTypes(); int paramCount = arguments.length + 1; int varCount = Math.max(paramCount, method != null ? method.getProgram().variableCount() : 0); @@ -224,17 +261,23 @@ public class DependencyChecker implements DependencyInformation { } } stack = new DependencyStack(methodRef, stack); - final MethodGraph graph = new MethodGraph(parameterNodes, paramCount, resultNode, stack, methodRef); + final MethodDependency dep = new MethodDependency(parameterNodes, paramCount, resultNode, stack, method, + methodRef); if (method != null) { - final MethodHolder currentMethod = method; + final MethodReader currentMethod = method; executor.execute(new Runnable() { @Override public void run() { DependencyGraphBuilder graphBuilder = new DependencyGraphBuilder(DependencyChecker.this); - graphBuilder.buildGraph(currentMethod, graph); + graphBuilder.buildGraph(currentMethod, dep); } }); + } else { + missingMethods.putIfAbsent(methodRef, stack); } - return graph; + if (method != null) { + initClass(methodRef.getClassName(), stack); + } + return dep; } public boolean isMethodAchievable(MethodReference methodRef) { @@ -260,7 +303,7 @@ public class DependencyChecker implements DependencyInformation { return new HashSet<>(achievableClasses.keySet()); } - public DependencyNode attachFieldNode(FieldReference fieldRef, DependencyStack stack) { + public DependencyNode linkField(FieldReference fieldRef, DependencyStack stack) { fieldStacks.putIfAbsent(fieldRef, stack); return fieldCache.map(fieldRef); } @@ -270,38 +313,27 @@ public class DependencyChecker implements DependencyInformation { return fieldCache.getKnown(fieldRef); } - private DependencyNode createFieldNode(FieldReference fieldRef, DependencyStack stack) { - initClass(fieldRef.getClassName(), stack); - ClassHolder cls = classSource.get(fieldRef.getClassName()); - if (cls == null) { - missingClasses.put(fieldRef.getClassName(), stack); - } else { - FieldHolder field = cls.getField(fieldRef.getFieldName()); - if (field == null) { - while (cls != null) { - field = cls.getField(fieldRef.getFieldName()); - if (field != null) { - return attachFieldNode(new FieldReference(cls.getName(), fieldRef.getFieldName()), stack); - } - cls = cls.getParent() != null ? classSource.get(cls.getParent()) : null; - } - missingFields.put(fieldRef, stack); - } - } + private DependencyNode createFieldNode(FieldReference fieldRef, FieldReader field, DependencyStack stack) { DependencyNode node = new DependencyNode(this); + if (field == null) { + missingFields.putIfAbsent(fieldRef, stack); + } if (shouldLog) { node.setTag(fieldRef.getClassName() + "#" + fieldRef.getFieldName()); } + if (field != null) { + initClass(fieldRef.getClassName(), stack); + } return node; } - private void activateDependencyPlugin(MethodGraph graph) { + private void activateDependencyPlugin(MethodDependency graph) { MethodReference methodRef = graph.getReference(); - ClassHolder cls = classSource.get(methodRef.getClassName()); + ClassReader cls = classSource.get(methodRef.getClassName()); if (cls == null) { return; } - MethodHolder method = cls.getMethod(methodRef.getDescriptor()); + MethodReader method = cls.getMethod(methodRef.getDescriptor()); if (method == null) { return; } @@ -331,11 +363,11 @@ public class DependencyChecker implements DependencyInformation { if (abstractMethods.putIfAbsent(methodRef, methodRef) == null) { String className = methodRef.getClassName(); while (className != null) { - ClassHolder cls = classSource.get(className); + ClassReader cls = classSource.get(className); if (cls == null) { return; } - MethodHolder method = cls.getMethod(methodRef.getDescriptor()); + MethodReader method = cls.getMethod(methodRef.getDescriptor()); if (method != null) { abstractMethods.put(methodRef, methodRef); return; @@ -345,7 +377,7 @@ public class DependencyChecker implements DependencyInformation { } } - public ListableClassHolderSource cutUnachievableClasses() { + public ListableClassHolderSource cutUnachievableClasses(ClassHolderSource classSource) { MutableClassHolderSource cutClasses = new MutableClassHolderSource(); for (String className : achievableClasses.keySet()) { ClassHolder classHolder = classSource.get(className); 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 6953835e7..78a5fa801 100644 --- a/teavm-core/src/main/java/org/teavm/dependency/DependencyGraphBuilder.java +++ b/teavm-core/src/main/java/org/teavm/dependency/DependencyGraphBuilder.java @@ -16,6 +16,8 @@ package org.teavm.dependency; import java.util.List; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; import org.teavm.model.*; import org.teavm.model.instructions.*; import org.teavm.model.util.ListingBuilder; @@ -28,15 +30,15 @@ class DependencyGraphBuilder { private DependencyChecker dependencyChecker; private DependencyNode[] nodes; private DependencyNode resultNode; - private Program program; + private ProgramReader program; private DependencyStack callerStack; public DependencyGraphBuilder(DependencyChecker dependencyChecker) { this.dependencyChecker = dependencyChecker; } - public void buildGraph(MethodHolder method, MethodGraph graph) { - if (method.getProgram().basicBlockCount() == 0) { + public void buildGraph(MethodReader method, MethodDependency graph) { + if (method.getProgram() == null || method.getProgram().basicBlockCount() == 0) { return; } callerStack = graph.getStack(); @@ -48,12 +50,10 @@ class DependencyGraphBuilder { resultNode = graph.getResult(); nodes = graph.getVariables(); for (int i = 0; i < program.basicBlockCount(); ++i) { - BasicBlock block = program.basicBlockAt(i); - for (Instruction insn : block.getInstructions()) { - insn.acceptVisitor(visitor); - } - for (Phi phi : block.getPhis()) { - for (Incoming incoming : phi.getIncomings()) { + BasicBlockReader block = program.basicBlockAt(i); + block.readAllInstructions(reader); + for (PhiReader phi : block.readPhis()) { + for (IncomingReader incoming : phi.readIncomings()) { nodes[incoming.getValue().getIndex()].connect(nodes[phi.getReceiver().getIndex()]); } } @@ -67,6 +67,7 @@ class DependencyGraphBuilder { private final DependencyNode[] parameters; private final DependencyNode result; private final DependencyStack stack; + private final ConcurrentMap knownMethods = new ConcurrentHashMap<>(); public VirtualCallPropagationListener(DependencyNode node, MethodDescriptor methodDesc, DependencyChecker checker, DependencyNode[] parameters, DependencyNode result, @@ -89,262 +90,256 @@ class DependencyGraphBuilder { className = "java.lang.Object"; } MethodReference methodRef = new MethodReference(className, methodDesc); - MethodHolder method = findMethod(methodRef, checker.getClassSource()); - if (method == null) { - return; - } - MethodGraph targetGraph = checker.attachMethodGraph(methodRef, stack); - DependencyNode[] targetParams = targetGraph.getVariables(); - for (int i = 0; i < parameters.length; ++i) { - parameters[i].connect(targetParams[i]); - } - if (targetGraph.getResult() != null) { - targetGraph.getResult().connect(result); - } - } - } - - private static MethodHolder findMethod(MethodReference methodRef, ClassHolderSource classSource) { - String className = methodRef.getClassName(); - while (className != null) { - ClassHolder cls = classSource.get(className); - if (cls == null) { - break; - } - MethodHolder method = cls.getMethod(methodRef.getDescriptor()); - if (method != null) { - return method; - } - className = cls.getParent(); - } - return null; - } - - private InstructionVisitor visitor = new InstructionVisitor() { - @Override - public void visit(IsInstanceInstruction insn) { - } - - @Override - public void visit(InvokeInstruction insn) { - if (insn.getInstance() == null) { - invokeSpecial(insn); - } else { - switch (insn.getType()) { - case SPECIAL: - invokeSpecial(insn); - break; - case VIRTUAL: - invokeVirtual(insn); - break; + MethodDependency methodDep = checker.linkMethod(methodRef, stack); + if (!methodDep.isMissing() && knownMethods.putIfAbsent(methodRef, methodRef) == null) { + DependencyNode[] targetParams = methodDep.getVariables(); + for (int i = 0; i < parameters.length; ++i) { + parameters[i].connect(targetParams[i]); + } + if (methodDep.getResult() != null) { + methodDep.getResult().connect(result); } } } + } - private void invokeSpecial(InvokeInstruction insn) { - MethodGraph targetGraph = dependencyChecker.attachMethodGraph(insn.getMethod(), callerStack); - 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]); - } - if (insn.getInstance() != null) { - nodes[insn.getInstance().getIndex()].connect(targetParams[0]); - } - if (targetGraph.getResult() != null && insn.getReceiver() != null) { - targetGraph.getResult().connect(nodes[insn.getReceiver().getIndex()]); - } - } - - private void invokeVirtual(InvokeInstruction insn) { - List arguments = insn.getArguments(); - DependencyNode[] actualArgs = new DependencyNode[arguments.size() + 1]; - for (int i = 0; i < arguments.size(); ++i) { - actualArgs[i + 1] = nodes[arguments.get(i).getIndex()]; - } - actualArgs[0] = nodes[insn.getInstance().getIndex()]; - DependencyConsumer listener = new VirtualCallPropagationListener(nodes[insn.getInstance().getIndex()], - insn.getMethod().getDescriptor(), dependencyChecker, actualArgs, - insn.getReceiver() != null ? nodes[insn.getReceiver().getIndex()] : null, callerStack); - dependencyChecker.addAbstractMethod(insn.getMethod(), callerStack); - nodes[insn.getInstance().getIndex()].addConsumer(listener); + private InstructionReader reader = new InstructionReader() { + @Override + public void nop() { } @Override - public void visit(PutElementInstruction insn) { - DependencyNode valueNode = nodes[insn.getValue().getIndex()]; - DependencyNode arrayNode = nodes[insn.getArray().getIndex()]; - valueNode.connect(arrayNode.getArrayItem()); + public void classConstant(VariableReader receiver, ValueType cst) { + nodes[receiver.getIndex()].propagate("java.lang.Class"); + while (cst instanceof ValueType.Array) { + cst = ((ValueType.Array)cst).getItemType(); + } + if (cst instanceof ValueType.Object) { + dependencyChecker.achieveClass(((ValueType.Object)cst).getClassName(), callerStack); + } } @Override - public void visit(GetElementInstruction insn) { - DependencyNode arrayNode = nodes[insn.getArray().getIndex()]; - DependencyNode receiverNode = nodes[insn.getReceiver().getIndex()]; - arrayNode.getArrayItem().connect(receiverNode); + public void nullConstant(VariableReader receiver) { } @Override - public void visit(UnwrapArrayInstruction insn) { - DependencyNode arrayNode = nodes[insn.getArray().getIndex()]; - DependencyNode receiverNode = nodes[insn.getReceiver().getIndex()]; - arrayNode.connect(receiverNode); + public void integerConstant(VariableReader receiver, int cst) { } @Override - public void visit(CloneArrayInstruction insn) { - DependencyNode arrayNode = nodes[insn.getArray().getIndex()]; - final DependencyNode receiverNode = nodes[insn.getReceiver().getIndex()]; + public void longConstant(VariableReader receiver, long cst) { + } + + @Override + public void floatConstant(VariableReader receiver, float cst) { + } + + @Override + public void doubleConstant(VariableReader receiver, double cst) { + } + + @Override + public void stringConstant(VariableReader receiver, String cst) { + nodes[receiver.getIndex()].propagate("java.lang.String"); + dependencyChecker.linkMethod(new MethodReference("java.lang.String", new MethodDescriptor( + "", ValueType.arrayOf(ValueType.CHARACTER), ValueType.VOID)), callerStack); + } + + @Override + public void binary(BinaryOperation op, VariableReader receiver, VariableReader first, VariableReader second, + NumericOperandType type) { + } + + @Override + public void negate(VariableReader receiver, VariableReader operand, NumericOperandType type) { + } + + @Override + public void assign(VariableReader receiver, VariableReader assignee) { + DependencyNode valueNode = nodes[assignee.getIndex()]; + DependencyNode receiverNode = nodes[receiver.getIndex()]; + valueNode.connect(receiverNode); + } + + @Override + public void cast(VariableReader receiver, VariableReader value, ValueType targetType) { + DependencyNode valueNode = nodes[value.getIndex()]; + DependencyNode receiverNode = nodes[receiver.getIndex()]; + valueNode.connect(receiverNode); + } + + @Override + public void cast(VariableReader receiver, VariableReader value, NumericOperandType sourceType, + NumericOperandType targetType) { + } + + @Override + public void cast(VariableReader receiver, VariableReader value, IntegerSubtype type, + CastIntegerDirection targetType) { + } + + @Override + public void jumpIf(BranchingCondition cond, VariableReader operand, BasicBlockReader consequent, + BasicBlockReader alternative) { + } + + @Override + public void jumpIf(BinaryBranchingCondition cond, VariableReader first, VariableReader second, + BasicBlockReader consequent, BasicBlockReader alternative) { + } + + @Override + public void jump(BasicBlockReader target) { + } + + @Override + public void choose(VariableReader condition, List table, + BasicBlockReader defaultTarget) { + } + + @Override + public void exit(VariableReader valueToReturn) { + if (valueToReturn != null) { + nodes[valueToReturn.getIndex()].connect(resultNode); + } + } + + @Override + public void raise(VariableReader exception) { + } + + @Override + public void createArray(VariableReader receiver, ValueType itemType, VariableReader size) { + nodes[receiver.getIndex()].propagate("[" + itemType); + } + + @Override + public void createArray(VariableReader receiver, ValueType itemType, + List dimensions) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < dimensions.size(); ++i) { + sb.append('['); + } + sb.append(itemType); + nodes[receiver.getIndex()].propagate(sb.toString()); + } + + @Override + public void create(VariableReader receiver, String type) { + nodes[receiver.getIndex()].propagate(type); + } + + @Override + public void getField(VariableReader receiver, VariableReader instance, FieldReference field, + ValueType fieldType) { + DependencyNode fieldNode = dependencyChecker.linkField(field, callerStack); + DependencyNode receiverNode = nodes[receiver.getIndex()]; + fieldNode.connect(receiverNode); + } + + @Override + public void putField(VariableReader instance, FieldReference field, VariableReader value) { + DependencyNode fieldNode = dependencyChecker.linkField(field, callerStack); + DependencyNode valueNode = nodes[value.getIndex()]; + valueNode.connect(fieldNode); + } + + @Override + public void arrayLength(VariableReader receiver, VariableReader array) { + } + + @Override + public void cloneArray(VariableReader receiver, VariableReader array) { + DependencyNode arrayNode = nodes[array.getIndex()]; + final DependencyNode receiverNode = nodes[receiver.getIndex()]; arrayNode.addConsumer(new DependencyConsumer() { @Override public void consume(String type) { receiverNode.propagate(type); - } }); arrayNode.getArrayItem().connect(receiverNode.getArrayItem()); } @Override - public void visit(ArrayLengthInstruction insn) { + public void unwrapArray(VariableReader receiver, VariableReader array, ArrayElementType elementType) { + DependencyNode arrayNode = nodes[array.getIndex()]; + DependencyNode receiverNode = nodes[receiver.getIndex()]; + arrayNode.connect(receiverNode); } @Override - public void visit(PutFieldInstruction insn) { - DependencyNode fieldNode = dependencyChecker.attachFieldNode(insn.getField(), callerStack); - DependencyNode valueNode = nodes[insn.getValue().getIndex()]; - valueNode.connect(fieldNode); + public void getElement(VariableReader receiver, VariableReader array, VariableReader index) { + DependencyNode arrayNode = nodes[array.getIndex()]; + DependencyNode receiverNode = nodes[receiver.getIndex()]; + arrayNode.getArrayItem().connect(receiverNode); } @Override - public void visit(GetFieldInstruction insn) { - DependencyNode fieldNode = dependencyChecker.attachFieldNode(insn.getField(), callerStack); - DependencyNode receiverNode = nodes[insn.getReceiver().getIndex()]; - fieldNode.connect(receiverNode); + public void putElement(VariableReader array, VariableReader index, VariableReader value) { + DependencyNode valueNode = nodes[value.getIndex()]; + DependencyNode arrayNode = nodes[array.getIndex()]; + valueNode.connect(arrayNode.getArrayItem()); } @Override - public void visit(ConstructMultiArrayInstruction insn) { - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < insn.getDimensions().size(); ++i) { - sb.append('['); - } - sb.append(insn.getItemType()); - nodes[insn.getReceiver().getIndex()].propagate(sb.toString()); - } - - @Override - public void visit(ConstructInstruction insn) { - nodes[insn.getReceiver().getIndex()].propagate(insn.getType()); - } - - @Override - public void visit(ConstructArrayInstruction insn) { - nodes[insn.getReceiver().getIndex()].propagate("[" + insn.getItemType()); - } - - @Override - public void visit(RaiseInstruction insn) { - } - - @Override - public void visit(ExitInstruction insn) { - if (insn.getValueToReturn() != null) { - nodes[insn.getValueToReturn().getIndex()].connect(resultNode); + public void invoke(VariableReader receiver, VariableReader instance, MethodReference method, + List arguments, InvocationType type) { + if (instance == null) { + invokeSpecial(receiver, instance, method, arguments); + } else { + switch (type) { + case SPECIAL: + invokeSpecial(receiver, instance, method, arguments); + break; + case VIRTUAL: + invokeVirtual(receiver, instance, method, arguments); + break; + } } } - @Override - public void visit(SwitchInstruction insn) { - } - - @Override - public void visit(JumpInstruction insn) { - } - - @Override - public void visit(BinaryBranchingInstruction insn) { - } - - @Override - public void visit(BranchingInstruction insn) { - } - - @Override - public void visit(CastNumberInstruction insn) { - } - - @Override - public void visit(CastInstruction insn) { - DependencyNode valueNode = nodes[insn.getValue().getIndex()]; - DependencyNode receiverNode = nodes[insn.getReceiver().getIndex()]; - valueNode.connect(receiverNode); - } - - @Override - public void visit(CastIntegerInstruction insn) { - } - - @Override - public void visit(AssignInstruction insn) { - DependencyNode valueNode = nodes[insn.getAssignee().getIndex()]; - DependencyNode receiverNode = nodes[insn.getReceiver().getIndex()]; - valueNode.connect(receiverNode); - } - - @Override - public void visit(NegateInstruction insn) { - } - - @Override - public void visit(BinaryInstruction insn) { - } - - @Override - public void visit(StringConstantInstruction insn) { - nodes[insn.getReceiver().getIndex()].propagate("java.lang.String"); - dependencyChecker.attachMethodGraph(new MethodReference("java.lang.String", new MethodDescriptor( - "", ValueType.arrayOf(ValueType.CHARACTER), ValueType.VOID)), callerStack); - } - - @Override - public void visit(DoubleConstantInstruction insn) { - } - - @Override - public void visit(FloatConstantInstruction insn) { - } - - @Override - public void visit(LongConstantInstruction insn) { - } - - @Override - public void visit(IntegerConstantInstruction insn) { - } - - @Override - public void visit(NullConstantInstruction insn) { - } - - @Override - public void visit(ClassConstantInstruction insn) { - nodes[insn.getReceiver().getIndex()].propagate("java.lang.Class"); - ValueType type = insn.getConstant(); - while (type instanceof ValueType.Array) { - type = ((ValueType.Array)type).getItemType(); + private void invokeSpecial(VariableReader receiver, VariableReader instance, MethodReference method, + List arguments) { + MethodDependency methodDep = dependencyChecker.linkMethod(method, callerStack); + if (methodDep.isMissing()) { + return; } - if (type instanceof ValueType.Object) { - dependencyChecker.achieveClass(((ValueType.Object)type).getClassName(), callerStack); + DependencyNode[] targetParams = methodDep.getVariables(); + for (int i = 0; i < arguments.size(); ++i) { + nodes[arguments.get(i).getIndex()].connect(targetParams[i + 1]); + } + if (instance != null) { + nodes[instance.getIndex()].connect(targetParams[0]); + } + if (methodDep.getResult() != null && receiver != null) { + methodDep.getResult().connect(nodes[receiver.getIndex()]); } } - @Override - public void visit(EmptyInstruction insn) { + private void invokeVirtual(VariableReader receiver, VariableReader instance, MethodReference method, + List arguments) { + if (dependencyChecker.linkMethod(method, callerStack).isMissing()) { + return; + } + DependencyNode[] actualArgs = new DependencyNode[arguments.size() + 1]; + for (int i = 0; i < arguments.size(); ++i) { + actualArgs[i + 1] = nodes[arguments.get(i).getIndex()]; + } + actualArgs[0] = nodes[instance.getIndex()]; + DependencyConsumer listener = new VirtualCallPropagationListener(nodes[instance.getIndex()], + method.getDescriptor(), dependencyChecker, actualArgs, + receiver != null ? nodes[receiver.getIndex()] : null, callerStack); + nodes[instance.getIndex()].addConsumer(listener); } @Override - public void visit(InitClassInstruction insn) { - dependencyChecker.initClass(insn.getClassName(), callerStack); + public void isInstance(VariableReader receiver, VariableReader value, ValueType type) { + } + + @Override + public void initClass(String className) { + dependencyChecker.initClass(className, callerStack); } }; } diff --git a/teavm-core/src/main/java/org/teavm/dependency/DependencyListener.java b/teavm-core/src/main/java/org/teavm/dependency/DependencyListener.java index 17f87271f..07b8d5728 100644 --- a/teavm-core/src/main/java/org/teavm/dependency/DependencyListener.java +++ b/teavm-core/src/main/java/org/teavm/dependency/DependencyListener.java @@ -26,7 +26,7 @@ public interface DependencyListener { void classAchieved(DependencyChecker dependencyChecker, String className); - void methodAchieved(DependencyChecker dependencyChecker, MethodGraph method); + void methodAchieved(DependencyChecker dependencyChecker, MethodDependency method); void fieldAchieved(DependencyChecker dependencyChecker, FieldReference field, DependencyNode node); } diff --git a/teavm-core/src/main/java/org/teavm/dependency/DependencyPlugin.java b/teavm-core/src/main/java/org/teavm/dependency/DependencyPlugin.java index 50e769c71..23ff0723e 100644 --- a/teavm-core/src/main/java/org/teavm/dependency/DependencyPlugin.java +++ b/teavm-core/src/main/java/org/teavm/dependency/DependencyPlugin.java @@ -20,5 +20,5 @@ package org.teavm.dependency; * @author Alexey Andreev */ public interface DependencyPlugin { - void methodAchieved(DependencyChecker checker, MethodGraph graph); + void methodAchieved(DependencyChecker checker, MethodDependency graph); } diff --git a/teavm-core/src/main/java/org/teavm/dependency/MethodGraph.java b/teavm-core/src/main/java/org/teavm/dependency/MethodDependency.java similarity index 78% rename from teavm-core/src/main/java/org/teavm/dependency/MethodGraph.java rename to teavm-core/src/main/java/org/teavm/dependency/MethodDependency.java index 42efd403c..443e7ca7e 100644 --- a/teavm-core/src/main/java/org/teavm/dependency/MethodGraph.java +++ b/teavm-core/src/main/java/org/teavm/dependency/MethodDependency.java @@ -16,25 +16,28 @@ package org.teavm.dependency; import java.util.Arrays; +import org.teavm.model.MethodReader; import org.teavm.model.MethodReference; /** * * @author Alexey Andreev */ -public class MethodGraph implements DependencyMethodInformation { +public class MethodDependency implements DependencyMethodInformation { private DependencyNode[] variableNodes; private int parameterCount; private DependencyNode resultNode; private DependencyStack stack; + private MethodReader method; private MethodReference reference; - MethodGraph(DependencyNode[] variableNodes, int parameterCount, DependencyNode resultNode, - DependencyStack stack, MethodReference reference) { + MethodDependency(DependencyNode[] variableNodes, int parameterCount, DependencyNode resultNode, + DependencyStack stack, MethodReader method, MethodReference reference) { this.variableNodes = Arrays.copyOf(variableNodes, variableNodes.length); this.parameterCount = parameterCount; this.resultNode = resultNode; this.stack = stack; + this.method = method; this.reference = reference; } @@ -70,4 +73,12 @@ public class MethodGraph implements DependencyMethodInformation { public MethodReference getReference() { return reference; } + + public MethodReader getMethod() { + return method; + } + + public boolean isMissing() { + return method == null; + } } 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 b01ebcc8e..4e79729f7 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/JavascriptBuilder.java +++ b/teavm-core/src/main/java/org/teavm/javascript/JavascriptBuilder.java @@ -91,7 +91,7 @@ public class JavascriptBuilder implements JavascriptBuilderHost { "for method " + ref); } JavascriptEntryPoint entryPoint = new JavascriptEntryPoint(name, ref, - dependencyChecker.attachMethodGraph(ref, DependencyStack.ROOT)); + dependencyChecker.linkMethod(ref, DependencyStack.ROOT)); entryPoints.put(name, entryPoint); return entryPoint; } @@ -119,13 +119,13 @@ public class JavascriptBuilder implements JavascriptBuilderHost { SourceWriterBuilder builder = new SourceWriterBuilder(naming); builder.setMinified(minifying); SourceWriter sourceWriter = builder.build(writer); - dependencyChecker.attachMethodGraph(new MethodReference("java.lang.Class", new MethodDescriptor("createNew", + dependencyChecker.linkMethod(new MethodReference("java.lang.Class", new MethodDescriptor("createNew", ValueType.object("java.lang.Class"))), DependencyStack.ROOT); - dependencyChecker.attachMethodGraph(new MethodReference("java.lang.String", new MethodDescriptor("", + dependencyChecker.linkMethod(new MethodReference("java.lang.String", new MethodDescriptor("", ValueType.arrayOf(ValueType.CHARACTER), ValueType.VOID)), DependencyStack.ROOT); executor.complete(); dependencyChecker.checkForMissingItems(); - ListableClassHolderSource classSet = dependencyChecker.cutUnachievableClasses(); + ListableClassHolderSource classSet = dependencyChecker.cutUnachievableClasses(classSource); Decompiler decompiler = new Decompiler(classSet, classLoader, executor); devirtualize(classSet, dependencyChecker); executor.complete(); 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 f97ffd858..18b4fcbc8 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/JavascriptEntryPoint.java +++ b/teavm-core/src/main/java/org/teavm/javascript/JavascriptEntryPoint.java @@ -15,7 +15,7 @@ */ package org.teavm.javascript; -import org.teavm.dependency.MethodGraph; +import org.teavm.dependency.MethodDependency; import org.teavm.model.MethodReference; /** @@ -25,9 +25,9 @@ import org.teavm.model.MethodReference; public class JavascriptEntryPoint { private String publicName; MethodReference reference; - private MethodGraph graph; + private MethodDependency graph; - JavascriptEntryPoint(String publicName, MethodReference reference, MethodGraph graph) { + JavascriptEntryPoint(String publicName, MethodReference reference, MethodDependency graph) { this.publicName = publicName; this.reference = reference; this.graph = graph; diff --git a/teavm-core/src/main/java/org/teavm/model/FieldHolder.java b/teavm-core/src/main/java/org/teavm/model/FieldHolder.java index 10aef8983..9b24aea5e 100644 --- a/teavm-core/src/main/java/org/teavm/model/FieldHolder.java +++ b/teavm-core/src/main/java/org/teavm/model/FieldHolder.java @@ -59,4 +59,9 @@ public class FieldHolder extends MemberHolder implements FieldReader { public String getOwnerName() { return owner != null ? owner.getName() : null; } + + @Override + public FieldReference getReference() { + return new FieldReference(getOwnerName(), getName()); + } } diff --git a/teavm-core/src/main/java/org/teavm/model/FieldReader.java b/teavm-core/src/main/java/org/teavm/model/FieldReader.java index 577df212a..bae5340f3 100644 --- a/teavm-core/src/main/java/org/teavm/model/FieldReader.java +++ b/teavm-core/src/main/java/org/teavm/model/FieldReader.java @@ -23,4 +23,6 @@ public interface FieldReader extends MemberReader { ValueType getType(); Object getInitialValue(); + + FieldReference getReference(); } 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 2f60d2b0e..8da4e3e2a 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 @@ -16,14 +16,14 @@ package org.teavm.model.util; import java.util.List; -import org.teavm.model.Variable; +import org.teavm.model.*; import org.teavm.model.instructions.*; /** * * @author Alexey Andreev */ -public class InstructionStringifier implements InstructionVisitor { +public class InstructionStringifier implements InstructionReader { private StringBuilder sb; public InstructionStringifier(StringBuilder sb) { @@ -31,56 +31,50 @@ public class InstructionStringifier implements InstructionVisitor { } @Override - public void visit(EmptyInstruction insn) { + public void nop() { sb.append("nop"); } @Override - public void visit(ClassConstantInstruction insn) { - sb.append("@").append(insn.getReceiver().getIndex()).append(" := classOf ") - .append(insn.getConstant()); + public void classConstant(VariableReader receiver, ValueType cst) { + sb.append("@").append(receiver.getIndex()).append(" := classOf ").append(cst); } @Override - public void visit(NullConstantInstruction insn) { - sb.append("@").append(insn.getReceiver().getIndex()).append(" := null"); + public void nullConstant(VariableReader receiver) { + sb.append("@").append(receiver.getIndex()).append(" := null"); } @Override - public void visit(IntegerConstantInstruction insn) { - sb.append("@").append(insn.getReceiver().getIndex()).append(" := ") - .append(insn.getConstant()); + public void integerConstant(VariableReader receiver, int cst) { + sb.append("@").append(receiver.getIndex()).append(" := ").append(cst); } @Override - public void visit(LongConstantInstruction insn) { - sb.append("@").append(insn.getReceiver().getIndex()).append(" := ") - .append(insn.getConstant()); + public void longConstant(VariableReader receiver, long cst) { + sb.append("@").append(receiver.getIndex()).append(" := ").append(cst); } @Override - public void visit(FloatConstantInstruction insn) { - sb.append("@").append(insn.getReceiver().getIndex()).append(" := ") - .append(insn.getConstant()); + public void floatConstant(VariableReader receiver, float cst) { + sb.append("@").append(receiver.getIndex()).append(" := ").append(cst); } @Override - public void visit(DoubleConstantInstruction insn) { - sb.append("@").append(insn.getReceiver().getIndex()).append(" := ") - .append(insn.getConstant()); + public void doubleConstant(VariableReader receiver, double cst) { + sb.append("@").append(receiver.getIndex()).append(" := ").append(cst); } @Override - public void visit(StringConstantInstruction insn) { - sb.append("@").append(insn.getReceiver().getIndex()).append(" := '") - .append(insn.getConstant()).append("'"); + public void stringConstant(VariableReader receiver, String cst) { + sb.append("@").append(receiver.getIndex()).append(" := '").append(cst).append("'"); } @Override - public void visit(BinaryInstruction insn) { - sb.append("@").append(insn.getReceiver().getIndex()).append(" := @") - .append(insn.getFirstOperand().getIndex()).append(" "); - switch (insn.getOperation()) { + public void binary(BinaryOperation op, VariableReader receiver, VariableReader first, VariableReader second, + NumericOperandType type) { + sb.append("@").append(receiver.getIndex()).append(" := @").append(first.getIndex()).append(" "); + switch (op) { case ADD: sb.append("+"); break; @@ -118,25 +112,51 @@ public class InstructionStringifier implements InstructionVisitor { sb.append("^"); break; } - sb.append(" @").append(insn.getSecondOperand().getIndex()); + sb.append(" @").append(second.getIndex()); } @Override - public void visit(NegateInstruction insn) { - sb.append("@").append(insn.getReceiver().getIndex()).append(" := -") - .append(" @").append(insn.getOperand().getIndex()); + public void negate(VariableReader receiver, VariableReader operand, NumericOperandType type) { + sb.append("@").append(receiver.getIndex()).append(" := -").append(" @").append(operand.getIndex()); } @Override - public void visit(AssignInstruction insn) { - sb.append("@").append(insn.getReceiver().getIndex()).append(" := @") - .append(insn.getAssignee().getIndex()); + public void assign(VariableReader receiver, VariableReader assignee) { + sb.append("@").append(receiver.getIndex()).append(" := @").append(assignee.getIndex()); } @Override - public void visit(BranchingInstruction insn) { - sb.append("if @").append(insn.getOperand().getIndex()).append(" "); - switch (insn.getCondition()) { + public void cast(VariableReader receiver, VariableReader value, ValueType targetType) { + sb.append("@").append(receiver.getIndex()).append(" := cast @").append(value.getIndex()) + .append(" to ").append(targetType); + } + + @Override + public void cast(VariableReader receiver, VariableReader value, NumericOperandType sourceType, + NumericOperandType targetType) { + sb.append("@").append(receiver.getIndex()).append(" := cast @").append(value.getIndex()) + .append(" from ").append(sourceType).append(" to ").append(targetType); + } + + @Override + public void cast(VariableReader receiver, VariableReader value, IntegerSubtype type, + CastIntegerDirection direction) { + sb.append("@").append(receiver.getIndex()).append(" := cast @").append(value.getIndex()); + switch (direction) { + case FROM_INTEGER: + sb.append(" from INT to ").append(type); + break; + case TO_INTEGER: + sb.append(" from ").append(type).append(" to INT"); + break; + } + } + + @Override + public void jumpIf(BranchingCondition cond, VariableReader operand, BasicBlockReader consequent, + BasicBlockReader alternative) { + sb.append("if @").append(operand.getIndex()).append(" "); + switch (cond) { case EQUAL: sb.append("== 0"); break; @@ -162,14 +182,14 @@ public class InstructionStringifier implements InstructionVisitor { sb.append("== null"); break; } - sb.append(" then goto $").append(insn.getConsequent().getIndex()).append(" else goto $") - .append(insn.getAlternative().getIndex()); + sb.append(" then goto $").append(consequent.getIndex()).append(" else goto $").append(alternative.getIndex()); } @Override - public void visit(BinaryBranchingInstruction insn) { - sb.append("if @").append(insn.getFirstOperand().getIndex()).append(" "); - switch (insn.getCondition()) { + public void jumpIf(BinaryBranchingCondition cond, VariableReader first, VariableReader second, + BasicBlockReader consequent, BasicBlockReader alternative) { + sb.append("if @").append(first.getIndex()).append(" "); + switch (cond) { case EQUAL: case REFERENCE_EQUAL: sb.append("=="); @@ -179,119 +199,125 @@ public class InstructionStringifier implements InstructionVisitor { sb.append("!="); break; } - sb.append("@").append(insn.getSecondOperand().getIndex()) - .append(" then goto $").append(insn.getConsequent().getIndex()) - .append(" else goto $").append(insn.getAlternative().getIndex()); + sb.append("@").append(second.getIndex()).append(" then goto $").append(consequent.getIndex()) + .append(" else goto $").append(alternative.getIndex()); } @Override - public void visit(JumpInstruction insn) { - sb.append("goto $").append(insn.getTarget().getIndex()); + public void jump(BasicBlockReader target) { + sb.append("goto $").append(target.getIndex()); } @Override - public void visit(SwitchInstruction insn) { - sb.append("switch @").append(insn.getCondition().getIndex()).append(" "); - List entries = insn.getEntries(); - for (int i = 0; i < entries.size(); ++i) { + public void choose(VariableReader condition, List table, + BasicBlockReader defaultTarget) { + sb.append("switch @").append(condition.getIndex()).append(" "); + for (int i = 0; i < table.size(); ++i) { if (i > 0) { sb.append("; "); } - SwitchTableEntry entry = entries.get(i); - sb.append("case ").append(entry.getCondition()).append(": goto $") - .append(entry.getTarget()); + SwitchTableEntryReader entry = table.get(i); + sb.append("case ").append(entry.getCondition()).append(": goto $").append(entry.getTarget()); } - sb.append(", default: goto $").append(insn.getDefaultTarget()); + sb.append(", default: goto $").append(defaultTarget.getIndex()); } @Override - public void visit(ExitInstruction insn) { + public void exit(VariableReader valueToReturn) { sb.append("return"); - if (insn.getValueToReturn() != null) { - sb.append(" @").append(insn.getValueToReturn().getIndex()); + if (valueToReturn != null) { + sb.append(" @").append(valueToReturn.getIndex()); } } @Override - public void visit(RaiseInstruction insn) { - sb.append("throw @").append(insn.getException().getIndex()); + public void raise(VariableReader exception) { + sb.append("throw @").append(exception.getIndex()); } @Override - public void visit(ConstructArrayInstruction insn) { - sb.append("@").append(insn.getReceiver().getIndex()).append(" = new ") - .append(insn.getItemType()).append("[@").append(insn.getSize().getIndex()) - .append(']'); + public void createArray(VariableReader receiver, ValueType itemType, VariableReader size) { + sb.append("@").append(receiver.getIndex()).append(" = new ").append(itemType).append("[@") + .append(size.getIndex()).append(']'); } @Override - public void visit(ConstructInstruction insn) { - sb.append("@").append(insn.getReceiver().getIndex()).append(" = new ") - .append(insn.getType()).append("()"); - } - - @Override - public void visit(ConstructMultiArrayInstruction insn) { - sb.append("@").append(insn.getReceiver().getIndex()).append(" = new ") - .append(insn.getItemType()).append("["); - List dimensions = insn.getDimensions(); + public void createArray(VariableReader receiver, ValueType itemType, List dimensions) { + sb.append("@").append(receiver.getIndex()).append(" = new ").append(itemType).append("["); for (int i = 0; i < dimensions.size(); ++i) { if (i > 0) { sb.append(", "); } - Variable dimension = dimensions.get(i); - sb.append("@").append(dimension.getIndex()); + sb.append("@").append(dimensions.get(i).getIndex()); } sb.append("]"); } @Override - public void visit(GetFieldInstruction insn) { - sb.append("@").append(insn.getReceiver().getIndex()).append(" := "); - if (insn.getInstance() != null) { - sb.append("@").append(insn.getInstance().getIndex()); + public void create(VariableReader receiver, String type) { + sb.append("@").append(receiver.getIndex()).append(" = new ").append(type).append("()"); + } + + @Override + public void getField(VariableReader receiver, VariableReader instance, FieldReference field, ValueType fieldType) { + sb.append("@").append(receiver.getIndex()).append(" := "); + if (instance != null) { + sb.append("@").append(instance.getIndex()); } else { - sb.append(insn.getField().getClassName()); + sb.append(field.getClassName()); } - sb.append(".").append(insn.getField().getFieldName()); + sb.append(".").append(field.getFieldName()); } @Override - public void visit(PutFieldInstruction insn) { - if (insn.getInstance() != null) { - sb.append("@").append(insn.getInstance().getIndex()); + public void putField(VariableReader instance, FieldReference field, VariableReader value) { + if (instance != null) { + sb.append("@").append(instance.getIndex()); } else { - sb.append(insn.getField().getClassName()); + sb.append(field.getClassName()); } - sb.append(".").append(insn.getField().getFieldName()).append(" := @").append(insn.getValue().getIndex()); + sb.append(".").append(field.getFieldName()).append(" := @").append(value.getIndex()); } @Override - public void visit(GetElementInstruction insn) { - sb.append("@").append(insn.getReceiver().getIndex()).append(" := @") - .append(insn.getArray().getIndex()).append("[@") - .append(insn.getIndex().getIndex()).append("]"); + public void arrayLength(VariableReader receiver, VariableReader array) { + sb.append("@").append(receiver.getIndex()).append(" := @").append(array.getIndex()).append(".length"); } @Override - public void visit(PutElementInstruction insn) { - sb.append("@").append(insn.getArray().getIndex()).append("[@") - .append(insn.getIndex().getIndex()).append("] := @") - .append(insn.getValue().getIndex()); + public void cloneArray(VariableReader receiver, VariableReader array) { + sb.append("@").append(receiver.getIndex()).append("@").append(array.getIndex()).append(".clone()"); } @Override - public void visit(InvokeInstruction insn) { - if (insn.getReceiver() != null) { - sb.append("@").append(insn.getReceiver().getIndex()).append(" := "); + public void unwrapArray(VariableReader receiver, VariableReader array, ArrayElementType elementType) { + sb.append("@").append(receiver.getIndex()).append(" := @").append(array.getIndex()).append(".data"); + } + + @Override + public void getElement(VariableReader receiver, VariableReader array, VariableReader index) { + sb.append("@").append(receiver.getIndex()).append(" := @").append(array.getIndex()).append("[@") + .append(index.getIndex()).append("]"); + } + + @Override + public void putElement(VariableReader array, VariableReader index, VariableReader value) { + sb.append("@").append(array.getIndex()).append("[@").append(index.getIndex()).append("] := @") + .append(value.getIndex()); + } + + @Override + public void invoke(VariableReader receiver, VariableReader instance, MethodReference method, + List arguments, InvocationType type) { + if (receiver != null) { + sb.append("@").append(receiver.getIndex()).append(" := "); } - if (insn.getInstance() != null) { - sb.append("@").append(insn.getInstance().getIndex()); + if (instance != null) { + sb.append("@").append(instance.getIndex()); } else { - sb.append(insn.getMethod().getClassName()); + sb.append(method.getClassName()); } - sb.append(".").append(insn.getMethod().getName()).append("("); - List arguments = insn.getArguments(); + sb.append(".").append(method.getName()).append("("); for (int i = 0; i < arguments.size(); ++i) { if (i > 0) { sb.append(", "); @@ -302,53 +328,13 @@ public class InstructionStringifier implements InstructionVisitor { } @Override - public void visit(IsInstanceInstruction insn) { - sb.append("@").append(insn.getReceiver().getIndex()).append(" := @") - .append(insn.getValue().getIndex()).append(" instanceof ").append(insn.getType()); + public void isInstance(VariableReader receiver, VariableReader value, ValueType type) { + sb.append("@").append(receiver.getIndex()).append(" := @").append(value.getIndex()) + .append(" instanceof ").append(type); } @Override - public void visit(CastInstruction insn) { - sb.append("@").append(insn.getReceiver().getIndex()).append(" := cast @") - .append(insn.getValue().getIndex()).append(" to ") - .append(insn.getTargetType()); - } - - @Override - public void visit(CastNumberInstruction insn) { - sb.append("@").append(insn.getReceiver().getIndex()).append(" := cast @") - .append(insn.getValue().getIndex()) - .append(" from ").append(insn.getSourceType()) - .append(" to ").append(insn.getTargetType()); - } - - @Override - public void visit(CastIntegerInstruction insn) { - sb.append("@").append(insn.getReceiver().getIndex()).append(" := cast @") - .append(insn.getValue().getIndex()) - .append(" from INT to ").append(insn.getTargetType()); - } - - @Override - public void visit(UnwrapArrayInstruction insn) { - sb.append("@").append(insn.getReceiver().getIndex()).append(" := @") - .append(insn.getArray().getIndex()).append(".data"); - } - - @Override - public void visit(ArrayLengthInstruction insn) { - sb.append("@").append(insn.getReceiver().getIndex()).append(" := @") - .append(insn.getArray().getIndex()).append(".length"); - } - - @Override - public void visit(CloneArrayInstruction insn) { - sb.append("@").append(insn.getReceiver().getIndex()).append("@") - .append(insn.getArray().getIndex()).append(".clone()"); - } - - @Override - public void visit(InitClassInstruction insn) { - sb.append("initclass ").append(insn.getClassName()); + public void initClass(String className) { + sb.append("initclass ").append(className); } } diff --git a/teavm-core/src/main/java/org/teavm/model/util/ListingBuilder.java b/teavm-core/src/main/java/org/teavm/model/util/ListingBuilder.java index c11872c09..382dd4e8b 100644 --- a/teavm-core/src/main/java/org/teavm/model/util/ListingBuilder.java +++ b/teavm-core/src/main/java/org/teavm/model/util/ListingBuilder.java @@ -23,29 +23,29 @@ import org.teavm.model.*; * @author Alexey Andreev */ public class ListingBuilder { - public String buildListing(Program program, String prefix) { + public String buildListing(ProgramReader program, String prefix) { StringBuilder sb = new StringBuilder(); InstructionStringifier stringifier = new InstructionStringifier(sb); for (int i = 0; i < program.basicBlockCount(); ++i) { - BasicBlock block = program.basicBlockAt(i); + BasicBlockReader block = program.basicBlockAt(i); sb.append(prefix).append("$").append(i).append(":\n"); - for (Phi phi : block.getPhis()) { + for (PhiReader phi : block.readPhis()) { sb.append(prefix).append(" "); sb.append("@").append(phi.getReceiver().getIndex()).append(" := "); - List incomings = phi.getIncomings(); + List incomings = phi.readIncomings(); for (int j = 0; j < incomings.size(); ++j) { if (j > 0) { sb.append(", "); } - Incoming incoming = incomings.get(j); + IncomingReader incoming = incomings.get(j); sb.append("@").append(incoming.getValue().getIndex()).append(" from ") .append("$").append(incoming.getSource().getIndex()); } sb.append("\n"); } - for (Instruction insn : block.getInstructions()) { + for (int j = 0; j < block.instructionCount(); ++j) { sb.append(prefix).append(" "); - insn.acceptVisitor(stringifier); + block.readInstruction(j, stringifier); sb.append("\n"); } } diff --git a/teavm-html4j/src/main/java/org/teavm/html4j/JavaScriptBodyDependency.java b/teavm-html4j/src/main/java/org/teavm/html4j/JavaScriptBodyDependency.java index 72d742454..40a1752e0 100644 --- a/teavm-html4j/src/main/java/org/teavm/html4j/JavaScriptBodyDependency.java +++ b/teavm-html4j/src/main/java/org/teavm/html4j/JavaScriptBodyDependency.java @@ -48,10 +48,11 @@ public class JavaScriptBodyDependency implements DependencyListener { } @Override - public void methodAchieved(DependencyChecker dependencyChecker, MethodGraph graph) { - ClassHolder cls = dependencyChecker.getClassSource().get(graph.getReference().getClassName()); - MethodHolder method = cls.getMethod(graph.getReference().getDescriptor()); - AnnotationReader annot = method.getAnnotations().get(JavaScriptBody.class.getName()); + public void methodAchieved(DependencyChecker dependencyChecker, MethodDependency graph) { + if (graph.isMissing()) { + return; + } + AnnotationReader annot = graph.getMethod().getAnnotations().get(JavaScriptBody.class.getName()); if (annot != null) { includeDefaultDependencies(dependencyChecker); AnnotationValue javacall = annot.getValue("javacall"); @@ -75,12 +76,12 @@ public class JavaScriptBodyDependency implements DependencyListener { } private void includeDefaultDependencies(DependencyChecker dependencyChecker) { - dependencyChecker.attachMethodGraph(JavaScriptConvGenerator.fromJsMethod, DependencyStack.ROOT); - dependencyChecker.attachMethodGraph(JavaScriptConvGenerator.toJsMethod, DependencyStack.ROOT); - dependencyChecker.attachMethodGraph(JavaScriptConvGenerator.intValueMethod, DependencyStack.ROOT); - dependencyChecker.attachMethodGraph(JavaScriptConvGenerator.valueOfIntMethod, DependencyStack.ROOT); - dependencyChecker.attachMethodGraph(JavaScriptConvGenerator.booleanValueMethod, DependencyStack.ROOT); - dependencyChecker.attachMethodGraph(JavaScriptConvGenerator.valueOfBooleanMethod, DependencyStack.ROOT); + dependencyChecker.linkMethod(JavaScriptConvGenerator.fromJsMethod, DependencyStack.ROOT); + dependencyChecker.linkMethod(JavaScriptConvGenerator.toJsMethod, DependencyStack.ROOT); + dependencyChecker.linkMethod(JavaScriptConvGenerator.intValueMethod, DependencyStack.ROOT); + dependencyChecker.linkMethod(JavaScriptConvGenerator.valueOfIntMethod, DependencyStack.ROOT); + dependencyChecker.linkMethod(JavaScriptConvGenerator.booleanValueMethod, DependencyStack.ROOT); + dependencyChecker.linkMethod(JavaScriptConvGenerator.valueOfBooleanMethod, DependencyStack.ROOT); } @Override @@ -114,9 +115,9 @@ public class JavaScriptBodyDependency implements DependencyListener { private class GeneratorJsCallback extends JsCallback { private ClassReaderSource classSource; private DependencyChecker dependencyChecker; - private MethodGraph caller; + private MethodDependency caller; public GeneratorJsCallback(ClassReaderSource classSource, DependencyChecker dependencyChecker, - MethodGraph caller) { + MethodDependency caller) { this.classSource = classSource; this.dependencyChecker = dependencyChecker; this.caller = caller; @@ -126,13 +127,13 @@ public class JavaScriptBodyDependency implements DependencyListener { MethodReader reader = findMethod(classSource, fqn, desc); if (reader != null) { if (reader.hasModifier(ElementModifier.STATIC) || reader.hasModifier(ElementModifier.FINAL)) { - MethodGraph graph = dependencyChecker.attachMethodGraph(reader.getReference(), caller.getStack()); + MethodDependency graph = dependencyChecker.linkMethod(reader.getReference(), caller.getStack()); for (int i = 0; i <= graph.getParameterCount(); ++i) { allClassesNode.connect(graph.getVariable(i)); } } else { - allClassesNode.addConsumer(new VirtualCallbackConsumer(classSource, dependencyChecker, desc, - caller)); + allClassesNode.addConsumer(new VirtualCallbackConsumer(dependencyChecker, + reader.getReference(), caller)); } } return ""; @@ -140,24 +141,21 @@ public class JavaScriptBodyDependency implements DependencyListener { } private class VirtualCallbackConsumer implements DependencyConsumer { - private ClassReaderSource classSource; + private String superClass; private DependencyChecker dependencyChecker; - private MethodDescriptor desc; - private MethodGraph caller; - public VirtualCallbackConsumer(ClassReaderSource classSource, DependencyChecker dependencyChecker, - MethodDescriptor desc, MethodGraph caller) { - this.classSource = classSource; + private MethodReference superMethod; + private MethodDependency caller; + public VirtualCallbackConsumer(DependencyChecker dependencyChecker, MethodReference superMethod, + MethodDependency caller) { this.dependencyChecker = dependencyChecker; - this.desc = desc; + this.superMethod = superMethod; this.caller = caller; } @Override public void consume(String type) { - MethodReader reader = findMethod(classSource, type, desc); - if (reader != null) { - MethodGraph graph = dependencyChecker.attachMethodGraph(reader.getReference(), caller.getStack()); - for (int i = 0; i < graph.getParameterCount(); ++i) { - allClassesNode.connect(graph.getVariable(i)); - } + MethodReference method = new MethodReference(type, superMethod.getDescriptor()); + MethodDependency graph = dependencyChecker.linkMethod(method, caller.getStack()); + for (int i = 0; i < graph.getParameterCount(); ++i) { + allClassesNode.connect(graph.getVariable(i)); } } } diff --git a/teavm-html4j/src/test/java/net/java/html/js/tests/JavaScriptBodyTests.java b/teavm-html4j/src/test/java/net/java/html/js/tests/JavaScriptBodyTests.java index 49317dab8..bb305d6da 100644 --- a/teavm-html4j/src/test/java/net/java/html/js/tests/JavaScriptBodyTests.java +++ b/teavm-html4j/src/test/java/net/java/html/js/tests/JavaScriptBodyTests.java @@ -317,15 +317,15 @@ public class JavaScriptBodyTests { private static class R implements Runnable { int cnt; - //private final Thread initThread; + private final Thread initThread; public R() { - //initThread = Thread.currentThread(); + initThread = Thread.currentThread(); } @Override public void run() { - //assert initThread == Thread.currentThread() : "Expecting to run in " + initThread + " but running in " + Thread.currentThread(); + assert initThread == Thread.currentThread() : "Expecting to run in " + initThread + " but running in " + Thread.currentThread(); cnt++; } } diff --git a/teavm-jso/src/main/java/org/teavm/javascript/ni/JSNativeGenerator.java b/teavm-jso/src/main/java/org/teavm/javascript/ni/JSNativeGenerator.java index ada8d5390..24449a955 100644 --- a/teavm-jso/src/main/java/org/teavm/javascript/ni/JSNativeGenerator.java +++ b/teavm-jso/src/main/java/org/teavm/javascript/ni/JSNativeGenerator.java @@ -20,14 +20,11 @@ import org.teavm.codegen.SourceWriter; import org.teavm.dependency.DependencyChecker; import org.teavm.dependency.DependencyConsumer; import org.teavm.dependency.DependencyPlugin; -import org.teavm.dependency.MethodGraph; +import org.teavm.dependency.MethodDependency; import org.teavm.javascript.ast.ConstantExpr; import org.teavm.javascript.ast.Expr; import org.teavm.javascript.ast.InvocationExpr; -import org.teavm.model.ClassHolder; -import org.teavm.model.FieldReference; -import org.teavm.model.MethodHolder; -import org.teavm.model.MethodReference; +import org.teavm.model.*; /** * @@ -97,7 +94,7 @@ public class JSNativeGenerator implements Generator, Injector, DependencyPlugin } @Override - public void methodAchieved(final DependencyChecker checker, final MethodGraph graph) { + public void methodAchieved(final DependencyChecker checker, final MethodDependency graph) { for (int i = 0; i < graph.getReference().parameterCount(); ++i) { graph.getVariable(i).addConsumer(new DependencyConsumer() { @Override public void consume(String type) { @@ -107,11 +104,14 @@ public class JSNativeGenerator implements Generator, Injector, DependencyPlugin } } - private void achieveFunctorMethods(DependencyChecker checker, String type, MethodGraph caller) { - ClassHolder cls = checker.getClassSource().get(type); + private void achieveFunctorMethods(DependencyChecker checker, String type, MethodDependency caller) { + if (caller.isMissing()) { + return; + } + ClassReader cls = checker.getClassSource().get(type); if (cls != null) { - for (MethodHolder method : cls.getMethods()) { - checker.attachMethodGraph(method.getReference(), caller.getStack()); + for (MethodReader method : cls.getMethods()) { + checker.linkMethod(method.getReference(), caller.getStack()); } } }