From 93e43456d1e48399b515d083cde40a7f3a49fb99 Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Tue, 10 Mar 2015 12:49:00 +0400 Subject: [PATCH] Outline of upcoming improvements of continuations --- .../org/teavm/classlib/java/lang/TObject.java | 46 +++-- .../org/teavm/classlib/java/lang/TThread.java | 40 ++-- .../teavm/codegen/DefaultNamingStrategy.java | 14 +- .../teavm/codegen/NameFrequencyConsumer.java | 4 - .../java/org/teavm/codegen/NamingOrderer.java | 31 ---- .../org/teavm/codegen/NamingStrategy.java | 4 - .../javascript/NameFrequencyEstimator.java | 53 +----- .../java/org/teavm/javascript/Renderer.java | 171 +++++------------- .../javascript/spi/GeneratorContext.java | 2 - .../src/main/java/org/teavm/vm/TeaVM.java | 8 +- .../resources/org/teavm/javascript/runtime.js | 51 ++++++ 11 files changed, 164 insertions(+), 260 deletions(-) diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TObject.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TObject.java index 65776b5b8..3fb6b2e9a 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TObject.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TObject.java @@ -72,10 +72,7 @@ public class TObject { monitorEnter(o, 1); } - @Async - static native void monitorEnter(TObject o, int count); - - static void monitorEnter(final TObject o, final int count, final AsyncCallback callback) { + static void monitorEnter(TObject o, int count) { if (o.monitor == null) { o.monitor = new Monitor(); } @@ -83,21 +80,27 @@ public class TObject { o.monitor.owner = TThread.currentThread(); } if (o.monitor.owner != TThread.currentThread()) { - 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); - } - }); + monitorEnterWait(o, count); } else { 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 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 static void monitorExit(final TObject o) { monitorExit(o, 1); @@ -230,15 +233,18 @@ public class TObject { } } - @Async @Rename("wait") - private native final void wait0(long timeout, int nanos) throws TInterruptedException; - - @Rename("wait") - public final void wait0(long timeout, int nanos, final AsyncCallback callback) { + private final void wait0(long timeout, int nanos) throws TInterruptedException { if (!holdsLock(this)) { 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 callback) { final NotifyListenerImpl listener = new NotifyListenerImpl(this, callback, monitor.count); monitor.notifyListeners.add(listener); if (timeout > 0 || nanos > 0) { @@ -288,7 +294,7 @@ public class TObject { timerId = -1; } TThread.setCurrentThread(currentThread); - monitorEnter(obj, lockCount, callback); + monitorEnterWait(obj, lockCount, callback); } } diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TThread.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TThread.java index f50841b41..2576f0653 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TThread.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TThread.java @@ -23,7 +23,6 @@ import org.teavm.platform.Platform; import org.teavm.platform.PlatformRunnable; import org.teavm.platform.async.AsyncCallback; - /** * * @author Alexey Andreev @@ -36,6 +35,7 @@ public class TThread extends TObject implements TRunnable { private static int activeCount = 1; private long id; private int priority = 0; + private long timeSliceStart; private TString name; TRunnable target; @@ -55,10 +55,10 @@ public class TThread extends TObject implements TRunnable { public TThread(TRunnable target, TString name ) { this.name = name; this.target = target; - id=nextId++; + id = nextId++; } - public void start(){ + public void start() { Platform.startThread(new PlatformRunnable() { @Override public void run() { @@ -74,8 +74,11 @@ public class TThread extends TObject implements TRunnable { }); } - static void setCurrentThread(TThread thread){ - currentThread = thread; + static void setCurrentThread(TThread thread) { + if (currentThread != thread) { + currentThread = thread; + currentThread.timeSliceStart = System.currentTimeMillis(); + } } static TThread getMainThread(){ return mainThread; @@ -96,11 +99,26 @@ public class TThread extends TObject implements TRunnable { return name; } - @Async - public static native void yield(); + public static void yield() { + if (currentThread.timeSliceStart + 100 < System.currentTimeMillis()) { + switchContext(); + } + } - private static void yield(final AsyncCallback callback) { - callback.complete(null); + @Async + static native void switchContext(); + + private static void switchContext(final AsyncCallback 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() { @@ -138,11 +156,11 @@ public class TThread extends TObject implements TRunnable { } }, millis); } - + public final void setPriority(int newPriority){ this.priority = newPriority; } - + public final int getPriority(){ return this.priority; } diff --git a/teavm-core/src/main/java/org/teavm/codegen/DefaultNamingStrategy.java b/teavm-core/src/main/java/org/teavm/codegen/DefaultNamingStrategy.java index 0a28824b0..7fdd95a22 100644 --- a/teavm-core/src/main/java/org/teavm/codegen/DefaultNamingStrategy.java +++ b/teavm-core/src/main/java/org/teavm/codegen/DefaultNamingStrategy.java @@ -58,12 +58,7 @@ public class DefaultNamingStrategy implements NamingStrategy { @Override public String getNameFor(MethodDescriptor method) { - return getNameFor(method, 'S'); - } - - @Override - public String getNameForAsync(MethodDescriptor method) throws NamingException { - return getNameFor(method, 'A'); + return getNameFor(method, 'M'); } private String getNameFor(MethodDescriptor method, char classifier) { @@ -78,12 +73,7 @@ public class DefaultNamingStrategy implements NamingStrategy { @Override public String getFullNameFor(MethodReference method) throws NamingException { - return getFullNameFor(method, 'S'); - } - - @Override - public String getFullNameForAsync(MethodReference method) throws NamingException { - return getFullNameFor(method, 'A'); + return getFullNameFor(method, 'M'); } @Override diff --git a/teavm-core/src/main/java/org/teavm/codegen/NameFrequencyConsumer.java b/teavm-core/src/main/java/org/teavm/codegen/NameFrequencyConsumer.java index 20aec0331..558e2eab8 100644 --- a/teavm-core/src/main/java/org/teavm/codegen/NameFrequencyConsumer.java +++ b/teavm-core/src/main/java/org/teavm/codegen/NameFrequencyConsumer.java @@ -26,14 +26,10 @@ import org.teavm.model.MethodReference; public interface NameFrequencyConsumer { void consume(MethodReference method); - void consumeAsync(MethodReference method); - void consumeInit(MethodReference method); void consume(MethodDescriptor method); - void consumeAsync(MethodDescriptor method); - void consume(String className); void consume(FieldReference field); diff --git a/teavm-core/src/main/java/org/teavm/codegen/NamingOrderer.java b/teavm-core/src/main/java/org/teavm/codegen/NamingOrderer.java index 8cfc4399d..72cf2f652 100644 --- a/teavm-core/src/main/java/org/teavm/codegen/NamingOrderer.java +++ b/teavm-core/src/main/java/org/teavm/codegen/NamingOrderer.java @@ -43,21 +43,6 @@ public class NamingOrderer implements NameFrequencyConsumer { 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 public void consumeInit(final MethodReference method) { @@ -91,22 +76,6 @@ public class NamingOrderer implements NameFrequencyConsumer { 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 public void consume(final String className) { String key = "c:" + className; diff --git a/teavm-core/src/main/java/org/teavm/codegen/NamingStrategy.java b/teavm-core/src/main/java/org/teavm/codegen/NamingStrategy.java index 0902b5093..9873446af 100644 --- a/teavm-core/src/main/java/org/teavm/codegen/NamingStrategy.java +++ b/teavm-core/src/main/java/org/teavm/codegen/NamingStrategy.java @@ -28,14 +28,10 @@ public interface NamingStrategy { String getNameFor(MethodDescriptor method) throws NamingException; - String getNameForAsync(MethodDescriptor method) throws NamingException; - String getNameForInit(MethodReference method) throws NamingException; String getFullNameFor(MethodReference method) throws NamingException; - String getFullNameForAsync(MethodReference method) throws NamingException; - String getNameFor(FieldReference field) throws NamingException; String getNameForFunction(String name) throws NamingException; diff --git a/teavm-core/src/main/java/org/teavm/javascript/NameFrequencyEstimator.java b/teavm-core/src/main/java/org/teavm/javascript/NameFrequencyEstimator.java index 61d639cde..278e9e642 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/NameFrequencyEstimator.java +++ b/teavm-core/src/main/java/org/teavm/javascript/NameFrequencyEstimator.java @@ -63,38 +63,17 @@ public class NameFrequencyEstimator implements StatementVisitor, ExprVisitor, Me MethodReader clinit = classSource.get(cls.getName()).getMethod( new MethodDescriptor("", ValueType.VOID)); for (MethodNode method : cls.getMethods()) { - if (method.isAsync()) { - consumer.consumeAsync(method.getReference()); - } else { + consumer.consume(method.getReference()); + if (asyncFamilyMethods.contains(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) || - method.getReference().getName().equals(""))) { - if (!method.isAsync()) { - consumer.consume(method.getReference()); - } - if (asyncFamilyMethods.contains(method.getReference())) { - consumer.consumeAsync(method.getReference()); - } + method.getReference().getName().equals(""))) { + consumer.consume(method.getReference()); } if (!method.getModifiers().contains(NodeModifier.STATIC)) { - if (method.isAsync()) { - consumer.consumeAsync(method.getReference().getDescriptor()); - 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()); - } - } + consumer.consume(method.getReference().getDescriptor()); + consumer.consume(method.getReference()); } } @@ -217,7 +196,7 @@ public class NameFrequencyEstimator implements StatementVisitor, ExprVisitor, Me if (async) { MethodReference monitorEnterRef = new MethodReference( Object.class, "monitorEnter", Object.class, void.class); - consumer.consumeAsync(monitorEnterRef); + consumer.consume(monitorEnterRef); } else { MethodReference monitorEnterRef = new MethodReference( Object.class, "monitorEnterSync", Object.class, void.class); @@ -230,7 +209,7 @@ public class NameFrequencyEstimator implements StatementVisitor, ExprVisitor, Me if (async) { MethodReference monitorEnterRef = new MethodReference( Object.class, "monitorExit", Object.class, void.class); - consumer.consumeAsync(monitorEnterRef); + consumer.consume(monitorEnterRef); } else { MethodReference monitorEnterRef = new MethodReference( Object.class, "monitorExitSync", Object.class, void.class); @@ -308,30 +287,18 @@ public class NameFrequencyEstimator implements StatementVisitor, ExprVisitor, Me if (injectedMethods.contains(expr.getMethod())) { return; } - boolean asyncCall = expr.getAsyncTarget() != null; switch (expr.getType()) { case SPECIAL: case STATIC: - if (asyncCall) { - consumer.consumeAsync(expr.getMethod()); - } else { - consumer.consume(expr.getMethod()); - } + consumer.consume(expr.getMethod()); break; case CONSTRUCTOR: consumer.consumeInit(expr.getMethod()); break; case DYNAMIC: - if (asyncCall) { - consumer.consumeAsync(expr.getMethod().getDescriptor()); - } else { - consumer.consume(expr.getMethod().getDescriptor()); - } + consumer.consume(expr.getMethod().getDescriptor()); break; } - if (asyncCall) { - consumer.consumeFunction("$rt_continue"); - } } @Override diff --git a/teavm-core/src/main/java/org/teavm/javascript/Renderer.java b/teavm-core/src/main/java/org/teavm/javascript/Renderer.java index d158d1dd3..92f95159d 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/Renderer.java +++ b/teavm-core/src/main/java/org/teavm/javascript/Renderer.java @@ -452,12 +452,7 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext for (MethodNode method : cls.getMethods()) { if (clinit != null && (method.getModifiers().contains(NodeModifier.STATIC) || method.getReference().getName().equals(""))) { - if (!method.isAsync()) { - stubNames.add(naming.getFullNameFor(method.getReference())); - } - if (asyncFamilyMethods.contains(method.getReference())) { - stubNames.add(naming.getFullNameForAsync(method.getReference())); - } + stubNames.add(naming.getFullNameFor(method.getReference())); } if (!method.getModifiers().contains(NodeModifier.STATIC)) { virtualMethods.add(method); @@ -546,32 +541,20 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext writer.append(",").ws(); } first = false; - if (method.isAsync()) { - emitVirtualDeclaration(ref, true); - } else { - emitVirtualDeclaration(ref, false); - if (asyncFamilyMethods.contains(ref)) { - writer.append(",").ws(); - emitVirtualDeclaration(ref, true); - } - } + emitVirtualDeclaration(ref); debugEmitter.emitMethod(null); } writer.append("]"); } - private void emitVirtualDeclaration(MethodReference ref, boolean async) throws IOException { - String methodName = async ? naming.getNameForAsync(ref.getDescriptor()) : - naming.getNameFor(ref.getDescriptor()); + private void emitVirtualDeclaration(MethodReference ref) throws IOException { + String methodName = naming.getNameFor(ref.getDescriptor()); writer.append("\"").append(methodName).append("\""); writer.append(",").ws().append("function("); List args = new ArrayList<>(); for (int i = 1; i <= ref.parameterCount(); ++i) { args.add(variableName(i)); } - if (async) { - args.add(getReturnVariable()); - } for (int i = 0; i < args.size(); ++i) { if (i > 0) { writer.append(",").ws(); @@ -582,7 +565,7 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext if (ref.getDescriptor().getResultType() != ValueType.VOID) { writer.append("return "); } - writer.append(async ? naming.getFullNameForAsync(ref) : naming.getFullNameFor(ref)).append("("); + writer.appendMethodBody(ref).append("("); writer.append("this"); for (int i = 0; i < args.size(); ++i) { writer.append(",").ws().append(args.get(i)); @@ -590,23 +573,11 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext 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 { blockIdMap.clear(); MethodReference ref = method.getReference(); debugEmitter.emitMethod(ref.getDescriptor()); - String name = method.isAsync() ? naming.getFullNameForAsync(ref) : naming.getFullNameFor(ref); + String name = naming.getFullNameFor(ref); if (inner) { writer.append(name).ws().append("=").ws().append("function("); } else { @@ -622,12 +593,6 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext } writer.append(variableName(i)); } - if (method.isAsync()) { - if (startParam < ref.parameterCount() + 1) { - writer.append(',').ws(); - } - writer.append(getReturnVariable()); - } writer.append(")").ws().append("{").softNewLine().indent(); method.acceptVisitor(new MethodBodyRenderer()); writer.outdent().append("}"); @@ -635,42 +600,6 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext writer.append(';'); } 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); } @@ -756,6 +685,7 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext if (hasTryCatch) { variableNames.add("$je"); } + variableNames.add("$ptr"); if (!variableNames.isEmpty()) { writer.append("var "); for (int i = 0; i < variableNames.size(); ++i) { @@ -766,18 +696,34 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext } 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) { - writer.append("var ").append(getPartVariable(i)).ws().append("=").ws() - .appendFunction("$rt_guardAsync").append("(function("); - if (i > 0) { - writer.append("$restore"); - } - writer.append(")").ws().append("{").indent().softNewLine(); + writer.append("case ").append(i).append(":").indent().softNewLine(); AsyncMethodPart part = methodNode.getBody().get(i); 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) { throw new RenderingException("IO error occured", e); } @@ -823,11 +769,6 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext return asyncFamilyMethods.contains(method); } - @Override - public String getCompleteContinuation() { - return getReturnVariable(); - } - @Override public Diagnostics getDiagnostics() { return diagnostics; @@ -1097,23 +1038,14 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext pushLocation(statement.getLocation()); } writer.append("return"); - if (async) { - writer.append(' ').append(getReturnVariable()).append("(").appendFunction("$rt_asyncResult") - .append("("); - } if (statement.getResult() != null) { - if (!async) { - writer.append(' '); - } + writer.append(' '); prevCallSite = debugEmitter.emitCallSite(); priority = Priority.COMMA; associativity = Associativity.NONE; statement.getResult().acceptVisitor(this); debugEmitter.emitCallSite(); } - if (async) { - writer.append("))"); - } writer.append(";").softNewLine(); if (statement.getLocation() != null) { popLocation(); @@ -1693,43 +1625,33 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext if (injector != null) { injector.generate(new InjectorContextImpl(expr.getArguments()), expr.getMethod()); } else { - boolean asyncCall = expr.getAsyncTarget() != null; - if (asyncCall) { - writer.append("return "); - } if (expr.getType() == InvocationType.DYNAMIC) { expr.getArguments().get(0).acceptVisitor(this); } MethodReference method = expr.getMethod(); - String name = asyncCall ? naming.getNameForAsync(method.getDescriptor()) : - naming.getNameFor(method.getDescriptor()); + String name = naming.getNameFor(method.getDescriptor()); DeferredCallSite callSite = prevCallSite; boolean shouldEraseCallSite = lastCallSite == null; if (lastCallSite == null) { lastCallSite = callSite; } boolean virtual = false; - boolean hasParams = false; enterPriority(Priority.COMMA, Associativity.NONE, false); switch (expr.getType()) { case STATIC: - writer.append(asyncCall ? naming.getFullNameForAsync(method) : - naming.getFullNameFor(method)).append("("); + writer.append(naming.getFullNameFor(method)).append("("); prevCallSite = debugEmitter.emitCallSite(); for (int i = 0; i < expr.getArguments().size(); ++i) { if (i > 0) { writer.append(",").ws(); } expr.getArguments().get(i).acceptVisitor(this); - hasParams = true; } break; case SPECIAL: - writer.append(asyncCall ? naming.getFullNameForAsync(method) : - naming.getFullNameFor(method)).append("("); + writer.append(naming.getFullNameFor(method)).append("("); prevCallSite = debugEmitter.emitCallSite(); expr.getArguments().get(0).acceptVisitor(this); - hasParams = true; for (int i = 1; i < expr.getArguments().size(); ++i) { writer.append(",").ws(); expr.getArguments().get(i).acceptVisitor(this); @@ -1742,7 +1664,6 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext if (i > 1) { writer.append(",").ws(); } - hasParams = true; expr.getArguments().get(i).acceptVisitor(this); } virtual = true; @@ -1754,20 +1675,21 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext if (i > 0) { writer.append(",").ws(); } - hasParams = true; expr.getArguments().get(i).acceptVisitor(this); } break; } - if (expr.getAsyncTarget() != null) { - if (hasParams) { - writer.append(',').ws(); - } - writer.appendFunction("$rt_continue").append("(").append(getPartVariable(expr.getAsyncTarget())) - .append(')'); - } 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()); @@ -2061,11 +1983,8 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext if (async) { MethodReference monitorEnterRef = new MethodReference( Object.class, "monitorEnter", Object.class, void.class); - writer.append("return ").append(naming.getFullNameForAsync(monitorEnterRef)).append("("); + writer.appendMethodBody(monitorEnterRef).append("("); statement.getObjectRef().acceptVisitor(this); - writer.append(",").ws(); - writer.appendFunction("$rt_continue").append("(").append(getPartVariable(statement.getAsyncTarget())) - .append(')'); writer.append(");").softNewLine(); } else { MethodReference monitorEnterRef = new MethodReference( diff --git a/teavm-core/src/main/java/org/teavm/javascript/spi/GeneratorContext.java b/teavm-core/src/main/java/org/teavm/javascript/spi/GeneratorContext.java index b2c97a8e9..90d1ff82f 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/spi/GeneratorContext.java +++ b/teavm-core/src/main/java/org/teavm/javascript/spi/GeneratorContext.java @@ -36,8 +36,6 @@ public interface GeneratorContext extends ServiceRepository { boolean isAsync(); - String getCompleteContinuation(); - boolean isAsync(MethodReference method); boolean isAsyncFamily(MethodReference method); diff --git a/teavm-core/src/main/java/org/teavm/vm/TeaVM.java b/teavm-core/src/main/java/org/teavm/vm/TeaVM.java index f459e4a46..4f0d4d107 100644 --- a/teavm-core/src/main/java/org/teavm/vm/TeaVM.java +++ b/teavm-core/src/main/java/org/teavm/vm/TeaVM.java @@ -437,13 +437,7 @@ public class TeaVM implements TeaVMHost, ServiceRepository { for (Map.Entry entry : entryPoints.entrySet()) { sourceWriter.append("var ").append(entry.getKey()).ws().append("=").ws(); MethodReference ref = entry.getValue().reference; - boolean asyncMethod = asyncMethods.contains(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(naming.getFullNameFor(ref)); sourceWriter.append(";").newLine(); } for (Map.Entry entry : exportedClasses.entrySet()) { diff --git a/teavm-core/src/main/resources/org/teavm/javascript/runtime.js b/teavm-core/src/main/resources/org/teavm/javascript/runtime.js index 88d9ddef4..ee02d37ed 100644 --- a/teavm-core/src/main/resources/org/teavm/javascript/runtime.js +++ b/teavm-core/src/main/resources/org/teavm/javascript/runtime.js @@ -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) { this.message = "Async error occured"; this.cause = cause;