Long arithmetic prototype, Long currently represented by separate JavaScript object with two JS-Numbers.
Just few operation implemented to pass tests. Tests under vmtest directory are still failing.
1.1 --- a/emul/src/main/resources/org/apidesign/vm4brwsr/emul/java_lang_Number.js Mon Jan 21 15:57:01 2013 +0100
1.2 +++ b/emul/src/main/resources/org/apidesign/vm4brwsr/emul/java_lang_Number.js Fri Jan 25 11:00:52 2013 +0100
1.3 @@ -6,4 +6,66 @@
1.4 };
1.5
1.6 Number.prototype.toInt8 = function() { return (this << 24) >> 24; };
1.7 -Number.prototype.toInt16 = function() { return (this << 16) >> 16; };
1.8 \ No newline at end of file
1.9 +Number.prototype.toInt16 = function() { return (this << 16) >> 16; };
1.10 +
1.11 +var Long = function(low, hi) {
1.12 + this.low = low;
1.13 + this.hi = hi;
1.14 +};
1.15 +
1.16 +function LongFromNumber(x) {
1.17 + return new Long(x % 0xFFFFFFFF, Math.floor(x / 0xFFFFFFFF));
1.18 +};
1.19 +
1.20 +function MakeLong(x) {
1.21 + if ((x.hi == undefined) && (x.low == undefined)) {
1.22 + return LongFromNumber(x);
1.23 + }
1.24 + return x;
1.25 +};
1.26 +
1.27 +Long.prototype.toInt32 = function() { return this.low | 0; };
1.28 +Long.prototype.toFP = function() { return this.hi * 0xFFFFFFFF + this.low; };
1.29 +
1.30 +Long.prototype.toString = function() {
1.31 + return String(this.toFP());
1.32 +};
1.33 +
1.34 +Long.prototype.valueOf = function() {
1.35 + return this.toFP();
1.36 +};
1.37 +
1.38 +Long.prototype.compare64 = function(x) {
1.39 + if (this.hi == x.hi) {
1.40 + return (this.low == x.low) ? 0 : ((this.low < x.low) ? -1 : 1);
1.41 + }
1.42 + return (this.hi < x.hi) ? -1 : 1;
1.43 +};
1.44 +
1.45 +Long.prototype.add64 = function(x) {
1.46 + low = this.low + x.low;
1.47 + carry = 0;
1.48 + if (low > 0xFFFFFFFF) {
1.49 + carry = 1;
1.50 + low -= 0xFFFFFFFF;
1.51 + }
1.52 + hi = (this.hi + x.hi + carry) & 0xFFFFFFFF;
1.53 + return new Long(low, hi);
1.54 +};
1.55 +
1.56 +Long.prototype.div64 = function(x) {
1.57 + return LongFromNumber(Math.floor(this.toFP() / x.toFP()));
1.58 +};
1.59 +
1.60 +Long.prototype.shl64 = function(x) {
1.61 + if (x > 32) {
1.62 + hi = (this.low << (x - 32)) & 0xFFFFFFFF;
1.63 + low = 0;
1.64 + } else {
1.65 + hi = (this.hi << x) & 0xFFFFFFFF;
1.66 + low_reminder = this.low >> x;
1.67 + hi |= low_reminder;
1.68 + low = this.low << x;
1.69 + }
1.70 + return new Long(low, hi);
1.71 +};
2.1 --- a/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java Mon Jan 21 15:57:01 2013 +0100
2.2 +++ b/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java Fri Jan 25 11:00:52 2013 +0100
2.3 @@ -304,7 +304,7 @@
2.4 emit(out, "var @1 = @2;", smapper.pushI(), lmapper.getI(0));
2.5 break;
2.6 case opc_lload_0:
2.7 - emit(out, "var @1 = @2;", smapper.pushL(), lmapper.getL(0));
2.8 + emit(out, "var @1 = MakeLong(@2);", smapper.pushL(), lmapper.getL(0));
2.9 break;
2.10 case opc_fload_0:
2.11 emit(out, "var @1 = @2;", smapper.pushF(), lmapper.getF(0));
2.12 @@ -319,7 +319,7 @@
2.13 emit(out, "var @1 = @2;", smapper.pushI(), lmapper.getI(1));
2.14 break;
2.15 case opc_lload_1:
2.16 - emit(out, "var @1 = @2;", smapper.pushL(), lmapper.getL(1));
2.17 + emit(out, "var @1 = MakeLong(@2);", smapper.pushL(), lmapper.getL(1));
2.18 break;
2.19 case opc_fload_1:
2.20 emit(out, "var @1 = @2;", smapper.pushF(), lmapper.getF(1));
2.21 @@ -334,7 +334,7 @@
2.22 emit(out, "var @1 = @2;", smapper.pushI(), lmapper.getI(2));
2.23 break;
2.24 case opc_lload_2:
2.25 - emit(out, "var @1 = @2;", smapper.pushL(), lmapper.getL(2));
2.26 + emit(out, "var @1 = MakeLong(@2);", smapper.pushL(), lmapper.getL(2));
2.27 break;
2.28 case opc_fload_2:
2.29 emit(out, "var @1 = @2;", smapper.pushF(), lmapper.getF(2));
2.30 @@ -349,7 +349,7 @@
2.31 emit(out, "var @1 = @2;", smapper.pushI(), lmapper.getI(3));
2.32 break;
2.33 case opc_lload_3:
2.34 - emit(out, "var @1 = @2;", smapper.pushL(), lmapper.getL(3));
2.35 + emit(out, "var @1 = MakeLong(@2);", smapper.pushL(), lmapper.getL(3));
2.36 break;
2.37 case opc_fload_3:
2.38 emit(out, "var @1 = @2;", smapper.pushF(), lmapper.getF(3));
2.39 @@ -481,7 +481,7 @@
2.40 emit(out, "@1 = @1.add32(@2);", smapper.getI(1), smapper.popI());
2.41 break;
2.42 case opc_ladd:
2.43 - emit(out, "@1 += @2;", smapper.getL(1), smapper.popL());
2.44 + emit(out, "@1 = @1.add64(@2);", smapper.getL(1), smapper.popL());
2.45 break;
2.46 case opc_fadd:
2.47 emit(out, "@1 += @2;", smapper.getF(1), smapper.popF());
2.48 @@ -518,7 +518,7 @@
2.49 smapper.getI(1), smapper.popI());
2.50 break;
2.51 case opc_ldiv:
2.52 - emit(out, "@1 = Math.floor(@1 / @2);",
2.53 + emit(out, "@1 = @1.div64(@2);",
2.54 smapper.getL(1), smapper.popL());
2.55 break;
2.56 case opc_fdiv:
2.57 @@ -573,7 +573,7 @@
2.58 emit(out, "@1 <<= @2;", smapper.getI(1), smapper.popI());
2.59 break;
2.60 case opc_lshl:
2.61 - emit(out, "@1 <<= @2;", smapper.getL(1), smapper.popI());
2.62 + emit(out, "@1 = @1.shl64(@2);", smapper.getL(1), smapper.popI());
2.63 break;
2.64 case opc_ishr:
2.65 emit(out, "@1 >>= @2;", smapper.getI(1), smapper.popI());
2.66 @@ -618,7 +618,7 @@
2.67 emit(out, "return @1;", smapper.popA());
2.68 break;
2.69 case opc_i2l:
2.70 - emit(out, "var @2 = @1;", smapper.popI(), smapper.pushL());
2.71 + emit(out, "var @2 = new Long(@1, 0);", smapper.popI(), smapper.pushL());
2.72 break;
2.73 case opc_i2f:
2.74 emit(out, "var @2 = @1;", smapper.popI(), smapper.pushF());
2.75 @@ -627,14 +627,14 @@
2.76 emit(out, "var @2 = @1;", smapper.popI(), smapper.pushD());
2.77 break;
2.78 case opc_l2i:
2.79 - emit(out, "var @2 = @1;", smapper.popL(), smapper.pushI());
2.80 + emit(out, "var @2 = @1.toInt32();", smapper.popL(), smapper.pushI());
2.81 break;
2.82 // max int check?
2.83 case opc_l2f:
2.84 - emit(out, "var @2 = @1;", smapper.popL(), smapper.pushF());
2.85 + emit(out, "var @2 = @1.toFP();", smapper.popL(), smapper.pushF());
2.86 break;
2.87 case opc_l2d:
2.88 - emit(out, "var @2 = @1;", smapper.popL(), smapper.pushD());
2.89 + emit(out, "var @2 = @1.toFP();", smapper.popL(), smapper.pushD());
2.90 break;
2.91 case opc_f2d:
2.92 emit(out, "var @2 = @1;", smapper.popF(), smapper.pushD());
2.93 @@ -647,7 +647,7 @@
2.94 smapper.popF(), smapper.pushI());
2.95 break;
2.96 case opc_f2l:
2.97 - emit(out, "var @2 = Math.floor(@1);",
2.98 + emit(out, "var @2 = LongFromNumber(Math.floor(@1));",
2.99 smapper.popF(), smapper.pushL());
2.100 break;
2.101 case opc_d2i:
2.102 @@ -655,7 +655,7 @@
2.103 smapper.popD(), smapper.pushI());
2.104 break;
2.105 case opc_d2l:
2.106 - emit(out, "var @2 = Math.floor(@1);",
2.107 + emit(out, "var @2 = LongFromNumber(Math.floor(@1));",
2.108 smapper.popD(), smapper.pushL());
2.109 break;
2.110 case opc_i2b:
2.111 @@ -680,7 +680,7 @@
2.112 emit(out, "var @1 = 0;", smapper.pushD());
2.113 break;
2.114 case opc_lconst_0:
2.115 - emit(out, "var @1 = 0;", smapper.pushL());
2.116 + emit(out, "var @1 = new Long(0,0);", smapper.pushL());
2.117 break;
2.118 case opc_fconst_0:
2.119 emit(out, "var @1 = 0;", smapper.pushF());
2.120 @@ -689,7 +689,7 @@
2.121 emit(out, "var @1 = 1;", smapper.pushI());
2.122 break;
2.123 case opc_lconst_1:
2.124 - emit(out, "var @1 = 1;", smapper.pushL());
2.125 + emit(out, "var @1 = new Long(1,0);", smapper.pushL());
2.126 break;
2.127 case opc_fconst_1:
2.128 emit(out, "var @1 = 1;", smapper.pushF());
2.129 @@ -725,11 +725,19 @@
2.130 i += 2;
2.131 String v = encodeConstant(indx);
2.132 int type = VarType.fromConstantType(jc.getTag(indx));
2.133 - emit(out, "var @1 = @2;", smapper.pushT(type), v);
2.134 + if (type == VarType.LONG) {
2.135 + final Long lv = new Long(v);
2.136 + final int low = (int)(lv.longValue() & 0xFFFFFFFF);
2.137 + final int hi = (int)(lv.longValue() >> 32);
2.138 + emit(out, "var @1 = new Long(0x@2, 0x@3);", smapper.pushL(),
2.139 + Integer.toHexString(low), Integer.toHexString(hi));
2.140 + } else {
2.141 + emit(out, "var @1 = @2;", smapper.pushT(type), v);
2.142 + }
2.143 break;
2.144 }
2.145 case opc_lcmp:
2.146 - emit(out, "var @3 = (@2 == @1) ? 0 : ((@2 < @1) ? -1 : 1);",
2.147 + emit(out, "var @3 = @2.compare64(@1);",
2.148 smapper.popL(), smapper.popL(), smapper.pushI());
2.149 break;
2.150 case opc_fcmpl:
3.1 --- a/vm/src/test/java/org/apidesign/vm4brwsr/NumberTest.java Mon Jan 21 15:57:01 2013 +0100
3.2 +++ b/vm/src/test/java/org/apidesign/vm4brwsr/NumberTest.java Fri Jan 25 11:00:52 2013 +0100
3.3 @@ -157,22 +157,10 @@
3.4 }
3.5
3.6 private static void assertExec(
3.7 - String msg, Class<?> clazz, String method, Object expRes, Object... args) throws Exception {
3.8 -
3.9 - Object ret = null;
3.10 - try {
3.11 - ret = code.invokeFunction("bck2brwsr");
3.12 - ret = code.invokeMethod(ret, "loadClass", clazz.getName());
3.13 - ret = code.invokeMethod(ret, method, args);
3.14 - } catch (ScriptException ex) {
3.15 - fail("Execution failed in\n" + StaticMethodTest.dumpJS(codeSeq), ex);
3.16 - } catch (NoSuchMethodException ex) {
3.17 - fail("Cannot find method in\n" + StaticMethodTest.dumpJS(codeSeq), ex);
3.18 - }
3.19 - if (ret == null && expRes == null) {
3.20 - return;
3.21 - }
3.22 - if (expRes.equals(ret)) {
3.23 + String msg, Class<?> clazz, String method, Object expRes, Object... args) throws Exception
3.24 + {
3.25 + Object ret = TestUtils.execCode(code, codeSeq, msg, clazz, method, expRes, args);
3.26 + if (ret == null) {
3.27 return;
3.28 }
3.29 if (expRes instanceof Double && ret instanceof Double) {
4.1 --- a/vm/src/test/java/org/apidesign/vm4brwsr/StaticMethodTest.java Mon Jan 21 15:57:01 2013 +0100
4.2 +++ b/vm/src/test/java/org/apidesign/vm4brwsr/StaticMethodTest.java Fri Jan 25 11:00:52 2013 +0100
4.3 @@ -270,17 +270,8 @@
4.4 String msg, Class clazz, String method,
4.5 Object expRes, Object... args
4.6 ) throws Exception {
4.7 - Object ret = null;
4.8 - try {
4.9 - ret = toRun.invokeFunction("bck2brwsr");
4.10 - ret = toRun.invokeMethod(ret, "loadClass", clazz.getName());
4.11 - ret = toRun.invokeMethod(ret, method, args);
4.12 - } catch (ScriptException ex) {
4.13 - fail("Execution failed in\n" + dumpJS(theCode), ex);
4.14 - } catch (NoSuchMethodException ex) {
4.15 - fail("Cannot find method in\n" + dumpJS(theCode), ex);
4.16 - }
4.17 - if (ret == null && expRes == null) {
4.18 + Object ret = TestUtils.execCode(toRun, theCode, msg, clazz, method, expRes, args);
4.19 + if (ret == null) {
4.20 return;
4.21 }
4.22 if (expRes != null && expRes.equals(ret)) {
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
5.2 +++ b/vm/src/test/java/org/apidesign/vm4brwsr/TestUtils.java Fri Jan 25 11:00:52 2013 +0100
5.3 @@ -0,0 +1,59 @@
5.4 +/**
5.5 + * Back 2 Browser Bytecode Translator
5.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
5.7 + *
5.8 + * This program is free software: you can redistribute it and/or modify
5.9 + * it under the terms of the GNU General Public License as published by
5.10 + * the Free Software Foundation, version 2 of the License.
5.11 + *
5.12 + * This program is distributed in the hope that it will be useful,
5.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
5.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
5.15 + * GNU General Public License for more details.
5.16 + *
5.17 + * You should have received a copy of the GNU General Public License
5.18 + * along with this program. Look for COPYING file in the top folder.
5.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
5.20 + */
5.21 +package org.apidesign.vm4brwsr;
5.22 +
5.23 +import javax.script.Invocable;
5.24 +import javax.script.ScriptException;
5.25 +import static org.testng.Assert.*;
5.26 +
5.27 +class TestUtils {
5.28 +
5.29 + static Object execCode(Invocable code, CharSequence codeSeq,
5.30 + String msg, Class<?> clazz, String method, Object expRes, Object... args)
5.31 + throws Exception
5.32 + {
5.33 + Object ret = null;
5.34 + try {
5.35 + ret = code.invokeFunction("bck2brwsr");
5.36 + ret = code.invokeMethod(ret, "loadClass", clazz.getName());
5.37 + ret = code.invokeMethod(ret, method, args);
5.38 + } catch (ScriptException ex) {
5.39 + fail("Execution failed in " + StaticMethodTest.dumpJS(codeSeq), ex);
5.40 + } catch (NoSuchMethodException ex) {
5.41 + fail("Cannot find method in " + StaticMethodTest.dumpJS(codeSeq), ex);
5.42 + }
5.43 + if (ret == null && expRes == null) {
5.44 + return null;
5.45 + }
5.46 + if (expRes.equals(ret)) {
5.47 + return null;
5.48 + }
5.49 + if (expRes instanceof Number) {
5.50 + // in case of Long it is necessary convert it to number
5.51 + // since the Long is represented by two numbers in JavaScript
5.52 + try {
5.53 + ret = code.invokeFunction("Number", ret);
5.54 + } catch (ScriptException ex) {
5.55 + fail("Conversion to number failed in " + StaticMethodTest.dumpJS(codeSeq), ex);
5.56 + } catch (NoSuchMethodException ex) {
5.57 + fail("Cannot find global Number(x) function in " + StaticMethodTest.dumpJS(codeSeq), ex);
5.58 + }
5.59 + }
5.60 + return ret;
5.61 + }
5.62 +}
6.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
6.2 +++ b/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/LongArithmeticTest.java Fri Jan 25 11:00:52 2013 +0100
6.3 @@ -0,0 +1,104 @@
6.4 +/**
6.5 + * Back 2 Browser Bytecode Translator
6.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
6.7 + *
6.8 + * This program is free software: you can redistribute it and/or modify
6.9 + * it under the terms of the GNU General Public License as published by
6.10 + * the Free Software Foundation, version 2 of the License.
6.11 + *
6.12 + * This program is distributed in the hope that it will be useful,
6.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
6.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
6.15 + * GNU General Public License for more details.
6.16 + *
6.17 + * You should have received a copy of the GNU General Public License
6.18 + * along with this program. Look for COPYING file in the top folder.
6.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
6.20 + */
6.21 +package org.apidesign.bck2brwsr.tck;
6.22 +
6.23 +import org.apidesign.bck2brwsr.vmtest.Compare;
6.24 +import org.apidesign.bck2brwsr.vmtest.VMTest;
6.25 +import org.testng.annotations.Factory;
6.26 +
6.27 +/**
6.28 + *
6.29 + * @author Jaroslav Tulach <jtulach@netbeans.org>
6.30 + */
6.31 +public class LongArithmeticTest {
6.32 +
6.33 + private static long add(long x, long y) {
6.34 + return (x + y);
6.35 + }
6.36 +
6.37 + private static long sub(long x, long y) {
6.38 + return (x - y);
6.39 + }
6.40 +
6.41 + private static long mul(long x, long y) {
6.42 + return (x * y);
6.43 + }
6.44 +
6.45 + private static long div(long x, long y) {
6.46 + return (x / y);
6.47 + }
6.48 +
6.49 + private static long mod(long x, long y) {
6.50 + return (x % y);
6.51 + }
6.52 +
6.53 + @Compare public long conversion() {
6.54 + return Long.MAX_VALUE;
6.55 + }
6.56 +
6.57 + /*
6.58 + @Compare public long addOverflow() {
6.59 + return add(Long.MAX_VALUE, 1l);
6.60 + }
6.61 +
6.62 + @Compare public long subUnderflow() {
6.63 + return sub(Long.MIN_VALUE, 1l);
6.64 + }
6.65 +
6.66 + @Compare public long addMaxLongAndMaxLong() {
6.67 + return add(Long.MAX_VALUE, Long.MAX_VALUE);
6.68 + }
6.69 +
6.70 + @Compare public long subMinLongAndMinLong() {
6.71 + return sub(Long.MIN_VALUE, Long.MIN_VALUE);
6.72 + }
6.73 +
6.74 + @Compare public long multiplyMaxLong() {
6.75 + return mul(Long.MAX_VALUE, 2l);
6.76 + }
6.77 +
6.78 + @Compare public long multiplyMaxLongAndMaxLong() {
6.79 + return mul(Long.MAX_VALUE, Long.MAX_VALUE);
6.80 + }
6.81 +
6.82 + @Compare public long multiplyMinLong() {
6.83 + return mul(Long.MIN_VALUE, 2l);
6.84 + }
6.85 +
6.86 + @Compare public long multiplyMinLongAndMinLong() {
6.87 + return mul(Long.MIN_VALUE, Long.MIN_VALUE);
6.88 + }
6.89 +
6.90 + @Compare public long multiplyPrecision() {
6.91 + return mul(17638l, 1103l);
6.92 + }
6.93 +
6.94 + @Compare public long division() {
6.95 + return div(1l, 2l);
6.96 + }
6.97 +
6.98 + @Compare public long divisionReminder() {
6.99 + return mod(1l, 2l);
6.100 + }
6.101 + */
6.102 +
6.103 + @Factory
6.104 + public static Object[] create() {
6.105 + return VMTest.create(LongArithmeticTest.class);
6.106 + }
6.107 +}