Update V8 to r6101 as required by WebKit r74534

Change-Id: I7f84af8dd732f11898fd644b2c2b1538914cb78d
diff --git a/src/json.js b/src/json.js
index 5993100..89009a9 100644
--- a/src/json.js
+++ b/src/json.js
@@ -66,51 +66,10 @@
   }
 }
 
-var characterQuoteCache = {
-  '\b': '\\b',  // ASCII 8, Backspace
-  '\t': '\\t',  // ASCII 9, Tab
-  '\n': '\\n',  // ASCII 10, Newline
-  '\f': '\\f',  // ASCII 12, Formfeed
-  '\r': '\\r',  // ASCII 13, Carriage Return
-  '\"': '\\"',
-  '\\': '\\\\'
-};
-
-function QuoteSingleJSONCharacter(c) {
-  if (c in characterQuoteCache) {
-    return characterQuoteCache[c];
-  }
-  var charCode = c.charCodeAt(0);
-  var result;
-  if (charCode < 16) result = '\\u000';
-  else if (charCode < 256) result = '\\u00';
-  else if (charCode < 4096) result = '\\u0';
-  else result = '\\u';
-  result += charCode.toString(16);
-  characterQuoteCache[c] = result;
-  return result;
-}
-
-function QuoteJSONString(str) {
-  var quotable = /[\\\"\x00-\x1f]/g;
-  return '"' + str.replace(quotable, QuoteSingleJSONCharacter) + '"';
-}
-
-function StackContains(stack, val) {
-  var length = stack.length;
-  for (var i = 0; i < length; i++) {
-    if (stack[i] === val) {
-      return true;
-    }
-  }
-  return false;
-}
-
 function SerializeArray(value, replacer, stack, indent, gap) {
-  if (StackContains(stack, value)) {
+  if (!%PushIfAbsent(stack, value)) {
     throw MakeTypeError('circular_structure', []);
   }
-  stack.push(value);
   var stepback = indent;
   indent += gap;
   var partial = [];
@@ -138,10 +97,9 @@
 }
 
 function SerializeObject(value, replacer, stack, indent, gap) {
-  if (StackContains(stack, value)) {
+  if (!%PushIfAbsent(stack, value)) {
     throw MakeTypeError('circular_structure', []);
   }
-  stack.push(value);
   var stepback = indent;
   indent += gap;
   var partial = [];
@@ -152,7 +110,7 @@
         var p = replacer[i];
         var strP = JSONSerialize(p, value, replacer, stack, indent, gap);
         if (!IS_UNDEFINED(strP)) {
-          var member = QuoteJSONString(p) + ":";
+          var member = %QuoteJSONString(p) + ":";
           if (gap != "") member += " ";
           member += strP;
           partial.push(member);
@@ -164,7 +122,7 @@
       if (ObjectHasOwnProperty.call(value, p)) {
         var strP = JSONSerialize(p, value, replacer, stack, indent, gap);
         if (!IS_UNDEFINED(strP)) {
-          var member = QuoteJSONString(p) + ":";
+          var member = %QuoteJSONString(p) + ":";
           if (gap != "") member += " ";
           member += strP;
           partial.push(member);
@@ -188,71 +146,159 @@
 
 function JSONSerialize(key, holder, replacer, stack, indent, gap) {
   var value = holder[key];
-  if (IS_OBJECT(value) && value) {
+  if (IS_SPEC_OBJECT(value)) {
     var toJSON = value.toJSON;
     if (IS_FUNCTION(toJSON)) {
-      value = toJSON.call(value, key);
+      value = %_CallFunction(value, key, toJSON);
     }
   }
   if (IS_FUNCTION(replacer)) {
-    value = replacer.call(holder, key, value);
+    value = %_CallFunction(holder, key, value, replacer);
   }
-  // Unwrap value if necessary
-  if (IS_OBJECT(value)) {
-    if (IS_NUMBER_WRAPPER(value)) {
-      value = $Number(value);
+  if (IS_STRING(value)) {
+    return %QuoteJSONString(value);
+  } else if (IS_NUMBER(value)) {
+    return $isFinite(value) ? $String(value) : "null";
+  } else if (IS_BOOLEAN(value)) {
+    return value ? "true" : "false";
+  } else if (IS_NULL(value)) {
+    return "null";
+  } else if (IS_SPEC_OBJECT(value) && !(typeof value == "function")) {
+    // Non-callable object. If it's a primitive wrapper, it must be unwrapped.
+    if (IS_ARRAY(value)) {
+      return SerializeArray(value, replacer, stack, indent, gap);
+    } else if (IS_NUMBER_WRAPPER(value)) {
+      value = ToNumber(value);
+      return $isFinite(value) ? ToString(value) : "null";
     } else if (IS_STRING_WRAPPER(value)) {
-      value = $String(value);
+      return %QuoteJSONString(ToString(value));
     } else if (IS_BOOLEAN_WRAPPER(value)) {
-      value =  %_ValueOf(value);
+      return %_ValueOf(value) ? "true" : "false";
+    } else {
+      return SerializeObject(value, replacer, stack, indent, gap);
     }
   }
-  switch (typeof value) {
-    case "string":
-      return QuoteJSONString(value);
-    case "object":
-      if (!value) {
-        return "null";
-      } else if (IS_ARRAY(value)) {
-        return SerializeArray(value, replacer, stack, indent, gap);
+  // Undefined or a callable object.
+  return void 0;
+}
+
+
+function BasicSerializeArray(value, stack, builder) {
+  if (!%PushIfAbsent(stack, value)) {
+    throw MakeTypeError('circular_structure', []);
+  }
+  builder.push("[");
+  var len = value.length;
+  for (var i = 0; i < len; i++) {
+    var before = builder.length;
+    BasicJSONSerialize(i, value, stack, builder);
+    if (before == builder.length) builder.push("null");
+    builder.push(",");
+  }
+  stack.pop();
+  if (builder.pop() != ",") {
+    builder.push("[]");  // Zero length array. Push "[" back on.
+  } else {
+    builder.push("]");
+  }
+
+}
+
+
+function BasicSerializeObject(value, stack, builder) {
+  if (!%PushIfAbsent(stack, value)) {
+    throw MakeTypeError('circular_structure', []);
+  }
+  builder.push("{");
+  for (var p in value) {
+    if (%HasLocalProperty(value, p)) {
+      builder.push(%QuoteJSONString(p));
+      builder.push(":");
+      var before = builder.length;
+      BasicJSONSerialize(p, value, stack, builder);
+      if (before == builder.length) {
+        builder.pop();
+        builder.pop();
       } else {
-        return SerializeObject(value, replacer, stack, indent, gap);
+        builder.push(",");
       }
-    case "number":
-      return $isFinite(value) ? $String(value) : "null";
-    case "boolean":
-      return value ? "true" : "false";
+    }
+  }
+  stack.pop();
+  if (builder.pop() != ",") {
+    builder.push("{}");  // Object has no own properties. Push "{" back on.
+  } else {
+    builder.push("}");
   }
 }
 
+
+function BasicJSONSerialize(key, holder, stack, builder) {
+  var value = holder[key];
+  if (IS_SPEC_OBJECT(value)) {
+    var toJSON = value.toJSON;
+    if (IS_FUNCTION(toJSON)) {
+      value = %_CallFunction(value, ToString(key), toJSON);
+    }
+  }
+  if (IS_STRING(value)) {
+    builder.push(%QuoteJSONString(value));
+  } else if (IS_NUMBER(value)) {
+    builder.push(($isFinite(value) ? %_NumberToString(value) : "null"));
+  } else if (IS_BOOLEAN(value)) {
+    builder.push(value ? "true" : "false");
+  } else if (IS_NULL(value)) {
+    builder.push("null");
+  } else if (IS_SPEC_OBJECT(value) && !(typeof value == "function")) {
+    // Value is a non-callable object.
+    // Unwrap value if necessary
+    if (IS_NUMBER_WRAPPER(value)) {
+      value = ToNumber(value);
+      builder.push(($isFinite(value) ? %_NumberToString(value) : "null"));
+    } else if (IS_STRING_WRAPPER(value)) {
+      builder.push(%QuoteJSONString(ToString(value)));
+    } else if (IS_BOOLEAN_WRAPPER(value)) {
+      builder.push(%_ValueOf(value) ? "true" : "false");
+    } else if (IS_ARRAY(value)) {
+      BasicSerializeArray(value, stack, builder);
+    } else {
+      BasicSerializeObject(value, stack, builder);
+    }
+  }
+}
+
+
 function JSONStringify(value, replacer, space) {
-  var stack = [];
-  var indent = "";
+  if (%_ArgumentsLength() == 1) {
+    var builder = [];
+    BasicJSONSerialize('', {'': value}, [], builder);
+    if (builder.length == 0) return;
+    var result = %_FastAsciiArrayJoin(builder, "");
+    if (!IS_UNDEFINED(result)) return result;
+    return %StringBuilderConcat(builder, builder.length, "");
+  }
   if (IS_OBJECT(space)) {
     // Unwrap 'space' if it is wrapped
     if (IS_NUMBER_WRAPPER(space)) {
-      space = $Number(space);
+      space = ToNumber(space);
     } else if (IS_STRING_WRAPPER(space)) {
-      space = $String(space);
+      space = ToString(space);
     }
   }
   var gap;
   if (IS_NUMBER(space)) {
-    space = $Math.min(ToInteger(space), 10);
-    gap = "";
-    for (var i = 0; i < space; i++) {
-      gap += " ";
-    }
+    space = MathMax(0, MathMin(ToInteger(space), 10));
+    gap = SubString("          ", 0, space);
   } else if (IS_STRING(space)) {
     if (space.length > 10) {
-      gap = space.substring(0, 10);
+      gap = SubString(space, 0, 10);
     } else {
       gap = space;
     }
   } else {
     gap = "";
   }
-  return JSONSerialize('', {'': value}, replacer, stack, indent, gap);
+  return JSONSerialize('', {'': value}, replacer, [], "", gap);
 }
 
 function SetupJSON() {