diff --git a/teavm-cli/src/main/java/org/teavm/cli/TeaVMRunner.java b/teavm-cli/src/main/java/org/teavm/cli/TeaVMRunner.java index 440c15ede..a3b7656b9 100644 --- a/teavm-cli/src/main/java/org/teavm/cli/TeaVMRunner.java +++ b/teavm-cli/src/main/java/org/teavm/cli/TeaVMRunner.java @@ -152,6 +152,7 @@ public final class TeaVMRunner { try { tool.generate(); + tool.checkForMissingItems(); } catch (Exception e) { e.printStackTrace(System.err); System.exit(-2); diff --git a/teavm-core/src/main/java/org/teavm/dependency/ClassDependency.java b/teavm-core/src/main/java/org/teavm/dependency/ClassDependency.java new file mode 100644 index 000000000..17b85d577 --- /dev/null +++ b/teavm-core/src/main/java/org/teavm/dependency/ClassDependency.java @@ -0,0 +1,61 @@ +/* + * 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 org.teavm.model.ClassReader; + +/** + * + * @author Alexey Andreev + */ +public class ClassDependency implements ClassDependencyInfo { + private DependencyChecker checker; + private String className; + private DependencyStack stack; + private ClassReader classReader; + + ClassDependency(DependencyChecker checker, String className, DependencyStack stack, ClassReader classReader) { + this.checker = checker; + this.className = className; + this.stack = stack; + this.classReader = classReader; + } + + @Override + public String getClassName() { + return className; + } + + @Override + public boolean isMissing() { + return classReader == null; + } + + public ClassReader getClassReader() { + return classReader; + } + + @Override + public DependencyStack getStack() { + return stack; + } + + public void initClass(DependencyStack stack) { + if (!isMissing()) { + checker.initClass(this, stack); + } + } +} diff --git a/teavm-core/src/main/java/org/teavm/dependency/ClassDependencyInfo.java b/teavm-core/src/main/java/org/teavm/dependency/ClassDependencyInfo.java new file mode 100644 index 000000000..46ecc9c72 --- /dev/null +++ b/teavm-core/src/main/java/org/teavm/dependency/ClassDependencyInfo.java @@ -0,0 +1,28 @@ +/* + * 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 ClassDependencyInfo { + String getClassName(); + + boolean isMissing(); + + DependencyStack getStack(); +} diff --git a/teavm-core/src/main/java/org/teavm/dependency/DependencyAgent.java b/teavm-core/src/main/java/org/teavm/dependency/DependencyAgent.java index c0d5f2908..b8442f5dc 100644 --- a/teavm-core/src/main/java/org/teavm/dependency/DependencyAgent.java +++ b/teavm-core/src/main/java/org/teavm/dependency/DependencyAgent.java @@ -35,7 +35,7 @@ public interface DependencyAgent extends DependencyInfo, ServiceRepository { MethodDependency linkMethod(MethodReference methodRef, DependencyStack stack); - void initClass(String className, final DependencyStack stack); + ClassDependency linkClass(String className, final DependencyStack stack); FieldDependency linkField(FieldReference fieldRef, DependencyStack stack); } 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 51821a750..ae2599d6d 100644 --- a/teavm-core/src/main/java/org/teavm/dependency/DependencyChecker.java +++ b/teavm-core/src/main/java/org/teavm/dependency/DependencyChecker.java @@ -38,16 +38,16 @@ public class DependencyChecker implements DependencyInfo, DependencyAgent { private Map classStacks = new HashMap<>(); private CachedMapper methodCache; private CachedMapper fieldCache; - private Set achievableClasses = new HashSet<>(); - private Set initializedClasses = new HashSet<>(); + private CachedMapper classCache; private List listeners = new ArrayList<>(); private ServiceRepository services; private Queue tasks = new ArrayDeque<>(); - Map missingMethods = new HashMap<>(); - Map missingClasses = new HashMap<>(); - Map missingFields = new HashMap<>(); + Set missingMethods = new HashSet<>(); + Set missingClasses = new HashSet<>(); + Set missingFields = new HashSet<>(); List types = new ArrayList<>(); Map typeMap = new HashMap<>(); + private DependencyViolations dependencyViolations; public DependencyChecker(ClassReaderSource classSource, ClassLoader classLoader, ServiceRepository services) { this.classSource = new DependencyClassSource(classSource); @@ -83,6 +83,12 @@ public class DependencyChecker implements DependencyInfo, DependencyAgent { return createFieldNode(preimage, field, fieldStacks.get(preimage)); } }); + + classCache = new CachedMapper<>(new Mapper() { + @Override public ClassDependency map(String preimage) { + return createClassDependency(preimage, classStacks.get(preimage)); + } + }); methodCache.addKeyListener(new KeyListener() { @Override public void keyAdded(MethodReference key) { MethodDependency graph = methodCache.getKnown(key); @@ -104,6 +110,16 @@ public class DependencyChecker implements DependencyInfo, DependencyAgent { } } }); + classCache.addKeyListener(new KeyListener() { + @Override public void keyAdded(String key) { + ClassDependency classDep = classCache.getKnown(key); + if (!classDep.isMissing()) { + for (DependencyListener listener : listeners) { + listener.classAchieved(DependencyChecker.this, key); + } + } + } + }); } @Override @@ -183,15 +199,25 @@ public class DependencyChecker implements DependencyInfo, DependencyAgent { }); } - boolean achieveClass(String className, DependencyStack stack) { + @Override + public ClassDependency linkClass(String className, DependencyStack stack) { classStacks.put(className, stack); - if (!achievableClasses.add(className)) { - return false; + return classCache.map(className); + } + + private ClassDependency createClassDependency(String className, DependencyStack stack) { + ClassReader cls = classSource.get(className); + ClassDependency dependency = new ClassDependency(this, className, stack, cls); + if (dependency.isMissing()) { + missingClasses.add(dependency); } - for (DependencyListener listener : listeners) { - listener.classAchieved(this, className); + if (cls.getParent() != null) { + linkClass(cls.getParent(), stack); } - return true; + for (String ifaceName : cls.getInterfaces()) { + linkClass(ifaceName, stack); + } + return dependency; } @Override @@ -203,44 +229,15 @@ public class DependencyChecker implements DependencyInfo, DependencyAgent { return methodCache.map(methodRef); } - @Override - public void initClass(String className, final DependencyStack stack) { - classStacks.put(className, stack); - MethodDescriptor clinitDesc = new MethodDescriptor("", ValueType.VOID); - while (className != null) { - if (!initializedClasses.add(className)) { - break; - } - achieveClass(className, stack); - achieveInterfaces(className, stack); - ClassReader cls = classSource.get(className); - if (cls == null) { - missingClasses.put(className, stack); - return; - } - if (cls.getMethod(clinitDesc) != null) { - final MethodReference methodRef = new MethodReference(className, clinitDesc); - tasks.add(new Runnable() { - @Override public void run() { - linkMethod(methodRef, new DependencyStack(methodRef, stack)).use(); - } - }); - } - className = cls.getParent(); - } - } - - private void achieveInterfaces(String className, DependencyStack stack) { - classStacks.put(className, stack); - ClassReader cls = classSource.get(className); - if (cls == null) { - missingClasses.put(className, stack); - return; - } - for (String iface : cls.getInterfaces()) { - if (achieveClass(iface, stack)) { - achieveInterfaces(iface, stack); - } + void initClass(ClassDependency cls, final DependencyStack stack) { + ClassReader reader = cls.getClassReader(); + final MethodReader method = reader.getMethod(new MethodDescriptor("", void.class)); + if (method != null) { + tasks.add(new Runnable() { + @Override public void run() { + linkMethod(method.getReference(), stack); + } + }); } } @@ -315,7 +312,6 @@ public class DependencyChecker implements DependencyInfo, DependencyAgent { if (shouldLog) { thrown.setTag(methodRef + ":THROWN"); } - stack = new DependencyStack(methodRef, stack); final MethodDependency dep = new MethodDependency(this, parameterNodes, paramCount, resultNode, thrown, stack, method, methodRef); if (method != null) { @@ -325,26 +321,17 @@ public class DependencyChecker implements DependencyInfo, DependencyAgent { graphBuilder.buildGraph(dep); } }); - } else { - missingMethods.put(methodRef, stack); - } - if (method != null) { - final DependencyStack callerStack = stack; tasks.add(new Runnable() { @Override public void run() { - initClass(dep.getReference().getClassName(), callerStack); + linkClass(dep.getMethod().getOwnerName(), dep.getStack()); } }); - + } else { + missingMethods.add(dep); } return dep; } - @Override - public boolean isMethodAchievable(MethodReference methodRef) { - return methodCache.caches(methodRef); - } - @Override public Collection getAchievableMethods() { return methodCache.getCachedPreimages(); @@ -357,7 +344,7 @@ public class DependencyChecker implements DependencyInfo, DependencyAgent { @Override public Collection getAchievableClasses() { - return new HashSet<>(achievableClasses); + return classCache.getCachedPreimages(); } @Override @@ -371,18 +358,28 @@ public class DependencyChecker implements DependencyInfo, DependencyAgent { return fieldCache.getKnown(fieldRef); } - private FieldDependency createFieldNode(FieldReference fieldRef, FieldReader field, DependencyStack stack) { + @Override + public ClassDependency getClass(String className) { + return classCache.getKnown(className); + } + + private FieldDependency createFieldNode(final FieldReference fieldRef, FieldReader field, + final DependencyStack stack) { DependencyNode node = new DependencyNode(this); - if (field == null) { - missingFields.put(fieldRef, stack); - } if (shouldLog) { node.setTag(fieldRef.getClassName() + "#" + fieldRef.getFieldName()); } - if (field != null) { - initClass(fieldRef.getClassName(), stack); + FieldDependency dep = new FieldDependency(node, stack, field, fieldRef); + if (dep.isMissing()) { + missingFields.add(dep); + } else { + tasks.add(new Runnable() { + @Override public void run() { + linkClass(fieldRef.getClassName(), stack).initClass(stack); + } + }); } - return new FieldDependency(node, stack, field, fieldRef); + return dep; } private void activateDependencyPlugin(MethodDependency methodDep) { @@ -412,53 +409,23 @@ public class DependencyChecker implements DependencyInfo, DependencyAgent { return methodCache.getKnown(methodRef); } + public DependencyViolations getDependencyViolations() { + if (dependencyViolations == null) { + dependencyViolations = new DependencyViolations(missingMethods, missingClasses, missingFields); + } + return dependencyViolations; + } + public void checkForMissingItems() { - if (!hasMissingItems()) { - return; - } - StringBuilder sb = new StringBuilder(); - try { - showMissingItems(sb); - } catch (IOException e) { - throw new AssertionError("StringBuilder should not throw IOException"); - } - throw new IllegalStateException(sb.toString()); + getDependencyViolations().checkForMissingItems(); } public boolean hasMissingItems() { - return !missingClasses.isEmpty() || !missingMethods.isEmpty() || !missingFields.isEmpty(); + return getDependencyViolations().hasMissingItems(); } public void showMissingItems(Appendable sb) throws IOException { - List items = new ArrayList<>(); - Map stackMap = new HashMap<>(); - for (String cls : missingClasses.keySet()) { - stackMap.put(cls, missingClasses.get(cls)); - items.add(cls); - } - for (MethodReference method : missingMethods.keySet()) { - stackMap.put(method.toString(), missingMethods.get(method)); - items.add(method.toString()); - } - for (FieldReference field : missingFields.keySet()) { - stackMap.put(field.toString(), missingFields.get(field)); - items.add(field.toString()); - } - Collections.sort(items); - sb.append("Can't compile due to the following items missing:\n"); - for (String item : items) { - sb.append(" ").append(item).append("\n"); - DependencyStack stack = stackMap.get(item); - if (stack == null) { - sb.append(" at unknown location\n"); - } else { - while (stack.getMethod() != null) { - sb.append(" at " + stack.getMethod() + "\n"); - stack = stack.getCause(); - } - } - sb.append('\n'); - } + getDependencyViolations().showMissingItems(sb); } public void processDependencies() { 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 cd0e00033..2532b8e4d 100644 --- a/teavm-core/src/main/java/org/teavm/dependency/DependencyGraphBuilder.java +++ b/teavm-core/src/main/java/org/teavm/dependency/DependencyGraphBuilder.java @@ -45,7 +45,6 @@ class DependencyGraphBuilder { if (method.getProgram() == null || method.getProgram().basicBlockCount() == 0) { return; } - callerStack = dep.getStack(); program = method.getProgram(); if (DependencyChecker.shouldLog) { System.out.println("Method achieved: " + method.getReference()); @@ -53,6 +52,7 @@ class DependencyGraphBuilder { } resultNode = dep.getResult(); nodes = dep.getVariables(); + callerStack = new DependencyStack(method.getReference(), dep.getStack()); for (int i = 0; i < program.basicBlockCount(); ++i) { BasicBlockReader block = program.basicBlockAt(i); currentExceptionConsumer = createExceptionConsumer(dep, block); @@ -66,7 +66,7 @@ class DependencyGraphBuilder { useRunners.add(new Runnable() { @Override public void run() { if (tryCatch.getExceptionType() != null) { - dependencyChecker.initClass(tryCatch.getExceptionType(), callerStack); + dependencyChecker.linkClass(tryCatch.getExceptionType(), callerStack); } } }); @@ -216,6 +216,7 @@ class DependencyGraphBuilder { private InstructionReader reader = new InstructionReader() { @Override public void location(InstructionLocation location) { + callerStack = new DependencyStack(callerStack.getMethod(), location, callerStack.getCause()); } @Override @@ -233,7 +234,7 @@ class DependencyGraphBuilder { final String className = ((ValueType.Object)cst).getClassName(); useRunners.add(new Runnable() { @Override public void run() { - dependencyChecker.initClass(className, callerStack); + dependencyChecker.linkClass(className, callerStack); } }); } @@ -355,7 +356,7 @@ class DependencyGraphBuilder { if (className != null) { useRunners.add(new Runnable() { @Override public void run() { - dependencyChecker.initClass(className, callerStack); + dependencyChecker.linkClass(className, callerStack); } }); } @@ -502,7 +503,7 @@ class DependencyGraphBuilder { final String className = ((ValueType.Object)type).getClassName(); useRunners.add(new Runnable() { @Override public void run() { - dependencyChecker.initClass(className, callerStack); + dependencyChecker.linkClass(className, callerStack); } }); } @@ -512,7 +513,7 @@ class DependencyGraphBuilder { public void initClass(final String className) { useRunners.add(new Runnable() { @Override public void run() { - dependencyChecker.initClass(className, callerStack); + dependencyChecker.linkClass(className, callerStack).initClass(callerStack); } }); } diff --git a/teavm-core/src/main/java/org/teavm/dependency/DependencyInfo.java b/teavm-core/src/main/java/org/teavm/dependency/DependencyInfo.java index c3b79f09e..25f59a580 100644 --- a/teavm-core/src/main/java/org/teavm/dependency/DependencyInfo.java +++ b/teavm-core/src/main/java/org/teavm/dependency/DependencyInfo.java @@ -29,8 +29,6 @@ public interface DependencyInfo { ClassLoader getClassLoader(); - boolean isMethodAchievable(MethodReference methodRef); - Collection getAchievableMethods(); Collection getAchievableFields(); @@ -40,4 +38,6 @@ public interface DependencyInfo { FieldDependencyInfo getField(FieldReference fieldRef); MethodDependencyInfo getMethod(MethodReference methodRef); + + ClassDependencyInfo getClass(String className); } diff --git a/teavm-core/src/main/java/org/teavm/dependency/DependencyStack.java b/teavm-core/src/main/java/org/teavm/dependency/DependencyStack.java index 1214d52a9..7072ddc44 100644 --- a/teavm-core/src/main/java/org/teavm/dependency/DependencyStack.java +++ b/teavm-core/src/main/java/org/teavm/dependency/DependencyStack.java @@ -74,6 +74,9 @@ public class DependencyStack { break; } else { sb.append(" used by " + stack.method); + if (stack.location != null) { + sb.append(" : ").append(stack.location.getLine()); + } stack = stack.cause; } } diff --git a/teavm-core/src/main/java/org/teavm/dependency/DependencyViolations.java b/teavm-core/src/main/java/org/teavm/dependency/DependencyViolations.java new file mode 100644 index 000000000..e04558d86 --- /dev/null +++ b/teavm-core/src/main/java/org/teavm/dependency/DependencyViolations.java @@ -0,0 +1,102 @@ +/* + * 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.io.IOException; +import java.util.*; + +/** + * + * @author Alexey Andreev + */ +public class DependencyViolations { + private final Set missingMethods; + private final Set missingClasses; + private final Set missingFields; + + DependencyViolations(Collection missingMethods, + Collection missingClasses, + Collection missingFields) { + this.missingMethods = Collections.unmodifiableSet(new HashSet<>(missingMethods)); + this.missingClasses = Collections.unmodifiableSet(new HashSet<>(missingClasses)); + this.missingFields = Collections.unmodifiableSet(new HashSet<>(missingFields)); + } + + public Set getMissingMethods() { + return missingMethods; + } + + public Set getMissingClasses() { + return missingClasses; + } + + public Set getMissingFields() { + return missingFields; + } + + public boolean hasMissingItems() { + return !missingMethods.isEmpty() || !missingClasses.isEmpty() || !missingFields.isEmpty(); + } + + public void checkForMissingItems() { + if (!hasMissingItems()) { + return; + } + StringBuilder sb = new StringBuilder(); + try { + showMissingItems(sb); + } catch (IOException e) { + throw new AssertionError("StringBuilder should not throw IOException"); + } + throw new IllegalStateException(sb.toString()); + } + + public void showMissingItems(Appendable sb) throws IOException { + List items = new ArrayList<>(); + Map stackMap = new HashMap<>(); + for (ClassDependencyInfo cls : missingClasses) { + stackMap.put(cls.getClassName(), cls.getStack()); + items.add(cls.getClassName()); + } + for (MethodDependencyInfo method : missingMethods) { + stackMap.put(method.getReference().toString(), method.getStack()); + items.add(method.getReference().toString()); + } + for (FieldDependencyInfo field : missingFields) { + stackMap.put(field.getReference().toString(), field.getStack()); + items.add(field.getReference().toString()); + } + Collections.sort(items); + sb.append("Can't compile due to the following items missing:\n"); + for (String item : items) { + sb.append(" ").append(item).append("\n"); + DependencyStack stack = stackMap.get(item); + if (stack == null) { + sb.append(" at unknown location\n"); + } else { + while (stack.getMethod() != null) { + sb.append(" at ").append(stack.getMethod().toString()); + if (stack.getLocation() != null) { + sb.append(":").append(String.valueOf(stack.getLocation().getLine())); + } + sb.append("\n"); + stack = stack.getCause(); + } + } + sb.append('\n'); + } + } +} diff --git a/teavm-core/src/main/java/org/teavm/dependency/FieldDependency.java b/teavm-core/src/main/java/org/teavm/dependency/FieldDependency.java index 9c820aa33..af5fd8270 100644 --- a/teavm-core/src/main/java/org/teavm/dependency/FieldDependency.java +++ b/teavm-core/src/main/java/org/teavm/dependency/FieldDependency.java @@ -40,6 +40,7 @@ public class FieldDependency implements FieldDependencyInfo { return value; } + @Override public DependencyStack getStack() { return stack; } @@ -53,6 +54,7 @@ public class FieldDependency implements FieldDependencyInfo { return reference; } + @Override public boolean isMissing() { return field == null; } diff --git a/teavm-core/src/main/java/org/teavm/dependency/FieldDependencyInfo.java b/teavm-core/src/main/java/org/teavm/dependency/FieldDependencyInfo.java index e6decab32..80f1ce936 100644 --- a/teavm-core/src/main/java/org/teavm/dependency/FieldDependencyInfo.java +++ b/teavm-core/src/main/java/org/teavm/dependency/FieldDependencyInfo.java @@ -25,4 +25,8 @@ public interface FieldDependencyInfo { ValueDependencyInfo getValue(); FieldReference getReference(); + + boolean isMissing(); + + DependencyStack getStack(); } diff --git a/teavm-core/src/main/java/org/teavm/dependency/MethodDependency.java b/teavm-core/src/main/java/org/teavm/dependency/MethodDependency.java index 09955e1bb..f68aa72dd 100644 --- a/teavm-core/src/main/java/org/teavm/dependency/MethodDependency.java +++ b/teavm-core/src/main/java/org/teavm/dependency/MethodDependency.java @@ -82,6 +82,7 @@ public class MethodDependency implements MethodDependencyInfo { return thrown; } + @Override public DependencyStack getStack() { return stack; } @@ -95,6 +96,7 @@ public class MethodDependency implements MethodDependencyInfo { return method; } + @Override public boolean isMissing() { return method == null; } diff --git a/teavm-core/src/main/java/org/teavm/dependency/MethodDependencyInfo.java b/teavm-core/src/main/java/org/teavm/dependency/MethodDependencyInfo.java index 723800360..4f06ebfec 100644 --- a/teavm-core/src/main/java/org/teavm/dependency/MethodDependencyInfo.java +++ b/teavm-core/src/main/java/org/teavm/dependency/MethodDependencyInfo.java @@ -37,4 +37,8 @@ public interface MethodDependencyInfo { MethodReference getReference(); boolean isUsed(); + + boolean isMissing(); + + DependencyStack getStack(); } diff --git a/teavm-core/src/main/java/org/teavm/model/BasicBlock.java b/teavm-core/src/main/java/org/teavm/model/BasicBlock.java index 066df2651..2f5dd5e1e 100644 --- a/teavm-core/src/main/java/org/teavm/model/BasicBlock.java +++ b/teavm-core/src/main/java/org/teavm/model/BasicBlock.java @@ -180,7 +180,12 @@ public class BasicBlock implements BasicBlockReader { @Override public void readAllInstructions(InstructionReader reader) { InstructionReadVisitor visitor = new InstructionReadVisitor(reader); + InstructionLocation location = null; for (Instruction insn : instructions) { + if (!Objects.equals(location, insn.getLocation())) { + location = insn.getLocation(); + reader.location(location); + } insn.acceptVisitor(visitor); } } diff --git a/teavm-core/src/main/java/org/teavm/tooling/TeaVMTool.java b/teavm-core/src/main/java/org/teavm/tooling/TeaVMTool.java index 09090cdcb..4a3df76f3 100644 --- a/teavm-core/src/main/java/org/teavm/tooling/TeaVMTool.java +++ b/teavm-core/src/main/java/org/teavm/tooling/TeaVMTool.java @@ -26,6 +26,7 @@ import org.teavm.cache.DiskRegularMethodNodeCache; import org.teavm.cache.FileSymbolTable; import org.teavm.debugging.information.DebugInformation; import org.teavm.debugging.information.DebugInformationBuilder; +import org.teavm.dependency.DependencyViolations; import org.teavm.javascript.RenderingContext; import org.teavm.model.*; import org.teavm.parsing.ClasspathClassHolderSource; @@ -61,6 +62,7 @@ public class TeaVMTool { private FileSymbolTable fileTable; private boolean cancelled; private TeaVMProgressListener progressListener; + private TeaVM vm; public File getTargetDirectory() { return targetDirectory; @@ -215,7 +217,7 @@ public class TeaVMTool { } else { vmBuilder.setClassLoader(classLoader).setClassSource(new ClasspathClassHolderSource(classLoader)); } - TeaVM vm = vmBuilder.build(); + vm = vmBuilder.build(); if (progressListener != null) { vm.setProgressListener(progressListener); } @@ -271,7 +273,10 @@ public class TeaVMTool { cancelled = true; return; } - vm.checkForMissingItems(); + if (vm.hasMissingItems()) { + log.info("Missing items found"); + return; + } log.info("JavaScript file successfully built"); if (debugInformationGenerated) { DebugInformation debugInfo = debugEmitter.getDebugInformation(); @@ -319,6 +324,14 @@ public class TeaVMTool { } } + public DependencyViolations getDependencyViolations() { + return vm.getDependencyViolations(); + } + + public void checkForMissingItems() { + vm.checkForMissingItems(); + } + private AbstractRendererListener runtimeInjector = new AbstractRendererListener() { @Override public void begin(RenderingContext context, BuildTarget buildTarget) throws IOException { diff --git a/teavm-core/src/main/java/org/teavm/vm/TeaVM.java b/teavm-core/src/main/java/org/teavm/vm/TeaVM.java index 1ac48a857..ca54e98d1 100644 --- a/teavm-core/src/main/java/org/teavm/vm/TeaVM.java +++ b/teavm-core/src/main/java/org/teavm/vm/TeaVM.java @@ -232,7 +232,7 @@ public class TeaVM implements TeaVMHost, ServiceRepository { } TeaVMEntryPoint entryPoint = new TeaVMEntryPoint(name, ref, dependencyChecker.linkMethod(ref, DependencyStack.ROOT)); - dependencyChecker.initClass(ref.getClassName(), DependencyStack.ROOT); + dependencyChecker.linkClass(ref.getClassName(), DependencyStack.ROOT).initClass(DependencyStack.ROOT); if (name != null) { entryPoints.put(name, entryPoint); } @@ -258,7 +258,7 @@ public class TeaVM implements TeaVMHost, ServiceRepository { public TeaVMEntryPoint linkMethod(MethodReference ref) { TeaVMEntryPoint entryPoint = new TeaVMEntryPoint("", ref, dependencyChecker.linkMethod(ref, DependencyStack.ROOT)); - dependencyChecker.initClass(ref.getClassName(), DependencyStack.ROOT); + dependencyChecker.linkClass(ref.getClassName(), DependencyStack.ROOT).initClass(DependencyStack.ROOT); return entryPoint; } @@ -267,12 +267,12 @@ public class TeaVM implements TeaVMHost, ServiceRepository { throw new IllegalArgumentException("Class with public name `" + name + "' already defined for class " + className); } - dependencyChecker.initClass(className, DependencyStack.ROOT); + dependencyChecker.linkClass(className, DependencyStack.ROOT).initClass(DependencyStack.ROOT); exportedClasses.put(name, className); } public void linkType(String className) { - dependencyChecker.initClass(className, DependencyStack.ROOT); + dependencyChecker.linkClass(className, DependencyStack.ROOT).initClass(DependencyStack.ROOT); } /** @@ -303,6 +303,10 @@ public class TeaVM implements TeaVMHost, ServiceRepository { dependencyChecker.showMissingItems(target); } + public DependencyViolations getDependencyViolations() { + return dependencyChecker.getDependencyViolations(); + } + /** *

After building checks whether the build has failed due to some missing items (classes, methods and fields). * If it has failed, throws exception, containing report on all missing items. diff --git a/teavm-eclipse/teavm-eclipse-plugin/src/main/java/org/teavm/eclipse/TeaVMBuilder.java b/teavm-eclipse/teavm-eclipse-plugin/src/main/java/org/teavm/eclipse/TeaVMBuilder.java index 0f44cd2db..d4736087f 100644 --- a/teavm-eclipse/teavm-eclipse-plugin/src/main/java/org/teavm/eclipse/TeaVMBuilder.java +++ b/teavm-eclipse/teavm-eclipse-plugin/src/main/java/org/teavm/eclipse/TeaVMBuilder.java @@ -39,6 +39,7 @@ public class TeaVMBuilder extends IncrementalProjectBuilder { tool.setProgressListener(new TeaVMEclipseProgressListener(monitor)); try { tool.generate(); + tool.checkForMissingItems(); } catch (TeaVMToolException e) { throw new CoreException(TeaVMEclipsePlugin.makeError(e)); } diff --git a/teavm-html4j/src/main/java/org/teavm/html4j/EntryPointGenerator.java b/teavm-html4j/src/main/java/org/teavm/html4j/EntryPointGenerator.java index b6cfc9256..4d1823f9b 100644 --- a/teavm-html4j/src/main/java/org/teavm/html4j/EntryPointGenerator.java +++ b/teavm-html4j/src/main/java/org/teavm/html4j/EntryPointGenerator.java @@ -69,7 +69,7 @@ public class EntryPointGenerator extends AbstractRendererListener implements Dep @Override public void started(DependencyAgent agent) { for (String className : classesToLoad) { - agent.initClass(className, DependencyStack.ROOT); + agent.linkClass(className, DependencyStack.ROOT).initClass(DependencyStack.ROOT); } } diff --git a/teavm-maven-plugin/src/main/java/org/teavm/maven/BuildJavascriptMojo.java b/teavm-maven-plugin/src/main/java/org/teavm/maven/BuildJavascriptMojo.java index 3a7d431e2..5bb42851a 100644 --- a/teavm-maven-plugin/src/main/java/org/teavm/maven/BuildJavascriptMojo.java +++ b/teavm-maven-plugin/src/main/java/org/teavm/maven/BuildJavascriptMojo.java @@ -210,6 +210,7 @@ public class BuildJavascriptMojo extends AbstractMojo { tool.setDebugInformationGenerated(debugInformationGenerated); tool.setSourceMapsFileGenerated(sourceMapsGenerated); tool.generate(); + tool.checkForMissingItems(); } catch (RuntimeException e) { throw new MojoExecutionException("Unexpected error occured", e); } catch (TeaVMToolException e) { diff --git a/teavm-samples/src/main/java/org/teavm/samples/HelloWorld.java b/teavm-samples/src/main/java/org/teavm/samples/HelloWorld.java index c8255a95b..907667ba7 100644 --- a/teavm-samples/src/main/java/org/teavm/samples/HelloWorld.java +++ b/teavm-samples/src/main/java/org/teavm/samples/HelloWorld.java @@ -40,6 +40,7 @@ public final class HelloWorld { document = window.getDocument(); body = document.getDocumentElement().getElementsByTagName("body").item(0); createButton(); + new Thread().start(); } private static void createButton() {