<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[183141] trunk</title>
</head>
<body>
<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; }
#msg dl a { font-weight: bold}
#msg dl a:link { color:#fc3; }
#msg dl a:active { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/183141">183141</a></dd>
<dt>Author</dt> <dd>benjamin@webkit.org</dd>
<dt>Date</dt> <dd>2015-04-22 15:25:27 -0700 (Wed, 22 Apr 2015)</dd>
</dl>
<h3>Log Message</h3>
<pre>Implement String.codePointAt()
https://bugs.webkit.org/show_bug.cgi?id=143934
Reviewed by Darin Adler.
Source/JavaScriptCore:
This patch adds String.codePointAt() as defined by ES6.
I opted for a C++ implementation for now.
* runtime/StringPrototype.cpp:
(JSC::StringPrototype::finishCreation):
(JSC::codePointAt):
(JSC::stringProtoFuncCodePointAt):
LayoutTests:
* js/Object-getOwnPropertyNames-expected.txt:
* js/script-tests/string-code-point-at.js: Added.
(objectWithCustomToString.toString):
(objectThrowingOnToString.toString):
(objectCountingToString.toString):
(testLeadSurrogateOutOfBounds):
(testLeadSurrogateAsLastCharacter):
(testTrailSurrogateOutOfbounds):
(testAccessNullInString):
(testNormalCombinationOfSurrogates):
* js/string-code-point-at-expected.txt: Added.
* js/string-code-point-at.html: Added.</pre>
<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkLayoutTestsjsObjectgetOwnPropertyNamesexpectedtxt">trunk/LayoutTests/js/Object-getOwnPropertyNames-expected.txt</a></li>
<li><a href="#trunkLayoutTestsjsscripttestsObjectgetOwnPropertyNamesjs">trunk/LayoutTests/js/script-tests/Object-getOwnPropertyNames.js</a></li>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeStringPrototypecpp">trunk/Source/JavaScriptCore/runtime/StringPrototype.cpp</a></li>
</ul>
<h3>Added Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsjsscripttestsstringcodepointatjs">trunk/LayoutTests/js/script-tests/string-code-point-at.js</a></li>
<li><a href="#trunkLayoutTestsjsstringcodepointatexpectedtxt">trunk/LayoutTests/js/string-code-point-at-expected.txt</a></li>
<li><a href="#trunkLayoutTestsjsstringcodepointathtml">trunk/LayoutTests/js/string-code-point-at.html</a></li>
</ul>
</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (183140 => 183141)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog        2015-04-22 22:17:49 UTC (rev 183140)
+++ trunk/LayoutTests/ChangeLog        2015-04-22 22:25:27 UTC (rev 183141)
</span><span class="lines">@@ -1,3 +1,23 @@
</span><ins>+2015-04-22 Benjamin Poulain <benjamin@webkit.org>
+
+ Implement String.codePointAt()
+ https://bugs.webkit.org/show_bug.cgi?id=143934
+
+ Reviewed by Darin Adler.
+
+ * js/Object-getOwnPropertyNames-expected.txt:
+ * js/script-tests/string-code-point-at.js: Added.
+ (objectWithCustomToString.toString):
+ (objectThrowingOnToString.toString):
+ (objectCountingToString.toString):
+ (testLeadSurrogateOutOfBounds):
+ (testLeadSurrogateAsLastCharacter):
+ (testTrailSurrogateOutOfbounds):
+ (testAccessNullInString):
+ (testNormalCombinationOfSurrogates):
+ * js/string-code-point-at-expected.txt: Added.
+ * js/string-code-point-at.html: Added.
+
</ins><span class="cx"> 2015-04-22 Brent Fulgham <bfulgham@apple.com>
</span><span class="cx">
</span><span class="cx"> Context menu doesn't account for selection semantics
</span></span></pre></div>
<a id="trunkLayoutTestsjsObjectgetOwnPropertyNamesexpectedtxt"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/js/Object-getOwnPropertyNames-expected.txt (183140 => 183141)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/Object-getOwnPropertyNames-expected.txt        2015-04-22 22:17:49 UTC (rev 183140)
+++ trunk/LayoutTests/js/Object-getOwnPropertyNames-expected.txt        2015-04-22 22:25:27 UTC (rev 183141)
</span><span class="lines">@@ -48,7 +48,7 @@
</span><span class="cx"> PASS getSortedOwnPropertyNames(Array) is ['from', 'isArray', 'length', 'name', 'of', 'prototype']
</span><span class="cx"> PASS getSortedOwnPropertyNames(Array.prototype) is ['concat', 'constructor', 'entries', 'every', 'fill', 'filter', 'find', 'findIndex', 'forEach', 'includes', 'indexOf', 'join', 'keys', 'lastIndexOf', 'length', 'map', 'pop', 'push', 'reduce', 'reduceRight', 'reverse', 'shift', 'slice', 'some', 'sort', 'splice', 'toLocaleString', 'toString', 'unshift', 'values']
</span><span class="cx"> PASS getSortedOwnPropertyNames(String) is ['fromCharCode', 'length', 'name', 'prototype']
</span><del>-PASS getSortedOwnPropertyNames(String.prototype) is ['anchor', 'big', 'blink', 'bold', 'charAt', 'charCodeAt', 'concat', 'constructor', 'endsWith', 'fixed', 'fontcolor', 'fontsize', 'includes', 'indexOf', 'italics', 'lastIndexOf', 'length', 'link', 'localeCompare', 'match', 'repeat', 'replace', 'search', 'slice', 'small', 'split', 'startsWith', 'strike', 'sub', 'substr', 'substring', 'sup', 'toLocaleLowerCase', 'toLocaleUpperCase', 'toLowerCase', 'toString', 'toUpperCase', 'trim', 'trimLeft', 'trimRight', 'valueOf']
</del><ins>+PASS getSortedOwnPropertyNames(String.prototype) is ['anchor', 'big', 'blink', 'bold', 'charAt', 'charCodeAt', 'codePointAt', 'concat', 'constructor', 'endsWith', 'fixed', 'fontcolor', 'fontsize', 'includes', 'indexOf', 'italics', 'lastIndexOf', 'length', 'link', 'localeCompare', 'match', 'repeat', 'replace', 'search', 'slice', 'small', 'split', 'startsWith', 'strike', 'sub', 'substr', 'substring', 'sup', 'toLocaleLowerCase', 'toLocaleUpperCase', 'toLowerCase', 'toString', 'toUpperCase', 'trim', 'trimLeft', 'trimRight', 'valueOf']
</ins><span class="cx"> PASS getSortedOwnPropertyNames(Boolean) is ['length', 'name', 'prototype']
</span><span class="cx"> PASS getSortedOwnPropertyNames(Boolean.prototype) is ['constructor', 'toString', 'valueOf']
</span><span class="cx"> PASS getSortedOwnPropertyNames(Number) is ['EPSILON', 'MAX_SAFE_INTEGER', 'MAX_VALUE', 'MIN_SAFE_INTEGER', 'MIN_VALUE', 'NEGATIVE_INFINITY', 'NaN', 'POSITIVE_INFINITY', 'isFinite', 'isInteger', 'isNaN', 'isSafeInteger', 'length', 'name', 'parseFloat', 'parseInt', 'prototype']
</span></span></pre></div>
<a id="trunkLayoutTestsjsscripttestsObjectgetOwnPropertyNamesjs"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/js/script-tests/Object-getOwnPropertyNames.js (183140 => 183141)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/script-tests/Object-getOwnPropertyNames.js        2015-04-22 22:17:49 UTC (rev 183140)
+++ trunk/LayoutTests/js/script-tests/Object-getOwnPropertyNames.js        2015-04-22 22:25:27 UTC (rev 183141)
</span><span class="lines">@@ -57,7 +57,7 @@
</span><span class="cx"> "Array": "['from', 'isArray', 'length', 'name', 'of', 'prototype']",
</span><span class="cx"> "Array.prototype": "['concat', 'constructor', 'entries', 'every', 'fill', 'filter', 'find', 'findIndex', 'forEach', 'includes', 'indexOf', 'join', 'keys', 'lastIndexOf', 'length', 'map', 'pop', 'push', 'reduce', 'reduceRight', 'reverse', 'shift', 'slice', 'some', 'sort', 'splice', 'toLocaleString', 'toString', 'unshift', 'values']",
</span><span class="cx"> "String": "['fromCharCode', 'length', 'name', 'prototype']",
</span><del>- "String.prototype": "['anchor', 'big', 'blink', 'bold', 'charAt', 'charCodeAt', 'concat', 'constructor', 'endsWith', 'fixed', 'fontcolor', 'fontsize', 'includes', 'indexOf', 'italics', 'lastIndexOf', 'length', 'link', 'localeCompare', 'match', 'repeat', 'replace', 'search', 'slice', 'small', 'split', 'startsWith', 'strike', 'sub', 'substr', 'substring', 'sup', 'toLocaleLowerCase', 'toLocaleUpperCase', 'toLowerCase', 'toString', 'toUpperCase', 'trim', 'trimLeft', 'trimRight', 'valueOf']",
</del><ins>+ "String.prototype": "['anchor', 'big', 'blink', 'bold', 'charAt', 'charCodeAt', 'codePointAt', 'concat', 'constructor', 'endsWith', 'fixed', 'fontcolor', 'fontsize', 'includes', 'indexOf', 'italics', 'lastIndexOf', 'length', 'link', 'localeCompare', 'match', 'repeat', 'replace', 'search', 'slice', 'small', 'split', 'startsWith', 'strike', 'sub', 'substr', 'substring', 'sup', 'toLocaleLowerCase', 'toLocaleUpperCase', 'toLowerCase', 'toString', 'toUpperCase', 'trim', 'trimLeft', 'trimRight', 'valueOf']",
</ins><span class="cx"> "Boolean": "['length', 'name', 'prototype']",
</span><span class="cx"> "Boolean.prototype": "['constructor', 'toString', 'valueOf']",
</span><span class="cx"> "Number": "['EPSILON', 'MAX_SAFE_INTEGER', 'MAX_VALUE', 'MIN_SAFE_INTEGER', 'MIN_VALUE', 'NEGATIVE_INFINITY', 'NaN', 'POSITIVE_INFINITY', 'isFinite', 'isInteger', 'isNaN', 'isSafeInteger', 'length', 'name', 'parseFloat', 'parseInt', 'prototype']",
</span></span></pre></div>
<a id="trunkLayoutTestsjsscripttestsstringcodepointatjs"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/js/script-tests/string-code-point-at.js (0 => 183141)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/script-tests/string-code-point-at.js         (rev 0)
+++ trunk/LayoutTests/js/script-tests/string-code-point-at.js        2015-04-22 22:25:27 UTC (rev 183141)
</span><span class="lines">@@ -0,0 +1,143 @@
</span><ins>+description("Test the basic behaviors of String.codePointAt");
+
+shouldBe('String.codePointAt', 'undefined');
+
+shouldBeEqualToString('typeof String.prototype.codePointAt', 'function');
+
+// Function properties.
+shouldBe('String.prototype.codePointAt.length', '1');
+shouldBeEqualToString('String.prototype.codePointAt.name', 'codePointAt')
+shouldBe('Object.getOwnPropertyDescriptor(String.prototype, "codePointAt").configurable', 'true');
+shouldBe('Object.getOwnPropertyDescriptor(String.prototype, "codePointAt").enumerable', 'false');
+shouldBe('Object.getOwnPropertyDescriptor(String.prototype, "codePointAt").writable', 'true');
+
+// The function should only be on the prototype chain, not on the object themselves.
+shouldBeFalse('"foo".hasOwnProperty("codePointAt")');
+shouldBeFalse('(new String("bar")).hasOwnProperty("codePointAt")');
+
+// Some simple cases.
+shouldBe('"".codePointAt(0)', 'undefined');
+shouldBe('"".codePointAt(1)', 'undefined');
+
+shouldBe('"Été".codePointAt(0)', '201');
+shouldBe('"Été".codePointAt(1)', '116');
+shouldBe('"Été".codePointAt(2)', '233');
+shouldBe('"Été".codePointAt(3)', 'undefined');
+
+shouldBe('"ウェブキット".codePointAt(0)', '12454');
+shouldBe('"ウェブキット".codePointAt(1)', '12455');
+shouldBe('"ウェブキット".codePointAt(2)', '12502');
+shouldBe('"ウェブキット".codePointAt(3)', '12461');
+shouldBe('"ウェブキット".codePointAt(4)', '12483');
+shouldBe('"ウェブキット".codePointAt(5)', '12488');
+shouldBe('"ウェブキット".codePointAt(6)', 'undefined');
+
+// Object coercion.
+shouldThrow('"".codePointAt.call(null, 0)');
+shouldThrow('"".codePointAt.call(undefined, 0)');
+shouldBe('"".codePointAt.call(0, 0)', '48');
+shouldBe('"".codePointAt.call(Math.PI, 0)', '51');
+shouldBe('"".codePointAt.call(Math.PI, 1)', '46');
+shouldBe('"".codePointAt.call(Math.PI, 3)', '52');
+shouldBe('"".codePointAt.call(true, 3)', '101');
+shouldBe('"".codePointAt.call(false, 3)', '115');
+shouldBe('"".codePointAt.call(new Object, 3)', '106');
+shouldThrow('"".codePointAt.call(Symbol("WebKit"), 3)');
+
+// toString.
+var objectWithCustomToString = { toString: function() { return "ø"; } };
+shouldBe('"".codePointAt.call(objectWithCustomToString, 0)', '248');
+
+var objectThrowingOnToString = { toString: function() { throw "Hehe"; } };
+shouldThrow('"".codePointAt.call(objectThrowingOnToString, 0)');
+
+var objectCountingToString = { counter: 0, toString: function() { ++this.counter; return this.counter; } };
+shouldBe('"".codePointAt.call(objectCountingToString, 0)', '49');
+shouldBe('objectCountingToString.counter', '1');
+
+// ToNumber.
+var objectWithCustomValueOf = { toString: function() { return "5"; }, valueOf: function() { return 1; } };
+shouldBe('"abcde".codePointAt(objectWithCustomValueOf)', '98');
+
+// The second object is never converted to number if the first object did not convert to string.
+var objectRecordsValueOf = { valueOfEvaluated: false, valueOf: function() { this.valueOfEvaluated = true; return 1; } }
+shouldThrow('"".codePointAt.call(null, objectRecordsValueOf)');
+shouldThrow('"".codePointAt.call(undefined, objectRecordsValueOf)');
+shouldThrow('"".codePointAt.call(Symbol("WebKit"), objectRecordsValueOf)');
+shouldThrow('"".codePointAt.call(objectThrowingOnToString, objectRecordsValueOf)');
+shouldBeFalse('objectRecordsValueOf.valueOfEvaluated');
+
+// Evaluation order.
+var evaluationOrderRecorder = {
+ methodsCalled: [],
+ toString: function() { this.methodsCalled.push("toString"); return "foobar"; },
+ valueOf: function() { this.methodsCalled.push("valueOf"); return 5; }
+}
+shouldBe('"".codePointAt.call(evaluationOrderRecorder, evaluationOrderRecorder)', '114');
+shouldBeEqualToString('evaluationOrderRecorder.methodsCalled.toString()', 'toString,valueOf');
+
+// Weird positions.
+shouldBe('"abc".codePointAt(NaN)', '97');
+shouldBe('"abc".codePointAt(-0)', '97');
+shouldBe('"abc".codePointAt(-0.0)', '97');
+shouldBe('"abc".codePointAt(-0.05)', '97');
+shouldBe('"abc".codePointAt(-0.999)', '97');
+shouldBe('"abc".codePointAt(0.4)', '97');
+shouldBe('"abc".codePointAt(0.9)', '97');
+shouldBe('"abc".codePointAt(2.9999)', '99');
+
+// Out of bound positions.
+shouldBe('"abc".codePointAt(-1)', 'undefined');
+shouldBe('"abc".codePointAt(4)', 'undefined');
+shouldBe('var str = "abc"; str.codePointAt(str.length)', 'undefined');
+shouldBe('"abc".codePointAt(4.1)', 'undefined');
+shouldBe('"abc".codePointAt(Number.POSITIVE_INFINITY)', 'undefined');
+shouldBe('"abc".codePointAt(Number.NEGATIVE_INFINITY)', 'undefined');
+
+// Non-number as positions.
+shouldBe('"abc".codePointAt(null)', '97');
+shouldBe('"abc".codePointAt(undefined)', '97');
+shouldBe('"abc".codePointAt("")', '97');
+shouldBe('"abc".codePointAt("WebKit!")', '97');
+shouldBe('"abc".codePointAt(new Object)', '97');
+shouldThrow('"abc".codePointAt(Symbol("WebKit"))');
+
+// The following are using special test functions because of limitations of WebKitTestRunner when handling strings with invalid codepoints.
+// When transfering the text of a test, WebKitTestRunner converts it to a UTF-8 C String. Not all invalid code point can be represented.
+
+// If first < 0xD800 or first > 0xDBFF or position+1 = size, return first.
+function testLeadSurrogateOutOfBounds()
+{
+ return ("\uD7FF\uDC00".codePointAt(0) === 0xd7ff && "\uD7FF\uDC00".codePointAt(1) === 0xdc00 && "\uD7FF\uDC00".codePointAt(2) === undefined
+ && "\uDC00\uDC00".codePointAt(0) === 0xdc00 && "\uDC00\uDC00".codePointAt(1) === 0xdc00 && "\uDC00\uDC00".codePointAt(2) === undefined)
+}
+shouldBeTrue("testLeadSurrogateOutOfBounds()");
+
+function testLeadSurrogateAsLastCharacter()
+{
+ return "abc\uD800".codePointAt(3) === 0xd800;
+}
+shouldBeTrue("testLeadSurrogateAsLastCharacter()");
+
+// If second < 0xDC00 or second > 0xDFFF, return first.
+function testTrailSurrogateOutOfbounds()
+{
+ return ("\uD800\uDBFF".codePointAt(0) === 0xd800 && "\uD800\uDBFF".codePointAt(1) === 0xdbff && "\uD800\uDBFF".codePointAt(2) === undefined
+ && "\uD800\uE000".codePointAt(0) === 0xd800 && "\uD800\uE000".codePointAt(1) === 0xe000 && "\uD800\uE000".codePointAt(2) === undefined)
+}
+shouldBeTrue("testTrailSurrogateOutOfbounds()");
+
+// Null in a string.
+function testAccessNullInString()
+{
+ return "a\u0000b".codePointAt(0) === 97 && "a\u0000b".codePointAt(1) === 0 && "a\u0000b".codePointAt(2) === 98 && "a\u0000b".codePointAt(3) === undefined;
+}
+shouldBeTrue("testAccessNullInString()");
+
+
+// Normal combinations of surrogates.
+function testNormalCombinationOfSurrogates()
+{
+ return "\uD800\uDC00".codePointAt(0) === 65536 && "\uD800\uDC00".codePointAt(1) === 56320 && "\uD800\uDC00".codePointAt(2) === undefined;
+}
+shouldBeTrue("testNormalCombinationOfSurrogates()");
</ins></span></pre></div>
<a id="trunkLayoutTestsjsstringcodepointatexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/js/string-code-point-at-expected.txt (0 => 183141)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/string-code-point-at-expected.txt         (rev 0)
+++ trunk/LayoutTests/js/string-code-point-at-expected.txt        2015-04-22 22:25:27 UTC (rev 183141)
</span><span class="lines">@@ -0,0 +1,78 @@
</span><ins>+Test the basic behaviors of String.codePointAt
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS String.codePointAt is undefined
+PASS typeof String.prototype.codePointAt is "function"
+PASS String.prototype.codePointAt.length is 1
+PASS String.prototype.codePointAt.name is "codePointAt"
+PASS Object.getOwnPropertyDescriptor(String.prototype, "codePointAt").configurable is true
+PASS Object.getOwnPropertyDescriptor(String.prototype, "codePointAt").enumerable is false
+PASS Object.getOwnPropertyDescriptor(String.prototype, "codePointAt").writable is true
+PASS "foo".hasOwnProperty("codePointAt") is false
+PASS (new String("bar")).hasOwnProperty("codePointAt") is false
+PASS "".codePointAt(0) is undefined
+PASS "".codePointAt(1) is undefined
+PASS "Été".codePointAt(0) is 201
+PASS "Été".codePointAt(1) is 116
+PASS "Été".codePointAt(2) is 233
+PASS "Été".codePointAt(3) is undefined
+PASS "ウェブキット".codePointAt(0) is 12454
+PASS "ウェブキット".codePointAt(1) is 12455
+PASS "ウェブキット".codePointAt(2) is 12502
+PASS "ウェブキット".codePointAt(3) is 12461
+PASS "ウェブキット".codePointAt(4) is 12483
+PASS "ウェブキット".codePointAt(5) is 12488
+PASS "ウェブキット".codePointAt(6) is undefined
+PASS "".codePointAt.call(null, 0) threw exception TypeError: Type error.
+PASS "".codePointAt.call(undefined, 0) threw exception TypeError: Type error.
+PASS "".codePointAt.call(0, 0) is 48
+PASS "".codePointAt.call(Math.PI, 0) is 51
+PASS "".codePointAt.call(Math.PI, 1) is 46
+PASS "".codePointAt.call(Math.PI, 3) is 52
+PASS "".codePointAt.call(true, 3) is 101
+PASS "".codePointAt.call(false, 3) is 115
+PASS "".codePointAt.call(new Object, 3) is 106
+PASS "".codePointAt.call(Symbol("WebKit"), 3) threw exception TypeError: Type error.
+PASS "".codePointAt.call(objectWithCustomToString, 0) is 248
+PASS "".codePointAt.call(objectThrowingOnToString, 0) threw exception Hehe.
+PASS "".codePointAt.call(objectCountingToString, 0) is 49
+PASS objectCountingToString.counter is 1
+PASS "abcde".codePointAt(objectWithCustomValueOf) is 98
+PASS "".codePointAt.call(null, objectRecordsValueOf) threw exception TypeError: Type error.
+PASS "".codePointAt.call(undefined, objectRecordsValueOf) threw exception TypeError: Type error.
+PASS "".codePointAt.call(Symbol("WebKit"), objectRecordsValueOf) threw exception TypeError: Type error.
+PASS "".codePointAt.call(objectThrowingOnToString, objectRecordsValueOf) threw exception Hehe.
+PASS objectRecordsValueOf.valueOfEvaluated is false
+PASS "".codePointAt.call(evaluationOrderRecorder, evaluationOrderRecorder) is 114
+PASS evaluationOrderRecorder.methodsCalled.toString() is "toString,valueOf"
+PASS "abc".codePointAt(NaN) is 97
+PASS "abc".codePointAt(-0) is 97
+PASS "abc".codePointAt(-0.0) is 97
+PASS "abc".codePointAt(-0.05) is 97
+PASS "abc".codePointAt(-0.999) is 97
+PASS "abc".codePointAt(0.4) is 97
+PASS "abc".codePointAt(0.9) is 97
+PASS "abc".codePointAt(2.9999) is 99
+PASS "abc".codePointAt(-1) is undefined
+PASS "abc".codePointAt(4) is undefined
+PASS var str = "abc"; str.codePointAt(str.length) is undefined
+PASS "abc".codePointAt(4.1) is undefined
+PASS "abc".codePointAt(Number.POSITIVE_INFINITY) is undefined
+PASS "abc".codePointAt(Number.NEGATIVE_INFINITY) is undefined
+PASS "abc".codePointAt(null) is 97
+PASS "abc".codePointAt(undefined) is 97
+PASS "abc".codePointAt("") is 97
+PASS "abc".codePointAt("WebKit!") is 97
+PASS "abc".codePointAt(new Object) is 97
+PASS "abc".codePointAt(Symbol("WebKit")) threw exception TypeError: Type error.
+PASS testLeadSurrogateOutOfBounds() is true
+PASS testLeadSurrogateAsLastCharacter() is true
+PASS testTrailSurrogateOutOfbounds() is true
+PASS testAccessNullInString() is true
+PASS testNormalCombinationOfSurrogates() is true
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
</ins></span></pre></div>
<a id="trunkLayoutTestsjsstringcodepointathtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/js/string-code-point-at.html (0 => 183141)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/string-code-point-at.html         (rev 0)
+++ trunk/LayoutTests/js/string-code-point-at.html        2015-04-22 22:25:27 UTC (rev 183141)
</span><span class="lines">@@ -0,0 +1,11 @@
</span><ins>+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<meta charset="utf-8">
+<script src="../resources/js-test-pre.js"></script>
+</head>
+<body>
+<script src="script-tests/string-code-point-at.js"></script>
+<script src="../resources/js-test-post.js"></script>
+</body>
+</html>
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (183140 => 183141)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2015-04-22 22:17:49 UTC (rev 183140)
+++ trunk/Source/JavaScriptCore/ChangeLog        2015-04-22 22:25:27 UTC (rev 183141)
</span><span class="lines">@@ -1,3 +1,18 @@
</span><ins>+2015-04-22 Benjamin Poulain <benjamin@webkit.org>
+
+ Implement String.codePointAt()
+ https://bugs.webkit.org/show_bug.cgi?id=143934
+
+ Reviewed by Darin Adler.
+
+ This patch adds String.codePointAt() as defined by ES6.
+ I opted for a C++ implementation for now.
+
+ * runtime/StringPrototype.cpp:
+ (JSC::StringPrototype::finishCreation):
+ (JSC::codePointAt):
+ (JSC::stringProtoFuncCodePointAt):
+
</ins><span class="cx"> 2015-04-22 Mark Lam <mark.lam@apple.com>
</span><span class="cx">
</span><span class="cx"> SparseArrayEntry's write barrier owner should be the SparseArrayValueMap.
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeStringPrototypecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/StringPrototype.cpp (183140 => 183141)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/StringPrototype.cpp        2015-04-22 22:17:49 UTC (rev 183140)
+++ trunk/Source/JavaScriptCore/runtime/StringPrototype.cpp        2015-04-22 22:25:27 UTC (rev 183141)
</span><span class="lines">@@ -56,6 +56,7 @@
</span><span class="cx"> EncodedJSValue JSC_HOST_CALL stringProtoFuncToString(ExecState*);
</span><span class="cx"> EncodedJSValue JSC_HOST_CALL stringProtoFuncCharAt(ExecState*);
</span><span class="cx"> EncodedJSValue JSC_HOST_CALL stringProtoFuncCharCodeAt(ExecState*);
</span><ins>+EncodedJSValue JSC_HOST_CALL stringProtoFuncCodePointAt(ExecState*);
</ins><span class="cx"> EncodedJSValue JSC_HOST_CALL stringProtoFuncConcat(ExecState*);
</span><span class="cx"> EncodedJSValue JSC_HOST_CALL stringProtoFuncIndexOf(ExecState*);
</span><span class="cx"> EncodedJSValue JSC_HOST_CALL stringProtoFuncLastIndexOf(ExecState*);
</span><span class="lines">@@ -108,6 +109,7 @@
</span><span class="cx"> JSC_NATIVE_INTRINSIC_FUNCTION(vm.propertyNames->valueOf, stringProtoFuncToString, DontEnum, 0, StringPrototypeValueOfIntrinsic);
</span><span class="cx"> JSC_NATIVE_INTRINSIC_FUNCTION("charAt", stringProtoFuncCharAt, DontEnum, 1, CharAtIntrinsic);
</span><span class="cx"> JSC_NATIVE_INTRINSIC_FUNCTION("charCodeAt", stringProtoFuncCharCodeAt, DontEnum, 1, CharCodeAtIntrinsic);
</span><ins>+ JSC_NATIVE_FUNCTION("codePointAt", stringProtoFuncCodePointAt, DontEnum, 1);
</ins><span class="cx"> JSC_NATIVE_FUNCTION("concat", stringProtoFuncConcat, DontEnum, 1);
</span><span class="cx"> JSC_NATIVE_FUNCTION("indexOf", stringProtoFuncIndexOf, DontEnum, 1);
</span><span class="cx"> JSC_NATIVE_FUNCTION("lastIndexOf", stringProtoFuncLastIndexOf, DontEnum, 1);
</span><span class="lines">@@ -811,6 +813,42 @@
</span><span class="cx"> return JSValue::encode(jsNaN());
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+static inline UChar32 codePointAt(const String& string, unsigned position, unsigned length)
+{
+ RELEASE_ASSERT(position < length);
+ if (string.is8Bit())
+ return string.characters8()[position];
+ UChar32 character;
+ U16_NEXT(string.characters16(), position, length, character);
+ return character;
+}
+
+EncodedJSValue JSC_HOST_CALL stringProtoFuncCodePointAt(ExecState* exec)
+{
+ JSValue thisValue = exec->thisValue();
+ if (!checkObjectCoercible(thisValue))
+ return throwVMTypeError(exec);
+
+ String string = thisValue.toWTFString(exec);
+ unsigned length = string.length();
+
+ JSValue argument0 = exec->argument(0);
+ if (argument0.isUInt32()) {
+ unsigned position = argument0.asUInt32();
+ if (position < length)
+ return JSValue::encode(jsNumber(codePointAt(string, position, length)));
+ return JSValue::encode(jsUndefined());
+ }
+
+ if (UNLIKELY(exec->hadException()))
+ return JSValue::encode(jsUndefined());
+
+ double doublePosition = argument0.toInteger(exec);
+ if (doublePosition >= 0 && doublePosition < length)
+ return JSValue::encode(jsNumber(codePointAt(string, static_cast<unsigned>(doublePosition), length)));
+ return JSValue::encode(jsUndefined());
+}
+
</ins><span class="cx"> EncodedJSValue JSC_HOST_CALL stringProtoFuncConcat(ExecState* exec)
</span><span class="cx"> {
</span><span class="cx"> JSValue thisValue = exec->thisValue();
</span></span></pre>
</div>
</div>
</body>
</html>