From 3f58e3b24f0e235777a82a5fc08ee69c1506e25d Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Wed, 11 May 2016 21:15:36 +0300 Subject: [PATCH 1/5] When name of method parameter is not an identifier, mangle it to contain only Java identifier character --- core/src/main/java/org/teavm/javascript/Renderer.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/org/teavm/javascript/Renderer.java b/core/src/main/java/org/teavm/javascript/Renderer.java index 289fca789..1d7f4867c 100644 --- a/core/src/main/java/org/teavm/javascript/Renderer.java +++ b/core/src/main/java/org/teavm/javascript/Renderer.java @@ -1245,12 +1245,21 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext List nameList = new ArrayList<>(names); Collections.sort(nameList); for (String name : nameList) { - sb.append('_').append(name); + sb.append('_').append(escapeName(name)); } } return sb.toString(); } + private static String escapeName(String name) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < name.length(); ++i) { + char c = name.charAt(i); + sb.append(Character.isJavaIdentifierPart(c) ? c : '_'); + } + return sb.toString(); + } + private String pointerName() { return minifying ? "$p" : "$ptr"; } From 88a1a39301f99d8d55e38c399bc5adb00865bf2b Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Wed, 11 May 2016 21:16:01 +0300 Subject: [PATCH 2/5] Add PrintStream methods --- .../teavm/classlib/java/io/TPrintStream.java | 28 +++++++++++++------ 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/classlib/src/main/java/org/teavm/classlib/java/io/TPrintStream.java b/classlib/src/main/java/org/teavm/classlib/java/io/TPrintStream.java index 417f9376c..0d297640c 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/io/TPrintStream.java +++ b/classlib/src/main/java/org/teavm/classlib/java/io/TPrintStream.java @@ -167,13 +167,28 @@ public class TPrintStream extends TFilterOutputStream { printSB(); } - public void println(int i) { - sb.append(i).append('\n'); + public void print(long l) { + sb.append(l); printSB(); } - public void print(long l) { - sb.append(l); + public void print(double d) { + sb.append(d); + printSB(); + } + + public void print(TString s) { + sb.append(s); + printSB(); + } + + public void print(TObject s) { + sb.append(s); + printSB(); + } + + public void println(int i) { + sb.append(i).append('\n'); printSB(); } @@ -187,11 +202,6 @@ public class TPrintStream extends TFilterOutputStream { printSB(); } - public void print(TString s) { - sb.append(s); - printSB(); - } - public void println(TString s) { sb.append(s).append('\n'); printSB(); From 062f30634c70efed4d6924e217537ebe0d588b2d Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Wed, 11 May 2016 22:05:50 +0300 Subject: [PATCH 3/5] Fix support of SWAP instruction --- .../java/org/teavm/parsing/ProgramParser.java | 29 ++++++++++--------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/core/src/main/java/org/teavm/parsing/ProgramParser.java b/core/src/main/java/org/teavm/parsing/ProgramParser.java index 3addd6f11..27a0e1825 100644 --- a/core/src/main/java/org/teavm/parsing/ProgramParser.java +++ b/core/src/main/java/org/teavm/parsing/ProgramParser.java @@ -28,10 +28,10 @@ import org.teavm.model.util.ProgramUtils; * @author Alexey Andreev */ public class ProgramParser implements VariableDebugInformation { - static final byte ROOT = 0; - static final byte SINGLE = 1; - static final byte DOUBLE_FIRST_HALF = 2; - static final byte DOUBLE_SECOND_HALF = 3; + private static final byte ROOT = 0; + private static final byte SINGLE = 1; + private static final byte DOUBLE_FIRST_HALF = 2; + private static final byte DOUBLE_SECOND_HALF = 3; private String fileName; private StackFrame[] stackBefore; private StackFrame[] stackAfter; @@ -60,17 +60,17 @@ public class ProgramParser implements VariableDebugInformation { } private static class StackFrame { - public final StackFrame next; - public final byte type; - public final int depth; + final StackFrame next; + final byte type; + final int depth; - public StackFrame(int depth) { + StackFrame(int depth) { this.next = null; this.type = ROOT; this.depth = depth; } - public StackFrame(StackFrame next, byte type) { + StackFrame(StackFrame next, byte type) { this.next = next; this.type = type; this.depth = next != null ? next.depth + 1 : 0; @@ -162,7 +162,7 @@ public class ProgramParser implements VariableDebugInformation { @Override public Map getDebugNames(Instruction insn) { Map map = variableDebugNames.get(insn); - return map != null ? Collections.unmodifiableMap(map) : Collections.emptyMap(); + return map != null ? Collections.unmodifiableMap(map) : Collections.emptyMap(); } private void prepare(MethodNode method) { @@ -513,8 +513,8 @@ public class ProgramParser implements VariableDebugInformation { } insn.setMethod(new MethodDescriptor(name, MethodDescriptor.parseSignature(desc))); - for (int i = 0; i < bsmArgs.length; ++i) { - insn.getBootstrapArguments().add(convertConstant(bsmArgs[i])); + for (Object bsmArg : bsmArgs) { + insn.getBootstrapArguments().add(convertConstant(bsmArg)); } addInstruction(insn); @@ -1200,8 +1200,9 @@ public class ProgramParser implements VariableDebugInformation { case Opcodes.SWAP: { int b = popSingle(); int a = popSingle(); - int tmp = pushSingle(); pushSingle(); + pushSingle(); + int tmp = b + 1; emitAssignInsn(a, tmp); emitAssignInsn(b, a); emitAssignInsn(tmp, b); @@ -1726,7 +1727,7 @@ public class ProgramParser implements VariableDebugInformation { } }; - static MethodHandle parseHandle(Handle handle) { + private static MethodHandle parseHandle(Handle handle) { switch (handle.getTag()) { case Opcodes.H_GETFIELD: return MethodHandle.fieldGetter(handle.getOwner().replace('/', '.'), handle.getName(), From 02f414b61a3246450e805c1e8fd2ba90d5cc8f3e Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Thu, 12 May 2016 22:25:31 +0300 Subject: [PATCH 4/5] Speed up allocation of objects and arrays --- .../org/teavm/classlib/java/lang/TObject.java | 6 +- .../java/org/teavm/javascript/Renderer.java | 5 ++ .../resources/org/teavm/javascript/runtime.js | 57 ++++++++++++------- .../java/org/teavm/platform/Platform.java | 5 +- 4 files changed, 49 insertions(+), 24 deletions(-) diff --git a/classlib/src/main/java/org/teavm/classlib/java/lang/TObject.java b/classlib/src/main/java/org/teavm/classlib/java/lang/TObject.java index 1a7f95785..d58d1dbed 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/lang/TObject.java +++ b/classlib/src/main/java/org/teavm/classlib/java/lang/TObject.java @@ -21,6 +21,7 @@ import org.teavm.javascript.spi.Superclass; import org.teavm.javascript.spi.Sync; import org.teavm.jso.browser.TimerHandler; import org.teavm.platform.Platform; +import org.teavm.platform.PlatformObject; import org.teavm.platform.PlatformQueue; import org.teavm.platform.PlatformRunnable; import org.teavm.platform.async.AsyncCallback; @@ -168,7 +169,6 @@ public class TObject { @Rename("") private void init() { - Platform.getPlatformObject(this).setId(Platform.nextObjectId()); } @Rename("getClass") @@ -192,6 +192,10 @@ public class TObject { } int identity() { + PlatformObject platformThis = Platform.getPlatformObject(this); + if (platformThis.getId() == 0) { + platformThis.setId(Platform.nextObjectId()); + } return Platform.getPlatformObject(this).getId(); } diff --git a/core/src/main/java/org/teavm/javascript/Renderer.java b/core/src/main/java/org/teavm/javascript/Renderer.java index 1d7f4867c..a97fb0524 100644 --- a/core/src/main/java/org/teavm/javascript/Renderer.java +++ b/core/src/main/java/org/teavm/javascript/Renderer.java @@ -390,6 +390,11 @@ public class Renderer implements ExprVisitor, StatementVisitor, RenderingContext .append("=").ws().append(constantToString(value)).append(";").softNewLine(); debugEmitter.addField(field.getName(), naming.getNameFor(fieldRef)); } + + if (cls.getName().equals("java.lang.Object")) { + writer.append("this.$id").ws().append('=').ws().append("0;").softNewLine(); + } + writer.outdent().append("}").newLine(); for (FieldNode field : staticFields) { diff --git a/core/src/main/resources/org/teavm/javascript/runtime.js b/core/src/main/resources/org/teavm/javascript/runtime.js index ef6b592a6..41dbb0eea 100644 --- a/core/src/main/resources/org/teavm/javascript/runtime.js +++ b/core/src/main/resources/org/teavm/javascript/runtime.js @@ -14,9 +14,15 @@ * limitations under the License. */ "use strict"; -var $rt_lastObjectId = 0; +var $rt_lastObjectId = 1; function $rt_nextId() { - return $rt_lastObjectId++; + var current = $rt_lastObjectId; + var next = (current + 1) | 0; + if (next === 0) { + next = (next + 1) | 0; + } + $rt_lastObjectId = next; + return current; } function $rt_compare(a, b) { return a > b ? 1 : a < b ? -1 : 0; @@ -39,14 +45,17 @@ function $rt_isAssignable(from, to) { function $rt_createArray(cls, sz) { var data = new Array(sz); var arr = new ($rt_arraycls(cls))(data); - for (var i = 0; i < sz; i = (i + 1) | 0) { - data[i] = null; + if (sz > 0) { + var i = 0; + do { + data[i] = null; + i = (i + 1) | 0; + } while (i < sz); } return arr; } function $rt_wrapArray(cls, data) { - var arr = new ($rt_arraycls(cls))(data); - return arr; + return new ($rt_arraycls(cls))(data); } function $rt_createUnfilledArray(cls, sz) { return new ($rt_arraycls(cls))(new Array(sz)); @@ -67,7 +76,7 @@ var $rt_createIntArray; var $rt_createBooleanArray; var $rt_createFloatArray; var $rt_createDoubleArray; -if (ArrayBuffer) { +if (typeof 'ArrayBuffer' !== 'undefined') { $rt_createNumericArray = function(cls, nativeArray) { return new ($rt_arraycls(cls))(nativeArray); }; @@ -110,10 +119,11 @@ if (ArrayBuffer) { $rt_createCharArray = function(sz) { return $rt_createNumericArray($rt_charcls(), sz); } } function $rt_arraycls(cls) { - if (typeof cls.$array === 'undefined') { + var result = cls.$array; + if (result === null) { var arraycls = function(data) { this.data = data; - this.$id = $rt_nextId(); + this.$id = 0; }; arraycls.prototype = new ($rt_objcls())(); arraycls.prototype.constructor = arraycls; @@ -132,12 +142,15 @@ function $rt_arraycls(cls) { arraycls.$meta = { item : cls, supertypes : [$rt_objcls()], primitive : false, superclass : $rt_objcls(), name : name, binaryName : name, enum : false }; arraycls.classObject = null; + arraycls.$array = null; + result = arraycls; cls.$array = arraycls; } - return cls.$array; + return result; } function $rt_createcls() { return { + $array : null, classObject : null, $meta : { supertypes : [], @@ -228,7 +241,7 @@ function $rt_throw(ex) { function $rt_exception(ex) { var err = ex.$jsException; if (!err) { - var err = new Error("Java exception thrown"); + err = new Error("Java exception thrown"); err.$javaException = ex; ex.$jsException = err; } @@ -363,7 +376,7 @@ function $rt_putStderr(ch) { } function $rt_metadata(data) { for (var i = 0; i < data.length; i += 8) { - var cls = data[i + 0]; + var cls = data[i]; cls.$meta = {}; var m = cls.$meta; m.name = data[i + 1]; @@ -402,8 +415,8 @@ function $rt_metadata(data) { } var virtualMethods = data[i + 7]; - for (var j = 0; j < virtualMethods.length; j += 2) { - var name = virtualMethods[j + 0]; + for (j = 0; j < virtualMethods.length; j += 2) { + var name = virtualMethods[j]; var func = virtualMethods[j + 1]; if (typeof name === 'string') { name = [name]; @@ -412,6 +425,8 @@ function $rt_metadata(data) { cls.prototype[name[k]] = func; } } + + cls.$array = null; } } function $rt_threadStarter(f) { @@ -681,7 +696,7 @@ function Long_compare(a, b) { if (r !== 0) { return r; } - var r = (a.lo >>> 1) - (b.lo >>> 1); + r = (a.lo >>> 1) - (b.lo >>> 1); if (r !== 0) { return r; } @@ -895,15 +910,15 @@ function LongInt_ucompare(a, b) { if (r != 0) { return r; } - var r = (a.hi >>> 1) - (b.hi >>> 1); + r = (a.hi >>> 1) - (b.hi >>> 1); if (r != 0) { return r; } - var r = (a.hi & 1) - (b.hi & 1); + r = (a.hi & 1) - (b.hi & 1); if (r != 0) { return r; } - var r = (a.lo >>> 1) - (b.lo >>> 1); + r = (a.lo >>> 1) - (b.lo >>> 1); if (r != 0) { return r; } @@ -924,7 +939,8 @@ function LongInt_numOfLeadingZeroBits(a) { function LongInt_shl(a, b) { if (b == 0) { return; - } else if (b < 32) { + } + if (b < 32) { a.sup = ((a.hi >>> (32 - b)) | (a.sup << b)) & 0xFFFF; a.hi = (a.lo >>> (32 - b)) | (a.hi << b); a.lo <<= b; @@ -949,7 +965,8 @@ function LongInt_shl(a, b) { function LongInt_shr(a, b) { if (b == 0) { return; - } else if (b == 32) { + } + if (b == 32) { a.lo = a.hi; a.hi = a.sup; a.sup = 0; diff --git a/platform/src/main/java/org/teavm/platform/Platform.java b/platform/src/main/java/org/teavm/platform/Platform.java index abf5483b6..7cfa01ffc 100644 --- a/platform/src/main/java/org/teavm/platform/Platform.java +++ b/platform/src/main/java/org/teavm/platform/Platform.java @@ -74,9 +74,8 @@ public final class Platform { return (PlatformConsole) Window.current(); } - public static int nextObjectId() { - return ((PlatformHelper) Window.current()).nextId(); - } + @JSBody(params = {}, script = "return $rt_nextId();") + public static native int nextObjectId(); public static T newInstance(PlatformClass cls) { prepareNewInstance(); From 9942f8b0487ea7ff673b24f9ae7743698cbacdb1 Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Thu, 12 May 2016 22:26:54 +0300 Subject: [PATCH 5/5] Fix type of HTMLElement.getInnerHTML. Fix https://github.com/konsoletyper/teavm/issues/189 --- jso/apis/src/main/java/org/teavm/jso/dom/html/HTMLElement.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jso/apis/src/main/java/org/teavm/jso/dom/html/HTMLElement.java b/jso/apis/src/main/java/org/teavm/jso/dom/html/HTMLElement.java index 54e5674e9..6b57bee00 100644 --- a/jso/apis/src/main/java/org/teavm/jso/dom/html/HTMLElement.java +++ b/jso/apis/src/main/java/org/teavm/jso/dom/html/HTMLElement.java @@ -110,7 +110,7 @@ public interface HTMLElement extends Element, ElementCSSInlineStyle, EventTarget HTMLDocument getOwnerDocument(); @JSProperty - int getInnerHTML(); + String getInnerHTML(); @JSProperty void setInnerHTML(String content);