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