mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2025-01-08 07:54:11 -08:00
Allow interruption during dependency and linking phases. Use buffered
writer to render final JavaScript
This commit is contained in:
parent
ac2ffa42ff
commit
700d50b110
|
@ -48,6 +48,8 @@ public class DependencyChecker implements DependencyInfo, DependencyAgent {
|
|||
List<DependencyType> types = new ArrayList<>();
|
||||
Map<String, DependencyType> typeMap = new HashMap<>();
|
||||
private DependencyViolations dependencyViolations;
|
||||
private DependencyCheckerInterruptor interruptor;
|
||||
private boolean interrupted;
|
||||
|
||||
public DependencyChecker(ClassReaderSource classSource, ClassLoader classLoader, ServiceRepository services) {
|
||||
this.classSource = new DependencyClassSource(classSource);
|
||||
|
@ -122,6 +124,18 @@ public class DependencyChecker implements DependencyInfo, DependencyAgent {
|
|||
});
|
||||
}
|
||||
|
||||
public DependencyCheckerInterruptor getInterruptor() {
|
||||
return interruptor;
|
||||
}
|
||||
|
||||
public void setInterruptor(DependencyCheckerInterruptor interruptor) {
|
||||
this.interruptor = interruptor;
|
||||
}
|
||||
|
||||
public boolean wasInterrupted() {
|
||||
return interrupted;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DependencyType getType(String name) {
|
||||
DependencyType type = typeMap.get(name);
|
||||
|
@ -434,8 +448,17 @@ public class DependencyChecker implements DependencyInfo, DependencyAgent {
|
|||
}
|
||||
|
||||
public void processDependencies() {
|
||||
interrupted = false;
|
||||
int index = 0;
|
||||
while (!tasks.isEmpty()) {
|
||||
tasks.poll().run();
|
||||
if (++index == 100) {
|
||||
if (interruptor != null && !interruptor.shouldContinue()) {
|
||||
interrupted = true;
|
||||
break;
|
||||
}
|
||||
index = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* 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 <konsoletyper@gmail.com>
|
||||
*/
|
||||
public interface DependencyCheckerInterruptor {
|
||||
boolean shouldContinue();
|
||||
}
|
|
@ -19,24 +19,13 @@ import org.teavm.model.*;
|
|||
import org.teavm.model.instructions.GetFieldInstruction;
|
||||
import org.teavm.model.instructions.InvokeInstruction;
|
||||
import org.teavm.model.instructions.PutFieldInstruction;
|
||||
import org.teavm.model.util.ModelUtils;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
public class Linker {
|
||||
public ListableClassHolderSource link(DependencyInfo dependency) {
|
||||
MutableClassHolderSource cutClasses = new MutableClassHolderSource();
|
||||
for (String className : dependency.getAchievableClasses()) {
|
||||
ClassHolder cls = ModelUtils.copyClass(dependency.getClassSource().get(className));
|
||||
cutClasses.putClassHolder(cls);
|
||||
link(dependency, cls);
|
||||
}
|
||||
return cutClasses;
|
||||
}
|
||||
|
||||
private void link(DependencyInfo dependency, ClassHolder cls) {
|
||||
public void link(DependencyInfo dependency, ClassHolder cls) {
|
||||
for (MethodHolder method : cls.getMethods().toArray(new MethodHolder[0])) {
|
||||
MethodReference methodRef = new MethodReference(cls.getName(), method.getDescriptor());
|
||||
MethodDependencyInfo methodDep = dependency.getMethod(methodRef);
|
||||
|
|
|
@ -16,9 +16,7 @@
|
|||
package org.teavm.tooling;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import java.util.*;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.teavm.cache.DiskCachedClassHolderSource;
|
||||
import org.teavm.cache.DiskProgramCache;
|
||||
|
@ -192,6 +190,10 @@ public class TeaVMTool {
|
|||
return cancelled;
|
||||
}
|
||||
|
||||
public Collection<String> getClasses() {
|
||||
return vm != null ? vm.getClasses() : Collections.<String>emptyList();
|
||||
}
|
||||
|
||||
public void generate() throws TeaVMToolException {
|
||||
try {
|
||||
cancelled = false;
|
||||
|
@ -263,7 +265,8 @@ public class TeaVMTool {
|
|||
}
|
||||
}
|
||||
targetDirectory.mkdirs();
|
||||
try (FileWriter writer = new FileWriter(new File(targetDirectory, targetFileName))) {
|
||||
try (Writer writer = new OutputStreamWriter(new BufferedOutputStream(
|
||||
new FileOutputStream(new File(targetDirectory, targetFileName))), "UTF-8")) {
|
||||
if (runtime == RuntimeCopyOperation.MERGED) {
|
||||
vm.add(runtimeInjector);
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ import org.teavm.javascript.ni.Generator;
|
|||
import org.teavm.javascript.ni.Injector;
|
||||
import org.teavm.model.*;
|
||||
import org.teavm.model.util.ListingBuilder;
|
||||
import org.teavm.model.util.ModelUtils;
|
||||
import org.teavm.model.util.ProgramUtils;
|
||||
import org.teavm.model.util.RegisterAllocator;
|
||||
import org.teavm.optimization.*;
|
||||
|
@ -307,6 +308,10 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
|
|||
return dependencyChecker.getDependencyViolations();
|
||||
}
|
||||
|
||||
public Collection<String> getClasses() {
|
||||
return dependencyChecker.getAchievableClasses();
|
||||
}
|
||||
|
||||
/**
|
||||
* <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.
|
||||
|
@ -343,23 +348,26 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
|
|||
return;
|
||||
}
|
||||
AliasProvider aliasProvider = minifying ? new MinifyingAliasProvider() : new DefaultAliasProvider();
|
||||
dependencyChecker.linkMethod(new MethodReference("java.lang.Class", "createNew",
|
||||
ValueType.object("java.lang.Class")), DependencyStack.ROOT).use();
|
||||
dependencyChecker.linkMethod(new MethodReference("java.lang.String", "<init>",
|
||||
ValueType.arrayOf(ValueType.CHARACTER), ValueType.VOID), DependencyStack.ROOT).use();
|
||||
dependencyChecker.linkMethod(new MethodReference("java.lang.String", "getChars",
|
||||
ValueType.INTEGER, ValueType.INTEGER, ValueType.arrayOf(ValueType.CHARACTER), ValueType.INTEGER,
|
||||
ValueType.VOID), DependencyStack.ROOT).use();
|
||||
MethodDependency internDep = dependencyChecker.linkMethod(new MethodReference("java.lang.String", "intern",
|
||||
ValueType.object("java.lang.String")), DependencyStack.ROOT);
|
||||
dependencyChecker.setInterruptor(new DependencyCheckerInterruptor() {
|
||||
@Override public boolean shouldContinue() {
|
||||
return progressListener.progressReached(0) == TeaVMProgressFeedback.CONTINUE;
|
||||
}
|
||||
});
|
||||
dependencyChecker.linkMethod(new MethodReference(Class.class, "createNew", Class.class),
|
||||
DependencyStack.ROOT).use();
|
||||
dependencyChecker.linkMethod(new MethodReference(String.class, "<init>", char[].class, void.class),
|
||||
DependencyStack.ROOT).use();
|
||||
dependencyChecker.linkMethod(new MethodReference(String.class, "getChars", int.class, int.class, char[].class,
|
||||
int.class, void.class), DependencyStack.ROOT).use();
|
||||
MethodDependency internDep = dependencyChecker.linkMethod(new MethodReference(String.class, "intern",
|
||||
String.class), DependencyStack.ROOT);
|
||||
internDep.getVariable(0).propagate(dependencyChecker.getType("java.lang.String"));
|
||||
internDep.use();
|
||||
dependencyChecker.linkMethod(new MethodReference("java.lang.String", "length", ValueType.INTEGER),
|
||||
dependencyChecker.linkMethod(new MethodReference(String.class, "length", int.class),
|
||||
DependencyStack.ROOT).use();
|
||||
dependencyChecker.linkMethod(new MethodReference(Object.class, "clone", Object.class),
|
||||
DependencyStack.ROOT).use();
|
||||
dependencyChecker.linkMethod(new MethodReference("java.lang.Object", new MethodDescriptor("clone",
|
||||
ValueType.object("java.lang.Object"))), DependencyStack.ROOT).use();
|
||||
dependencyChecker.processDependencies();
|
||||
reportProgress(1);
|
||||
if (wasCancelled() || hasMissingItems()) {
|
||||
return;
|
||||
}
|
||||
|
@ -369,9 +377,7 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
|
|||
if (wasCancelled()) {
|
||||
return;
|
||||
}
|
||||
Linker linker = new Linker();
|
||||
ListableClassHolderSource classSet = linker.link(dependencyChecker);
|
||||
reportProgress(1);
|
||||
ListableClassHolderSource classSet = link(dependencyChecker);
|
||||
if (wasCancelled()) {
|
||||
return;
|
||||
}
|
||||
|
@ -449,6 +455,23 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
|
|||
}
|
||||
}
|
||||
|
||||
public ListableClassHolderSource link(DependencyInfo dependency) {
|
||||
reportPhase(TeaVMPhase.LINKING, dependency.getAchievableClasses().size());
|
||||
Linker linker = new Linker();
|
||||
MutableClassHolderSource cutClasses = new MutableClassHolderSource();
|
||||
if (wasCancelled()) {
|
||||
return cutClasses;
|
||||
}
|
||||
int index = 0;
|
||||
for (String className : dependency.getAchievableClasses()) {
|
||||
ClassHolder cls = ModelUtils.copyClass(dependency.getClassSource().get(className));
|
||||
cutClasses.putClassHolder(cls);
|
||||
linker.link(dependency, cls);
|
||||
progressListener.progressReached(++index);
|
||||
}
|
||||
return cutClasses;
|
||||
}
|
||||
|
||||
private void reportPhase(TeaVMPhase phase, int progressLimit) {
|
||||
if (progressListener.phaseStarted(phase, progressLimit) == TeaVMProgressFeedback.CANCEL) {
|
||||
cancelled = true;
|
||||
|
|
|
@ -10,7 +10,9 @@ import org.eclipse.core.runtime.CoreException;
|
|||
import org.eclipse.core.runtime.IPath;
|
||||
import org.eclipse.core.runtime.IProgressMonitor;
|
||||
import org.eclipse.core.variables.VariablesPlugin;
|
||||
import org.eclipse.jdt.core.*;
|
||||
import org.eclipse.jdt.core.IClasspathEntry;
|
||||
import org.eclipse.jdt.core.IJavaProject;
|
||||
import org.eclipse.jdt.core.JavaCore;
|
||||
import org.teavm.dependency.*;
|
||||
import org.teavm.model.InstructionLocation;
|
||||
import org.teavm.model.MethodReference;
|
||||
|
@ -26,9 +28,15 @@ import org.teavm.tooling.TeaVMToolException;
|
|||
public class TeaVMBuilder extends IncrementalProjectBuilder {
|
||||
private URL[] classPath;
|
||||
private IContainer[] sourceContainers;
|
||||
private IContainer[] classFileContainers;
|
||||
private Set<IProject> usedProjects = new HashSet<>();
|
||||
|
||||
@Override
|
||||
protected IProject[] build(int kind, Map<String, String> args, IProgressMonitor monitor) throws CoreException {
|
||||
if ((kind == AUTO_BUILD || kind == INCREMENTAL_BUILD) && !shouldBuild()) {
|
||||
System.out.println("Skipping project " + getProject().getName());
|
||||
return null;
|
||||
}
|
||||
TeaVMProjectSettings projectSettings = getProjectSettings();
|
||||
projectSettings.load();
|
||||
TeaVMTool tool = new TeaVMTool();
|
||||
|
@ -49,13 +57,59 @@ public class TeaVMBuilder extends IncrementalProjectBuilder {
|
|||
if (tool.getDependencyViolations().hasMissingItems()) {
|
||||
putMarkers(tool.getDependencyViolations());
|
||||
}
|
||||
TeaVMEclipsePlugin.getDefault().setProjectClasses(getProject(), classesToResources(tool.getClasses()));
|
||||
if (!monitor.isCanceled()) {
|
||||
monitor.done();
|
||||
}
|
||||
} catch (TeaVMToolException e) {
|
||||
throw new CoreException(TeaVMEclipsePlugin.makeError(e));
|
||||
} finally {
|
||||
sourceContainers = null;
|
||||
classFileContainers = null;
|
||||
classPath = null;
|
||||
usedProjects.clear();
|
||||
}
|
||||
return null;
|
||||
return !usedProjects.isEmpty() ? usedProjects.toArray(new IProject[0]) : null;
|
||||
}
|
||||
|
||||
private Set<String> classesToResources(Collection<String> classNames) {
|
||||
Set<String> resourcePaths = new HashSet<>();
|
||||
for (String className : classNames) {
|
||||
for (IContainer clsContainer : classFileContainers) {
|
||||
IResource res = clsContainer.findMember(className.replace('.', '/') + ".class");
|
||||
if (res != null) {
|
||||
resourcePaths.add(res.getFullPath().toString());
|
||||
usedProjects.add(res.getProject());
|
||||
}
|
||||
}
|
||||
}
|
||||
return resourcePaths;
|
||||
}
|
||||
|
||||
private boolean shouldBuild() throws CoreException {
|
||||
Set<String> classes = TeaVMEclipsePlugin.getDefault().getProjectClasses(getProject());
|
||||
if (classes.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
for (IProject project : getRelatedProjects()) {
|
||||
IResourceDelta delta = getDelta(project);
|
||||
if (shouldBuild(classes, delta)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean shouldBuild(Set<String> classes, IResourceDelta delta) {
|
||||
if (classes.contains(delta.getResource().getFullPath().toString())) {
|
||||
return true;
|
||||
}
|
||||
for (IResourceDelta child : delta.getAffectedChildren()) {
|
||||
if (shouldBuild(classes, child)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void removeMarkers() throws CoreException {
|
||||
|
@ -200,6 +254,29 @@ public class TeaVMBuilder extends IncrementalProjectBuilder {
|
|||
return new URLClassLoader(classPath, TeaVMBuilder.class.getClassLoader());
|
||||
}
|
||||
|
||||
private Set<IProject> getRelatedProjects() throws CoreException {
|
||||
Set<IProject> projects = new HashSet<>();
|
||||
Set<IProject> visited = new HashSet<>();
|
||||
Queue<IProject> queue = new ArrayDeque<>();
|
||||
queue.add(getProject());
|
||||
IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
|
||||
while (!queue.isEmpty()) {
|
||||
IProject project = queue.remove();
|
||||
if (!visited.add(project) || !project.hasNature(JavaCore.NATURE_ID)) {
|
||||
continue;
|
||||
}
|
||||
projects.add(project);
|
||||
IJavaProject javaProject = JavaCore.create(project);
|
||||
for (IClasspathEntry entry : javaProject.getRawClasspath()) {
|
||||
if (entry.getEntryKind() == IClasspathEntry.CPE_PROJECT) {
|
||||
project = (IProject)root.findMember(entry.getPath());
|
||||
queue.add(project);
|
||||
}
|
||||
}
|
||||
}
|
||||
return projects;
|
||||
}
|
||||
|
||||
private void prepareClassPath() throws CoreException {
|
||||
classPath = new URL[0];
|
||||
sourceContainers = new IContainer[0];
|
||||
|
@ -210,9 +287,14 @@ public class TeaVMBuilder extends IncrementalProjectBuilder {
|
|||
IJavaProject javaProject = JavaCore.create(project);
|
||||
PathCollector collector = new PathCollector();
|
||||
SourcePathCollector srcCollector = new SourcePathCollector();
|
||||
SourcePathCollector binCollector = new SourcePathCollector();
|
||||
IWorkspaceRoot workspaceRoot = project.getWorkspace().getRoot();
|
||||
try {
|
||||
collector.addPath(workspaceRoot.findMember(javaProject.getOutputLocation()).getLocation());
|
||||
if (javaProject.getOutputLocation() != null) {
|
||||
IContainer container = (IContainer)workspaceRoot.findMember(javaProject.getOutputLocation());
|
||||
collector.addPath(container.getLocation());
|
||||
binCollector.addContainer(container);
|
||||
}
|
||||
} catch (MalformedURLException e) {
|
||||
TeaVMEclipsePlugin.logError(e);
|
||||
}
|
||||
|
@ -248,8 +330,10 @@ public class TeaVMBuilder extends IncrementalProjectBuilder {
|
|||
IJavaProject depJavaProject = JavaCore.create(depProject);
|
||||
if (depJavaProject.getOutputLocation() != null) {
|
||||
try {
|
||||
collector.addPath(workspaceRoot.findMember(depJavaProject.getOutputLocation())
|
||||
.getLocation());
|
||||
IContainer container = (IContainer)workspaceRoot.findMember(
|
||||
depJavaProject.getOutputLocation());
|
||||
collector.addPath(container.getLocation());
|
||||
binCollector.addContainer(container);
|
||||
} catch (MalformedURLException e) {
|
||||
TeaVMEclipsePlugin.logError(e);
|
||||
}
|
||||
|
@ -260,6 +344,7 @@ public class TeaVMBuilder extends IncrementalProjectBuilder {
|
|||
}
|
||||
classPath = collector.getUrls();
|
||||
sourceContainers = srcCollector.getContainers();
|
||||
classFileContainers = binCollector.getContainers();
|
||||
}
|
||||
|
||||
static class PathCollector {
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
package org.teavm.eclipse;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.Arrays;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import org.eclipse.core.resources.IProject;
|
||||
|
@ -41,6 +41,7 @@ public class TeaVMEclipsePlugin extends AbstractUIPlugin {
|
|||
public static final String DEPENDENCY_MARKER_ID = ID + ".dependencyMarker";
|
||||
private static TeaVMEclipsePlugin defaultInstance;
|
||||
private ConcurrentMap<IProject, TeaVMProjectSettings> settingsMap = new ConcurrentHashMap<>();
|
||||
private Map<IProject, Set<String>> projectClasses = new WeakHashMap<>();
|
||||
|
||||
public TeaVMEclipsePlugin() {
|
||||
defaultInstance = this;
|
||||
|
@ -131,4 +132,18 @@ public class TeaVMEclipsePlugin extends AbstractUIPlugin {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setProjectClasses(IProject project, Set<String> classes) {
|
||||
synchronized (projectClasses) {
|
||||
projectClasses.put(project, new HashSet<>(classes));
|
||||
}
|
||||
}
|
||||
|
||||
public Set<String> getProjectClasses(IProject project) {
|
||||
Set<String> classes;
|
||||
synchronized (projectClasses) {
|
||||
classes = projectClasses.get(project);
|
||||
}
|
||||
return classes != null ? new HashSet<>(classes) : new HashSet<String>();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user