From 3c9acd8fabf3f991d3a75f5085033a86a8065aa9 Mon Sep 17 00:00:00 2001 From: konsoletyper Date: Sun, 1 Feb 2015 17:43:21 +0400 Subject: [PATCH] Further work on CPS generator --- .../org/teavm/classlib/java/lang/TThread.java | 16 +++- .../java/lang/ThreadNativeGenerator.java | 49 ++++++++++ .../teavm/codegen/DefaultNamingStrategy.java | 13 ++- .../org/teavm/codegen/NamingStrategy.java | 2 + .../java/org/teavm/javascript/Decompiler.java | 10 +-- .../teavm/javascript/OptimizingVisitor.java | 4 +- .../java/org/teavm/javascript/Renderer.java | 44 +++++++-- .../teavm/javascript/ast/AsyncMethodNode.java | 5 ++ .../org/teavm/javascript/ast/ClassNode.java | 5 -- .../java/org/teavm/javascript/ast/Expr.java | 2 +- .../org/teavm/javascript/ast/MethodNode.java | 2 + .../javascript/ast/NativeMethodNode.java | 1 + .../javascript/ast/RegularMethodNode.java | 5 ++ .../teavm/javascript/ni/GeneratorContext.java | 6 ++ .../model/instructions/InvokeInstruction.java | 16 ---- .../teavm/model/util/AsyncMethodFinder.java | 89 +++++++++++++++++++ .../model/util/AsyncProgramSplitter.java | 2 +- .../src/main/java/org/teavm/runtime/Sync.java | 30 +++++++ .../src/main/java/org/teavm/vm/TeaVM.java | 5 +- .../resources/org/teavm/javascript/runtime.js | 14 +++ 20 files changed, 273 insertions(+), 47 deletions(-) create mode 100644 teavm-classlib/src/main/java/org/teavm/classlib/java/lang/ThreadNativeGenerator.java create mode 100644 teavm-core/src/main/java/org/teavm/model/util/AsyncMethodFinder.java create mode 100644 teavm-core/src/main/java/org/teavm/runtime/Sync.java 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 d718e70cc..12ff437f9 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 @@ -15,6 +15,9 @@ */ package org.teavm.classlib.java.lang; +import org.teavm.javascript.ni.GeneratedBy; +import org.teavm.runtime.Async; + /** * * @author Alexey Andreev @@ -56,8 +59,9 @@ public class TThread extends TObject implements TRunnable { return name; } - public static void yield() { - } + @Async + @GeneratedBy(ThreadNativeGenerator.class) + public static native void yield(); public void interrupt() { } @@ -81,4 +85,12 @@ public class TThread extends TObject implements TRunnable { public static boolean holdsLock(@SuppressWarnings("unused") TObject obj) { return true; } + + public static void sleep(long millis) throws TInterruptedException { + sleep((double)millis); + } + + @Async + @GeneratedBy(ThreadNativeGenerator.class) + private static native void sleep(double millis) throws TInterruptedException; } diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/ThreadNativeGenerator.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/ThreadNativeGenerator.java new file mode 100644 index 000000000..56ca7bfa3 --- /dev/null +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/ThreadNativeGenerator.java @@ -0,0 +1,49 @@ +/* + * Copyright 2015 Alexey Andreev. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.teavm.classlib.java.lang; + +import java.io.IOException; +import org.teavm.codegen.SourceWriter; +import org.teavm.javascript.ni.Generator; +import org.teavm.javascript.ni.GeneratorContext; +import org.teavm.model.MethodReference; + +/** + * + * @author Alexey Andreev + */ +public class ThreadNativeGenerator implements Generator { + @Override + public void generate(GeneratorContext context, SourceWriter writer, MethodReference methodRef) throws IOException { + if (methodRef.getName().equals("sleep")) { + generateSleep(context, writer); + } else if (methodRef.getName().equals("yield")) { + generateYield(context, writer); + } + } + + private void generateSleep(GeneratorContext context, SourceWriter writer) throws IOException { + writer.append("setTimer(function() {").indent().softNewLine(); + writer.append(context.getCompleteContinuation()).append("();").softNewLine(); + writer.outdent().append(',').ws().append(context.getParameterName(1)).append(");").softNewLine(); + } + + private void generateYield(GeneratorContext context, SourceWriter writer) throws IOException { + writer.append("setTimer(function() {").indent().softNewLine(); + writer.append(context.getCompleteContinuation()).append("();").softNewLine(); + writer.outdent().append(',').ws().append("0);").softNewLine(); + } +} 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 1fd8cea18..f4cbf3a1e 100644 --- a/teavm-core/src/main/java/org/teavm/codegen/DefaultNamingStrategy.java +++ b/teavm-core/src/main/java/org/teavm/codegen/DefaultNamingStrategy.java @@ -57,6 +57,15 @@ public class DefaultNamingStrategy implements NamingStrategy { @Override public String getNameFor(MethodReference method) { + return getNameFor(method, false); + } + + @Override + public String getNameForAsync(MethodReference method) throws NamingException { + return getNameFor(method, true); + } + + private String getNameFor(MethodReference method, boolean async) { MethodReference origMethod = method; method = getRealMethod(method); if (method == null) { @@ -67,7 +76,7 @@ public class DefaultNamingStrategy implements NamingStrategy { if (methodHolder.hasModifier(ElementModifier.STATIC) || method.getDescriptor().getName().equals("") || methodHolder.getLevel() == AccessLevel.PRIVATE) { - String key = method.toString(); + String key = (async ? "A" : "S") + method.toString(); String alias = privateAliases.get(key); if (alias == null) { alias = aliasProvider.getAlias(method); @@ -75,7 +84,7 @@ public class DefaultNamingStrategy implements NamingStrategy { } return alias; } else { - String key = method.getDescriptor().toString(); + String key = (async ? "A" : "S") + method.getDescriptor().toString(); String alias = aliases.get(key); if (alias == null) { alias = aliasProvider.getAlias(method); 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 e8f3c289e..9ac73ecfe 100644 --- a/teavm-core/src/main/java/org/teavm/codegen/NamingStrategy.java +++ b/teavm-core/src/main/java/org/teavm/codegen/NamingStrategy.java @@ -27,6 +27,8 @@ public interface NamingStrategy { String getNameFor(MethodReference method) throws NamingException; + String getNameForAsync(MethodReference method) throws NamingException; + String getFullNameFor(MethodReference method) throws NamingException; String getNameFor(FieldReference field) throws NamingException; 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 f60778ad2..af8aaf9a0 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/Decompiler.java +++ b/teavm-core/src/main/java/org/teavm/javascript/Decompiler.java @@ -149,7 +149,6 @@ public class Decompiler { if (method.getAnnotations().get(PreserveOriginalName.class.getName()) != null) { methodNode.setOriginalNamePreserved(true); } - clsNode.getAsyncMethods().add(decompileAsync(method)); } clsNode.getInterfaces().addAll(cls.getInterfaces()); clsNode.getModifiers().addAll(mapModifiers(cls.getModifiers())); @@ -158,12 +157,7 @@ public class Decompiler { public MethodNode decompile(MethodHolder method) { return method.getModifiers().contains(ElementModifier.NATIVE) ? decompileNative(method, false) : - decompileRegular(method); - } - - public MethodNode decompileAsync(MethodHolder method) { - return method.getModifiers().contains(ElementModifier.NATIVE) ? decompileNative(method, true) : - decompileRegularAsync(method); + !asyncMethods.contains(method.getReference()) ? decompileRegular(method) : decompileAsync(method); } public NativeMethodNode decompileNative(MethodHolder method, boolean async) { @@ -204,7 +198,7 @@ public class Decompiler { return node; } - public AsyncMethodNode decompileRegularAsync(MethodHolder method) { + public AsyncMethodNode decompileAsync(MethodHolder method) { AsyncMethodNode node = new AsyncMethodNode(method.getReference()); AsyncProgramSplitter splitter = new AsyncProgramSplitter(asyncMethods); splitter.split(method.getProgram()); diff --git a/teavm-core/src/main/java/org/teavm/javascript/OptimizingVisitor.java b/teavm-core/src/main/java/org/teavm/javascript/OptimizingVisitor.java index 61fd9345b..2d8dd3528 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/OptimizingVisitor.java +++ b/teavm-core/src/main/java/org/teavm/javascript/OptimizingVisitor.java @@ -180,7 +180,7 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor { } private boolean tryApplyConstructor(InvocationExpr expr) { - if (!expr.getMethod().getName().equals("")) { + if (expr.getAsyncTarget() != null || !expr.getMethod().getName().equals("")) { return false; } if (resultSequence == null || resultSequence.isEmpty()) { @@ -211,7 +211,7 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor { } Expr[] args = expr.getArguments().toArray(new Expr[0]); args = Arrays.copyOfRange(args, 1, args.length); - Expr constructrExpr = Expr.constructObject(expr.getMethod(), args); + InvocationExpr constructrExpr = Expr.constructObject(expr.getMethod(), args); constructrExpr.setLocation(expr.getLocation()); assignment.setRightValue(constructrExpr); stats.reads[var.getIndex()]--; 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 fb1d11f8f..16befdbe6 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/Renderer.java +++ b/teavm-core/src/main/java/org/teavm/javascript/Renderer.java @@ -370,11 +370,6 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext for (MethodNode method : nonInitMethods) { renderBody(method, false); } - for (MethodNode method : cls.getAsyncMethods()) { - writer.append("/*").softNewLine(); - renderBody(method, false); - writer.append("*/").softNewLine(); - } renderVirtualDeclarations(cls.getName(), virtualMethods); } catch (NamingException e) { throw new RenderingException("Error rendering class " + cls.getName() + ". See a cause for details", e); @@ -475,6 +470,12 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext } writer.append(");").ws().append("}"); debugEmitter.emitMethod(null); + + if (!method.isAsync()) { + writer.append(",").newLine(); + writer.append("\"").append(naming.getNameForAsync(ref)).append("\",").ws(); + writer.append("$rt_asyncAdapter(").appendMethodBody(ref).append(')'); + } } writer.append(");").newLine().outdent(); } @@ -524,6 +525,9 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext } writer.append(variableName(i)); } + if (method.isAsync()) { + writer.append(',').ws().append("$return,").ws().append("$throw"); + } writer.append(")").ws().append("{").softNewLine().indent(); method.acceptVisitor(new MethodBodyRenderer()); writer.outdent().append("}").newLine(); @@ -531,9 +535,13 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext } private class MethodBodyRenderer implements MethodNodeVisitor, GeneratorContext { + private boolean async; + @Override public void visit(NativeMethodNode methodNode) { try { + this.async = methodNode.isAsync(); + Renderer.this.async = methodNode.isAsync(); methodNode.getGenerator().generate(this, writer, methodNode.getReference()); } catch (IOException e) { throw new RenderingException("IO error occured", e); @@ -544,6 +552,7 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext public void visit(RegularMethodNode method) { try { Renderer.this.async = false; + this.async = false; MethodReference ref = method.getReference(); for (int i = 0; i < method.getParameterDebugNames().size(); ++i) { debugEmitter.emitVariable(method.getParameterDebugNames().get(i).toArray(new String[0]), @@ -583,6 +592,7 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext public void visit(AsyncMethodNode methodNode) { try { Renderer.this.async = true; + this.async = true; MethodReference ref = methodNode.getReference(); for (int i = 0; i < methodNode.getParameterDebugNames().size(); ++i) { debugEmitter.emitVariable(methodNode.getParameterDebugNames().get(i).toArray(new String[0]), @@ -607,8 +617,8 @@ 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("($input,").ws().append("$return,").ws() - .append("$throw)").ws().append('{').indent().softNewLine(); + writer.append("function $part_").append(i).append("($input)").ws().append('{') + .indent().softNewLine(); AsyncMethodPart part = methodNode.getBody().get(i); if (part.getInputVariable() != null) { writer.append(variableName(part.getInputVariable())).ws().append('=').ws().append("$input;") @@ -617,7 +627,7 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext part.getStatement().acceptVisitor(Renderer.this); writer.outdent().append('}').softNewLine(); } - writer.append("return $part_0;").softNewLine(); + writer.append("return $part_0();").softNewLine(); } catch (IOException e) { throw new RenderingException("IO error occured", e); } @@ -647,6 +657,21 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext public T getService(Class type) { return services.getService(type); } + + @Override + public boolean isAsync() { + return async; + } + + @Override + public String getErrorContinuation() { + return "$throw"; + } + + @Override + public String getCompleteContinuation() { + return "$return"; + } } private void pushLocation(NodeLocation location) { @@ -1404,7 +1429,8 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext expr.getArguments().get(0).acceptVisitor(this); } String className = naming.getNameFor(expr.getMethod().getClassName()); - String name = naming.getNameFor(expr.getMethod()); + String name = expr.getAsyncTarget() == null ? naming.getNameFor(expr.getMethod()) : + naming.getNameForAsync(expr.getMethod()); String fullName = naming.getFullNameFor(expr.getMethod()); DeferredCallSite callSite = prevCallSite; boolean shouldEraseCallSite = lastCallSite == null; diff --git a/teavm-core/src/main/java/org/teavm/javascript/ast/AsyncMethodNode.java b/teavm-core/src/main/java/org/teavm/javascript/ast/AsyncMethodNode.java index 9c017e342..bdeb269e3 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/ast/AsyncMethodNode.java +++ b/teavm-core/src/main/java/org/teavm/javascript/ast/AsyncMethodNode.java @@ -49,4 +49,9 @@ public class AsyncMethodNode extends MethodNode { public void acceptVisitor(MethodNodeVisitor visitor) { visitor.visit(this); } + + @Override + public boolean isAsync() { + return true; + } } diff --git a/teavm-core/src/main/java/org/teavm/javascript/ast/ClassNode.java b/teavm-core/src/main/java/org/teavm/javascript/ast/ClassNode.java index b76128af7..dcfcb3923 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/ast/ClassNode.java +++ b/teavm-core/src/main/java/org/teavm/javascript/ast/ClassNode.java @@ -30,7 +30,6 @@ public class ClassNode { private Set modifiers = EnumSet.noneOf(NodeModifier.class); private List fields = new ArrayList<>(); private List methods = new ArrayList<>(); - private List asyncMethods = new ArrayList<>(); private List interfaces = new ArrayList<>(); public ClassNode(String name, String parentName) { @@ -54,10 +53,6 @@ public class ClassNode { return methods; } - public List getAsyncMethods() { - return asyncMethods; - } - public List getInterfaces() { return interfaces; } diff --git a/teavm-core/src/main/java/org/teavm/javascript/ast/Expr.java b/teavm-core/src/main/java/org/teavm/javascript/ast/Expr.java index 476f79e6b..0c8f13f2e 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/ast/Expr.java +++ b/teavm-core/src/main/java/org/teavm/javascript/ast/Expr.java @@ -104,7 +104,7 @@ public abstract class Expr implements Cloneable { return expr; } - public static Expr constructObject(MethodReference method, Expr[] arguments) { + public static InvocationExpr constructObject(MethodReference method, Expr[] arguments) { InvocationExpr expr = new InvocationExpr(); expr.setMethod(method); expr.setType(InvocationType.CONSTRUCTOR); diff --git a/teavm-core/src/main/java/org/teavm/javascript/ast/MethodNode.java b/teavm-core/src/main/java/org/teavm/javascript/ast/MethodNode.java index ba1e8653b..952a1d154 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/ast/MethodNode.java +++ b/teavm-core/src/main/java/org/teavm/javascript/ast/MethodNode.java @@ -50,4 +50,6 @@ public abstract class MethodNode { } public abstract void acceptVisitor(MethodNodeVisitor visitor); + + public abstract boolean isAsync(); } diff --git a/teavm-core/src/main/java/org/teavm/javascript/ast/NativeMethodNode.java b/teavm-core/src/main/java/org/teavm/javascript/ast/NativeMethodNode.java index 0849a4cfa..a58ea263e 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/ast/NativeMethodNode.java +++ b/teavm-core/src/main/java/org/teavm/javascript/ast/NativeMethodNode.java @@ -38,6 +38,7 @@ public class NativeMethodNode extends MethodNode { this.generator = generator; } + @Override public boolean isAsync() { return async; } diff --git a/teavm-core/src/main/java/org/teavm/javascript/ast/RegularMethodNode.java b/teavm-core/src/main/java/org/teavm/javascript/ast/RegularMethodNode.java index 442d6a963..054a050b1 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/ast/RegularMethodNode.java +++ b/teavm-core/src/main/java/org/teavm/javascript/ast/RegularMethodNode.java @@ -53,4 +53,9 @@ public class RegularMethodNode extends MethodNode { public void acceptVisitor(MethodNodeVisitor visitor) { visitor.visit(this); } + + @Override + public boolean isAsync() { + return false; + } } diff --git a/teavm-core/src/main/java/org/teavm/javascript/ni/GeneratorContext.java b/teavm-core/src/main/java/org/teavm/javascript/ni/GeneratorContext.java index 985727a90..c28756a55 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/ni/GeneratorContext.java +++ b/teavm-core/src/main/java/org/teavm/javascript/ni/GeneratorContext.java @@ -31,4 +31,10 @@ public interface GeneratorContext extends ServiceRepository { ClassLoader getClassLoader(); Properties getProperties(); + + boolean isAsync(); + + String getErrorContinuation(); + + String getCompleteContinuation(); } diff --git a/teavm-core/src/main/java/org/teavm/model/instructions/InvokeInstruction.java b/teavm-core/src/main/java/org/teavm/model/instructions/InvokeInstruction.java index 982b4d792..8bf04206e 100644 --- a/teavm-core/src/main/java/org/teavm/model/instructions/InvokeInstruction.java +++ b/teavm-core/src/main/java/org/teavm/model/instructions/InvokeInstruction.java @@ -16,9 +16,7 @@ package org.teavm.model.instructions; import java.util.ArrayList; -import java.util.HashSet; import java.util.List; -import java.util.Set; import org.teavm.model.Instruction; import org.teavm.model.MethodReference; import org.teavm.model.Variable; @@ -32,8 +30,6 @@ public class InvokeInstruction extends Instruction { private MethodReference method; private Variable instance; private List arguments = new ArrayList<>(); - private Set implemenetations = new HashSet(); - private boolean resolved; private Variable receiver; public InvocationType getType() { @@ -72,18 +68,6 @@ public class InvokeInstruction extends Instruction { this.receiver = receiver; } - public Set getImplemenetations() { - return implemenetations; - } - - public boolean isResolved() { - return resolved; - } - - public void setResolved(boolean resolved) { - this.resolved = resolved; - } - @Override public void acceptVisitor(InstructionVisitor visitor) { visitor.visit(this); diff --git a/teavm-core/src/main/java/org/teavm/model/util/AsyncMethodFinder.java b/teavm-core/src/main/java/org/teavm/model/util/AsyncMethodFinder.java new file mode 100644 index 000000000..4c07b28bd --- /dev/null +++ b/teavm-core/src/main/java/org/teavm/model/util/AsyncMethodFinder.java @@ -0,0 +1,89 @@ +/* + * Copyright 2015 Alexey Andreev. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.teavm.model.util; + +import java.util.HashSet; +import java.util.Set; +import org.teavm.callgraph.CallGraph; +import org.teavm.callgraph.CallGraphNode; +import org.teavm.callgraph.CallSite; +import org.teavm.diagnostics.Diagnostics; +import org.teavm.javascript.ni.InjectedBy; +import org.teavm.model.*; +import org.teavm.runtime.Async; +import org.teavm.runtime.Sync; + +/** + * + * @author Alexey Andreev + */ +public class AsyncMethodFinder { + private Set asyncMethods = new HashSet<>(); + private CallGraph callGraph; + private Diagnostics diagnostics; + private ListableClassReaderSource classSource; + + public AsyncMethodFinder(CallGraph callGraph, Diagnostics diagnostics) { + this.callGraph = callGraph; + this.diagnostics = diagnostics; + } + + public Set getAsyncMethods() { + return asyncMethods; + } + + public void find(ListableClassReaderSource classSource) { + this.classSource = classSource; + for (String clsName : classSource.getClassNames()) { + ClassReader cls = classSource.get(clsName); + for (MethodReader method : cls.getMethods()) { + if (asyncMethods.contains(method.getReference())) { + continue; + } + if (method.getAnnotations().get(Async.class.getName()) != null) { + add(method.getReference()); + } + } + } + } + + private void add(MethodReference methodRef) { + if (!asyncMethods.add(methodRef)) { + return; + } + CallGraphNode node = callGraph.getNode(methodRef); + if (node == null) { + return; + } + ClassReader cls = classSource.get(methodRef.getClassName()); + if (cls == null) { + return; + } + MethodReader method = cls.getMethod(methodRef.getDescriptor()); + if (method == null) { + return; + } + if (method.getAnnotations().get(Sync.class.getName()) != null || + method.getAnnotations().get(InjectedBy.class.getName()) != null) { + diagnostics.error(new CallLocation(methodRef), "Method {{m0}} is claimed to be synchronous, " + + "but it is has invocations of asynchronous methods", methodRef); + return; + } + for (CallSite callSite : node.getCallerCallSites()) { + add(callSite.getCaller().getMethod()); + } + } +} diff --git a/teavm-core/src/main/java/org/teavm/model/util/AsyncProgramSplitter.java b/teavm-core/src/main/java/org/teavm/model/util/AsyncProgramSplitter.java index 3df6610b3..da46951ac 100644 --- a/teavm-core/src/main/java/org/teavm/model/util/AsyncProgramSplitter.java +++ b/teavm-core/src/main/java/org/teavm/model/util/AsyncProgramSplitter.java @@ -61,7 +61,7 @@ public class AsyncProgramSplitter { Instruction insn = sourceBlock.getInstructions().get(i); if (insn instanceof InvokeInstruction) { InvokeInstruction invoke = (InvokeInstruction)insn; - if (true) { //asyncMethods.contains(invoke)) { + if (asyncMethods.contains(invoke.getMethod())) { asyncOccured = true; long key = ((long)step.source << 32) | i; if (partMap.containsKey(key)) { diff --git a/teavm-core/src/main/java/org/teavm/runtime/Sync.java b/teavm-core/src/main/java/org/teavm/runtime/Sync.java new file mode 100644 index 000000000..8b5a68c2a --- /dev/null +++ b/teavm-core/src/main/java/org/teavm/runtime/Sync.java @@ -0,0 +1,30 @@ +/* + * Copyright 2015 Alexey Andreev. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.teavm.runtime; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * + * @author Alexey Andreev + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface Sync { +} 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 f7e43e5af..ea59790cc 100644 --- a/teavm-core/src/main/java/org/teavm/vm/TeaVM.java +++ b/teavm-core/src/main/java/org/teavm/vm/TeaVM.java @@ -526,8 +526,11 @@ public class TeaVM implements TeaVMHost, ServiceRepository { } private List modelToAst(ListableClassHolderSource classes) { + AsyncMethodFinder asyncFinder = new AsyncMethodFinder(dependencyChecker.getCallGraph(), diagnostics); + asyncFinder.find(classes); + progressListener.phaseStarted(TeaVMPhase.DECOMPILATION, classes.getClassNames().size()); - Decompiler decompiler = new Decompiler(classes, classLoader, new HashSet()); + Decompiler decompiler = new Decompiler(classes, classLoader, asyncFinder.getAsyncMethods()); decompiler.setRegularMethodCache(incremental ? astCache : null); for (Map.Entry entry : methodGenerators.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 f839305bc..c95809d7c 100644 --- a/teavm-core/src/main/resources/org/teavm/javascript/runtime.js +++ b/teavm-core/src/main/resources/org/teavm/javascript/runtime.js @@ -392,6 +392,20 @@ function $rt_virtualMethods(cls) { } } } +function $rt_asyncAdapter(f) { + return function() { + var e; + var args = Array.prototype.slice.apply(arguments); + var $throw = args.pop(); + var $return args.pop(); + try { + var result = f.apply(this, args); + } catch (e) { + return $throw(e); + } + return $return(result); + } +} var $rt_stringPool_instance; function $rt_stringPool(strings) { $rt_stringPool_instance = new Array(strings.length);