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