From 8fe3876641af13ee6c24d0009c8b32aba8fff907 Mon Sep 17 00:00:00 2001 From: konsoletyper Date: Tue, 10 Mar 2015 22:09:43 +0300 Subject: [PATCH] First working prototype of new async --- .../org/teavm/classlib/java/lang/TObject.java | 17 ++++++++++++----- .../org/teavm/classlib/java/lang/TThread.java | 18 +++++++----------- .../java/org/teavm/javascript/Decompiler.java | 11 +++++++---- .../java/org/teavm/javascript/Renderer.java | 3 ++- .../resources/org/teavm/javascript/runtime.js | 12 +++++++----- .../main/java/org/teavm/platform/Platform.java | 6 +++++- .../platform/plugin/AsyncMethodGenerator.java | 1 + .../platform/plugin/PlatformGenerator.java | 6 +++++- 8 files changed, 46 insertions(+), 28 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 376c007ea..827b0267d 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 @@ -91,6 +91,13 @@ public class TObject { static void monitorEnterWait(final TObject o, final int count, final AsyncCallback callback) { final TThread thread = TThread.currentThread(); + if (o.monitor == null) { + o.monitor = new Monitor(); + TThread.setCurrentThread(thread); + o.monitor.count += count; + callback.complete(null); + return; + } o.monitor.enteringThreads.add(new PlatformRunnable() { @Override public void run() { TThread.setCurrentThread(thread); @@ -118,7 +125,7 @@ public class TObject { o.monitor.owner = null; if (!o.monitor.enteringThreads.isEmpty()) { - Platform.startThread(new PlatformRunnable() { + Platform.postpone(new PlatformRunnable() { @Override public void run() { if (o.isEmptyMonitor() || o.monitor.owner != null) { return; @@ -127,7 +134,7 @@ public class TObject { o.monitor.enteringThreads.remove().run(); } } - }, false); + }); } else { o.isEmptyMonitor(); } @@ -203,7 +210,7 @@ public class TObject { while (!listeners.isEmpty()) { NotifyListener listener = listeners.remove(); if (!listener.expired()) { - Platform.startThread(listener, false); + Platform.postpone(listener); break; } } @@ -219,7 +226,7 @@ public class TObject { while (!listeners.isEmpty()) { NotifyListener listener = listeners.remove(); if (!listener.expired()) { - Platform.startThread(listener, false); + Platform.postpone(listener); } } } @@ -279,7 +286,7 @@ public class TObject { @Override public void onTimer() { if (!expired()) { - Platform.startThread(this, false); + Platform.postpone(this); } } 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 416a5be0d..855382fa4 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 @@ -71,14 +71,14 @@ public class TThread extends TObject implements TRunnable { setCurrentThread(mainThread); } } - }, true); + }); } static void setCurrentThread(TThread thread) { if (currentThread != thread) { currentThread = thread; - currentThread.timeSliceStart = System.currentTimeMillis(); } + currentThread.timeSliceStart = System.currentTimeMillis(); } static TThread getMainThread(){ @@ -102,24 +102,20 @@ public class TThread extends TObject implements TRunnable { public static void yield() { if (currentThread.timeSliceStart + 100 < System.currentTimeMillis()) { - switchContext(); + switchContext(currentThread); } } @Async - static native void switchContext(); + static native void switchContext(TThread thread); - private static void switchContext(final AsyncCallback callback) { - final TThread thread = currentThread(); - Platform.startThread(new PlatformRunnable() { + private static void switchContext(final TThread thread, final AsyncCallback callback) { + Platform.postpone(new PlatformRunnable() { @Override public void run() { setCurrentThread(thread); callback.complete(null); } - }, false); - } - - private static void yieldImpl() { + }); } public void interrupt() { diff --git a/teavm-core/src/main/java/org/teavm/javascript/Decompiler.java b/teavm-core/src/main/java/org/teavm/javascript/Decompiler.java index 40ad05685..7e09ab256 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/Decompiler.java +++ b/teavm-core/src/main/java/org/teavm/javascript/Decompiler.java @@ -204,7 +204,8 @@ public class Decompiler { AsyncProgramSplitter splitter = new AsyncProgramSplitter(classSource, splitMethods); splitter.split(method.getProgram()); for (int i = 0; i < splitter.size(); ++i) { - AsyncMethodPart part = getRegularMethodStatement(splitter.getProgram(i), splitter.getBlockSuccessors(i)); + AsyncMethodPart part = getRegularMethodStatement(splitter.getProgram(i), splitter.getBlockSuccessors(i), + i > 0); node.getBody().add(part); } Program program = method.getProgram(); @@ -227,7 +228,7 @@ public class Decompiler { Program program = method.getProgram(); int[] targetBlocks = new int[program.basicBlockCount()]; Arrays.fill(targetBlocks, -1); - methodNode.setBody(getRegularMethodStatement(program, targetBlocks).getStatement()); + methodNode.setBody(getRegularMethodStatement(program, targetBlocks, false).getStatement()); for (int i = 0; i < program.variableCount(); ++i) { methodNode.getVariables().add(program.variableAt(i).getRegister()); } @@ -242,7 +243,7 @@ public class Decompiler { return methodNode; } - private AsyncMethodPart getRegularMethodStatement(Program program, int[] targetBlocks) { + private AsyncMethodPart getRegularMethodStatement(Program program, int[] targetBlocks, boolean async) { AsyncMethodPart result = new AsyncMethodPart(); lastBlockId = 1; graph = ProgramUtils.buildControlFlowGraph(program); @@ -290,6 +291,7 @@ public class Decompiler { if (head != -1 && loopSuccessors[head] == next) { next = head; } + boolean saved = !async; if (node >= 0) { generator.currentBlock = program.basicBlockAt(node); int tmp = indexer.nodeAt(next); @@ -308,8 +310,9 @@ public class Decompiler { generator.setCurrentLocation(nodeLocation); } insn.acceptVisitor(generator); - if (j == 0 && insn instanceof InvokeInstruction) { + if (insn instanceof InvokeInstruction && !saved) { generator.statements.add(new SaveStatement()); + saved = true; } } if (targetBlocks[node] >= 0) { 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 f5faaeeb3..1f3acc218 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/Renderer.java +++ b/teavm-core/src/main/java/org/teavm/javascript/Renderer.java @@ -711,7 +711,7 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext 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("T.pop();"); + writer.append(variableName(i)).ws().append('=').ws().append("$T.pop();"); } writer.softNewLine(); writer.outdent().append("}").softNewLine(); @@ -724,6 +724,7 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext part.getStatement().acceptVisitor(Renderer.this); writer.outdent(); } + writer.append("default:").ws().append("throw new Error('Invalid recorded state');").softNewLine(); writer.append("}").softNewLine(); writer.outdent().append("}").softNewLine(); } catch (IOException e) { 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 f004f7b26..d6063734c 100644 --- a/teavm-core/src/main/resources/org/teavm/javascript/runtime.js +++ b/teavm-core/src/main/resources/org/teavm/javascript/runtime.js @@ -444,17 +444,17 @@ function TeaVMThread(runner) { this.attribute = null; } TeaVMThread.prototype.push = function(value) { - this.stack.push[value]; + this.stack.push(value); return this; } TeaVMThread.prototype.pop = function() { return this.stack.pop(); } TeaVMThread.prototype.isResuming = function() { - return this.status == 1; + return this.status == 2; } TeaVMThread.prototype.isSuspending = function() { - return this.status == 2; + return this.status == 1; } TeaVMThread.prototype.suspend = function(callback) { this.suspendCallback = callback; @@ -489,10 +489,12 @@ TeaVMThread.prototype.run = function() { } } function $rt_suspending() { - return $rt_nativeThread().isSuspending(); + var thread = $rt_nativeThread(); + return thread != null && thread.isSuspending(); } function $rt_resuming() { - return $rt_nativeThread().isResuming(); + var thread = $rt_nativeThread(); + return thread != null && thread.isResuming(); } function $rt_suspend(callback) { return $rt_nativeThread().suspend(callback); diff --git a/teavm-platform/src/main/java/org/teavm/platform/Platform.java b/teavm-platform/src/main/java/org/teavm/platform/Platform.java index 749b9d0b5..9b8739652 100644 --- a/teavm-platform/src/main/java/org/teavm/platform/Platform.java +++ b/teavm-platform/src/main/java/org/teavm/platform/Platform.java @@ -107,12 +107,16 @@ public final class Platform { @GeneratedBy(PlatformGenerator.class) @PluggableDependency(PlatformGenerator.class) - public static native void startThread(PlatformRunnable runnable, boolean newNativeThread); + public static native void startThread(PlatformRunnable runnable); private static void launchThread(PlatformRunnable runnable) { runnable.run(); } + public static void postpone(PlatformRunnable runnable) { + schedule(runnable, 0); + } + @GeneratedBy(PlatformGenerator.class) @PluggableDependency(PlatformGenerator.class) public static native int schedule(PlatformRunnable runnable, int timeout); diff --git a/teavm-platform/src/main/java/org/teavm/platform/plugin/AsyncMethodGenerator.java b/teavm-platform/src/main/java/org/teavm/platform/plugin/AsyncMethodGenerator.java index fb2c30487..f3a417540 100644 --- a/teavm-platform/src/main/java/org/teavm/platform/plugin/AsyncMethodGenerator.java +++ b/teavm-platform/src/main/java/org/teavm/platform/plugin/AsyncMethodGenerator.java @@ -40,6 +40,7 @@ public class AsyncMethodGenerator implements Generator, DependencyPlugin { 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("thread.status").ws().append("=").ws().append("0;").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(); diff --git a/teavm-platform/src/main/java/org/teavm/platform/plugin/PlatformGenerator.java b/teavm-platform/src/main/java/org/teavm/platform/plugin/PlatformGenerator.java index bc05a14f2..92c0435d5 100644 --- a/teavm-platform/src/main/java/org/teavm/platform/plugin/PlatformGenerator.java +++ b/teavm-platform/src/main/java/org/teavm/platform/plugin/PlatformGenerator.java @@ -153,7 +153,11 @@ 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(); - writer.append("$rt_threadStarter(").appendMethodBody(launchRef).append(")"); + if (timeout) { + writer.appendMethodBody(launchRef); + } else { + 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();