From 8a423c0d4f658fa2e66aced1c7ecafe31f3dc4e8 Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Sun, 9 Feb 2014 14:27:32 +0400 Subject: [PATCH] Adds support of *functors*. Adds benchmark from bck2brwsr --- .../java/lang/SystemNativeGenerator.java | 7 + .../java/lang/TAbstractStringBuilder.java | 10 +- .../teavm/classlib/java/lang/TAppendable.java | 30 ++++ .../classlib/java/lang/TStringBuilder.java | 2 +- .../org/teavm/classlib/java/lang/TSystem.java | 3 + .../javascript/JavascriptNativeProcessor.java | 30 +++- .../NativeJavascriptClassRepository.java | 15 ++ .../main/java/org/teavm/javascript/ni/JS.java | 3 + .../javascript/ni/JSNativeGenerator.java | 15 ++ .../javascript/ni/PreserveOriginalName.java | 15 ++ .../org/teavm/dom/browser/TimerHandler.java | 28 ++++ .../teavm/dom/{core => browser}/Window.java | 12 +- teavm-samples/pom.xml | 17 ++- .../java/org/teavm/samples/HelloWorld.java | 2 +- .../main/java/org/teavm/samples/Matrix.java | 128 ++++++++++++++++++ .../teavm/samples/MatrixMultiplication.java | 47 +++++++ 16 files changed, 353 insertions(+), 11 deletions(-) create mode 100644 teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TAppendable.java create mode 100644 teavm-dom/src/main/java/org/teavm/dom/browser/TimerHandler.java rename teavm-dom/src/main/java/org/teavm/dom/{core => browser}/Window.java (77%) create mode 100644 teavm-samples/src/main/java/org/teavm/samples/Matrix.java create mode 100644 teavm-samples/src/main/java/org/teavm/samples/MatrixMultiplication.java diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/SystemNativeGenerator.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/SystemNativeGenerator.java index 9b917700c..9a4401d8c 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/SystemNativeGenerator.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/SystemNativeGenerator.java @@ -36,6 +36,9 @@ public class SystemNativeGenerator implements Generator, DependencyPlugin { case "doArrayCopy": generateArrayCopy(context, writer); break; + case "currentTimeMillis": + generateCurrentTimeMillis(writer); + break; } } @@ -59,6 +62,10 @@ public class SystemNativeGenerator implements Generator, DependencyPlugin { writer.outdent().append("}").softNewLine(); } + private void generateCurrentTimeMillis(SourceWriter writer) throws IOException { + writer.append("return Long_fromNumber(new Date().getTime());").softNewLine(); + } + private void achieveArrayCopy(DependencyChecker checker, MethodReference method) { MethodGraph graph = checker.attachMethodGraph(method); DependencyNode src = graph.getVariableNode(1); diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TAbstractStringBuilder.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TAbstractStringBuilder.java index 61b1c1565..8e3bb6d65 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TAbstractStringBuilder.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TAbstractStringBuilder.java @@ -162,9 +162,9 @@ class TAbstractStringBuilder extends TObject implements TSerializable, TCharSequ return this; } else if (TFloat.isInfinite(value)) { if (value > 0) { - ensureCapacity(8); + ensureCapacity(length + 8); } else { - ensureCapacity(9); + ensureCapacity(length + 9); buffer[length++] = '-'; } buffer[length++] = 'I'; @@ -306,9 +306,9 @@ class TAbstractStringBuilder extends TObject implements TSerializable, TCharSequ return this; } else if (TDouble.isInfinite(value)) { if (value > 0) { - ensureCapacity(8); + ensureCapacity(length + 8); } else { - ensureCapacity(9); + ensureCapacity(length + 9); buffer[length++] = '-'; } buffer[length++] = 'I'; @@ -531,7 +531,7 @@ class TAbstractStringBuilder extends TObject implements TSerializable, TCharSequ if (start > end || end > s.length() || start < 0) { throw new TIndexOutOfBoundsException(); } - ensureCapacity(end - start); + ensureCapacity(end - start + length); for (int i = start; i < end; ++i) { buffer[length++] = s.charAt(i); } diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TAppendable.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TAppendable.java new file mode 100644 index 000000000..3e28d7388 --- /dev/null +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TAppendable.java @@ -0,0 +1,30 @@ +/* + * 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.classlib.java.lang; + +import org.teavm.classlib.java.io.TIOException; + +/** + * + * @author Alexey Andreev + */ +public interface TAppendable { + TAppendable append(TCharSequence csq) throws TIOException; + + TAppendable append(TCharSequence csq, int start, int end) throws TIOException; + + TAppendable append(char c) throws TIOException; +} diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TStringBuilder.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TStringBuilder.java index f3e0e8eee..017be86fb 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TStringBuilder.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TStringBuilder.java @@ -19,7 +19,7 @@ package org.teavm.classlib.java.lang; * * @author Alexey Andreev */ -public class TStringBuilder extends TAbstractStringBuilder { +public class TStringBuilder extends TAbstractStringBuilder implements TAppendable { public TStringBuilder(int capacity) { super(capacity); } diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TSystem.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TSystem.java index 70e66aafe..7fb6eb876 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TSystem.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TSystem.java @@ -46,4 +46,7 @@ public final class TSystem extends TObject { @GeneratedBy(SystemNativeGenerator.class) private static native void doArrayCopy(Object src, int srcPos, Object dest, int destPos, int length); + + @GeneratedBy(SystemNativeGenerator.class) + public static native long currentTimeMillis(); } diff --git a/teavm-core/src/main/java/org/teavm/javascript/JavascriptNativeProcessor.java b/teavm-core/src/main/java/org/teavm/javascript/JavascriptNativeProcessor.java index b40fedb49..2ec035ff5 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/JavascriptNativeProcessor.java +++ b/teavm-core/src/main/java/org/teavm/javascript/JavascriptNativeProcessor.java @@ -132,7 +132,7 @@ class JavascriptNativeProcessor { newInvoke.getArguments().add(invoke.getInstance()); newInvoke.getArguments().add(addStringWrap(addString(method.getName()))); for (int k = 0; k < invoke.getArguments().size(); ++k) { - Variable arg = wrap(invoke.getArguments().get(k), method.parameterType(k)); + Variable arg = wrapArgument(invoke.getArguments().get(k), method.parameterType(k)); newInvoke.getArguments().add(arg); } replacement.add(newInvoke); @@ -265,6 +265,34 @@ class JavascriptNativeProcessor { return result; } + private Variable wrapArgument(Variable var, ValueType type) { + if (type instanceof ValueType.Object) { + String className = ((ValueType.Object)type).getClassName(); + ClassHolder cls = classSource.getClassHolder(className); + if (cls.getAnnotations().get(JSFunctor.class.getName()) != null) { + return wrapFunctor(var, cls); + } + } + return wrap(var, type); + } + + private Variable wrapFunctor(Variable var, ClassHolder type) { + if (!type.hasModifier(ElementModifier.INTERFACE) || type.getMethods().size() != 1) { + throw new RuntimeException("Wrong functor: " + type.getName()); + } + String name = type.getMethods().iterator().next().getName(); + Variable functor = program.createVariable(); + Variable nameVar = addString(name); + InvokeInstruction insn = new InvokeInstruction(); + insn.setMethod(new MethodReference(JS.class.getName(), new MethodDescriptor("function", + ValueType.object(JSObject.class.getName()), ValueType.object(JSObject.class.getName()), + ValueType.object(JSObject.class.getName())))); + insn.setReceiver(functor); + insn.getArguments().add(var); + insn.getArguments().add(nameVar); + return functor; + } + private Variable wrap(Variable var, ValueType type) { if (type instanceof ValueType.Object) { String className = ((ValueType.Object)type).getClassName(); diff --git a/teavm-core/src/main/java/org/teavm/javascript/NativeJavascriptClassRepository.java b/teavm-core/src/main/java/org/teavm/javascript/NativeJavascriptClassRepository.java index 1b69c98b1..43e2635c1 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/NativeJavascriptClassRepository.java +++ b/teavm-core/src/main/java/org/teavm/javascript/NativeJavascriptClassRepository.java @@ -1,3 +1,18 @@ +/* + * 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.javascript; import java.util.HashMap; diff --git a/teavm-core/src/main/java/org/teavm/javascript/ni/JS.java b/teavm-core/src/main/java/org/teavm/javascript/ni/JS.java index c08fcf3b6..d2612de18 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/ni/JS.java +++ b/teavm-core/src/main/java/org/teavm/javascript/ni/JS.java @@ -188,4 +188,7 @@ public final class JS { @InjectedBy(JSNativeGenerator.class) public static native void set(JSObject instance, JSObject index, JSObject obj); + + @InjectedBy(JSNativeGenerator.class) + public static native JSObject function(JSObject instance, JSObject property); } diff --git a/teavm-core/src/main/java/org/teavm/javascript/ni/JSNativeGenerator.java b/teavm-core/src/main/java/org/teavm/javascript/ni/JSNativeGenerator.java index 698064309..ca7fba5d4 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/ni/JSNativeGenerator.java +++ b/teavm-core/src/main/java/org/teavm/javascript/ni/JSNativeGenerator.java @@ -90,6 +90,9 @@ public class JSNativeGenerator implements Generator, Injector, DependencyPlugin case "unwrap": context.writeExpr(context.getArgument(0)); break; + case "function": + generateFunction(context); + break; } } @@ -125,6 +128,18 @@ public class JSNativeGenerator implements Generator, Injector, DependencyPlugin writer.append("return result;").softNewLine(); } + private void generateFunction(InjectorContext context) throws IOException { + SourceWriter writer = context.getWriter(); + writer.append("(function()").ws().append("{").indent().softNewLine(); + writer.append("return "); + context.writeExpr(context.getArgument(1)); + renderProperty(context.getArgument(2), context); + writer.append(".apply("); + context.writeExpr(context.getArgument(1)); + writer.append(",").ws().append("arguments);").softNewLine(); + writer.outdent().append("})"); + } + private void renderProperty(Expr property, InjectorContext context) throws IOException { SourceWriter writer = context.getWriter(); String name = extractPropertyName(property); diff --git a/teavm-core/src/main/java/org/teavm/javascript/ni/PreserveOriginalName.java b/teavm-core/src/main/java/org/teavm/javascript/ni/PreserveOriginalName.java index 5a787aadf..dcc53a109 100644 --- a/teavm-core/src/main/java/org/teavm/javascript/ni/PreserveOriginalName.java +++ b/teavm-core/src/main/java/org/teavm/javascript/ni/PreserveOriginalName.java @@ -1,3 +1,18 @@ +/* + * 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.javascript.ni; import java.lang.annotation.ElementType; diff --git a/teavm-dom/src/main/java/org/teavm/dom/browser/TimerHandler.java b/teavm-dom/src/main/java/org/teavm/dom/browser/TimerHandler.java new file mode 100644 index 000000000..fa6576cf5 --- /dev/null +++ b/teavm-dom/src/main/java/org/teavm/dom/browser/TimerHandler.java @@ -0,0 +1,28 @@ +/* + * 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.dom.browser; + +import org.teavm.javascript.ni.JSFunctor; +import org.teavm.javascript.ni.JSObject; + +/** + * + * @author Alexey Andreev + */ +@JSFunctor +public interface TimerHandler extends JSObject { + void onTimer(); +} diff --git a/teavm-dom/src/main/java/org/teavm/dom/core/Window.java b/teavm-dom/src/main/java/org/teavm/dom/browser/Window.java similarity index 77% rename from teavm-dom/src/main/java/org/teavm/dom/core/Window.java rename to teavm-dom/src/main/java/org/teavm/dom/browser/Window.java index 886ad94a8..bff2e1f7e 100644 --- a/teavm-dom/src/main/java/org/teavm/dom/core/Window.java +++ b/teavm-dom/src/main/java/org/teavm/dom/browser/Window.java @@ -13,8 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.teavm.dom.core; +package org.teavm.dom.browser; +import org.teavm.dom.core.Document; +import org.teavm.dom.core.Element; import org.teavm.javascript.ni.JSGlobal; import org.teavm.javascript.ni.JSObject; import org.teavm.javascript.ni.JSProperty; @@ -33,4 +35,12 @@ public interface Window extends JSGlobal { void alert(JSObject message); void alert(String message); + + int setTimeout(TimerHandler handler, int delay); + + void clearTimeout(int timeoutId); + + int setInterval(TimerHandler handler, int delay); + + void clearInterval(int timeoutId); } diff --git a/teavm-samples/pom.xml b/teavm-samples/pom.xml index 44aef862b..7d0a7ed4c 100644 --- a/teavm-samples/pom.xml +++ b/teavm-samples/pom.xml @@ -51,7 +51,7 @@ - generate-javascript + generate-hello build-javascript @@ -60,7 +60,20 @@ false org.teavm.samples.HelloWorld true - false + ${project.build.directory}/javascript/hello + + + + generate-matrix + + build-javascript + + process-classes + + false + org.teavm.samples.MatrixMultiplication + true + ${project.build.directory}/javascript/matrix diff --git a/teavm-samples/src/main/java/org/teavm/samples/HelloWorld.java b/teavm-samples/src/main/java/org/teavm/samples/HelloWorld.java index 077886832..dc0236720 100644 --- a/teavm-samples/src/main/java/org/teavm/samples/HelloWorld.java +++ b/teavm-samples/src/main/java/org/teavm/samples/HelloWorld.java @@ -15,9 +15,9 @@ */ package org.teavm.samples; +import org.teavm.dom.browser.Window; import org.teavm.dom.core.Document; import org.teavm.dom.core.Element; -import org.teavm.dom.core.Window; import org.teavm.dom.events.Event; import org.teavm.dom.events.EventListener; import org.teavm.dom.events.EventTarget; diff --git a/teavm-samples/src/main/java/org/teavm/samples/Matrix.java b/teavm-samples/src/main/java/org/teavm/samples/Matrix.java new file mode 100644 index 000000000..650baca5e --- /dev/null +++ b/teavm-samples/src/main/java/org/teavm/samples/Matrix.java @@ -0,0 +1,128 @@ +/* + * 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. + */ +// This file is based on the original source code from Bck2Brwsr +/** + * Back 2 Browser Bytecode Translator + * Copyright (C) 2012 Jaroslav Tulach + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. Look for COPYING file in the top folder. + * If not, see http://opensource.org/licenses/GPL-2.0. + */ +package org.teavm.samples; + +import java.io.IOException; +import java.util.Arrays; + +/** + * + * @author Alexey Andreev + */ +public class Matrix { + private final int rank; + private final float data[][]; + + public Matrix(int r) { + this(r, new float[r][r]); + } + + private Matrix(int r, float[][] data) { + this.rank = r; + this.data = data; + } + + public void setElement(int i, int j, float value) { + data[i][j] = value; + } + public float getElement(int i, int j) { + return data[i][j]; + } + + public void generateData() { + //final Random rand = new Random(); + //final int x = 10; + for (int i = 0; i < rank; i++) { + for (int j = 0; j < rank; j++) { + data[i][j] = 1 / (1 + i + j); + } + } + } + + public Matrix multiply(Matrix m) { + if (rank != m.rank) { + throw new IllegalArgumentException("Rank doesn't match"); + } + + final float res[][] = new float[rank][rank]; + for (int i = 0; i < rank; i++) { + for (int j = 0; j < rank; j++) { + float ij = 0; + for (int q = 0; q < rank; q++) { + ij += data[i][q] * m.data[q][j]; + } + res[i][j] = ij; + } + } + return new Matrix(rank, res); + } + + public void printOn(Appendable s) throws IOException { + for (int i = 0; i < rank; i++) { + String sep = ""; + for (int j = 0; j < rank; j++) { + s.append(sep + data[i][j]); + sep = " "; + } + s.append("\n"); + } + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof Matrix) { + Matrix snd = (Matrix)obj; + if (snd.rank != rank) { + return false; + } + for (int i = 0; i < rank; i++) { + for (int j = 0; j < rank; j++) { + if (data[i][j] != snd.data[i][j]) { + return false; + } + } + } + return true; + } + return false; + } + + @Override + public int hashCode() { + int hash = 3; + hash = 97 * hash + this.rank; + hash = 97 * hash + Arrays.deepHashCode(this.data); + return hash; + } +} diff --git a/teavm-samples/src/main/java/org/teavm/samples/MatrixMultiplication.java b/teavm-samples/src/main/java/org/teavm/samples/MatrixMultiplication.java new file mode 100644 index 000000000..5f917be4a --- /dev/null +++ b/teavm-samples/src/main/java/org/teavm/samples/MatrixMultiplication.java @@ -0,0 +1,47 @@ +/* + * 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.samples; + +import java.io.IOException; + +/** + * + * @author Alexey Andreev + */ +public class MatrixMultiplication { + public static void main(String[] args) throws IOException { + for (int k = 0; k < 100; ++k) { + long startTime = System.currentTimeMillis(); + + Matrix m1 = new Matrix(5); + Matrix m2 = new Matrix(5); + + m1.generateData(); + m2.generateData(); + + Matrix res = null; + for (int i = 0; i < 10000; i++) { + res = m1.multiply(m2); + m1 = res; + } + StringBuilder sb = new StringBuilder(); + res.printOn(sb); + long timeSpent = System.currentTimeMillis() - startTime; + System.out.println(sb.toString()); + System.out.println("Time spent: " + timeSpent); + } + } +}