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 affd53dd4..477eccc0f 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/Decompiler.java +++ b/teavm-core/src/main/java/org/teavm/javascript/Decompiler.java @@ -202,7 +202,6 @@ public class Decompiler { AsyncMethodNode node = new AsyncMethodNode(method.getReference()); AsyncProgramSplitter splitter = new AsyncProgramSplitter(asyncMethods); splitter.split(method.getProgram()); - List partPrograms = new ArrayList<>(); for (int i = 0; i < splitter.size(); ++i) { Integer input = null; if (i > 0) { @@ -214,14 +213,13 @@ public class Decompiler { AsyncMethodPart part = getRegularMethodStatement(splitter.getProgram(i), splitter.getBlockSuccessors(i), input); node.getBody().add(part); - partPrograms.add(splitter.getProgram(i)); } Program program = method.getProgram(); for (int i = 0; i < program.variableCount(); ++i) { node.getVariables().add(program.variableAt(i).getRegister()); } Optimizer optimizer = new Optimizer(); - optimizer.optimize(node, partPrograms); + optimizer.optimize(node, program, splitter); node.getModifiers().addAll(mapModifiers(method.getModifiers())); int paramCount = Math.min(method.getSignature().length, program.variableCount()); for (int i = 0; i < paramCount; ++i) { diff --git a/teavm-core/src/main/java/org/teavm/javascript/Optimizer.java b/teavm-core/src/main/java/org/teavm/javascript/Optimizer.java index 9e0d53395..f69803a48 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/Optimizer.java +++ b/teavm-core/src/main/java/org/teavm/javascript/Optimizer.java @@ -15,12 +15,11 @@ */ package org.teavm.javascript; -import java.util.List; 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; /** * @@ -44,13 +43,17 @@ public class Optimizer { } } - public void optimize(AsyncMethodNode method, List programs) { + public void optimize(AsyncMethodNode method, Program program, AsyncProgramSplitter splitter) { ReadWriteStatsBuilder stats = new ReadWriteStatsBuilder(method.getVariables().size()); - for (Program program : programs) { - stats.analyze(program); + stats.analyze(program); + for (int i = 0; i < splitter.size(); ++i) { + Integer var = splitter.getInput(i); + if (var != null) { + stats.reads[var]++; + } } - OptimizingVisitor optimizer = new OptimizingVisitor(stats); for (AsyncMethodPart part : method.getBody()) { + OptimizingVisitor optimizer = new OptimizingVisitor(stats.copy()); part.getStatement().acceptVisitor(optimizer); part.setStatement(optimizer.resultStmt); } diff --git a/teavm-core/src/main/java/org/teavm/javascript/ReadWriteStatsBuilder.java b/teavm-core/src/main/java/org/teavm/javascript/ReadWriteStatsBuilder.java index 9be54242a..0e39dd41c 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/ReadWriteStatsBuilder.java +++ b/teavm-core/src/main/java/org/teavm/javascript/ReadWriteStatsBuilder.java @@ -15,6 +15,7 @@ */ package org.teavm.javascript; +import java.util.Arrays; import org.teavm.model.*; import org.teavm.model.util.DefinitionExtractor; import org.teavm.model.util.UsageExtractor; @@ -27,11 +28,21 @@ class ReadWriteStatsBuilder { public int[] reads; public int[] writes; + private ReadWriteStatsBuilder() { + } + public ReadWriteStatsBuilder(int variableCount) { reads = new int[variableCount]; writes = new int[variableCount]; } + public ReadWriteStatsBuilder copy() { + ReadWriteStatsBuilder result = new ReadWriteStatsBuilder(); + result.reads = Arrays.copyOf(reads, reads.length); + result.writes = Arrays.copyOf(writes, writes.length); + return result; + } + public void analyze(Program program) { DefinitionExtractor defExtractor = new DefinitionExtractor(); UsageExtractor useExtractor = new UsageExtractor(); 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 545a26032..4d0dc05df 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/Renderer.java +++ b/teavm-core/src/main/java/org/teavm/javascript/Renderer.java @@ -533,7 +533,11 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext } writer.append(")").ws().append("{").softNewLine().indent(); method.acceptVisitor(new MethodBodyRenderer()); - writer.outdent().append("}").newLine(); + writer.outdent().append("}"); + if (inner) { + writer.append(';'); + } + writer.newLine(); debugEmitter.emitMethod(null); } @@ -630,18 +634,15 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext writer.append(";").softNewLine(); } for (int i = 0; i < methodNode.getBody().size(); ++i) { - writer.append("function $part_").append(i).append("("); + writer.append("var $part_").append(i).ws().append("=").ws().append("$rt_guardAsync(function("); if (i > 0) { writer.append("$restore"); } - writer.append(")").ws().append('{').indent().softNewLine(); - writer.append("try {").indent().softNewLine(); + writer.append(")").ws().append("{").indent().softNewLine(); AsyncMethodPart part = methodNode.getBody().get(i); part.getStatement().acceptVisitor(Renderer.this); - writer.outdent().append("} catch ($guard) {").indent().softNewLine(); writer.append("return $return($rt_asyncError($guard));").softNewLine(); - writer.outdent().append("}").softNewLine(); - writer.outdent().append("}").softNewLine(); + writer.outdent().append("},").ws().append("$return);").softNewLine(); } writer.append("return $part_0();").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 0fd948135..8cf0b7f10 100644 --- a/teavm-core/src/main/resources/org/teavm/javascript/runtime.js +++ b/teavm-core/src/main/resources/org/teavm/javascript/runtime.js @@ -455,6 +455,15 @@ function $rt_continue(f) { return f; } } +function $rt_guardAsync(f, continuation) { + return function() { + try { + return f.apply(this, arguments); + } catch (e) { + return continuation($rt_asyncError(e)); + } + } +} function $dbg_repr(obj) { return obj.toString ? obj.toString() : ""; diff --git a/teavm-samples/teavm-samples-async/src/main/java/org/teavm/samples/async/AsyncProgram.java b/teavm-samples/teavm-samples-async/src/main/java/org/teavm/samples/async/AsyncProgram.java index dc1fa0fc3..fca37cc4a 100644 --- a/teavm-samples/teavm-samples-async/src/main/java/org/teavm/samples/async/AsyncProgram.java +++ b/teavm-samples/teavm-samples-async/src/main/java/org/teavm/samples/async/AsyncProgram.java @@ -55,18 +55,5 @@ public final class AsyncProgram { } } System.out.println("Complete async"); - - System.out.println("Throwing exception"); - try { - throwException(); - } catch (IllegalStateException e) { - System.out.println("Exception caught"); - } - } - - private static void throwException() { - Thread.yield(); - System.out.println("Thread.yield called"); - throw new IllegalStateException(); } }