Refactoring of dependency checker in order to achieve better diagnostics

in Eclipse plugin
This commit is contained in:
konsoletyper 2014-09-15 17:52:55 +04:00
parent d9ea3764f8
commit a26522f959
20 changed files with 326 additions and 126 deletions

View File

@ -152,6 +152,7 @@ public final class TeaVMRunner {
try {
tool.generate();
tool.checkForMissingItems();
} catch (Exception e) {
e.printStackTrace(System.err);
System.exit(-2);

View File

@ -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);
}
}
}

View File

@ -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();
}

View File

@ -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);
}

View File

@ -38,16 +38,16 @@ public class DependencyChecker implements DependencyInfo, DependencyAgent {
private Map<String, DependencyStack> classStacks = new HashMap<>();
private CachedMapper<MethodReference, MethodDependency> methodCache;
private CachedMapper<FieldReference, FieldDependency> fieldCache;
private Set<String> achievableClasses = new HashSet<>();
private Set<String> initializedClasses = new HashSet<>();
private CachedMapper<String, ClassDependency> classCache;
private List<DependencyListener> listeners = new ArrayList<>();
private ServiceRepository services;
private Queue<Runnable> tasks = new ArrayDeque<>();
Map<MethodReference, DependencyStack> missingMethods = new HashMap<>();
Map<String, DependencyStack> missingClasses = new HashMap<>();
Map<FieldReference, DependencyStack> missingFields = new HashMap<>();
Set<MethodDependency> missingMethods = new HashSet<>();
Set<ClassDependency> missingClasses = new HashSet<>();
Set<FieldDependency> missingFields = new HashSet<>();
List<DependencyType> types = new ArrayList<>();
Map<String, DependencyType> 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<String, ClassDependency>() {
@Override public ClassDependency map(String preimage) {
return createClassDependency(preimage, classStacks.get(preimage));
}
});
methodCache.addKeyListener(new KeyListener<MethodReference>() {
@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<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
@ -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("<clinit>", 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("<clinit>", 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<MethodReference> getAchievableMethods() {
return methodCache.getCachedPreimages();
@ -357,7 +344,7 @@ public class DependencyChecker implements DependencyInfo, DependencyAgent {
@Override
public Collection<String> 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<String> items = new ArrayList<>();
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');
}
getDependencyViolations().showMissingItems(sb);
}
public void processDependencies() {

View File

@ -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);
}
});
}

View File

@ -29,8 +29,6 @@ public interface DependencyInfo {
ClassLoader getClassLoader();
boolean isMethodAchievable(MethodReference methodRef);
Collection<MethodReference> getAchievableMethods();
Collection<FieldReference> getAchievableFields();
@ -40,4 +38,6 @@ public interface DependencyInfo {
FieldDependencyInfo getField(FieldReference fieldRef);
MethodDependencyInfo getMethod(MethodReference methodRef);
ClassDependencyInfo getClass(String className);
}

View File

@ -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;
}
}

View File

@ -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');
}
}
}

View File

@ -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;
}

View File

@ -25,4 +25,8 @@ public interface FieldDependencyInfo {
ValueDependencyInfo getValue();
FieldReference getReference();
boolean isMissing();
DependencyStack getStack();
}

View File

@ -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;
}

View File

@ -37,4 +37,8 @@ public interface MethodDependencyInfo {
MethodReference getReference();
boolean isUsed();
boolean isMissing();
DependencyStack getStack();
}

View File

@ -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);
}
}

View File

@ -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 {

View File

@ -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();
}
/**
* <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.

View File

@ -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));
}

View File

@ -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);
}
}

View File

@ -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) {

View File

@ -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() {