mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 16:14:10 -08:00
Merge branch 'async' of https://github.com/konsoletyper/teavm into threads
This commit is contained in:
commit
7c084effb0
|
@ -15,6 +15,9 @@
|
|||
*/
|
||||
package org.teavm.classlib.java.lang;
|
||||
|
||||
import org.teavm.javascript.ni.GeneratedBy;
|
||||
import org.teavm.runtime.Async;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
|
@ -56,8 +59,9 @@ public class TThread extends TObject implements TRunnable {
|
|||
return name;
|
||||
}
|
||||
|
||||
public static void yield() {
|
||||
}
|
||||
@Async
|
||||
@GeneratedBy(ThreadNativeGenerator.class)
|
||||
public static native void yield();
|
||||
|
||||
public void interrupt() {
|
||||
}
|
||||
|
@ -81,4 +85,12 @@ public class TThread extends TObject implements TRunnable {
|
|||
public static boolean holdsLock(@SuppressWarnings("unused") TObject obj) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void sleep(long millis) throws TInterruptedException {
|
||||
sleep((double)millis);
|
||||
}
|
||||
|
||||
@Async
|
||||
@GeneratedBy(ThreadNativeGenerator.class)
|
||||
private static native void sleep(double millis) throws TInterruptedException;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Copyright 2015 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.classlib.java.lang;
|
||||
|
||||
import java.io.IOException;
|
||||
import org.teavm.codegen.SourceWriter;
|
||||
import org.teavm.javascript.ni.Generator;
|
||||
import org.teavm.javascript.ni.GeneratorContext;
|
||||
import org.teavm.model.MethodReference;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev <konsoletyper@gmail.com>
|
||||
*/
|
||||
public class ThreadNativeGenerator implements Generator {
|
||||
@Override
|
||||
public void generate(GeneratorContext context, SourceWriter writer, MethodReference methodRef) throws IOException {
|
||||
if (methodRef.getName().equals("sleep")) {
|
||||
generateSleep(context, writer);
|
||||
} else if (methodRef.getName().equals("yield")) {
|
||||
generateYield(context, writer);
|
||||
}
|
||||
}
|
||||
|
||||
private void generateSleep(GeneratorContext context, SourceWriter writer) throws IOException {
|
||||
writer.append("setTimeout(function() {").indent().softNewLine();
|
||||
writer.append(context.getCompleteContinuation()).append("();").softNewLine();
|
||||
writer.outdent().append("},").ws().append(context.getParameterName(1)).append(");").softNewLine();
|
||||
}
|
||||
|
||||
private void generateYield(GeneratorContext context, SourceWriter writer) throws IOException {
|
||||
writer.append("setTimeout(function() {").indent().softNewLine();
|
||||
writer.append(context.getCompleteContinuation()).append("();").softNewLine();
|
||||
writer.outdent().append("},").ws().append("0);").softNewLine();
|
||||
}
|
||||
}
|
|
@ -57,6 +57,15 @@ public class DefaultNamingStrategy implements NamingStrategy {
|
|||
|
||||
@Override
|
||||
public String getNameFor(MethodReference method) {
|
||||
return getNameFor(method, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getNameForAsync(MethodReference method) throws NamingException {
|
||||
return getNameFor(method, true);
|
||||
}
|
||||
|
||||
private String getNameFor(MethodReference method, boolean async) {
|
||||
MethodReference origMethod = method;
|
||||
method = getRealMethod(method);
|
||||
if (method == null) {
|
||||
|
@ -67,7 +76,7 @@ public class DefaultNamingStrategy implements NamingStrategy {
|
|||
if (methodHolder.hasModifier(ElementModifier.STATIC) ||
|
||||
method.getDescriptor().getName().equals("<init>") ||
|
||||
methodHolder.getLevel() == AccessLevel.PRIVATE) {
|
||||
String key = method.toString();
|
||||
String key = (async ? "A" : "S") + method.toString();
|
||||
String alias = privateAliases.get(key);
|
||||
if (alias == null) {
|
||||
alias = aliasProvider.getAlias(method);
|
||||
|
@ -75,7 +84,7 @@ public class DefaultNamingStrategy implements NamingStrategy {
|
|||
}
|
||||
return alias;
|
||||
} else {
|
||||
String key = method.getDescriptor().toString();
|
||||
String key = (async ? "A" : "S") + method.getDescriptor().toString();
|
||||
String alias = aliases.get(key);
|
||||
if (alias == null) {
|
||||
alias = aliasProvider.getAlias(method);
|
||||
|
|
|
@ -27,6 +27,8 @@ public interface NamingStrategy {
|
|||
|
||||
String getNameFor(MethodReference method) throws NamingException;
|
||||
|
||||
String getNameForAsync(MethodReference method) throws NamingException;
|
||||
|
||||
String getFullNameFor(MethodReference method) throws NamingException;
|
||||
|
||||
String getNameFor(FieldReference field) throws NamingException;
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Copyright 2015 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;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
public enum AsyncInvocationType {
|
||||
COMPLETE,
|
||||
ERROR
|
||||
}
|
|
@ -23,6 +23,7 @@ import org.teavm.javascript.ni.Generator;
|
|||
import org.teavm.javascript.ni.InjectedBy;
|
||||
import org.teavm.javascript.ni.PreserveOriginalName;
|
||||
import org.teavm.model.*;
|
||||
import org.teavm.model.util.AsyncProgramSplitter;
|
||||
import org.teavm.model.util.ProgramUtils;
|
||||
|
||||
/**
|
||||
|
@ -45,10 +46,12 @@ public class Decompiler {
|
|||
private Map<MethodReference, Generator> generators = new HashMap<>();
|
||||
private Set<MethodReference> methodsToPass = new HashSet<>();
|
||||
private RegularMethodNodeCache regularMethodCache;
|
||||
private Set<MethodReference> asyncMethods;
|
||||
|
||||
public Decompiler(ClassHolderSource classSource, ClassLoader classLoader) {
|
||||
public Decompiler(ClassHolderSource classSource, ClassLoader classLoader, Set<MethodReference> asyncMethods) {
|
||||
this.classSource = classSource;
|
||||
this.classLoader = classLoader;
|
||||
this.asyncMethods = asyncMethods;
|
||||
}
|
||||
|
||||
public RegularMethodNodeCache getRegularMethodCache() {
|
||||
|
@ -154,7 +157,7 @@ public class Decompiler {
|
|||
|
||||
public MethodNode decompile(MethodHolder method) {
|
||||
return method.getModifiers().contains(ElementModifier.NATIVE) ? decompileNative(method) :
|
||||
decompileRegular(method);
|
||||
!asyncMethods.contains(method.getReference()) ? decompileRegular(method) : decompileAsync(method);
|
||||
}
|
||||
|
||||
public NativeMethodNode decompileNative(MethodHolder method) {
|
||||
|
@ -179,6 +182,7 @@ public class Decompiler {
|
|||
method.getDescriptor()));
|
||||
methodNode.getModifiers().addAll(mapModifiers(method.getModifiers()));
|
||||
methodNode.setGenerator(generator);
|
||||
methodNode.setAsync(asyncMethods.contains(method.getReference()));
|
||||
return methodNode;
|
||||
}
|
||||
|
||||
|
@ -194,14 +198,58 @@ public class Decompiler {
|
|||
return node;
|
||||
}
|
||||
|
||||
public AsyncMethodNode decompileAsync(MethodHolder method) {
|
||||
AsyncMethodNode node = new AsyncMethodNode(method.getReference());
|
||||
AsyncProgramSplitter splitter = new AsyncProgramSplitter(asyncMethods);
|
||||
splitter.split(method.getProgram());
|
||||
for (int i = 0; i < splitter.size(); ++i) {
|
||||
AsyncMethodPart part = getRegularMethodStatement(splitter.getProgram(i), splitter.getBlockSuccessors(i));
|
||||
part.setInputVariable(splitter.getInput(i));
|
||||
node.getBody().add(part);
|
||||
}
|
||||
Program program = method.getProgram();
|
||||
for (int i = 0; i < program.variableCount(); ++i) {
|
||||
node.getVariables().add(program.variableAt(i).getRegister());
|
||||
}
|
||||
Optimizer optimizer = new Optimizer();
|
||||
optimizer.optimize(node, method.getProgram());
|
||||
node.getModifiers().addAll(mapModifiers(method.getModifiers()));
|
||||
int paramCount = Math.min(method.getSignature().length, program.variableCount());
|
||||
for (int i = 0; i < paramCount; ++i) {
|
||||
Variable var = program.variableAt(i);
|
||||
node.getParameterDebugNames().add(new HashSet<>(var.getDebugNames()));
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
public RegularMethodNode decompileRegularCacheMiss(MethodHolder method) {
|
||||
RegularMethodNode methodNode = new RegularMethodNode(method.getReference());
|
||||
Program program = method.getProgram();
|
||||
int[] targetBlocks = new int[program.basicBlockCount()];
|
||||
Arrays.fill(targetBlocks, -1);
|
||||
methodNode.setBody(getRegularMethodStatement(program, targetBlocks).getStatement());
|
||||
for (int i = 0; i < program.variableCount(); ++i) {
|
||||
methodNode.getVariables().add(program.variableAt(i).getRegister());
|
||||
}
|
||||
Optimizer optimizer = new Optimizer();
|
||||
optimizer.optimize(methodNode, method.getProgram());
|
||||
methodNode.getModifiers().addAll(mapModifiers(method.getModifiers()));
|
||||
int paramCount = Math.min(method.getSignature().length, program.variableCount());
|
||||
for (int i = 0; i < paramCount; ++i) {
|
||||
Variable var = program.variableAt(i);
|
||||
methodNode.getParameterDebugNames().add(new HashSet<>(var.getDebugNames()));
|
||||
}
|
||||
return methodNode;
|
||||
}
|
||||
|
||||
private AsyncMethodPart getRegularMethodStatement(Program program, int[] targetBlocks) {
|
||||
AsyncMethodPart result = new AsyncMethodPart();
|
||||
lastBlockId = 1;
|
||||
graph = ProgramUtils.buildControlFlowGraph(method.getProgram());
|
||||
graph = ProgramUtils.buildControlFlowGraph(program);
|
||||
indexer = new GraphIndexer(graph);
|
||||
graph = indexer.getGraph();
|
||||
loopGraph = new LoopGraph(this.graph);
|
||||
unflatCode();
|
||||
Program program = method.getProgram();
|
||||
blockMap = new Block[program.basicBlockCount() * 2 + 1];
|
||||
Deque<Block> stack = new ArrayDeque<>();
|
||||
BlockStatement rootStmt = new BlockStatement();
|
||||
|
@ -247,9 +295,13 @@ public class Decompiler {
|
|||
int tmp = indexer.nodeAt(next);
|
||||
generator.nextBlock = tmp >= 0 && next < indexer.size() ? program.basicBlockAt(tmp) : null;
|
||||
generator.statements.clear();
|
||||
generator.asyncTarget = null;
|
||||
InstructionLocation lastLocation = null;
|
||||
NodeLocation nodeLocation = null;
|
||||
for (Instruction insn : generator.currentBlock.getInstructions()) {
|
||||
List<Instruction> instructions = generator.currentBlock.getInstructions();
|
||||
boolean asyncInvocation = false;
|
||||
for (int j = 0; j < instructions.size(); ++j) {
|
||||
Instruction insn = generator.currentBlock.getInstructions().get(j);
|
||||
if (insn.getLocation() != null && lastLocation != insn.getLocation()) {
|
||||
lastLocation = insn.getLocation();
|
||||
nodeLocation = new NodeLocation(lastLocation.getFileName(), lastLocation.getLine());
|
||||
|
@ -257,9 +309,15 @@ public class Decompiler {
|
|||
if (insn.getLocation() != null) {
|
||||
generator.setCurrentLocation(nodeLocation);
|
||||
}
|
||||
if (targetBlocks[node] >= 0 && j == instructions.size() - 1) {
|
||||
generator.asyncTarget = targetBlocks[node];
|
||||
asyncInvocation = true;
|
||||
}
|
||||
insn.acceptVisitor(generator);
|
||||
}
|
||||
boolean hasAsyncCatch = false;
|
||||
for (TryCatchBlock tryCatch : generator.currentBlock.getTryCatchBlocks()) {
|
||||
if (asyncInvocation) {
|
||||
TryCatchStatement tryCatchStmt = new TryCatchStatement();
|
||||
tryCatchStmt.setExceptionType(tryCatch.getExceptionType());
|
||||
tryCatchStmt.setExceptionVariable(tryCatch.getExceptionVariable().getIndex());
|
||||
|
@ -270,28 +328,32 @@ public class Decompiler {
|
|||
if (handlerStmt != null) {
|
||||
tryCatchStmt.getHandler().add(handlerStmt);
|
||||
}
|
||||
} else {
|
||||
AsyncMethodCatch asyncCatch = new AsyncMethodCatch();
|
||||
asyncCatch.setExceptionType(tryCatch.getExceptionType());
|
||||
asyncCatch.setExceptionVariable(tryCatch.getExceptionVariable().getIndex());
|
||||
Statement handlerStmt = generator.generateJumpStatement(tryCatch.getHandler());
|
||||
if (handlerStmt != null) {
|
||||
asyncCatch.getHandler().add(handlerStmt);
|
||||
}
|
||||
result.getCatches().add(asyncCatch);
|
||||
hasAsyncCatch = true;
|
||||
}
|
||||
}
|
||||
if (hasAsyncCatch) {
|
||||
TryCatchStatement guardTryCatch = new TryCatchStatement();
|
||||
guardTryCatch.setAsync(true);
|
||||
guardTryCatch.getProtectedBody().addAll(generator.statements);
|
||||
generator.statements.clear();
|
||||
generator.statements.add(guardTryCatch);
|
||||
}
|
||||
block.body.addAll(generator.statements);
|
||||
}
|
||||
}
|
||||
SequentialStatement result = new SequentialStatement();
|
||||
result.getSequence().addAll(rootStmt.getBody());
|
||||
MethodReference reference = new MethodReference(method.getOwnerName(), method.getDescriptor());
|
||||
RegularMethodNode methodNode = new RegularMethodNode(reference);
|
||||
methodNode.getModifiers().addAll(mapModifiers(method.getModifiers()));
|
||||
methodNode.setBody(result);
|
||||
for (int i = 0; i < program.variableCount(); ++i) {
|
||||
methodNode.getVariables().add(program.variableAt(i).getRegister());
|
||||
}
|
||||
Optimizer optimizer = new Optimizer();
|
||||
optimizer.optimize(methodNode, method.getProgram());
|
||||
methodNode.getModifiers().addAll(mapModifiers(method.getModifiers()));
|
||||
int paramCount = Math.min(method.getSignature().length, program.variableCount());
|
||||
for (int i = 0; i < paramCount; ++i) {
|
||||
Variable var = program.variableAt(i);
|
||||
methodNode.getParameterDebugNames().add(new HashSet<>(var.getDebugNames()));
|
||||
}
|
||||
return methodNode;
|
||||
SequentialStatement resultBody = new SequentialStatement();
|
||||
resultBody.getSequence().addAll(rootStmt.getBody());
|
||||
result.setStatement(resultBody);
|
||||
return result;
|
||||
}
|
||||
|
||||
private Set<NodeModifier> mapModifiers(Set<ElementModifier> modifiers) {
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
*/
|
||||
package org.teavm.javascript;
|
||||
|
||||
import org.teavm.javascript.ast.AsyncMethodNode;
|
||||
import org.teavm.javascript.ast.AsyncMethodPart;
|
||||
import org.teavm.javascript.ast.RegularMethodNode;
|
||||
import org.teavm.model.Program;
|
||||
|
||||
|
@ -40,4 +42,27 @@ public class Optimizer {
|
|||
method.getVariables().set(i, i);
|
||||
}
|
||||
}
|
||||
|
||||
public void optimize(AsyncMethodNode method, Program program) {
|
||||
ReadWriteStatsBuilder stats = new ReadWriteStatsBuilder(method.getVariables().size());
|
||||
stats.analyze(program);
|
||||
OptimizingVisitor optimizer = new OptimizingVisitor(stats);
|
||||
for (AsyncMethodPart part : method.getBody()) {
|
||||
part.getStatement().acceptVisitor(optimizer);
|
||||
part.setStatement(optimizer.resultStmt);
|
||||
}
|
||||
int paramCount = method.getReference().parameterCount();
|
||||
UnusedVariableEliminator unusedEliminator = new UnusedVariableEliminator(paramCount, method.getVariables());
|
||||
for (AsyncMethodPart part : method.getBody()) {
|
||||
part.getStatement().acceptVisitor(unusedEliminator);
|
||||
}
|
||||
method.getVariables().subList(unusedEliminator.lastIndex, method.getVariables().size()).clear();
|
||||
RedundantLabelEliminator labelEliminator = new RedundantLabelEliminator();
|
||||
for (AsyncMethodPart part : method.getBody()) {
|
||||
part.getStatement().acceptVisitor(labelEliminator);
|
||||
}
|
||||
for (int i = 0; i < method.getVariables().size(); ++i) {
|
||||
method.getVariables().set(i, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -180,7 +180,7 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor {
|
|||
}
|
||||
|
||||
private boolean tryApplyConstructor(InvocationExpr expr) {
|
||||
if (!expr.getMethod().getName().equals("<init>")) {
|
||||
if (expr.getAsyncTarget() != null || !expr.getMethod().getName().equals("<init>")) {
|
||||
return false;
|
||||
}
|
||||
if (resultSequence == null || resultSequence.isEmpty()) {
|
||||
|
@ -211,7 +211,7 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor {
|
|||
}
|
||||
Expr[] args = expr.getArguments().toArray(new Expr[0]);
|
||||
args = Arrays.copyOfRange(args, 1, args.length);
|
||||
Expr constructrExpr = Expr.constructObject(expr.getMethod(), args);
|
||||
InvocationExpr constructrExpr = Expr.constructObject(expr.getMethod(), args);
|
||||
constructrExpr.setLocation(expr.getLocation());
|
||||
assignment.setRightValue(constructrExpr);
|
||||
stats.reads[var.getIndex()]--;
|
||||
|
|
|
@ -53,6 +53,7 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
|||
private Deque<LocationStackEntry> locationStack = new ArrayDeque<>();
|
||||
private DeferredCallSite lastCallSite;
|
||||
private DeferredCallSite prevCallSite;
|
||||
private boolean async;
|
||||
|
||||
private static class InjectorHolder {
|
||||
public final Injector injector;
|
||||
|
@ -469,6 +470,12 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
|||
}
|
||||
writer.append(");").ws().append("}");
|
||||
debugEmitter.emitMethod(null);
|
||||
|
||||
if (!method.isAsync()) {
|
||||
writer.append(",").newLine();
|
||||
writer.append("\"").append(naming.getNameForAsync(ref)).append("\",").ws();
|
||||
writer.append("$rt_asyncAdapter(").appendMethodBody(ref).append(')');
|
||||
}
|
||||
}
|
||||
writer.append(");").newLine().outdent();
|
||||
}
|
||||
|
@ -518,6 +525,12 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
|||
}
|
||||
writer.append(variableName(i));
|
||||
}
|
||||
if (method.isAsync()) {
|
||||
if (startParam < ref.parameterCount() + 1) {
|
||||
writer.append(',').ws();
|
||||
}
|
||||
writer.append("$return,").ws().append("$throw");
|
||||
}
|
||||
writer.append(")").ws().append("{").softNewLine().indent();
|
||||
method.acceptVisitor(new MethodBodyRenderer());
|
||||
writer.outdent().append("}").newLine();
|
||||
|
@ -525,9 +538,13 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
|||
}
|
||||
|
||||
private class MethodBodyRenderer implements MethodNodeVisitor, GeneratorContext {
|
||||
private boolean async;
|
||||
|
||||
@Override
|
||||
public void visit(NativeMethodNode methodNode) {
|
||||
try {
|
||||
this.async = methodNode.isAsync();
|
||||
Renderer.this.async = methodNode.isAsync();
|
||||
methodNode.getGenerator().generate(this, writer, methodNode.getReference());
|
||||
} catch (IOException e) {
|
||||
throw new RenderingException("IO error occured", e);
|
||||
|
@ -537,6 +554,8 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
|||
@Override
|
||||
public void visit(RegularMethodNode method) {
|
||||
try {
|
||||
Renderer.this.async = false;
|
||||
this.async = false;
|
||||
MethodReference ref = method.getReference();
|
||||
for (int i = 0; i < method.getParameterDebugNames().size(); ++i) {
|
||||
debugEmitter.emitVariable(method.getParameterDebugNames().get(i).toArray(new String[0]),
|
||||
|
@ -572,6 +591,51 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(AsyncMethodNode methodNode) {
|
||||
try {
|
||||
Renderer.this.async = true;
|
||||
this.async = true;
|
||||
MethodReference ref = methodNode.getReference();
|
||||
for (int i = 0; i < methodNode.getParameterDebugNames().size(); ++i) {
|
||||
debugEmitter.emitVariable(methodNode.getParameterDebugNames().get(i).toArray(new String[0]),
|
||||
variableName(i));
|
||||
}
|
||||
int variableCount = 0;
|
||||
for (int var : methodNode.getVariables()) {
|
||||
variableCount = Math.max(variableCount, var + 1);
|
||||
}
|
||||
List<String> variableNames = new ArrayList<>();
|
||||
for (int i = ref.parameterCount() + 1; i < variableCount; ++i) {
|
||||
variableNames.add(variableName(i));
|
||||
}
|
||||
if (!variableNames.isEmpty()) {
|
||||
writer.append("var ");
|
||||
for (int i = 0; i < variableNames.size(); ++i) {
|
||||
if (i > 0) {
|
||||
writer.append(",").ws();
|
||||
}
|
||||
writer.append(variableNames.get(i));
|
||||
}
|
||||
writer.append(";").softNewLine();
|
||||
}
|
||||
for (int i = 0; i < methodNode.getBody().size(); ++i) {
|
||||
writer.append("function $part_").append(i).append("($input)").ws().append('{')
|
||||
.indent().softNewLine();
|
||||
AsyncMethodPart part = methodNode.getBody().get(i);
|
||||
if (part.getInputVariable() != null) {
|
||||
writer.append(variableName(part.getInputVariable())).ws().append('=').ws().append("$input;")
|
||||
.softNewLine();
|
||||
}
|
||||
part.getStatement().acceptVisitor(Renderer.this);
|
||||
writer.outdent().append('}').softNewLine();
|
||||
}
|
||||
writer.append("return $part_0();").softNewLine();
|
||||
} catch (IOException e) {
|
||||
throw new RenderingException("IO error occured", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getParameterName(int index) {
|
||||
return variableName(index);
|
||||
|
@ -596,6 +660,21 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
|||
public <T> T getService(Class<T> type) {
|
||||
return services.getService(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAsync() {
|
||||
return async;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getErrorContinuation() {
|
||||
return "$throw";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCompleteContinuation() {
|
||||
return "$return";
|
||||
}
|
||||
}
|
||||
|
||||
private void pushLocation(NodeLocation location) {
|
||||
|
@ -832,12 +911,18 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
|||
pushLocation(statement.getLocation());
|
||||
}
|
||||
writer.append("return");
|
||||
if (async) {
|
||||
writer.append(" $return(");
|
||||
}
|
||||
if (statement.getResult() != null) {
|
||||
writer.append(' ');
|
||||
prevCallSite = debugEmitter.emitCallSite();
|
||||
statement.getResult().acceptVisitor(this);
|
||||
debugEmitter.emitCallSite();
|
||||
}
|
||||
if (async) {
|
||||
writer.append(')');
|
||||
}
|
||||
writer.append(";").softNewLine();
|
||||
if (statement.getLocation() != null) {
|
||||
popLocation();
|
||||
|
@ -1336,11 +1421,15 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
|||
if (injector != null) {
|
||||
injector.generate(new InjectorContextImpl(expr.getArguments()), expr.getMethod());
|
||||
} else {
|
||||
if (expr.getAsyncTarget() != null) {
|
||||
writer.append("return ");
|
||||
}
|
||||
if (expr.getType() == InvocationType.DYNAMIC) {
|
||||
expr.getArguments().get(0).acceptVisitor(this);
|
||||
}
|
||||
String className = naming.getNameFor(expr.getMethod().getClassName());
|
||||
String name = naming.getNameFor(expr.getMethod());
|
||||
String name = expr.getAsyncTarget() == null ? naming.getNameFor(expr.getMethod()) :
|
||||
naming.getNameForAsync(expr.getMethod());
|
||||
String fullName = naming.getFullNameFor(expr.getMethod());
|
||||
DeferredCallSite callSite = prevCallSite;
|
||||
boolean shouldEraseCallSite = lastCallSite == null;
|
||||
|
@ -1348,6 +1437,7 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
|||
lastCallSite = callSite;
|
||||
}
|
||||
boolean virtual = false;
|
||||
boolean hasParams = false;
|
||||
switch (expr.getType()) {
|
||||
case STATIC:
|
||||
writer.append(fullName).append("(");
|
||||
|
@ -1357,18 +1447,18 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
|||
writer.append(",").ws();
|
||||
}
|
||||
expr.getArguments().get(i).acceptVisitor(this);
|
||||
hasParams = true;
|
||||
}
|
||||
writer.append(')');
|
||||
break;
|
||||
case SPECIAL:
|
||||
writer.append(fullName).append("(");
|
||||
prevCallSite = debugEmitter.emitCallSite();
|
||||
expr.getArguments().get(0).acceptVisitor(this);
|
||||
hasParams = true;
|
||||
for (int i = 1; i < expr.getArguments().size(); ++i) {
|
||||
writer.append(",").ws();
|
||||
expr.getArguments().get(i).acceptVisitor(this);
|
||||
}
|
||||
writer.append(")");
|
||||
break;
|
||||
case DYNAMIC:
|
||||
writer.append(".").append(name).append("(");
|
||||
|
@ -1377,9 +1467,9 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
|||
if (i > 1) {
|
||||
writer.append(",").ws();
|
||||
}
|
||||
hasParams = true;
|
||||
expr.getArguments().get(i).acceptVisitor(this);
|
||||
}
|
||||
writer.append(')');
|
||||
virtual = true;
|
||||
break;
|
||||
case CONSTRUCTOR:
|
||||
|
@ -1389,11 +1479,18 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
|||
if (i > 0) {
|
||||
writer.append(",").ws();
|
||||
}
|
||||
hasParams = true;
|
||||
expr.getArguments().get(i).acceptVisitor(this);
|
||||
}
|
||||
writer.append(')');
|
||||
break;
|
||||
}
|
||||
if (expr.getAsyncTarget() != null) {
|
||||
if (hasParams) {
|
||||
writer.append(',').ws();
|
||||
}
|
||||
writer.append("$rt_continue($part_").append(expr.getAsyncTarget()).append(')');
|
||||
}
|
||||
writer.append(')');
|
||||
if (lastCallSite != null) {
|
||||
if (virtual) {
|
||||
lastCallSite.setVirtualMethod(expr.getMethod());
|
||||
|
|
|
@ -37,6 +37,7 @@ class StatementGenerator implements InstructionVisitor {
|
|||
Program program;
|
||||
ClassHolderSource classSource;
|
||||
private NodeLocation currentLocation;
|
||||
Integer asyncTarget;
|
||||
|
||||
public void setCurrentLocation(NodeLocation currentLocation) {
|
||||
this.currentLocation = currentLocation;
|
||||
|
@ -546,7 +547,7 @@ class StatementGenerator implements InstructionVisitor {
|
|||
for (int i = 0; i < insn.getArguments().size(); ++i) {
|
||||
exprArgs[i] = Expr.var(insn.getArguments().get(i).getIndex());
|
||||
}
|
||||
Expr invocationExpr;
|
||||
InvocationExpr invocationExpr;
|
||||
if (insn.getInstance() != null) {
|
||||
if (insn.getType() == InvocationType.VIRTUAL) {
|
||||
invocationExpr = Expr.invoke(insn.getMethod(), Expr.var(insn.getInstance().getIndex()), exprArgs);
|
||||
|
@ -557,6 +558,8 @@ class StatementGenerator implements InstructionVisitor {
|
|||
} else {
|
||||
invocationExpr = Expr.invokeStatic(insn.getMethod(), exprArgs);
|
||||
}
|
||||
invocationExpr.setAsyncTarget(asyncTarget);
|
||||
if (asyncTarget == null) {
|
||||
if (insn.getReceiver() != null) {
|
||||
assign(invocationExpr, insn.getReceiver());
|
||||
} else {
|
||||
|
@ -564,6 +567,11 @@ class StatementGenerator implements InstructionVisitor {
|
|||
stmt.setLocation(currentLocation);
|
||||
statements.add(stmt);
|
||||
}
|
||||
} else {
|
||||
AssignmentStatement stmt = Statement.assign(null, invocationExpr);
|
||||
stmt.setLocation(currentLocation);
|
||||
statements.add(stmt);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Copyright 2015 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.ast;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
public class AsyncMethodCatch {
|
||||
private List<Statement> handler = new ArrayList<>();
|
||||
private String exceptionType;
|
||||
private Integer exceptionVariable;
|
||||
|
||||
public List<Statement> getHandler() {
|
||||
return handler;
|
||||
}
|
||||
|
||||
public String getExceptionType() {
|
||||
return exceptionType;
|
||||
}
|
||||
|
||||
public void setExceptionType(String exceptionType) {
|
||||
this.exceptionType = exceptionType;
|
||||
}
|
||||
|
||||
public Integer getExceptionVariable() {
|
||||
return exceptionVariable;
|
||||
}
|
||||
|
||||
public void setExceptionVariable(Integer exceptionVariable) {
|
||||
this.exceptionVariable = exceptionVariable;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* Copyright 2015 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.ast;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import org.teavm.model.MethodReference;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
public class AsyncMethodNode extends MethodNode {
|
||||
private List<AsyncMethodPart> body = new ArrayList<>();
|
||||
private List<Integer> variables = new ArrayList<>();
|
||||
private List<Set<String>> parameterDebugNames = new ArrayList<>();
|
||||
|
||||
public AsyncMethodNode(MethodReference reference) {
|
||||
super(reference);
|
||||
}
|
||||
|
||||
public List<AsyncMethodPart> getBody() {
|
||||
return body;
|
||||
}
|
||||
|
||||
public List<Integer> getVariables() {
|
||||
return variables;
|
||||
}
|
||||
|
||||
public List<Set<String>> getParameterDebugNames() {
|
||||
return parameterDebugNames;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void acceptVisitor(MethodNodeVisitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAsync() {
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Copyright 2015 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.ast;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
public class AsyncMethodPart {
|
||||
private Statement statement;
|
||||
private Integer inputVariable;
|
||||
private List<AsyncMethodCatch> catches = new ArrayList<>();
|
||||
|
||||
public Statement getStatement() {
|
||||
return statement;
|
||||
}
|
||||
|
||||
public void setStatement(Statement statement) {
|
||||
this.statement = statement;
|
||||
}
|
||||
|
||||
public Integer getInputVariable() {
|
||||
return inputVariable;
|
||||
}
|
||||
|
||||
public void setInputVariable(Integer inputVariable) {
|
||||
this.inputVariable = inputVariable;
|
||||
}
|
||||
|
||||
public List<AsyncMethodCatch> getCatches() {
|
||||
return catches;
|
||||
}
|
||||
}
|
|
@ -104,7 +104,7 @@ public abstract class Expr implements Cloneable {
|
|||
return expr;
|
||||
}
|
||||
|
||||
public static Expr constructObject(MethodReference method, Expr[] arguments) {
|
||||
public static InvocationExpr constructObject(MethodReference method, Expr[] arguments) {
|
||||
InvocationExpr expr = new InvocationExpr();
|
||||
expr.setMethod(method);
|
||||
expr.setType(InvocationType.CONSTRUCTOR);
|
||||
|
@ -119,7 +119,7 @@ public abstract class Expr implements Cloneable {
|
|||
return expr;
|
||||
}
|
||||
|
||||
public static Expr invoke(MethodReference method, Expr target, Expr[] arguments) {
|
||||
public static InvocationExpr invoke(MethodReference method, Expr target, Expr[] arguments) {
|
||||
InvocationExpr expr = new InvocationExpr();
|
||||
expr.setMethod(method);
|
||||
expr.setType(InvocationType.DYNAMIC);
|
||||
|
@ -128,7 +128,7 @@ public abstract class Expr implements Cloneable {
|
|||
return expr;
|
||||
}
|
||||
|
||||
public static Expr invokeSpecial(MethodReference method, Expr target, Expr[] arguments) {
|
||||
public static InvocationExpr invokeSpecial(MethodReference method, Expr target, Expr[] arguments) {
|
||||
InvocationExpr expr = new InvocationExpr();
|
||||
expr.setMethod(method);
|
||||
expr.setType(InvocationType.SPECIAL);
|
||||
|
@ -137,7 +137,7 @@ public abstract class Expr implements Cloneable {
|
|||
return expr;
|
||||
}
|
||||
|
||||
public static Expr invokeStatic(MethodReference method, Expr[] arguments) {
|
||||
public static InvocationExpr invokeStatic(MethodReference method, Expr[] arguments) {
|
||||
InvocationExpr expr = new InvocationExpr();
|
||||
expr.setMethod(method);
|
||||
expr.setType(InvocationType.STATIC);
|
||||
|
|
|
@ -28,6 +28,7 @@ public class InvocationExpr extends Expr {
|
|||
private MethodReference method;
|
||||
private InvocationType type;
|
||||
private List<Expr> arguments = new ArrayList<>();
|
||||
private Integer asyncTarget;
|
||||
|
||||
public MethodReference getMethod() {
|
||||
return method;
|
||||
|
@ -49,6 +50,14 @@ public class InvocationExpr extends Expr {
|
|||
return arguments;
|
||||
}
|
||||
|
||||
public Integer getAsyncTarget() {
|
||||
return asyncTarget;
|
||||
}
|
||||
|
||||
public void setAsyncTarget(Integer asyncTarget) {
|
||||
this.asyncTarget = asyncTarget;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void acceptVisitor(ExprVisitor visitor) {
|
||||
visitor.visit(this);
|
||||
|
@ -63,6 +72,7 @@ public class InvocationExpr extends Expr {
|
|||
InvocationExpr copy = new InvocationExpr();
|
||||
cache.put(this, copy);
|
||||
copy.setMethod(method);
|
||||
copy.setAsyncTarget(asyncTarget);
|
||||
for (Expr arg : arguments) {
|
||||
copy.getArguments().add(arg.clone(cache));
|
||||
}
|
||||
|
|
|
@ -50,4 +50,6 @@ public abstract class MethodNode {
|
|||
}
|
||||
|
||||
public abstract void acceptVisitor(MethodNodeVisitor visitor);
|
||||
|
||||
public abstract boolean isAsync();
|
||||
}
|
||||
|
|
|
@ -22,5 +22,7 @@ package org.teavm.javascript.ast;
|
|||
public interface MethodNodeVisitor {
|
||||
void visit(RegularMethodNode methodNode);
|
||||
|
||||
void visit(AsyncMethodNode methodNode);
|
||||
|
||||
void visit(NativeMethodNode methodNode);
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ import org.teavm.model.MethodReference;
|
|||
*/
|
||||
public class NativeMethodNode extends MethodNode {
|
||||
private Generator generator;
|
||||
private boolean async;
|
||||
|
||||
public NativeMethodNode(MethodReference reference) {
|
||||
super(reference);
|
||||
|
@ -37,6 +38,15 @@ public class NativeMethodNode extends MethodNode {
|
|||
this.generator = generator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAsync() {
|
||||
return async;
|
||||
}
|
||||
|
||||
public void setAsync(boolean async) {
|
||||
this.async = async;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void acceptVisitor(MethodNodeVisitor visitor) {
|
||||
visitor.visit(this);
|
||||
|
|
|
@ -53,4 +53,9 @@ public class RegularMethodNode extends MethodNode {
|
|||
public void acceptVisitor(MethodNodeVisitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAsync() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@ public class TryCatchStatement extends Statement {
|
|||
private List<Statement> handler = new ArrayList<>();
|
||||
private String exceptionType;
|
||||
private Integer exceptionVariable;
|
||||
private boolean async;
|
||||
|
||||
public List<Statement> getProtectedBody() {
|
||||
return protectedBody;
|
||||
|
@ -52,6 +53,14 @@ public class TryCatchStatement extends Statement {
|
|||
this.exceptionVariable = exceptionVariable;
|
||||
}
|
||||
|
||||
public boolean isAsync() {
|
||||
return async;
|
||||
}
|
||||
|
||||
public void setAsync(boolean async) {
|
||||
this.async = async;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void acceptVisitor(StatementVisitor visitor) {
|
||||
visitor.visit(this);
|
||||
|
|
|
@ -31,4 +31,10 @@ public interface GeneratorContext extends ServiceRepository {
|
|||
ClassLoader getClassLoader();
|
||||
|
||||
Properties getProperties();
|
||||
|
||||
boolean isAsync();
|
||||
|
||||
String getErrorContinuation();
|
||||
|
||||
String getCompleteContinuation();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright 2015 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.model;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
public class AsyncInformation {
|
||||
private Set<MethodReference> syncMethods = new HashSet<>();
|
||||
private Set<MethodReference> asyncMethods = new HashSet<>();
|
||||
|
||||
public Set<MethodReference> getSyncMethods() {
|
||||
return syncMethods;
|
||||
}
|
||||
|
||||
public Set<MethodReference> getAsyncMethods() {
|
||||
return asyncMethods;
|
||||
}
|
||||
}
|
|
@ -17,7 +17,9 @@ package org.teavm.model.instructions;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.teavm.model.*;
|
||||
import org.teavm.model.Instruction;
|
||||
import org.teavm.model.MethodReference;
|
||||
import org.teavm.model.Variable;
|
||||
|
||||
/**
|
||||
*
|
||||
|
|
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
* Copyright 2015 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.model.util;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import org.teavm.callgraph.CallGraph;
|
||||
import org.teavm.callgraph.CallGraphNode;
|
||||
import org.teavm.callgraph.CallSite;
|
||||
import org.teavm.diagnostics.Diagnostics;
|
||||
import org.teavm.javascript.ni.InjectedBy;
|
||||
import org.teavm.model.*;
|
||||
import org.teavm.runtime.Async;
|
||||
import org.teavm.runtime.Sync;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev <konsoletyper@gmail.com>
|
||||
*/
|
||||
public class AsyncMethodFinder {
|
||||
private Set<MethodReference> asyncMethods = new HashSet<>();
|
||||
private CallGraph callGraph;
|
||||
private Diagnostics diagnostics;
|
||||
private ListableClassReaderSource classSource;
|
||||
|
||||
public AsyncMethodFinder(CallGraph callGraph, Diagnostics diagnostics) {
|
||||
this.callGraph = callGraph;
|
||||
this.diagnostics = diagnostics;
|
||||
}
|
||||
|
||||
public Set<MethodReference> getAsyncMethods() {
|
||||
return asyncMethods;
|
||||
}
|
||||
|
||||
public void find(ListableClassReaderSource classSource) {
|
||||
this.classSource = classSource;
|
||||
for (String clsName : classSource.getClassNames()) {
|
||||
ClassReader cls = classSource.get(clsName);
|
||||
for (MethodReader method : cls.getMethods()) {
|
||||
if (asyncMethods.contains(method.getReference())) {
|
||||
continue;
|
||||
}
|
||||
if (method.getAnnotations().get(Async.class.getName()) != null) {
|
||||
add(method.getReference());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void add(MethodReference methodRef) {
|
||||
if (!asyncMethods.add(methodRef)) {
|
||||
return;
|
||||
}
|
||||
CallGraphNode node = callGraph.getNode(methodRef);
|
||||
if (node == null) {
|
||||
return;
|
||||
}
|
||||
ClassReader cls = classSource.get(methodRef.getClassName());
|
||||
if (cls == null) {
|
||||
return;
|
||||
}
|
||||
MethodReader method = cls.getMethod(methodRef.getDescriptor());
|
||||
if (method == null) {
|
||||
return;
|
||||
}
|
||||
if (method.getAnnotations().get(Sync.class.getName()) != null ||
|
||||
method.getAnnotations().get(InjectedBy.class.getName()) != null) {
|
||||
diagnostics.error(new CallLocation(methodRef), "Method {{m0}} is claimed to be synchronous, " +
|
||||
"but it is has invocations of asynchronous methods", methodRef);
|
||||
return;
|
||||
}
|
||||
for (CallSite callSite : node.getCallerCallSites()) {
|
||||
add(callSite.getCaller().getMethod());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,178 @@
|
|||
/*
|
||||
* Copyright 2015 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.model.util;
|
||||
|
||||
import java.util.*;
|
||||
import org.teavm.model.*;
|
||||
import org.teavm.model.instructions.InvokeInstruction;
|
||||
import org.teavm.model.instructions.JumpInstruction;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
public class AsyncProgramSplitter {
|
||||
private List<Part> parts = new ArrayList<>();
|
||||
private Map<Long, Integer> partMap = new HashMap<>();
|
||||
private Set<MethodReference> asyncMethods = new HashSet<>();
|
||||
|
||||
public AsyncProgramSplitter(Set<MethodReference> asyncMethods) {
|
||||
this.asyncMethods = asyncMethods;
|
||||
}
|
||||
|
||||
public void split(Program program) {
|
||||
parts.clear();
|
||||
Program initialProgram = createStubCopy(program);
|
||||
Part initialPart = new Part();
|
||||
initialPart.program = initialProgram;
|
||||
initialPart.blockSuccessors = new int[program.basicBlockCount()];
|
||||
Arrays.fill(initialPart.blockSuccessors, -1);
|
||||
parts.add(initialPart);
|
||||
partMap.put(0L, 0);
|
||||
Step initialStep = new Step();
|
||||
initialStep.source = 0;
|
||||
initialStep.targetPart = initialPart;
|
||||
Queue<Step> queue = new ArrayDeque<>();
|
||||
queue.add(initialStep);
|
||||
|
||||
taskLoop: while (!queue.isEmpty()) {
|
||||
Step step = queue.remove();
|
||||
BasicBlock targetBlock = step.targetPart.program.basicBlockAt(step.source);
|
||||
if (targetBlock.instructionCount() > 0) {
|
||||
continue;
|
||||
}
|
||||
BasicBlock sourceBlock = program.basicBlockAt(step.source);
|
||||
int last = 0;
|
||||
for (int i = 0; i < sourceBlock.getInstructions().size(); ++i) {
|
||||
Instruction insn = sourceBlock.getInstructions().get(i);
|
||||
if (insn instanceof InvokeInstruction) {
|
||||
InvokeInstruction invoke = (InvokeInstruction)insn;
|
||||
if (!asyncMethods.contains(invoke.getMethod())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If we met asynchronous invocation...
|
||||
// Copy portion of current block from last occurence (or from start) to i'th instruction.
|
||||
targetBlock.getInstructions().addAll(ProgramUtils.copyInstructions(sourceBlock,
|
||||
last, i + 1, targetBlock.getProgram()));
|
||||
ProgramUtils.copyTryCatches(sourceBlock, targetBlock.getProgram());
|
||||
for (TryCatchBlock tryCatch : targetBlock.getTryCatchBlocks()) {
|
||||
if (tryCatch.getHandler() != null) {
|
||||
Step next = new Step();
|
||||
next.source = tryCatch.getHandler().getIndex();
|
||||
next.targetPart = step.targetPart;
|
||||
queue.add(next);
|
||||
}
|
||||
}
|
||||
last = i + 1;
|
||||
|
||||
// If this instruction already separates program, end with current block and refer to the
|
||||
// existing part
|
||||
long key = ((long)step.source << 32) | i;
|
||||
if (partMap.containsKey(key)) {
|
||||
step.targetPart.blockSuccessors[targetBlock.getIndex()] = partMap.get(key);
|
||||
continue taskLoop;
|
||||
}
|
||||
|
||||
// Create a new part
|
||||
Program nextProgram = createStubCopy(program);
|
||||
Part part = new Part();
|
||||
part.input = invoke.getReceiver() != null ? invoke.getReceiver().getIndex() : null;
|
||||
part.program = nextProgram;
|
||||
int partId = parts.size();
|
||||
parts.add(part);
|
||||
part.blockSuccessors = new int[program.basicBlockCount() + 1];
|
||||
Arrays.fill(part.blockSuccessors, -1);
|
||||
|
||||
// Mark current instruction as a separator and remember which part is in charge.
|
||||
partMap.put(key, partId);
|
||||
step.targetPart.blockSuccessors[targetBlock.getIndex()] = partId;
|
||||
|
||||
// Continue with a new block in the new part
|
||||
targetBlock = nextProgram.createBasicBlock();
|
||||
if (step.source > 0) {
|
||||
JumpInstruction jumpToNextBlock = new JumpInstruction();
|
||||
jumpToNextBlock.setTarget(targetBlock);
|
||||
nextProgram.basicBlockAt(0).getInstructions().add(jumpToNextBlock);
|
||||
}
|
||||
step.targetPart = part;
|
||||
}
|
||||
}
|
||||
targetBlock.getInstructions().addAll(ProgramUtils.copyInstructions(sourceBlock,
|
||||
last, sourceBlock.getInstructions().size(), targetBlock.getProgram()));
|
||||
for (TryCatchBlock tryCatch : targetBlock.getTryCatchBlocks()) {
|
||||
if (tryCatch.getHandler() != null) {
|
||||
Step next = new Step();
|
||||
next.source = tryCatch.getHandler().getIndex();
|
||||
next.targetPart = step.targetPart;
|
||||
queue.add(next);
|
||||
}
|
||||
}
|
||||
InstructionTransitionExtractor successorExtractor = new InstructionTransitionExtractor();
|
||||
sourceBlock.getLastInstruction().acceptVisitor(successorExtractor);
|
||||
for (BasicBlock successor : successorExtractor.getTargets()) {
|
||||
BasicBlock targetSuccessor = targetBlock.getProgram().basicBlockAt(successor.getIndex());
|
||||
if (targetSuccessor.instructionCount() == 0) {
|
||||
Step next = new Step();
|
||||
next.source = successor.getIndex();
|
||||
next.targetPart = step.targetPart;
|
||||
queue.add(next);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
partMap.clear();
|
||||
}
|
||||
|
||||
private Program createStubCopy(Program program) {
|
||||
Program copy = new Program();
|
||||
for (int i = 0; i < program.basicBlockCount(); ++i) {
|
||||
copy.createBasicBlock();
|
||||
}
|
||||
for (int i = 0; i < program.variableCount(); ++i) {
|
||||
copy.createVariable();
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return parts.size();
|
||||
}
|
||||
|
||||
public Program getProgram(int index) {
|
||||
return parts.get(index).program;
|
||||
}
|
||||
|
||||
public Integer getInput(int index) {
|
||||
return parts.get(index).input;
|
||||
}
|
||||
|
||||
public int[] getBlockSuccessors(int index) {
|
||||
int[] result = parts.get(index).blockSuccessors;
|
||||
return Arrays.copyOf(result, result.length);
|
||||
}
|
||||
|
||||
private static class Part {
|
||||
Program program;
|
||||
Integer input;
|
||||
int[] blockSuccessors;
|
||||
}
|
||||
|
||||
private static class Step {
|
||||
Part targetPart;
|
||||
int source;
|
||||
}
|
||||
}
|
|
@ -92,21 +92,8 @@ public final class ProgramUtils {
|
|||
for (int i = 0; i < program.basicBlockCount(); ++i) {
|
||||
BasicBlockReader block = program.basicBlockAt(i);
|
||||
BasicBlock blockCopy = copy.basicBlockAt(i);
|
||||
for (int j = 0; j < block.instructionCount(); ++j) {
|
||||
block.readInstruction(j, insnCopier);
|
||||
blockCopy.getInstructions().add(insnCopier.copy);
|
||||
}
|
||||
for (PhiReader phi : block.readPhis()) {
|
||||
Phi phiCopy = new Phi();
|
||||
phiCopy.setReceiver(copy.variableAt(phi.getReceiver().getIndex()));
|
||||
for (IncomingReader incoming : phi.readIncomings()) {
|
||||
Incoming incomingCopy = new Incoming();
|
||||
incomingCopy.setSource(copy.basicBlockAt(incoming.getSource().getIndex()));
|
||||
incomingCopy.setValue(copy.variableAt(incoming.getValue().getIndex()));
|
||||
phiCopy.getIncomings().add(incomingCopy);
|
||||
}
|
||||
blockCopy.getPhis().add(phiCopy);
|
||||
}
|
||||
blockCopy.getInstructions().addAll(copyInstructions(block, 0, block.instructionCount(), copy));
|
||||
blockCopy.getPhis().addAll(copyPhis(block, copy));
|
||||
for (TryCatchBlockReader tryCatch : block.readTryCatchBlocks()) {
|
||||
TryCatchBlock tryCatchCopy = new TryCatchBlock();
|
||||
tryCatchCopy.setExceptionType(tryCatch.getExceptionType());
|
||||
|
@ -118,6 +105,46 @@ public final class ProgramUtils {
|
|||
return copy;
|
||||
}
|
||||
|
||||
public static List<Instruction> copyInstructions(BasicBlockReader block, int from, int to, Program target) {
|
||||
List<Instruction> result = new ArrayList<>();
|
||||
InstructionCopyReader copyReader = new InstructionCopyReader();
|
||||
copyReader.programCopy = target;
|
||||
for (int i = from; i < to; ++i) {
|
||||
block.readInstruction(i, copyReader);
|
||||
copyReader.copy.setLocation(copyReader.location);
|
||||
result.add(copyReader.copy);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static List<Phi> copyPhis(BasicBlockReader block, Program target) {
|
||||
List<Phi> result = new ArrayList<>();
|
||||
for (PhiReader phi : block.readPhis()) {
|
||||
Phi phiCopy = new Phi();
|
||||
phiCopy.setReceiver(target.variableAt(phi.getReceiver().getIndex()));
|
||||
for (IncomingReader incoming : phi.readIncomings()) {
|
||||
Incoming incomingCopy = new Incoming();
|
||||
incomingCopy.setSource(target.basicBlockAt(incoming.getSource().getIndex()));
|
||||
incomingCopy.setValue(target.variableAt(incoming.getValue().getIndex()));
|
||||
phiCopy.getIncomings().add(incomingCopy);
|
||||
}
|
||||
result.add(phiCopy);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static List<TryCatchBlock> copyTryCatches(BasicBlockReader block, Program target) {
|
||||
List<TryCatchBlock> result = new ArrayList<>();
|
||||
for (TryCatchBlockReader tryCatch : block.readTryCatchBlocks()) {
|
||||
TryCatchBlock tryCatchCopy = new TryCatchBlock();
|
||||
tryCatchCopy.setExceptionType(tryCatch.getExceptionType());
|
||||
tryCatchCopy.setExceptionVariable(target.variableAt(tryCatch.getExceptionVariable().getIndex()));
|
||||
tryCatchCopy.setHandler(target.basicBlockAt(tryCatch.getHandler().getIndex()));
|
||||
result.add(tryCatchCopy);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static class InstructionCopyReader implements InstructionReader {
|
||||
Instruction copy;
|
||||
Program programCopy;
|
||||
|
|
30
teavm-core/src/main/java/org/teavm/runtime/Async.java
Normal file
30
teavm-core/src/main/java/org/teavm/runtime/Async.java
Normal file
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* Copyright 2015 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.runtime;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.CONSTRUCTOR, ElementType.METHOD })
|
||||
public @interface Async {
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* Copyright 2015 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.runtime;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
public interface AsyncCallback<T> {
|
||||
void complete(T value);
|
||||
|
||||
void error(Exception e);
|
||||
}
|
30
teavm-core/src/main/java/org/teavm/runtime/Sync.java
Normal file
30
teavm-core/src/main/java/org/teavm/runtime/Sync.java
Normal file
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* Copyright 2015 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.runtime;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev <konsoletyper@gmail.com>
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
public @interface Sync {
|
||||
}
|
|
@ -436,7 +436,8 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
|
|||
renderer.renderStringPool();
|
||||
for (Map.Entry<String, TeaVMEntryPoint> entry : entryPoints.entrySet()) {
|
||||
sourceWriter.append("var ").append(entry.getKey()).ws().append("=").ws()
|
||||
.appendMethodBody(entry.getValue().reference).append(";").softNewLine();
|
||||
.append("$rt_rootInvocationAdapter(")
|
||||
.appendMethodBody(entry.getValue().reference).append(");").softNewLine();
|
||||
}
|
||||
for (Map.Entry<String, String> entry : exportedClasses.entrySet()) {
|
||||
sourceWriter.append("var ").append(entry.getKey()).ws().append("=").ws()
|
||||
|
@ -526,8 +527,11 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
|
|||
}
|
||||
|
||||
private List<ClassNode> modelToAst(ListableClassHolderSource classes) {
|
||||
AsyncMethodFinder asyncFinder = new AsyncMethodFinder(dependencyChecker.getCallGraph(), diagnostics);
|
||||
asyncFinder.find(classes);
|
||||
|
||||
progressListener.phaseStarted(TeaVMPhase.DECOMPILATION, classes.getClassNames().size());
|
||||
Decompiler decompiler = new Decompiler(classes, classLoader);
|
||||
Decompiler decompiler = new Decompiler(classes, classLoader, asyncFinder.getAsyncMethods());
|
||||
decompiler.setRegularMethodCache(incremental ? astCache : null);
|
||||
|
||||
for (Map.Entry<MethodReference, Generator> entry : methodGenerators.entrySet()) {
|
||||
|
|
|
@ -392,6 +392,28 @@ function $rt_virtualMethods(cls) {
|
|||
}
|
||||
}
|
||||
}
|
||||
function $rt_asyncAdapter(f) {
|
||||
return function() {
|
||||
var e;
|
||||
var args = Array.prototype.slice.apply(arguments);
|
||||
var $throw = args.pop();
|
||||
var $return = args.pop();
|
||||
try {
|
||||
var result = f.apply(this, args);
|
||||
} catch (e) {
|
||||
return $throw(e);
|
||||
}
|
||||
return $return(result);
|
||||
}
|
||||
}
|
||||
function $rt_rootInvocationAdapter(f) {
|
||||
return function() {
|
||||
var args = Array.prototype.slice.apply(arguments);
|
||||
args.push(function() {});
|
||||
args.push(function() {});
|
||||
return f.apply(this, args);
|
||||
}
|
||||
}
|
||||
var $rt_stringPool_instance;
|
||||
function $rt_stringPool(strings) {
|
||||
$rt_stringPool_instance = new Array(strings.length);
|
||||
|
@ -402,6 +424,21 @@ function $rt_stringPool(strings) {
|
|||
function $rt_s(index) {
|
||||
return $rt_stringPool_instance[index];
|
||||
}
|
||||
var $rt_continueCounter = 0;
|
||||
function $rt_continue(f) {
|
||||
if ($rt_continueCounter++ == 10) {
|
||||
$rt_continueCounter = 0;
|
||||
return function() {
|
||||
var self = this;
|
||||
var args = arguments;
|
||||
setTimeout(function() {
|
||||
f.apply(self, args);
|
||||
}, 0);
|
||||
};
|
||||
} else {
|
||||
return f;
|
||||
}
|
||||
}
|
||||
|
||||
function $dbg_repr(obj) {
|
||||
return obj.toString ? obj.toString() : "";
|
||||
|
|
|
@ -34,5 +34,6 @@
|
|||
<module>teavm-samples-benchmark</module>
|
||||
<module>teavm-samples-storage</module>
|
||||
<module>teavm-samples-video</module>
|
||||
<module>teavm-samples-async</module>
|
||||
</modules>
|
||||
</project>
|
4
teavm-samples/teavm-samples-async/.gitignore
vendored
Normal file
4
teavm-samples/teavm-samples-async/.gitignore
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
/target
|
||||
/.settings
|
||||
/.classpath
|
||||
/.project
|
93
teavm-samples/teavm-samples-async/pom.xml
Normal file
93
teavm-samples/teavm-samples-async/pom.xml
Normal file
|
@ -0,0 +1,93 @@
|
|||
<!--
|
||||
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.
|
||||
-->
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.teavm</groupId>
|
||||
<artifactId>teavm-samples</artifactId>
|
||||
<version>0.3.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>teavm-samples-async</artifactId>
|
||||
|
||||
<packaging>war</packaging>
|
||||
|
||||
<name>TeaVM CPS demo</name>
|
||||
<description>TeaVM application that demonstrates continuation-passing style generator</description>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.teavm</groupId>
|
||||
<artifactId>teavm-classlib</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-war-plugin</artifactId>
|
||||
<version>2.4</version>
|
||||
<configuration>
|
||||
<webResources>
|
||||
<resource>
|
||||
<directory>${project.build.directory}/generated/js</directory>
|
||||
</resource>
|
||||
</webResources>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.teavm</groupId>
|
||||
<artifactId>teavm-maven-plugin</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>web-client</id>
|
||||
<phase>prepare-package</phase>
|
||||
<goals>
|
||||
<goal>build-javascript</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<targetDirectory>${project.build.directory}/generated/js/teavm</targetDirectory>
|
||||
<mainClass>org.teavm.samples.async.AsyncProgram</mainClass>
|
||||
<runtime>SEPARATE</runtime>
|
||||
<minifying>false</minifying>
|
||||
<debugInformationGenerated>true</debugInformationGenerated>
|
||||
<sourceMapsGenerated>true</sourceMapsGenerated>
|
||||
<sourceFilesCopied>true</sourceFilesCopied>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-checkstyle-plugin</artifactId>
|
||||
<configuration>
|
||||
<configLocation>../../checkstyle.xml</configLocation>
|
||||
<propertyExpansion>config_loc=${basedir}/../..</propertyExpansion>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-source-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* Copyright 2015 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.samples.async;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev <konsoletyper@gmail.com>
|
||||
*/
|
||||
public final class AsyncProgram {
|
||||
private AsyncProgram() {
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws InterruptedException {
|
||||
withoutAsync();
|
||||
System.out.println();
|
||||
withAsync();
|
||||
}
|
||||
|
||||
private static void withoutAsync() {
|
||||
System.out.println("Start sync");
|
||||
for (int i = 0; i < 20; ++i) {
|
||||
for (int j = 0; j <= i; ++j) {
|
||||
System.out.print(j);
|
||||
System.out.print(' ');
|
||||
}
|
||||
System.out.println();
|
||||
}
|
||||
System.out.println("Complete sync");
|
||||
}
|
||||
|
||||
private static void withAsync() throws InterruptedException {
|
||||
System.out.println("Start async");
|
||||
for (int i = 0; i < 20; ++i) {
|
||||
for (int j = 0; j <= i; ++j) {
|
||||
System.out.print(j);
|
||||
System.out.print(' ');
|
||||
}
|
||||
System.out.println();
|
||||
if (i % 3 == 0) {
|
||||
System.out.println("Suspend for a second");
|
||||
Thread.sleep(1000);
|
||||
}
|
||||
}
|
||||
System.out.println("Complete async");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
Copyright 2015 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.
|
||||
-->
|
||||
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
|
||||
version="3.0">
|
||||
</web-app>
|
27
teavm-samples/teavm-samples-async/src/main/webapp/index.html
Normal file
27
teavm-samples/teavm-samples-async/src/main/webapp/index.html
Normal file
|
@ -0,0 +1,27 @@
|
|||
<!--
|
||||
Copyright 2015 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.
|
||||
-->
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Continuation-passing style demo</title>
|
||||
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
|
||||
<script type="text/javascript" charset="utf-8" src="teavm/runtime.js"></script>
|
||||
<script type="text/javascript" charset="utf-8" src="teavm/classes.js"></script>
|
||||
</head>
|
||||
<body onload="main()">
|
||||
<p>Please, open developer's console to view program's output</p>
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in New Issue
Block a user