THRIFT-4675: Generate Int64 constants for js
diff --git a/lib/js/src/thrift.js b/lib/js/src/thrift.js
index fad24d6..b9fa62d 100644
--- a/lib/js/src/thrift.js
+++ b/lib/js/src/thrift.js
@@ -1007,7 +1007,11 @@
 
     /** Serializes a number */
     writeI64: function(i64) {
-        this.tstack.push(i64);
+        if (typeof i64 === 'number') {
+            this.tstack.push(i64);
+        } else {
+            this.tstack.push(Int64Util.toDecimalString(i64));
+        }
     },
 
     /** Serializes a number */
@@ -1078,12 +1082,16 @@
         this.rstack = [];
         this.rpos = [];
 
-        if (typeof JSON !== 'undefined' && typeof JSON.parse === 'function') {
-            this.robj = JSON.parse(this.transport.readAll());
+        received = this.transport.readAll();
+
+        if (typeof JSONInt64 !== 'undefined' && typeof JSONInt64.parse === 'function') {
+            this.robj = JSONInt64.parse(received);
+        } else if (typeof JSON !== 'undefined' && typeof JSON.parse === 'function') {
+            this.robj = JSON.parse(received);
         } else if (typeof jQuery !== 'undefined') {
-            this.robj = jQuery.parseJSON(this.transport.readAll());
+            this.robj = jQuery.parseJSON(received);
         } else {
-            this.robj = eval(this.transport.readAll());
+            this.robj = eval(received);
         }
 
         var r = {};
@@ -1226,7 +1234,6 @@
         r.vtype = Thrift.Protocol.RType[map.shift()];
         r.size = map.shift();
 
-
         this.rpos.push(this.rstack.length);
         this.rstack.push(map.shift());
 
@@ -1351,8 +1358,54 @@
 
     /** Returns the an object with a value property set to the
         next value found in the protocol buffer */
-    readI64: function() {
-        return this.readI32();
+    readI64: function(f) {
+        if (f === undefined) {
+            f = this.rstack[this.rstack.length - 1];
+        }
+
+        var r = {};
+
+        if (f instanceof Array) {
+            if (f.length === 0) {
+                r.value = undefined;
+            } else {
+                if (!f.isReversed) {
+                    f.reverse();
+                    f.isReversed = true;
+                }
+                r.value = f.pop();
+            }
+        } else if (f instanceof Object) {
+            var int64Object = true;
+            var objectKeys = Object.keys(f).sort();
+            var int64Keys = ['buffer', 'offset'];
+            if (objectKeys.length !== int64Keys.length) {
+                int64Object = false;
+            }
+            for (var it=0; int64Object && it < objectKeys.length; ++it) {
+                if (objectKeys[it] !== int64Keys[it]) {
+                    int64Object = false;
+                }
+            }
+            if (int64Object) {
+                r.value = f;
+            } else {
+                for (var i in f) {
+                    if (i === null) {
+                    continue;
+                    }
+                    this.rstack.push(f[i]);
+                    delete f[i];
+
+                    r.value = i;
+                    break;
+                }
+            }
+        } else {
+            r.value = f;
+            this.rstack.pop();
+        }
+        return r;
     },
 
     /** Returns the an object with a value property set to the