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;
|
package org.teavm.classlib.java.lang;
|
||||||
|
|
||||||
|
import org.teavm.javascript.ni.GeneratedBy;
|
||||||
|
import org.teavm.runtime.Async;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author Alexey Andreev
|
* @author Alexey Andreev
|
||||||
|
@ -56,8 +59,9 @@ public class TThread extends TObject implements TRunnable {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void yield() {
|
@Async
|
||||||
}
|
@GeneratedBy(ThreadNativeGenerator.class)
|
||||||
|
public static native void yield();
|
||||||
|
|
||||||
public void interrupt() {
|
public void interrupt() {
|
||||||
}
|
}
|
||||||
|
@ -81,4 +85,12 @@ public class TThread extends TObject implements TRunnable {
|
||||||
public static boolean holdsLock(@SuppressWarnings("unused") TObject obj) {
|
public static boolean holdsLock(@SuppressWarnings("unused") TObject obj) {
|
||||||
return true;
|
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
|
@Override
|
||||||
public String getNameFor(MethodReference method) {
|
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;
|
MethodReference origMethod = method;
|
||||||
method = getRealMethod(method);
|
method = getRealMethod(method);
|
||||||
if (method == null) {
|
if (method == null) {
|
||||||
|
@ -67,7 +76,7 @@ public class DefaultNamingStrategy implements NamingStrategy {
|
||||||
if (methodHolder.hasModifier(ElementModifier.STATIC) ||
|
if (methodHolder.hasModifier(ElementModifier.STATIC) ||
|
||||||
method.getDescriptor().getName().equals("<init>") ||
|
method.getDescriptor().getName().equals("<init>") ||
|
||||||
methodHolder.getLevel() == AccessLevel.PRIVATE) {
|
methodHolder.getLevel() == AccessLevel.PRIVATE) {
|
||||||
String key = method.toString();
|
String key = (async ? "A" : "S") + method.toString();
|
||||||
String alias = privateAliases.get(key);
|
String alias = privateAliases.get(key);
|
||||||
if (alias == null) {
|
if (alias == null) {
|
||||||
alias = aliasProvider.getAlias(method);
|
alias = aliasProvider.getAlias(method);
|
||||||
|
@ -75,7 +84,7 @@ public class DefaultNamingStrategy implements NamingStrategy {
|
||||||
}
|
}
|
||||||
return alias;
|
return alias;
|
||||||
} else {
|
} else {
|
||||||
String key = method.getDescriptor().toString();
|
String key = (async ? "A" : "S") + method.getDescriptor().toString();
|
||||||
String alias = aliases.get(key);
|
String alias = aliases.get(key);
|
||||||
if (alias == null) {
|
if (alias == null) {
|
||||||
alias = aliasProvider.getAlias(method);
|
alias = aliasProvider.getAlias(method);
|
||||||
|
|
|
@ -27,6 +27,8 @@ public interface NamingStrategy {
|
||||||
|
|
||||||
String getNameFor(MethodReference method) throws NamingException;
|
String getNameFor(MethodReference method) throws NamingException;
|
||||||
|
|
||||||
|
String getNameForAsync(MethodReference method) throws NamingException;
|
||||||
|
|
||||||
String getFullNameFor(MethodReference method) throws NamingException;
|
String getFullNameFor(MethodReference method) throws NamingException;
|
||||||
|
|
||||||
String getNameFor(FieldReference field) 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.InjectedBy;
|
||||||
import org.teavm.javascript.ni.PreserveOriginalName;
|
import org.teavm.javascript.ni.PreserveOriginalName;
|
||||||
import org.teavm.model.*;
|
import org.teavm.model.*;
|
||||||
|
import org.teavm.model.util.AsyncProgramSplitter;
|
||||||
import org.teavm.model.util.ProgramUtils;
|
import org.teavm.model.util.ProgramUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -45,10 +46,12 @@ public class Decompiler {
|
||||||
private Map<MethodReference, Generator> generators = new HashMap<>();
|
private Map<MethodReference, Generator> generators = new HashMap<>();
|
||||||
private Set<MethodReference> methodsToPass = new HashSet<>();
|
private Set<MethodReference> methodsToPass = new HashSet<>();
|
||||||
private RegularMethodNodeCache regularMethodCache;
|
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.classSource = classSource;
|
||||||
this.classLoader = classLoader;
|
this.classLoader = classLoader;
|
||||||
|
this.asyncMethods = asyncMethods;
|
||||||
}
|
}
|
||||||
|
|
||||||
public RegularMethodNodeCache getRegularMethodCache() {
|
public RegularMethodNodeCache getRegularMethodCache() {
|
||||||
|
@ -154,7 +157,7 @@ public class Decompiler {
|
||||||
|
|
||||||
public MethodNode decompile(MethodHolder method) {
|
public MethodNode decompile(MethodHolder method) {
|
||||||
return method.getModifiers().contains(ElementModifier.NATIVE) ? decompileNative(method) :
|
return method.getModifiers().contains(ElementModifier.NATIVE) ? decompileNative(method) :
|
||||||
decompileRegular(method);
|
!asyncMethods.contains(method.getReference()) ? decompileRegular(method) : decompileAsync(method);
|
||||||
}
|
}
|
||||||
|
|
||||||
public NativeMethodNode decompileNative(MethodHolder method) {
|
public NativeMethodNode decompileNative(MethodHolder method) {
|
||||||
|
@ -179,6 +182,7 @@ public class Decompiler {
|
||||||
method.getDescriptor()));
|
method.getDescriptor()));
|
||||||
methodNode.getModifiers().addAll(mapModifiers(method.getModifiers()));
|
methodNode.getModifiers().addAll(mapModifiers(method.getModifiers()));
|
||||||
methodNode.setGenerator(generator);
|
methodNode.setGenerator(generator);
|
||||||
|
methodNode.setAsync(asyncMethods.contains(method.getReference()));
|
||||||
return methodNode;
|
return methodNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -194,14 +198,58 @@ public class Decompiler {
|
||||||
return node;
|
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) {
|
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;
|
lastBlockId = 1;
|
||||||
graph = ProgramUtils.buildControlFlowGraph(method.getProgram());
|
graph = ProgramUtils.buildControlFlowGraph(program);
|
||||||
indexer = new GraphIndexer(graph);
|
indexer = new GraphIndexer(graph);
|
||||||
graph = indexer.getGraph();
|
graph = indexer.getGraph();
|
||||||
loopGraph = new LoopGraph(this.graph);
|
loopGraph = new LoopGraph(this.graph);
|
||||||
unflatCode();
|
unflatCode();
|
||||||
Program program = method.getProgram();
|
|
||||||
blockMap = new Block[program.basicBlockCount() * 2 + 1];
|
blockMap = new Block[program.basicBlockCount() * 2 + 1];
|
||||||
Deque<Block> stack = new ArrayDeque<>();
|
Deque<Block> stack = new ArrayDeque<>();
|
||||||
BlockStatement rootStmt = new BlockStatement();
|
BlockStatement rootStmt = new BlockStatement();
|
||||||
|
@ -247,9 +295,13 @@ public class Decompiler {
|
||||||
int tmp = indexer.nodeAt(next);
|
int tmp = indexer.nodeAt(next);
|
||||||
generator.nextBlock = tmp >= 0 && next < indexer.size() ? program.basicBlockAt(tmp) : null;
|
generator.nextBlock = tmp >= 0 && next < indexer.size() ? program.basicBlockAt(tmp) : null;
|
||||||
generator.statements.clear();
|
generator.statements.clear();
|
||||||
|
generator.asyncTarget = null;
|
||||||
InstructionLocation lastLocation = null;
|
InstructionLocation lastLocation = null;
|
||||||
NodeLocation nodeLocation = 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()) {
|
if (insn.getLocation() != null && lastLocation != insn.getLocation()) {
|
||||||
lastLocation = insn.getLocation();
|
lastLocation = insn.getLocation();
|
||||||
nodeLocation = new NodeLocation(lastLocation.getFileName(), lastLocation.getLine());
|
nodeLocation = new NodeLocation(lastLocation.getFileName(), lastLocation.getLine());
|
||||||
|
@ -257,41 +309,51 @@ public class Decompiler {
|
||||||
if (insn.getLocation() != null) {
|
if (insn.getLocation() != null) {
|
||||||
generator.setCurrentLocation(nodeLocation);
|
generator.setCurrentLocation(nodeLocation);
|
||||||
}
|
}
|
||||||
|
if (targetBlocks[node] >= 0 && j == instructions.size() - 1) {
|
||||||
|
generator.asyncTarget = targetBlocks[node];
|
||||||
|
asyncInvocation = true;
|
||||||
|
}
|
||||||
insn.acceptVisitor(generator);
|
insn.acceptVisitor(generator);
|
||||||
}
|
}
|
||||||
|
boolean hasAsyncCatch = false;
|
||||||
for (TryCatchBlock tryCatch : generator.currentBlock.getTryCatchBlocks()) {
|
for (TryCatchBlock tryCatch : generator.currentBlock.getTryCatchBlocks()) {
|
||||||
TryCatchStatement tryCatchStmt = new TryCatchStatement();
|
if (asyncInvocation) {
|
||||||
tryCatchStmt.setExceptionType(tryCatch.getExceptionType());
|
TryCatchStatement tryCatchStmt = new TryCatchStatement();
|
||||||
tryCatchStmt.setExceptionVariable(tryCatch.getExceptionVariable().getIndex());
|
tryCatchStmt.setExceptionType(tryCatch.getExceptionType());
|
||||||
tryCatchStmt.getProtectedBody().addAll(generator.statements);
|
tryCatchStmt.setExceptionVariable(tryCatch.getExceptionVariable().getIndex());
|
||||||
generator.statements.clear();
|
tryCatchStmt.getProtectedBody().addAll(generator.statements);
|
||||||
generator.statements.add(tryCatchStmt);
|
generator.statements.clear();
|
||||||
Statement handlerStmt = generator.generateJumpStatement(tryCatch.getHandler());
|
generator.statements.add(tryCatchStmt);
|
||||||
if (handlerStmt != null) {
|
Statement handlerStmt = generator.generateJumpStatement(tryCatch.getHandler());
|
||||||
tryCatchStmt.getHandler().add(handlerStmt);
|
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);
|
block.body.addAll(generator.statements);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SequentialStatement result = new SequentialStatement();
|
SequentialStatement resultBody = new SequentialStatement();
|
||||||
result.getSequence().addAll(rootStmt.getBody());
|
resultBody.getSequence().addAll(rootStmt.getBody());
|
||||||
MethodReference reference = new MethodReference(method.getOwnerName(), method.getDescriptor());
|
result.setStatement(resultBody);
|
||||||
RegularMethodNode methodNode = new RegularMethodNode(reference);
|
return result;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Set<NodeModifier> mapModifiers(Set<ElementModifier> modifiers) {
|
private Set<NodeModifier> mapModifiers(Set<ElementModifier> modifiers) {
|
||||||
|
|
|
@ -15,6 +15,8 @@
|
||||||
*/
|
*/
|
||||||
package org.teavm.javascript;
|
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.javascript.ast.RegularMethodNode;
|
||||||
import org.teavm.model.Program;
|
import org.teavm.model.Program;
|
||||||
|
|
||||||
|
@ -40,4 +42,27 @@ public class Optimizer {
|
||||||
method.getVariables().set(i, i);
|
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) {
|
private boolean tryApplyConstructor(InvocationExpr expr) {
|
||||||
if (!expr.getMethod().getName().equals("<init>")) {
|
if (expr.getAsyncTarget() != null || !expr.getMethod().getName().equals("<init>")) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (resultSequence == null || resultSequence.isEmpty()) {
|
if (resultSequence == null || resultSequence.isEmpty()) {
|
||||||
|
@ -211,7 +211,7 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor {
|
||||||
}
|
}
|
||||||
Expr[] args = expr.getArguments().toArray(new Expr[0]);
|
Expr[] args = expr.getArguments().toArray(new Expr[0]);
|
||||||
args = Arrays.copyOfRange(args, 1, args.length);
|
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());
|
constructrExpr.setLocation(expr.getLocation());
|
||||||
assignment.setRightValue(constructrExpr);
|
assignment.setRightValue(constructrExpr);
|
||||||
stats.reads[var.getIndex()]--;
|
stats.reads[var.getIndex()]--;
|
||||||
|
|
|
@ -53,6 +53,7 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
||||||
private Deque<LocationStackEntry> locationStack = new ArrayDeque<>();
|
private Deque<LocationStackEntry> locationStack = new ArrayDeque<>();
|
||||||
private DeferredCallSite lastCallSite;
|
private DeferredCallSite lastCallSite;
|
||||||
private DeferredCallSite prevCallSite;
|
private DeferredCallSite prevCallSite;
|
||||||
|
private boolean async;
|
||||||
|
|
||||||
private static class InjectorHolder {
|
private static class InjectorHolder {
|
||||||
public final Injector injector;
|
public final Injector injector;
|
||||||
|
@ -469,6 +470,12 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
||||||
}
|
}
|
||||||
writer.append(");").ws().append("}");
|
writer.append(");").ws().append("}");
|
||||||
debugEmitter.emitMethod(null);
|
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();
|
writer.append(");").newLine().outdent();
|
||||||
}
|
}
|
||||||
|
@ -518,6 +525,12 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
||||||
}
|
}
|
||||||
writer.append(variableName(i));
|
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();
|
writer.append(")").ws().append("{").softNewLine().indent();
|
||||||
method.acceptVisitor(new MethodBodyRenderer());
|
method.acceptVisitor(new MethodBodyRenderer());
|
||||||
writer.outdent().append("}").newLine();
|
writer.outdent().append("}").newLine();
|
||||||
|
@ -525,9 +538,13 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
||||||
}
|
}
|
||||||
|
|
||||||
private class MethodBodyRenderer implements MethodNodeVisitor, GeneratorContext {
|
private class MethodBodyRenderer implements MethodNodeVisitor, GeneratorContext {
|
||||||
|
private boolean async;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(NativeMethodNode methodNode) {
|
public void visit(NativeMethodNode methodNode) {
|
||||||
try {
|
try {
|
||||||
|
this.async = methodNode.isAsync();
|
||||||
|
Renderer.this.async = methodNode.isAsync();
|
||||||
methodNode.getGenerator().generate(this, writer, methodNode.getReference());
|
methodNode.getGenerator().generate(this, writer, methodNode.getReference());
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new RenderingException("IO error occured", e);
|
throw new RenderingException("IO error occured", e);
|
||||||
|
@ -537,6 +554,8 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
||||||
@Override
|
@Override
|
||||||
public void visit(RegularMethodNode method) {
|
public void visit(RegularMethodNode method) {
|
||||||
try {
|
try {
|
||||||
|
Renderer.this.async = false;
|
||||||
|
this.async = false;
|
||||||
MethodReference ref = method.getReference();
|
MethodReference ref = method.getReference();
|
||||||
for (int i = 0; i < method.getParameterDebugNames().size(); ++i) {
|
for (int i = 0; i < method.getParameterDebugNames().size(); ++i) {
|
||||||
debugEmitter.emitVariable(method.getParameterDebugNames().get(i).toArray(new String[0]),
|
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
|
@Override
|
||||||
public String getParameterName(int index) {
|
public String getParameterName(int index) {
|
||||||
return variableName(index);
|
return variableName(index);
|
||||||
|
@ -596,6 +660,21 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
||||||
public <T> T getService(Class<T> type) {
|
public <T> T getService(Class<T> type) {
|
||||||
return services.getService(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) {
|
private void pushLocation(NodeLocation location) {
|
||||||
|
@ -832,12 +911,18 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
||||||
pushLocation(statement.getLocation());
|
pushLocation(statement.getLocation());
|
||||||
}
|
}
|
||||||
writer.append("return");
|
writer.append("return");
|
||||||
|
if (async) {
|
||||||
|
writer.append(" $return(");
|
||||||
|
}
|
||||||
if (statement.getResult() != null) {
|
if (statement.getResult() != null) {
|
||||||
writer.append(' ');
|
writer.append(' ');
|
||||||
prevCallSite = debugEmitter.emitCallSite();
|
prevCallSite = debugEmitter.emitCallSite();
|
||||||
statement.getResult().acceptVisitor(this);
|
statement.getResult().acceptVisitor(this);
|
||||||
debugEmitter.emitCallSite();
|
debugEmitter.emitCallSite();
|
||||||
}
|
}
|
||||||
|
if (async) {
|
||||||
|
writer.append(')');
|
||||||
|
}
|
||||||
writer.append(";").softNewLine();
|
writer.append(";").softNewLine();
|
||||||
if (statement.getLocation() != null) {
|
if (statement.getLocation() != null) {
|
||||||
popLocation();
|
popLocation();
|
||||||
|
@ -1336,11 +1421,15 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
||||||
if (injector != null) {
|
if (injector != null) {
|
||||||
injector.generate(new InjectorContextImpl(expr.getArguments()), expr.getMethod());
|
injector.generate(new InjectorContextImpl(expr.getArguments()), expr.getMethod());
|
||||||
} else {
|
} else {
|
||||||
|
if (expr.getAsyncTarget() != null) {
|
||||||
|
writer.append("return ");
|
||||||
|
}
|
||||||
if (expr.getType() == InvocationType.DYNAMIC) {
|
if (expr.getType() == InvocationType.DYNAMIC) {
|
||||||
expr.getArguments().get(0).acceptVisitor(this);
|
expr.getArguments().get(0).acceptVisitor(this);
|
||||||
}
|
}
|
||||||
String className = naming.getNameFor(expr.getMethod().getClassName());
|
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());
|
String fullName = naming.getFullNameFor(expr.getMethod());
|
||||||
DeferredCallSite callSite = prevCallSite;
|
DeferredCallSite callSite = prevCallSite;
|
||||||
boolean shouldEraseCallSite = lastCallSite == null;
|
boolean shouldEraseCallSite = lastCallSite == null;
|
||||||
|
@ -1348,6 +1437,7 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
||||||
lastCallSite = callSite;
|
lastCallSite = callSite;
|
||||||
}
|
}
|
||||||
boolean virtual = false;
|
boolean virtual = false;
|
||||||
|
boolean hasParams = false;
|
||||||
switch (expr.getType()) {
|
switch (expr.getType()) {
|
||||||
case STATIC:
|
case STATIC:
|
||||||
writer.append(fullName).append("(");
|
writer.append(fullName).append("(");
|
||||||
|
@ -1357,18 +1447,18 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
||||||
writer.append(",").ws();
|
writer.append(",").ws();
|
||||||
}
|
}
|
||||||
expr.getArguments().get(i).acceptVisitor(this);
|
expr.getArguments().get(i).acceptVisitor(this);
|
||||||
|
hasParams = true;
|
||||||
}
|
}
|
||||||
writer.append(')');
|
|
||||||
break;
|
break;
|
||||||
case SPECIAL:
|
case SPECIAL:
|
||||||
writer.append(fullName).append("(");
|
writer.append(fullName).append("(");
|
||||||
prevCallSite = debugEmitter.emitCallSite();
|
prevCallSite = debugEmitter.emitCallSite();
|
||||||
expr.getArguments().get(0).acceptVisitor(this);
|
expr.getArguments().get(0).acceptVisitor(this);
|
||||||
|
hasParams = true;
|
||||||
for (int i = 1; i < expr.getArguments().size(); ++i) {
|
for (int i = 1; i < expr.getArguments().size(); ++i) {
|
||||||
writer.append(",").ws();
|
writer.append(",").ws();
|
||||||
expr.getArguments().get(i).acceptVisitor(this);
|
expr.getArguments().get(i).acceptVisitor(this);
|
||||||
}
|
}
|
||||||
writer.append(")");
|
|
||||||
break;
|
break;
|
||||||
case DYNAMIC:
|
case DYNAMIC:
|
||||||
writer.append(".").append(name).append("(");
|
writer.append(".").append(name).append("(");
|
||||||
|
@ -1377,9 +1467,9 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
||||||
if (i > 1) {
|
if (i > 1) {
|
||||||
writer.append(",").ws();
|
writer.append(",").ws();
|
||||||
}
|
}
|
||||||
|
hasParams = true;
|
||||||
expr.getArguments().get(i).acceptVisitor(this);
|
expr.getArguments().get(i).acceptVisitor(this);
|
||||||
}
|
}
|
||||||
writer.append(')');
|
|
||||||
virtual = true;
|
virtual = true;
|
||||||
break;
|
break;
|
||||||
case CONSTRUCTOR:
|
case CONSTRUCTOR:
|
||||||
|
@ -1389,11 +1479,18 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
||||||
if (i > 0) {
|
if (i > 0) {
|
||||||
writer.append(",").ws();
|
writer.append(",").ws();
|
||||||
}
|
}
|
||||||
|
hasParams = true;
|
||||||
expr.getArguments().get(i).acceptVisitor(this);
|
expr.getArguments().get(i).acceptVisitor(this);
|
||||||
}
|
}
|
||||||
writer.append(')');
|
|
||||||
break;
|
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 (lastCallSite != null) {
|
||||||
if (virtual) {
|
if (virtual) {
|
||||||
lastCallSite.setVirtualMethod(expr.getMethod());
|
lastCallSite.setVirtualMethod(expr.getMethod());
|
||||||
|
|
|
@ -37,6 +37,7 @@ class StatementGenerator implements InstructionVisitor {
|
||||||
Program program;
|
Program program;
|
||||||
ClassHolderSource classSource;
|
ClassHolderSource classSource;
|
||||||
private NodeLocation currentLocation;
|
private NodeLocation currentLocation;
|
||||||
|
Integer asyncTarget;
|
||||||
|
|
||||||
public void setCurrentLocation(NodeLocation currentLocation) {
|
public void setCurrentLocation(NodeLocation currentLocation) {
|
||||||
this.currentLocation = currentLocation;
|
this.currentLocation = currentLocation;
|
||||||
|
@ -546,7 +547,7 @@ class StatementGenerator implements InstructionVisitor {
|
||||||
for (int i = 0; i < insn.getArguments().size(); ++i) {
|
for (int i = 0; i < insn.getArguments().size(); ++i) {
|
||||||
exprArgs[i] = Expr.var(insn.getArguments().get(i).getIndex());
|
exprArgs[i] = Expr.var(insn.getArguments().get(i).getIndex());
|
||||||
}
|
}
|
||||||
Expr invocationExpr;
|
InvocationExpr invocationExpr;
|
||||||
if (insn.getInstance() != null) {
|
if (insn.getInstance() != null) {
|
||||||
if (insn.getType() == InvocationType.VIRTUAL) {
|
if (insn.getType() == InvocationType.VIRTUAL) {
|
||||||
invocationExpr = Expr.invoke(insn.getMethod(), Expr.var(insn.getInstance().getIndex()), exprArgs);
|
invocationExpr = Expr.invoke(insn.getMethod(), Expr.var(insn.getInstance().getIndex()), exprArgs);
|
||||||
|
@ -557,8 +558,15 @@ class StatementGenerator implements InstructionVisitor {
|
||||||
} else {
|
} else {
|
||||||
invocationExpr = Expr.invokeStatic(insn.getMethod(), exprArgs);
|
invocationExpr = Expr.invokeStatic(insn.getMethod(), exprArgs);
|
||||||
}
|
}
|
||||||
if (insn.getReceiver() != null) {
|
invocationExpr.setAsyncTarget(asyncTarget);
|
||||||
assign(invocationExpr, insn.getReceiver());
|
if (asyncTarget == null) {
|
||||||
|
if (insn.getReceiver() != null) {
|
||||||
|
assign(invocationExpr, insn.getReceiver());
|
||||||
|
} else {
|
||||||
|
AssignmentStatement stmt = Statement.assign(null, invocationExpr);
|
||||||
|
stmt.setLocation(currentLocation);
|
||||||
|
statements.add(stmt);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
AssignmentStatement stmt = Statement.assign(null, invocationExpr);
|
AssignmentStatement stmt = Statement.assign(null, invocationExpr);
|
||||||
stmt.setLocation(currentLocation);
|
stmt.setLocation(currentLocation);
|
||||||
|
|
|
@ -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;
|
return expr;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Expr constructObject(MethodReference method, Expr[] arguments) {
|
public static InvocationExpr constructObject(MethodReference method, Expr[] arguments) {
|
||||||
InvocationExpr expr = new InvocationExpr();
|
InvocationExpr expr = new InvocationExpr();
|
||||||
expr.setMethod(method);
|
expr.setMethod(method);
|
||||||
expr.setType(InvocationType.CONSTRUCTOR);
|
expr.setType(InvocationType.CONSTRUCTOR);
|
||||||
|
@ -119,7 +119,7 @@ public abstract class Expr implements Cloneable {
|
||||||
return expr;
|
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();
|
InvocationExpr expr = new InvocationExpr();
|
||||||
expr.setMethod(method);
|
expr.setMethod(method);
|
||||||
expr.setType(InvocationType.DYNAMIC);
|
expr.setType(InvocationType.DYNAMIC);
|
||||||
|
@ -128,7 +128,7 @@ public abstract class Expr implements Cloneable {
|
||||||
return expr;
|
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();
|
InvocationExpr expr = new InvocationExpr();
|
||||||
expr.setMethod(method);
|
expr.setMethod(method);
|
||||||
expr.setType(InvocationType.SPECIAL);
|
expr.setType(InvocationType.SPECIAL);
|
||||||
|
@ -137,7 +137,7 @@ public abstract class Expr implements Cloneable {
|
||||||
return expr;
|
return expr;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Expr invokeStatic(MethodReference method, Expr[] arguments) {
|
public static InvocationExpr invokeStatic(MethodReference method, Expr[] arguments) {
|
||||||
InvocationExpr expr = new InvocationExpr();
|
InvocationExpr expr = new InvocationExpr();
|
||||||
expr.setMethod(method);
|
expr.setMethod(method);
|
||||||
expr.setType(InvocationType.STATIC);
|
expr.setType(InvocationType.STATIC);
|
||||||
|
|
|
@ -28,6 +28,7 @@ public class InvocationExpr extends Expr {
|
||||||
private MethodReference method;
|
private MethodReference method;
|
||||||
private InvocationType type;
|
private InvocationType type;
|
||||||
private List<Expr> arguments = new ArrayList<>();
|
private List<Expr> arguments = new ArrayList<>();
|
||||||
|
private Integer asyncTarget;
|
||||||
|
|
||||||
public MethodReference getMethod() {
|
public MethodReference getMethod() {
|
||||||
return method;
|
return method;
|
||||||
|
@ -49,6 +50,14 @@ public class InvocationExpr extends Expr {
|
||||||
return arguments;
|
return arguments;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Integer getAsyncTarget() {
|
||||||
|
return asyncTarget;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAsyncTarget(Integer asyncTarget) {
|
||||||
|
this.asyncTarget = asyncTarget;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void acceptVisitor(ExprVisitor visitor) {
|
public void acceptVisitor(ExprVisitor visitor) {
|
||||||
visitor.visit(this);
|
visitor.visit(this);
|
||||||
|
@ -63,6 +72,7 @@ public class InvocationExpr extends Expr {
|
||||||
InvocationExpr copy = new InvocationExpr();
|
InvocationExpr copy = new InvocationExpr();
|
||||||
cache.put(this, copy);
|
cache.put(this, copy);
|
||||||
copy.setMethod(method);
|
copy.setMethod(method);
|
||||||
|
copy.setAsyncTarget(asyncTarget);
|
||||||
for (Expr arg : arguments) {
|
for (Expr arg : arguments) {
|
||||||
copy.getArguments().add(arg.clone(cache));
|
copy.getArguments().add(arg.clone(cache));
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,4 +50,6 @@ public abstract class MethodNode {
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract void acceptVisitor(MethodNodeVisitor visitor);
|
public abstract void acceptVisitor(MethodNodeVisitor visitor);
|
||||||
|
|
||||||
|
public abstract boolean isAsync();
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,5 +22,7 @@ package org.teavm.javascript.ast;
|
||||||
public interface MethodNodeVisitor {
|
public interface MethodNodeVisitor {
|
||||||
void visit(RegularMethodNode methodNode);
|
void visit(RegularMethodNode methodNode);
|
||||||
|
|
||||||
|
void visit(AsyncMethodNode methodNode);
|
||||||
|
|
||||||
void visit(NativeMethodNode methodNode);
|
void visit(NativeMethodNode methodNode);
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@ import org.teavm.model.MethodReference;
|
||||||
*/
|
*/
|
||||||
public class NativeMethodNode extends MethodNode {
|
public class NativeMethodNode extends MethodNode {
|
||||||
private Generator generator;
|
private Generator generator;
|
||||||
|
private boolean async;
|
||||||
|
|
||||||
public NativeMethodNode(MethodReference reference) {
|
public NativeMethodNode(MethodReference reference) {
|
||||||
super(reference);
|
super(reference);
|
||||||
|
@ -37,6 +38,15 @@ public class NativeMethodNode extends MethodNode {
|
||||||
this.generator = generator;
|
this.generator = generator;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAsync() {
|
||||||
|
return async;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAsync(boolean async) {
|
||||||
|
this.async = async;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void acceptVisitor(MethodNodeVisitor visitor) {
|
public void acceptVisitor(MethodNodeVisitor visitor) {
|
||||||
visitor.visit(this);
|
visitor.visit(this);
|
||||||
|
|
|
@ -53,4 +53,9 @@ public class RegularMethodNode extends MethodNode {
|
||||||
public void acceptVisitor(MethodNodeVisitor visitor) {
|
public void acceptVisitor(MethodNodeVisitor visitor) {
|
||||||
visitor.visit(this);
|
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 List<Statement> handler = new ArrayList<>();
|
||||||
private String exceptionType;
|
private String exceptionType;
|
||||||
private Integer exceptionVariable;
|
private Integer exceptionVariable;
|
||||||
|
private boolean async;
|
||||||
|
|
||||||
public List<Statement> getProtectedBody() {
|
public List<Statement> getProtectedBody() {
|
||||||
return protectedBody;
|
return protectedBody;
|
||||||
|
@ -52,6 +53,14 @@ public class TryCatchStatement extends Statement {
|
||||||
this.exceptionVariable = exceptionVariable;
|
this.exceptionVariable = exceptionVariable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isAsync() {
|
||||||
|
return async;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAsync(boolean async) {
|
||||||
|
this.async = async;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void acceptVisitor(StatementVisitor visitor) {
|
public void acceptVisitor(StatementVisitor visitor) {
|
||||||
visitor.visit(this);
|
visitor.visit(this);
|
||||||
|
|
|
@ -31,4 +31,10 @@ public interface GeneratorContext extends ServiceRepository {
|
||||||
ClassLoader getClassLoader();
|
ClassLoader getClassLoader();
|
||||||
|
|
||||||
Properties getProperties();
|
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.ArrayList;
|
||||||
import java.util.List;
|
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) {
|
for (int i = 0; i < program.basicBlockCount(); ++i) {
|
||||||
BasicBlockReader block = program.basicBlockAt(i);
|
BasicBlockReader block = program.basicBlockAt(i);
|
||||||
BasicBlock blockCopy = copy.basicBlockAt(i);
|
BasicBlock blockCopy = copy.basicBlockAt(i);
|
||||||
for (int j = 0; j < block.instructionCount(); ++j) {
|
blockCopy.getInstructions().addAll(copyInstructions(block, 0, block.instructionCount(), copy));
|
||||||
block.readInstruction(j, insnCopier);
|
blockCopy.getPhis().addAll(copyPhis(block, copy));
|
||||||
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);
|
|
||||||
}
|
|
||||||
for (TryCatchBlockReader tryCatch : block.readTryCatchBlocks()) {
|
for (TryCatchBlockReader tryCatch : block.readTryCatchBlocks()) {
|
||||||
TryCatchBlock tryCatchCopy = new TryCatchBlock();
|
TryCatchBlock tryCatchCopy = new TryCatchBlock();
|
||||||
tryCatchCopy.setExceptionType(tryCatch.getExceptionType());
|
tryCatchCopy.setExceptionType(tryCatch.getExceptionType());
|
||||||
|
@ -118,6 +105,46 @@ public final class ProgramUtils {
|
||||||
return copy;
|
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 {
|
private static class InstructionCopyReader implements InstructionReader {
|
||||||
Instruction copy;
|
Instruction copy;
|
||||||
Program programCopy;
|
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();
|
renderer.renderStringPool();
|
||||||
for (Map.Entry<String, TeaVMEntryPoint> entry : entryPoints.entrySet()) {
|
for (Map.Entry<String, TeaVMEntryPoint> entry : entryPoints.entrySet()) {
|
||||||
sourceWriter.append("var ").append(entry.getKey()).ws().append("=").ws()
|
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()) {
|
for (Map.Entry<String, String> entry : exportedClasses.entrySet()) {
|
||||||
sourceWriter.append("var ").append(entry.getKey()).ws().append("=").ws()
|
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) {
|
private List<ClassNode> modelToAst(ListableClassHolderSource classes) {
|
||||||
|
AsyncMethodFinder asyncFinder = new AsyncMethodFinder(dependencyChecker.getCallGraph(), diagnostics);
|
||||||
|
asyncFinder.find(classes);
|
||||||
|
|
||||||
progressListener.phaseStarted(TeaVMPhase.DECOMPILATION, classes.getClassNames().size());
|
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);
|
decompiler.setRegularMethodCache(incremental ? astCache : null);
|
||||||
|
|
||||||
for (Map.Entry<MethodReference, Generator> entry : methodGenerators.entrySet()) {
|
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;
|
var $rt_stringPool_instance;
|
||||||
function $rt_stringPool(strings) {
|
function $rt_stringPool(strings) {
|
||||||
$rt_stringPool_instance = new Array(strings.length);
|
$rt_stringPool_instance = new Array(strings.length);
|
||||||
|
@ -402,6 +424,21 @@ function $rt_stringPool(strings) {
|
||||||
function $rt_s(index) {
|
function $rt_s(index) {
|
||||||
return $rt_stringPool_instance[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) {
|
function $dbg_repr(obj) {
|
||||||
return obj.toString ? obj.toString() : "";
|
return obj.toString ? obj.toString() : "";
|
||||||
|
|
|
@ -34,5 +34,6 @@
|
||||||
<module>teavm-samples-benchmark</module>
|
<module>teavm-samples-benchmark</module>
|
||||||
<module>teavm-samples-storage</module>
|
<module>teavm-samples-storage</module>
|
||||||
<module>teavm-samples-video</module>
|
<module>teavm-samples-video</module>
|
||||||
|
<module>teavm-samples-async</module>
|
||||||
</modules>
|
</modules>
|
||||||
</project>
|
</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