# HG changeset patch # User Jaroslav Tulach # Date 1360238842 -3600 # Node ID dbcd1a21f3f8d2cae8283f4e199570c1c6a47069 # Parent 0d277415ed0290045dfa2f9b5857748b280bf7ec# Parent f87c33d2fa7b1833bedce36ff80abbe48ccb1338 Merging in long arithmetic, otherwise the zip support won't work diff -r 0d277415ed02 -r dbcd1a21f3f8 emul/mini/src/main/java/java/lang/Character.java --- a/emul/mini/src/main/java/java/lang/Character.java Thu Feb 07 12:58:12 2013 +0100 +++ b/emul/mini/src/main/java/java/lang/Character.java Thu Feb 07 13:07:22 2013 +0100 @@ -2193,6 +2193,10 @@ * @see Character#isDigit(int) * @since 1.5 */ + @JavaScriptBody(args = { "codePoint", "radix" }, body= + "var x = parseInt(String.fromCharCode(codePoint), radix);\n" + + "return isNaN(x) ? -1 : x;" + ) public static int digit(int codePoint, int radix) { throw new UnsupportedOperationException(); } diff -r 0d277415ed02 -r dbcd1a21f3f8 emul/mini/src/main/java/java/lang/Long.java --- a/emul/mini/src/main/java/java/lang/Long.java Thu Feb 07 12:58:12 2013 +0100 +++ b/emul/mini/src/main/java/java/lang/Long.java Thu Feb 07 13:07:22 2013 +0100 @@ -262,7 +262,7 @@ * @param i a {@code long} to be converted. * @return a string representation of the argument in base 10. */ - @JavaScriptBody(args = "i", body = "return i.toString();") + @JavaScriptBody(args = "i", body = "return i.toExactString();") public static String toString(long i) { if (i == Long.MIN_VALUE) return "-9223372036854775808"; diff -r 0d277415ed02 -r dbcd1a21f3f8 emul/mini/src/main/java/org/apidesign/bck2brwsr/emul/lang/System.java --- a/emul/mini/src/main/java/org/apidesign/bck2brwsr/emul/lang/System.java Thu Feb 07 12:58:12 2013 +0100 +++ b/emul/mini/src/main/java/org/apidesign/bck2brwsr/emul/lang/System.java Thu Feb 07 13:07:22 2013 +0100 @@ -54,7 +54,7 @@ ) public static native byte[] expandArray(byte[] arr, int expectedSize); - @JavaScriptBody(args = {}, body = "new Date().getMilliseconds();") + @JavaScriptBody(args = {}, body = "return new Date().getMilliseconds();") public static native long currentTimeMillis(); public static long nanoTime() { diff -r 0d277415ed02 -r dbcd1a21f3f8 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 Thu Feb 07 12:58:12 2013 +0100 +++ b/emul/mini/src/main/resources/org/apidesign/vm4brwsr/emul/lang/java_lang_Number.js Thu Feb 07 13:07:22 2013 +0100 @@ -6,4 +6,509 @@ }; Number.prototype.toInt8 = function() { return (this << 24) >> 24; }; -Number.prototype.toInt16 = function() { return (this << 16) >> 16; }; \ No newline at end of file +Number.prototype.toInt16 = function() { return (this << 16) >> 16; }; + +var __m32 = 0xFFFFFFFF; + +Number.prototype.next32 = function(low) { + if (this === 0) { + return low; + } + var l = new Number(low); + l.hi = this | 0; + return l; +}; + +Number.prototype.high32 = function() { + return this.hi ? this.hi : (Math.floor(this / (__m32+1))) | 0; +}; +Number.prototype.toInt32 = function() { return this | 0; }; +Number.prototype.toFP = function() { + return this.hi ? this.hi * (__m32+1) + this : this; +}; +Number.prototype.toLong = function() { + var hi = (this > __m32) ? (Math.floor(this / (__m32+1))) | 0 : 0; + return hi.next32(Math.floor(this % (__m32+1))); +}; + +Number.prototype.toExactString = function() { + if (this.hi) { + var res = 0; + var a = [ 6,9,2,7,6,9,4,9,2,4 ]; + var s = ''; + var digit; + var neg = this.hi < 0; + if (neg) { + var x = this.neg64(); + var hi = x.hi; + var low = x; + } else { + var hi = this.hi; + var low = this; + } + for (var i = 0; i < a.length; i++) { + res += hi * a[i]; + var low_digit = low % 10; + digit = (res % 10) + low_digit; + + low = Math.floor(low / 10); + res = Math.floor(res / 10); + + if (digit >= 10) { + digit -= 10; + res++; + } + s = String(digit).concat(s); + } + return (neg ? '-' : '').concat(res).concat(s); + } + return String(this); +}; + +Number.prototype.add64 = function(x) { + var low = this + x; + carry = 0; + if (low > __m32) { + carry = 1; + low -= (__m32+1); + } + var hi = (this.high32() + x.high32() + carry) | 0; + return hi.next32(low); +}; + +Number.prototype.sub64 = function(x) { + var low = this - x; + carry = 0; + if (low < 0) { + carry = 1; + low += (__m32+1); + } + var hi = (this.high32() - x.high32() - carry) | 0; + 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.and64 = function(x) { + var low = this & x; + low += (low < 0) ? (__m32+1) : 0; + if (this.hi && x.hi) { + var hi = this.hi & x.hi; + return hi.next32(low); + }; + return low; +}; + +Number.prototype.or64 = function(x) { + var low = this | x; + low += (low < 0) ? (__m32+1) : 0; + if (this.hi || x.hi) { + var hi = this.hi | x.hi; + return hi.next32(low); + }; + return low; +}; + +Number.prototype.xor64 = function(x) { + var low = this ^ x; + low += (low < 0) ? (__m32+1) : 0; + if (this.hi || x.hi) { + var hi = this.hi ^ x.hi; + return hi.next32(low); + }; + return low; +}; + +Number.prototype.shl64 = function(x) { + if (x >= 32) { + var hi = this << (x - 32); + return hi.next32(0); + } else { + var hi = this.high32() << x; + var low_reminder = this >> (32 - x); + hi |= low_reminder; + var low = this << x; + low += (low < 0) ? (__m32+1) : 0; + return hi.next32(low); + } +}; + +Number.prototype.shr64 = function(x) { + if (x >= 32) { + var low = this.high32() >> (x - 32); + low += (low < 0) ? (__m32+1) : 0; + return low; + } else { + var low = this >> x; + var hi_reminder = this.high32() << (32 - x); + low |= hi_reminder; + low += (low < 0) ? (__m32+1) : 0; + var hi = this.high32() >> x; + return hi.next32(low); + } +}; + +Number.prototype.ushr64 = function(x) { + if (x >= 32) { + var low = this.high32() >>> (x - 32); + low += (low < 0) ? (__m32+1) : 0; + return low; + } else { + var low = this >>> x; + var hi_reminder = this.high32() << (32 - x); + low |= hi_reminder; + low += (low < 0) ? (__m32+1) : 0; + var hi = this.high32() >>> x; + return hi.next32(low); + } +}; + +Number.prototype.compare64 = function(x) { + if (this.high32() === x.high32()) { + return (this < x) ? -1 : ((this > x) ? 1 : 0); + } + return (this.high32() < x.high32()) ? -1 : 1; +}; + +Number.prototype.neg64 = function() { + var hi = this.high32(); + var low = this; + if ((hi === 0) && (low < 0)) { return -low; } + hi = ~hi; + low = ~low; + low += (low < 0) ? (__m32+1) : 0; + var ret = hi.next32(low); + return ret.add64(1); +}; + +(function(numberPrototype) { + function __Int64(hi32, lo32) { + this.hi32 = hi32 | 0; + this.lo32 = lo32 | 0; + + this.get32 = function(bitIndex) { + var v0; + var v1; + bitIndex += 32; + var selector = bitIndex >>> 5; + switch (selector) { + case 0: + v0 = 0; + v1 = this.lo32; + break; + case 1: + v0 = this.lo32; + v1 = this.hi32; + break; + case 2: + v0 = this.hi32; + v1 = 0; + break + default: + return 0; + } + + var shift = bitIndex & 31; + if (shift === 0) { + return v0; + } + + return (v1 << (32 - shift)) | (v0 >>> shift); + } + + this.get16 = function(bitIndex) { + return this.get32(bitIndex) & 0xffff; + } + + this.set16 = function(bitIndex, value) { + bitIndex += 32; + var shift = bitIndex & 15; + var svalue = (value & 0xffff) << shift; + var smask = 0xffff << shift; + var selector = bitIndex >>> 4; + switch (selector) { + case 0: + break; + case 1: + this.lo32 = (this.lo32 & ~(smask >>> 16)) + | (svalue >>> 16); + break; + case 2: + this.lo32 = (this.lo32 & ~smask) | svalue; + break; + case 3: + this.lo32 = (this.lo32 & ~(smask << 16)) + | (svalue << 16); + this.hi32 = (this.hi32 & ~(smask >>> 16)) + | (svalue >>> 16); + break; + case 4: + this.hi32 = (this.hi32 & ~smask) | svalue; + break; + case 5: + this.hi32 = (this.hi32 & ~(smask << 16)) + | (svalue << 16); + break; + } + } + + this.getDigit = function(index, shift) { + return this.get16((index << 4) - shift); + } + + this.getTwoDigits = function(index, shift) { + return this.get32(((index - 1) << 4) - shift); + } + + this.setDigit = function(index, shift, value) { + this.set16((index << 4) - shift, value); + } + + this.countSignificantDigits = function() { + var sd; + var remaining; + + if (this.hi32 === 0) { + if (this.lo32 === 0) { + return 0; + } + + sd = 2; + remaining = this.lo32; + } else { + sd = 4; + remaining = this.hi32; + } + + if (remaining < 0) { + return sd; + } + + return (remaining < 65536) ? sd - 1 : sd; + } + + this.toNumber = function() { + var lo32 = this.lo32; + if (lo32 < 0) { + lo32 += 0x100000000; + } + + return this.hi32.next32(lo32); + } + } + + function __countLeadingZeroes16(number) { + var nlz = 0; + + if (number < 256) { + nlz += 8; + number <<= 8; + } + + if (number < 4096) { + nlz += 4; + number <<= 4; + } + + if (number < 16384) { + nlz += 2; + number <<= 2; + } + + return (number < 32768) ? nlz + 1 : nlz; + } + + // q = u / v; r = u - q * v; + // v != 0 + function __div64(q, r, u, v) { + var m = u.countSignificantDigits(); + var n = v.countSignificantDigits(); + + q.hi32 = q.lo32 = 0; + + if (n === 1) { + // v has single digit + var vd = v.getDigit(0, 0); + var carry = 0; + for (var i = m - 1; i >= 0; --i) { + var ui = (carry << 16) | u.getDigit(i, 0); + if (ui < 0) { + ui += 0x100000000; + } + var qi = (ui / vd) | 0; + q.setDigit(i, 0, qi); + carry = ui - qi * vd; + } + + r.hi32 = 0; + r.lo32 = carry; + return; + } + + r.hi32 = u.hi32; + r.lo32 = u.lo32; + + if (m < n) { + return; + } + + // Normalize + var nrm = __countLeadingZeroes16(v.getDigit(n - 1, 0)); + + var vd1 = v.getDigit(n - 1, nrm); + var vd0 = v.getDigit(n - 2, nrm); + for (var j = m - n; j >= 0; --j) { + // Calculate qj estimate + var ud21 = r.getTwoDigits(j + n, nrm); + var ud2 = ud21 >>> 16; + if (ud21 < 0) { + ud21 += 0x100000000; + } + + var qest = (ud2 === vd1) ? 0xFFFF : ((ud21 / vd1) | 0); + var rest = ud21 - qest * vd1; + + // 0 <= (qest - qj) <= 2 + + // Refine qj estimate + var ud0 = r.getDigit(j + n - 2, nrm); + while ((qest * vd0) > ((rest * 0x10000) + ud0)) { + --qest; + rest += vd1; + } + + // 0 <= (qest - qj) <= 1 + + // Multiply and subtract + var carry = 0; + for (var i = 0; i < n; ++i) { + var vi = qest * v.getDigit(i, nrm); + var ui = r.getDigit(i + j, nrm) - carry - (vi & 0xffff); + r.setDigit(i + j, nrm, ui); + carry = (vi >>> 16) - (ui >> 16); + } + var uj = ud2 - carry; + + if (uj < 0) { + // qest - qj = 1 + + // Add back + --qest; + var carry = 0; + for (var i = 0; i < n; ++i) { + var ui = r.getDigit(i + j, nrm) + v.getDigit(i, nrm) + + carry; + r.setDigit(i + j, nrm, ui); + carry = ui >> 16; + } + uj += carry; + } + + q.setDigit(j, 0, qest); + r.setDigit(j + n, nrm, uj); + } + } + + numberPrototype.div64 = function(x) { + var negateResult = false; + var u, v; + + if ((this.high32() & 0x80000000) != 0) { + u = this.neg64(); + negateResult = !negateResult; + } else { + u = this; + } + + if ((x.high32() & 0x80000000) != 0) { + v = x.neg64(); + negateResult = !negateResult; + } else { + v = x; + } + + if ((v === 0) && (v.high32() === 0)) { + // TODO: throw + } + + if (u.high32() === 0) { + if (v.high32() === 0) { + var result = (u / v) | 0; + return negateResult ? result.neg64() : result; + } + + return 0; + } + + var u64 = new __Int64(u.high32(), u); + var v64 = new __Int64(v.high32(), v); + var q64 = new __Int64(0, 0); + var r64 = new __Int64(0, 0); + + __div64(q64, r64, u64, v64); + + var result = q64.toNumber(); + return negateResult ? result.neg64() : result; + } + + numberPrototype.mod64 = function(x) { + var negateResult = false; + var u, v; + + if ((this.high32() & 0x80000000) != 0) { + u = this.neg64(); + negateResult = !negateResult; + } else { + u = this; + } + + if ((x.high32() & 0x80000000) != 0) { + v = x.neg64(); + } else { + v = x; + } + + if ((v === 0) && (v.high32() === 0)) { + // TODO: throw + } + + if (u.high32() === 0) { + var result = (v.high32() === 0) ? (u % v) : u; + return negateResult ? result.neg64() : result; + } + + var u64 = new __Int64(u.high32(), u); + var v64 = new __Int64(v.high32(), v); + var q64 = new __Int64(0, 0); + var r64 = new __Int64(0, 0); + + __div64(q64, r64, u64, v64); + + var result = r64.toNumber(); + return negateResult ? result.neg64() : result; + } +})(Number.prototype); diff -r 0d277415ed02 -r dbcd1a21f3f8 vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java --- a/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java Thu Feb 07 12:58:12 2013 +0100 +++ b/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java Thu Feb 07 13:07:22 2013 +0100 @@ -521,7 +521,7 @@ emit(out, "@1 = @1.add32(@2);", smapper.getI(1), smapper.popI()); break; case opc_ladd: - emit(out, "@1 += @2;", smapper.getL(1), smapper.popL()); + emit(out, "@1 = @1.add64(@2);", smapper.getL(1), smapper.popL()); break; case opc_fadd: emit(out, "@1 += @2;", smapper.getF(1), smapper.popF()); @@ -533,7 +533,7 @@ emit(out, "@1 = @1.sub32(@2);", smapper.getI(1), smapper.popI()); break; case opc_lsub: - emit(out, "@1 -= @2;", smapper.getL(1), smapper.popL()); + emit(out, "@1 = @1.sub64(@2);", smapper.getL(1), smapper.popL()); break; case opc_fsub: emit(out, "@1 -= @2;", smapper.getF(1), smapper.popF()); @@ -545,7 +545,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()); @@ -558,7 +558,7 @@ smapper.getI(1), smapper.popI()); break; case opc_ldiv: - emit(out, "@1 = Math.floor(@1 / @2);", + emit(out, "@1 = @1.div64(@2);", smapper.getL(1), smapper.popL()); break; case opc_fdiv: @@ -571,7 +571,8 @@ emit(out, "@1 %= @2;", smapper.getI(1), smapper.popI()); break; case opc_lrem: - emit(out, "@1 %= @2;", smapper.getL(1), smapper.popL()); + emit(out, "@1 = @1.mod64(@2);", + smapper.getL(1), smapper.popL()); break; case opc_frem: emit(out, "@1 %= @2;", smapper.getF(1), smapper.popF()); @@ -583,25 +584,25 @@ emit(out, "@1 &= @2;", smapper.getI(1), smapper.popI()); break; case opc_land: - emit(out, "@1 &= @2;", smapper.getL(1), smapper.popL()); + emit(out, "@1 = @1.and64(@2);", smapper.getL(1), smapper.popL()); break; case opc_ior: emit(out, "@1 |= @2;", smapper.getI(1), smapper.popI()); break; case opc_lor: - emit(out, "@1 |= @2;", smapper.getL(1), smapper.popL()); + emit(out, "@1 = @1.or64(@2);", smapper.getL(1), smapper.popL()); break; case opc_ixor: emit(out, "@1 ^= @2;", smapper.getI(1), smapper.popI()); break; case opc_lxor: - emit(out, "@1 ^= @2;", smapper.getL(1), smapper.popL()); + emit(out, "@1 = @1.xor64(@2);", smapper.getL(1), smapper.popL()); break; case opc_ineg: emit(out, "@1 = -@1;", smapper.getI(0)); break; case opc_lneg: - emit(out, "@1 = -@1;", smapper.getL(0)); + emit(out, "@1 = @1.neg64();", smapper.getL(0)); break; case opc_fneg: emit(out, "@1 = -@1;", smapper.getF(0)); @@ -613,19 +614,19 @@ emit(out, "@1 <<= @2;", smapper.getI(1), smapper.popI()); break; case opc_lshl: - emit(out, "@1 <<= @2;", smapper.getL(1), smapper.popI()); + emit(out, "@1 = @1.shl64(@2);", smapper.getL(1), smapper.popI()); break; case opc_ishr: emit(out, "@1 >>= @2;", smapper.getI(1), smapper.popI()); break; case opc_lshr: - emit(out, "@1 >>= @2;", smapper.getL(1), smapper.popI()); + emit(out, "@1 = @1.shr64(@2);", smapper.getL(1), smapper.popI()); break; case opc_iushr: emit(out, "@1 >>>= @2;", smapper.getI(1), smapper.popI()); break; case opc_lushr: - emit(out, "@1 >>>= @2;", smapper.getL(1), smapper.popI()); + emit(out, "@1 = @1.ushr64(@2);", smapper.getL(1), smapper.popI()); break; case opc_iinc: { ++i; @@ -672,14 +673,14 @@ emit(out, "var @2 = @1;", smapper.popI(), smapper.pushD()); break; case opc_l2i: - emit(out, "var @2 = @1;", smapper.popL(), smapper.pushI()); + emit(out, "var @2 = @1.toInt32();", smapper.popL(), smapper.pushI()); break; // max int check? case opc_l2f: - emit(out, "var @2 = @1;", smapper.popL(), smapper.pushF()); + emit(out, "var @2 = @1.toFP();", smapper.popL(), smapper.pushF()); break; case opc_l2d: - emit(out, "var @2 = @1;", smapper.popL(), smapper.pushD()); + emit(out, "var @2 = @1.toFP();", smapper.popL(), smapper.pushD()); break; case opc_f2d: emit(out, "var @2 = @1;", smapper.popF(), smapper.pushD()); @@ -692,7 +693,7 @@ smapper.popF(), smapper.pushI()); break; case opc_f2l: - emit(out, "var @2 = Math.floor(@1);", + emit(out, "var @2 = Math.floor(@1).toLong();", smapper.popF(), smapper.pushL()); break; case opc_d2i: @@ -700,7 +701,7 @@ smapper.popD(), smapper.pushI()); break; case opc_d2l: - emit(out, "var @2 = Math.floor(@1);", + emit(out, "var @2 = Math.floor(@1).toLong();", smapper.popD(), smapper.pushL()); break; case opc_i2b: @@ -770,11 +771,19 @@ i += 2; String v = encodeConstant(indx); int type = VarType.fromConstantType(jc.getTag(indx)); - emit(out, "var @1 = @2;", smapper.pushT(type), v); + if (type == VarType.LONG) { + final Long lv = new Long(v); + final int low = (int)(lv.longValue() & 0xFFFFFFFF); + final int hi = (int)(lv.longValue() >> 32); + emit(out, "var @1 = 0x@3.next32(0x@2);", smapper.pushL(), + Integer.toHexString(low), Integer.toHexString(hi)); + } else { + emit(out, "var @1 = @2;", smapper.pushT(type), v); + } break; } case opc_lcmp: - emit(out, "var @3 = (@2 == @1) ? 0 : ((@2 < @1) ? -1 : 1);", + emit(out, "var @3 = @2.compare64(@1);", smapper.popL(), smapper.popL(), smapper.pushI()); break; case opc_fcmpl: diff -r 0d277415ed02 -r dbcd1a21f3f8 vm/src/test/java/org/apidesign/vm4brwsr/NumberTest.java --- a/vm/src/test/java/org/apidesign/vm4brwsr/NumberTest.java Thu Feb 07 12:58:12 2013 +0100 +++ b/vm/src/test/java/org/apidesign/vm4brwsr/NumberTest.java Thu Feb 07 13:07:22 2013 +0100 @@ -144,6 +144,552 @@ ); } + @Test public void longConversion() throws Exception { + assertExec("Long from cPool", + Numbers.class, "conversionL__J", + Double.valueOf(Long.MAX_VALUE) + ); + } + + @Test public void longNegate1() throws Exception { + final long res = -0x00fa37d7763e0ca1l; + assertExec("Long negate", + Numbers.class, "negL__J_3B", + Double.valueOf(res), + new byte[] { (byte)0x00, (byte)0xfa, (byte)0x37, (byte)0xd7, (byte)0x76, (byte)0x3e, (byte)0x0c, (byte)0xa1 } + ); + } + + @Test public void longNegate2() throws Exception { + final long res = -0x80fa37d7763e0ca1l; + assertExec("Long negate", + Numbers.class, "negL__J_3B", + Double.valueOf(res), + new byte[] { (byte)0x80, (byte)0xfa, (byte)0x37, (byte)0xd7, (byte)0x76, (byte)0x3e, (byte)0x0c, (byte)0xa1 } + ); + } + + @Test public void longNegate3() throws Exception { + final long res = -0xfffffffffffffeddl; + assertExec("Long negate", + Numbers.class, "negL__J_3B", + Double.valueOf(res), + new byte[] { (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xfe, (byte)0xdd } + ); + } + + @Test public void longAddOverflow() throws Exception { + final long res = Long.MAX_VALUE + 1l; + assertExec("Addition 1+MAX", + Numbers.class, "addL__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)0, (byte)0, (byte)0, (byte)0, (byte)0, (byte)0, (byte)0, (byte)1 } + ); + } + + @Test public void longAddMaxAndMax() throws Exception { + final long res = Long.MAX_VALUE + Long.MAX_VALUE; + assertExec("Addition MAX+MAX", + Numbers.class, "addL__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 longSubUnderflow() throws Exception { + final long res = Long.MIN_VALUE - 1l; + assertExec("Subtraction MIN-1", + Numbers.class, "subL__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)0, (byte)0, (byte)0, (byte)0, (byte)0, (byte)0, (byte)0, (byte)1 } + ); + } + + @Test public void longSubMinAndMin() throws Exception { + final long res = Long.MIN_VALUE - Long.MIN_VALUE; + assertExec("Subtraction MIN-MIN", + Numbers.class, "subL__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 longSubMinAndMax() throws Exception { + final long res = Long.MIN_VALUE - Long.MAX_VALUE; + assertExec("Subtraction MIN-MAX", + Numbers.class, "subL__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)0x7f, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff } + ); + } + + @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 longDivideSmallPositiveNumbers() throws Exception { + final long res = 0xabcdef / 0x123; + assertExec("Division Small Positive Numbers", + Numbers.class, "divL__J_3B_3B", + Double.valueOf(res), + new byte[] { (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xab, (byte)0xcd, (byte)0xef }, + new byte[] { (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x01, (byte)0x23 } + ); + } + + @Test public void longDivideSmallNegativeNumbers() throws Exception { + final long res = -0xabcdef / -0x123; + assertExec("Division Small Negative Numbers", + Numbers.class, "divL__J_3B_3B", + Double.valueOf(res), + new byte[] { (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x54, (byte)0x32, (byte)0x11 }, + new byte[] { (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xfe, (byte)0xdd } + ); + } + + @Test public void longDivideSmallMixedNumbers() throws Exception { + final long res = 0xabcdef / -0x123; + assertExec("Division Small Mixed Numbers", + Numbers.class, "divL__J_3B_3B", + Double.valueOf(res), + new byte[] { (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xab, (byte)0xcd, (byte)0xef }, + new byte[] { (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xfe, (byte)0xdd } + ); + } + + @Test public void longDividePositiveNumbersOneDigitDenom() + throws Exception { + final long res = 0xabcdef0102ffffL / 0x654; + assertExec("Division Positive Numbers One Digit Denom", + Numbers.class, "divL__J_3B_3B", + Double.valueOf(res), + new byte[] { (byte)0x00, (byte)0xab, (byte)0xcd, (byte)0xef, (byte)0x01, (byte)0x02, (byte)0xff, (byte)0xff }, + new byte[] { (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x06, (byte)0x54 } + ); + } + + @Test public void longDivideNegativeNumbersOneDigitDenom() + throws Exception { + final long res = -0xabcdef0102ffffL / -0x654; + assertExec("Division Negative Numbers One Digit Denom", + Numbers.class, "divL__J_3B_3B", + Double.valueOf(res), + new byte[] { (byte)0xff, (byte)0x54, (byte)0x32, (byte)0x10, (byte)0xfe, (byte)0xfd, (byte)0x00, (byte)0x01 }, + new byte[] { (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xf9, (byte)0xac } + ); + } + + @Test public void longDivideMixedNumbersOneDigitDenom() + throws Exception { + final long res = -0xabcdef0102ffffL / 0x654; + assertExec("Division Mixed Numbers One Digit Denom", + Numbers.class, "divL__J_3B_3B", + Double.valueOf(res), + new byte[] { (byte)0xff, (byte)0x54, (byte)0x32, (byte)0x10, (byte)0xfe, (byte)0xfd, (byte)0x00, (byte)0x01 }, + new byte[] { (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x06, (byte)0x54 } + ); + } + + @Test public void longDividePositiveNumbersMultiDigitDenom() + throws Exception { + final long res = 0x7ffefc003322aabbL / 0x89ab1000L; + assertExec("Division Positive Numbers Multi Digit Denom", + Numbers.class, "divL__J_3B_3B", + Double.valueOf(res), + new byte[] { (byte)0x7f, (byte)0xfe, (byte)0xfc, (byte)0x00, (byte)0x33, (byte)0x22, (byte)0xaa, (byte)0xbb }, + new byte[] { (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x89, (byte)0xab, (byte)0x10, (byte)0x00 } + ); + } + + @Test public void longDivideNegativeNumbersMultiDigitDenom() + throws Exception { + final long res = -0x7ffefc003322aabbL / -0x123489ab1001L; + assertExec("Division Negative Numbers Multi Digit Denom", + Numbers.class, "divL__J_3B_3B", + Double.valueOf(res), + new byte[] { (byte)0x80, (byte)0x01, (byte)0x03, (byte)0xff, (byte)0xcc, (byte)0xdd, (byte)0x55, (byte)0x45 }, + new byte[] { (byte)0xff, (byte)0xff, (byte)0xed, (byte)0xcb, (byte)0x76, (byte)0x54, (byte)0xef, (byte)0xff } + ); + } + + @Test public void longDivideMixedNumbersMultiDigitDenom() + throws Exception { + final long res = 0x7ffefc003322aabbL / -0x38f49b0b7574e36L; + assertExec("Division Mixed Numbers Multi Digit Denom", + Numbers.class, "divL__J_3B_3B", + Double.valueOf(res), + new byte[] { (byte)0x7f, (byte)0xfe, (byte)0xfc, (byte)0x00, (byte)0x33, (byte)0x22, (byte)0xaa, (byte)0xbb }, + new byte[] { (byte)0xfc, (byte)0x70, (byte)0xb6, (byte)0x4f, (byte)0x48, (byte)0xa8, (byte)0xb1, (byte)0xca } + ); + } + + @Test public void longDivideWithOverflow() throws Exception { + final long res = 0x8000fffe0000L / 0x8000ffffL; + assertExec("Division With Overflow", + Numbers.class, "divL__J_3B_3B", + Double.valueOf(res), + new byte[] { (byte)0x00, (byte)0x00, (byte)0x80, (byte)0x00, (byte)0xff, (byte)0xfe, (byte)0x00, (byte)0x00 }, + new byte[] { (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x80, (byte)0x00, (byte)0xff, (byte)0xff } + ); + } + + @Test public void longDivideWithCorrection() throws Exception { + final long res = 0x7fff800000000000L / 0x800000000001L; + assertExec("Division With Correction", + Numbers.class, "divL__J_3B_3B", + Double.valueOf(res), + new byte[] { (byte)0x7f, (byte)0xff, (byte)0x80, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00 }, + new byte[] { (byte)0x00, (byte)0x00, (byte)0x80, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x01 } + ); + } + + @Test public void longModuloSmallPositiveNumbers() throws Exception { + final long res = 0xabcdef % 0x123; + assertExec("Modulo Small Positive Numbers", + Numbers.class, "modL__J_3B_3B", + Double.valueOf(res), + new byte[] { (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xab, (byte)0xcd, (byte)0xef }, + new byte[] { (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x01, (byte)0x23 } + ); + } + + @Test public void longModuloSmallNegativeNumbers() throws Exception { + final long res = -0xabcdef % -0x123; + assertExec("Modulo Small Negative Numbers", + Numbers.class, "modL__J_3B_3B", + Double.valueOf(res), + new byte[] { (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x54, (byte)0x32, (byte)0x11 }, + new byte[] { (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xfe, (byte)0xdd } + ); + } + + @Test public void longModuloSmallMixedNumbers() throws Exception { + final long res = 0xabcdef % -0x123; + assertExec("Modulo Small Mixed Numbers", + Numbers.class, "modL__J_3B_3B", + Double.valueOf(res), + new byte[] { (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xab, (byte)0xcd, (byte)0xef }, + new byte[] { (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xfe, (byte)0xdd } + ); + } + + @Test public void longModuloPositiveNumbersOneDigitDenom() + throws Exception { + final long res = 0xabcdef0102ffffL % 0x654; + assertExec("Modulo Positive Numbers One Digit Denom", + Numbers.class, "modL__J_3B_3B", + Double.valueOf(res), + new byte[] { (byte)0x00, (byte)0xab, (byte)0xcd, (byte)0xef, (byte)0x01, (byte)0x02, (byte)0xff, (byte)0xff }, + new byte[] { (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x06, (byte)0x54 } + ); + } + + @Test public void longModuloNegativeNumbersOneDigitDenom() + throws Exception { + final long res = -0xabcdef0102ffffL % -0x654; + assertExec("Modulo Negative Numbers One Digit Denom", + Numbers.class, "modL__J_3B_3B", + Double.valueOf(res), + new byte[] { (byte)0xff, (byte)0x54, (byte)0x32, (byte)0x10, (byte)0xfe, (byte)0xfd, (byte)0x00, (byte)0x01 }, + new byte[] { (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xf9, (byte)0xac } + ); + } + + @Test public void longModuloMixedNumbersOneDigitDenom() + throws Exception { + final long res = -0xabcdef0102ffffL % 0x654; + assertExec("Modulo Mixed Numbers One Digit Denom", + Numbers.class, "modL__J_3B_3B", + Double.valueOf(res), + new byte[] { (byte)0xff, (byte)0x54, (byte)0x32, (byte)0x10, (byte)0xfe, (byte)0xfd, (byte)0x00, (byte)0x01 }, + new byte[] { (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x06, (byte)0x54 } + ); + } + + @Test public void longModuloPositiveNumbersMultiDigitDenom() + throws Exception { + final long res = 0x7ffefc003322aabbL % 0x89ab1000L; + assertExec("Modulo Positive Numbers Multi Digit Denom", + Numbers.class, "modL__J_3B_3B", + Double.valueOf(res), + new byte[] { (byte)0x7f, (byte)0xfe, (byte)0xfc, (byte)0x00, (byte)0x33, (byte)0x22, (byte)0xaa, (byte)0xbb }, + new byte[] { (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x89, (byte)0xab, (byte)0x10, (byte)0x00 } + ); + } + + @Test public void longModuloNegativeNumbersMultiDigitDenom() + throws Exception { + final long res = -0x7ffefc003322aabbL % -0x123489ab1001L; + assertExec("Modulo Negative Numbers Multi Digit Denom", + Numbers.class, "modL__J_3B_3B", + Double.valueOf(res), + new byte[] { (byte)0x80, (byte)0x01, (byte)0x03, (byte)0xff, (byte)0xcc, (byte)0xdd, (byte)0x55, (byte)0x45 }, + new byte[] { (byte)0xff, (byte)0xff, (byte)0xed, (byte)0xcb, (byte)0x76, (byte)0x54, (byte)0xef, (byte)0xff } + ); + } + + @Test public void longModuloMixedNumbersMultiDigitDenom() + throws Exception { + final long res = 0x7ffefc003322aabbL % -0x38f49b0b7574e36L; + assertExec("Modulo Mixed Numbers Multi Digit Denom", + Numbers.class, "modL__J_3B_3B", + Double.valueOf(res), + new byte[] { (byte)0x7f, (byte)0xfe, (byte)0xfc, (byte)0x00, (byte)0x33, (byte)0x22, (byte)0xaa, (byte)0xbb }, + new byte[] { (byte)0xfc, (byte)0x70, (byte)0xb6, (byte)0x4f, (byte)0x48, (byte)0xa8, (byte)0xb1, (byte)0xca } + ); + } + + @Test public void longModuloWithOverflow() throws Exception { + final long res = 0x8000fffe0000L % 0x8000ffffL; + assertExec("Modulo With Overflow", + Numbers.class, "modL__J_3B_3B", + Double.valueOf(res), + new byte[] { (byte)0x00, (byte)0x00, (byte)0x80, (byte)0x00, (byte)0xff, (byte)0xfe, (byte)0x00, (byte)0x00 }, + new byte[] { (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x80, (byte)0x00, (byte)0xff, (byte)0xff } + ); + } + + @Test public void longModuloWithCorrection() throws Exception { + final long res = 0x7fff800000000000L % 0x800000000001L; + assertExec("Modulo With Correction", + Numbers.class, "modL__J_3B_3B", + Double.valueOf(res), + new byte[] { (byte)0x7f, (byte)0xff, (byte)0x80, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00 }, + new byte[] { (byte)0x00, (byte)0x00, (byte)0x80, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x01 } + ); + } + + @Test public void longShiftL1() throws Exception { + final long res = 0x00fa37d7763e0ca1l << 5; + assertExec("Long << 5", + Numbers.class, "shlL__J_3BI", + Double.valueOf(res), + new byte[] { (byte)0x00, (byte)0xfa, (byte)0x37, (byte)0xd7, (byte)0x76, (byte)0x3e, (byte)0x0c, (byte)0xa1 }, + 5); + } + + @Test public void longShiftL2() throws Exception { + final long res = 0x00fa37d7763e0ca1l << 32; + assertExec("Long << 32", + Numbers.class, "shlL__J_3BI", + Double.valueOf(res), + new byte[] { (byte)0x00, (byte)0xfa, (byte)0x37, (byte)0xd7, (byte)0x76, (byte)0x3e, (byte)0x0c, (byte)0xa1 }, + 32); + } + + @Test public void longShiftL3() throws Exception { + final long res = 0x00fa37d7763e0ca1l << 45; + assertExec("Long << 45", + Numbers.class, "shlL__J_3BI", + Double.valueOf(res), + new byte[] { (byte)0x00, (byte)0xfa, (byte)0x37, (byte)0xd7, (byte)0x76, (byte)0x3e, (byte)0x0c, (byte)0xa1 }, + 45); + } + + @Test public void longShiftR1() throws Exception { + final long res = 0x00fa37d7763e0ca1l >> 5; + assertExec("Long >> 5", + Numbers.class, "shrL__J_3BI", + Double.valueOf(res), + new byte[] { (byte)0x00, (byte)0xfa, (byte)0x37, (byte)0xd7, (byte)0x76, (byte)0x3e, (byte)0x0c, (byte)0xa1 }, + 5); + } + + @Test public void longShiftR2() throws Exception { + final long res = 0x00fa37d7763e0ca1l >> 32; + assertExec("Long >> 32", + Numbers.class, "shrL__J_3BI", + Double.valueOf(res), + new byte[] { (byte)0x00, (byte)0xfa, (byte)0x37, (byte)0xd7, (byte)0x76, (byte)0x3e, (byte)0x0c, (byte)0xa1 }, + 32); + } + + @Test public void longShiftR3() throws Exception { + final long res = 0x00fa37d7763e0ca1l >> 45; + assertExec("Long >> 45", + Numbers.class, "shrL__J_3BI", + Double.valueOf(res), + new byte[] { (byte)0x00, (byte)0xfa, (byte)0x37, (byte)0xd7, (byte)0x76, (byte)0x3e, (byte)0x0c, (byte)0xa1 }, + 45); + } + + @Test public void longUShiftR1() throws Exception { + final long res = 0x00fa37d7763e0ca1l >>> 5; + assertExec("Long >>> 5", + Numbers.class, "ushrL__J_3BI", + Double.valueOf(res), + new byte[] { (byte)0x00, (byte)0xfa, (byte)0x37, (byte)0xd7, (byte)0x76, (byte)0x3e, (byte)0x0c, (byte)0xa1 }, + 5); + } + + @Test public void longUShiftR2() throws Exception { + final long res = 0x00fa37d7763e0ca1l >>> 45; + assertExec("Long >>> 45", + Numbers.class, "ushrL__J_3BI", + Double.valueOf(res), + new byte[] { (byte)0x00, (byte)0xfa, (byte)0x37, (byte)0xd7, (byte)0x76, (byte)0x3e, (byte)0x0c, (byte)0xa1 }, + 45); + } + + @Test public void longUShiftR3() throws Exception { + final long res = 0xf0fa37d7763e0ca1l >>> 5; + assertExec("Long >>> 5", + Numbers.class, "ushrL__J_3BI", + Double.valueOf(res), + new byte[] { (byte)0xf0, (byte)0xfa, (byte)0x37, (byte)0xd7, (byte)0x76, (byte)0x3e, (byte)0x0c, (byte)0xa1 }, + 5); + } + + @Test public void longUShiftR4() throws Exception { + final long res = 0xf0fa37d7763e0ca1l >>> 45; + assertExec("Long >>> 45", + Numbers.class, "ushrL__J_3BI", + Double.valueOf(res), + new byte[] { (byte)0xf0, (byte)0xfa, (byte)0x37, (byte)0xd7, (byte)0x76, (byte)0x3e, (byte)0x0c, (byte)0xa1 }, + 45); + } + + @Test public void longAnd() throws Exception { + final long res = 0x00fa37d7763e0ca1l & 0xa7b3432fff00123el; + assertExec("LOng binary AND", + Numbers.class, "andL__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 longOr() throws Exception { + final long res = 0x00fa37d7763e0ca1l | 0xa7b3432fff00123el; + assertExec("Long binary OR", + Numbers.class, "orL__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 longXor1() throws Exception { + final long res = 0x00fa37d7763e0ca1l ^ 0xa7b3432fff00123el; + assertExec("Long binary XOR", + Numbers.class, "xorL__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 longXor2() throws Exception { + final long res = 0x00fa37d7763e0ca1l ^ 0x00000000ff00123el; + assertExec("Long binary XOR", + Numbers.class, "xorL__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)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xff, (byte)0x00, (byte)0x12, (byte)0x3e } + ); + } + + @Test public void longXor3() throws Exception { + final long res = 0x00000000763e0ca1l ^ 0x00000000ff00123el; + assertExec("Long binary XOR", + Numbers.class, "xorL__J_3B_3B", + Double.valueOf(res), + new byte[] { (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x76, (byte)0x3e, (byte)0x0c, (byte)0xa1 }, + new byte[] { (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0xff, (byte)0x00, (byte)0x12, (byte)0x3e } + ); + } + + @Test public void longCompareSameNumbers() throws Exception { + assertExec("Long compare same numbers", + Numbers.class, "compareL__I_3B_3BI", + 0.0, + new byte[] { (byte)0x00, (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)0x00 }, + 0 + ); + } + + @Test public void longComparePositiveNumbers() throws Exception { + assertExec("Long compare positive numbers", + Numbers.class, "compareL__I_3B_3BI", + -1.0, + new byte[] { (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x20, (byte)0x00, (byte)0x00 }, + new byte[] { (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x10, (byte)0x00, (byte)0x00, (byte)0x00 }, + 0 + ); + } + + @Test public void longCompareNegativeNumbers() throws Exception { + assertExec("Long compare negative numbers", + Numbers.class, "compareL__I_3B_3BI", + 1.0, + new byte[] { (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff }, + new byte[] { (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00 }, + 0 + ); + } + + @Test public void longCompareMixedNumbers() throws Exception { + assertExec("Long compare mixed numbers", + Numbers.class, "compareL__I_3B_3BI", + -1.0, + new byte[] { (byte)0x80, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00 }, + new byte[] { (byte)0x7f, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff }, + 0 + ); + } + private static CharSequence codeSeq; private static Invocable code; @@ -157,31 +703,20 @@ } private static void assertExec( - String msg, Class clazz, String method, Object expRes, Object... args) throws Exception { - - Object ret = null; - try { - ret = code.invokeFunction("bck2brwsr"); - ret = code.invokeMethod(ret, "loadClass", clazz.getName()); - ret = code.invokeMethod(ret, method, args); - } catch (ScriptException ex) { - fail("Execution failed in\n" + StaticMethodTest.dumpJS(codeSeq), ex); - } catch (NoSuchMethodException ex) { - fail("Cannot find method in\n" + StaticMethodTest.dumpJS(codeSeq), ex); - } - if (ret == null && expRes == null) { - return; - } - if (expRes.equals(ret)) { + String msg, Class clazz, String method, Object expRes, Object... args) throws Exception + { + Object ret = TestUtils.execCode(code, codeSeq, msg, clazz, method, expRes, args); + if (ret == null) { return; } if (expRes instanceof Double && ret instanceof Double) { double expD = ((Double)expRes).doubleValue(); double retD = ((Double)ret).doubleValue(); - assertEquals(retD, expD, 0.000004, msg + " was " + ret + "\n" + StaticMethodTest.dumpJS(codeSeq)); + assertEquals(retD, expD, 0.000004, msg + " " + + StaticMethodTest.dumpJS(codeSeq)); return; } - assertEquals(ret, expRes, msg + "was: " + ret + "\n" + StaticMethodTest.dumpJS(codeSeq)); + assertEquals(ret, expRes, msg + " " + StaticMethodTest.dumpJS(codeSeq)); } } diff -r 0d277415ed02 -r dbcd1a21f3f8 vm/src/test/java/org/apidesign/vm4brwsr/Numbers.java --- a/vm/src/test/java/org/apidesign/vm4brwsr/Numbers.java Thu Feb 07 12:58:12 2013 +0100 +++ b/vm/src/test/java/org/apidesign/vm4brwsr/Numbers.java Thu Feb 07 13:07:22 2013 +0100 @@ -67,4 +67,136 @@ static String floatToString() { return new Float(7.0).toString().toString(); } + + public static long conversionL() { + return Long.MAX_VALUE; + } + + public static long negL(byte[] arrValue) throws IOException { + ByteArrayInputStream isValue = new ByteArrayInputStream(arrValue); + DataInputStream disValue = new DataInputStream(isValue); + return (-disValue.readLong()); + } + + public static long addL(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 subL(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 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(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 modL(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 shlL(byte[] arrValue, int nBits) throws IOException { + ByteArrayInputStream isValue = new ByteArrayInputStream(arrValue); + DataInputStream disValue = new DataInputStream(isValue); + return (disValue.readLong() << nBits); + } + + public static long shrL(byte[] arrValue, int nBits) throws IOException { + ByteArrayInputStream isValue = new ByteArrayInputStream(arrValue); + DataInputStream disValue = new DataInputStream(isValue); + return (disValue.readLong() >> nBits); + } + + public static long ushrL(byte[] arrValue, int nBits) throws IOException { + ByteArrayInputStream isValue = new ByteArrayInputStream(arrValue); + DataInputStream disValue = new DataInputStream(isValue); + return (disValue.readLong() >>> nBits); + } + + public static long andL(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 orL(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 xorL(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 int compareL(byte[] arrX, byte[] arrY, + int zero) throws IOException { + ByteArrayInputStream isX = new ByteArrayInputStream(arrX); + DataInputStream disX = new DataInputStream(isX); + ByteArrayInputStream isY = new ByteArrayInputStream(arrY); + DataInputStream disY = new DataInputStream(isY); + final long x = disX.readLong(); + final long y = disY.readLong(); + + final int xyResult = compareL(x, y, zero); + final int yxResult = compareL(y, x, zero); + + return ((xyResult + yxResult) == 0) ? xyResult : -2; + } + + private static int compareL(long x, long y, int zero) { + int result = -2; + int trueCount = 0; + + x += zero; + if (x == y) { + result = 0; + ++trueCount; + } + + x += zero; + if (x < y) { + result = -1; + ++trueCount; + } + + x += zero; + if (x > y) { + result = 1; + ++trueCount; + } + + return (trueCount == 1) ? result : -2; + } } diff -r 0d277415ed02 -r dbcd1a21f3f8 vm/src/test/java/org/apidesign/vm4brwsr/StaticMethodTest.java --- a/vm/src/test/java/org/apidesign/vm4brwsr/StaticMethodTest.java Thu Feb 07 12:58:12 2013 +0100 +++ b/vm/src/test/java/org/apidesign/vm4brwsr/StaticMethodTest.java Thu Feb 07 13:07:22 2013 +0100 @@ -353,17 +353,8 @@ String msg, Class clazz, String method, Object expRes, Object... args ) throws Exception { - Object ret = null; - try { - ret = toRun.invokeFunction("bck2brwsr"); - ret = toRun.invokeMethod(ret, "loadClass", clazz.getName()); - ret = toRun.invokeMethod(ret, method, args); - } catch (ScriptException ex) { - fail("Execution failed in\n" + dumpJS(theCode), ex); - } catch (NoSuchMethodException ex) { - fail("Cannot find method in\n" + dumpJS(theCode), ex); - } - if (ret == null && expRes == null) { + Object ret = TestUtils.execCode(toRun, theCode, msg, clazz, method, expRes, args); + if (ret == null) { return; } if (expRes != null && expRes.equals(ret)) { diff -r 0d277415ed02 -r dbcd1a21f3f8 vm/src/test/java/org/apidesign/vm4brwsr/TestUtils.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm/src/test/java/org/apidesign/vm4brwsr/TestUtils.java Thu Feb 07 13:07:22 2013 +0100 @@ -0,0 +1,60 @@ +/** + * 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.apidesign.vm4brwsr; + +import javax.script.Invocable; +import javax.script.ScriptException; +import static org.testng.Assert.*; + +class TestUtils { + + static Object execCode(Invocable code, CharSequence codeSeq, + String msg, Class clazz, String method, Object expRes, Object... args) + throws Exception + { + Object ret = null; + try { + ret = code.invokeFunction("bck2brwsr"); + ret = code.invokeMethod(ret, "loadClass", clazz.getName()); + ret = code.invokeMethod(ret, method, args); + } catch (ScriptException ex) { + fail("Execution failed in " + StaticMethodTest.dumpJS(codeSeq), ex); + } catch (NoSuchMethodException ex) { + fail("Cannot find method in " + StaticMethodTest.dumpJS(codeSeq), ex); + } + if (ret == null && expRes == null) { + return null; + } + if (expRes.equals(ret)) { + return null; + } + if (expRes instanceof Number) { + // in case of Long it is necessary convert it to number + // since the Long is represented by two numbers in JavaScript + try { + ret = code.invokeMethod(ret, "toFP"); + ret = code.invokeFunction("Number", ret); + } catch (ScriptException ex) { + fail("Conversion to number failed in " + StaticMethodTest.dumpJS(codeSeq), ex); + } catch (NoSuchMethodException ex) { + fail("Cannot find global Number(x) function in " + StaticMethodTest.dumpJS(codeSeq), ex); + } + } + return ret; + } +} diff -r 0d277415ed02 -r dbcd1a21f3f8 vm/src/test/java/org/apidesign/vm4brwsr/VMLazyTest.java --- a/vm/src/test/java/org/apidesign/vm4brwsr/VMLazyTest.java Thu Feb 07 12:58:12 2013 +0100 +++ b/vm/src/test/java/org/apidesign/vm4brwsr/VMLazyTest.java Thu Feb 07 13:07:22 2013 +0100 @@ -51,7 +51,7 @@ ScriptEngine[] arr = { null }; code = StaticMethodTest.compileClass(sb, arr, - "org/apidesign/vm4brwsr/VM" + new String[]{"org/apidesign/vm4brwsr/VM", "org/apidesign/vm4brwsr/StaticMethod"} ); arr[0].getContext().setAttribute("loader", new BytesLoader(), ScriptContext.ENGINE_SCOPE); codeSeq = sb; diff -r 0d277415ed02 -r dbcd1a21f3f8 vmtest/src/test/java/org/apidesign/bck2brwsr/tck/LongArithmeticTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/LongArithmeticTest.java Thu Feb 07 13:07:22 2013 +0100 @@ -0,0 +1,104 @@ +/** + * 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.apidesign.bck2brwsr.tck; + +import org.apidesign.bck2brwsr.vmtest.Compare; +import org.apidesign.bck2brwsr.vmtest.VMTest; +import org.testng.annotations.Factory; + +/** + * + * @author Jaroslav Tulach + */ +public class LongArithmeticTest { + + private static long add(long x, long y) { + return (x + y); + } + + private static long sub(long x, long y) { + return (x - y); + } + + private static long mul(long x, long y) { + return (x * y); + } + + private static long div(long x, long y) { + return (x / y); + } + + private static long mod(long x, long y) { + return (x % y); + } + + @Compare public long conversion() { + return Long.MAX_VALUE; + } + + /* + @Compare public long addOverflow() { + return add(Long.MAX_VALUE, 1l); + } + + @Compare public long subUnderflow() { + return sub(Long.MIN_VALUE, 1l); + } + + @Compare public long addMaxLongAndMaxLong() { + return add(Long.MAX_VALUE, Long.MAX_VALUE); + } + + @Compare public long subMinLongAndMinLong() { + return sub(Long.MIN_VALUE, Long.MIN_VALUE); + } + + @Compare public long multiplyMaxLong() { + return mul(Long.MAX_VALUE, 2l); + } + + @Compare public long multiplyMaxLongAndMaxLong() { + return mul(Long.MAX_VALUE, Long.MAX_VALUE); + } + + @Compare public long multiplyMinLong() { + return mul(Long.MIN_VALUE, 2l); + } + + @Compare public long multiplyMinLongAndMinLong() { + return mul(Long.MIN_VALUE, Long.MIN_VALUE); + } + + @Compare public long multiplyPrecision() { + return mul(17638l, 1103l); + } + + @Compare public long division() { + return div(1l, 2l); + } + + @Compare public long divisionReminder() { + return mod(1l, 2l); + } + */ + + @Factory + public static Object[] create() { + return VMTest.create(LongArithmeticTest.class); + } +}