# HG changeset patch # User Martin Soch # Date 1359967293 -3600 # Node ID b42bfe334128950b294a5dadbd032ca3653045f2 # Parent 04e312a7887e5795856004fee50c06a3f703dc97 Support for Long multiplication + tests diff -r 04e312a7887e -r b42bfe334128 emul/mini/src/main/resources/org/apidesign/vm4brwsr/emul/lang/java_lang_Number.js --- a/emul/mini/src/main/resources/org/apidesign/vm4brwsr/emul/lang/java_lang_Number.js Fri Feb 01 09:00:30 2013 +0100 +++ b/emul/mini/src/main/resources/org/apidesign/vm4brwsr/emul/lang/java_lang_Number.js Mon Feb 04 09:41:33 2013 +0100 @@ -80,6 +80,32 @@ return hi.next32(low); }; +Number.prototype.mul64 = function(x) { + var low = this.mul32(x); + low += (low < 0) ? (__m32+1) : 0; + // first count upper 32 bits of (this.low * x.low) + var hi_hi = 0; + var hi_low = 0; + var m = 1; + for (var i = 0; i < 32; i++) { + if (x & m) { + hi_hi += this >>> 16; + hi_low += this & 0xFFFF + } + hi_low >>= 1; + hi_low += (hi_hi & 1) ? 0x8000 : 0; + hi_hi >>= 1; + m <<= 1; + } + var hi = (hi_hi << 16) + hi_low; + + var m1 = this.high32().mul32(x); + var m2 = this.mul32(x.high32()); + hi = hi.add32(m1).add32(m2); + + return hi.next32(low); +}; + Number.prototype.div64 = function(x) { var low = Math.floor(this.toFP() / x.toFP()); // TODO: not exact enough if (low > __m32) { diff -r 04e312a7887e -r b42bfe334128 vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java --- a/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java Fri Feb 01 09:00:30 2013 +0100 +++ b/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java Mon Feb 04 09:41:33 2013 +0100 @@ -544,7 +544,7 @@ emit(out, "@1 = @1.mul32(@2);", smapper.getI(1), smapper.popI()); break; case opc_lmul: - emit(out, "@1 *= @2;", smapper.getL(1), smapper.popL()); + emit(out, "@1 = @1.mul64(@2);", smapper.getL(1), smapper.popL()); break; case opc_fmul: emit(out, "@1 *= @2;", smapper.getF(1), smapper.popF()); diff -r 04e312a7887e -r b42bfe334128 vm/src/test/java/org/apidesign/vm4brwsr/NumberTest.java --- a/vm/src/test/java/org/apidesign/vm4brwsr/NumberTest.java Fri Feb 01 09:00:30 2013 +0100 +++ b/vm/src/test/java/org/apidesign/vm4brwsr/NumberTest.java Mon Feb 04 09:41:33 2013 +0100 @@ -219,6 +219,56 @@ ); } + @Test public void longMultiplyMax() throws Exception { + final long res = Long.MAX_VALUE * 2l; + assertExec("Multiplication MAX*2", + Numbers.class, "mulL__J_3B_3B", + Double.valueOf(res), + new byte[] { (byte)0x7f, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff }, + new byte[] { (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x02 } + ); + } + + @Test public void longMultiplyMaxAndMax() throws Exception { + final long res = Long.MAX_VALUE * Long.MAX_VALUE; + assertExec("Multiplication MAX*MAX", + Numbers.class, "mulL__J_3B_3B", + Double.valueOf(res), + new byte[] { (byte)0x7f, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff }, + new byte[] { (byte)0x7f, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff } + ); + } + + @Test public void longMultiplyMin() throws Exception { + final long res = Long.MIN_VALUE * 2l; + assertExec("Multiplication MIN*2", + Numbers.class, "mulL__J_3B_3B", + Double.valueOf(res), + new byte[] { (byte)0x80, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00 }, + new byte[] { (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x02 } + ); + } + + @Test public void longMultiplyMinAndMin() throws Exception { + final long res = Long.MIN_VALUE * Long.MIN_VALUE; + assertExec("Multiplication MIN*2", + Numbers.class, "mulL__J_3B_3B", + Double.valueOf(res), + new byte[] { (byte)0x80, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00 }, + new byte[] { (byte)0x80, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00 } + ); + } + + @Test public void longMultiplyPrecision() throws Exception { + final long res = 0x00fa37d7763e0ca1l * 0xa7b3432fff00123el; + assertExec("Multiplication", + Numbers.class, "mulL__J_3B_3B", + Double.valueOf(res), + new byte[] { (byte)0x00, (byte)0xfa, (byte)0x37, (byte)0xd7, (byte)0x76, (byte)0x3e, (byte)0x0c, (byte)0xa1 }, + new byte[] { (byte)0xa7, (byte)0xb3, (byte)0x43, (byte)0x2f, (byte)0xff, (byte)0x00, (byte)0x12, (byte)0x3e } + ); + } + @Test public void longShiftL1() throws Exception { final long res = 0x00fa37d7763e0ca1l << 5; assertExec("Long << 5", diff -r 04e312a7887e -r b42bfe334128 vm/src/test/java/org/apidesign/vm4brwsr/Numbers.java --- a/vm/src/test/java/org/apidesign/vm4brwsr/Numbers.java Fri Feb 01 09:00:30 2013 +0100 +++ b/vm/src/test/java/org/apidesign/vm4brwsr/Numbers.java Mon Feb 04 09:41:33 2013 +0100 @@ -94,8 +94,12 @@ return (disX.readLong() - disY.readLong()); } - public static long mulL(long x, long y) { - return (x * y); + public static long mulL(byte[] arrX, byte[] arrY) throws IOException { + ByteArrayInputStream isX = new ByteArrayInputStream(arrX); + DataInputStream disX = new DataInputStream(isX); + ByteArrayInputStream isY = new ByteArrayInputStream(arrY); + DataInputStream disY = new DataInputStream(isY); + return (disX.readLong() * disY.readLong()); } public static long divL(long x, long y) {