Further work on a new thread emulator

This commit is contained in:
Alexey Andreev 2015-03-10 15:19:54 +04:00
parent 93e43456d1
commit 32deaf2716
27 changed files with 193 additions and 333 deletions

View File

@ -80,6 +80,7 @@ public class TThread extends TObject implements TRunnable {
currentThread.timeSliceStart = System.currentTimeMillis();
}
}
static TThread getMainThread(){
return mainThread;
}

View File

@ -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);
}

View File

@ -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) {
}
}

View File

@ -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) {
}
}

View File

@ -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) {
}
}

View File

@ -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;

View File

@ -188,7 +188,7 @@ public class NameFrequencyEstimator implements StatementVisitor, ExprVisitor, Me
}
@Override
public void visit(RestoreAsyncStatement statement) {
public void visit(GotoPartStatement statement) {
}
@Override

View File

@ -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);

View File

@ -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;
}
}

View File

@ -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) {
}
}

View File

@ -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) {
}
}

View File

@ -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);

View File

@ -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

View File

@ -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) {
}
}

View File

@ -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

View File

@ -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

View File

@ -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));
}

View File

@ -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) {
}
}

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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()) {

View File

@ -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() : "";

View File

@ -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)

View File

@ -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) {

View File

@ -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() {

View File

@ -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();
}

View File

@ -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>