1+ //
2+ // Tiny module that provides big (64bit) integers.
3+ //
4+ // Copyright (c) 2016 Samuel Groß
5+ //
6+ // Requires utils.js
7+ //
8+
9+ // Datatype to represent 64-bit integers.
10+ //
11+ // Internally, the integer is stored as a Uint8Array in little endian byte order.
12+ function Int64 ( v ) {
13+ // The underlying byte array.
14+ var bytes = new Uint8Array ( 8 ) ;
15+
16+ switch ( typeof v ) {
17+ case 'number' :
18+ v = '0x' + Math . floor ( v ) . toString ( 16 ) ;
19+ case 'string' :
20+ if ( v . startsWith ( '0x' ) )
21+ v = v . substr ( 2 ) ;
22+ if ( v . length % 2 == 1 )
23+ v = '0' + v ;
24+
25+ var bigEndian = unhexlify ( v , 8 ) ;
26+ bytes . set ( Array . from ( bigEndian ) . reverse ( ) ) ;
27+ break ;
28+ case 'object' :
29+ if ( v instanceof Int64 ) {
30+ bytes . set ( v . bytes ( ) ) ;
31+ } else {
32+ if ( v . length != 8 )
33+ throw TypeError ( "Array must have excactly 8 elements." ) ;
34+ bytes . set ( v ) ;
35+ }
36+ break ;
37+ case 'undefined' :
38+ break ;
39+ default :
40+ throw TypeError ( "Int64 constructor requires an argument." ) ;
41+ }
42+
43+ // Return a double whith the same underlying bit representation.
44+ this . asDouble = function ( ) {
45+ // Check for NaN
46+ if ( bytes [ 7 ] == 0xff && ( bytes [ 6 ] == 0xff || bytes [ 6 ] == 0xfe ) )
47+ throw new RangeError ( "Integer can not be represented by a double" ) ;
48+
49+ return Struct . unpack ( Struct . float64 , bytes ) ;
50+ } ;
51+
52+ // Return a javascript value with the same underlying bit representation.
53+ // This is only possible for integers in the range [0x0001000000000000, 0xffff000000000000)
54+ // due to double conversion constraints.
55+ this . asJSValue = function ( ) {
56+ if ( ( bytes [ 7 ] == 0 && bytes [ 6 ] == 0 ) || ( bytes [ 7 ] == 0xff && bytes [ 6 ] == 0xff ) )
57+ throw new RangeError ( "Integer can not be represented by a JSValue" ) ;
58+
59+ // For NaN-boxing, JSC adds 2^48 to a double value's bit pattern.
60+ this . assignSub ( this , 0x1000000000000 ) ;
61+ var res = Struct . unpack ( Struct . float64 , bytes ) ;
62+ this . assignAdd ( this , 0x1000000000000 ) ;
63+
64+ return res ;
65+ } ;
66+
67+ // Return the underlying bytes of this number as array.
68+ this . bytes = function ( ) {
69+ return Array . from ( bytes ) ;
70+ } ;
71+
72+ // Return the byte at the given index.
73+ this . byteAt = function ( i ) {
74+ return bytes [ i ] ;
75+ } ;
76+
77+ // Return the value of this number as unsigned hex string.
78+ this . toString = function ( ) {
79+ return '0x' + hexlify ( Array . from ( bytes ) . reverse ( ) ) ;
80+ } ;
81+
82+ this . lo = function ( )
83+ {
84+ var b = this . bytes ( ) ;
85+ return ( b [ 0 ] | ( b [ 1 ] << 8 ) | ( b [ 2 ] << 16 ) | ( b [ 3 ] << 24 ) ) >>> 0 ;
86+ } ;
87+
88+ this . hi = function ( )
89+ {
90+ var b = this . bytes ( ) ;
91+ return ( b [ 4 ] | ( b [ 5 ] << 8 ) | ( b [ 6 ] << 16 ) | ( b [ 7 ] << 24 ) ) >>> 0 ;
92+ } ;
93+
94+ // Basic arithmetic.
95+ // These functions assign the result of the computation to their 'this' object.
96+
97+ // Decorator for Int64 instance operations. Takes care
98+ // of converting arguments to Int64 instances if required.
99+ function operation ( f , nargs ) {
100+ return function ( ) {
101+ if ( arguments . length != nargs )
102+ throw Error ( "Not enough arguments for function " + f . name ) ;
103+ for ( var i = 0 ; i < arguments . length ; i ++ )
104+ if ( ! ( arguments [ i ] instanceof Int64 ) )
105+ arguments [ i ] = new Int64 ( arguments [ i ] ) ;
106+ return f . apply ( this , arguments ) ;
107+ } ;
108+ }
109+
110+ // this = -n (two's complement)
111+ this . assignNeg = operation ( function neg ( n ) {
112+ for ( var i = 0 ; i < 8 ; i ++ )
113+ bytes [ i ] = ~ n . byteAt ( i ) ;
114+
115+ return this . assignAdd ( this , Int64 . One ) ;
116+ } , 1 ) ;
117+
118+ // this = a + b
119+ this . assignAdd = operation ( function add ( a , b ) {
120+ var carry = 0 ;
121+ for ( var i = 0 ; i < 8 ; i ++ ) {
122+ var cur = a . byteAt ( i ) + b . byteAt ( i ) + carry ;
123+ carry = cur > 0xff | 0 ;
124+ bytes [ i ] = cur ;
125+ }
126+ return this ;
127+ } , 2 ) ;
128+
129+ // this = a - b
130+ this . assignSub = operation ( function sub ( a , b ) {
131+ var carry = 0 ;
132+ for ( var i = 0 ; i < 8 ; i ++ ) {
133+ var cur = a . byteAt ( i ) - b . byteAt ( i ) - carry ;
134+ carry = cur < 0 | 0 ;
135+ bytes [ i ] = cur ;
136+ }
137+ return this ;
138+ } , 2 ) ;
139+ }
140+
141+ // Constructs a new Int64 instance with the same bit representation as the provided double.
142+ Int64 . fromDouble = function ( d ) {
143+ var bytes = Struct . pack ( Struct . float64 , d ) ;
144+ return new Int64 ( bytes ) ;
145+ } ;
146+
147+ // Convenience functions. These allocate a new Int64 to hold the result.
148+
149+ // Return -n (two's complement)
150+ function Neg ( n ) {
151+ return ( new Int64 ( ) ) . assignNeg ( n ) ;
152+ }
153+
154+ // Return a + b
155+ function Add ( a , b ) {
156+ return ( new Int64 ( ) ) . assignAdd ( a , b ) ;
157+ }
158+
159+ // Return a - b
160+ function Sub ( a , b ) {
161+ return ( new Int64 ( ) ) . assignSub ( a , b ) ;
162+ }
163+
164+ // Return a & b
165+ function And ( a , b ) {
166+ return ( new Int64 ( ) ) . assignAnd ( a , b ) ;
167+ }
168+
169+ // Return a << 1
170+ function LShift1 ( a ) {
171+ return ( new Int64 ( ) ) . assignLShift1 ( a ) ;
172+ }
173+
174+ // Return a >> 1
175+ function RShift1 ( a ) {
176+ return ( new Int64 ( ) ) . assignRShift1 ( a ) ;
177+ }
178+
179+ // Return a << b
180+ function ShiftLeft ( a , b ) {
181+ return ( new Int64 ( ) ) . assignShiftLeft ( a , b ) ;
182+ }
183+
184+ // Return a >> b
185+ function ShiftRight ( a , b ) {
186+ return ( new Int64 ( ) ) . assignShiftRight ( a , b ) ;
187+ }
188+
189+ // Return a == b
190+ function Eq ( a , b ) {
191+ if ( ! ( a instanceof Int64 ) ) {
192+ a = new Int64 ( a ) ;
193+ }
194+
195+ if ( ! ( b instanceof Int64 ) ) {
196+ b = new Int64 ( b ) ;
197+ }
198+
199+ for ( let Idx = 0 ; Idx < 8 ; Idx ++ ) {
200+ if ( a . byteAt ( Idx ) != b . byteAt ( Idx ) ) {
201+ return false ;
202+ }
203+ }
204+
205+ return true ;
206+ }
207+
208+ // Some commonly used numbers.
209+ Int64 . Zero = new Int64 ( 0 ) ;
210+ Int64 . One = new Int64 ( 1 ) ;
211+
212+ // That's all the arithmetic we need for exploiting WebKit.. :)
0 commit comments