From ae2ca37ee0b3a03fea09c1ab7ab66c8111c452fa Mon Sep 17 00:00:00 2001 From: konsoletyper Date: Mon, 17 Feb 2014 08:15:06 +0400 Subject: [PATCH 1/2] Adds type conversion from Java array and integer to JS array and number --- .../java/lang/StringNativeGenerator.java | 1 - .../teavm/classlib/java/lang/TInteger.java | 2 +- .../teavm/codegen/DefaultNamingStrategy.java | 3 +- .../teavm/html4j/JavaScriptBodyConverter.java | 32 ++++++ .../JavaScriptBodyConverterGenerator.java | 103 ++++++++++++++++++ .../html4j/JavaScriptBodyDependency.java | 10 ++ .../teavm/html4j/JavaScriptBodyGenerator.java | 13 ++- .../test/JavaScriptBodyConversionTests.java | 34 ++++++ .../html4j/test/JavaScriptBodyTests.java | 14 +++ 9 files changed, 208 insertions(+), 4 deletions(-) create mode 100644 teavm-html4j/src/main/java/org/teavm/html4j/JavaScriptBodyConverter.java create mode 100644 teavm-html4j/src/main/java/org/teavm/html4j/JavaScriptBodyConverterGenerator.java create mode 100644 teavm-html4j/src/test/java/org/teavm/html4j/test/JavaScriptBodyConversionTests.java diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/StringNativeGenerator.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/StringNativeGenerator.java index d54ff12ab..69bf0e7a7 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/StringNativeGenerator.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/StringNativeGenerator.java @@ -25,7 +25,6 @@ import org.teavm.model.MethodReference; * @author Alexey Andreev */ public class StringNativeGenerator implements Injector { - @Override public void generate(InjectorContext context, MethodReference methodRef) throws IOException { switch (methodRef.getName()) { diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TInteger.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TInteger.java index d1ea4eea3..3e2caaa36 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TInteger.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TInteger.java @@ -123,7 +123,7 @@ public class TInteger extends TNumber implements TComparable { if (integerCache == null) { integerCache = new TInteger[256]; for (int j = 0; j < integerCache.length; ++j) { - integerCache[j - 128] = new TInteger(j); + integerCache[j] = new TInteger(j - 128); } } } 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 225eeea3d..2a9684fc5 100644 --- a/teavm-core/src/main/java/org/teavm/codegen/DefaultNamingStrategy.java +++ b/teavm-core/src/main/java/org/teavm/codegen/DefaultNamingStrategy.java @@ -57,9 +57,10 @@ public class DefaultNamingStrategy implements NamingStrategy { @Override public String getNameFor(MethodReference method) { + MethodReference origMethod = method; method = getRealMethod(method); if (method == null) { - throw new NamingException("Can't provide name for method as it was not found: " + method); + throw new NamingException("Can't provide name for method as it was not found: " + origMethod); } ClassHolder clsHolder = classSource.get(method.getClassName()); MethodHolder methodHolder = clsHolder.getMethod(method.getDescriptor()); diff --git a/teavm-html4j/src/main/java/org/teavm/html4j/JavaScriptBodyConverter.java b/teavm-html4j/src/main/java/org/teavm/html4j/JavaScriptBodyConverter.java new file mode 100644 index 000000000..9b2dbef12 --- /dev/null +++ b/teavm-html4j/src/main/java/org/teavm/html4j/JavaScriptBodyConverter.java @@ -0,0 +1,32 @@ +/* + * Copyright 2014 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.html4j; + +import org.teavm.dependency.PluggableDependency; +import org.teavm.javascript.ni.GeneratedBy; + +/** + * + * @author Alexey Andreev + */ +public final class JavaScriptBodyConverter { + private JavaScriptBodyConverter() { + } + + @GeneratedBy(JavaScriptBodyConverterGenerator.class) + @PluggableDependency(JavaScriptBodyConverterGenerator.class) + public static native Object toJavaScript(Object obj); +} diff --git a/teavm-html4j/src/main/java/org/teavm/html4j/JavaScriptBodyConverterGenerator.java b/teavm-html4j/src/main/java/org/teavm/html4j/JavaScriptBodyConverterGenerator.java new file mode 100644 index 000000000..3e010b73f --- /dev/null +++ b/teavm-html4j/src/main/java/org/teavm/html4j/JavaScriptBodyConverterGenerator.java @@ -0,0 +1,103 @@ +/* + * Copyright 2014 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.html4j; + +import java.io.IOException; +import org.teavm.codegen.SourceWriter; +import org.teavm.dependency.DependencyChecker; +import org.teavm.dependency.DependencyConsumer; +import org.teavm.dependency.DependencyPlugin; +import org.teavm.dependency.MethodGraph; +import org.teavm.javascript.ni.Generator; +import org.teavm.javascript.ni.GeneratorContext; +import org.teavm.model.*; + +/** + * + * @author Alexey Andreev + */ +public class JavaScriptBodyConverterGenerator implements Generator, DependencyPlugin { + private static final MethodReference intValueMethod = new MethodReference("java.lang.Integer", + new MethodDescriptor("intValue", ValueType.INTEGER)); + + @Override + public void methodAchieved(DependencyChecker checker, MethodReference method) { + switch (method.getName()) { + case "toJavaScript": + achieveToJavaScript(checker, method); + break; + } + } + + private void achieveToJavaScript(final DependencyChecker checker, MethodReference method) { + MethodGraph graph = checker.attachMethodGraph(method); + graph.getVariable(1).addConsumer(new DependencyConsumer() { + @Override public void consume(String type) { + if (type.equals("java.lang.Integer")) { + checker.attachMethodGraph(intValueMethod); + } + } + }); + } + + @Override + public void generate(GeneratorContext context, SourceWriter writer, MethodReference methodRef) throws IOException { + switch (methodRef.getName()) { + case "toJavaScript": + generateToJavaScript(context, writer); + break; + } + } + + private void generateToJavaScript(GeneratorContext context, SourceWriter writer) throws IOException { + ClassReaderSource classSource = context.getClassSource(); + String obj = context.getParameterName(1); + writer.append("if").ws().append("(").append(obj).ws().append("===").ws().append("null)").ws().append("{") + .softNewLine().indent(); + writer.append("return null;").softNewLine(); + writer.outdent().append("}").ws().append("else if").ws().append('(').append(obj) + .append(".constructor.$meta.item)").ws().append("{").indent().softNewLine(); + writer.append("return ").append(obj).append(".data;").softNewLine(); + writer.outdent().append("}"); + if (classSource.get("java.lang.String") != null) { + writer.ws().append("else if").ws().append("(").append(obj).append(".constructor").ws().append("===").ws() + .appendClass("java.lang.String").append(")").ws().append("{").indent().softNewLine(); + generateStringToJavaScript(context, writer); + writer.outdent().append("}"); + } + if (classSource.get("java.lang.Integer") != null) { + writer.ws().append("else if").ws().append("(").append(obj).append(".constructor").ws().append("===").ws() + .appendClass("java.lang.Integer").append(")").ws().append("{").indent().softNewLine(); + writer.append("return ").appendMethodBody(intValueMethod).append("(").append(obj) + .append(");").softNewLine(); + writer.outdent().append("}"); + } + writer.ws().append("else").ws().append("{").indent().softNewLine(); + writer.append("return ").append(obj).append(";").softNewLine(); + writer.outdent().append("}").softNewLine(); + } + + private void generateStringToJavaScript(GeneratorContext context, SourceWriter writer) throws IOException { + FieldReference charsField = new FieldReference("java.lang.String", "characters"); + writer.append("var result = \"\";").softNewLine(); + writer.append("var data = ").append(context.getParameterName(1)).append('.') + .appendField(charsField).append(".data;").softNewLine(); + writer.append("for (var i = 0; i < data.length; i = (i + 1) | 0) {").indent().softNewLine(); + writer.append("result += String.fromCharCode(data[i]);").softNewLine(); + writer.outdent().append("}").softNewLine(); + writer.append("return result;").softNewLine(); + } +} diff --git a/teavm-html4j/src/main/java/org/teavm/html4j/JavaScriptBodyDependency.java b/teavm-html4j/src/main/java/org/teavm/html4j/JavaScriptBodyDependency.java index ae6eb87ef..136a2a376 100644 --- a/teavm-html4j/src/main/java/org/teavm/html4j/JavaScriptBodyDependency.java +++ b/teavm-html4j/src/main/java/org/teavm/html4j/JavaScriptBodyDependency.java @@ -73,6 +73,16 @@ public class JavaScriptBodyDependency implements DependencyListener { String body = annot.getValue("body").getString(); new GeneratorJsCallback(dependencyChecker.getClassSource(), dependencyChecker).parse(body); } + for (int i = 0; i < methodRef.parameterCount(); ++i) { + ValueType type = methodRef.getDescriptor().parameterType(i); + if (type.isObject("java.lang.Object")) { + MethodGraph convGraph = dependencyChecker.attachMethodGraph(new MethodReference( + JavaScriptBodyConverter.class.getName(), + new MethodDescriptor("toJavaScript", ValueType.object("java.lang.Object"), + ValueType.object("java.lang.Object")))); + graph.getVariable(i + 1).connect(convGraph.getVariable(i + 1)); + } + } } } diff --git a/teavm-html4j/src/main/java/org/teavm/html4j/JavaScriptBodyGenerator.java b/teavm-html4j/src/main/java/org/teavm/html4j/JavaScriptBodyGenerator.java index d56bd9f2d..9a7c6d512 100644 --- a/teavm-html4j/src/main/java/org/teavm/html4j/JavaScriptBodyGenerator.java +++ b/teavm-html4j/src/main/java/org/teavm/html4j/JavaScriptBodyGenerator.java @@ -53,11 +53,22 @@ public class JavaScriptBodyGenerator implements Generator { writer.outdent().append("}).call(").append(context.getParameterName(0)); for (int i = 0; i < args.size(); ++i) { writer.append(",").ws(); - writer.append(context.getParameterName(i + 1)); + wrapParameter(writer, methodRef.getDescriptor().parameterType(i), context.getParameterName(i + 1)); } writer.append(");").softNewLine(); } + private void wrapParameter(SourceWriter writer, ValueType type, String param) throws IOException { + if (type.isObject("java.lang.Object")) { + writer.appendMethodBody(new MethodReference(JavaScriptBodyConverter.class.getName(), + new MethodDescriptor("toJavaScript", ValueType.object("java.lang.Object"), + ValueType.object("java.lang.Object")))); + writer.append("(").append(param).append(")"); + } else { + writer.append(param); + } + } + private static class GeneratorJsCallback extends JsCallback { private ClassReaderSource classSource; private NamingStrategy naming; diff --git a/teavm-html4j/src/test/java/org/teavm/html4j/test/JavaScriptBodyConversionTests.java b/teavm-html4j/src/test/java/org/teavm/html4j/test/JavaScriptBodyConversionTests.java new file mode 100644 index 000000000..b64d34f37 --- /dev/null +++ b/teavm-html4j/src/test/java/org/teavm/html4j/test/JavaScriptBodyConversionTests.java @@ -0,0 +1,34 @@ +/* + * Copyright 2014 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.html4j.test; + +import static org.junit.Assert.*; +import net.java.html.js.JavaScriptBody; +import org.junit.Test; + +/** + * + * @author Alexey Andreev + */ +public class JavaScriptBodyConversionTests { + @Test + public void convertsInteger() { + assertEquals(23, returnAsInt(23)); + } + + @JavaScriptBody(args = { "value" }, body = "return value;") + private native int returnAsInt(Object value); +} diff --git a/teavm-html4j/src/test/java/org/teavm/html4j/test/JavaScriptBodyTests.java b/teavm-html4j/src/test/java/org/teavm/html4j/test/JavaScriptBodyTests.java index b0a4b44d0..30e96d3cb 100644 --- a/teavm-html4j/src/test/java/org/teavm/html4j/test/JavaScriptBodyTests.java +++ b/teavm-html4j/src/test/java/org/teavm/html4j/test/JavaScriptBodyTests.java @@ -64,6 +64,11 @@ public class JavaScriptBodyTests { assertEquals(23, invokeCallback(a)); } + @Test + public void staticCallbackInvoked() { + assertEquals(23, invokeStaticCallback(new AImpl())); + } + private static class AImpl implements A { @Override public int foo() { return 23; @@ -90,4 +95,13 @@ public class JavaScriptBodyTests { "@org.teavm.html4j.test.B::bar(" + "Lorg/teavm/html4j/test/A;)(_global_)", javacall = true) private native int invokeCallback(B callback); + + public static int staticCallback(A a) { + return a.foo(); + } + + @JavaScriptBody(args = { "a" }, body = "return " + + "@org.teavm.html4j.test.JavaScriptBodyTests::staticCallback(" + + "Lorg/teavm/html4j/test/A;)(a)", javacall = true) + private native int invokeStaticCallback(A a); } From 169ecb18c88cc8f1a12389ae29b4495fa9836a81 Mon Sep 17 00:00:00 2001 From: konsoletyper Date: Mon, 17 Feb 2014 17:05:17 +0400 Subject: [PATCH 2/2] Adds integer conversion --- .../resources/org/teavm/javascript/runtime.js | 4 + .../teavm/html4j/JavaScriptBodyConverter.java | 5 +- .../JavaScriptBodyConverterGenerator.java | 90 ++++++++++--------- .../html4j/JavaScriptBodyDependency.java | 19 ++-- .../teavm/html4j/JavaScriptBodyGenerator.java | 20 +++-- .../html4j/test/JavaScriptBodyTests.java | 9 -- 6 files changed, 75 insertions(+), 72 deletions(-) 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 3e3800468..02f6e9043 100644 --- a/teavm-core/src/main/resources/org/teavm/javascript/runtime.js +++ b/teavm-core/src/main/resources/org/teavm/javascript/runtime.js @@ -43,6 +43,10 @@ $rt_createArray = function(cls, sz) { } return arr; } +$rt_wrapArray = function(cls, data) { + var arr = new ($rt_arraycls(cls))(data); + return arr; +} $rt_createUnfilledArray = function(cls, sz) { return new ($rt_arraycls(cls))(new Array(sz)); } diff --git a/teavm-html4j/src/main/java/org/teavm/html4j/JavaScriptBodyConverter.java b/teavm-html4j/src/main/java/org/teavm/html4j/JavaScriptBodyConverter.java index 9b2dbef12..1dc0d0fdd 100644 --- a/teavm-html4j/src/main/java/org/teavm/html4j/JavaScriptBodyConverter.java +++ b/teavm-html4j/src/main/java/org/teavm/html4j/JavaScriptBodyConverter.java @@ -15,7 +15,6 @@ */ package org.teavm.html4j; -import org.teavm.dependency.PluggableDependency; import org.teavm.javascript.ni.GeneratedBy; /** @@ -27,6 +26,8 @@ public final class JavaScriptBodyConverter { } @GeneratedBy(JavaScriptBodyConverterGenerator.class) - @PluggableDependency(JavaScriptBodyConverterGenerator.class) public static native Object toJavaScript(Object obj); + + @GeneratedBy(JavaScriptBodyConverterGenerator.class) + public static native Object fromJavaScript(Object obj); } diff --git a/teavm-html4j/src/main/java/org/teavm/html4j/JavaScriptBodyConverterGenerator.java b/teavm-html4j/src/main/java/org/teavm/html4j/JavaScriptBodyConverterGenerator.java index 3e010b73f..930695608 100644 --- a/teavm-html4j/src/main/java/org/teavm/html4j/JavaScriptBodyConverterGenerator.java +++ b/teavm-html4j/src/main/java/org/teavm/html4j/JavaScriptBodyConverterGenerator.java @@ -17,10 +17,6 @@ package org.teavm.html4j; import java.io.IOException; import org.teavm.codegen.SourceWriter; -import org.teavm.dependency.DependencyChecker; -import org.teavm.dependency.DependencyConsumer; -import org.teavm.dependency.DependencyPlugin; -import org.teavm.dependency.MethodGraph; import org.teavm.javascript.ni.Generator; import org.teavm.javascript.ni.GeneratorContext; import org.teavm.model.*; @@ -29,29 +25,15 @@ import org.teavm.model.*; * * @author Alexey Andreev */ -public class JavaScriptBodyConverterGenerator implements Generator, DependencyPlugin { - private static final MethodReference intValueMethod = new MethodReference("java.lang.Integer", +public class JavaScriptBodyConverterGenerator implements Generator { + private static final String convCls = JavaScriptBodyConverter.class.getName(); + static final MethodReference intValueMethod = new MethodReference("java.lang.Integer", new MethodDescriptor("intValue", ValueType.INTEGER)); - - @Override - public void methodAchieved(DependencyChecker checker, MethodReference method) { - switch (method.getName()) { - case "toJavaScript": - achieveToJavaScript(checker, method); - break; - } - } - - private void achieveToJavaScript(final DependencyChecker checker, MethodReference method) { - MethodGraph graph = checker.attachMethodGraph(method); - graph.getVariable(1).addConsumer(new DependencyConsumer() { - @Override public void consume(String type) { - if (type.equals("java.lang.Integer")) { - checker.attachMethodGraph(intValueMethod); - } - } - }); - } + private static final ValueType objType = ValueType.object("java.lang.Object"); + static final MethodReference toJsMethod = new MethodReference(convCls, new MethodDescriptor( + "toJavaScript", objType, objType)); + static final MethodReference fromJsMethod = new MethodReference(convCls, new MethodDescriptor( + "fromJavaScript", objType, objType)); @Override public void generate(GeneratorContext context, SourceWriter writer, MethodReference methodRef) throws IOException { @@ -59,32 +41,52 @@ public class JavaScriptBodyConverterGenerator implements Generator, DependencyPl case "toJavaScript": generateToJavaScript(context, writer); break; + case "fromJavaScript": + generateFromJavaScript(context, writer); + break; } } private void generateToJavaScript(GeneratorContext context, SourceWriter writer) throws IOException { - ClassReaderSource classSource = context.getClassSource(); String obj = context.getParameterName(1); - writer.append("if").ws().append("(").append(obj).ws().append("===").ws().append("null)").ws().append("{") + writer.append("if (" + obj + " === null) {").softNewLine().indent(); + writer.append("return null;").softNewLine(); + writer.outdent().append("} else if (" + obj + ".constructor.$meta.item) {").indent().softNewLine(); + writer.append("var arr = new Array(" + obj + ".data.length);").softNewLine(); + writer.append("for (var i = 0; i < arr.length; ++i) {").indent().softNewLine(); + writer.append("arr[i] = ").appendMethodBody(toJsMethod).append("(" + obj + ".data[i]);").softNewLine(); + writer.outdent().append("}").softNewLine(); + writer.append("return arr;").softNewLine(); + writer.outdent().append("}"); + writer.append(" else if (" + obj + ".constructor === ").appendClass("java.lang.String") + .append(") {").indent().softNewLine(); + generateStringToJavaScript(context, writer); + writer.outdent().append("} else if (" + obj + ".constructor === ").appendClass("java.lang.Integer") + .append(") {").indent().softNewLine(); + writer.append("return ").appendMethodBody(intValueMethod).append("(" + obj + ");").softNewLine(); + writer.outdent().append("}"); + writer.append(" else {").indent().softNewLine(); + writer.append("return " + obj + ";").softNewLine(); + writer.outdent().append("}").softNewLine(); + } + + private void generateFromJavaScript(GeneratorContext context, SourceWriter writer) throws IOException { + String obj = context.getParameterName(1); + writer.append("if (" + obj +" === null || " + obj + " === undefined)").ws().append("{") .softNewLine().indent(); writer.append("return null;").softNewLine(); - writer.outdent().append("}").ws().append("else if").ws().append('(').append(obj) - .append(".constructor.$meta.item)").ws().append("{").indent().softNewLine(); - writer.append("return ").append(obj).append(".data;").softNewLine(); + writer.outdent().append("} else if (" + obj + " instanceof Array) {").indent().softNewLine(); + writer.append("var arr = $rt_createArray($rt_objcls(), " + obj + ".length);").softNewLine(); + writer.append("for (var i = 0; i < arr.data.length; ++i) {").indent().softNewLine(); + writer.append("arr.data[i] = ").appendMethodBody(fromJsMethod).append("(" + obj + "[i]);") + .softNewLine(); + writer.outdent().append("}").softNewLine(); + writer.append("return arr;").softNewLine(); + writer.outdent().append("}"); + writer.append(" else if (" + obj + ".constructor === ").appendClass("java.lang.String") + .append(") {").indent().softNewLine(); + writer.append("return $rt_str(" + obj + ");").softNewLine(); writer.outdent().append("}"); - if (classSource.get("java.lang.String") != null) { - writer.ws().append("else if").ws().append("(").append(obj).append(".constructor").ws().append("===").ws() - .appendClass("java.lang.String").append(")").ws().append("{").indent().softNewLine(); - generateStringToJavaScript(context, writer); - writer.outdent().append("}"); - } - if (classSource.get("java.lang.Integer") != null) { - writer.ws().append("else if").ws().append("(").append(obj).append(".constructor").ws().append("===").ws() - .appendClass("java.lang.Integer").append(")").ws().append("{").indent().softNewLine(); - writer.append("return ").appendMethodBody(intValueMethod).append("(").append(obj) - .append(");").softNewLine(); - writer.outdent().append("}"); - } writer.ws().append("else").ws().append("{").indent().softNewLine(); writer.append("return ").append(obj).append(";").softNewLine(); writer.outdent().append("}").softNewLine(); diff --git a/teavm-html4j/src/main/java/org/teavm/html4j/JavaScriptBodyDependency.java b/teavm-html4j/src/main/java/org/teavm/html4j/JavaScriptBodyDependency.java index 136a2a376..ded276f45 100644 --- a/teavm-html4j/src/main/java/org/teavm/html4j/JavaScriptBodyDependency.java +++ b/teavm-html4j/src/main/java/org/teavm/html4j/JavaScriptBodyDependency.java @@ -30,8 +30,6 @@ public class JavaScriptBodyDependency implements DependencyListener { public void started(DependencyChecker dependencyChecker) { allClassesNode = dependencyChecker.createNode(); allClassesNode.setTag("JavaScriptBody:global"); - allClassesNode.getArrayItem().addConsumer(new OneDirectionalConnection(allClassesNode)); - allClassesNode.getArrayItem().getArrayItem().addConsumer(new OneDirectionalConnection(allClassesNode)); } private static class OneDirectionalConnection implements DependencyConsumer { @@ -55,6 +53,7 @@ public class JavaScriptBodyDependency implements DependencyListener { MethodHolder method = cls.getMethod(methodRef.getDescriptor()); AnnotationReader annot = method.getAnnotations().get(JavaScriptBody.class.getName()); if (annot != null) { + includeDefaultDependencies(dependencyChecker); AnnotationValue javacall = annot.getValue("javacall"); MethodGraph graph = dependencyChecker.attachMethodGraph(methodRef); if (graph.getResult() != null) { @@ -73,19 +72,15 @@ public class JavaScriptBodyDependency implements DependencyListener { String body = annot.getValue("body").getString(); new GeneratorJsCallback(dependencyChecker.getClassSource(), dependencyChecker).parse(body); } - for (int i = 0; i < methodRef.parameterCount(); ++i) { - ValueType type = methodRef.getDescriptor().parameterType(i); - if (type.isObject("java.lang.Object")) { - MethodGraph convGraph = dependencyChecker.attachMethodGraph(new MethodReference( - JavaScriptBodyConverter.class.getName(), - new MethodDescriptor("toJavaScript", ValueType.object("java.lang.Object"), - ValueType.object("java.lang.Object")))); - graph.getVariable(i + 1).connect(convGraph.getVariable(i + 1)); - } - } } } + private void includeDefaultDependencies(DependencyChecker dependencyChecker) { + dependencyChecker.attachMethodGraph(JavaScriptBodyConverterGenerator.fromJsMethod); + dependencyChecker.attachMethodGraph(JavaScriptBodyConverterGenerator.toJsMethod); + dependencyChecker.attachMethodGraph(JavaScriptBodyConverterGenerator.intValueMethod); + } + @Override public void fieldAchieved(DependencyChecker dependencyChecker, FieldReference field) { } diff --git a/teavm-html4j/src/main/java/org/teavm/html4j/JavaScriptBodyGenerator.java b/teavm-html4j/src/main/java/org/teavm/html4j/JavaScriptBodyGenerator.java index 9a7c6d512..88c7677b2 100644 --- a/teavm-html4j/src/main/java/org/teavm/html4j/JavaScriptBodyGenerator.java +++ b/teavm-html4j/src/main/java/org/teavm/html4j/JavaScriptBodyGenerator.java @@ -41,7 +41,7 @@ public class JavaScriptBodyGenerator implements Generator { GeneratorJsCallback callbackGen = new GeneratorJsCallback(context.getClassSource(), writer.getNaming()); body = callbackGen.parse(body); } - writer.append("return (function("); + writer.append("var result = (function("); for (int i = 0; i < args.size(); ++i) { if (i > 0) { writer.append(",").ws(); @@ -55,14 +55,24 @@ public class JavaScriptBodyGenerator implements Generator { writer.append(",").ws(); wrapParameter(writer, methodRef.getDescriptor().parameterType(i), context.getParameterName(i + 1)); } - writer.append(");").softNewLine(); + writer.append(")").softNewLine(); + writer.append("return "); + unwrapValue(writer, method.getResultType(), "result"); + writer.append(";").softNewLine(); } private void wrapParameter(SourceWriter writer, ValueType type, String param) throws IOException { if (type.isObject("java.lang.Object")) { - writer.appendMethodBody(new MethodReference(JavaScriptBodyConverter.class.getName(), - new MethodDescriptor("toJavaScript", ValueType.object("java.lang.Object"), - ValueType.object("java.lang.Object")))); + writer.appendMethodBody(JavaScriptBodyConverterGenerator.toJsMethod); + writer.append("(").append(param).append(")"); + } else { + writer.append(param); + } + } + + private void unwrapValue(SourceWriter writer, ValueType type, String param) throws IOException { + if (type.isObject("java.lang.Object")) { + writer.appendMethodBody(JavaScriptBodyConverterGenerator.fromJsMethod); writer.append("(").append(param).append(")"); } else { writer.append(param); diff --git a/teavm-html4j/src/test/java/org/teavm/html4j/test/JavaScriptBodyTests.java b/teavm-html4j/src/test/java/org/teavm/html4j/test/JavaScriptBodyTests.java index 30e96d3cb..a49ab769a 100644 --- a/teavm-html4j/src/test/java/org/teavm/html4j/test/JavaScriptBodyTests.java +++ b/teavm-html4j/src/test/java/org/teavm/html4j/test/JavaScriptBodyTests.java @@ -49,15 +49,6 @@ public class JavaScriptBodyTests { assertEquals(23, array[0].foo()); } - @Test - public void dependencyPropagatedBackThroughArray() { - A[] first = new A[1]; - storeObject(first); - Object[] second = (Object[])retrieveObject(); - second[0] = new AImpl(); - assertEquals(23, first[0].foo()); - } - @Test public void valuePropagatedToCallback() { A a = new AImpl();