mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 08:14:09 -08:00
Further work on a new thread emulator
This commit is contained in:
parent
93e43456d1
commit
32deaf2716
|
@ -80,6 +80,7 @@ public class TThread extends TObject implements TRunnable {
|
|||
currentThread.timeSliceStart = System.currentTimeMillis();
|
||||
}
|
||||
}
|
||||
|
||||
static TThread getMainThread(){
|
||||
return mainThread;
|
||||
}
|
||||
|
|
|
@ -305,10 +305,31 @@ public class AstIO {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void visit(RestoreAsyncStatement statement) {
|
||||
public void visit(GotoPartStatement statement) {
|
||||
try {
|
||||
output.writeByte(17);
|
||||
output.writeShort(statement.getReceiver() != null ? statement.getReceiver() : -1);
|
||||
output.writeShort(statement.getPart());
|
||||
} catch (IOException e) {
|
||||
throw new IOExceptionWrapper(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(MonitorEnterStatement statement) {
|
||||
try {
|
||||
output.writeByte(18);
|
||||
output.writeShort(statement.getAsyncTarget() != null ? 0 : statement.getAsyncTarget());
|
||||
writeExpr(statement.getObjectRef());
|
||||
} catch (IOException e) {
|
||||
throw new IOExceptionWrapper(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(MonitorExitStatement statement) {
|
||||
try {
|
||||
output.writeByte(19);
|
||||
writeExpr(statement.getObjectRef());
|
||||
} catch (IOException e) {
|
||||
throw new IOExceptionWrapper(e);
|
||||
}
|
||||
|
@ -506,16 +527,6 @@ public class AstIO {
|
|||
throw new IOExceptionWrapper(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(MonitorEnterStatement statement) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(MonitorExitStatement statement) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private NodeLocation readLocation(DataInput input) throws IOException {
|
||||
|
@ -670,11 +681,11 @@ public class AstIO {
|
|||
return stmt;
|
||||
}
|
||||
case 17: {
|
||||
short var = input.readShort();
|
||||
RestoreAsyncStatement stmt = new RestoreAsyncStatement();
|
||||
stmt.setReceiver(var >= 0 ? (int)var : null);
|
||||
GotoPartStatement stmt = new GotoPartStatement();
|
||||
stmt.setPart(input.readShort());
|
||||
return stmt;
|
||||
}
|
||||
// TODO: MonitorEnter/MonitorExit
|
||||
default:
|
||||
throw new RuntimeException("Unexpected statement type: " + type);
|
||||
}
|
||||
|
|
|
@ -259,17 +259,16 @@ public class DiskRegularMethodNodeCache implements RegularMethodNodeCache {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void visit(RestoreAsyncStatement statement) {
|
||||
public void visit(GotoPartStatement statement) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(MonitorEnterStatement statement) {
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(MonitorExitStatement statement) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -114,16 +114,14 @@ class BreakToContinueReplacer implements StatementVisitor {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void visit(RestoreAsyncStatement statement) {
|
||||
public void visit(GotoPartStatement statement) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(MonitorEnterStatement statement) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(MonitorExitStatement statement) {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -109,16 +109,14 @@ class CertainBlockCountVisitor implements StatementVisitor {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void visit(RestoreAsyncStatement statement) {
|
||||
public void visit(GotoPartStatement statement) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(MonitorEnterStatement statement) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(MonitorExitStatement statement) {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -203,15 +203,7 @@ public class Decompiler {
|
|||
AsyncProgramSplitter splitter = new AsyncProgramSplitter(classSource, splitMethods);
|
||||
splitter.split(method.getProgram());
|
||||
for (int i = 0; i < splitter.size(); ++i) {
|
||||
Integer input = null;
|
||||
if (i > 0) {
|
||||
input = splitter.getInput(i);
|
||||
if (input == null) {
|
||||
input = -1;
|
||||
}
|
||||
}
|
||||
AsyncMethodPart part = getRegularMethodStatement(splitter.getProgram(i), splitter.getBlockSuccessors(i),
|
||||
input);
|
||||
AsyncMethodPart part = getRegularMethodStatement(splitter.getProgram(i), splitter.getBlockSuccessors(i));
|
||||
node.getBody().add(part);
|
||||
}
|
||||
Program program = method.getProgram();
|
||||
|
@ -219,7 +211,7 @@ public class Decompiler {
|
|||
node.getVariables().add(program.variableAt(i).getRegister());
|
||||
}
|
||||
Optimizer optimizer = new Optimizer();
|
||||
optimizer.optimize(node, program, splitter);
|
||||
optimizer.optimize(node, program);
|
||||
node.getModifiers().addAll(mapModifiers(method.getModifiers()));
|
||||
int paramCount = Math.min(method.getSignature().length, program.variableCount());
|
||||
for (int i = 0; i < paramCount; ++i) {
|
||||
|
@ -234,7 +226,7 @@ public class Decompiler {
|
|||
Program program = method.getProgram();
|
||||
int[] targetBlocks = new int[program.basicBlockCount()];
|
||||
Arrays.fill(targetBlocks, -1);
|
||||
methodNode.setBody(getRegularMethodStatement(program, targetBlocks, null).getStatement());
|
||||
methodNode.setBody(getRegularMethodStatement(program, targetBlocks).getStatement());
|
||||
for (int i = 0; i < program.variableCount(); ++i) {
|
||||
methodNode.getVariables().add(program.variableAt(i).getRegister());
|
||||
}
|
||||
|
@ -249,7 +241,7 @@ public class Decompiler {
|
|||
return methodNode;
|
||||
}
|
||||
|
||||
private AsyncMethodPart getRegularMethodStatement(Program program, int[] targetBlocks, Integer inputVar) {
|
||||
private AsyncMethodPart getRegularMethodStatement(Program program, int[] targetBlocks) {
|
||||
AsyncMethodPart result = new AsyncMethodPart();
|
||||
lastBlockId = 1;
|
||||
graph = ProgramUtils.buildControlFlowGraph(program);
|
||||
|
@ -302,11 +294,6 @@ public class Decompiler {
|
|||
int tmp = indexer.nodeAt(next);
|
||||
generator.nextBlock = tmp >= 0 && next < indexer.size() ? program.basicBlockAt(tmp) : null;
|
||||
generator.statements.clear();
|
||||
if (node == 0 && inputVar != null) {
|
||||
RestoreAsyncStatement restoreStmt = new RestoreAsyncStatement();
|
||||
restoreStmt.setReceiver(inputVar >= 0 ? inputVar : null);
|
||||
generator.statements.add(restoreStmt);
|
||||
}
|
||||
generator.asyncTarget = null;
|
||||
InstructionLocation lastLocation = null;
|
||||
NodeLocation nodeLocation = null;
|
||||
|
|
|
@ -188,7 +188,7 @@ public class NameFrequencyEstimator implements StatementVisitor, ExprVisitor, Me
|
|||
}
|
||||
|
||||
@Override
|
||||
public void visit(RestoreAsyncStatement statement) {
|
||||
public void visit(GotoPartStatement statement) {
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -19,7 +19,6 @@ import org.teavm.javascript.ast.AsyncMethodNode;
|
|||
import org.teavm.javascript.ast.AsyncMethodPart;
|
||||
import org.teavm.javascript.ast.RegularMethodNode;
|
||||
import org.teavm.model.Program;
|
||||
import org.teavm.model.util.AsyncProgramSplitter;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -43,15 +42,9 @@ public class Optimizer {
|
|||
}
|
||||
}
|
||||
|
||||
public void optimize(AsyncMethodNode method, Program program, AsyncProgramSplitter splitter) {
|
||||
public void optimize(AsyncMethodNode method, Program program) {
|
||||
ReadWriteStatsBuilder stats = new ReadWriteStatsBuilder(method.getVariables().size());
|
||||
stats.analyze(program);
|
||||
for (int i = 0; i < splitter.size(); ++i) {
|
||||
Integer var = splitter.getInput(i);
|
||||
if (var != null) {
|
||||
stats.reads[var]++;
|
||||
}
|
||||
}
|
||||
for (AsyncMethodPart part : method.getBody()) {
|
||||
OptimizingVisitor optimizer = new OptimizingVisitor(stats.copy());
|
||||
part.getStatement().acceptVisitor(optimizer);
|
||||
|
|
|
@ -180,7 +180,7 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor {
|
|||
}
|
||||
|
||||
private boolean tryApplyConstructor(InvocationExpr expr) {
|
||||
if (expr.getAsyncTarget() != null || !expr.getMethod().getName().equals("<init>")) {
|
||||
if (!expr.getMethod().getName().equals("<init>")) {
|
||||
return false;
|
||||
}
|
||||
if (resultSequence == null || resultSequence.isEmpty()) {
|
||||
|
@ -615,17 +615,21 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void visit(RestoreAsyncStatement statement) {
|
||||
public void visit(GotoPartStatement statement) {
|
||||
resultStmt = statement;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(MonitorEnterStatement statement) {
|
||||
statement.getObjectRef().acceptVisitor(this);
|
||||
statement.setObjectRef(resultExpr);
|
||||
resultStmt = statement;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(MonitorExitStatement statement) {
|
||||
statement.getObjectRef().acceptVisitor(this);
|
||||
statement.setObjectRef(resultExpr);
|
||||
resultStmt = statement;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -119,16 +119,14 @@ class RedundantLabelEliminator implements StatementVisitor {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void visit(RestoreAsyncStatement statement) {
|
||||
public void visit(GotoPartStatement statement) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(MonitorEnterStatement statement) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(MonitorExitStatement statement) {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -113,16 +113,14 @@ class ReferenceCountingVisitor implements StatementVisitor {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void visit(RestoreAsyncStatement statement) {
|
||||
public void visit(GotoPartStatement statement) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(MonitorEnterStatement statement) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(MonitorExitStatement statement) {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -260,8 +260,8 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
|||
}
|
||||
|
||||
private void renderRuntimeAliases() throws IOException {
|
||||
String[] names = { "$rt_asyncResult", "$rt_asyncError", "$rt_continue", "$rt_guardAsync", "$rt_throw",
|
||||
"$rt_compare", "$rt_nullCheck", "$rt_cls", "$rt_createArray", "$rt_isInstance" };
|
||||
String[] names = { "$rt_throw", "$rt_compare", "$rt_nullCheck", "$rt_cls", "$rt_createArray",
|
||||
"$rt_isInstance" };
|
||||
boolean first = true;
|
||||
for (String name : names) {
|
||||
if (!first) {
|
||||
|
@ -698,20 +698,20 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
|||
}
|
||||
|
||||
writer.append("function $save()").ws().append("{").indent().softNewLine();
|
||||
writer.append("var $").ws().append('=').ws().append("$rt_stack();").softNewLine();
|
||||
writer.append("$rt_nativeThread()");
|
||||
for (int i = ref.parameterCount() + 1; i < variableCount; ++i) {
|
||||
writer.append("$.push(").append(variableName(i)).append(");");
|
||||
writer.append(".push(").append(variableName(i)).append(")");
|
||||
}
|
||||
writer.append("$.push($ptr)");
|
||||
writer.append(".push($ptr);");
|
||||
writer.softNewLine();
|
||||
writer.outdent().append("}").softNewLine();
|
||||
|
||||
writer.append("$ptr").ws().append('=').ws().append("0;").softNewLine();
|
||||
writer.append("if").ws().append("($rt_isRestoring())").ws().append("{").indent().softNewLine();
|
||||
writer.append("var $s").ws().append('=').ws().append("$rt_stack();").softNewLine();
|
||||
writer.append("var $ptr").ws().append('=').append("$s.pop();");
|
||||
writer.append("if").ws().append("($rt_resuming())").ws().append("{").indent().softNewLine();
|
||||
writer.append("var $T").ws().append('=').ws().append("$rt_nativeThread();").softNewLine();
|
||||
writer.append("$ptr").ws().append('=').ws().append("$T.pop();");
|
||||
for (int i = variableCount - 1; i > ref.parameterCount(); --i) {
|
||||
writer.append(variableName(i)).ws().append('=').ws().append("$.pop();");
|
||||
writer.append(variableName(i)).ws().append('=').ws().append("T.pop();");
|
||||
}
|
||||
writer.softNewLine();
|
||||
writer.outdent().append("}").softNewLine();
|
||||
|
@ -1681,15 +1681,6 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
|||
}
|
||||
writer.append(')');
|
||||
exitPriority();
|
||||
if (expr.getAsyncTarget() != null) {
|
||||
writer.append(';').softNewLine();
|
||||
writer.append("$ptr").ws().append("=").ws().append(expr.getAsyncTarget()).append(";")
|
||||
.softNewLine();
|
||||
writer.append("if").ws().append("($rt_suspending())").ws().append("{").indent();
|
||||
writer.append("return $save();").softNewLine();
|
||||
writer.outdent().append("}").softNewLine();
|
||||
writer.append("break $main;").softNewLine();
|
||||
}
|
||||
if (lastCallSite != null) {
|
||||
if (virtual) {
|
||||
lastCallSite.setVirtualMethod(expr.getMethod());
|
||||
|
@ -1965,18 +1956,25 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void visit(RestoreAsyncStatement statement) {
|
||||
public void visit(GotoPartStatement statement) {
|
||||
try {
|
||||
if (statement.getReceiver() != null) {
|
||||
writer.append(variableName(statement.getReceiver())).ws().append('=').ws();
|
||||
}
|
||||
writer.append("$restore();").softNewLine();
|
||||
} catch (IOException e) {
|
||||
throw new RenderingException("IO error occured", e);
|
||||
gotoPart(statement.getPart());
|
||||
} catch (IOException ex){
|
||||
throw new RenderingException("IO error occured", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private void gotoPart(int part) throws IOException {
|
||||
writer.append("$ptr").ws().append("=").ws().append(part).append(";")
|
||||
.softNewLine();
|
||||
writer.append("if").ws().append("($rt_suspending())").ws().append("{").indent().softNewLine();
|
||||
writer.append("return $save();").softNewLine();
|
||||
writer.outdent().append("}").softNewLine();
|
||||
writer.append("break $main;").softNewLine();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(MonitorEnterStatement statement) {
|
||||
try {
|
||||
|
@ -1986,6 +1984,9 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
|
|||
writer.appendMethodBody(monitorEnterRef).append("(");
|
||||
statement.getObjectRef().acceptVisitor(this);
|
||||
writer.append(");").softNewLine();
|
||||
if (statement.getAsyncTarget() != null) {
|
||||
gotoPart(statement.getAsyncTarget());
|
||||
}
|
||||
} else {
|
||||
MethodReference monitorEnterRef = new MethodReference(
|
||||
Object.class, "monitorEnterSync", Object.class, void.class);
|
||||
|
|
|
@ -550,20 +550,18 @@ 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 {
|
||||
AssignmentStatement stmt = Statement.assign(null, invocationExpr);
|
||||
stmt.setLocation(currentLocation);
|
||||
statements.add(stmt);
|
||||
}
|
||||
if (insn.getReceiver() != null) {
|
||||
assign(invocationExpr, insn.getReceiver());
|
||||
} else {
|
||||
AssignmentStatement stmt = Statement.assign(null, invocationExpr);
|
||||
stmt.setLocation(currentLocation);
|
||||
statements.add(stmt);
|
||||
}
|
||||
if (asyncTarget != null) {
|
||||
GotoPartStatement gotoStmt = new GotoPartStatement();
|
||||
gotoStmt.setPart(asyncTarget);
|
||||
statements.add(gotoStmt);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -112,16 +112,14 @@ class TryCatchFinder implements StatementVisitor {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void visit(RestoreAsyncStatement statement) {
|
||||
public void visit(GotoPartStatement statement) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(MonitorEnterStatement statement) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(MonitorExitStatement statement) {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -226,10 +226,7 @@ class UnusedVariableEliminator implements ExprVisitor, StatementVisitor {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void visit(RestoreAsyncStatement statement) {
|
||||
if (statement.getReceiver() != null) {
|
||||
statement.setReceiver(renumber(statement.getReceiver()));
|
||||
}
|
||||
public void visit(GotoPartStatement statement) {
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -19,15 +19,15 @@ package org.teavm.javascript.ast;
|
|||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
public class RestoreAsyncStatement extends Statement {
|
||||
private Integer receiver;
|
||||
public class GotoPartStatement extends Statement {
|
||||
private int part;
|
||||
|
||||
public Integer getReceiver() {
|
||||
return receiver;
|
||||
public int getPart() {
|
||||
return part;
|
||||
}
|
||||
|
||||
public void setReceiver(Integer receiver) {
|
||||
this.receiver = receiver;
|
||||
public void setPart(int part) {
|
||||
this.part = part;
|
||||
}
|
||||
|
||||
@Override
|
|
@ -28,7 +28,6 @@ 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;
|
||||
|
@ -50,14 +49,6 @@ 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);
|
||||
|
@ -72,7 +63,6 @@ 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));
|
||||
}
|
||||
|
|
|
@ -193,19 +193,16 @@ public class RenamingVisitor implements StatementVisitor, ExprVisitor {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void visit(RestoreAsyncStatement statement) {
|
||||
if (statement.getReceiver() != null) {
|
||||
statement.setReceiver(varNames[statement.getReceiver()]);
|
||||
}
|
||||
public void visit(GotoPartStatement statement) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(MonitorEnterStatement statement) {
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(MonitorExitStatement statement) {
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,9 +44,9 @@ public interface StatementVisitor {
|
|||
|
||||
void visit(TryCatchStatement statement);
|
||||
|
||||
void visit(RestoreAsyncStatement statement);
|
||||
|
||||
void visit(GotoPartStatement statement);
|
||||
|
||||
void visit(MonitorEnterStatement statement);
|
||||
|
||||
|
||||
void visit(MonitorExitStatement statement);
|
||||
}
|
||||
|
|
|
@ -62,16 +62,12 @@ public class AsyncProgramSplitter {
|
|||
int last = 0;
|
||||
for (int i = 0; i < sourceBlock.getInstructions().size(); ++i) {
|
||||
Instruction insn = sourceBlock.getInstructions().get(i);
|
||||
Integer receiver;
|
||||
if (insn instanceof InvokeInstruction) {
|
||||
InvokeInstruction invoke = (InvokeInstruction)insn;
|
||||
if (!asyncMethods.contains(findRealMethod(invoke.getMethod()))) {
|
||||
continue;
|
||||
}
|
||||
receiver = invoke.getReceiver() != null ? invoke.getReceiver().getIndex() : null;
|
||||
} else if (insn instanceof MonitorEnterInstruction) {
|
||||
receiver = null;
|
||||
} else {
|
||||
} else if (!(insn instanceof MonitorEnterInstruction)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -102,7 +98,6 @@ public class AsyncProgramSplitter {
|
|||
// Create a new part
|
||||
Program nextProgram = createStubCopy(program);
|
||||
Part part = new Part();
|
||||
part.input = receiver;
|
||||
part.program = nextProgram;
|
||||
int partId = parts.size();
|
||||
parts.add(part);
|
||||
|
@ -201,10 +196,6 @@ public class AsyncProgramSplitter {
|
|||
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);
|
||||
|
@ -212,7 +203,6 @@ public class AsyncProgramSplitter {
|
|||
|
||||
private static class Part {
|
||||
Program program;
|
||||
Integer input;
|
||||
int[] blockSuccessors;
|
||||
}
|
||||
|
||||
|
|
|
@ -303,7 +303,7 @@ public class TeaVMTool {
|
|||
return;
|
||||
}
|
||||
if (mainClass != null) {
|
||||
writer.append("main = $rt_mainWrapper(main);\n");
|
||||
writer.append("main = $rt_mainStarter(main);\n");
|
||||
}
|
||||
ProblemProvider problemProvider = vm.getProblemProvider();
|
||||
if (problemProvider.getProblems().isEmpty()) {
|
||||
|
|
|
@ -223,13 +223,16 @@ function $rt_init(cls, constructor, args) {
|
|||
return obj;
|
||||
}
|
||||
function $rt_throw(ex) {
|
||||
throw $rt_exception(ex);
|
||||
}
|
||||
function $rt_exception(ex) {
|
||||
var err = ex.$jsException;
|
||||
if (!err) {
|
||||
var err = new Error("Java exception thrown");
|
||||
err.$javaException = ex;
|
||||
ex.$jsException = err;
|
||||
}
|
||||
throw err;
|
||||
return err;
|
||||
}
|
||||
function $rt_createMultiArray(cls, dimensions) {
|
||||
var arrays = new Array($rt_primitiveArrayCount(dimensions));
|
||||
|
@ -403,71 +406,15 @@ function $rt_metadata(data) {
|
|||
}
|
||||
}
|
||||
}
|
||||
function $rt_asyncResult(value) {
|
||||
return function() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
function $rt_asyncError(e) {
|
||||
return function() {
|
||||
throw new TeaVMAsyncError(e);
|
||||
}
|
||||
}
|
||||
function $rt_staticAsyncAdapter(f) {
|
||||
return function() {
|
||||
var result;
|
||||
var args = Array.prototype.slice.apply(arguments);
|
||||
var $return = args.pop();
|
||||
try {
|
||||
result = f.apply(this, args);
|
||||
} catch (e) {
|
||||
return $return($rt_asyncError(e));
|
||||
}
|
||||
return $return($rt_asyncResult(result));
|
||||
}
|
||||
}
|
||||
function $rt_asyncAdapter(f) {
|
||||
return function() {
|
||||
var result;
|
||||
var args = Array.prototype.slice.apply(arguments);
|
||||
var $return = args.pop();
|
||||
args.unshift(this);
|
||||
try {
|
||||
result = f.apply(null, args);
|
||||
} catch (e) {
|
||||
return $return($rt_asyncError(e));
|
||||
}
|
||||
return $return($rt_asyncResult(result));
|
||||
}
|
||||
}
|
||||
function $rt_rootInvocationAdapter(f) {
|
||||
function $rt_threadStarter(f) {
|
||||
return function() {
|
||||
var args = Array.prototype.slice.apply(arguments);
|
||||
args.push(function(result) {
|
||||
try {
|
||||
result();
|
||||
} catch (e) {
|
||||
var prefix = "Exception occured %s at %o";
|
||||
var hasWrappers = false;
|
||||
while (e instanceof TeaVMAsyncError) {
|
||||
console.error(prefix, e.message, e.stack);
|
||||
e = e.cause;
|
||||
prefix = "Caused by %s at %o";
|
||||
hasWrappers = true;
|
||||
}
|
||||
console.error(!hasWrappers ? prefix : "Root cause is %s at %o", e.message, e.stack);
|
||||
}
|
||||
$rt_startThread(function() {
|
||||
f.apply(this, args);
|
||||
});
|
||||
f.apply(this, args);
|
||||
var thread = $rt_getThread();
|
||||
if (thread.hasOwnProperty("postponed")) {
|
||||
while (thread.postponed.length > 0) {
|
||||
thread.postponed.shift()();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
function $rt_mainWrapper(f) {
|
||||
function $rt_mainStarter(f) {
|
||||
return function(args) {
|
||||
if (!args) {
|
||||
args = [];
|
||||
|
@ -476,7 +423,7 @@ function $rt_mainWrapper(f) {
|
|||
for (var i = 0; i < args.length; ++i) {
|
||||
javaArgs.data[i] = $rt_str(args[i]);
|
||||
}
|
||||
$rt_rootInvocationAdapter(f)(javaArgs);
|
||||
$rt_threadStarter(f)(javaArgs);
|
||||
};
|
||||
}
|
||||
var $rt_stringPool_instance;
|
||||
|
@ -489,66 +436,51 @@ function $rt_stringPool(strings) {
|
|||
function $rt_s(index) {
|
||||
return $rt_stringPool_instance[index];
|
||||
}
|
||||
var $rt_continueCounter = 0;
|
||||
function $rt_continue(f) {
|
||||
if ($rt_continueCounter++ == 5) {
|
||||
$rt_continueCounter = 0;
|
||||
return function() {
|
||||
var self = this;
|
||||
var args = arguments;
|
||||
var thread = $rt_getThread();
|
||||
if (!thread.hasOwnProperty("postponed")) {
|
||||
thread.postponed = [];
|
||||
}
|
||||
thread.postponed.push(function() {
|
||||
f.apply(self, args);
|
||||
});
|
||||
};
|
||||
} else {
|
||||
return f;
|
||||
}
|
||||
}
|
||||
function $rt_guardAsync(f, continuation) {
|
||||
return function() {
|
||||
try {
|
||||
return f.apply(this, arguments);
|
||||
} catch (e) {
|
||||
return continuation($rt_asyncError(e));
|
||||
}
|
||||
}
|
||||
}
|
||||
function TeaVMThread(runner) {
|
||||
this.status = 3;
|
||||
this.stack = [];
|
||||
this.suspendCallback = null;
|
||||
this.runner = runner;
|
||||
this.attribute = null;
|
||||
}
|
||||
TeaVMThread.push = function(value) {
|
||||
TeaVMThread.prototype.push = function(value) {
|
||||
this.stack.push[value];
|
||||
return this;
|
||||
}
|
||||
TeaVMThread.isResuming = function() {
|
||||
TeaVMThread.prototype.pop = function() {
|
||||
return this.stack.pop();
|
||||
}
|
||||
TeaVMThread.prototype.isResuming = function() {
|
||||
return this.status == 1;
|
||||
}
|
||||
TeaVMThread.isSuspending = function() {
|
||||
TeaVMThread.prototype.isSuspending = function() {
|
||||
return this.status == 2;
|
||||
}
|
||||
TeaVMThread.suspend(callback) {
|
||||
TeaVMThread.prototype.suspend = function(callback) {
|
||||
this.suspendCallback = callback;
|
||||
this.status = 1;
|
||||
}
|
||||
TeaVMThread.start = function() {
|
||||
TeaVMThread.prototype.start = function() {
|
||||
if (this.status != 3) {
|
||||
throw new Error("Thread already started");
|
||||
}
|
||||
if ($rt_currentNativeThread !== null) {
|
||||
throw new Error("Another thread is running");
|
||||
}
|
||||
this.status = 0;
|
||||
this.run();
|
||||
}
|
||||
TeaVMThread.resume = function() {
|
||||
TeaVMThread.prototype.resume = function() {
|
||||
if ($rt_currentNativeThread !== null) {
|
||||
throw new Error("Another thread is running");
|
||||
}
|
||||
this.status = 2;
|
||||
this.run();
|
||||
}
|
||||
TeaVMThread.run = function() {
|
||||
TeaVMThread.prototype.run = function() {
|
||||
$rt_currentNativeThread = this;
|
||||
this.runner();
|
||||
$rt_currentNativeThread = null;
|
||||
if (this.suspendCallback !== null) {
|
||||
var self = this;
|
||||
this.suspendCallback(function() {
|
||||
|
@ -556,27 +488,22 @@ TeaVMThread.run = function() {
|
|||
});
|
||||
}
|
||||
}
|
||||
function $rt_nativeThread(thread) {
|
||||
if (!thread.hasNativeProperty("$teavm_thread")) {
|
||||
thread.$teavm_thread = new TeaVMThread();
|
||||
}
|
||||
}
|
||||
function $rt_suspending() {
|
||||
return $rt_nativeThread($rt_getThread()).isSuspending();
|
||||
return $rt_nativeThread().isSuspending();
|
||||
}
|
||||
function $rt_resuming() {
|
||||
return $rt_nativeThread($rt_getThread()).isResuming();
|
||||
return $rt_nativeThread().isResuming();
|
||||
}
|
||||
|
||||
function TeaVMAsyncError(cause) {
|
||||
this.message = "Async error occured";
|
||||
this.cause = cause;
|
||||
if (cause) {
|
||||
this.$javaException = cause.$javaException;
|
||||
}
|
||||
function $rt_suspend(callback) {
|
||||
return $rt_nativeThread().suspend(callback);
|
||||
}
|
||||
function $rt_startThread(runner) {
|
||||
new TeaVMThread(runner).start();
|
||||
}
|
||||
var $rt_currentNativeThread = null;
|
||||
function $rt_nativeThread() {
|
||||
return $rt_currentNativeThread;
|
||||
}
|
||||
TeaVMAsyncError.prototype = new Error();
|
||||
TeaVMAsyncError.prototype.constructor = TeaVMAsyncError;
|
||||
|
||||
function $dbg_repr(obj) {
|
||||
return obj.toString ? obj.toString() : "";
|
||||
|
|
|
@ -73,9 +73,17 @@ public final class Platform {
|
|||
return ((PlatformHelper)JS.getGlobal()).nextId();
|
||||
}
|
||||
|
||||
public static <T> T newInstance(PlatformClass cls) {
|
||||
prepareNewInstance();
|
||||
return newInstanceImpl(cls);
|
||||
}
|
||||
|
||||
@GeneratedBy(PlatformGenerator.class)
|
||||
private static native void prepareNewInstance();
|
||||
|
||||
@GeneratedBy(PlatformGenerator.class)
|
||||
@PluggableDependency(PlatformGenerator.class)
|
||||
public static native <T> T newInstance(PlatformClass cls);
|
||||
private static native <T> T newInstanceImpl(PlatformClass cls);
|
||||
|
||||
@GeneratedBy(PlatformGenerator.class)
|
||||
@PluggableDependency(PlatformGenerator.class)
|
||||
|
|
|
@ -38,19 +38,29 @@ public class AsyncMethodGenerator implements Generator, DependencyPlugin {
|
|||
@Override
|
||||
public void generate(GeneratorContext context, SourceWriter writer, MethodReference methodRef) throws IOException {
|
||||
MethodReference asyncRef = getAsyncReference(methodRef);
|
||||
writer.append("var thread").ws().append('=').ws().append("$rt_nativeThread();").softNewLine();
|
||||
writer.append("if").ws().append("(thread.isResuming())").ws().append("{").indent().softNewLine();
|
||||
writer.append("var result").ws().append("=").ws().append("thread.attribute;").softNewLine();
|
||||
writer.append("if").ws().append("(result instanceof Error)").ws().append("{").indent().softNewLine();
|
||||
writer.append("throw result;").softNewLine();
|
||||
writer.outdent().append("}").softNewLine();
|
||||
writer.append("return result;").softNewLine();
|
||||
writer.outdent().append("}").softNewLine();
|
||||
|
||||
writer.append("var callback").ws().append("=").ws().append("function()").ws().append("{};").softNewLine();
|
||||
writer.append("callback.").appendMethod(completeMethod.getDescriptor()).ws().append("=").ws()
|
||||
.append("function(val)").ws().append("{").indent().softNewLine();
|
||||
writer.append("return ").append(context.getCompleteContinuation()).append("($rt_asyncResult(val));")
|
||||
.softNewLine();
|
||||
writer.append("thread.attribute").ws().append('=').ws().append("val;").softNewLine();
|
||||
writer.append("thread.resume();").softNewLine();
|
||||
writer.outdent().append("};").softNewLine();
|
||||
writer.append("callback.").appendMethod(errorMethod.getDescriptor()).ws().append("=").ws()
|
||||
.append("function(e)").ws().append("{").indent().softNewLine();
|
||||
writer.append("return ").append(context.getCompleteContinuation()).append("($rt_asyncError(e));")
|
||||
.softNewLine();
|
||||
writer.append("thread.attribute").ws().append('=').ws().append("$rt_exception(e);").softNewLine();
|
||||
writer.append("thread.resume();").softNewLine();
|
||||
writer.outdent().append("};").softNewLine();
|
||||
writer.append("return thread.suspend(function()").ws().append("{").indent().softNewLine();
|
||||
writer.append("try").ws().append("{").indent().softNewLine();
|
||||
writer.append("return ").appendMethodBody(asyncRef).append('(');
|
||||
writer.appendMethodBody(asyncRef).append('(');
|
||||
ClassReader cls = context.getClassSource().get(methodRef.getClassName());
|
||||
MethodReader method = cls.getMethod(methodRef.getDescriptor());
|
||||
int start = method.hasModifier(ElementModifier.STATIC) ? 1 : 0;
|
||||
|
@ -60,9 +70,10 @@ public class AsyncMethodGenerator implements Generator, DependencyPlugin {
|
|||
}
|
||||
writer.append("callback);").softNewLine();
|
||||
writer.outdent().append("}").ws().append("catch($e)").ws().append("{").indent().softNewLine();
|
||||
writer.append("return ").append(context.getCompleteContinuation()).append("($rt_asyncError($e));")
|
||||
writer.append("callback.").appendMethod(errorMethod.getDescriptor()).append("($rt_exception($e));")
|
||||
.softNewLine();
|
||||
writer.outdent().append("}").softNewLine();
|
||||
writer.outdent().append("});").softNewLine();
|
||||
}
|
||||
|
||||
private MethodReference getAsyncReference(MethodReference methodRef) {
|
||||
|
|
|
@ -49,7 +49,7 @@ public class NewInstanceDependencySupport implements DependencyListener {
|
|||
@Override
|
||||
public void methodAchieved(final DependencyAgent agent, MethodDependency method, CallLocation location) {
|
||||
MethodReader reader = method.getMethod();
|
||||
if (reader.getOwnerName().equals(Platform.class.getName()) && reader.getName().equals("newInstance")) {
|
||||
if (reader.getOwnerName().equals(Platform.class.getName()) && reader.getName().equals("newInstanceImpl")) {
|
||||
allClassesNode.connect(method.getResult());
|
||||
final MethodReference methodRef = reader.getReference();
|
||||
method.getResult().addConsumer(new DependencyConsumer() {
|
||||
|
|
|
@ -68,8 +68,11 @@ public class PlatformGenerator implements Generator, Injector, DependencyPlugin
|
|||
@Override
|
||||
public void generate(GeneratorContext context, SourceWriter writer, MethodReference methodRef) throws IOException {
|
||||
switch (methodRef.getName()) {
|
||||
case "newInstance":
|
||||
generateNewInstance(context, writer, methodRef);
|
||||
case "newInstanceImpl":
|
||||
generateNewInstance(writer);
|
||||
break;
|
||||
case "prepareNewInstance":
|
||||
generatePrepareNewInstance(context, writer);
|
||||
break;
|
||||
case "lookupClass":
|
||||
generateLookup(context, writer);
|
||||
|
@ -89,76 +92,37 @@ public class PlatformGenerator implements Generator, Injector, DependencyPlugin
|
|||
}
|
||||
}
|
||||
|
||||
private void generateNewInstance(GeneratorContext context, SourceWriter writer, MethodReference methodRef)
|
||||
private void generatePrepareNewInstance(GeneratorContext context, SourceWriter writer)
|
||||
throws IOException {
|
||||
writer.append("var c").ws().append("=").ws().append("'$$constructor$$';").softNewLine();
|
||||
if (context.isAsync()) {
|
||||
writer.append("function async(cls, init) {").indent().softNewLine();
|
||||
writer.append("return function($return) {").indent().softNewLine();
|
||||
writer.append("var r = new cls;").softNewLine();
|
||||
writer.append("init(r, $rt_guardAsync(function($restore) {").indent().softNewLine();
|
||||
writer.append("$restore();").softNewLine();
|
||||
writer.append("$return($rt_asyncResult(r))").softNewLine();
|
||||
writer.outdent().append("}));").softNewLine();
|
||||
writer.outdent().append("};").softNewLine();
|
||||
writer.outdent().append("}").softNewLine();
|
||||
|
||||
writer.append("function sync(cls, init) {").indent().softNewLine();
|
||||
writer.append("return function($return) {").indent().softNewLine();
|
||||
writer.append("var r = new cls;").softNewLine();
|
||||
writer.append("try {").indent().softNewLine();
|
||||
writer.append("init(r);").softNewLine();
|
||||
writer.append("$return($rt_asyncResult(r));").softNewLine();
|
||||
writer.outdent().append("} catch (e) {").indent().softNewLine();
|
||||
writer.append("$return($rt_asyncError(e));").softNewLine();
|
||||
writer.outdent().append("}").softNewLine();
|
||||
writer.outdent().append("};").softNewLine();
|
||||
writer.outdent().append("}").softNewLine();
|
||||
}
|
||||
for (String clsName : context.getClassSource().getClassNames()) {
|
||||
ClassReader cls = context.getClassSource().get(clsName);
|
||||
MethodReader method = cls.getMethod(new MethodDescriptor("<init>", void.class));
|
||||
if (method != null) {
|
||||
writer.appendClass(clsName).append("[c]").ws().append("=").ws();
|
||||
if (!context.isAsync()) {
|
||||
writer.append(writer.getNaming().getNameForInit(method.getReference()));
|
||||
} else {
|
||||
String function = context.isAsync(method.getReference()) ? "async" : "sync";
|
||||
String methodName = context.isAsync(method.getReference()) ?
|
||||
writer.getNaming().getFullNameForAsync(method.getReference()) :
|
||||
writer.getNaming().getFullNameFor(method.getReference());
|
||||
writer.append(function).append("(").appendClass(clsName).append(',').ws()
|
||||
.append(methodName).append(")");
|
||||
}
|
||||
writer.append(";").softNewLine();
|
||||
writer.appendClass(clsName).append("[c]").ws().append("=").ws()
|
||||
.appendMethodBody(method.getReference()).append(")").append(";").softNewLine();
|
||||
}
|
||||
}
|
||||
String selfName = context.isAsync() ? writer.getNaming().getFullNameForAsync(methodRef) :
|
||||
writer.getNaming().getFullNameFor(methodRef);
|
||||
writer.append(selfName).ws().append("=").ws().append("function(cls");
|
||||
if (context.isAsync()) {
|
||||
writer.append(',').ws().append("$return");
|
||||
}
|
||||
writer.append(")").ws().append("{").softNewLine().indent();
|
||||
writer.append("if").ws().append("(!cls.hasOwnProperty(c))").ws().append("{").indent().softNewLine();
|
||||
if (!context.isAsync()) {
|
||||
writer.append("return null;").softNewLine();
|
||||
} else {
|
||||
writer.append("return $return($rt_asyncResult(null));").softNewLine();
|
||||
}
|
||||
writer.outdent().append("}").softNewLine();
|
||||
if (!context.isAsync()) {
|
||||
writer.append("return cls[c]();").softNewLine();
|
||||
} else {
|
||||
writer.append("return cls[c]($return);").softNewLine();
|
||||
}
|
||||
writer.outdent().append("};").softNewLine();
|
||||
writer.appendMethodBody(Platform.class, "newInstance", PlatformClass.class, Object.class).ws().append('=').ws()
|
||||
.appendMethodBody(Platform.class, "newInstanceImpl", PlatformClass.class, Object.class)
|
||||
.append(";").softNewLine();
|
||||
}
|
||||
|
||||
writer.append("return ").append(selfName).append("(").append(context.getParameterName(1));
|
||||
if (context.isAsync()) {
|
||||
writer.append(',').ws().append(context.getCompleteContinuation());
|
||||
}
|
||||
writer.append(");").softNewLine();
|
||||
private void generateNewInstance(SourceWriter writer) throws IOException {
|
||||
writer.append("if").ws().append("($rt_resuming())").ws().append("{").indent().softNewLine();
|
||||
writer.append("return $rt_nativeThread().pop();").softNewLine();
|
||||
writer.outdent().append("}").softNewLine();
|
||||
|
||||
writer.append("if").ws().append("(!cls.hasOwnProperty('$$constructor$$'))").ws().append("{")
|
||||
.indent().softNewLine();
|
||||
writer.append("return null;").softNewLine();
|
||||
writer.outdent().append("}").softNewLine();
|
||||
|
||||
writer.append("var $r").ws().append('=').ws().append("cls.$$constructor$$();");
|
||||
writer.append("if").ws().append("($rt_suspending())").ws().append("{").indent().softNewLine();
|
||||
writer.append("return $rt_nativeThread().push($r);").softNewLine();
|
||||
writer.outdent().append("}").softNewLine();
|
||||
writer.append("return $r;").softNewLine();
|
||||
}
|
||||
|
||||
private void generateLookup(GeneratorContext context, SourceWriter writer) throws IOException {
|
||||
|
@ -189,18 +153,8 @@ public class PlatformGenerator implements Generator, Injector, DependencyPlugin
|
|||
PlatformRunnable.class, void.class);
|
||||
String runnable = context.getParameterName(1);
|
||||
writer.append("return window.setTimeout(function()").ws().append("{").indent().softNewLine();
|
||||
boolean async = context.isAsyncFamily(launchRef);
|
||||
String methodName = async ? writer.getNaming().getFullNameForAsync(launchRef) :
|
||||
writer.getNaming().getFullNameFor(launchRef);
|
||||
if (async) {
|
||||
writer.append("$rt_rootInvocationAdapter(");
|
||||
}
|
||||
writer.append(methodName);
|
||||
if (async) {
|
||||
writer.append(")");
|
||||
}
|
||||
writer.append("(").append(runnable).append(");")
|
||||
.softNewLine();
|
||||
writer.append("$rt_threadStarter(").appendMethodBody(launchRef).append(")");
|
||||
writer.append("(").append(runnable).append(");").softNewLine();
|
||||
writer.outdent().append("},").ws().append(timeout ? context.getParameterName(2) : "0")
|
||||
.append(");").softNewLine();
|
||||
}
|
||||
|
|
|
@ -65,10 +65,12 @@
|
|||
<targetDirectory>${project.build.directory}/generated/js/teavm</targetDirectory>
|
||||
<mainClass>org.teavm.samples.async.AsyncProgram</mainClass>
|
||||
<runtime>SEPARATE</runtime>
|
||||
<minifying>true</minifying>
|
||||
<minifying>false</minifying>
|
||||
<debugInformationGenerated>true</debugInformationGenerated>
|
||||
<!--
|
||||
<sourceMapsGenerated>true</sourceMapsGenerated>
|
||||
<sourceFilesCopied>true</sourceFilesCopied>
|
||||
-->
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
|
|
Loading…
Reference in New Issue
Block a user