mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 08:14:09 -08:00
Multithreading support refactoring
This commit is contained in:
parent
c9a891d9cd
commit
915add4d97
|
@ -53,6 +53,7 @@
|
|||
<phase>process-test-classes</phase>
|
||||
<configuration>
|
||||
<minifying>false</minifying>
|
||||
<numThreads>1</numThreads>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
|
|
|
@ -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.common;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
public interface FiniteExecutor extends Executor {
|
||||
void complete();
|
||||
|
||||
void executeFast(Runnable runnable);
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* 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.common;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.Queue;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
public class SimpleFiniteExecutor implements FiniteExecutor {
|
||||
private Queue<Runnable> queue = new LinkedList<>();
|
||||
|
||||
@Override
|
||||
public void execute(Runnable command) {
|
||||
queue.add(command);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void executeFast(Runnable runnable) {
|
||||
execute(runnable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void complete() {
|
||||
while (!queue.isEmpty()) {
|
||||
queue.remove().run();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,115 @@
|
|||
/*
|
||||
* 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.common;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
public class ThreadPoolFiniteExecutor implements FiniteExecutor {
|
||||
private List<Thread> threads = new ArrayList<>();
|
||||
private BlockingQueue<Runnable> queue = new LinkedBlockingQueue<>();
|
||||
private AtomicInteger runningTasks = new AtomicInteger();
|
||||
private final Object monitor = new Object();
|
||||
private AtomicReference<RuntimeException> thrownException = new AtomicReference<>();
|
||||
private ThreadLocal<Queue<Runnable>> localQueueues = new ThreadLocal<>();
|
||||
|
||||
public ThreadPoolFiniteExecutor(int numThreads) {
|
||||
for (int i = 0; i < numThreads; ++i) {
|
||||
Thread thread = new Thread() {
|
||||
@Override public void run() {
|
||||
takeTask();
|
||||
}
|
||||
};
|
||||
threads.add(thread);
|
||||
thread.start();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(Runnable command) {
|
||||
runningTasks.incrementAndGet();
|
||||
try {
|
||||
queue.put(command);
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void executeFast(Runnable runnable) {
|
||||
localQueueues.get().add(runnable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void complete() {
|
||||
synchronized (monitor) {
|
||||
try {
|
||||
monitor.wait();
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
return;
|
||||
}
|
||||
if (thrownException.get() != null) {
|
||||
throw thrownException.get();
|
||||
}
|
||||
if (runningTasks.get() == 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void takeTask() {
|
||||
Queue<Runnable> localQueue = new ArrayDeque<>();
|
||||
localQueueues.set(localQueue);
|
||||
try {
|
||||
while (true) {
|
||||
Runnable task = queue.take();
|
||||
try {
|
||||
task.run();
|
||||
while (!localQueue.isEmpty()) {
|
||||
localQueue.remove().run();
|
||||
}
|
||||
} catch (RuntimeException e) {
|
||||
thrownException.set(e);
|
||||
} finally {
|
||||
if (runningTasks.decrementAndGet() == 0 || thrownException.get() != null) {
|
||||
synchronized (monitor) {
|
||||
monitor.notifyAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
for (Thread thread : threads) {
|
||||
thread.interrupt();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -18,10 +18,10 @@ package org.teavm.dependency;
|
|||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import org.teavm.common.ConcurrentCachedMapper;
|
||||
import org.teavm.common.FiniteExecutor;
|
||||
import org.teavm.common.Mapper;
|
||||
import org.teavm.common.SimpleFiniteExecutor;
|
||||
import org.teavm.common.ConcurrentCachedMapper.KeyListener;
|
||||
import org.teavm.model.*;
|
||||
|
||||
|
@ -34,31 +34,21 @@ public class DependencyChecker {
|
|||
static final boolean shouldLog = System.getProperty("org.teavm.logDependencies", "false").equals("true");
|
||||
private ClassHolderSource classSource;
|
||||
private ClassLoader classLoader;
|
||||
private ScheduledThreadPoolExecutor executor;
|
||||
private FiniteExecutor executor;
|
||||
private ConcurrentMap<MethodReference, Object> abstractMethods = new ConcurrentHashMap<>();
|
||||
private ConcurrentCachedMapper<MethodReference, MethodGraph> methodCache;
|
||||
private ConcurrentCachedMapper<FieldReference, DependencyNode> fieldCache;
|
||||
private ConcurrentMap<String, Object> achievableClasses = new ConcurrentHashMap<>();
|
||||
private ConcurrentMap<String, Object> initializedClasses = new ConcurrentHashMap<>();
|
||||
private AtomicReference<RuntimeException> exceptionOccured = new AtomicReference<>();
|
||||
private AtomicInteger activeTaskCount = new AtomicInteger(0);
|
||||
private final Object activeTaskMonitor = new Object();
|
||||
|
||||
public DependencyChecker(ClassHolderSource classSource, ClassLoader classLoader) {
|
||||
this(classSource, classLoader, Runtime.getRuntime().availableProcessors());
|
||||
this(classSource, classLoader, new SimpleFiniteExecutor());
|
||||
}
|
||||
|
||||
public DependencyChecker(ClassHolderSource classSource, ClassLoader classLoader, int numThreads) {
|
||||
public DependencyChecker(ClassHolderSource classSource, ClassLoader classLoader, FiniteExecutor executor) {
|
||||
this.classSource = classSource;
|
||||
this.classLoader = classLoader;
|
||||
executor = new ScheduledThreadPoolExecutor(numThreads);
|
||||
executor.setThreadFactory(new ThreadFactory() {
|
||||
@Override public Thread newThread(Runnable r) {
|
||||
Thread thread = new Thread(r);
|
||||
thread.setDaemon(true);
|
||||
return thread;
|
||||
}
|
||||
});
|
||||
this.executor = executor;
|
||||
methodCache = new ConcurrentCachedMapper<>(new Mapper<MethodReference, MethodGraph>() {
|
||||
@Override public MethodGraph map(MethodReference preimage) {
|
||||
return createMethodGraph(preimage);
|
||||
|
@ -98,58 +88,15 @@ public class DependencyChecker {
|
|||
}
|
||||
|
||||
public void schedulePropagation(final DependencyConsumer consumer, final String type) {
|
||||
schedule(new Runnable() {
|
||||
executor.executeFast(new Runnable() {
|
||||
@Override public void run() {
|
||||
consumer.consume(type);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void schedule(final Runnable runnable) {
|
||||
synchronized (activeTaskMonitor) {
|
||||
activeTaskCount.incrementAndGet();
|
||||
}
|
||||
try {
|
||||
executor.execute(new Runnable() {
|
||||
@Override public void run() {
|
||||
try {
|
||||
runnable.run();
|
||||
} catch (RuntimeException e) {
|
||||
activeTaskMonitor.notifyAll();
|
||||
exceptionOccured.compareAndSet(null, e);
|
||||
executor.shutdownNow();
|
||||
}
|
||||
synchronized (activeTaskMonitor) {
|
||||
if (activeTaskCount.decrementAndGet() == 0) {
|
||||
activeTaskMonitor.notifyAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (RejectedExecutionException e) {
|
||||
throw exceptionOccured.get();
|
||||
}
|
||||
}
|
||||
|
||||
public void checkDependencies() {
|
||||
while (true) {
|
||||
try {
|
||||
synchronized (activeTaskMonitor) {
|
||||
if (activeTaskCount.get() == 0 || exceptionOccured.get() != null) {
|
||||
break;
|
||||
}
|
||||
activeTaskMonitor.wait();
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
break;
|
||||
}
|
||||
}
|
||||
RuntimeException e = exceptionOccured.get();
|
||||
if (e != null) {
|
||||
throw exceptionOccured.get();
|
||||
}
|
||||
executor.shutdown();
|
||||
public FiniteExecutor getExecutor() {
|
||||
return executor;
|
||||
}
|
||||
|
||||
boolean achieveClass(String className) {
|
||||
|
@ -226,7 +173,7 @@ public class DependencyChecker {
|
|||
}
|
||||
final MethodGraph graph = new MethodGraph(parameterNodes, paramCount, resultNode, this);
|
||||
final MethodHolder currentMethod = method;
|
||||
schedule(new Runnable() {
|
||||
executor.execute(new Runnable() {
|
||||
@Override public void run() {
|
||||
DependencyGraphBuilder graphBuilder = new DependencyGraphBuilder(DependencyChecker.this);
|
||||
graphBuilder.buildGraph(currentMethod, graph);
|
||||
|
|
|
@ -21,10 +21,10 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import org.teavm.codegen.*;
|
||||
import org.teavm.common.FiniteExecutor;
|
||||
import org.teavm.dependency.DependencyChecker;
|
||||
import org.teavm.javascript.ast.ClassNode;
|
||||
import org.teavm.model.*;
|
||||
import org.teavm.model.resource.ClasspathClassHolderSource;
|
||||
import org.teavm.model.util.*;
|
||||
import org.teavm.optimization.ClassSetOptimizer;
|
||||
|
||||
|
@ -35,25 +35,19 @@ import org.teavm.optimization.ClassSetOptimizer;
|
|||
public class JavascriptBuilder {
|
||||
private ClassHolderSource classSource;
|
||||
private DependencyChecker dependencyChecker;
|
||||
private FiniteExecutor executor;
|
||||
private ClassLoader classLoader;
|
||||
private boolean minifying = true;
|
||||
private boolean bytecodeLogging = true;
|
||||
private boolean bytecodeLogging;
|
||||
private OutputStream logStream = System.out;
|
||||
private Map<String, JavascriptEntryPoint> entryPoints = new HashMap<>();
|
||||
private Map<String, String> exportedClasses = new HashMap<>();
|
||||
|
||||
public JavascriptBuilder(ClassHolderSource classSource, ClassLoader classLoader) {
|
||||
JavascriptBuilder(ClassHolderSource classSource, ClassLoader classLoader, FiniteExecutor executor) {
|
||||
this.classSource = classSource;
|
||||
this.classLoader = classLoader;
|
||||
dependencyChecker = new DependencyChecker(classSource, classLoader);
|
||||
}
|
||||
|
||||
public JavascriptBuilder(ClassLoader classLoader) {
|
||||
this(new ClasspathClassHolderSource(classLoader), classLoader);
|
||||
}
|
||||
|
||||
public JavascriptBuilder() {
|
||||
this(JavascriptBuilder.class.getClassLoader());
|
||||
dependencyChecker = new DependencyChecker(classSource, classLoader, executor);
|
||||
this.executor = executor;
|
||||
}
|
||||
|
||||
public boolean isMinifying() {
|
||||
|
@ -107,7 +101,7 @@ public class JavascriptBuilder {
|
|||
ValueType.object("java.lang.Class"))));
|
||||
dependencyChecker.attachMethodGraph(new MethodReference("java.lang.String", new MethodDescriptor("<init>",
|
||||
ValueType.arrayOf(ValueType.CHARACTER), ValueType.VOID)));
|
||||
dependencyChecker.checkDependencies();
|
||||
executor.complete();
|
||||
ListableClassHolderSource classSet = dependencyChecker.cutUnachievableClasses();
|
||||
Decompiler decompiler = new Decompiler(classSet, classLoader);
|
||||
ClassSetOptimizer optimizer = new ClassSetOptimizer();
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* 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.javascript;
|
||||
|
||||
import org.teavm.common.FiniteExecutor;
|
||||
import org.teavm.common.SimpleFiniteExecutor;
|
||||
import org.teavm.model.ClassHolderSource;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
public class JavascriptBuilderFactory {
|
||||
ClassHolderSource classSource;
|
||||
ClassLoader classLoader;
|
||||
FiniteExecutor executor = new SimpleFiniteExecutor();
|
||||
|
||||
public ClassHolderSource getClassSource() {
|
||||
return classSource;
|
||||
}
|
||||
|
||||
public void setClassSource(ClassHolderSource classSource) {
|
||||
this.classSource = classSource;
|
||||
}
|
||||
|
||||
public ClassLoader getClassLoader() {
|
||||
return classLoader;
|
||||
}
|
||||
|
||||
public void setClassLoader(ClassLoader classLoader) {
|
||||
this.classLoader = classLoader;
|
||||
}
|
||||
|
||||
public FiniteExecutor getExecutor() {
|
||||
return executor;
|
||||
}
|
||||
|
||||
public void setExecutor(FiniteExecutor executor) {
|
||||
this.executor = executor;
|
||||
}
|
||||
|
||||
public JavascriptBuilder create() {
|
||||
return new JavascriptBuilder(classSource, classLoader, executor);
|
||||
}
|
||||
}
|
|
@ -34,7 +34,11 @@ import org.apache.maven.plugins.annotations.Parameter;
|
|||
import org.apache.maven.plugins.annotations.ResolutionScope;
|
||||
import org.apache.maven.project.MavenProject;
|
||||
import org.junit.Test;
|
||||
import org.teavm.common.FiniteExecutor;
|
||||
import org.teavm.common.SimpleFiniteExecutor;
|
||||
import org.teavm.common.ThreadPoolFiniteExecutor;
|
||||
import org.teavm.javascript.JavascriptBuilder;
|
||||
import org.teavm.javascript.JavascriptBuilderFactory;
|
||||
import org.teavm.model.*;
|
||||
import org.teavm.model.resource.ClasspathClassHolderSource;
|
||||
|
||||
|
@ -68,6 +72,9 @@ public class BuildJavascriptJUnitMojo extends AbstractMojo {
|
|||
@Parameter
|
||||
private boolean minifying = true;
|
||||
|
||||
@Parameter
|
||||
private int numThreads = 1;
|
||||
|
||||
public void setProject(MavenProject project) {
|
||||
this.project = project;
|
||||
}
|
||||
|
@ -88,8 +95,13 @@ public class BuildJavascriptJUnitMojo extends AbstractMojo {
|
|||
this.minifying = minifying;
|
||||
}
|
||||
|
||||
public void setNumThreads(int numThreads) {
|
||||
this.numThreads = numThreads;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() throws MojoExecutionException, MojoFailureException {
|
||||
Runnable finalizer = null;
|
||||
try {
|
||||
ClassLoader classLoader = prepareClassLoader();
|
||||
getLog().info("Searching for tests in the directory `" + testFiles.getAbsolutePath() + "'");
|
||||
|
@ -146,14 +158,29 @@ public class BuildJavascriptJUnitMojo extends AbstractMojo {
|
|||
}
|
||||
int methodsGenerated = 0;
|
||||
log.info("Generating test files");
|
||||
FiniteExecutor executor = new SimpleFiniteExecutor();
|
||||
if (numThreads != 1) {
|
||||
int threads = numThreads != 0 ? numThreads : Runtime.getRuntime().availableProcessors();
|
||||
final ThreadPoolFiniteExecutor threadedExecutor = new ThreadPoolFiniteExecutor(threads);
|
||||
finalizer = new Runnable() {
|
||||
@Override public void run() {
|
||||
threadedExecutor.stop();
|
||||
}
|
||||
};
|
||||
executor = threadedExecutor;
|
||||
}
|
||||
for (MethodReference method : testMethods) {
|
||||
log.debug("Building test for " + method);
|
||||
decompileClassesForTest(classLoader, method, fileNames.get(method));
|
||||
decompileClassesForTest(classLoader, method, fileNames.get(method), executor);
|
||||
++methodsGenerated;
|
||||
}
|
||||
log.info("Test files successfully generated for " + methodsGenerated + " method(s)");
|
||||
} catch (IOException e) {
|
||||
throw new MojoFailureException("IO error occured generating JavaScript files", e);
|
||||
} finally {
|
||||
if (finalizer != null) {
|
||||
finalizer.run();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -189,9 +216,13 @@ public class BuildJavascriptJUnitMojo extends AbstractMojo {
|
|||
}
|
||||
}
|
||||
|
||||
private void decompileClassesForTest(ClassLoader classLoader, MethodReference methodRef, String targetName)
|
||||
throws IOException {
|
||||
JavascriptBuilder builder = new JavascriptBuilder(classLoader);
|
||||
private void decompileClassesForTest(ClassLoader classLoader, MethodReference methodRef, String targetName,
|
||||
FiniteExecutor executor) throws IOException {
|
||||
JavascriptBuilderFactory builderFactory = new JavascriptBuilderFactory();
|
||||
builderFactory.setClassLoader(classLoader);
|
||||
builderFactory.setClassSource(new ClasspathClassHolderSource(classLoader));
|
||||
builderFactory.setExecutor(executor);
|
||||
JavascriptBuilder builder = builderFactory.create();
|
||||
builder.setMinifying(minifying);
|
||||
File file = new File(outputDir, targetName);
|
||||
try (Writer innerWriter = new OutputStreamWriter(new FileOutputStream(file), "UTF-8")) {
|
||||
|
|
|
@ -30,10 +30,13 @@ import org.apache.maven.plugins.annotations.Mojo;
|
|||
import org.apache.maven.plugins.annotations.Parameter;
|
||||
import org.apache.maven.plugins.annotations.ResolutionScope;
|
||||
import org.apache.maven.project.MavenProject;
|
||||
import org.teavm.common.ThreadPoolFiniteExecutor;
|
||||
import org.teavm.javascript.JavascriptBuilder;
|
||||
import org.teavm.javascript.JavascriptBuilderFactory;
|
||||
import org.teavm.model.MethodDescriptor;
|
||||
import org.teavm.model.MethodReference;
|
||||
import org.teavm.model.ValueType;
|
||||
import org.teavm.model.resource.ClasspathClassHolderSource;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -71,6 +74,9 @@ public class BuildJavascriptMojo extends AbstractMojo {
|
|||
@Parameter
|
||||
private boolean bytecodeLogging;
|
||||
|
||||
@Parameter(required = false)
|
||||
private int numThreads = 1;
|
||||
|
||||
public void setProject(MavenProject project) {
|
||||
this.project = project;
|
||||
}
|
||||
|
@ -99,13 +105,31 @@ public class BuildJavascriptMojo extends AbstractMojo {
|
|||
this.mainPageIncluded = mainPageIncluded;
|
||||
}
|
||||
|
||||
public void setNumThreads(int numThreads) {
|
||||
this.numThreads = numThreads;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() throws MojoExecutionException {
|
||||
Log log = getLog();
|
||||
Runnable finalizer = null;
|
||||
try {
|
||||
ClassLoader classLoader = prepareClassLoader();
|
||||
log.info("Building JavaScript file");
|
||||
JavascriptBuilder builder = new JavascriptBuilder(classLoader);
|
||||
JavascriptBuilderFactory builderFactory = new JavascriptBuilderFactory();
|
||||
builderFactory.setClassLoader(classLoader);
|
||||
builderFactory.setClassSource(new ClasspathClassHolderSource(classLoader));
|
||||
if (numThreads != 1) {
|
||||
int threads = numThreads != 0 ? numThreads : Runtime.getRuntime().availableProcessors();
|
||||
final ThreadPoolFiniteExecutor executor = new ThreadPoolFiniteExecutor(threads);
|
||||
finalizer = new Runnable() {
|
||||
@Override public void run() {
|
||||
executor.stop();
|
||||
}
|
||||
};
|
||||
builderFactory.setExecutor(executor);
|
||||
}
|
||||
JavascriptBuilder builder = builderFactory.create();
|
||||
builder.setMinifying(minifying);
|
||||
builder.setBytecodeLogging(bytecodeLogging);
|
||||
MethodDescriptor mainMethodDesc = new MethodDescriptor("main", ValueType.arrayOf(
|
||||
|
@ -133,6 +157,10 @@ public class BuildJavascriptMojo extends AbstractMojo {
|
|||
throw new MojoExecutionException("Unexpected error occured", e);
|
||||
} catch (IOException e) {
|
||||
throw new MojoExecutionException("IO error occured", e);
|
||||
} finally {
|
||||
if (finalizer != null) {
|
||||
finalizer.run();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user