mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 16:14:10 -08:00
Refactoring of dependency checker in order to achieve better diagnostics
in Eclipse plugin
This commit is contained in:
parent
d9ea3764f8
commit
a26522f959
|
@ -152,6 +152,7 @@ public final class TeaVMRunner {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
tool.generate();
|
tool.generate();
|
||||||
|
tool.checkForMissingItems();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace(System.err);
|
e.printStackTrace(System.err);
|
||||||
System.exit(-2);
|
System.exit(-2);
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
|
@ -35,7 +35,7 @@ public interface DependencyAgent extends DependencyInfo, ServiceRepository {
|
||||||
|
|
||||||
MethodDependency linkMethod(MethodReference methodRef, DependencyStack stack);
|
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);
|
FieldDependency linkField(FieldReference fieldRef, DependencyStack stack);
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,16 +38,16 @@ public class DependencyChecker implements DependencyInfo, DependencyAgent {
|
||||||
private Map<String, DependencyStack> classStacks = new HashMap<>();
|
private Map<String, DependencyStack> classStacks = new HashMap<>();
|
||||||
private CachedMapper<MethodReference, MethodDependency> methodCache;
|
private CachedMapper<MethodReference, MethodDependency> methodCache;
|
||||||
private CachedMapper<FieldReference, FieldDependency> fieldCache;
|
private CachedMapper<FieldReference, FieldDependency> fieldCache;
|
||||||
private Set<String> achievableClasses = new HashSet<>();
|
private CachedMapper<String, ClassDependency> classCache;
|
||||||
private Set<String> initializedClasses = new HashSet<>();
|
|
||||||
private List<DependencyListener> listeners = new ArrayList<>();
|
private List<DependencyListener> listeners = new ArrayList<>();
|
||||||
private ServiceRepository services;
|
private ServiceRepository services;
|
||||||
private Queue<Runnable> tasks = new ArrayDeque<>();
|
private Queue<Runnable> tasks = new ArrayDeque<>();
|
||||||
Map<MethodReference, DependencyStack> missingMethods = new HashMap<>();
|
Set<MethodDependency> missingMethods = new HashSet<>();
|
||||||
Map<String, DependencyStack> missingClasses = new HashMap<>();
|
Set<ClassDependency> missingClasses = new HashSet<>();
|
||||||
Map<FieldReference, DependencyStack> missingFields = new HashMap<>();
|
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;
|
||||||
|
|
||||||
public DependencyChecker(ClassReaderSource classSource, ClassLoader classLoader, ServiceRepository services) {
|
public DependencyChecker(ClassReaderSource classSource, ClassLoader classLoader, ServiceRepository services) {
|
||||||
this.classSource = new DependencyClassSource(classSource);
|
this.classSource = new DependencyClassSource(classSource);
|
||||||
|
@ -83,6 +83,12 @@ public class DependencyChecker implements DependencyInfo, DependencyAgent {
|
||||||
return createFieldNode(preimage, field, fieldStacks.get(preimage));
|
return createFieldNode(preimage, field, fieldStacks.get(preimage));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
classCache = new CachedMapper<>(new Mapper<String, ClassDependency>() {
|
||||||
|
@Override public ClassDependency map(String preimage) {
|
||||||
|
return createClassDependency(preimage, classStacks.get(preimage));
|
||||||
|
}
|
||||||
|
});
|
||||||
methodCache.addKeyListener(new KeyListener<MethodReference>() {
|
methodCache.addKeyListener(new KeyListener<MethodReference>() {
|
||||||
@Override public void keyAdded(MethodReference key) {
|
@Override public void keyAdded(MethodReference key) {
|
||||||
MethodDependency graph = methodCache.getKnown(key);
|
MethodDependency graph = methodCache.getKnown(key);
|
||||||
|
@ -104,6 +110,16 @@ public class DependencyChecker implements DependencyInfo, DependencyAgent {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
classCache.addKeyListener(new KeyListener<String>() {
|
||||||
|
@Override public void keyAdded(String key) {
|
||||||
|
ClassDependency classDep = classCache.getKnown(key);
|
||||||
|
if (!classDep.isMissing()) {
|
||||||
|
for (DependencyListener listener : listeners) {
|
||||||
|
listener.classAchieved(DependencyChecker.this, key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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);
|
classStacks.put(className, stack);
|
||||||
if (!achievableClasses.add(className)) {
|
return classCache.map(className);
|
||||||
return false;
|
}
|
||||||
|
|
||||||
|
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) {
|
if (cls.getParent() != null) {
|
||||||
listener.classAchieved(this, className);
|
linkClass(cls.getParent(), stack);
|
||||||
}
|
}
|
||||||
return true;
|
for (String ifaceName : cls.getInterfaces()) {
|
||||||
|
linkClass(ifaceName, stack);
|
||||||
|
}
|
||||||
|
return dependency;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -203,44 +229,15 @@ public class DependencyChecker implements DependencyInfo, DependencyAgent {
|
||||||
return methodCache.map(methodRef);
|
return methodCache.map(methodRef);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
void initClass(ClassDependency cls, final DependencyStack stack) {
|
||||||
public void initClass(String className, final DependencyStack stack) {
|
ClassReader reader = cls.getClassReader();
|
||||||
classStacks.put(className, stack);
|
final MethodReader method = reader.getMethod(new MethodDescriptor("<clinit>", void.class));
|
||||||
MethodDescriptor clinitDesc = new MethodDescriptor("<clinit>", ValueType.VOID);
|
if (method != null) {
|
||||||
while (className != null) {
|
tasks.add(new Runnable() {
|
||||||
if (!initializedClasses.add(className)) {
|
@Override public void run() {
|
||||||
break;
|
linkMethod(method.getReference(), stack);
|
||||||
}
|
}
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -315,7 +312,6 @@ public class DependencyChecker implements DependencyInfo, DependencyAgent {
|
||||||
if (shouldLog) {
|
if (shouldLog) {
|
||||||
thrown.setTag(methodRef + ":THROWN");
|
thrown.setTag(methodRef + ":THROWN");
|
||||||
}
|
}
|
||||||
stack = new DependencyStack(methodRef, stack);
|
|
||||||
final MethodDependency dep = new MethodDependency(this, parameterNodes, paramCount, resultNode, thrown,
|
final MethodDependency dep = new MethodDependency(this, parameterNodes, paramCount, resultNode, thrown,
|
||||||
stack, method, methodRef);
|
stack, method, methodRef);
|
||||||
if (method != null) {
|
if (method != null) {
|
||||||
|
@ -325,26 +321,17 @@ public class DependencyChecker implements DependencyInfo, DependencyAgent {
|
||||||
graphBuilder.buildGraph(dep);
|
graphBuilder.buildGraph(dep);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
missingMethods.put(methodRef, stack);
|
|
||||||
}
|
|
||||||
if (method != null) {
|
|
||||||
final DependencyStack callerStack = stack;
|
|
||||||
tasks.add(new Runnable() {
|
tasks.add(new Runnable() {
|
||||||
@Override public void run() {
|
@Override public void run() {
|
||||||
initClass(dep.getReference().getClassName(), callerStack);
|
linkClass(dep.getMethod().getOwnerName(), dep.getStack());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
missingMethods.add(dep);
|
||||||
}
|
}
|
||||||
return dep;
|
return dep;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isMethodAchievable(MethodReference methodRef) {
|
|
||||||
return methodCache.caches(methodRef);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<MethodReference> getAchievableMethods() {
|
public Collection<MethodReference> getAchievableMethods() {
|
||||||
return methodCache.getCachedPreimages();
|
return methodCache.getCachedPreimages();
|
||||||
|
@ -357,7 +344,7 @@ public class DependencyChecker implements DependencyInfo, DependencyAgent {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<String> getAchievableClasses() {
|
public Collection<String> getAchievableClasses() {
|
||||||
return new HashSet<>(achievableClasses);
|
return classCache.getCachedPreimages();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -371,18 +358,28 @@ public class DependencyChecker implements DependencyInfo, DependencyAgent {
|
||||||
return fieldCache.getKnown(fieldRef);
|
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);
|
DependencyNode node = new DependencyNode(this);
|
||||||
if (field == null) {
|
|
||||||
missingFields.put(fieldRef, stack);
|
|
||||||
}
|
|
||||||
if (shouldLog) {
|
if (shouldLog) {
|
||||||
node.setTag(fieldRef.getClassName() + "#" + fieldRef.getFieldName());
|
node.setTag(fieldRef.getClassName() + "#" + fieldRef.getFieldName());
|
||||||
}
|
}
|
||||||
if (field != null) {
|
FieldDependency dep = new FieldDependency(node, stack, field, fieldRef);
|
||||||
initClass(fieldRef.getClassName(), stack);
|
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) {
|
private void activateDependencyPlugin(MethodDependency methodDep) {
|
||||||
|
@ -412,53 +409,23 @@ public class DependencyChecker implements DependencyInfo, DependencyAgent {
|
||||||
return methodCache.getKnown(methodRef);
|
return methodCache.getKnown(methodRef);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public DependencyViolations getDependencyViolations() {
|
||||||
|
if (dependencyViolations == null) {
|
||||||
|
dependencyViolations = new DependencyViolations(missingMethods, missingClasses, missingFields);
|
||||||
|
}
|
||||||
|
return dependencyViolations;
|
||||||
|
}
|
||||||
|
|
||||||
public void checkForMissingItems() {
|
public void checkForMissingItems() {
|
||||||
if (!hasMissingItems()) {
|
getDependencyViolations().checkForMissingItems();
|
||||||
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 boolean hasMissingItems() {
|
public boolean hasMissingItems() {
|
||||||
return !missingClasses.isEmpty() || !missingMethods.isEmpty() || !missingFields.isEmpty();
|
return getDependencyViolations().hasMissingItems();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void showMissingItems(Appendable sb) throws IOException {
|
public void showMissingItems(Appendable sb) throws IOException {
|
||||||
List<String> items = new ArrayList<>();
|
getDependencyViolations().showMissingItems(sb);
|
||||||
Map<String, DependencyStack> 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');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void processDependencies() {
|
public void processDependencies() {
|
||||||
|
|
|
@ -45,7 +45,6 @@ class DependencyGraphBuilder {
|
||||||
if (method.getProgram() == null || method.getProgram().basicBlockCount() == 0) {
|
if (method.getProgram() == null || method.getProgram().basicBlockCount() == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
callerStack = dep.getStack();
|
|
||||||
program = method.getProgram();
|
program = method.getProgram();
|
||||||
if (DependencyChecker.shouldLog) {
|
if (DependencyChecker.shouldLog) {
|
||||||
System.out.println("Method achieved: " + method.getReference());
|
System.out.println("Method achieved: " + method.getReference());
|
||||||
|
@ -53,6 +52,7 @@ class DependencyGraphBuilder {
|
||||||
}
|
}
|
||||||
resultNode = dep.getResult();
|
resultNode = dep.getResult();
|
||||||
nodes = dep.getVariables();
|
nodes = dep.getVariables();
|
||||||
|
callerStack = new DependencyStack(method.getReference(), dep.getStack());
|
||||||
for (int i = 0; i < program.basicBlockCount(); ++i) {
|
for (int i = 0; i < program.basicBlockCount(); ++i) {
|
||||||
BasicBlockReader block = program.basicBlockAt(i);
|
BasicBlockReader block = program.basicBlockAt(i);
|
||||||
currentExceptionConsumer = createExceptionConsumer(dep, block);
|
currentExceptionConsumer = createExceptionConsumer(dep, block);
|
||||||
|
@ -66,7 +66,7 @@ class DependencyGraphBuilder {
|
||||||
useRunners.add(new Runnable() {
|
useRunners.add(new Runnable() {
|
||||||
@Override public void run() {
|
@Override public void run() {
|
||||||
if (tryCatch.getExceptionType() != null) {
|
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() {
|
private InstructionReader reader = new InstructionReader() {
|
||||||
@Override
|
@Override
|
||||||
public void location(InstructionLocation location) {
|
public void location(InstructionLocation location) {
|
||||||
|
callerStack = new DependencyStack(callerStack.getMethod(), location, callerStack.getCause());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -233,7 +234,7 @@ class DependencyGraphBuilder {
|
||||||
final String className = ((ValueType.Object)cst).getClassName();
|
final String className = ((ValueType.Object)cst).getClassName();
|
||||||
useRunners.add(new Runnable() {
|
useRunners.add(new Runnable() {
|
||||||
@Override public void run() {
|
@Override public void run() {
|
||||||
dependencyChecker.initClass(className, callerStack);
|
dependencyChecker.linkClass(className, callerStack);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -355,7 +356,7 @@ class DependencyGraphBuilder {
|
||||||
if (className != null) {
|
if (className != null) {
|
||||||
useRunners.add(new Runnable() {
|
useRunners.add(new Runnable() {
|
||||||
@Override public void run() {
|
@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();
|
final String className = ((ValueType.Object)type).getClassName();
|
||||||
useRunners.add(new Runnable() {
|
useRunners.add(new Runnable() {
|
||||||
@Override public void run() {
|
@Override public void run() {
|
||||||
dependencyChecker.initClass(className, callerStack);
|
dependencyChecker.linkClass(className, callerStack);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -512,7 +513,7 @@ class DependencyGraphBuilder {
|
||||||
public void initClass(final String className) {
|
public void initClass(final String className) {
|
||||||
useRunners.add(new Runnable() {
|
useRunners.add(new Runnable() {
|
||||||
@Override public void run() {
|
@Override public void run() {
|
||||||
dependencyChecker.initClass(className, callerStack);
|
dependencyChecker.linkClass(className, callerStack).initClass(callerStack);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,8 +29,6 @@ public interface DependencyInfo {
|
||||||
|
|
||||||
ClassLoader getClassLoader();
|
ClassLoader getClassLoader();
|
||||||
|
|
||||||
boolean isMethodAchievable(MethodReference methodRef);
|
|
||||||
|
|
||||||
Collection<MethodReference> getAchievableMethods();
|
Collection<MethodReference> getAchievableMethods();
|
||||||
|
|
||||||
Collection<FieldReference> getAchievableFields();
|
Collection<FieldReference> getAchievableFields();
|
||||||
|
@ -40,4 +38,6 @@ public interface DependencyInfo {
|
||||||
FieldDependencyInfo getField(FieldReference fieldRef);
|
FieldDependencyInfo getField(FieldReference fieldRef);
|
||||||
|
|
||||||
MethodDependencyInfo getMethod(MethodReference methodRef);
|
MethodDependencyInfo getMethod(MethodReference methodRef);
|
||||||
|
|
||||||
|
ClassDependencyInfo getClass(String className);
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,6 +74,9 @@ public class DependencyStack {
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
sb.append(" used by " + stack.method);
|
sb.append(" used by " + stack.method);
|
||||||
|
if (stack.location != null) {
|
||||||
|
sb.append(" : ").append(stack.location.getLine());
|
||||||
|
}
|
||||||
stack = stack.cause;
|
stack = stack.cause;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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<MethodDependencyInfo> missingMethods;
|
||||||
|
private final Set<ClassDependencyInfo> missingClasses;
|
||||||
|
private final Set<FieldDependencyInfo> missingFields;
|
||||||
|
|
||||||
|
DependencyViolations(Collection<? extends MethodDependencyInfo> missingMethods,
|
||||||
|
Collection<? extends ClassDependencyInfo> missingClasses,
|
||||||
|
Collection<? extends FieldDependencyInfo> missingFields) {
|
||||||
|
this.missingMethods = Collections.unmodifiableSet(new HashSet<>(missingMethods));
|
||||||
|
this.missingClasses = Collections.unmodifiableSet(new HashSet<>(missingClasses));
|
||||||
|
this.missingFields = Collections.unmodifiableSet(new HashSet<>(missingFields));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<MethodDependencyInfo> getMissingMethods() {
|
||||||
|
return missingMethods;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<ClassDependencyInfo> getMissingClasses() {
|
||||||
|
return missingClasses;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<FieldDependencyInfo> 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<String> items = new ArrayList<>();
|
||||||
|
Map<String, DependencyStack> 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');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -40,6 +40,7 @@ public class FieldDependency implements FieldDependencyInfo {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public DependencyStack getStack() {
|
public DependencyStack getStack() {
|
||||||
return stack;
|
return stack;
|
||||||
}
|
}
|
||||||
|
@ -53,6 +54,7 @@ public class FieldDependency implements FieldDependencyInfo {
|
||||||
return reference;
|
return reference;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean isMissing() {
|
public boolean isMissing() {
|
||||||
return field == null;
|
return field == null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,4 +25,8 @@ public interface FieldDependencyInfo {
|
||||||
ValueDependencyInfo getValue();
|
ValueDependencyInfo getValue();
|
||||||
|
|
||||||
FieldReference getReference();
|
FieldReference getReference();
|
||||||
|
|
||||||
|
boolean isMissing();
|
||||||
|
|
||||||
|
DependencyStack getStack();
|
||||||
}
|
}
|
||||||
|
|
|
@ -82,6 +82,7 @@ public class MethodDependency implements MethodDependencyInfo {
|
||||||
return thrown;
|
return thrown;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public DependencyStack getStack() {
|
public DependencyStack getStack() {
|
||||||
return stack;
|
return stack;
|
||||||
}
|
}
|
||||||
|
@ -95,6 +96,7 @@ public class MethodDependency implements MethodDependencyInfo {
|
||||||
return method;
|
return method;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean isMissing() {
|
public boolean isMissing() {
|
||||||
return method == null;
|
return method == null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,4 +37,8 @@ public interface MethodDependencyInfo {
|
||||||
MethodReference getReference();
|
MethodReference getReference();
|
||||||
|
|
||||||
boolean isUsed();
|
boolean isUsed();
|
||||||
|
|
||||||
|
boolean isMissing();
|
||||||
|
|
||||||
|
DependencyStack getStack();
|
||||||
}
|
}
|
||||||
|
|
|
@ -180,7 +180,12 @@ public class BasicBlock implements BasicBlockReader {
|
||||||
@Override
|
@Override
|
||||||
public void readAllInstructions(InstructionReader reader) {
|
public void readAllInstructions(InstructionReader reader) {
|
||||||
InstructionReadVisitor visitor = new InstructionReadVisitor(reader);
|
InstructionReadVisitor visitor = new InstructionReadVisitor(reader);
|
||||||
|
InstructionLocation location = null;
|
||||||
for (Instruction insn : instructions) {
|
for (Instruction insn : instructions) {
|
||||||
|
if (!Objects.equals(location, insn.getLocation())) {
|
||||||
|
location = insn.getLocation();
|
||||||
|
reader.location(location);
|
||||||
|
}
|
||||||
insn.acceptVisitor(visitor);
|
insn.acceptVisitor(visitor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,7 @@ 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;
|
||||||
|
@ -61,6 +62,7 @@ public class TeaVMTool {
|
||||||
private FileSymbolTable fileTable;
|
private FileSymbolTable fileTable;
|
||||||
private boolean cancelled;
|
private boolean cancelled;
|
||||||
private TeaVMProgressListener progressListener;
|
private TeaVMProgressListener progressListener;
|
||||||
|
private TeaVM vm;
|
||||||
|
|
||||||
public File getTargetDirectory() {
|
public File getTargetDirectory() {
|
||||||
return targetDirectory;
|
return targetDirectory;
|
||||||
|
@ -215,7 +217,7 @@ public class TeaVMTool {
|
||||||
} else {
|
} else {
|
||||||
vmBuilder.setClassLoader(classLoader).setClassSource(new ClasspathClassHolderSource(classLoader));
|
vmBuilder.setClassLoader(classLoader).setClassSource(new ClasspathClassHolderSource(classLoader));
|
||||||
}
|
}
|
||||||
TeaVM vm = vmBuilder.build();
|
vm = vmBuilder.build();
|
||||||
if (progressListener != null) {
|
if (progressListener != null) {
|
||||||
vm.setProgressListener(progressListener);
|
vm.setProgressListener(progressListener);
|
||||||
}
|
}
|
||||||
|
@ -271,7 +273,10 @@ public class TeaVMTool {
|
||||||
cancelled = true;
|
cancelled = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
vm.checkForMissingItems();
|
if (vm.hasMissingItems()) {
|
||||||
|
log.info("Missing items found");
|
||||||
|
return;
|
||||||
|
}
|
||||||
log.info("JavaScript file successfully built");
|
log.info("JavaScript file successfully built");
|
||||||
if (debugInformationGenerated) {
|
if (debugInformationGenerated) {
|
||||||
DebugInformation debugInfo = debugEmitter.getDebugInformation();
|
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() {
|
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 {
|
||||||
|
|
|
@ -232,7 +232,7 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
|
||||||
}
|
}
|
||||||
TeaVMEntryPoint entryPoint = new TeaVMEntryPoint(name, ref,
|
TeaVMEntryPoint entryPoint = new TeaVMEntryPoint(name, ref,
|
||||||
dependencyChecker.linkMethod(ref, DependencyStack.ROOT));
|
dependencyChecker.linkMethod(ref, DependencyStack.ROOT));
|
||||||
dependencyChecker.initClass(ref.getClassName(), DependencyStack.ROOT);
|
dependencyChecker.linkClass(ref.getClassName(), DependencyStack.ROOT).initClass(DependencyStack.ROOT);
|
||||||
if (name != null) {
|
if (name != null) {
|
||||||
entryPoints.put(name, entryPoint);
|
entryPoints.put(name, entryPoint);
|
||||||
}
|
}
|
||||||
|
@ -258,7 +258,7 @@ 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, DependencyStack.ROOT));
|
dependencyChecker.linkMethod(ref, DependencyStack.ROOT));
|
||||||
dependencyChecker.initClass(ref.getClassName(), DependencyStack.ROOT);
|
dependencyChecker.linkClass(ref.getClassName(), DependencyStack.ROOT).initClass(DependencyStack.ROOT);
|
||||||
return entryPoint;
|
return entryPoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -267,12 +267,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.initClass(className, DependencyStack.ROOT);
|
dependencyChecker.linkClass(className, DependencyStack.ROOT).initClass(DependencyStack.ROOT);
|
||||||
exportedClasses.put(name, className);
|
exportedClasses.put(name, className);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void linkType(String 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);
|
dependencyChecker.showMissingItems(target);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public DependencyViolations getDependencyViolations() {
|
||||||
|
return dependencyChecker.getDependencyViolations();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>After building checks whether the build has failed due to some missing items (classes, methods and fields).
|
* <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.
|
* If it has failed, throws exception, containing report on all missing items.
|
||||||
|
|
|
@ -39,6 +39,7 @@ public class TeaVMBuilder extends IncrementalProjectBuilder {
|
||||||
tool.setProgressListener(new TeaVMEclipseProgressListener(monitor));
|
tool.setProgressListener(new TeaVMEclipseProgressListener(monitor));
|
||||||
try {
|
try {
|
||||||
tool.generate();
|
tool.generate();
|
||||||
|
tool.checkForMissingItems();
|
||||||
} catch (TeaVMToolException e) {
|
} catch (TeaVMToolException e) {
|
||||||
throw new CoreException(TeaVMEclipsePlugin.makeError(e));
|
throw new CoreException(TeaVMEclipsePlugin.makeError(e));
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,7 +69,7 @@ public class EntryPointGenerator extends AbstractRendererListener implements Dep
|
||||||
@Override
|
@Override
|
||||||
public void started(DependencyAgent agent) {
|
public void started(DependencyAgent agent) {
|
||||||
for (String className : classesToLoad) {
|
for (String className : classesToLoad) {
|
||||||
agent.initClass(className, DependencyStack.ROOT);
|
agent.linkClass(className, DependencyStack.ROOT).initClass(DependencyStack.ROOT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -210,6 +210,7 @@ public class BuildJavascriptMojo extends AbstractMojo {
|
||||||
tool.setDebugInformationGenerated(debugInformationGenerated);
|
tool.setDebugInformationGenerated(debugInformationGenerated);
|
||||||
tool.setSourceMapsFileGenerated(sourceMapsGenerated);
|
tool.setSourceMapsFileGenerated(sourceMapsGenerated);
|
||||||
tool.generate();
|
tool.generate();
|
||||||
|
tool.checkForMissingItems();
|
||||||
} catch (RuntimeException e) {
|
} catch (RuntimeException e) {
|
||||||
throw new MojoExecutionException("Unexpected error occured", e);
|
throw new MojoExecutionException("Unexpected error occured", e);
|
||||||
} catch (TeaVMToolException e) {
|
} catch (TeaVMToolException e) {
|
||||||
|
|
|
@ -40,6 +40,7 @@ public final class HelloWorld {
|
||||||
document = window.getDocument();
|
document = window.getDocument();
|
||||||
body = document.getDocumentElement().getElementsByTagName("body").item(0);
|
body = document.getDocumentElement().getElementsByTagName("body").item(0);
|
||||||
createButton();
|
createButton();
|
||||||
|
new Thread().start();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void createButton() {
|
private static void createButton() {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user