diff --git a/core/src/main/java/org/teavm/backend/javascript/rendering/NameFrequencyEstimator.java b/core/src/main/java/org/teavm/backend/javascript/rendering/NameFrequencyEstimator.java index 356d74338..74053018d 100644 --- a/core/src/main/java/org/teavm/backend/javascript/rendering/NameFrequencyEstimator.java +++ b/core/src/main/java/org/teavm/backend/javascript/rendering/NameFrequencyEstimator.java @@ -312,8 +312,10 @@ class NameFrequencyEstimator extends RecursiveVisitor implements MethodNodeVisit if (expr.getSource() == OperationType.LONG) { if (expr.getTarget() == OperationType.DOUBLE || expr.getTarget() == OperationType.FLOAT) { consumer.consumeFunction("Long_toNumber"); + } else if (expr.getTarget() == OperationType.INT) { + consumer.consumeFunction("Long_lo"); } - } else { + } else if (expr.getTarget() == OperationType.LONG) { switch (expr.getSource()) { case INT: consumer.consumeFunction("Long_fromInt"); @@ -339,7 +341,7 @@ class NameFrequencyEstimator extends RecursiveVisitor implements MethodNodeVisit } else if ((int) value == value) { consumer.consumeFunction("Long_fromInt"); } else { - consumer.consumeFunction("Long"); + consumer.consumeFunction("Long_create"); } } } diff --git a/core/src/main/java/org/teavm/backend/javascript/rendering/Renderer.java b/core/src/main/java/org/teavm/backend/javascript/rendering/Renderer.java index b9a73bac3..149d1422b 100644 --- a/core/src/main/java/org/teavm/backend/javascript/rendering/Renderer.java +++ b/core/src/main/java/org/teavm/backend/javascript/rendering/Renderer.java @@ -261,7 +261,8 @@ public class Renderer implements RenderingManager { "$rt_createLongArrayFromData", "$rt_createBooleanArray", "$rt_createByteArray", "$rt_createShortArray", "$rt_createCharArray", "$rt_createIntArray", "$rt_createLongArray", "$rt_createFloatArray", "$rt_createDoubleArray", "$rt_compare", - "Long_toNumber", "Long_fromInt", "Long_fromNumber", "Long", "Long_ZERO"); + "Long_toNumber", "Long_fromInt", "Long_fromNumber", "Long_create", "Long_ZERO", + "Long_hi", "Long_lo"); } public void renderLongRuntimeAliases() throws IOException { diff --git a/core/src/main/java/org/teavm/backend/javascript/rendering/RenderingContext.java b/core/src/main/java/org/teavm/backend/javascript/rendering/RenderingContext.java index f1f087ed1..f1f7893e7 100644 --- a/core/src/main/java/org/teavm/backend/javascript/rendering/RenderingContext.java +++ b/core/src/main/java/org/teavm/backend/javascript/rendering/RenderingContext.java @@ -239,7 +239,7 @@ public class RenderingContext { } else if ((int) value == value) { writer.appendFunction("Long_fromInt").append("(").append(String.valueOf(value)).append(")"); } else { - writer.append("new ").appendFunction("Long").append("(" + (value & 0xFFFFFFFFL) + writer.appendFunction("Long_create").append("(" + (value & 0xFFFFFFFFL) + ", " + (value >>> 32) + ")"); } } else if (cst instanceof Character) { diff --git a/core/src/main/java/org/teavm/backend/javascript/rendering/StatementRenderer.java b/core/src/main/java/org/teavm/backend/javascript/rendering/StatementRenderer.java index 402c9616f..5ba1684ee 100644 --- a/core/src/main/java/org/teavm/backend/javascript/rendering/StatementRenderer.java +++ b/core/src/main/java/org/teavm/backend/javascript/rendering/StatementRenderer.java @@ -929,11 +929,13 @@ public class StatementRenderer implements ExprVisitor, StatementVisitor { precedence = Precedence.MEMBER_ACCESS; Expr longShifted = extractLongRightShiftedBy32(expr.getValue()); if (longShifted != null) { + writer.appendFunction("Long_hi").append("("); longShifted.acceptVisitor(this); - writer.append(".hi"); + writer.append(")"); } else { + writer.appendFunction("Long_lo").append("("); expr.getValue().acceptVisitor(this); - writer.append(".lo"); + writer.append(")"); } break; case FLOAT: diff --git a/core/src/main/resources/org/teavm/backend/javascript/long.js b/core/src/main/resources/org/teavm/backend/javascript/long.js index 420a9a452..ec0cf7bd2 100644 --- a/core/src/main/resources/org/teavm/backend/javascript/long.js +++ b/core/src/main/resources/org/teavm/backend/javascript/long.js @@ -14,491 +14,646 @@ * limitations under the License. */ "use strict"; -function Long_eq(a, b) { - return a.hi === b.hi && a.lo === b.lo; -} -function Long_ne(a, b) { - return a.hi !== b.hi || a.lo !== b.lo; -} -function Long_gt(a, b) { - if (a.hi < b.hi) { - return false; - } - if (a.hi > b.hi) { - return true; - } - var x = a.lo >>> 1; - var y = b.lo >>> 1; - if (x !== y) { - return x > y; - } - return (a.lo & 1) > (b.lo & 1); -} -function Long_ge(a, b) { - if (a.hi < b.hi) { - return false; - } - if (a.hi > b.hi) { - return true; - } - var x = a.lo >>> 1; - var y = b.lo >>> 1; - if (x !== y) { - return x >= y; - } - return (a.lo & 1) >= (b.lo & 1); -} -function Long_lt(a, b) { - if (a.hi > b.hi) { - return false; - } - if (a.hi < b.hi) { - return true; - } - var x = a.lo >>> 1; - var y = b.lo >>> 1; - if (x !== y) { - return x < y; - } - return (a.lo & 1) < (b.lo & 1); -} -function Long_le(a, b) { - if (a.hi > b.hi) { - return false; - } - if (a.hi < b.hi) { - return true; - } - var x = a.lo >>> 1; - var y = b.lo >>> 1; - if (x !== y) { - return x <= y; - } - return (a.lo & 1) <= (b.lo & 1); -} -function Long_add(a, b) { - if (a.hi === (a.lo >> 31) && b.hi === (b.lo >> 31)) { - return Long_fromNumber(a.lo + b.lo); - } else if (Math.abs(a.hi) < Long_MAX_NORMAL && Math.abs(b.hi) < Long_MAX_NORMAL) { - return Long_fromNumber(Long_toNumber(a) + Long_toNumber(b)); - } - var a_lolo = a.lo & 0xFFFF; - var a_lohi = a.lo >>> 16; - var a_hilo = a.hi & 0xFFFF; - var a_hihi = a.hi >>> 16; - var b_lolo = b.lo & 0xFFFF; - var b_lohi = b.lo >>> 16; - var b_hilo = b.hi & 0xFFFF; - var b_hihi = b.hi >>> 16; +var Long_eq; +var Long_ne; +var Long_gt; +var Long_ge; +var Long_lt; +var Long_le; +var Long_compare; +var Long_add; +var Long_sub; +var Long_inc; +var Long_dec; +var Long_mul; +var Long_div; +var Long_rem; +var Long_udiv; +var Long_urem; +var Long_neg; +var Long_and; +var Long_or; +var Long_xor; +var Long_shl; +var Long_shr; +var Long_shru; +var Long_not; - var lolo = (a_lolo + b_lolo) | 0; - var lohi = (a_lohi + b_lohi + (lolo >> 16)) | 0; - var hilo = (a_hilo + b_hilo + (lohi >> 16)) | 0; - var hihi = (a_hihi + b_hihi + (hilo >> 16)) | 0; - return new Long((lolo & 0xFFFF) | ((lohi & 0xFFFF) << 16), (hilo & 0xFFFF) | ((hihi & 0xFFFF) << 16)); -} -function Long_inc(a) { - var lo = (a.lo + 1) | 0; - var hi = a.hi; - if (lo === 0) { - hi = (hi + 1) | 0; +if (typeof BigInt !== 'function') { + Long_eq = function(a, b) { + return a.hi === b.hi && a.lo === b.lo; } - return new Long(lo, hi); -} -function Long_dec(a) { - var lo = (a.lo - 1) | 0; - var hi = a.hi; - if (lo === -1) { - hi = (hi - 1) | 0; - } - return new Long(lo, hi); -} -function Long_neg(a) { - return Long_inc(new Long(a.lo ^ 0xFFFFFFFF, a.hi ^ 0xFFFFFFFF)); -} -function Long_sub(a, b) { - if (a.hi === (a.lo >> 31) && b.hi === (b.lo >> 31)) { - return Long_fromNumber(a.lo - b.lo); - } - var a_lolo = a.lo & 0xFFFF; - var a_lohi = a.lo >>> 16; - var a_hilo = a.hi & 0xFFFF; - var a_hihi = a.hi >>> 16; - var b_lolo = b.lo & 0xFFFF; - var b_lohi = b.lo >>> 16; - var b_hilo = b.hi & 0xFFFF; - var b_hihi = b.hi >>> 16; - var lolo = (a_lolo - b_lolo) | 0; - var lohi = (a_lohi - b_lohi + (lolo >> 16)) | 0; - var hilo = (a_hilo - b_hilo + (lohi >> 16)) | 0; - var hihi = (a_hihi - b_hihi + (hilo >> 16)) | 0; - return new Long((lolo & 0xFFFF) | ((lohi & 0xFFFF) << 16), (hilo & 0xFFFF) | ((hihi & 0xFFFF) << 16)); -} -function Long_compare(a, b) { - var r = a.hi - b.hi; - if (r !== 0) { - return r; + Long_ne = function(a, b) { + return a.hi !== b.hi || a.lo !== b.lo; } - r = (a.lo >>> 1) - (b.lo >>> 1); - if (r !== 0) { - return r; - } - return (a.lo & 1) - (b.lo & 1); -} -function Long_isPositive(a) { - return (a.hi & 0x80000000) === 0; -} -function Long_isNegative(a) { - return (a.hi & 0x80000000) !== 0; -} -function Long_mul(a, b) { - var positive = Long_isNegative(a) === Long_isNegative(b); - if (Long_isNegative(a)) { - a = Long_neg(a); - } - if (Long_isNegative(b)) { - b = Long_neg(b); - } - var a_lolo = a.lo & 0xFFFF; - var a_lohi = a.lo >>> 16; - var a_hilo = a.hi & 0xFFFF; - var a_hihi = a.hi >>> 16; - var b_lolo = b.lo & 0xFFFF; - var b_lohi = b.lo >>> 16; - var b_hilo = b.hi & 0xFFFF; - var b_hihi = b.hi >>> 16; - var lolo = 0; - var lohi = 0; - var hilo = 0; - var hihi = 0; - lolo = (a_lolo * b_lolo) | 0; - lohi = lolo >>> 16; - lohi = ((lohi & 0xFFFF) + a_lohi * b_lolo) | 0; - hilo = (hilo + (lohi >>> 16)) | 0; - lohi = ((lohi & 0xFFFF) + a_lolo * b_lohi) | 0; - hilo = (hilo + (lohi >>> 16)) | 0; - hihi = hilo >>> 16; - hilo = ((hilo & 0xFFFF) + a_hilo * b_lolo) | 0; - hihi = (hihi + (hilo >>> 16)) | 0; - hilo = ((hilo & 0xFFFF) + a_lohi * b_lohi) | 0; - hihi = (hihi + (hilo >>> 16)) | 0; - hilo = ((hilo & 0xFFFF) + a_lolo * b_hilo) | 0; - hihi = (hihi + (hilo >>> 16)) | 0; - hihi = (hihi + a_hihi * b_lolo + a_hilo * b_lohi + a_lohi * b_hilo + a_lolo * b_hihi) | 0; - var result = new Long((lolo & 0xFFFF) | (lohi << 16), (hilo & 0xFFFF) | (hihi << 16)); - return positive ? result : Long_neg(result); -} -function Long_div(a, b) { - if (Math.abs(a.hi) < Long_MAX_NORMAL && Math.abs(b.hi) < Long_MAX_NORMAL) { - return Long_fromNumber(Long_toNumber(a) / Long_toNumber(b)); - } - return Long_divRem(a, b)[0]; -} -function Long_udiv(a, b) { - if (a.hi >= 0 && a.hi < Long_MAX_NORMAL && b.hi >= 0 && b.hi < Long_MAX_NORMAL) { - return Long_fromNumber(Long_toNumber(a) / Long_toNumber(b)); - } - return Long_udivRem(a, b)[0]; -} -function Long_rem(a, b) { - if (Math.abs(a.hi) < Long_MAX_NORMAL && Math.abs(b.hi) < Long_MAX_NORMAL) { - return Long_fromNumber(Long_toNumber(a) % Long_toNumber(b)); - } - return Long_divRem(a, b)[1]; -} -function Long_urem(a, b) { - if (a.hi >= 0 && a.hi < Long_MAX_NORMAL && b.hi >= 0 && b.hi < Long_MAX_NORMAL) { - return Long_fromNumber(Long_toNumber(a) / Long_toNumber(b)); - } - return Long_udivRem(a, b)[1]; -} -function Long_divRem(a, b) { - if (b.lo === 0 && b.hi === 0) { - throw new Error("Division by zero"); - } - var positive = Long_isNegative(a) === Long_isNegative(b); - if (Long_isNegative(a)) { - a = Long_neg(a); - } - if (Long_isNegative(b)) { - b = Long_neg(b); - } - a = new LongInt(a.lo, a.hi, 0); - b = new LongInt(b.lo, b.hi, 0); - var q = LongInt_div(a, b); - a = new Long(a.lo, a.hi); - q = new Long(q.lo, q.hi); - return positive ? [q, a] : [Long_neg(q), Long_neg(a)]; -} -function Long_udivRem(a, b) { - if (b.lo === 0 && b.hi === 0) { - throw new Error("Division by zero"); - } - a = new LongInt(a.lo, a.hi, 0); - b = new LongInt(b.lo, b.hi, 0); - var q = LongInt_div(a, b); - a = new Long(a.lo, a.hi); - q = new Long(q.lo, q.hi); - return [q, a]; -} -function Long_shiftLeft16(a) { - return new Long(a.lo << 16, (a.lo >>> 16) | (a.hi << 16)); -} -function Long_shiftRight16(a) { - return new Long((a.lo >>> 16) | (a.hi << 16), a.hi >>> 16); -} -function Long_and(a, b) { - return new Long(a.lo & b.lo, a.hi & b.hi); -} -function Long_or(a, b) { - return new Long(a.lo | b.lo, a.hi | b.hi); -} -function Long_xor(a, b) { - return new Long(a.lo ^ b.lo, a.hi ^ b.hi); -} -function Long_shl(a, b) { - b &= 63; - if (b === 0) { - return a; - } else if (b < 32) { - return new Long(a.lo << b, (a.lo >>> (32 - b)) | (a.hi << b)); - } else if (b === 32) { - return new Long(0, a.lo); - } else { - return new Long(0, a.lo << (b - 32)); - } -} -function Long_shr(a, b) { - b &= 63; - if (b === 0) { - return a; - } else if (b < 32) { - return new Long((a.lo >>> b) | (a.hi << (32 - b)), a.hi >> b); - } else if (b === 32) { - return new Long(a.hi, a.hi >> 31); - } else { - return new Long((a.hi >> (b - 32)), a.hi >> 31); - } -} -function Long_shru(a, b) { - b &= 63; - if (b === 0) { - return a; - } else if (b < 32) { - return new Long((a.lo >>> b) | (a.hi << (32 - b)), a.hi >>> b); - } else if (b === 32) { - return new Long(a.hi, 0); - } else { - return new Long((a.hi >>> (b - 32)), 0); - } -} -function Long_not(a) { - return new Long(~a.hi, ~a.lo); -} - -// Represents a mutable 80-bit unsigned integer -function LongInt(lo, hi, sup) { - this.lo = lo; - this.hi = hi; - this.sup = sup; -} -function LongInt_mul(a, b) { - var a_lolo = ((a.lo & 0xFFFF) * b) | 0; - var a_lohi = ((a.lo >>> 16) * b) | 0; - var a_hilo = ((a.hi & 0xFFFF) * b) | 0; - var a_hihi = ((a.hi >>> 16) * b) | 0; - var sup = (a.sup * b) | 0; - - a_lohi = (a_lohi + (a_lolo >>> 16)) | 0; - a_hilo = (a_hilo + (a_lohi >>> 16)) | 0; - a_hihi = (a_hihi + (a_hilo >>> 16)) | 0; - sup = (sup + (a_hihi >>> 16)) | 0; - a.lo = (a_lolo & 0xFFFF) | (a_lohi << 16); - a.hi = (a_hilo & 0xFFFF) | (a_hihi << 16); - a.sup = sup & 0xFFFF; -} -function LongInt_sub(a, b) { - var a_lolo = a.lo & 0xFFFF; - var a_lohi = a.lo >>> 16; - var a_hilo = a.hi & 0xFFFF; - var a_hihi = a.hi >>> 16; - var b_lolo = b.lo & 0xFFFF; - var b_lohi = b.lo >>> 16; - var b_hilo = b.hi & 0xFFFF; - var b_hihi = b.hi >>> 16; - - a_lolo = (a_lolo - b_lolo) | 0; - a_lohi = (a_lohi - b_lohi + (a_lolo >> 16)) | 0; - a_hilo = (a_hilo - b_hilo + (a_lohi >> 16)) | 0; - a_hihi = (a_hihi - b_hihi + (a_hilo >> 16)) | 0; - var sup = (a.sup - b.sup + (a_hihi >> 16)) | 0; - a.lo = (a_lolo & 0xFFFF) | (a_lohi << 16); - a.hi = (a_hilo & 0xFFFF) | (a_hihi << 16); - a.sup = sup; -} -function LongInt_add(a, b) { - var a_lolo = a.lo & 0xFFFF; - var a_lohi = a.lo >>> 16; - var a_hilo = a.hi & 0xFFFF; - var a_hihi = a.hi >>> 16; - var b_lolo = b.lo & 0xFFFF; - var b_lohi = b.lo >>> 16; - var b_hilo = b.hi & 0xFFFF; - var b_hihi = b.hi >>> 16; - - a_lolo = (a_lolo + b_lolo) | 0; - a_lohi = (a_lohi + b_lohi + (a_lolo >> 16)) | 0; - a_hilo = (a_hilo + b_hilo + (a_lohi >> 16)) | 0; - a_hihi = (a_hihi + b_hihi + (a_hilo >> 16)) | 0; - var sup = (a.sup + b.sup + (a_hihi >> 16)) | 0; - a.lo = (a_lolo & 0xFFFF) | (a_lohi << 16); - a.hi = (a_hilo & 0xFFFF) | (a_hihi << 16); - a.sup = sup; -} -function LongInt_inc(a) { - a.lo = (a.lo + 1) | 0; - if (a.lo === 0) { - a.hi = (a.hi + 1) | 0; - if (a.hi === 0) { - a.sup = (a.sup + 1) & 0xFFFF; + Long_gt = function(a, b) { + if (a.hi < b.hi) { + return false; } - } -} -function LongInt_dec(a) { - a.lo = (a.lo - 1) | 0; - if (a.lo === -1) { - a.hi = (a.hi - 1) | 0; - if (a.hi === -1) { - a.sup = (a.sup - 1) & 0xFFFF; + if (a.hi > b.hi) { + return true; } - } -} -function LongInt_ucompare(a, b) { - var r = (a.sup - b.sup); - if (r !== 0) { - return r; - } - r = (a.hi >>> 1) - (b.hi >>> 1); - if (r !== 0) { - return r; - } - r = (a.hi & 1) - (b.hi & 1); - if (r !== 0) { - return r; - } - r = (a.lo >>> 1) - (b.lo >>> 1); - if (r !== 0) { - return r; - } - return (a.lo & 1) - (b.lo & 1); -} -function LongInt_numOfLeadingZeroBits(a) { - var n = 0; - var d = 16; - while (d > 0) { - if ((a >>> d) !== 0) { - a >>>= d; - n = (n + d) | 0; + var x = a.lo >>> 1; + var y = b.lo >>> 1; + if (x !== y) { + return x > y; } - d = (d / 2) | 0; + return (a.lo & 1) > (b.lo & 1); } - return 31 - n; -} -function LongInt_shl(a, b) { - if (b === 0) { - return; + + Long_ge = function(a, b) { + if (a.hi < b.hi) { + return false; + } + if (a.hi > b.hi) { + return true; + } + var x = a.lo >>> 1; + var y = b.lo >>> 1; + if (x !== y) { + return x >= y; + } + return (a.lo & 1) >= (b.lo & 1); } - 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; - } else if (b === 32) { - a.sup = a.hi & 0xFFFF; - a.hi = a.lo; - a.lo = 0; - } else if (b < 64) { - a.sup = ((a.lo >>> (64 - b)) | (a.hi << (b - 32))) & 0xFFFF; - a.hi = a.lo << b; - a.lo = 0; - } else if (b === 64) { - a.sup = a.lo & 0xFFFF; - a.hi = 0; - a.lo = 0; - } else { - a.sup = (a.lo << (b - 64)) & 0xFFFF; - a.hi = 0; - a.lo = 0; + + Long_lt = function(a, b) { + if (a.hi > b.hi) { + return false; + } + if (a.hi < b.hi) { + return true; + } + var x = a.lo >>> 1; + var y = b.lo >>> 1; + if (x !== y) { + return x < y; + } + return (a.lo & 1) < (b.lo & 1); } -} -function LongInt_shr(a, b) { - if (b === 0) { - return; + + Long_le = function(a, b) { + if (a.hi > b.hi) { + return false; + } + if (a.hi < b.hi) { + return true; + } + var x = a.lo >>> 1; + var y = b.lo >>> 1; + if (x !== y) { + return x <= y; + } + return (a.lo & 1) <= (b.lo & 1); } - if (b === 32) { - a.lo = a.hi; - a.hi = a.sup; - a.sup = 0; - } else if (b < 32) { - a.lo = (a.lo >>> b) | (a.hi << (32 - b)); - a.hi = (a.hi >>> b) | (a.sup << (32 - b)); - a.sup >>>= b; - } else if (b === 64) { - a.lo = a.sup; - a.hi = 0; - a.sup = 0; - } else if (b < 64) { - a.lo = (a.hi >>> (b - 32)) | (a.sup << (64 - b)); - a.hi = a.sup >>> (b - 32); - a.sup = 0; - } else { - a.lo = a.sup >>> (b - 64); - a.hi = 0; - a.sup = 0; + + Long_add = function(a, b) { + if (a.hi === (a.lo >> 31) && b.hi === (b.lo >> 31)) { + return Long_fromNumber(a.lo + b.lo); + } else if (Math.abs(a.hi) < Long_MAX_NORMAL && Math.abs(b.hi) < Long_MAX_NORMAL) { + return Long_fromNumber(Long_toNumber(a) + Long_toNumber(b)); + } + var a_lolo = a.lo & 0xFFFF; + var a_lohi = a.lo >>> 16; + var a_hilo = a.hi & 0xFFFF; + var a_hihi = a.hi >>> 16; + var b_lolo = b.lo & 0xFFFF; + var b_lohi = b.lo >>> 16; + var b_hilo = b.hi & 0xFFFF; + var b_hihi = b.hi >>> 16; + + var lolo = (a_lolo + b_lolo) | 0; + var lohi = (a_lohi + b_lohi + (lolo >> 16)) | 0; + var hilo = (a_hilo + b_hilo + (lohi >> 16)) | 0; + var hihi = (a_hihi + b_hihi + (hilo >> 16)) | 0; + return new Long((lolo & 0xFFFF) | ((lohi & 0xFFFF) << 16), (hilo & 0xFFFF) | ((hihi & 0xFFFF) << 16)); } -} -function LongInt_copy(a) { - return new LongInt(a.lo, a.hi, a.sup); -} -function LongInt_div(a, b) { - // Normalize divisor - var bits = b.hi !== 0 ? LongInt_numOfLeadingZeroBits(b.hi) : LongInt_numOfLeadingZeroBits(b.lo) + 32; - var sz = 1 + ((bits / 16) | 0); - var dividentBits = bits % 16; - LongInt_shl(b, bits); - LongInt_shl(a, dividentBits); - var q = new LongInt(0, 0, 0); - while (sz-- > 0) { - LongInt_shl(q, 16); - // Calculate approximate q - var digitA = (a.hi >>> 16) + (0x10000 * a.sup); - var digitB = b.hi >>> 16; - var digit = (digitA / digitB) | 0; - var t = LongInt_copy(b); - LongInt_mul(t, digit); - // Adjust q either down or up - if (LongInt_ucompare(t, a) >= 0) { - while (LongInt_ucompare(t, a) > 0) { - LongInt_sub(t, b); - --digit; - } + + Long_inc = function(a) { + var lo = (a.lo + 1) | 0; + var hi = a.hi; + if (lo === 0) { + hi = (hi + 1) | 0; + } + return new Long(lo, hi); + } + + Long_dec = function(a) { + var lo = (a.lo - 1) | 0; + var hi = a.hi; + if (lo === -1) { + hi = (hi - 1) | 0; + } + return new Long(lo, hi); + } + + Long_neg = function(a) { + return Long_inc(new Long(a.lo ^ 0xFFFFFFFF, a.hi ^ 0xFFFFFFFF)); + } + + Long_sub = function(a, b) { + if (a.hi === (a.lo >> 31) && b.hi === (b.lo >> 31)) { + return Long_fromNumber(a.lo - b.lo); + } + var a_lolo = a.lo & 0xFFFF; + var a_lohi = a.lo >>> 16; + var a_hilo = a.hi & 0xFFFF; + var a_hihi = a.hi >>> 16; + var b_lolo = b.lo & 0xFFFF; + var b_lohi = b.lo >>> 16; + var b_hilo = b.hi & 0xFFFF; + var b_hihi = b.hi >>> 16; + + var lolo = (a_lolo - b_lolo) | 0; + var lohi = (a_lohi - b_lohi + (lolo >> 16)) | 0; + var hilo = (a_hilo - b_hilo + (lohi >> 16)) | 0; + var hihi = (a_hihi - b_hihi + (hilo >> 16)) | 0; + return new Long((lolo & 0xFFFF) | ((lohi & 0xFFFF) << 16), (hilo & 0xFFFF) | ((hihi & 0xFFFF) << 16)); + } + + Long_compare = function(a, b) { + var r = a.hi - b.hi; + if (r !== 0) { + return r; + } + r = (a.lo >>> 1) - (b.lo >>> 1); + if (r !== 0) { + return r; + } + return (a.lo & 1) - (b.lo & 1); + } + + Long_mul = function(a, b) { + var positive = Long_isNegative(a) === Long_isNegative(b); + if (Long_isNegative(a)) { + a = Long_neg(a); + } + if (Long_isNegative(b)) { + b = Long_neg(b); + } + var a_lolo = a.lo & 0xFFFF; + var a_lohi = a.lo >>> 16; + var a_hilo = a.hi & 0xFFFF; + var a_hihi = a.hi >>> 16; + var b_lolo = b.lo & 0xFFFF; + var b_lohi = b.lo >>> 16; + var b_hilo = b.hi & 0xFFFF; + var b_hihi = b.hi >>> 16; + + var lolo = 0; + var lohi = 0; + var hilo = 0; + var hihi = 0; + lolo = (a_lolo * b_lolo) | 0; + lohi = lolo >>> 16; + lohi = ((lohi & 0xFFFF) + a_lohi * b_lolo) | 0; + hilo = (hilo + (lohi >>> 16)) | 0; + lohi = ((lohi & 0xFFFF) + a_lolo * b_lohi) | 0; + hilo = (hilo + (lohi >>> 16)) | 0; + hihi = hilo >>> 16; + hilo = ((hilo & 0xFFFF) + a_hilo * b_lolo) | 0; + hihi = (hihi + (hilo >>> 16)) | 0; + hilo = ((hilo & 0xFFFF) + a_lohi * b_lohi) | 0; + hihi = (hihi + (hilo >>> 16)) | 0; + hilo = ((hilo & 0xFFFF) + a_lolo * b_hilo) | 0; + hihi = (hihi + (hilo >>> 16)) | 0; + hihi = (hihi + a_hihi * b_lolo + a_hilo * b_lohi + a_lohi * b_hilo + a_lolo * b_hihi) | 0; + var result = new Long((lolo & 0xFFFF) | (lohi << 16), (hilo & 0xFFFF) | (hihi << 16)); + return positive ? result : Long_neg(result); + } + + Long_div = function(a, b) { + if (Math.abs(a.hi) < Long_MAX_NORMAL && Math.abs(b.hi) < Long_MAX_NORMAL) { + return Long_fromNumber(Long_toNumber(a) / Long_toNumber(b)); + } + return Long_divRem(a, b)[0]; + } + + Long_udiv = function(a, b) { + if (a.hi >= 0 && a.hi < Long_MAX_NORMAL && b.hi >= 0 && b.hi < Long_MAX_NORMAL) { + return Long_fromNumber(Long_toNumber(a) / Long_toNumber(b)); + } + return Long_udivRem(a, b)[0]; + } + + Long_rem = function(a, b) { + if (Math.abs(a.hi) < Long_MAX_NORMAL && Math.abs(b.hi) < Long_MAX_NORMAL) { + return Long_fromNumber(Long_toNumber(a) % Long_toNumber(b)); + } + return Long_divRem(a, b)[1]; + } + + Long_urem = function(a, b) { + if (a.hi >= 0 && a.hi < Long_MAX_NORMAL && b.hi >= 0 && b.hi < Long_MAX_NORMAL) { + return Long_fromNumber(Long_toNumber(a) / Long_toNumber(b)); + } + return Long_udivRem(a, b)[1]; + } + + function Long_divRem(a, b) { + if (b.lo === 0 && b.hi === 0) { + throw new Error("Division by zero"); + } + var positive = Long_isNegative(a) === Long_isNegative(b); + if (Long_isNegative(a)) { + a = Long_neg(a); + } + if (Long_isNegative(b)) { + b = Long_neg(b); + } + a = new LongInt(a.lo, a.hi, 0); + b = new LongInt(b.lo, b.hi, 0); + var q = LongInt_div(a, b); + a = new Long(a.lo, a.hi); + q = new Long(q.lo, q.hi); + return positive ? [q, a] : [Long_neg(q), Long_neg(a)]; + } + + function Long_udivRem(a, b) { + if (b.lo === 0 && b.hi === 0) { + throw new Error("Division by zero"); + } + a = new LongInt(a.lo, a.hi, 0); + b = new LongInt(b.lo, b.hi, 0); + var q = LongInt_div(a, b); + a = new Long(a.lo, a.hi); + q = new Long(q.lo, q.hi); + return [q, a]; + } + + function Long_shiftLeft16(a) { + return new Long(a.lo << 16, (a.lo >>> 16) | (a.hi << 16)); + } + + function Long_shiftRight16(a) { + return new Long((a.lo >>> 16) | (a.hi << 16), a.hi >>> 16); + } + + Long_and = function(a, b) { + return new Long(a.lo & b.lo, a.hi & b.hi); + } + + Long_or = function(a, b) { + return new Long(a.lo | b.lo, a.hi | b.hi); + } + + Long_xor = function(a, b) { + return new Long(a.lo ^ b.lo, a.hi ^ b.hi); + } + + Long_shl = function(a, b) { + b &= 63; + if (b === 0) { + return a; + } else if (b < 32) { + return new Long(a.lo << b, (a.lo >>> (32 - b)) | (a.hi << b)); + } else if (b === 32) { + return new Long(0, a.lo); } else { - while (true) { - var nextT = LongInt_copy(t); - LongInt_add(nextT, b); - if (LongInt_ucompare(nextT, a) > 0) { - break; - } - t = nextT; - ++digit; + return new Long(0, a.lo << (b - 32)); + } + } + + Long_shr = function(a, b) { + b &= 63; + if (b === 0) { + return a; + } else if (b < 32) { + return new Long((a.lo >>> b) | (a.hi << (32 - b)), a.hi >> b); + } else if (b === 32) { + return new Long(a.hi, a.hi >> 31); + } else { + return new Long((a.hi >> (b - 32)), a.hi >> 31); + } + } + + Long_shru = function(a, b) { + b &= 63; + if (b === 0) { + return a; + } else if (b < 32) { + return new Long((a.lo >>> b) | (a.hi << (32 - b)), a.hi >>> b); + } else if (b === 32) { + return new Long(a.hi, 0); + } else { + return new Long((a.hi >>> (b - 32)), 0); + } + } + + Long_not = function(a) { + return new Long(~a.hi, ~a.lo); + } + + // Represents a mutable 80-bit unsigned integer + function LongInt(lo, hi, sup) { + this.lo = lo; + this.hi = hi; + this.sup = sup; + } + + function LongInt_mul(a, b) { + var a_lolo = ((a.lo & 0xFFFF) * b) | 0; + var a_lohi = ((a.lo >>> 16) * b) | 0; + var a_hilo = ((a.hi & 0xFFFF) * b) | 0; + var a_hihi = ((a.hi >>> 16) * b) | 0; + var sup = (a.sup * b) | 0; + + a_lohi = (a_lohi + (a_lolo >>> 16)) | 0; + a_hilo = (a_hilo + (a_lohi >>> 16)) | 0; + a_hihi = (a_hihi + (a_hilo >>> 16)) | 0; + sup = (sup + (a_hihi >>> 16)) | 0; + a.lo = (a_lolo & 0xFFFF) | (a_lohi << 16); + a.hi = (a_hilo & 0xFFFF) | (a_hihi << 16); + a.sup = sup & 0xFFFF; + } + + function LongInt_sub(a, b) { + var a_lolo = a.lo & 0xFFFF; + var a_lohi = a.lo >>> 16; + var a_hilo = a.hi & 0xFFFF; + var a_hihi = a.hi >>> 16; + var b_lolo = b.lo & 0xFFFF; + var b_lohi = b.lo >>> 16; + var b_hilo = b.hi & 0xFFFF; + var b_hihi = b.hi >>> 16; + + a_lolo = (a_lolo - b_lolo) | 0; + a_lohi = (a_lohi - b_lohi + (a_lolo >> 16)) | 0; + a_hilo = (a_hilo - b_hilo + (a_lohi >> 16)) | 0; + a_hihi = (a_hihi - b_hihi + (a_hilo >> 16)) | 0; + var sup = (a.sup - b.sup + (a_hihi >> 16)) | 0; + a.lo = (a_lolo & 0xFFFF) | (a_lohi << 16); + a.hi = (a_hilo & 0xFFFF) | (a_hihi << 16); + a.sup = sup; + } + + function LongInt_add(a, b) { + var a_lolo = a.lo & 0xFFFF; + var a_lohi = a.lo >>> 16; + var a_hilo = a.hi & 0xFFFF; + var a_hihi = a.hi >>> 16; + var b_lolo = b.lo & 0xFFFF; + var b_lohi = b.lo >>> 16; + var b_hilo = b.hi & 0xFFFF; + var b_hihi = b.hi >>> 16; + + a_lolo = (a_lolo + b_lolo) | 0; + a_lohi = (a_lohi + b_lohi + (a_lolo >> 16)) | 0; + a_hilo = (a_hilo + b_hilo + (a_lohi >> 16)) | 0; + a_hihi = (a_hihi + b_hihi + (a_hilo >> 16)) | 0; + var sup = (a.sup + b.sup + (a_hihi >> 16)) | 0; + a.lo = (a_lolo & 0xFFFF) | (a_lohi << 16); + a.hi = (a_hilo & 0xFFFF) | (a_hihi << 16); + a.sup = sup; + } + + function LongInt_inc(a) { + a.lo = (a.lo + 1) | 0; + if (a.lo === 0) { + a.hi = (a.hi + 1) | 0; + if (a.hi === 0) { + a.sup = (a.sup + 1) & 0xFFFF; } } - LongInt_sub(a, t); - q.lo |= digit; - LongInt_shl(a, 16); } - LongInt_shr(a, bits + 16); - return q; + + function LongInt_dec(a) { + a.lo = (a.lo - 1) | 0; + if (a.lo === -1) { + a.hi = (a.hi - 1) | 0; + if (a.hi === -1) { + a.sup = (a.sup - 1) & 0xFFFF; + } + } + } + + function LongInt_ucompare(a, b) { + var r = (a.sup - b.sup); + if (r !== 0) { + return r; + } + r = (a.hi >>> 1) - (b.hi >>> 1); + if (r !== 0) { + return r; + } + r = (a.hi & 1) - (b.hi & 1); + if (r !== 0) { + return r; + } + r = (a.lo >>> 1) - (b.lo >>> 1); + if (r !== 0) { + return r; + } + return (a.lo & 1) - (b.lo & 1); + } + + function LongInt_numOfLeadingZeroBits(a) { + var n = 0; + var d = 16; + while (d > 0) { + if ((a >>> d) !== 0) { + a >>>= d; + n = (n + d) | 0; + } + d = (d / 2) | 0; + } + return 31 - n; + } + + function LongInt_shl(a, b) { + if (b === 0) { + return; + } + 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; + } else if (b === 32) { + a.sup = a.hi & 0xFFFF; + a.hi = a.lo; + a.lo = 0; + } else if (b < 64) { + a.sup = ((a.lo >>> (64 - b)) | (a.hi << (b - 32))) & 0xFFFF; + a.hi = a.lo << b; + a.lo = 0; + } else if (b === 64) { + a.sup = a.lo & 0xFFFF; + a.hi = 0; + a.lo = 0; + } else { + a.sup = (a.lo << (b - 64)) & 0xFFFF; + a.hi = 0; + a.lo = 0; + } + } + + function LongInt_shr(a, b) { + if (b === 0) { + return; + } + if (b === 32) { + a.lo = a.hi; + a.hi = a.sup; + a.sup = 0; + } else if (b < 32) { + a.lo = (a.lo >>> b) | (a.hi << (32 - b)); + a.hi = (a.hi >>> b) | (a.sup << (32 - b)); + a.sup >>>= b; + } else if (b === 64) { + a.lo = a.sup; + a.hi = 0; + a.sup = 0; + } else if (b < 64) { + a.lo = (a.hi >>> (b - 32)) | (a.sup << (64 - b)); + a.hi = a.sup >>> (b - 32); + a.sup = 0; + } else { + a.lo = a.sup >>> (b - 64); + a.hi = 0; + a.sup = 0; + } + } + + function LongInt_copy(a) { + return new LongInt(a.lo, a.hi, a.sup); + } + + function LongInt_div(a, b) { + // Normalize divisor + var bits = b.hi !== 0 ? LongInt_numOfLeadingZeroBits(b.hi) : LongInt_numOfLeadingZeroBits(b.lo) + 32; + var sz = 1 + ((bits / 16) | 0); + var dividentBits = bits % 16; + LongInt_shl(b, bits); + LongInt_shl(a, dividentBits); + var q = new LongInt(0, 0, 0); + while (sz-- > 0) { + LongInt_shl(q, 16); + // Calculate approximate q + var digitA = (a.hi >>> 16) + (0x10000 * a.sup); + var digitB = b.hi >>> 16; + var digit = (digitA / digitB) | 0; + var t = LongInt_copy(b); + LongInt_mul(t, digit); + // Adjust q either down or up + if (LongInt_ucompare(t, a) >= 0) { + while (LongInt_ucompare(t, a) > 0) { + LongInt_sub(t, b); + --digit; + } + } else { + while (true) { + var nextT = LongInt_copy(t); + LongInt_add(nextT, b); + if (LongInt_ucompare(nextT, a) > 0) { + break; + } + t = nextT; + ++digit; + } + } + LongInt_sub(a, t); + q.lo |= digit; + LongInt_shl(a, 16); + } + LongInt_shr(a, bits + 16); + return q; + } +} else { + Long_eq = function(a, b) { + return a === b; + } + + Long_ne = function(a, b) { + return a !== b; + } + + Long_gt = function(a, b) { + return a > b; + } + + Long_ge = function(a, b) { + return a >= b; + } + + Long_lt = function(a, b) { + return a < b; + } + + Long_le = function(a, b) { + return a <= b; + } + + Long_add = function(a, b) { + return BigInt.asIntN(64, a + b); + } + + Long_inc = function(a) { + return BigInt.asIntN(64, a + 1); + } + + Long_dec = function(a) { + return BigInt.asIntN(64, a - 1); + } + + Long_neg = function(a) { + return BigInt.asIntN(64, -a); + } + + Long_sub = function(a, b) { + return BigInt.asIntN(64, a - b); + } + + Long_compare = function(a, b) { + return a < b ? -1 : a > b ? 1 : 0; + } + + Long_mul = function(a, b) { + return BigInt.asIntN(64, a * b); + } + + Long_div = function(a, b) { + return BigInt.asIntN(64, a / b); + } + + Long_udiv = function(a, b) { + return BigInt.asIntN(64, BigInt.asUintN(64, a) / BigInt.asUintN(64, b)); + } + + Long_rem = function(a, b) { + return BigInt.asIntN(64, a % b); + } + + Long_urem = function(a, b) { + return BigInt.asIntN(64, BigInt.asUintN(64, a) % BigInt.asUintN(64, b)); + } + + Long_and = function(a, b) { + return BigInt.asIntN(64, a & b); + } + + Long_or = function(a, b) { + return BigInt.asIntN(64, a | b); + } + + Long_xor = function(a, b) { + return BigInt.asIntN(64, a ^ b); + } + + Long_shl = function(a, b) { + return BigInt.asIntN(64, a << BigInt(b & 63)); + } + + Long_shr = function(a, b) { + return BigInt.asIntN(64, a >> BigInt(b & 63)); + } + + Long_shru = function(a, b) { + return BigInt.asIntN(64, BigInt.asUintN(64, a) >> BigInt(b & 63)); + } + + Long_not = function(a) { + return BigInt.asIntN(64, ~a); + } } diff --git a/core/src/main/resources/org/teavm/backend/javascript/runtime.js b/core/src/main/resources/org/teavm/backend/javascript/runtime.js index aa5514158..eab322673 100644 --- a/core/src/main/resources/org/teavm/backend/javascript/runtime.js +++ b/core/src/main/resources/org/teavm/backend/javascript/runtime.js @@ -74,18 +74,31 @@ function $rt_wrapArray(cls, data) { function $rt_createUnfilledArray(cls, sz) { return new $rt_array(cls, new Array(sz)); } -function $rt_createLongArray(sz) { - var data = new Array(sz); - var arr = new $rt_array($rt_longcls(), data); - data.fill(Long_ZERO); - return arr; -} -function $rt_createLongArrayFromData(init) { - return new $rt_array($rt_longcls(), init); -} function $rt_createNumericArray(cls, nativeArray) { return new $rt_array(cls, nativeArray); } +var $rt_createLongArray; +var $rt_createLongArrayFromData; +if (typeof BigInt !== 'function') { + $rt_createLongArray = function(sz) { + var data = new Array(sz); + var arr = new $rt_array($rt_longcls(), data); + data.fill(Long_ZERO); + return arr; + } + $rt_createLongArrayFromData = function(init) { + return new $rt_array($rt_longcls(), init); + } +} else { + $rt_createLongArray = function (sz) { + return $rt_createNumericArray($rt_longcls(), new BigInt64Array(sz)); + } + $rt_createLongArrayFromData = function(data) { + var buffer = new BigInt64Array(data.length); + buffer.set(data); + return $rt_createNumericArray($rt_longcls(), buffer); + } +} function $rt_createCharArray(sz) { return $rt_createNumericArray($rt_charcls(), new Uint16Array(sz)); } @@ -630,15 +643,29 @@ function $rt_eraseClinit(target) { var $rt_numberConversionView = new DataView(new ArrayBuffer(8)); -function $rt_doubleToLongBits(n) { - $rt_numberConversionView.setFloat64(0, n, true); - return new Long($rt_numberConversionView.getInt32(0, true), $rt_numberConversionView.getInt32(4, true)); -} -function $rt_longBitsToDouble(n) { - $rt_numberConversionView.setInt32(0, n.lo, true); - $rt_numberConversionView.setInt32(4, n.hi, true); - return $rt_numberConversionView.getFloat64(0, true); +var $rt_doubleToLongBits; +var $rt_longBitsToDouble; +if (typeof BigInt !== 'function') { + $rt_doubleToLongBits = function(n) { + $rt_numberConversionView.setFloat64(0, n, true); + return new Long($rt_numberConversionView.getInt32(0, true), $rt_numberConversionView.getInt32(4, true)); + } + $rt_longBitsToDouble = function(n) { + $rt_numberConversionView.setInt32(0, n.lo, true); + $rt_numberConversionView.setInt32(4, n.hi, true); + return $rt_numberConversionView.getFloat64(0, true); + } +} else { + $rt_doubleToLongBits = function(n) { + $rt_numberConversionView.setFloat64(0, n, true); + return $rt_numberConversionView.getBigInt64(0, true); + } + $rt_longBitsToDouble = function(n) { + $rt_numberConversionView.setBigInt64(0, n, true); + return $rt_numberConversionView.getFloat64(0, true); + } } + function $rt_floatToIntBits(n) { $rt_numberConversionView.setFloat32(0, n); return $rt_numberConversionView.getInt32(0); @@ -697,46 +724,94 @@ function $dbg_class(obj) { } return clsName; } -function Long(lo, hi) { - this.lo = lo | 0; - this.hi = hi | 0; -} -Long.prototype.__teavm_class__ = function() { - return "long"; -}; -Long.prototype.toString = function() { - var result = []; - var n = this; - var positive = Long_isPositive(n); - if (!positive) { - n = Long_neg(n); - } - var radix = new Long(10, 0); - do { - var divRem = Long_divRem(n, radix); - result.push(String.fromCharCode(48 + divRem[1].lo)); - n = divRem[0]; - } while (n.lo !== 0 || n.hi !== 0); - result = result.reverse().join(''); - return positive ? result : "-" + result; -}; -Long.prototype.valueOf = function() { - return Long_toNumber(this); -}; -var Long_ZERO = new Long(0, 0); var Long_MAX_NORMAL = 1 << 18; -function Long_fromInt(val) { - return new Long(val, (-(val < 0)) | 0); -} -function Long_fromNumber(val) { - if (val >= 0) { - return new Long(val | 0, (val / 0x100000000) | 0); - } else { - return Long_neg(new Long(-val | 0, (-val / 0x100000000) | 0)); +var Long_ZERO; +var Long_create; +var Long_fromInt; +var Long_fromNumber; +var Long_toNumber; +var Long_hi; +var Long_lo; +if (typeof BigInt !== "function") { + function Long(lo, hi) { + this.lo = lo | 0; + this.hi = hi | 0; + } + Long.prototype.__teavm_class__ = function() { + return "long"; + }; + + function Long_isPositive(a) { + return (a.hi & 0x80000000) === 0; + } + + function Long_isNegative(a) { + return (a.hi & 0x80000000) !== 0; + } + + Long.prototype.toString = function() { + var result = []; + var n = this; + var positive = Long_isPositive(n); + if (!positive) { + n = Long_neg(n); + } + var radix = new Long(10, 0); + do { + var divRem = Long_divRem(n, radix); + result.push(String.fromCharCode(48 + divRem[1].lo)); + n = divRem[0]; + } while (n.lo !== 0 || n.hi !== 0); + result = result.reverse().join(''); + return positive ? result : "-" + result; + }; + Long.prototype.valueOf = function() { + return Long_toNumber(this); + }; + + Long_ZERO = new Long(0, 0); + Long_fromInt = function(val) { + return new Long(val, (-(val < 0)) | 0); + } + Long_fromNumber = function(val) { + if (val >= 0) { + return new Long(val | 0, (val / 0x100000000) | 0); + } else { + return Long_neg(new Long(-val | 0, (-val / 0x100000000) | 0)); + } + } + Long_create = function(lo, hi) { + return new Long(hi, lo); + } + Long_toNumber = function(val) { + return 0x100000000 * val.hi + (val.lo >>> 0); + } + Long_hi = function(val) { + return val.hi; + } + Long_lo = function(val) { + return val.lo; + } +} else { + Long_ZERO = BigInt(0); + Long_create = function(lo, hi) { + return BigInt.asIntN(64, BigInt(lo) | (BigInt(hi) << BigInt(32))); + } + Long_fromInt = function(val) { + return BigInt(val); + } + Long_fromNumber = function(val) { + return BigInt(val >= 0 ? Math.floor(val) : Math.ceil(val)); + } + Long_toNumber = function(val) { + return Number(val); + } + Long_hi = function(val) { + return Number(BigInt.asIntN(64, val >> BigInt(32))) | 0; + } + Long_lo = function(val) { + return Number(BigInt.asIntN(32, val)) | 0; } -} -function Long_toNumber(val) { - return 0x100000000 * val.hi + (val.lo >>> 0); } var $rt_imul = Math.imul || function(a, b) { var ah = (a >>> 16) & 0xFFFF;