From 03538071c4f9b0357834c72a29d2909343b48e7a Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Fri, 25 Dec 2015 21:48:32 +0300 Subject: [PATCH] Prevent JSBody from inlining if its argumet get used more than once --- .../org/teavm/jso/impl/JSBodyAstEmitter.java | 13 ++++++++-- .../org/teavm/jso/impl/JSBodyInlineUtil.java | 2 +- .../teavm/jso/test/ImplementationTest.java | 26 ++++++++++++++++++- 3 files changed, 37 insertions(+), 4 deletions(-) diff --git a/jso/impl/src/main/java/org/teavm/jso/impl/JSBodyAstEmitter.java b/jso/impl/src/main/java/org/teavm/jso/impl/JSBodyAstEmitter.java index f35ee14f3..adae48c7e 100644 --- a/jso/impl/src/main/java/org/teavm/jso/impl/JSBodyAstEmitter.java +++ b/jso/impl/src/main/java/org/teavm/jso/impl/JSBodyAstEmitter.java @@ -16,7 +16,9 @@ package org.teavm.jso.impl; import java.io.IOException; +import org.mozilla.javascript.Node; import org.mozilla.javascript.ast.AstNode; +import org.mozilla.javascript.ast.Block; import org.teavm.codegen.SourceWriter; import org.teavm.javascript.Precedence; import org.teavm.javascript.spi.GeneratorContext; @@ -151,7 +153,14 @@ class JSBodyAstEmitter implements JSBodyEmitter { astWriter.declareNameEmitter(parameterNames[i], prec -> writer.append(context.getParameterName(index))); } astWriter.hoist(ast); - astWriter.print(ast); - writer.softNewLine(); + if (ast instanceof Block) { + for (Node child = ast.getFirstChild(); child != null; child = child.getNext()) { + astWriter.print((AstNode) child); + writer.softNewLine(); + } + } else { + astWriter.print(ast); + writer.softNewLine(); + } } } diff --git a/jso/impl/src/main/java/org/teavm/jso/impl/JSBodyInlineUtil.java b/jso/impl/src/main/java/org/teavm/jso/impl/JSBodyInlineUtil.java index 92051c637..b8d80feef 100644 --- a/jso/impl/src/main/java/org/teavm/jso/impl/JSBodyInlineUtil.java +++ b/jso/impl/src/main/java/org/teavm/jso/impl/JSBodyInlineUtil.java @@ -115,7 +115,7 @@ final class JSBodyInlineUtil { Name name = (Name) node; if (!name.isLocalName()) { String id = name.getIdentifier(); - usages.put(id, getUsage(id)); + usages.put(id, getUsage(id) + 1); } } return true; diff --git a/tests/src/test/java/org/teavm/jso/test/ImplementationTest.java b/tests/src/test/java/org/teavm/jso/test/ImplementationTest.java index b61848af4..f8ea5b1e1 100644 --- a/tests/src/test/java/org/teavm/jso/test/ImplementationTest.java +++ b/tests/src/test/java/org/teavm/jso/test/ImplementationTest.java @@ -15,9 +15,10 @@ */ package org.teavm.jso.test; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; import org.junit.Test; import org.teavm.jso.JSBody; +import org.teavm.jso.JSObject; /** * @@ -35,4 +36,27 @@ public class ImplementationTest { @JSBody(params = { "a", "b" }, script = "return a * b;") static final native int mul(int a, int b); + + @Test + public void inliningUsageCounterWorksProperly() { + ForInliningTest instance = ForInliningTest.create(); + wrongInlineCandidate(instance.foo()); + assertEquals(1, instance.counter); + } + + @JSBody(params = { "a" }, script = "console.log(a, a);") + private static native void wrongInlineCandidate(JSObject a); + + static class ForInliningTest implements JSObject { + public int counter = 0; + + public ForInliningTest foo() { + ++counter; + return this; + } + + public static ForInliningTest create() { + return new ForInliningTest(); + } + } }