Outline of upcoming improvements of continuations

This commit is contained in:
Alexey Andreev 2015-03-10 12:49:00 +04:00
parent 7f33f64d25
commit 93e43456d1
11 changed files with 164 additions and 260 deletions

View File

@ -72,10 +72,7 @@ public class TObject {
monitorEnter(o, 1); monitorEnter(o, 1);
} }
@Async static void monitorEnter(TObject o, int count) {
static native void monitorEnter(TObject o, int count);
static void monitorEnter(final TObject o, final int count, final AsyncCallback<Void> callback) {
if (o.monitor == null) { if (o.monitor == null) {
o.monitor = new Monitor(); o.monitor = new Monitor();
} }
@ -83,21 +80,27 @@ public class TObject {
o.monitor.owner = TThread.currentThread(); o.monitor.owner = TThread.currentThread();
} }
if (o.monitor.owner != TThread.currentThread()) { if (o.monitor.owner != TThread.currentThread()) {
final TThread thread = TThread.currentThread(); monitorEnterWait(o, count);
o.monitor.enteringThreads.add(new PlatformRunnable() {
@Override public void run() {
TThread.setCurrentThread(thread);
o.monitor.owner = thread;
o.monitor.count += count;
callback.complete(null);
}
});
} else { } else {
o.monitor.count += count; o.monitor.count += count;
callback.complete(null);
} }
} }
@Async
static native void monitorEnterWait(TObject o, int count);
static void monitorEnterWait(final TObject o, final int count, final AsyncCallback<Void> callback) {
final TThread thread = TThread.currentThread();
o.monitor.enteringThreads.add(new PlatformRunnable() {
@Override public void run() {
TThread.setCurrentThread(thread);
o.monitor.owner = thread;
o.monitor.count += count;
callback.complete(null);
}
});
}
@Sync @Sync
static void monitorExit(final TObject o) { static void monitorExit(final TObject o) {
monitorExit(o, 1); monitorExit(o, 1);
@ -230,15 +233,18 @@ public class TObject {
} }
} }
@Async
@Rename("wait") @Rename("wait")
private native final void wait0(long timeout, int nanos) throws TInterruptedException; private final void wait0(long timeout, int nanos) throws TInterruptedException {
@Rename("wait")
public final void wait0(long timeout, int nanos, final AsyncCallback<Void> callback) {
if (!holdsLock(this)) { if (!holdsLock(this)) {
throw new TIllegalMonitorStateException(); throw new TIllegalMonitorStateException();
} }
waitImpl(timeout, nanos);
}
@Async
private native final void waitImpl(long timeout, int nanos) throws TInterruptedException;
public final void waitImpl(long timeout, int nanos, final AsyncCallback<Void> callback) {
final NotifyListenerImpl listener = new NotifyListenerImpl(this, callback, monitor.count); final NotifyListenerImpl listener = new NotifyListenerImpl(this, callback, monitor.count);
monitor.notifyListeners.add(listener); monitor.notifyListeners.add(listener);
if (timeout > 0 || nanos > 0) { if (timeout > 0 || nanos > 0) {
@ -288,7 +294,7 @@ public class TObject {
timerId = -1; timerId = -1;
} }
TThread.setCurrentThread(currentThread); TThread.setCurrentThread(currentThread);
monitorEnter(obj, lockCount, callback); monitorEnterWait(obj, lockCount, callback);
} }
} }

View File

@ -23,7 +23,6 @@ import org.teavm.platform.Platform;
import org.teavm.platform.PlatformRunnable; import org.teavm.platform.PlatformRunnable;
import org.teavm.platform.async.AsyncCallback; import org.teavm.platform.async.AsyncCallback;
/** /**
* *
* @author Alexey Andreev * @author Alexey Andreev
@ -36,6 +35,7 @@ public class TThread extends TObject implements TRunnable {
private static int activeCount = 1; private static int activeCount = 1;
private long id; private long id;
private int priority = 0; private int priority = 0;
private long timeSliceStart;
private TString name; private TString name;
TRunnable target; TRunnable target;
@ -55,10 +55,10 @@ public class TThread extends TObject implements TRunnable {
public TThread(TRunnable target, TString name ) { public TThread(TRunnable target, TString name ) {
this.name = name; this.name = name;
this.target = target; this.target = target;
id=nextId++; id = nextId++;
} }
public void start(){ public void start() {
Platform.startThread(new PlatformRunnable() { Platform.startThread(new PlatformRunnable() {
@Override @Override
public void run() { public void run() {
@ -74,8 +74,11 @@ public class TThread extends TObject implements TRunnable {
}); });
} }
static void setCurrentThread(TThread thread){ static void setCurrentThread(TThread thread) {
currentThread = thread; if (currentThread != thread) {
currentThread = thread;
currentThread.timeSliceStart = System.currentTimeMillis();
}
} }
static TThread getMainThread(){ static TThread getMainThread(){
return mainThread; return mainThread;
@ -96,11 +99,26 @@ public class TThread extends TObject implements TRunnable {
return name; return name;
} }
@Async public static void yield() {
public static native void yield(); if (currentThread.timeSliceStart + 100 < System.currentTimeMillis()) {
switchContext();
}
}
private static void yield(final AsyncCallback<Void> callback) { @Async
callback.complete(null); static native void switchContext();
private static void switchContext(final AsyncCallback<Void> callback) {
final TThread thread = currentThread();
Platform.startThread(new PlatformRunnable() {
@Override public void run() {
setCurrentThread(thread);
callback.complete(null);
}
});
}
private static void yieldImpl() {
} }
public void interrupt() { public void interrupt() {
@ -138,11 +156,11 @@ public class TThread extends TObject implements TRunnable {
} }
}, millis); }, millis);
} }
public final void setPriority(int newPriority){ public final void setPriority(int newPriority){
this.priority = newPriority; this.priority = newPriority;
} }
public final int getPriority(){ public final int getPriority(){
return this.priority; return this.priority;
} }

View File

@ -58,12 +58,7 @@ public class DefaultNamingStrategy implements NamingStrategy {
@Override @Override
public String getNameFor(MethodDescriptor method) { public String getNameFor(MethodDescriptor method) {
return getNameFor(method, 'S'); return getNameFor(method, 'M');
}
@Override
public String getNameForAsync(MethodDescriptor method) throws NamingException {
return getNameFor(method, 'A');
} }
private String getNameFor(MethodDescriptor method, char classifier) { private String getNameFor(MethodDescriptor method, char classifier) {
@ -78,12 +73,7 @@ public class DefaultNamingStrategy implements NamingStrategy {
@Override @Override
public String getFullNameFor(MethodReference method) throws NamingException { public String getFullNameFor(MethodReference method) throws NamingException {
return getFullNameFor(method, 'S'); return getFullNameFor(method, 'M');
}
@Override
public String getFullNameForAsync(MethodReference method) throws NamingException {
return getFullNameFor(method, 'A');
} }
@Override @Override

View File

@ -26,14 +26,10 @@ import org.teavm.model.MethodReference;
public interface NameFrequencyConsumer { public interface NameFrequencyConsumer {
void consume(MethodReference method); void consume(MethodReference method);
void consumeAsync(MethodReference method);
void consumeInit(MethodReference method); void consumeInit(MethodReference method);
void consume(MethodDescriptor method); void consume(MethodDescriptor method);
void consumeAsync(MethodDescriptor method);
void consume(String className); void consume(String className);
void consume(FieldReference field); void consume(FieldReference field);

View File

@ -43,21 +43,6 @@ public class NamingOrderer implements NameFrequencyConsumer {
entry.frequency++; entry.frequency++;
} }
@Override
public void consumeAsync(final MethodReference method) {
String key = "A:" + method;
Entry entry = entries.get(key);
if (entry == null) {
entry = new Entry();
entry.operation = new NamingOperation() {
@Override public void perform(NamingStrategy naming) {
naming.getFullNameForAsync(method);
}
};
entries.put(key, entry);
}
entry.frequency++;
}
@Override @Override
public void consumeInit(final MethodReference method) { public void consumeInit(final MethodReference method) {
@ -91,22 +76,6 @@ public class NamingOrderer implements NameFrequencyConsumer {
entry.frequency++; entry.frequency++;
} }
@Override
public void consumeAsync(final MethodDescriptor method) {
String key = "a:" + method;
Entry entry = entries.get(key);
if (entry == null) {
entry = new Entry();
entry.operation = new NamingOperation() {
@Override public void perform(NamingStrategy naming) {
naming.getNameForAsync(method);
}
};
entries.put(key, entry);
}
entry.frequency++;
}
@Override @Override
public void consume(final String className) { public void consume(final String className) {
String key = "c:" + className; String key = "c:" + className;

View File

@ -28,14 +28,10 @@ public interface NamingStrategy {
String getNameFor(MethodDescriptor method) throws NamingException; String getNameFor(MethodDescriptor method) throws NamingException;
String getNameForAsync(MethodDescriptor method) throws NamingException;
String getNameForInit(MethodReference method) throws NamingException; String getNameForInit(MethodReference method) throws NamingException;
String getFullNameFor(MethodReference method) throws NamingException; String getFullNameFor(MethodReference method) throws NamingException;
String getFullNameForAsync(MethodReference method) throws NamingException;
String getNameFor(FieldReference field) throws NamingException; String getNameFor(FieldReference field) throws NamingException;
String getNameForFunction(String name) throws NamingException; String getNameForFunction(String name) throws NamingException;

View File

@ -63,38 +63,17 @@ public class NameFrequencyEstimator implements StatementVisitor, ExprVisitor, Me
MethodReader clinit = classSource.get(cls.getName()).getMethod( MethodReader clinit = classSource.get(cls.getName()).getMethod(
new MethodDescriptor("<clinit>", ValueType.VOID)); new MethodDescriptor("<clinit>", ValueType.VOID));
for (MethodNode method : cls.getMethods()) { for (MethodNode method : cls.getMethods()) {
if (method.isAsync()) { consumer.consume(method.getReference());
consumer.consumeAsync(method.getReference()); if (asyncFamilyMethods.contains(method.getReference())) {
} else {
consumer.consume(method.getReference()); consumer.consume(method.getReference());
if (asyncFamilyMethods.contains(method.getReference())) {
consumer.consume(method.getReference());
consumer.consumeAsync(method.getReference());
consumer.consumeFunction("$rt_asyncError");
consumer.consumeFunction("$rt_asyncResult");
}
} }
if (clinit != null && (method.getModifiers().contains(NodeModifier.STATIC) || if (clinit != null && (method.getModifiers().contains(NodeModifier.STATIC) ||
method.getReference().getName().equals("<init>"))) { method.getReference().getName().equals("<init>"))) {
if (!method.isAsync()) { consumer.consume(method.getReference());
consumer.consume(method.getReference());
}
if (asyncFamilyMethods.contains(method.getReference())) {
consumer.consumeAsync(method.getReference());
}
} }
if (!method.getModifiers().contains(NodeModifier.STATIC)) { if (!method.getModifiers().contains(NodeModifier.STATIC)) {
if (method.isAsync()) { consumer.consume(method.getReference().getDescriptor());
consumer.consumeAsync(method.getReference().getDescriptor()); consumer.consume(method.getReference());
consumer.consumeAsync(method.getReference());
} else {
consumer.consume(method.getReference().getDescriptor());
consumer.consume(method.getReference());
if (asyncFamilyMethods.contains(method.getReference())) {
consumer.consumeAsync(method.getReference().getDescriptor());
consumer.consumeAsync(method.getReference());
}
}
} }
} }
@ -217,7 +196,7 @@ public class NameFrequencyEstimator implements StatementVisitor, ExprVisitor, Me
if (async) { if (async) {
MethodReference monitorEnterRef = new MethodReference( MethodReference monitorEnterRef = new MethodReference(
Object.class, "monitorEnter", Object.class, void.class); Object.class, "monitorEnter", Object.class, void.class);
consumer.consumeAsync(monitorEnterRef); consumer.consume(monitorEnterRef);
} else { } else {
MethodReference monitorEnterRef = new MethodReference( MethodReference monitorEnterRef = new MethodReference(
Object.class, "monitorEnterSync", Object.class, void.class); Object.class, "monitorEnterSync", Object.class, void.class);
@ -230,7 +209,7 @@ public class NameFrequencyEstimator implements StatementVisitor, ExprVisitor, Me
if (async) { if (async) {
MethodReference monitorEnterRef = new MethodReference( MethodReference monitorEnterRef = new MethodReference(
Object.class, "monitorExit", Object.class, void.class); Object.class, "monitorExit", Object.class, void.class);
consumer.consumeAsync(monitorEnterRef); consumer.consume(monitorEnterRef);
} else { } else {
MethodReference monitorEnterRef = new MethodReference( MethodReference monitorEnterRef = new MethodReference(
Object.class, "monitorExitSync", Object.class, void.class); Object.class, "monitorExitSync", Object.class, void.class);
@ -308,30 +287,18 @@ public class NameFrequencyEstimator implements StatementVisitor, ExprVisitor, Me
if (injectedMethods.contains(expr.getMethod())) { if (injectedMethods.contains(expr.getMethod())) {
return; return;
} }
boolean asyncCall = expr.getAsyncTarget() != null;
switch (expr.getType()) { switch (expr.getType()) {
case SPECIAL: case SPECIAL:
case STATIC: case STATIC:
if (asyncCall) { consumer.consume(expr.getMethod());
consumer.consumeAsync(expr.getMethod());
} else {
consumer.consume(expr.getMethod());
}
break; break;
case CONSTRUCTOR: case CONSTRUCTOR:
consumer.consumeInit(expr.getMethod()); consumer.consumeInit(expr.getMethod());
break; break;
case DYNAMIC: case DYNAMIC:
if (asyncCall) { consumer.consume(expr.getMethod().getDescriptor());
consumer.consumeAsync(expr.getMethod().getDescriptor());
} else {
consumer.consume(expr.getMethod().getDescriptor());
}
break; break;
} }
if (asyncCall) {
consumer.consumeFunction("$rt_continue");
}
} }
@Override @Override

View File

@ -452,12 +452,7 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
for (MethodNode method : cls.getMethods()) { for (MethodNode method : cls.getMethods()) {
if (clinit != null && (method.getModifiers().contains(NodeModifier.STATIC) || if (clinit != null && (method.getModifiers().contains(NodeModifier.STATIC) ||
method.getReference().getName().equals("<init>"))) { method.getReference().getName().equals("<init>"))) {
if (!method.isAsync()) { stubNames.add(naming.getFullNameFor(method.getReference()));
stubNames.add(naming.getFullNameFor(method.getReference()));
}
if (asyncFamilyMethods.contains(method.getReference())) {
stubNames.add(naming.getFullNameForAsync(method.getReference()));
}
} }
if (!method.getModifiers().contains(NodeModifier.STATIC)) { if (!method.getModifiers().contains(NodeModifier.STATIC)) {
virtualMethods.add(method); virtualMethods.add(method);
@ -546,32 +541,20 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
writer.append(",").ws(); writer.append(",").ws();
} }
first = false; first = false;
if (method.isAsync()) { emitVirtualDeclaration(ref);
emitVirtualDeclaration(ref, true);
} else {
emitVirtualDeclaration(ref, false);
if (asyncFamilyMethods.contains(ref)) {
writer.append(",").ws();
emitVirtualDeclaration(ref, true);
}
}
debugEmitter.emitMethod(null); debugEmitter.emitMethod(null);
} }
writer.append("]"); writer.append("]");
} }
private void emitVirtualDeclaration(MethodReference ref, boolean async) throws IOException { private void emitVirtualDeclaration(MethodReference ref) throws IOException {
String methodName = async ? naming.getNameForAsync(ref.getDescriptor()) : String methodName = naming.getNameFor(ref.getDescriptor());
naming.getNameFor(ref.getDescriptor());
writer.append("\"").append(methodName).append("\""); writer.append("\"").append(methodName).append("\"");
writer.append(",").ws().append("function("); writer.append(",").ws().append("function(");
List<String> args = new ArrayList<>(); List<String> args = new ArrayList<>();
for (int i = 1; i <= ref.parameterCount(); ++i) { for (int i = 1; i <= ref.parameterCount(); ++i) {
args.add(variableName(i)); args.add(variableName(i));
} }
if (async) {
args.add(getReturnVariable());
}
for (int i = 0; i < args.size(); ++i) { for (int i = 0; i < args.size(); ++i) {
if (i > 0) { if (i > 0) {
writer.append(",").ws(); writer.append(",").ws();
@ -582,7 +565,7 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
if (ref.getDescriptor().getResultType() != ValueType.VOID) { if (ref.getDescriptor().getResultType() != ValueType.VOID) {
writer.append("return "); writer.append("return ");
} }
writer.append(async ? naming.getFullNameForAsync(ref) : naming.getFullNameFor(ref)).append("("); writer.appendMethodBody(ref).append("(");
writer.append("this"); writer.append("this");
for (int i = 0; i < args.size(); ++i) { for (int i = 0; i < args.size(); ++i) {
writer.append(",").ws().append(args.get(i)); writer.append(",").ws().append(args.get(i));
@ -590,23 +573,11 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
writer.append(");").ws().append("}"); writer.append(");").ws().append("}");
} }
private String getPartVariable(int index) {
if (minifying) {
return "$p" + indexToId(index);
} else {
return "$part_" + index;
}
}
private String getReturnVariable() {
return minifying ? "$r" : "$return";
}
public void renderBody(MethodNode method, boolean inner) throws IOException { public void renderBody(MethodNode method, boolean inner) throws IOException {
blockIdMap.clear(); blockIdMap.clear();
MethodReference ref = method.getReference(); MethodReference ref = method.getReference();
debugEmitter.emitMethod(ref.getDescriptor()); debugEmitter.emitMethod(ref.getDescriptor());
String name = method.isAsync() ? naming.getFullNameForAsync(ref) : naming.getFullNameFor(ref); String name = naming.getFullNameFor(ref);
if (inner) { if (inner) {
writer.append(name).ws().append("=").ws().append("function("); writer.append(name).ws().append("=").ws().append("function(");
} else { } else {
@ -622,12 +593,6 @@ 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(getReturnVariable());
}
writer.append(")").ws().append("{").softNewLine().indent(); writer.append(")").ws().append("{").softNewLine().indent();
method.acceptVisitor(new MethodBodyRenderer()); method.acceptVisitor(new MethodBodyRenderer());
writer.outdent().append("}"); writer.outdent().append("}");
@ -635,42 +600,6 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
writer.append(';'); writer.append(';');
} }
writer.newLine(); writer.newLine();
if (!method.isAsync() && asyncFamilyMethods.contains(method.getReference())) {
if (inner) {
writer.append(naming.getFullNameForAsync(ref)).ws().append("=").ws().append("function(");
} else {
writer.append("function ").append(naming.getFullNameForAsync(ref)).append("(");
}
for (int i = startParam; i <= ref.parameterCount(); ++i) {
writer.append(variableName(i));
writer.append(",").ws();
}
writer.append(getReturnVariable()).append(")").ws().append("{").softNewLine().indent();
writer.append("var $x;").softNewLine();
writer.append("try").ws().append('{').indent().softNewLine();
writer.append("$x").ws().append("=").ws().appendMethodBody(ref).append('(');
for (int i = startParam; i <= ref.parameterCount(); ++i) {
if (i > startParam) {
writer.append(",").ws();
}
writer.append(variableName(i));
}
writer.append(");").softNewLine();
writer.outdent().append("}").ws().append("catch").ws().append("($e)").ws()
.append("{").indent().softNewLine();
writer.append("return ").append(getReturnVariable()).append("(").appendFunction("$rt_asyncError")
.append("($e));").softNewLine();
writer.outdent().append("}");
writer.append(getReturnVariable()).append("(").appendFunction("$rt_asyncResult").append("($x));")
.softNewLine();
writer.outdent().append("}");
if (inner) {
writer.append(';');
}
writer.newLine();
}
debugEmitter.emitMethod(null); debugEmitter.emitMethod(null);
} }
@ -756,6 +685,7 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
if (hasTryCatch) { if (hasTryCatch) {
variableNames.add("$je"); variableNames.add("$je");
} }
variableNames.add("$ptr");
if (!variableNames.isEmpty()) { if (!variableNames.isEmpty()) {
writer.append("var "); writer.append("var ");
for (int i = 0; i < variableNames.size(); ++i) { for (int i = 0; i < variableNames.size(); ++i) {
@ -766,18 +696,34 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
} }
writer.append(";").softNewLine(); writer.append(";").softNewLine();
} }
writer.append("function $save()").ws().append("{").indent().softNewLine();
writer.append("var $").ws().append('=').ws().append("$rt_stack();").softNewLine();
for (int i = ref.parameterCount() + 1; i < variableCount; ++i) {
writer.append("$.push(").append(variableName(i)).append(");");
}
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();");
for (int i = variableCount - 1; i > ref.parameterCount(); --i) {
writer.append(variableName(i)).ws().append('=').ws().append("$.pop();");
}
writer.softNewLine();
writer.outdent().append("}").softNewLine();
writer.append("$main: switch").ws().append("($ptr)").ws().append('{').softNewLine();
for (int i = 0; i < methodNode.getBody().size(); ++i) { for (int i = 0; i < methodNode.getBody().size(); ++i) {
writer.append("var ").append(getPartVariable(i)).ws().append("=").ws() writer.append("case ").append(i).append(":").indent().softNewLine();
.appendFunction("$rt_guardAsync").append("(function(");
if (i > 0) {
writer.append("$restore");
}
writer.append(")").ws().append("{").indent().softNewLine();
AsyncMethodPart part = methodNode.getBody().get(i); AsyncMethodPart part = methodNode.getBody().get(i);
part.getStatement().acceptVisitor(Renderer.this); part.getStatement().acceptVisitor(Renderer.this);
writer.outdent().append("},").ws().append(getReturnVariable()).append(");").softNewLine(); writer.outdent();
} }
writer.append("return ").append(getPartVariable(0)).append("();").softNewLine(); writer.append("}").softNewLine();
} catch (IOException e) { } catch (IOException e) {
throw new RenderingException("IO error occured", e); throw new RenderingException("IO error occured", e);
} }
@ -823,11 +769,6 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
return asyncFamilyMethods.contains(method); return asyncFamilyMethods.contains(method);
} }
@Override
public String getCompleteContinuation() {
return getReturnVariable();
}
@Override @Override
public Diagnostics getDiagnostics() { public Diagnostics getDiagnostics() {
return diagnostics; return diagnostics;
@ -1097,23 +1038,14 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
pushLocation(statement.getLocation()); pushLocation(statement.getLocation());
} }
writer.append("return"); writer.append("return");
if (async) {
writer.append(' ').append(getReturnVariable()).append("(").appendFunction("$rt_asyncResult")
.append("(");
}
if (statement.getResult() != null) { if (statement.getResult() != null) {
if (!async) { writer.append(' ');
writer.append(' ');
}
prevCallSite = debugEmitter.emitCallSite(); prevCallSite = debugEmitter.emitCallSite();
priority = Priority.COMMA; priority = Priority.COMMA;
associativity = Associativity.NONE; associativity = Associativity.NONE;
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();
@ -1693,43 +1625,33 @@ 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 {
boolean asyncCall = expr.getAsyncTarget() != null;
if (asyncCall) {
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);
} }
MethodReference method = expr.getMethod(); MethodReference method = expr.getMethod();
String name = asyncCall ? naming.getNameForAsync(method.getDescriptor()) : String name = naming.getNameFor(method.getDescriptor());
naming.getNameFor(method.getDescriptor());
DeferredCallSite callSite = prevCallSite; DeferredCallSite callSite = prevCallSite;
boolean shouldEraseCallSite = lastCallSite == null; boolean shouldEraseCallSite = lastCallSite == null;
if (lastCallSite == null) { if (lastCallSite == null) {
lastCallSite = callSite; lastCallSite = callSite;
} }
boolean virtual = false; boolean virtual = false;
boolean hasParams = false;
enterPriority(Priority.COMMA, Associativity.NONE, false); enterPriority(Priority.COMMA, Associativity.NONE, false);
switch (expr.getType()) { switch (expr.getType()) {
case STATIC: case STATIC:
writer.append(asyncCall ? naming.getFullNameForAsync(method) : writer.append(naming.getFullNameFor(method)).append("(");
naming.getFullNameFor(method)).append("(");
prevCallSite = debugEmitter.emitCallSite(); prevCallSite = debugEmitter.emitCallSite();
for (int i = 0; i < expr.getArguments().size(); ++i) { for (int i = 0; i < expr.getArguments().size(); ++i) {
if (i > 0) { if (i > 0) {
writer.append(",").ws(); writer.append(",").ws();
} }
expr.getArguments().get(i).acceptVisitor(this); expr.getArguments().get(i).acceptVisitor(this);
hasParams = true;
} }
break; break;
case SPECIAL: case SPECIAL:
writer.append(asyncCall ? naming.getFullNameForAsync(method) : writer.append(naming.getFullNameFor(method)).append("(");
naming.getFullNameFor(method)).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);
@ -1742,7 +1664,6 @@ 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);
} }
virtual = true; virtual = true;
@ -1754,20 +1675,21 @@ 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);
} }
break; break;
} }
if (expr.getAsyncTarget() != null) {
if (hasParams) {
writer.append(',').ws();
}
writer.appendFunction("$rt_continue").append("(").append(getPartVariable(expr.getAsyncTarget()))
.append(')');
}
writer.append(')'); writer.append(')');
exitPriority(); 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 (lastCallSite != null) {
if (virtual) { if (virtual) {
lastCallSite.setVirtualMethod(expr.getMethod()); lastCallSite.setVirtualMethod(expr.getMethod());
@ -2061,11 +1983,8 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext
if (async) { if (async) {
MethodReference monitorEnterRef = new MethodReference( MethodReference monitorEnterRef = new MethodReference(
Object.class, "monitorEnter", Object.class, void.class); Object.class, "monitorEnter", Object.class, void.class);
writer.append("return ").append(naming.getFullNameForAsync(monitorEnterRef)).append("("); writer.appendMethodBody(monitorEnterRef).append("(");
statement.getObjectRef().acceptVisitor(this); statement.getObjectRef().acceptVisitor(this);
writer.append(",").ws();
writer.appendFunction("$rt_continue").append("(").append(getPartVariable(statement.getAsyncTarget()))
.append(')');
writer.append(");").softNewLine(); writer.append(");").softNewLine();
} else { } else {
MethodReference monitorEnterRef = new MethodReference( MethodReference monitorEnterRef = new MethodReference(

View File

@ -36,8 +36,6 @@ public interface GeneratorContext extends ServiceRepository {
boolean isAsync(); boolean isAsync();
String getCompleteContinuation();
boolean isAsync(MethodReference method); boolean isAsync(MethodReference method);
boolean isAsyncFamily(MethodReference method); boolean isAsyncFamily(MethodReference method);

View File

@ -437,13 +437,7 @@ public class TeaVM implements TeaVMHost, ServiceRepository {
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();
MethodReference ref = entry.getValue().reference; MethodReference ref = entry.getValue().reference;
boolean asyncMethod = asyncMethods.contains(ref); sourceWriter.append(naming.getFullNameFor(ref));
boolean wrapAsync = !asyncMethod && entry.getValue().isAsync();
if (wrapAsync) {
sourceWriter.append("$rt_staticAsyncAdapter(").appendMethodBody(ref).append(')');
} else {
sourceWriter.append(asyncMethod ? naming.getFullNameForAsync(ref) : naming.getFullNameFor(ref));
}
sourceWriter.append(";").newLine(); sourceWriter.append(";").newLine();
} }
for (Map.Entry<String, String> entry : exportedClasses.entrySet()) { for (Map.Entry<String, String> entry : exportedClasses.entrySet()) {

View File

@ -517,6 +517,57 @@ function $rt_guardAsync(f, continuation) {
} }
} }
} }
function TeaVMThread(runner) {
this.status = 3;
this.stack = [];
this.suspendCallback = null;
this.runner = runner;
}
TeaVMThread.push = function(value) {
this.stack.push[value];
}
TeaVMThread.isResuming = function() {
return this.status == 1;
}
TeaVMThread.isSuspending = function() {
return this.status == 2;
}
TeaVMThread.suspend(callback) {
this.suspendCallback = callback;
this.status = 1;
}
TeaVMThread.start = function() {
if (this.status != 3) {
throw new Error("Thread already started");
}
this.status = 0;
this.run();
}
TeaVMThread.resume = function() {
this.status = 2;
this.run();
}
TeaVMThread.run = function() {
this.runner();
if (this.suspendCallback !== null) {
var self = this;
this.suspendCallback(function() {
self.resume();
});
}
}
function $rt_nativeThread(thread) {
if (!thread.hasNativeProperty("$teavm_thread")) {
thread.$teavm_thread = new TeaVMThread();
}
}
function $rt_suspending() {
return $rt_nativeThread($rt_getThread()).isSuspending();
}
function $rt_resuming() {
return $rt_nativeThread($rt_getThread()).isResuming();
}
function TeaVMAsyncError(cause) { function TeaVMAsyncError(cause) {
this.message = "Async error occured"; this.message = "Async error occured";
this.cause = cause; this.cause = cause;