Further work on diagnostics API

This commit is contained in:
Alexey Andreev 2014-12-09 18:43:23 +04:00
parent 30781bb16e
commit 0945c27f16
7 changed files with 43 additions and 96 deletions

View File

@ -15,9 +15,8 @@
*/ */
package org.teavm.dependency; package org.teavm.dependency;
import org.teavm.model.CallLocation;
import org.teavm.model.ClassReader; import org.teavm.model.ClassReader;
import org.teavm.model.InstructionLocation;
import org.teavm.model.MethodReference;
/** /**
* *
@ -48,9 +47,9 @@ public class ClassDependency implements ClassDependencyInfo {
return classReader; return classReader;
} }
public void initClass(MethodReference caller, InstructionLocation location) { public void initClass(CallLocation callLocation) {
if (!isMissing()) { if (!isMissing()) {
checker.initClass(this, caller, location); checker.initClass(this, callLocation);
} }
} }
} }

View File

@ -32,11 +32,11 @@ public interface DependencyAgent extends DependencyInfo, ServiceRepository {
void submitClass(ClassHolder cls); void submitClass(ClassHolder cls);
MethodDependency linkMethod(MethodReference methodRef, MethodReference caller, InstructionLocation location); MethodDependency linkMethod(MethodReference methodRef, CallLocation callLocation);
ClassDependency linkClass(String className, MethodReference caller, InstructionLocation location); ClassDependency linkClass(String className, CallLocation callLocation);
FieldDependency linkField(FieldReference fieldRef, MethodReference caller, InstructionLocation location); FieldDependency linkField(FieldReference fieldRef, CallLocation callLocation);
Diagnostics getDiagnostics(); Diagnostics getDiagnostics();
} }

View File

@ -47,7 +47,6 @@ public class DependencyChecker implements DependencyInfo, DependencyAgent {
Set<FieldDependency> missingFields = new HashSet<>(); Set<FieldDependency> missingFields = new HashSet<>();
List<DependencyType> types = new ArrayList<>(); List<DependencyType> types = new ArrayList<>();
Map<String, DependencyType> typeMap = new HashMap<>(); Map<String, DependencyType> typeMap = new HashMap<>();
private DependencyViolations dependencyViolations;
private DependencyCheckerInterruptor interruptor; private DependencyCheckerInterruptor interruptor;
private boolean interrupted; private boolean interrupted;
private Diagnostics diagnostics; private Diagnostics diagnostics;
@ -188,7 +187,7 @@ public class DependencyChecker implements DependencyInfo, DependencyAgent {
if (parameters.length + 1 != argumentTypes.length) { if (parameters.length + 1 != argumentTypes.length) {
throw new IllegalArgumentException("argumentTypes length does not match the number of method's arguments"); throw new IllegalArgumentException("argumentTypes length does not match the number of method's arguments");
} }
MethodDependency method = linkMethod(methodRef, null, null); MethodDependency method = linkMethod(methodRef, null);
method.use(); method.use();
DependencyNode[] varNodes = method.getVariables(); DependencyNode[] varNodes = method.getVariables();
varNodes[0].propagate(getType(methodRef.getClassName())); varNodes[0].propagate(getType(methodRef.getClassName()));
@ -216,11 +215,11 @@ public class DependencyChecker implements DependencyInfo, DependencyAgent {
} }
@Override @Override
public ClassDependency linkClass(String className, DependencyStack stack) { public ClassDependency linkClass(String className, CallLocation callLocation) {
return classCache.map(className); return classCache.map(className);
} }
private ClassDependency createClassDependency(String className, DependencyStack stack) { private ClassDependency createClassDependency(String className, CallLocation callLocation) {
ClassReader cls = classSource.get(className); ClassReader cls = classSource.get(className);
ClassDependency dependency = new ClassDependency(this, className, stack, cls); ClassDependency dependency = new ClassDependency(this, className, stack, cls);
if (dependency.isMissing()) { if (dependency.isMissing()) {
@ -237,26 +236,25 @@ public class DependencyChecker implements DependencyInfo, DependencyAgent {
} }
@Override @Override
public MethodDependency linkMethod(MethodReference methodRef, MethodReference caller, public MethodDependency linkMethod(MethodReference methodRef, CallLocation callLocation) {
InstructionLocation location) {
if (methodRef == null) { if (methodRef == null) {
throw new IllegalArgumentException(); throw new IllegalArgumentException();
} }
callGraph.addNode(methodRef); callGraph.getNode(methodRef);
if (caller != null) { if (callLocation != null) {
callGraph.addNode(caller); callGraph.addNode(caller);
callGraph.getNode(caller).addCallSite(methodRef, location); callGraph.getNode(caller).addCallSite(methodRef, location);
} }
return methodCache.map(methodRef); return methodCache.map(methodRef);
} }
void initClass(ClassDependency cls, final MethodReference caller, final InstructionLocation location) { void initClass(ClassDependency cls, final CallLocation callLocation) {
ClassReader reader = cls.getClassReader(); ClassReader reader = cls.getClassReader();
final MethodReader method = reader.getMethod(new MethodDescriptor("<clinit>", void.class)); final MethodReader method = reader.getMethod(new MethodDescriptor("<clinit>", void.class));
if (method != null) { if (method != null) {
tasks.add(new Runnable() { tasks.add(new Runnable() {
@Override public void run() { @Override public void run() {
linkMethod(method.getReference(), caller, location).use(); linkMethod(method.getReference(), callLocation).use();
} }
}); });
} }

View File

@ -17,38 +17,27 @@ package org.teavm.diagnostics;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.teavm.model.InstructionLocation; import org.teavm.model.CallLocation;
import org.teavm.model.MethodReference;
/** /**
* *
* @author Alexey Andreev <konsoletyper@gmail.com> * @author Alexey Andreev <konsoletyper@gmail.com>
*/ */
class DependencyDiagnostics implements Diagnostics { public class AccumulationDiagnostics implements Diagnostics {
private List<Problem> problems = new ArrayList<>(); private List<Problem> problems = new ArrayList<>();
private List<Problem> severeProblems = new ArrayList<>(); private List<Problem> severeProblems = new ArrayList<>();
@Override @Override
public void error(MethodReference method, InstructionLocation location, String error, Object[] params) { public void error(CallLocation location, String error, Object... params) {
Problem violation = new Problem(ProblemSeverity.ERROR, location, error); Problem problem = new Problem(ProblemSeverity.ERROR, location, error, params);
problems.add(violation); problems.add(problem);
severeProblems.add(violation); severeProblems.add(problem);
} }
@Override @Override
public void error(String error) { public void warning(CallLocation location, String error, Object... params) {
error(null, error); Problem problem = new Problem(ProblemSeverity.ERROR, location, error, params);
} problems.add(problem);
@Override
public void warning(InstructionLocation location, String error) {
Problem violation = new Problem(ProblemSeverity.WARNING, location, error);
problems.add(violation);
}
@Override
public void warning(String error) {
warning(null, error);
} }
public List<Problem> getProblems() { public List<Problem> getProblems() {

View File

@ -46,4 +46,8 @@ public class Problem {
public String getText() { public String getText() {
return text; return text;
} }
public Object[] getParams() {
return params;
}
} }

View File

@ -24,7 +24,6 @@ import org.teavm.cache.DiskRegularMethodNodeCache;
import org.teavm.cache.FileSymbolTable; import org.teavm.cache.FileSymbolTable;
import org.teavm.debugging.information.DebugInformation; import org.teavm.debugging.information.DebugInformation;
import org.teavm.debugging.information.DebugInformationBuilder; import org.teavm.debugging.information.DebugInformationBuilder;
import org.teavm.dependency.DependencyViolations;
import org.teavm.javascript.RenderingContext; import org.teavm.javascript.RenderingContext;
import org.teavm.model.*; import org.teavm.model.*;
import org.teavm.parsing.ClasspathClassHolderSource; import org.teavm.parsing.ClasspathClassHolderSource;
@ -345,10 +344,6 @@ public class TeaVMTool {
} }
} }
public DependencyViolations getViolations() {
return vm.getViolations();
}
public void checkForMissingItems() { public void checkForMissingItems() {
vm.checkForViolations(); vm.checkForViolations();
} }
@ -366,7 +361,6 @@ public class TeaVMTool {
private AbstractRendererListener runtimeInjector = new AbstractRendererListener() { private AbstractRendererListener runtimeInjector = new AbstractRendererListener() {
@Override @Override
public void begin(RenderingContext context, BuildTarget buildTarget) throws IOException { public void begin(RenderingContext context, BuildTarget buildTarget) throws IOException {
@SuppressWarnings("resource")
StringWriter writer = new StringWriter(); StringWriter writer = new StringWriter();
resourceToWriter("org/teavm/javascript/runtime.js", writer); resourceToWriter("org/teavm/javascript/runtime.js", writer);
writer.close(); writer.close();

View File

@ -22,6 +22,7 @@ import org.teavm.common.ServiceRepository;
import org.teavm.debugging.information.DebugInformationEmitter; import org.teavm.debugging.information.DebugInformationEmitter;
import org.teavm.debugging.information.SourceLocation; import org.teavm.debugging.information.SourceLocation;
import org.teavm.dependency.*; import org.teavm.dependency.*;
import org.teavm.diagnostics.AccumulationDiagnostics;
import org.teavm.javascript.*; import org.teavm.javascript.*;
import org.teavm.javascript.ast.ClassNode; import org.teavm.javascript.ast.ClassNode;
import org.teavm.javascript.ni.Generator; import org.teavm.javascript.ni.Generator;
@ -68,6 +69,7 @@ import org.teavm.vm.spi.TeaVMPlugin;
public class TeaVM implements TeaVMHost, ServiceRepository { public class TeaVM implements TeaVMHost, ServiceRepository {
private ClassReaderSource classSource; private ClassReaderSource classSource;
private DependencyChecker dependencyChecker; private DependencyChecker dependencyChecker;
private AccumulationDiagnostics diagnostics = new AccumulationDiagnostics();
private ClassLoader classLoader; private ClassLoader classLoader;
private boolean minifying = true; private boolean minifying = true;
private boolean bytecodeLogging; private boolean bytecodeLogging;
@ -90,7 +92,7 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
TeaVM(ClassReaderSource classSource, ClassLoader classLoader) { TeaVM(ClassReaderSource classSource, ClassLoader classLoader) {
this.classSource = classSource; this.classSource = classSource;
this.classLoader = classLoader; this.classLoader = classLoader;
dependencyChecker = new DependencyChecker(this.classSource, classLoader, this); dependencyChecker = new DependencyChecker(this.classSource, classLoader, this, diagnostics);
progressListener = new TeaVMProgressListener() { progressListener = new TeaVMProgressListener() {
@Override public TeaVMProgressFeedback progressReached(int progress) { @Override public TeaVMProgressFeedback progressReached(int progress) {
return TeaVMProgressFeedback.CONTINUE; return TeaVMProgressFeedback.CONTINUE;
@ -232,9 +234,8 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
"for method " + ref); "for method " + ref);
} }
} }
TeaVMEntryPoint entryPoint = new TeaVMEntryPoint(name, ref, TeaVMEntryPoint entryPoint = new TeaVMEntryPoint(name, ref, dependencyChecker.linkMethod(ref, null));
dependencyChecker.linkMethod(ref, DependencyStack.ROOT)); dependencyChecker.linkClass(ref.getClassName(), null).initClass(null);
dependencyChecker.linkClass(ref.getClassName(), DependencyStack.ROOT).initClass(DependencyStack.ROOT);
if (name != null) { if (name != null) {
entryPoints.put(name, entryPoint); entryPoints.put(name, entryPoint);
} }
@ -258,9 +259,8 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
} }
public TeaVMEntryPoint linkMethod(MethodReference ref) { public TeaVMEntryPoint linkMethod(MethodReference ref) {
TeaVMEntryPoint entryPoint = new TeaVMEntryPoint("", ref, TeaVMEntryPoint entryPoint = new TeaVMEntryPoint("", ref, dependencyChecker.linkMethod(ref, null));
dependencyChecker.linkMethod(ref, DependencyStack.ROOT)); dependencyChecker.linkClass(ref.getClassName(), null).initClass(null);
dependencyChecker.linkClass(ref.getClassName(), DependencyStack.ROOT).initClass(DependencyStack.ROOT);
return entryPoint; return entryPoint;
} }
@ -269,12 +269,12 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
throw new IllegalArgumentException("Class with public name `" + name + "' already defined for class " + throw new IllegalArgumentException("Class with public name `" + name + "' already defined for class " +
className); className);
} }
dependencyChecker.linkClass(className, DependencyStack.ROOT).initClass(DependencyStack.ROOT); dependencyChecker.linkClass(className, null).initClass(null);
exportedClasses.put(name, className); exportedClasses.put(name, className);
} }
public void linkType(String className) { public void linkType(String className) {
dependencyChecker.linkClass(className, DependencyStack.ROOT).initClass(DependencyStack.ROOT); dependencyChecker.linkClass(className, null).initClass(null);
} }
/** /**
@ -285,30 +285,6 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
return classSource; return classSource;
} }
/**
* <p>After building indicates whether build has failed due to some missing items (classes, methods and fields)
* in the classpath. This can happen when you forgot some items in class path or when your code uses unimplemented
* Java class library methods. The behavior of this method before building is not specified.</p>
*/
public boolean hasMissingItems() {
return dependencyChecker.hasViolations();
}
/**
* <p>After building allows to build report on all items (classes, methods, fields) that are missing.
* This can happen when you forgot some items in class path or when your code uses unimplemented
* Java class library methods. The behavior of this method before building is not specified.</p>
*
* @param target where to append all dependency diagnostics errors.
*/
public void showMissingItems(Appendable target) throws IOException {
dependencyChecker.showViolations(target);
}
public DependencyViolations getViolations() {
return dependencyChecker.getViolations();
}
public Collection<String> getClasses() { public Collection<String> getClasses() {
return dependencyChecker.getAchievableClasses(); return dependencyChecker.getAchievableClasses();
} }
@ -321,16 +297,6 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
return writtenClasses; return writtenClasses;
} }
/**
* <p>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.
* This can happen when you forgot some items in class path or when your code uses unimplemented
* Java class library methods. The behavior of this method before building is not specified.</p>
*/
public void checkForViolations() {
dependencyChecker.checkForViolations();
}
public DebugInformationEmitter getDebugEmitter() { public DebugInformationEmitter getDebugEmitter() {
return debugEmitter; return debugEmitter;
} }
@ -362,22 +328,19 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
return progressListener.progressReached(0) == TeaVMProgressFeedback.CONTINUE; return progressListener.progressReached(0) == TeaVMProgressFeedback.CONTINUE;
} }
}); });
dependencyChecker.linkMethod(new MethodReference(Class.class, "createNew", Class.class), dependencyChecker.linkMethod(new MethodReference(Class.class, "createNew", Class.class), null).use();
DependencyStack.ROOT).use();
dependencyChecker.linkMethod(new MethodReference(String.class, "<init>", char[].class, void.class), dependencyChecker.linkMethod(new MethodReference(String.class, "<init>", char[].class, void.class),
DependencyStack.ROOT).use(); null).use();
dependencyChecker.linkMethod(new MethodReference(String.class, "getChars", int.class, int.class, char[].class, dependencyChecker.linkMethod(new MethodReference(String.class, "getChars", int.class, int.class, char[].class,
int.class, void.class), DependencyStack.ROOT).use(); int.class, void.class), null).use();
MethodDependency internDep = dependencyChecker.linkMethod(new MethodReference(String.class, "intern", MethodDependency internDep = dependencyChecker.linkMethod(new MethodReference(String.class, "intern",
String.class), DependencyStack.ROOT); String.class), null);
internDep.getVariable(0).propagate(dependencyChecker.getType("java.lang.String")); internDep.getVariable(0).propagate(dependencyChecker.getType("java.lang.String"));
internDep.use(); internDep.use();
dependencyChecker.linkMethod(new MethodReference(String.class, "length", int.class), dependencyChecker.linkMethod(new MethodReference(String.class, "length", int.class), null).use();
DependencyStack.ROOT).use(); dependencyChecker.linkMethod(new MethodReference(Object.class, "clone", Object.class), null).use();
dependencyChecker.linkMethod(new MethodReference(Object.class, "clone", Object.class),
DependencyStack.ROOT).use();
dependencyChecker.processDependencies(); dependencyChecker.processDependencies();
if (wasCancelled() || hasMissingItems()) { if (wasCancelled() || !diagnostics.getSevereProblems().isEmpty()) {
return; return;
} }