rt/emul/mini/src/main/resources/org/apidesign/vm4brwsr/emul/lang/java_lang_Number.js
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Wed, 27 Jan 2016 21:24:22 +0100
changeset 1871 bcbc4c03d35d
parent 1870 790cc8784820
child 1872 df5db062f180
permissions -rw-r--r--
Direct access to compare64 as well
     1 // empty line needed here
     2 
     3 (function(numberPrototype) {
     4     function add32(x, y) {
     5         return (x + y) | 0;
     6     };
     7     function mul32(x, y) {
     8         return (((x * (y >> 16)) << 16) + x * (y & 0xFFFF)) | 0;
     9     };
    10     var __m32 = 0xFFFFFFFF;
    11 
    12     numberPrototype.next32 = function(low) {
    13         if (this === 0) {
    14             return low;
    15         }
    16         var l = new Number(low);
    17         l.hi = this | 0;
    18         return l;
    19     };
    20 
    21     numberPrototype.high32 = function() {
    22         return this.hi ? this.hi : (Math.floor(this / (__m32 + 1))) | 0;
    23     };
    24     numberPrototype.toFP = function() {
    25         return this.hi ? this.hi * (__m32 + 1) + this : this;
    26     };
    27     numberPrototype.toLong = function() {
    28         var hi = (this / (__m32 + 1)) | 0;
    29         var low = (this % (__m32 + 1)) | 0;
    30         if (low < 0) {
    31             low += __m32 + 1;
    32         }
    33 
    34         if (this < 0) {
    35             hi -= 1;
    36         }
    37 
    38         return hi.next32(low);
    39     };
    40 
    41     numberPrototype.toExactString = function() {
    42         if (this.hi) {
    43             // check for Long.MIN_VALUE
    44             if ((this.hi == (0x80000000 | 0)) && (this == 0)) {
    45                 return '-9223372036854775808';
    46             }
    47             var res = 0;
    48             var a = [6, 9, 2, 7, 6, 9, 4, 9, 2, 4];
    49             var s = '';
    50             var digit;
    51             var neg = this.hi < 0;
    52             if (neg) {
    53                 var x = neg64(this);
    54                 var hi = x.hi;
    55                 var low = x;
    56             } else {
    57                 var hi = this.hi;
    58                 var low = this;
    59             }
    60             for (var i = 0; i < a.length; i++) {
    61                 res += hi * a[i];
    62                 var low_digit = low % 10;
    63                 digit = (res % 10) + low_digit;
    64 
    65                 low = Math.floor(low / 10);
    66                 res = Math.floor(res / 10);
    67 
    68                 if (digit >= 10) {
    69                     digit -= 10;
    70                     res++;
    71                 }
    72                 s = String(digit).concat(s);
    73             }
    74             s = String(res).concat(s).replace(/^0+/, '');
    75             return (neg ? '-' : '').concat(s);
    76         }
    77         return String(this);
    78     };
    79 
    80     function add64(x, y) {
    81         var low = x + y;
    82         carry = 0;
    83         if (low > __m32) {
    84             carry = 1;
    85             low -= (__m32 + 1);
    86         }
    87         var hi = (x.high32() + y.high32() + carry) | 0;
    88         return hi.next32(low);
    89     };
    90 
    91     function sub64(x, y) {
    92         var low = x - y;
    93         carry = 0;
    94         if (low < 0) {
    95             carry = 1;
    96             low += (__m32 + 1);
    97         }
    98         var hi = (x.high32() - y.high32() - carry) | 0;
    99         return hi.next32(low);
   100     };
   101 
   102     function mul64(x, y) {
   103         var low = mul32(x, y);
   104         low += (low < 0) ? (__m32 + 1) : 0;
   105         // first count upper 32 bits of (x.low * x.low)
   106         var hi_hi = 0;
   107         var hi_low = 0;
   108         var m = 1;
   109         for (var i = 0; i < 32; i++) {
   110             if (y & m) {
   111                 hi_hi += x >>> 16;
   112                 hi_low += x & 0xFFFF
   113             }
   114             hi_low >>= 1;
   115             hi_low += (hi_hi & 1) ? 0x8000 : 0;
   116             hi_hi >>= 1;
   117             m <<= 1;
   118         }
   119         var hi = (hi_hi << 16) + hi_low;
   120 
   121         var m1 = mul32(x.high32(), y);
   122         var m2 = mul32(x, y.high32());
   123         hi = add32(add32(hi, m1), m2);
   124 
   125         return hi.next32(low);
   126     };
   127 
   128     function and64(x, y) {
   129         var low = x & y;
   130         low += (low < 0) ? (__m32 + 1) : 0;
   131         if (x.hi && y.hi) {
   132             var hi = x.hi & y.hi;
   133             return hi.next32(low);
   134         }
   135         ;
   136         return low;
   137     };
   138 
   139     function or64(x, y) {
   140         var low = x | y;
   141         low += (low < 0) ? (__m32 + 1) : 0;
   142         if (x.hi || y.hi) {
   143             var hi = x.hi | y.hi;
   144             return hi.next32(low);
   145         }
   146         return low;
   147     };
   148 
   149     function xor64(x, y) {
   150         var low = x ^ y;
   151         low += (low < 0) ? (__m32 + 1) : 0;
   152         if (x.hi || y.hi) {
   153             var hi = x.hi ^ y.hi;
   154             return hi.next32(low);
   155         }
   156         ;
   157         return low;
   158     };
   159 
   160     function shl64(thiz, x) {
   161         x &= 0x3f;
   162         if (x == 0) return thiz;
   163         if (x >= 32) {
   164             var hi = thiz << (x - 32);
   165             return hi.next32(0);
   166         } else {
   167             var hi = thiz.high32() << x;
   168             var low_reminder = thiz >> (32 - x);
   169             hi |= low_reminder;
   170             var low = thiz << x;
   171             low += (low < 0) ? (__m32 + 1) : 0;
   172             return hi.next32(low);
   173         }
   174     };
   175 
   176     function shr64(thiz, x) {
   177         x &= 0x3f;
   178         if (x == 0) return thiz;
   179         if (x >= 32) {
   180             var low = thiz.high32() >> (x - 32);
   181             low += (low < 0) ? (__m32 + 1) : 0;
   182             return low;
   183         } else {
   184             var low = thiz >>> x;
   185             var hi_reminder = thiz.high32() << (32 - x);
   186             low |= hi_reminder;
   187             low += (low < 0) ? (__m32 + 1) : 0;
   188             var hi = thiz.high32() >> x;
   189             return hi.next32(low);
   190         }
   191     };
   192 
   193     function ushr64(thiz, x) {
   194         x &= 0x3f;
   195         if (x == 0) return thiz;
   196         if (x >= 32) {
   197             var low = thiz.high32() >>> (x - 32);
   198             low += (low < 0) ? (__m32 + 1) : 0;
   199             return low;
   200         } else {
   201             var low = thiz >>> x;
   202             var hi_reminder = thiz.high32() << (32 - x);
   203             low |= hi_reminder;
   204             low += (low < 0) ? (__m32 + 1) : 0;
   205             var hi = thiz.high32() >>> x;
   206             return hi.next32(low);
   207         }
   208     };
   209 
   210     function compare64(x, y) {
   211         if (x.high32() === y.high32()) {
   212             return (x < y) ? -1 : ((x > y) ? 1 : 0);
   213         }
   214         return (x.high32() < y.high32()) ? -1 : 1;
   215     };
   216 
   217     function neg64(x) {
   218         var hi = x.high32();
   219         var low = x;
   220         if ((hi === 0) && (low < 0)) {
   221             return -low;
   222         }
   223         hi = ~hi;
   224         low = ~low;
   225         low += (low < 0) ? (__m32 + 1) : 0;
   226         var ret = hi.next32(low);
   227         return add64(ret, 1);
   228     };
   229     
   230     function __handleDivByZero() {
   231         var exception = new vm.java_lang_ArithmeticException;
   232         vm.java_lang_ArithmeticException(false).constructor
   233           .cons__VLjava_lang_String_2.call(exception, "/ by zero");
   234 
   235         throw exception;
   236     }
   237 
   238     function __Int64(hi32, lo32) {
   239         this.hi32 = hi32 | 0;
   240         this.lo32 = lo32 | 0;
   241 
   242         this.get32 = function(bitIndex) {
   243             var v0;
   244             var v1;
   245             bitIndex += 32;
   246             var selector = bitIndex >>> 5;
   247             switch (selector) {
   248                 case 0:
   249                     v0 = 0;
   250                     v1 = this.lo32;
   251                     break;
   252                 case 1:
   253                     v0 = this.lo32;
   254                     v1 = this.hi32;
   255                     break;
   256                 case 2:
   257                     v0 = this.hi32;
   258                     v1 = 0;
   259                     break
   260                 default:
   261                     return 0;
   262             }
   263 
   264             var shift = bitIndex & 31;
   265             if (shift === 0) {
   266                 return v0;
   267             }
   268 
   269             return (v1 << (32 - shift)) | (v0 >>> shift);
   270         }
   271 
   272         this.get16 = function(bitIndex) {
   273             return this.get32(bitIndex) & 0xffff;
   274         }
   275 
   276         this.set16 = function(bitIndex, value) {
   277             bitIndex += 32;
   278             var shift = bitIndex & 15;
   279             var svalue = (value & 0xffff) << shift; 
   280             var smask = 0xffff << shift;
   281             var selector = bitIndex >>> 4;
   282             switch (selector) {
   283                 case 0:
   284                     break;
   285                 case 1:
   286                     this.lo32 = (this.lo32 & ~(smask >>> 16))
   287                                     | (svalue >>> 16);
   288                     break;
   289                 case 2:
   290                     this.lo32 = (this.lo32 & ~smask) | svalue;
   291                     break;
   292                 case 3:
   293                     this.lo32 = (this.lo32 & ~(smask << 16))
   294                                     | (svalue << 16);
   295                     this.hi32 = (this.hi32 & ~(smask >>> 16))
   296                                     | (svalue >>> 16);
   297                     break;
   298                 case 4:
   299                     this.hi32 = (this.hi32 & ~smask) | svalue;
   300                     break;
   301                 case 5:
   302                     this.hi32 = (this.hi32 & ~(smask << 16))
   303                                     | (svalue << 16);
   304                     break;
   305             }
   306         }
   307 
   308         this.getDigit = function(index, shift) {
   309             return this.get16((index << 4) - shift);
   310         }
   311 
   312         this.getTwoDigits = function(index, shift) {
   313             return this.get32(((index - 1) << 4) - shift);
   314         }
   315 
   316         this.setDigit = function(index, shift, value) {
   317             this.set16((index << 4) - shift, value);
   318         }
   319 
   320         this.countSignificantDigits = function() {
   321             var sd;
   322             var remaining;
   323 
   324             if (this.hi32 === 0) {
   325                 if (this.lo32 === 0) {
   326                     return 0;
   327                 }
   328 
   329                 sd = 2;
   330                 remaining = this.lo32;
   331             } else {
   332                 sd = 4;
   333                 remaining = this.hi32;
   334             }
   335 
   336             if (remaining < 0) {
   337                 return sd;
   338             }
   339 
   340             return (remaining < 65536) ? sd - 1 : sd;
   341         }
   342         
   343         this.toNumber = function() {
   344             var lo32 = this.lo32;
   345             if (lo32 < 0) {
   346                 lo32 += 0x100000000;
   347             }
   348 
   349             return this.hi32.next32(lo32);
   350         }
   351     }
   352 
   353     function __countLeadingZeroes16(number) {
   354         var nlz = 0;
   355 
   356         if (number < 256) {
   357             nlz += 8;
   358             number <<= 8;
   359         }
   360 
   361         if (number < 4096) {
   362             nlz += 4;
   363             number <<= 4;
   364         }
   365 
   366         if (number < 16384) {
   367             nlz += 2;
   368             number <<= 2;
   369         }
   370 
   371         return (number < 32768) ? nlz + 1 : nlz;
   372     }
   373     
   374     // q = u / v; r = u - q * v;
   375     // v != 0
   376     function __div64(q, r, u, v) {
   377         var m = u.countSignificantDigits();
   378         var n = v.countSignificantDigits();
   379 
   380         q.hi32 = q.lo32 = 0;
   381 
   382         if (n === 1) {
   383             // v has single digit
   384             var vd = v.getDigit(0, 0);
   385             var carry = 0;
   386             for (var i = m - 1; i >= 0; --i) {
   387                 var ui = (carry << 16) | u.getDigit(i, 0);
   388                 if (ui < 0) {
   389                     ui += 0x100000000;
   390                 }
   391                 var qi = (ui / vd) | 0;
   392                 q.setDigit(i, 0, qi);
   393                 carry = ui - qi * vd;
   394             }
   395 
   396             r.hi32 = 0;
   397             r.lo32 = carry;
   398             return;
   399         }
   400 
   401         r.hi32 = u.hi32;  
   402         r.lo32 = u.lo32;
   403 
   404         if (m < n) {
   405             return;
   406         }
   407 
   408         // Normalize
   409         var nrm = __countLeadingZeroes16(v.getDigit(n - 1, 0));
   410 
   411         var vd1 = v.getDigit(n - 1, nrm);                
   412         var vd0 = v.getDigit(n - 2, nrm);
   413         for (var j = m - n; j >= 0; --j) {
   414             // Calculate qj estimate
   415             var ud21 = r.getTwoDigits(j + n, nrm);
   416             var ud2 = ud21 >>> 16;
   417             if (ud21 < 0) {
   418                 ud21 += 0x100000000;
   419             }
   420 
   421             var qest = (ud2 === vd1) ? 0xFFFF : ((ud21 / vd1) | 0);
   422             var rest = ud21 - qest * vd1;
   423 
   424             // 0 <= (qest - qj) <= 2
   425 
   426             // Refine qj estimate
   427             var ud0 = r.getDigit(j + n - 2, nrm);
   428             while ((qest * vd0) > ((rest * 0x10000) + ud0)) {
   429                 --qest;
   430                 rest += vd1;
   431             }
   432 
   433             // 0 <= (qest - qj) <= 1
   434             
   435             // Multiply and subtract
   436             var carry = 0;
   437             for (var i = 0; i < n; ++i) {
   438                 var vi = qest * v.getDigit(i, nrm);
   439                 var ui = r.getDigit(i + j, nrm) - carry - (vi & 0xffff);
   440                 r.setDigit(i + j, nrm, ui);
   441                 carry = (vi >>> 16) - (ui >> 16);
   442             }
   443             var uj = ud2 - carry;
   444 
   445             if (uj < 0) {
   446                 // qest - qj = 1
   447 
   448                 // Add back
   449                 --qest;
   450                 var carry = 0;
   451                 for (var i = 0; i < n; ++i) {
   452                     var ui = r.getDigit(i + j, nrm) + v.getDigit(i, nrm)
   453                                  + carry;
   454                     r.setDigit(i + j, nrm, ui);
   455                     carry = ui >> 16;
   456                 }
   457                 uj += carry;
   458             }
   459 
   460             q.setDigit(j, 0, qest);
   461             r.setDigit(j + n, nrm, uj);
   462         }
   463     }
   464 
   465     function div64(x, y) {
   466         var negateResult = false;
   467         var u, v;
   468 
   469         if ((x.high32() & 0x80000000) !== 0) {
   470             u = neg64(x);
   471             negateResult = !negateResult;
   472         } else {
   473             u = x;
   474         }
   475 
   476         if ((y.high32() & 0x80000000) !== 0) {
   477             v = neg64(y);
   478             negateResult = !negateResult;
   479         } else {
   480             v = y;
   481         }
   482 
   483         if ((v === 0) && (v.high32() === 0)) {
   484             __handleDivByZero();
   485         }
   486 
   487         if (u.high32() === 0) {
   488             if (v.high32() === 0) {
   489                 var result = (u / v) | 0;
   490                 return negateResult ? neg64(result) : result;
   491             }
   492 
   493             return 0;
   494         }
   495 
   496         var u64 = new __Int64(u.high32(), u);
   497         var v64 = new __Int64(v.high32(), v);
   498         var q64 = new __Int64(0, 0);
   499         var r64 = new __Int64(0, 0);
   500 
   501         __div64(q64, r64, u64, v64);
   502 
   503         var result = q64.toNumber();
   504         return negateResult ? neg64(result) : result;
   505     }
   506 
   507     function mod64(x, y) {
   508         var negateResult = false;
   509         var u, v;
   510         
   511         if ((x.high32() & 0x80000000) !== 0) {
   512             u = neg64(x);
   513             negateResult = !negateResult;
   514         } else {
   515             u = x;
   516         }
   517 
   518         if ((y.high32() & 0x80000000) !== 0) {
   519             v = neg64(y);
   520         } else {
   521             v = y;
   522         }
   523 
   524         if ((v === 0) && (v.high32() === 0)) {
   525             __handleDivByZero();
   526         }
   527 
   528         if (u.high32() === 0) {
   529             var result = (v.high32() === 0) ? (u % v) : u;
   530             return negateResult ? neg64(result) : result;
   531         }
   532 
   533         var u64 = new __Int64(u.high32(), u);
   534         var v64 = new __Int64(v.high32(), v);
   535         var q64 = new __Int64(0, 0);
   536         var r64 = new __Int64(0, 0);
   537 
   538         __div64(q64, r64, u64, v64);
   539 
   540         var result = r64.toNumber();
   541         return negateResult ? neg64(result) : result;
   542     }
   543 
   544     var b = numberPrototype['__bit64'] = {};
   545     b.add64 = add64;
   546     b.sub64 = sub64;
   547     b.mul64 = mul64;
   548     b.div64 = div64;
   549     b.mod64 = mod64;
   550     b.and64 = and64;
   551     b.or64 = or64;
   552     b.xor64 = xor64;
   553     b.neg64 = neg64;
   554     b.shl64 = shl64;
   555     b.shr64 = shr64;
   556     b.ushr64 = ushr64;
   557     b.compare64 = compare64;
   558 })(Number.prototype);
   559 
   560 vm.java_lang_Number(false);