Update V8 to r4851 as required by WebKit r61121

Change-Id: Ib01b7c8e38d5b82b254192fc06365aa5b85780c5
diff --git a/test/mjsunit/string-charat.js b/test/mjsunit/string-charat.js
index d1989df..5ce4e89 100644
--- a/test/mjsunit/string-charat.js
+++ b/test/mjsunit/string-charat.js
@@ -27,29 +27,58 @@
 
 var s = "test";
 
-assertEquals("t", s.charAt());
-assertEquals("t", s.charAt("string"));
-assertEquals("t", s.charAt(null));
-assertEquals("t", s.charAt(void 0));
-assertEquals("t", s.charAt(false));
-assertEquals("e", s.charAt(true));
-assertEquals("", s.charAt(-1));
-assertEquals("", s.charAt(4));
-assertEquals("t", s.charAt(0));
-assertEquals("t", s.charAt(3));
-assertEquals("t", s.charAt(NaN));
+function getTwoByteString() { return "\u1234t"; }
+function getCons() { return "testtesttesttest" + getTwoByteString() }
 
-assertEquals(116, s.charCodeAt());
-assertEquals(116, s.charCodeAt("string"));
-assertEquals(116, s.charCodeAt(null));
-assertEquals(116, s.charCodeAt(void 0));
-assertEquals(116, s.charCodeAt(false));
-assertEquals(101, s.charCodeAt(true));
-assertEquals(116, s.charCodeAt(0));
-assertEquals(116, s.charCodeAt(3));
-assertEquals(116, s.charCodeAt(NaN));
-assertTrue(isNaN(s.charCodeAt(-1)));
-assertTrue(isNaN(s.charCodeAt(4)));
+var slowIndex1 = { valueOf: function() { return 1; } };
+var slowIndex2 = { toString: function() { return "2"; } };
+var slowIndexOutOfRange = { valueOf: function() { return -1; } };
+
+function basicTest(s, len) {
+  assertEquals("t", s().charAt());
+  assertEquals("t", s().charAt("string"));
+  assertEquals("t", s().charAt(null));
+  assertEquals("t", s().charAt(void 0));
+  assertEquals("t", s().charAt(false));
+  assertEquals("e", s().charAt(true));
+  assertEquals("", s().charAt(-1));
+  assertEquals("", s().charAt(len));
+  assertEquals("", s().charAt(slowIndexOutOfRange));
+  assertEquals("", s().charAt(1/0));
+  assertEquals("", s().charAt(-1/0));
+  assertEquals("t", s().charAt(0));
+  assertEquals("t", s().charAt(-0.0));
+  assertEquals("t", s().charAt(-0.1));
+  assertEquals("t", s().charAt(0.4));
+  assertEquals("e", s().charAt(slowIndex1));
+  assertEquals("s", s().charAt(slowIndex2));
+  assertEquals("t", s().charAt(3));
+  assertEquals("t", s().charAt(3.4));
+  assertEquals("t", s().charAt(NaN));
+
+  assertEquals(116, s().charCodeAt());
+  assertEquals(116, s().charCodeAt("string"));
+  assertEquals(116, s().charCodeAt(null));
+  assertEquals(116, s().charCodeAt(void 0));
+  assertEquals(116, s().charCodeAt(false));
+  assertEquals(101, s().charCodeAt(true));
+  assertEquals(116, s().charCodeAt(0));
+  assertEquals(116, s().charCodeAt(-0.0));
+  assertEquals(116, s().charCodeAt(-0.1));
+  assertEquals(116, s().charCodeAt(0.4));
+  assertEquals(101, s().charCodeAt(slowIndex1));
+  assertEquals(115, s().charCodeAt(slowIndex2));
+  assertEquals(116, s().charCodeAt(3));
+  assertEquals(116, s().charCodeAt(3.4));
+  assertEquals(116, s().charCodeAt(NaN));
+  assertTrue(isNaN(s().charCodeAt(-1)));
+  assertTrue(isNaN(s().charCodeAt(len)));
+  assertTrue(isNaN(s().charCodeAt(slowIndexOutOfRange)));
+  assertTrue(isNaN(s().charCodeAt(1/0)));
+  assertTrue(isNaN(s().charCodeAt(-1/0)));
+}
+basicTest(function() { return s; }, s.length);
+basicTest(getCons, getCons().length);
 
 // Make sure enough of the one-char string cache is filled.
 var alpha = ['@'];
@@ -64,3 +93,163 @@
   assertEquals(alpha[i], alphaStr.charAt(i));
   assertEquals(String.fromCharCode(i), alphaStr.charAt(i));
 }
+
+// Test stealing String.prototype.{charAt,charCodeAt}.
+var o = {
+  charAt: String.prototype.charAt,
+  charCodeAt: String.prototype.charCodeAt,
+  toString: function() { return "012"; },
+  valueOf: function() { return "should not be called"; }
+};
+
+function stealTest() {
+  assertEquals("0", o.charAt(0));
+  assertEquals("1", o.charAt(1));
+  assertEquals("1", o.charAt(1.4));
+  assertEquals("1", o.charAt(slowIndex1));
+  assertEquals("2", o.charAt(2));
+  assertEquals("2", o.charAt(slowIndex2));
+  assertEquals(48, o.charCodeAt(0));
+  assertEquals(49, o.charCodeAt(1));
+  assertEquals(49, o.charCodeAt(1.4));
+  assertEquals(49, o.charCodeAt(slowIndex1));
+  assertEquals(50, o.charCodeAt(2));
+  assertEquals(50, o.charCodeAt(slowIndex2));
+  assertEquals("", o.charAt(-1));
+  assertEquals("", o.charAt(-1.4));
+  assertEquals("", o.charAt(10));
+  assertEquals("", o.charAt(slowIndexOutOfRange));
+  assertTrue(isNaN(o.charCodeAt(-1)));
+  assertTrue(isNaN(o.charCodeAt(-1.4)));
+  assertTrue(isNaN(o.charCodeAt(10)));
+  assertTrue(isNaN(o.charCodeAt(slowIndexOutOfRange)));
+}
+stealTest();
+
+// Test custom string IC-s.
+for (var i = 0; i < 20; i++) {
+  basicTest(function() { return s; }, s.length);
+  basicTest(getCons, getCons().length);
+  stealTest();
+}
+
+var badToString = function() { return []; };
+
+function testBadToString_charAt() {
+  var goodToString = o.toString;
+  var hasCaught = false;
+  var numCalls = 0;
+  var result;
+  try {
+    for (var i = 0; i < 20; i++) {
+      if (i == 10) o.toString = o.valueOf = badToString;
+      result = o.charAt(1);
+      numCalls++;
+    }
+  } catch (e) {
+    hasCaught = true;
+  } finally {
+    o.toString = goodToString;
+  }
+  assertTrue(hasCaught);
+  assertEquals("1", result);
+  assertEquals(10, numCalls);
+}
+testBadToString_charAt();
+
+function testBadToString_charCodeAt() {
+  var goodToString = o.toString;
+  var hasCaught = false;
+  var numCalls = 0;
+  var result;
+  try {
+    for (var i = 0; i < 20; i++) {
+      if (i == 10) o.toString = o.valueOf = badToString;
+      result = o.charCodeAt(1);
+      numCalls++;
+    }
+  } catch (e) {
+    hasCaught = true;
+  } finally {
+    o.toString = goodToString;
+  }
+  assertTrue(hasCaught);
+  assertEquals(49, result);
+  assertEquals(10, numCalls);
+}
+testBadToString_charCodeAt();
+
+var badIndex = {
+  toString: badToString,
+  valueOf: badToString
+};
+
+function testBadIndex_charAt() {
+  var index = 1;
+  var hasCaught = false;
+  var numCalls = 0;
+  var result;
+  try {
+    for (var i = 0; i < 20; i++) {
+      if (i == 10) index = badIndex;
+      result = o.charAt(index);
+      numCalls++;
+    }
+  } catch (e) {
+    hasCaught = true;
+  }
+  assertTrue(hasCaught);
+  assertEquals("1", result);
+  assertEquals(10, numCalls);
+}
+testBadIndex_charAt();
+
+function testBadIndex_charCodeAt() {
+  var index = 1;
+  var hasCaught = false;
+  var numCalls = 0;
+  var result;
+  try {
+    for (var i = 0; i < 20; i++) {
+      if (i == 10) index = badIndex;
+      result = o.charCodeAt(index);
+      numCalls++;
+    }
+  } catch (e) {
+    hasCaught = true;
+  }
+  assertTrue(hasCaught);
+  assertEquals(49, result);
+  assertEquals(10, numCalls);
+}
+testBadIndex_charCodeAt();
+
+function testPrototypeChange_charAt() {
+  var result, oldResult;
+  for (var i = 0; i < 20; i++) {
+    if (i == 10) {
+      oldResult = result;
+      String.prototype.charAt = function() { return "%"; };
+    }
+    result = s.charAt(1);
+  }
+  assertEquals("%", result);
+  assertEquals("e", oldResult);
+  delete String.prototype.charAt;  // Restore the default.
+}
+testPrototypeChange_charAt();
+
+function testPrototypeChange_charCodeAt() {
+  var result, oldResult;
+  for (var i = 0; i < 20; i++) {
+    if (i == 10) {
+      oldResult = result;
+      String.prototype.charCodeAt = function() { return 42; };
+    }
+    result = s.charCodeAt(1);
+  }
+  assertEquals(42, result);
+  assertEquals(101, oldResult);
+  delete String.prototype.charCodeAt;  // Restore the default.
+}
+testPrototypeChange_charCodeAt();