<!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>[211319] 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/211319">211319</a></dd>
<dt>Author</dt> <dd>utatane.tea@gmail.com</dd>
<dt>Date</dt> <dd>2017-01-27 19:09:12 -0800 (Fri, 27 Jan 2017)</dd>
</dl>

<h3>Log Message</h3>
<pre>Lift template escape sequence restrictions in tagged templates
https://bugs.webkit.org/show_bug.cgi?id=166871

Reviewed by Saam Barati.

JSTests:

Update the error messages and add new tests.

* ChakraCore/test/es6/unicode_6_identifier_Blue524737.baseline-jsc:
* stress/lift-template-literal.js: Added.
(dump):
(testTag.return.tag):
(testTag):
* stress/template-literal-syntax.js:

Source/JavaScriptCore:

This patch implements stage 3 Lifting Template Literal Restriction[1].
Prior to this patch, template literal becomes syntax error if it contains
invalid escape sequences. But it is too restricted; Template literal
can have cooked and raw representations and only cooked representation
can escape sequences. So even if invalid escape sequences are included,
the raw representation can be valid.

Lifting Template Literal Restriction relaxes the above restriction.
When invalid escape sequence is included, if target template literals
are used as tagged templates, we make the result of the template including
the invalid escape sequence `undefined` instead of making it SyntaxError
immediately. It allows us to accept the templates including invalid
escape sequences in the raw representations in tagged templates.

On the other hand, the raw representation is only used in tagged templates.
So if invalid escape sequences are included in the usual template literals,
we just make it SyntaxError as before.

[1]: https://github.com/tc39/proposal-template-literal-revision

* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::emitGetTemplateObject):
* bytecompiler/NodesCodegen.cpp:
(JSC::TemplateStringNode::emitBytecode):
(JSC::TemplateLiteralNode::emitBytecode):
* parser/ASTBuilder.h:
(JSC::ASTBuilder::createTemplateString):
* parser/Lexer.cpp:
(JSC::Lexer&lt;CharacterType&gt;::parseUnicodeEscape):
(JSC::Lexer&lt;T&gt;::parseTemplateLiteral):
(JSC::Lexer&lt;T&gt;::lex):
(JSC::Lexer&lt;T&gt;::scanTemplateString):
(JSC::Lexer&lt;T&gt;::scanTrailingTemplateString): Deleted.
* parser/Lexer.h:
* parser/NodeConstructors.h:
(JSC::TemplateStringNode::TemplateStringNode):
* parser/Nodes.h:
(JSC::TemplateStringNode::cooked):
(JSC::TemplateStringNode::raw):
* parser/Parser.cpp:
(JSC::Parser&lt;LexerType&gt;::parseAssignmentElement):
(JSC::Parser&lt;LexerType&gt;::parseTemplateString):
(JSC::Parser&lt;LexerType&gt;::parseTemplateLiteral):
(JSC::Parser&lt;LexerType&gt;::parsePrimaryExpression):
(JSC::Parser&lt;LexerType&gt;::parseMemberExpression):
* parser/ParserTokens.h:
* parser/SyntaxChecker.h:
(JSC::SyntaxChecker::createTemplateString):
* runtime/TemplateRegistry.cpp:
(JSC::TemplateRegistry::getTemplateObject):
* runtime/TemplateRegistryKey.h:
(JSC::TemplateRegistryKey::cookedStrings):
(JSC::TemplateRegistryKey::create):
(JSC::TemplateRegistryKey::TemplateRegistryKey):
* runtime/TemplateRegistryKeyTable.cpp:
(JSC::TemplateRegistryKeyTable::createKey):
* runtime/TemplateRegistryKeyTable.h:

LayoutTests:

Update the error messages.

* inspector/runtime/parse-expected.txt:
* js/unicode-escape-sequences-expected.txt:</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkJSTestsChakraCoretestes6unicode_6_identifier_Blue524737baselinejsc">trunk/JSTests/ChakraCore/test/es6/unicode_6_identifier_Blue524737.baseline-jsc</a></li>
<li><a href="#trunkJSTestsChangeLog">trunk/JSTests/ChangeLog</a></li>
<li><a href="#trunkJSTestsstresstemplateliteralsyntaxjs">trunk/JSTests/stress/template-literal-syntax.js</a></li>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkLayoutTestsinspectorruntimeparseexpectedtxt">trunk/LayoutTests/inspector/runtime/parse-expected.txt</a></li>
<li><a href="#trunkLayoutTestsjsunicodeescapesequencesexpectedtxt">trunk/LayoutTests/js/unicode-escape-sequences-expected.txt</a></li>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecompilerBytecodeGeneratorcpp">trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecompilerNodesCodegencpp">trunk/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreparserASTBuilderh">trunk/Source/JavaScriptCore/parser/ASTBuilder.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreparserLexercpp">trunk/Source/JavaScriptCore/parser/Lexer.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreparserLexerh">trunk/Source/JavaScriptCore/parser/Lexer.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreparserNodeConstructorsh">trunk/Source/JavaScriptCore/parser/NodeConstructors.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreparserNodesh">trunk/Source/JavaScriptCore/parser/Nodes.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreparserParsercpp">trunk/Source/JavaScriptCore/parser/Parser.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreparserParserTokensh">trunk/Source/JavaScriptCore/parser/ParserTokens.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreparserSyntaxCheckerh">trunk/Source/JavaScriptCore/parser/SyntaxChecker.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeTemplateRegistrycpp">trunk/Source/JavaScriptCore/runtime/TemplateRegistry.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeTemplateRegistryKeyh">trunk/Source/JavaScriptCore/runtime/TemplateRegistryKey.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeTemplateRegistryKeyTablecpp">trunk/Source/JavaScriptCore/runtime/TemplateRegistryKeyTable.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeTemplateRegistryKeyTableh">trunk/Source/JavaScriptCore/runtime/TemplateRegistryKeyTable.h</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkJSTestsstresslifttemplateliteraljs">trunk/JSTests/stress/lift-template-literal.js</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkJSTestsChakraCoretestes6unicode_6_identifier_Blue524737baselinejsc"></a>
<div class="modfile"><h4>Modified: trunk/JSTests/ChakraCore/test/es6/unicode_6_identifier_Blue524737.baseline-jsc (211318 => 211319)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/ChakraCore/test/es6/unicode_6_identifier_Blue524737.baseline-jsc        2017-01-28 02:27:56 UTC (rev 211318)
+++ trunk/JSTests/ChakraCore/test/es6/unicode_6_identifier_Blue524737.baseline-jsc        2017-01-28 03:09:12 UTC (rev 211319)
</span><span class="lines">@@ -1,2 +1,2 @@
</span><del>-Exception: SyntaxError: Invalid unicode escape in identifier: '\u{13407'
</del><ins>+Exception: SyntaxError: Invalid unicode escape in identifier: '\u{134071'
</ins><span class="cx"> at unicode_6_identifier_Blue524737.js:6
</span></span></pre></div>
<a id="trunkJSTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/JSTests/ChangeLog (211318 => 211319)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/ChangeLog        2017-01-28 02:27:56 UTC (rev 211318)
+++ trunk/JSTests/ChangeLog        2017-01-28 03:09:12 UTC (rev 211319)
</span><span class="lines">@@ -1,3 +1,19 @@
</span><ins>+2017-01-27  Yusuke Suzuki  &lt;utatane.tea@gmail.com&gt;
+
+        Lift template escape sequence restrictions in tagged templates
+        https://bugs.webkit.org/show_bug.cgi?id=166871
+
+        Reviewed by Saam Barati.
+
+        Update the error messages and add new tests.
+
+        * ChakraCore/test/es6/unicode_6_identifier_Blue524737.baseline-jsc:
+        * stress/lift-template-literal.js: Added.
+        (dump):
+        (testTag.return.tag):
+        (testTag):
+        * stress/template-literal-syntax.js:
+
</ins><span class="cx"> 2017-01-26  Mark Lam  &lt;mark.lam@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Fix missing exception check in genericTypedArrayViewProtoFuncSet().
</span></span></pre></div>
<a id="trunkJSTestsstresslifttemplateliteraljs"></a>
<div class="addfile"><h4>Added: trunk/JSTests/stress/lift-template-literal.js (0 => 211319)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/stress/lift-template-literal.js                                (rev 0)
+++ trunk/JSTests/stress/lift-template-literal.js        2017-01-28 03:09:12 UTC (rev 211319)
</span><span class="lines">@@ -0,0 +1,69 @@
</span><ins>+function dump(callSite)
+{
+    return JSON.stringify({ cooked: callSite, raw: callSite.raw });
+}
+
+function shouldBe(actual, expected)
+{
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+shouldBe(dump`\newcommand{\fun}{\textbf{Fun!}}`, `{&quot;cooked&quot;:[&quot;\\newcommand{\\fun}{\\textbf{Fun!}}&quot;],&quot;raw&quot;:[&quot;\\\\newcommand{\\\\fun}{\\\\textbf{Fun!}}&quot;]}`);
+shouldBe(dump`\newcommand{\unicode}{\textbf{Unicode!}}`, `{&quot;cooked&quot;:[null],&quot;raw&quot;:[&quot;\\\\newcommand{\\\\unicode}{\\\\textbf{Unicode!}}&quot;]}`);
+shouldBe(dump`\newcommand{\xerxes}{\textbf{King!}}`, `{&quot;cooked&quot;:[null],&quot;raw&quot;:[&quot;\\\\newcommand{\\\\xerxes}{\\\\textbf{King!}}&quot;]}`);
+shouldBe(dump`Breve over the h goes \u{h}ere`, `{&quot;cooked&quot;:[null],&quot;raw&quot;:[&quot;Breve over the h goes \\\\u{h}ere&quot;]}`);
+
+function testTag(expected) {
+    return function tag(callSite) {
+        shouldBe(callSite.length, expected.cooked.length);
+        shouldBe(callSite.raw.length, expected.raw.length);
+        expected.cooked.forEach((value, index) =&gt; shouldBe(callSite[index], value));
+        expected.raw.forEach((value, index) =&gt; shouldBe(callSite.raw[index], value));
+    }
+}
+
+testTag({
+    cooked: [ undefined ],
+    raw: [ &quot;\\unicode and \\u{55}&quot; ],
+})`\unicode and \u{55}`;
+
+testTag({
+    cooked: [ undefined, &quot;test&quot; ],
+    raw: [ &quot;\\unicode and \\u{55}&quot;, &quot;test&quot; ],
+})`\unicode and \u{55}${42}test`;
+
+testTag({
+    cooked: [ undefined, undefined, &quot;Cocoa&quot; ],
+    raw: [ &quot;\\unicode and \\u{55}&quot;, &quot;\\uhello&quot;, &quot;Cocoa&quot; ],
+})`\unicode and \u{55}${42}\uhello${42}Cocoa`;
+
+testTag({
+    cooked: [ &quot;Cocoa&quot;, undefined, undefined, &quot;Cocoa&quot; ],
+    raw: [ &quot;Cocoa&quot;, &quot;\\unicode and \\u{55}&quot;, &quot;\\uhello&quot;, &quot;Cocoa&quot; ],
+})`Cocoa${42}\unicode and \u{55}${42}\uhello${42}Cocoa`;
+
+testTag({
+    cooked: [ &quot;Cocoa&quot;, undefined, undefined, &quot;Cocoa&quot; ],
+    raw: [ &quot;Cocoa&quot;, &quot;\\unicode and \\u{55}&quot;, &quot;\\uhello&quot;, &quot;Cocoa&quot; ],
+})`Cocoa${42}\unicode and \u{55}${42}\uhello${42}Cocoa`;
+
+testTag({
+    cooked: [ undefined, undefined, undefined ],
+    raw: [ &quot;\\00&quot;, &quot;\\01&quot;, &quot;\\1&quot; ]
+})`\00${42}\01${42}\1`;
+
+testTag({
+    cooked: [ undefined, undefined ],
+    raw: [ &quot;\\xo&quot;, &quot;\\x0o&quot; ]
+})`\xo${42}\x0o`;
+
+testTag({
+    cooked: [ undefined, undefined, undefined, undefined ],
+    raw: [ &quot;\\uo&quot;, &quot;\\u0o&quot;, &quot;\\u00o&quot;, &quot;\\u000o&quot; ]
+})`\uo${42}\u0o${42}\u00o${42}\u000o`;
+
+testTag({
+    cooked: [ undefined, undefined, undefined ],
+    raw: [ &quot;\\u{o&quot;, &quot;\\u{0o&quot;, &quot;\\u{110000o&quot; ]
+})`\u{o${42}\u{0o${42}\u{110000o`;
</ins></span></pre></div>
<a id="trunkJSTestsstresstemplateliteralsyntaxjs"></a>
<div class="modfile"><h4>Modified: trunk/JSTests/stress/template-literal-syntax.js (211318 => 211319)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/stress/template-literal-syntax.js        2017-01-28 02:27:56 UTC (rev 211318)
+++ trunk/JSTests/stress/template-literal-syntax.js        2017-01-28 03:09:12 UTC (rev 211319)
</span><span class="lines">@@ -46,6 +46,19 @@
</span><span class="cx"> testSyntax(&quot;`\\\n`&quot;);
</span><span class="cx"> testSyntax(&quot;`\\\r\n`&quot;);
</span><span class="cx"> testSyntax(&quot;`\\\r`&quot;);
</span><ins>+testSyntax(&quot;Hello`bad escape sequence: \\unicode`&quot;);
+testSyntax(&quot;Hello`\\00`&quot;);
+testSyntax(&quot;Hello`\\01`&quot;);
+testSyntax(&quot;Hello`\\1`&quot;);
+testSyntax(&quot;Hello`\\xo`&quot;);
+testSyntax(&quot;Hello`\\x0o`&quot;);
+testSyntax(&quot;Hello`\\uo`&quot;);
+testSyntax(&quot;Hello`\\u0o`&quot;);
+testSyntax(&quot;Hello`\\u00o`&quot;);
+testSyntax(&quot;Hello`\\u000o`&quot;);
+testSyntax(&quot;Hello`\\u{o`&quot;);
+testSyntax(&quot;Hello`\\u{0o`&quot;);
+testSyntax(&quot;Hello`\\u{110000o`&quot;);
</ins><span class="cx"> 
</span><span class="cx"> testSyntaxError(&quot;`Hello&quot;, &quot;SyntaxError: Unexpected EOF&quot;);
</span><span class="cx"> testSyntaxError(&quot;`Hello${expr}&quot;, &quot;SyntaxError: Unexpected EOF&quot;);
</span><span class="lines">@@ -81,3 +94,18 @@
</span><span class="cx"> testSyntaxError(&quot;`${expr}\\u20`&quot;, &quot;SyntaxError: \\u can only be followed by a Unicode character sequence&quot;);
</span><span class="cx"> testSyntaxError(&quot;`\\u202`&quot;, &quot;SyntaxError: \\u can only be followed by a Unicode character sequence&quot;);
</span><span class="cx"> testSyntaxError(&quot;`${expr}\\u202`&quot;, &quot;SyntaxError: \\u can only be followed by a Unicode character sequence&quot;);
</span><ins>+
+testSyntaxError(&quot;`bad escape sequence: \\unicode`&quot;, &quot;SyntaxError: \\u can only be followed by a Unicode character sequence&quot;);
+
+testSyntaxError(&quot;`\\00`&quot;, &quot;SyntaxError: The only valid numeric escape in strict mode is '\\0'&quot;);
+testSyntaxError(&quot;`\\01`&quot;, &quot;SyntaxError: The only valid numeric escape in strict mode is '\\0'&quot;);
+testSyntaxError(&quot;`\\1`&quot;, &quot;SyntaxError: The only valid numeric escape in strict mode is '\\0'&quot;);
+testSyntaxError(&quot;`\\xo`&quot;, &quot;SyntaxError: \\x can only be followed by a hex character sequence&quot;);
+testSyntaxError(&quot;`\\x0o`&quot;, &quot;SyntaxError: \\x can only be followed by a hex character sequence&quot;);
+testSyntaxError(&quot;`\\uo`&quot;, &quot;SyntaxError: \\u can only be followed by a Unicode character sequence&quot;);
+testSyntaxError(&quot;`\\u0o`&quot;, &quot;SyntaxError: \\u can only be followed by a Unicode character sequence&quot;);
+testSyntaxError(&quot;`\\u00o`&quot;, &quot;SyntaxError: \\u can only be followed by a Unicode character sequence&quot;);
+testSyntaxError(&quot;`\\u000o`&quot;, &quot;SyntaxError: \\u can only be followed by a Unicode character sequence&quot;);
+testSyntaxError(&quot;`\\u{o`&quot;, &quot;SyntaxError: \\u can only be followed by a Unicode character sequence&quot;);
+testSyntaxError(&quot;`\\u{0o`&quot;, &quot;SyntaxError: \\u can only be followed by a Unicode character sequence&quot;);
+testSyntaxError(&quot;`\\u{110000o`&quot;, &quot;SyntaxError: \\u can only be followed by a Unicode character sequence&quot;);
</ins></span></pre></div>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (211318 => 211319)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog        2017-01-28 02:27:56 UTC (rev 211318)
+++ trunk/LayoutTests/ChangeLog        2017-01-28 03:09:12 UTC (rev 211319)
</span><span class="lines">@@ -1,5 +1,17 @@
</span><span class="cx"> 2017-01-27  Yusuke Suzuki  &lt;utatane.tea@gmail.com&gt;
</span><span class="cx"> 
</span><ins>+        Lift template escape sequence restrictions in tagged templates
+        https://bugs.webkit.org/show_bug.cgi?id=166871
+
+        Reviewed by Saam Barati.
+
+        Update the error messages.
+
+        * inspector/runtime/parse-expected.txt:
+        * js/unicode-escape-sequences-expected.txt:
+
+2017-01-27  Yusuke Suzuki  &lt;utatane.tea@gmail.com&gt;
+
</ins><span class="cx">         setTimeout / setInterval's string execution should inherit SourceOrigin correctly
</span><span class="cx">         https://bugs.webkit.org/show_bug.cgi?id=167097
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkLayoutTestsinspectorruntimeparseexpectedtxt"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/inspector/runtime/parse-expected.txt (211318 => 211319)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/inspector/runtime/parse-expected.txt        2017-01-28 02:27:56 UTC (rev 211318)
+++ trunk/LayoutTests/inspector/runtime/parse-expected.txt        2017-01-28 03:09:12 UTC (rev 211319)
</span><span class="lines">@@ -67,9 +67,9 @@
</span><span class="cx"> 
</span><span class="cx"> PASS: Should be SyntaxErrorType UnterminatedLiteral.
</span><span class="cx"> Source: var \u007
</span><del>-            ^~
-Error Message: Incomplete unicode escape in identifier: '\u'
-Range: {&quot;startOffset&quot;:4,&quot;endOffset&quot;:6}
</del><ins>+            ^~~~~
+Error Message: Incomplete unicode escape in identifier: '\u007'
+Range: {&quot;startOffset&quot;:4,&quot;endOffset&quot;:9}
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> -- Running test case: SyntaxErrorType.Recoverable
</span></span></pre></div>
<a id="trunkLayoutTestsjsunicodeescapesequencesexpectedtxt"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/js/unicode-escape-sequences-expected.txt (211318 => 211319)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/unicode-escape-sequences-expected.txt        2017-01-28 02:27:56 UTC (rev 211318)
+++ trunk/LayoutTests/js/unicode-escape-sequences-expected.txt        2017-01-28 03:09:12 UTC (rev 211319)
</span><span class="lines">@@ -58,9 +58,9 @@
</span><span class="cx"> PASS codeUnits(function \u{}(){}.name) threw exception SyntaxError: Invalid unicode escape in identifier: '\u{'.
</span><span class="cx"> PASS codeUnits(function \u{G}(){}.name) threw exception SyntaxError: Invalid unicode escape in identifier: '\u{'.
</span><span class="cx"> PASS codeUnits(function \u{1G}(){}.name) threw exception SyntaxError: Invalid unicode escape in identifier: '\u{1'.
</span><del>-PASS codeUnits(function \u{110000}(){}.name) threw exception SyntaxError: Invalid unicode escape in identifier: '\u{11000'.
-PASS codeUnits(function \u{1000000}(){}.name) threw exception SyntaxError: Invalid unicode escape in identifier: '\u{100000'.
-PASS codeUnits(function \u{100000000000000000000000}(){}.name) threw exception SyntaxError: Invalid unicode escape in identifier: '\u{100000'.
</del><ins>+PASS codeUnits(function \u{110000}(){}.name) threw exception SyntaxError: Invalid unicode escape in identifier: '\u{110000'.
+PASS codeUnits(function \u{1000000}(){}.name) threw exception SyntaxError: Invalid unicode escape in identifier: '\u{1000000'.
+PASS codeUnits(function \u{100000000000000000000000}(){}.name) threw exception SyntaxError: Invalid unicode escape in identifier: '\u{100000000000000000000000'.
</ins><span class="cx"> PASS codeUnits(function x\u{41}(){}.name.substring(1)) is &quot;0041&quot;
</span><span class="cx"> PASS codeUnits(function x\u{10000}(){}.name.substring(1)) is &quot;D800,DC00&quot;
</span><span class="cx"> PASS codeUnits(function x\u{10001}(){}.name.substring(1)) is &quot;D800,DC01&quot;
</span><span class="lines">@@ -87,9 +87,9 @@
</span><span class="cx"> PASS codeUnits(function x\u{}(){}.name.substring(1)) threw exception SyntaxError: Invalid unicode escape in identifier: 'x\u{'.
</span><span class="cx"> PASS codeUnits(function x\u{G}(){}.name.substring(1)) threw exception SyntaxError: Invalid unicode escape in identifier: 'x\u{'.
</span><span class="cx"> PASS codeUnits(function x\u{1G}(){}.name.substring(1)) threw exception SyntaxError: Invalid unicode escape in identifier: 'x\u{1'.
</span><del>-PASS codeUnits(function x\u{110000}(){}.name.substring(1)) threw exception SyntaxError: Invalid unicode escape in identifier: 'x\u{11000'.
-PASS codeUnits(function x\u{1000000}(){}.name.substring(1)) threw exception SyntaxError: Invalid unicode escape in identifier: 'x\u{100000'.
-PASS codeUnits(function x\u{100000000000000000000000}(){}.name.substring(1)) threw exception SyntaxError: Invalid unicode escape in identifier: 'x\u{100000'.
</del><ins>+PASS codeUnits(function x\u{110000}(){}.name.substring(1)) threw exception SyntaxError: Invalid unicode escape in identifier: 'x\u{110000'.
+PASS codeUnits(function x\u{1000000}(){}.name.substring(1)) threw exception SyntaxError: Invalid unicode escape in identifier: 'x\u{1000000'.
+PASS codeUnits(function x\u{100000000000000000000000}(){}.name.substring(1)) threw exception SyntaxError: Invalid unicode escape in identifier: 'x\u{100000000000000000000000'.
</ins><span class="cx"> PASS successfullyParsed is true
</span><span class="cx"> 
</span><span class="cx"> TEST COMPLETE
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (211318 => 211319)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2017-01-28 02:27:56 UTC (rev 211318)
+++ trunk/Source/JavaScriptCore/ChangeLog        2017-01-28 03:09:12 UTC (rev 211319)
</span><span class="lines">@@ -1,3 +1,68 @@
</span><ins>+2017-01-27  Yusuke Suzuki  &lt;utatane.tea@gmail.com&gt;
+
+        Lift template escape sequence restrictions in tagged templates
+        https://bugs.webkit.org/show_bug.cgi?id=166871
+
+        Reviewed by Saam Barati.
+
+        This patch implements stage 3 Lifting Template Literal Restriction[1].
+        Prior to this patch, template literal becomes syntax error if it contains
+        invalid escape sequences. But it is too restricted; Template literal
+        can have cooked and raw representations and only cooked representation
+        can escape sequences. So even if invalid escape sequences are included,
+        the raw representation can be valid.
+
+        Lifting Template Literal Restriction relaxes the above restriction.
+        When invalid escape sequence is included, if target template literals
+        are used as tagged templates, we make the result of the template including
+        the invalid escape sequence `undefined` instead of making it SyntaxError
+        immediately. It allows us to accept the templates including invalid
+        escape sequences in the raw representations in tagged templates.
+
+        On the other hand, the raw representation is only used in tagged templates.
+        So if invalid escape sequences are included in the usual template literals,
+        we just make it SyntaxError as before.
+
+        [1]: https://github.com/tc39/proposal-template-literal-revision
+
+        * bytecompiler/BytecodeGenerator.cpp:
+        (JSC::BytecodeGenerator::emitGetTemplateObject):
+        * bytecompiler/NodesCodegen.cpp:
+        (JSC::TemplateStringNode::emitBytecode):
+        (JSC::TemplateLiteralNode::emitBytecode):
+        * parser/ASTBuilder.h:
+        (JSC::ASTBuilder::createTemplateString):
+        * parser/Lexer.cpp:
+        (JSC::Lexer&lt;CharacterType&gt;::parseUnicodeEscape):
+        (JSC::Lexer&lt;T&gt;::parseTemplateLiteral):
+        (JSC::Lexer&lt;T&gt;::lex):
+        (JSC::Lexer&lt;T&gt;::scanTemplateString):
+        (JSC::Lexer&lt;T&gt;::scanTrailingTemplateString): Deleted.
+        * parser/Lexer.h:
+        * parser/NodeConstructors.h:
+        (JSC::TemplateStringNode::TemplateStringNode):
+        * parser/Nodes.h:
+        (JSC::TemplateStringNode::cooked):
+        (JSC::TemplateStringNode::raw):
+        * parser/Parser.cpp:
+        (JSC::Parser&lt;LexerType&gt;::parseAssignmentElement):
+        (JSC::Parser&lt;LexerType&gt;::parseTemplateString):
+        (JSC::Parser&lt;LexerType&gt;::parseTemplateLiteral):
+        (JSC::Parser&lt;LexerType&gt;::parsePrimaryExpression):
+        (JSC::Parser&lt;LexerType&gt;::parseMemberExpression):
+        * parser/ParserTokens.h:
+        * parser/SyntaxChecker.h:
+        (JSC::SyntaxChecker::createTemplateString):
+        * runtime/TemplateRegistry.cpp:
+        (JSC::TemplateRegistry::getTemplateObject):
+        * runtime/TemplateRegistryKey.h:
+        (JSC::TemplateRegistryKey::cookedStrings):
+        (JSC::TemplateRegistryKey::create):
+        (JSC::TemplateRegistryKey::TemplateRegistryKey):
+        * runtime/TemplateRegistryKeyTable.cpp:
+        (JSC::TemplateRegistryKeyTable::createKey):
+        * runtime/TemplateRegistryKeyTable.h:
+
</ins><span class="cx"> 2017-01-27  Saam Barati  &lt;sbarati@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Make the CLI for the sampling profiler better for inlined call site indices
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecompilerBytecodeGeneratorcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp (211318 => 211319)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp        2017-01-28 02:27:56 UTC (rev 211318)
+++ trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp        2017-01-28 03:09:12 UTC (rev 211319)
</span><span class="lines">@@ -4253,17 +4253,22 @@
</span><span class="cx"> RegisterID* BytecodeGenerator::emitGetTemplateObject(RegisterID* dst, TaggedTemplateNode* taggedTemplate)
</span><span class="cx"> {
</span><span class="cx">     TemplateRegistryKey::StringVector rawStrings;
</span><del>-    TemplateRegistryKey::StringVector cookedStrings;
</del><ins>+    TemplateRegistryKey::OptionalStringVector cookedStrings;
</ins><span class="cx"> 
</span><span class="cx">     TemplateStringListNode* templateString = taggedTemplate-&gt;templateLiteral()-&gt;templateStrings();
</span><span class="cx">     for (; templateString; templateString = templateString-&gt;next()) {
</span><del>-        rawStrings.append(templateString-&gt;value()-&gt;raw().impl());
-        cookedStrings.append(templateString-&gt;value()-&gt;cooked().impl());
</del><ins>+        auto* string = templateString-&gt;value();
+        ASSERT(string-&gt;raw());
+        rawStrings.append(string-&gt;raw()-&gt;impl());
+        if (!string-&gt;cooked())
+            cookedStrings.append(std::nullopt);
+        else
+            cookedStrings.append(string-&gt;cooked()-&gt;impl());
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     RefPtr&lt;RegisterID&gt; getTemplateObject = emitGetGlobalPrivate(newTemporary(), propertyNames().builtinNames().getTemplateObjectPrivateName());
</span><span class="cx">     CallArguments arguments(*this, nullptr);
</span><del>-    emitLoad(arguments.thisRegister(), JSValue(addTemplateRegistryKeyConstant(m_vm-&gt;templateRegistryKeyTable().createKey(rawStrings, cookedStrings))));
</del><ins>+    emitLoad(arguments.thisRegister(), JSValue(addTemplateRegistryKeyConstant(m_vm-&gt;templateRegistryKeyTable().createKey(WTFMove(rawStrings), WTFMove(cookedStrings)))));
</ins><span class="cx">     return emitCall(dst, getTemplateObject.get(), NoExpectedFunction, arguments, taggedTemplate-&gt;divot(), taggedTemplate-&gt;divotStart(), taggedTemplate-&gt;divotEnd(), DebuggableCall::No);
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecompilerNodesCodegencpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp (211318 => 211319)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp        2017-01-28 02:27:56 UTC (rev 211318)
+++ trunk/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp        2017-01-28 03:09:12 UTC (rev 211319)
</span><span class="lines">@@ -246,7 +246,8 @@
</span><span class="cx"> {
</span><span class="cx">     if (dst == generator.ignoredResult())
</span><span class="cx">         return nullptr;
</span><del>-    return generator.emitLoad(dst, JSValue(generator.addStringConstant(cooked())));
</del><ins>+    ASSERT(cooked());
+    return generator.emitLoad(dst, JSValue(generator.addStringConstant(*cooked())));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> // ------------------------------ TemplateLiteralNode -----------------------------------
</span><span class="lines">@@ -265,7 +266,8 @@
</span><span class="cx">     TemplateExpressionListNode* templateExpression = m_templateExpressions;
</span><span class="cx">     for (; templateExpression; templateExpression = templateExpression-&gt;next(), templateString = templateString-&gt;next()) {
</span><span class="cx">         // Evaluate TemplateString.
</span><del>-        if (!templateString-&gt;value()-&gt;cooked().isEmpty()) {
</del><ins>+        ASSERT(templateString-&gt;value()-&gt;cooked());
+        if (!templateString-&gt;value()-&gt;cooked()-&gt;isEmpty()) {
</ins><span class="cx">             temporaryRegisters.append(generator.newTemporary());
</span><span class="cx">             generator.emitNode(temporaryRegisters.last().get(), templateString-&gt;value());
</span><span class="cx">         }
</span><span class="lines">@@ -277,7 +279,8 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     // Evaluate tail TemplateString.
</span><del>-    if (!templateString-&gt;value()-&gt;cooked().isEmpty()) {
</del><ins>+    ASSERT(templateString-&gt;value()-&gt;cooked());
+    if (!templateString-&gt;value()-&gt;cooked()-&gt;isEmpty()) {
</ins><span class="cx">         temporaryRegisters.append(generator.newTemporary());
</span><span class="cx">         generator.emitNode(temporaryRegisters.last().get(), templateString-&gt;value());
</span><span class="cx">     }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreparserASTBuilderh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/parser/ASTBuilder.h (211318 => 211319)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/parser/ASTBuilder.h        2017-01-28 02:27:56 UTC (rev 211318)
+++ trunk/Source/JavaScriptCore/parser/ASTBuilder.h        2017-01-28 03:09:12 UTC (rev 211319)
</span><span class="lines">@@ -275,7 +275,7 @@
</span><span class="cx">         return node;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    TemplateStringNode* createTemplateString(const JSTokenLocation&amp; location, const Identifier&amp; cooked, const Identifier&amp; raw)
</del><ins>+    TemplateStringNode* createTemplateString(const JSTokenLocation&amp; location, const Identifier* cooked, const Identifier* raw)
</ins><span class="cx">     {
</span><span class="cx">         return new (m_parserArena) TemplateStringNode(location, cooked, raw);
</span><span class="cx">     }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreparserLexercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/parser/Lexer.cpp (211318 => 211319)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/parser/Lexer.cpp        2017-01-28 02:27:56 UTC (rev 211318)
+++ trunk/Source/JavaScriptCore/parser/Lexer.cpp        2017-01-28 03:09:12 UTC (rev 211319)
</span><span class="lines">@@ -633,7 +633,8 @@
</span><span class="cx">     UChar32 m_value;
</span><span class="cx"> };
</span><span class="cx"> 
</span><del>-template&lt;typename CharacterType&gt; ParsedUnicodeEscapeValue Lexer&lt;CharacterType&gt;::parseUnicodeEscape()
</del><ins>+template&lt;typename CharacterType&gt;
+ParsedUnicodeEscapeValue Lexer&lt;CharacterType&gt;::parseUnicodeEscape()
</ins><span class="cx"> {
</span><span class="cx">     if (m_current == '{') {
</span><span class="cx">         shift();
</span><span class="lines">@@ -642,8 +643,26 @@
</span><span class="cx">             if (!isASCIIHexDigit(m_current))
</span><span class="cx">                 return m_current ? ParsedUnicodeEscapeValue::Invalid : ParsedUnicodeEscapeValue::Incomplete;
</span><span class="cx">             codePoint = (codePoint &lt;&lt; 4) | toASCIIHexValue(m_current);
</span><del>-            if (codePoint &gt; UCHAR_MAX_VALUE)
-                return ParsedUnicodeEscapeValue::Invalid;
</del><ins>+            if (codePoint &gt; UCHAR_MAX_VALUE) {
+                // For raw template literal syntax, we consume `NotEscapeSequence`.
+                // Here, we consume NotCodePoint's HexDigits.
+                //
+                // NotEscapeSequence ::
+                //     u { [lookahread not one of HexDigit]
+                //     u { NotCodePoint
+                //     u { CodePoint [lookahead != }]
+                //
+                // NotCodePoint ::
+                //     HexDigits but not if MV of HexDigits &lt;= 0x10FFFF
+                //
+                // CodePoint ::
+                //     HexDigits but not if MV of HexDigits &gt; 0x10FFFF
+                shift();
+                while (isASCIIHexDigit(m_current))
+                    shift();
+
+                return atEnd() ? ParsedUnicodeEscapeValue::Incomplete : ParsedUnicodeEscapeValue::Invalid;
+            }
</ins><span class="cx">             shift();
</span><span class="cx">         } while (m_current != '}');
</span><span class="cx">         shift();
</span><span class="lines">@@ -653,8 +672,22 @@
</span><span class="cx">     auto character2 = peek(1);
</span><span class="cx">     auto character3 = peek(2);
</span><span class="cx">     auto character4 = peek(3);
</span><del>-    if (UNLIKELY(!isASCIIHexDigit(m_current) || !isASCIIHexDigit(character2) || !isASCIIHexDigit(character3) || !isASCIIHexDigit(character4)))
-        return (m_code + 4) &gt;= m_codeEnd ? ParsedUnicodeEscapeValue::Incomplete : ParsedUnicodeEscapeValue::Invalid;
</del><ins>+    if (UNLIKELY(!isASCIIHexDigit(m_current) || !isASCIIHexDigit(character2) || !isASCIIHexDigit(character3) || !isASCIIHexDigit(character4))) {
+        auto result = (m_code + 4) &gt;= m_codeEnd ? ParsedUnicodeEscapeValue::Incomplete : ParsedUnicodeEscapeValue::Invalid;
+
+        // For raw template literal syntax, we consume `NotEscapeSequence`.
+        //
+        // NotEscapeSequence ::
+        //     u [lookahead not one of HexDigit][lookahead != {]
+        //     u HexDigit [lookahead not one of HexDigit]
+        //     u HexDigit HexDigit [lookahead not one of HexDigit]
+        //     u HexDigit HexDigit HexDigit [lookahead not one of HexDigit]
+        while (isASCIIHexDigit(m_current))
+            shift();
+
+        return result;
+    }
+
</ins><span class="cx">     auto result = convertUnicode(m_current, character2, character3, character4);
</span><span class="cx">     shift();
</span><span class="cx">     shift();
</span><span class="lines">@@ -1181,19 +1214,30 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> template &lt;typename T&gt;
</span><del>-template &lt;bool shouldBuildStrings&gt; ALWAYS_INLINE auto Lexer&lt;T&gt;::parseComplexEscape(EscapeParseMode escapeParseMode, bool strictMode, T stringQuoteCharacter) -&gt; StringParseResult
</del><ins>+template &lt;bool shouldBuildStrings, LexerEscapeParseMode escapeParseMode&gt; ALWAYS_INLINE auto Lexer&lt;T&gt;::parseComplexEscape(bool strictMode, T stringQuoteCharacter) -&gt; StringParseResult
</ins><span class="cx"> {
</span><span class="cx">     if (m_current == 'x') {
</span><span class="cx">         shift();
</span><span class="cx">         if (!isASCIIHexDigit(m_current) || !isASCIIHexDigit(peek(1))) {
</span><ins>+            // For raw template literal syntax, we consume `NotEscapeSequence`.
+            //
+            // NotEscapeSequence ::
+            //     x [lookahread not one of HexDigit]
+            //     x HexDigit [lookahread not one of HexDigit]
+            if (isASCIIHexDigit(m_current))
+                shift();
+            ASSERT(!isASCIIHexDigit(m_current));
+
</ins><span class="cx">             m_lexErrorMessage = ASCIILiteral(&quot;\\x can only be followed by a hex character sequence&quot;);
</span><del>-            return StringCannotBeParsed;
</del><ins>+            return atEnd() ? StringUnterminated : StringCannotBeParsed;
</ins><span class="cx">         }
</span><ins>+
</ins><span class="cx">         T prev = m_current;
</span><span class="cx">         shift();
</span><span class="cx">         if (shouldBuildStrings)
</span><span class="cx">             record16(convertHex(prev, m_current));
</span><span class="cx">         shift();
</span><ins>+
</ins><span class="cx">         return StringParsedSuccessfully;
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -1200,7 +1244,7 @@
</span><span class="cx">     if (m_current == 'u') {
</span><span class="cx">         shift();
</span><span class="cx"> 
</span><del>-        if (escapeParseMode == EscapeParseMode::String &amp;&amp; m_current == stringQuoteCharacter) {
</del><ins>+        if (escapeParseMode == LexerEscapeParseMode::String &amp;&amp; m_current == stringQuoteCharacter) {
</ins><span class="cx">             if (shouldBuildStrings)
</span><span class="cx">                 record16('u');
</span><span class="cx">             return StringParsedSuccessfully;
</span><span class="lines">@@ -1214,7 +1258,7 @@
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         m_lexErrorMessage = ASCIILiteral(&quot;\\u can only be followed by a Unicode character sequence&quot;);
</span><del>-        return character.isIncomplete() ? StringUnterminated : StringCannotBeParsed;
</del><ins>+        return atEnd() ? StringUnterminated : StringCannotBeParsed;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     if (strictMode) {
</span><span class="lines">@@ -1223,8 +1267,16 @@
</span><span class="cx">             int character1 = m_current;
</span><span class="cx">             shift();
</span><span class="cx">             if (character1 != '0' || isASCIIDigit(m_current)) {
</span><ins>+                // For raw template literal syntax, we consume `NotEscapeSequence`.
+                //
+                // NotEscapeSequence ::
+                //     0 DecimalDigit
+                //     DecimalDigit but not 0
+                if (character1 == '0')
+                    shift();
+
</ins><span class="cx">                 m_lexErrorMessage = ASCIILiteral(&quot;The only valid numeric escape in strict mode is '\\0'&quot;);
</span><del>-                return StringCannotBeParsed;
</del><ins>+                return atEnd() ? StringUnterminated : StringCannotBeParsed;
</ins><span class="cx">             }
</span><span class="cx">             if (shouldBuildStrings)
</span><span class="cx">                 record16(0);
</span><span class="lines">@@ -1290,7 +1342,7 @@
</span><span class="cx">             } else if (UNLIKELY(isLineTerminator(m_current)))
</span><span class="cx">                 shiftLineTerminator();
</span><span class="cx">             else {
</span><del>-                StringParseResult result = parseComplexEscape&lt;shouldBuildStrings&gt;(EscapeParseMode::String, strictMode, stringQuoteCharacter);
</del><ins>+                StringParseResult result = parseComplexEscape&lt;shouldBuildStrings, LexerEscapeParseMode::String&gt;(strictMode, stringQuoteCharacter);
</ins><span class="cx">                 if (result != StringParsedSuccessfully)
</span><span class="cx">                     return result;
</span><span class="cx">             }
</span><span class="lines">@@ -1372,8 +1424,9 @@
</span><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> template &lt;typename T&gt;
</span><del>-template &lt;bool shouldBuildStrings&gt; typename Lexer&lt;T&gt;::StringParseResult Lexer&lt;T&gt;::parseTemplateLiteral(JSTokenData* tokenData, RawStringsBuildMode rawStringsBuildMode)
</del><ins>+typename Lexer&lt;T&gt;::StringParseResult Lexer&lt;T&gt;::parseTemplateLiteral(JSTokenData* tokenData, RawStringsBuildMode rawStringsBuildMode)
</ins><span class="cx"> {
</span><ins>+    bool parseCookedFailed = false;
</ins><span class="cx">     const T* stringStart = currentSourcePtr();
</span><span class="cx">     const T* rawStringStart = currentSourcePtr();
</span><span class="cx"> 
</span><span class="lines">@@ -1382,7 +1435,7 @@
</span><span class="cx">     while (m_current != '`') {
</span><span class="cx">         if (UNLIKELY(m_current == '\\')) {
</span><span class="cx">             lineNumberAdder.clear();
</span><del>-            if (stringStart != currentSourcePtr() &amp;&amp; shouldBuildStrings)
</del><ins>+            if (stringStart != currentSourcePtr())
</ins><span class="cx">                 append16(stringStart, currentSourcePtr() - stringStart);
</span><span class="cx">             shift();
</span><span class="cx"> 
</span><span class="lines">@@ -1390,19 +1443,16 @@
</span><span class="cx"> 
</span><span class="cx">             // Most common escape sequences first.
</span><span class="cx">             if (escape) {
</span><del>-                if (shouldBuildStrings)
-                    record16(escape);
</del><ins>+                record16(escape);
</ins><span class="cx">                 shift();
</span><span class="cx">             } else if (UNLIKELY(isLineTerminator(m_current))) {
</span><span class="cx">                 // Normalize &lt;CR&gt;, &lt;CR&gt;&lt;LF&gt; to &lt;LF&gt;.
</span><span class="cx">                 if (m_current == '\r') {
</span><del>-                    if (shouldBuildStrings) {
-                        ASSERT_WITH_MESSAGE(rawStringStart != currentSourcePtr(), &quot;We should have at least shifted the escape.&quot;);
</del><ins>+                    ASSERT_WITH_MESSAGE(rawStringStart != currentSourcePtr(), &quot;We should have at least shifted the escape.&quot;);
</ins><span class="cx"> 
</span><del>-                        if (rawStringsBuildMode == RawStringsBuildMode::BuildRawStrings) {
-                            m_bufferForRawTemplateString16.append(rawStringStart, currentSourcePtr() - rawStringStart);
-                            m_bufferForRawTemplateString16.append('\n');
-                        }
</del><ins>+                    if (rawStringsBuildMode == RawStringsBuildMode::BuildRawStrings) {
+                        m_bufferForRawTemplateString16.append(rawStringStart, currentSourcePtr() - rawStringStart);
+                        m_bufferForRawTemplateString16.append('\n');
</ins><span class="cx">                     }
</span><span class="cx"> 
</span><span class="cx">                     lineNumberAdder.add(m_current);
</span><span class="lines">@@ -1419,9 +1469,13 @@
</span><span class="cx">                 }
</span><span class="cx">             } else {
</span><span class="cx">                 bool strictMode = true;
</span><del>-                StringParseResult result = parseComplexEscape&lt;shouldBuildStrings&gt;(EscapeParseMode::Template, strictMode, '`');
-                if (result != StringParsedSuccessfully)
-                    return result;
</del><ins>+                StringParseResult result = parseComplexEscape&lt;true, LexerEscapeParseMode::Template&gt;(strictMode, '`');
+                if (result != StringParsedSuccessfully) {
+                    if (rawStringsBuildMode == RawStringsBuildMode::BuildRawStrings &amp;&amp; result == StringCannotBeParsed)
+                        parseCookedFailed = true;
+                    else
+                        return result;
+                }
</ins><span class="cx">             }
</span><span class="cx"> 
</span><span class="cx">             stringStart = currentSourcePtr();
</span><span class="lines">@@ -1445,16 +1499,14 @@
</span><span class="cx">             if (isLineTerminator(m_current)) {
</span><span class="cx">                 if (m_current == '\r') {
</span><span class="cx">                     // Normalize &lt;CR&gt;, &lt;CR&gt;&lt;LF&gt; to &lt;LF&gt;.
</span><del>-                    if (shouldBuildStrings) {
-                        if (stringStart != currentSourcePtr())
-                            append16(stringStart, currentSourcePtr() - stringStart);
-                        if (rawStringStart != currentSourcePtr() &amp;&amp; rawStringsBuildMode == RawStringsBuildMode::BuildRawStrings)
-                            m_bufferForRawTemplateString16.append(rawStringStart, currentSourcePtr() - rawStringStart);
</del><ins>+                    if (stringStart != currentSourcePtr())
+                        append16(stringStart, currentSourcePtr() - stringStart);
+                    if (rawStringStart != currentSourcePtr() &amp;&amp; rawStringsBuildMode == RawStringsBuildMode::BuildRawStrings)
+                        m_bufferForRawTemplateString16.append(rawStringStart, currentSourcePtr() - rawStringStart);
</ins><span class="cx"> 
</span><del>-                        record16('\n');
-                        if (rawStringsBuildMode == RawStringsBuildMode::BuildRawStrings)
-                            m_bufferForRawTemplateString16.append('\n');
-                    }
</del><ins>+                    record16('\n');
+                    if (rawStringsBuildMode == RawStringsBuildMode::BuildRawStrings)
+                        m_bufferForRawTemplateString16.append('\n');
</ins><span class="cx">                     lineNumberAdder.add(m_current);
</span><span class="cx">                     shift();
</span><span class="cx">                     if (m_current == '\n') {
</span><span class="lines">@@ -1478,24 +1530,22 @@
</span><span class="cx"> 
</span><span class="cx">     bool isTail = m_current == '`';
</span><span class="cx"> 
</span><del>-    if (shouldBuildStrings) {
-        if (currentSourcePtr() != stringStart)
-            append16(stringStart, currentSourcePtr() - stringStart);
-        if (rawStringStart != currentSourcePtr() &amp;&amp; rawStringsBuildMode == RawStringsBuildMode::BuildRawStrings)
-            m_bufferForRawTemplateString16.append(rawStringStart, currentSourcePtr() - rawStringStart);
-    }
</del><ins>+    if (currentSourcePtr() != stringStart)
+        append16(stringStart, currentSourcePtr() - stringStart);
+    if (rawStringStart != currentSourcePtr() &amp;&amp; rawStringsBuildMode == RawStringsBuildMode::BuildRawStrings)
+        m_bufferForRawTemplateString16.append(rawStringStart, currentSourcePtr() - rawStringStart);
</ins><span class="cx"> 
</span><del>-    if (shouldBuildStrings) {
</del><ins>+    if (!parseCookedFailed)
</ins><span class="cx">         tokenData-&gt;cooked = makeIdentifier(m_buffer16.data(), m_buffer16.size());
</span><del>-        // Line terminator normalization (e.g. &lt;CR&gt; =&gt; &lt;LF&gt;) should be applied to both the raw and cooked representations.
-        if (rawStringsBuildMode == RawStringsBuildMode::BuildRawStrings)
-            tokenData-&gt;raw = makeIdentifier(m_bufferForRawTemplateString16.data(), m_bufferForRawTemplateString16.size());
-        else
-            tokenData-&gt;raw = makeEmptyIdentifier();
-    } else {
-        tokenData-&gt;cooked = makeEmptyIdentifier();
-        tokenData-&gt;raw = makeEmptyIdentifier();
-    }
</del><ins>+    else
+        tokenData-&gt;cooked = nullptr;
+
+    // Line terminator normalization (e.g. &lt;CR&gt; =&gt; &lt;LF&gt;) should be applied to both the raw and cooked representations.
+    if (rawStringsBuildMode == RawStringsBuildMode::BuildRawStrings)
+        tokenData-&gt;raw = makeIdentifier(m_bufferForRawTemplateString16.data(), m_bufferForRawTemplateString16.size());
+    else
+        tokenData-&gt;raw = nullptr;
+
</ins><span class="cx">     tokenData-&gt;isTail = isTail;
</span><span class="cx"> 
</span><span class="cx">     m_buffer16.shrink(0);
</span><span class="lines">@@ -2082,6 +2132,10 @@
</span><span class="cx">         shift();
</span><span class="cx">         token = SEMICOLON;
</span><span class="cx">         break;
</span><ins>+    case CharacterBackQuote:
+        shift();
+        token = BACKQUOTE;
+        break;
</ins><span class="cx">     case CharacterOpenBrace:
</span><span class="cx">         tokenData-&gt;line = lineNumber();
</span><span class="cx">         tokenData-&gt;offset = currentOffset();
</span><span class="lines">@@ -2234,22 +2288,6 @@
</span><span class="cx">         token = STRING;
</span><span class="cx">         break;
</span><span class="cx">         }
</span><del>-    case CharacterBackQuote: {
-        // Skip backquote.
-        shift();
-        StringParseResult result = StringCannotBeParsed;
-        if (lexerFlags &amp; LexerFlagsDontBuildStrings)
-            result = parseTemplateLiteral&lt;false&gt;(tokenData, RawStringsBuildMode::BuildRawStrings);
-        else
-            result = parseTemplateLiteral&lt;true&gt;(tokenData, RawStringsBuildMode::BuildRawStrings);
-
-        if (UNLIKELY(result != StringParsedSuccessfully)) {
-            token = result == StringUnterminated ? UNTERMINATED_TEMPLATE_LITERAL_ERRORTOK : INVALID_TEMPLATE_LITERAL_ERRORTOK;
-            goto returnError;
-        }
-        token = TEMPLATE;
-        break;
-        }
</del><span class="cx">     case CharacterIdentifierStart:
</span><span class="cx">         ASSERT(isIdentStart(m_current));
</span><span class="cx">         FALLTHROUGH;
</span><span class="lines">@@ -2420,15 +2458,15 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> template &lt;typename T&gt;
</span><del>-JSTokenType Lexer&lt;T&gt;::scanTrailingTemplateString(JSToken* tokenRecord, RawStringsBuildMode rawStringsBuildMode)
</del><ins>+JSTokenType Lexer&lt;T&gt;::scanTemplateString(JSToken* tokenRecord, RawStringsBuildMode rawStringsBuildMode)
</ins><span class="cx"> {
</span><span class="cx">     JSTokenData* tokenData = &amp;tokenRecord-&gt;m_data;
</span><span class="cx">     ASSERT(!m_error);
</span><span class="cx">     ASSERT(m_buffer16.isEmpty());
</span><span class="cx"> 
</span><del>-    // Leading closing brace } is already shifted in the previous token scan.
</del><ins>+    // Leading backquote ` (for template head) or closing brace } (for template trailing) are already shifted in the previous token scan.
</ins><span class="cx">     // So in this re-scan phase, shift() is not needed here.
</span><del>-    StringParseResult result = parseTemplateLiteral&lt;true&gt;(tokenData, rawStringsBuildMode);
</del><ins>+    StringParseResult result = parseTemplateLiteral(tokenData, rawStringsBuildMode);
</ins><span class="cx">     JSTokenType token = ERRORTOK;
</span><span class="cx">     if (UNLIKELY(result != StringParsedSuccessfully)) {
</span><span class="cx">         token = result == StringUnterminated ? UNTERMINATED_TEMPLATE_LITERAL_ERRORTOK : INVALID_TEMPLATE_LITERAL_ERRORTOK;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreparserLexerh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/parser/Lexer.h (211318 => 211319)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/parser/Lexer.h        2017-01-28 02:27:56 UTC (rev 211318)
+++ trunk/Source/JavaScriptCore/parser/Lexer.h        2017-01-28 03:09:12 UTC (rev 211319)
</span><span class="lines">@@ -37,6 +37,8 @@
</span><span class="cx">     LexexFlagsDontBuildKeywords = 4
</span><span class="cx"> };
</span><span class="cx"> 
</span><ins>+enum class LexerEscapeParseMode { Template, String };
+
</ins><span class="cx"> struct ParsedUnicodeEscapeValue;
</span><span class="cx"> 
</span><span class="cx"> bool isLexerKeyword(const Identifier&amp;);
</span><span class="lines">@@ -77,7 +79,7 @@
</span><span class="cx">     bool prevTerminator() const { return m_terminator; }
</span><span class="cx">     JSTokenType scanRegExp(JSToken*, UChar patternPrefix = 0);
</span><span class="cx">     enum class RawStringsBuildMode { BuildRawStrings, DontBuildRawStrings };
</span><del>-    JSTokenType scanTrailingTemplateString(JSToken*, RawStringsBuildMode);
</del><ins>+    JSTokenType scanTemplateString(JSToken*, RawStringsBuildMode);
</ins><span class="cx"> 
</span><span class="cx">     // Functions for use after parsing.
</span><span class="cx">     bool sawError() const { return m_error; }
</span><span class="lines">@@ -170,9 +172,8 @@
</span><span class="cx">     template &lt;bool shouldBuildStrings&gt; ALWAYS_INLINE StringParseResult parseString(JSTokenData*, bool strictMode);
</span><span class="cx">     template &lt;bool shouldBuildStrings&gt; NEVER_INLINE StringParseResult parseStringSlowCase(JSTokenData*, bool strictMode);
</span><span class="cx"> 
</span><del>-    enum class EscapeParseMode { Template, String };
-    template &lt;bool shouldBuildStrings&gt; ALWAYS_INLINE StringParseResult parseComplexEscape(EscapeParseMode, bool strictMode, T stringQuoteCharacter);
-    template &lt;bool shouldBuildStrings&gt; ALWAYS_INLINE StringParseResult parseTemplateLiteral(JSTokenData*, RawStringsBuildMode);
</del><ins>+    template &lt;bool shouldBuildStrings, LexerEscapeParseMode escapeParseMode&gt; ALWAYS_INLINE StringParseResult parseComplexEscape(bool strictMode, T stringQuoteCharacter);
+    ALWAYS_INLINE StringParseResult parseTemplateLiteral(JSTokenData*, RawStringsBuildMode);
</ins><span class="cx">     ALWAYS_INLINE void parseHex(double&amp; returnValue);
</span><span class="cx">     ALWAYS_INLINE bool parseBinary(double&amp; returnValue);
</span><span class="cx">     ALWAYS_INLINE bool parseOctal(double&amp; returnValue);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreparserNodeConstructorsh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/parser/NodeConstructors.h (211318 => 211319)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/parser/NodeConstructors.h        2017-01-28 02:27:56 UTC (rev 211318)
+++ trunk/Source/JavaScriptCore/parser/NodeConstructors.h        2017-01-28 03:09:12 UTC (rev 211319)
</span><span class="lines">@@ -111,7 +111,7 @@
</span><span class="cx">         previous-&gt;m_next = this;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    inline TemplateStringNode::TemplateStringNode(const JSTokenLocation&amp; location, const Identifier&amp; cooked, const Identifier&amp; raw)
</del><ins>+    inline TemplateStringNode::TemplateStringNode(const JSTokenLocation&amp; location, const Identifier* cooked, const Identifier* raw)
</ins><span class="cx">         : ExpressionNode(location)
</span><span class="cx">         , m_cooked(cooked)
</span><span class="cx">         , m_raw(raw)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreparserNodesh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/parser/Nodes.h (211318 => 211319)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/parser/Nodes.h        2017-01-28 02:27:56 UTC (rev 211318)
+++ trunk/Source/JavaScriptCore/parser/Nodes.h        2017-01-28 03:09:12 UTC (rev 211319)
</span><span class="lines">@@ -490,16 +490,16 @@
</span><span class="cx"> 
</span><span class="cx">     class TemplateStringNode : public ExpressionNode {
</span><span class="cx">     public:
</span><del>-        TemplateStringNode(const JSTokenLocation&amp;, const Identifier&amp; cooked, const Identifier&amp; raw);
</del><ins>+        TemplateStringNode(const JSTokenLocation&amp;, const Identifier* cooked, const Identifier* raw);
</ins><span class="cx"> 
</span><del>-        const Identifier&amp; cooked() { return m_cooked; }
-        const Identifier&amp; raw() { return m_raw; }
</del><ins>+        const Identifier* cooked() { return m_cooked; }
+        const Identifier* raw() { return m_raw; }
</ins><span class="cx"> 
</span><span class="cx">     private:
</span><span class="cx">         RegisterID* emitBytecode(BytecodeGenerator&amp;, RegisterID* = 0) override;
</span><span class="cx"> 
</span><del>-        const Identifier&amp; m_cooked;
-        const Identifier&amp; m_raw;
</del><ins>+        const Identifier* m_cooked;
+        const Identifier* m_raw;
</ins><span class="cx">     };
</span><span class="cx"> 
</span><span class="cx">     class TemplateStringListNode : public ParserArenaFreeable {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreparserParsercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/parser/Parser.cpp (211318 => 211319)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/parser/Parser.cpp        2017-01-28 02:27:56 UTC (rev 211318)
+++ trunk/Source/JavaScriptCore/parser/Parser.cpp        2017-01-28 03:09:12 UTC (rev 211319)
</span><span class="lines">@@ -904,7 +904,7 @@
</span><span class="cx">     if (match(OPENBRACE) || match(OPENBRACKET)) {
</span><span class="cx">         SavePoint savePoint = createSavePoint();
</span><span class="cx">         assignmentTarget = parseDestructuringPattern(context, kind, exportType, duplicateIdentifier, hasDestructuringPattern, bindingContext, depth);
</span><del>-        if (assignmentTarget &amp;&amp; !match(DOT) &amp;&amp; !match(OPENBRACKET) &amp;&amp; !match(OPENPAREN) &amp;&amp; !match(TEMPLATE))
</del><ins>+        if (assignmentTarget &amp;&amp; !match(DOT) &amp;&amp; !match(OPENBRACKET) &amp;&amp; !match(OPENPAREN) &amp;&amp; !match(BACKQUOTE))
</ins><span class="cx">             return assignmentTarget;
</span><span class="cx">         restoreSavePoint(savePoint);
</span><span class="cx">     }
</span><span class="lines">@@ -4089,11 +4089,13 @@
</span><span class="cx"> template &lt;typename LexerType&gt;
</span><span class="cx"> template &lt;class TreeBuilder&gt; typename TreeBuilder::TemplateString Parser&lt;LexerType&gt;::parseTemplateString(TreeBuilder&amp; context, bool isTemplateHead, typename LexerType::RawStringsBuildMode rawStringsBuildMode, bool&amp; elementIsTail)
</span><span class="cx"> {
</span><del>-    if (!isTemplateHead) {
</del><ins>+    if (isTemplateHead)
+        ASSERT(match(BACKQUOTE));
+    else
</ins><span class="cx">         matchOrFail(CLOSEBRACE, &quot;Expected a closing '}' following an expression in template literal&quot;);
</span><del>-        // Re-scan the token to recognize it as Template Element.
-        m_token.m_type = m_lexer-&gt;scanTrailingTemplateString(&amp;m_token, rawStringsBuildMode);
-    }
</del><ins>+
+    // Re-scan the token to recognize it as Template Element.
+    m_token.m_type = m_lexer-&gt;scanTemplateString(&amp;m_token, rawStringsBuildMode);
</ins><span class="cx">     matchOrFail(TEMPLATE, &quot;Expected an template element&quot;);
</span><span class="cx">     const Identifier* cooked = m_token.m_data.cooked;
</span><span class="cx">     const Identifier* raw = m_token.m_data.raw;
</span><span class="lines">@@ -4100,12 +4102,13 @@
</span><span class="cx">     elementIsTail = m_token.m_data.isTail;
</span><span class="cx">     JSTokenLocation location(tokenLocation());
</span><span class="cx">     next();
</span><del>-    return context.createTemplateString(location, *cooked, *raw);
</del><ins>+    return context.createTemplateString(location, cooked, raw);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> template &lt;typename LexerType&gt;
</span><span class="cx"> template &lt;class TreeBuilder&gt; typename TreeBuilder::TemplateLiteral Parser&lt;LexerType&gt;::parseTemplateLiteral(TreeBuilder&amp; context, typename LexerType::RawStringsBuildMode rawStringsBuildMode)
</span><span class="cx"> {
</span><ins>+    ASSERT(match(BACKQUOTE));
</ins><span class="cx">     JSTokenLocation location(tokenLocation());
</span><span class="cx">     bool elementIsTail = false;
</span><span class="cx"> 
</span><span class="lines">@@ -4268,7 +4271,7 @@
</span><span class="cx">         }
</span><span class="cx">         return re;
</span><span class="cx">     }
</span><del>-    case TEMPLATE:
</del><ins>+    case BACKQUOTE:
</ins><span class="cx">         return parseTemplateLiteral(context, LexerType::RawStringsBuildMode::DontBuildRawStrings);
</span><span class="cx">     case YIELD:
</span><span class="cx">         if (!strictMode() &amp;&amp; !currentScope()-&gt;isGenerator())
</span><span class="lines">@@ -4505,7 +4508,7 @@
</span><span class="cx">             next();
</span><span class="cx">             break;
</span><span class="cx">         }
</span><del>-        case TEMPLATE: {
</del><ins>+        case BACKQUOTE: {
</ins><span class="cx">             semanticFailIfTrue(baseIsSuper, &quot;Cannot use super as tag for tagged templates&quot;);
</span><span class="cx">             JSTextPosition expressionEnd = lastTokenEndPosition();
</span><span class="cx">             int nonLHSCount = m_parserState.nonLHSCount;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreparserParserTokensh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/parser/ParserTokens.h (211318 => 211319)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/parser/ParserTokens.h        2017-01-28 02:27:56 UTC (rev 211318)
+++ trunk/Source/JavaScriptCore/parser/ParserTokens.h        2017-01-28 03:09:12 UTC (rev 211319)
</span><span class="lines">@@ -109,6 +109,7 @@
</span><span class="cx">     CLOSEBRACKET,
</span><span class="cx">     COMMA,
</span><span class="cx">     QUESTION,
</span><ins>+    BACKQUOTE,
</ins><span class="cx">     INTEGER,
</span><span class="cx">     DOUBLE,
</span><span class="cx">     IDENT,
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreparserSyntaxCheckerh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/parser/SyntaxChecker.h (211318 => 211319)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/parser/SyntaxChecker.h        2017-01-28 02:27:56 UTC (rev 211318)
+++ trunk/Source/JavaScriptCore/parser/SyntaxChecker.h        2017-01-28 03:09:12 UTC (rev 211319)
</span><span class="lines">@@ -194,7 +194,7 @@
</span><span class="cx">     int createArguments() { return ArgumentsResult; }
</span><span class="cx">     int createArguments(int) { return ArgumentsResult; }
</span><span class="cx">     ExpressionType createSpreadExpression(const JSTokenLocation&amp;, ExpressionType, int, int, int) { return SpreadExpr; }
</span><del>-    TemplateString createTemplateString(const JSTokenLocation&amp;, const Identifier&amp;, const Identifier&amp;) { return TemplateStringResult; }
</del><ins>+    TemplateString createTemplateString(const JSTokenLocation&amp;, const Identifier*, const Identifier*) { return TemplateStringResult; }
</ins><span class="cx">     TemplateStringList createTemplateStringList(TemplateString) { return TemplateStringListResult; }
</span><span class="cx">     TemplateStringList createTemplateStringList(TemplateStringList, TemplateString) { return TemplateStringListResult; }
</span><span class="cx">     TemplateExpressionList createTemplateExpressionList(Expression) { return TemplateExpressionListResult; }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeTemplateRegistrycpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/TemplateRegistry.cpp (211318 => 211319)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/TemplateRegistry.cpp        2017-01-28 02:27:56 UTC (rev 211318)
+++ trunk/Source/JavaScriptCore/runtime/TemplateRegistry.cpp        2017-01-28 03:09:12 UTC (rev 211319)
</span><span class="lines">@@ -58,8 +58,13 @@
</span><span class="cx">     RETURN_IF_EXCEPTION(scope, nullptr);
</span><span class="cx"> 
</span><span class="cx">     for (unsigned index = 0; index &lt; count; ++index) {
</span><del>-        templateObject-&gt;putDirectIndex(exec, index, jsString(exec, templateKey.cookedStrings()[index]), ReadOnly | DontDelete, PutDirectIndexLikePutDirect);
</del><ins>+        auto cooked = templateKey.cookedStrings()[index];
+        if (cooked)
+            templateObject-&gt;putDirectIndex(exec, index, jsString(exec, cooked.value()), ReadOnly | DontDelete, PutDirectIndexLikePutDirect);
+        else
+            templateObject-&gt;putDirectIndex(exec, index, jsUndefined(), ReadOnly | DontDelete, PutDirectIndexLikePutDirect);
</ins><span class="cx">         RETURN_IF_EXCEPTION(scope, nullptr);
</span><ins>+
</ins><span class="cx">         rawObject-&gt;putDirectIndex(exec, index, jsString(exec, templateKey.rawStrings()[index]), ReadOnly | DontDelete, PutDirectIndexLikePutDirect);
</span><span class="cx">         RETURN_IF_EXCEPTION(scope, nullptr);
</span><span class="cx">     }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeTemplateRegistryKeyh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/TemplateRegistryKey.h (211318 => 211319)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/TemplateRegistryKey.h        2017-01-28 02:27:56 UTC (rev 211318)
+++ trunk/Source/JavaScriptCore/runtime/TemplateRegistryKey.h        2017-01-28 03:09:12 UTC (rev 211319)
</span><span class="lines">@@ -38,6 +38,7 @@
</span><span class="cx"> public:
</span><span class="cx">     friend class TemplateRegistryKeyTable;
</span><span class="cx">     typedef Vector&lt;String, 4&gt; StringVector;
</span><ins>+    typedef Vector&lt;std::optional&lt;String&gt;, 4&gt; OptionalStringVector;
</ins><span class="cx"> 
</span><span class="cx">     enum DeletedValueTag { DeletedValue };
</span><span class="cx">     TemplateRegistryKey(DeletedValueTag);
</span><span class="lines">@@ -51,7 +52,7 @@
</span><span class="cx">     unsigned hash() const { return m_hash; }
</span><span class="cx"> 
</span><span class="cx">     const StringVector&amp; rawStrings() const { return m_rawStrings; }
</span><del>-    const StringVector&amp; cookedStrings() const { return m_cookedStrings; }
</del><ins>+    const OptionalStringVector&amp; cookedStrings() const { return m_cookedStrings; }
</ins><span class="cx"> 
</span><span class="cx">     bool operator==(const TemplateRegistryKey&amp; other) const { return m_hash == other.m_hash &amp;&amp; m_rawStrings == other.m_rawStrings; }
</span><span class="cx">     bool operator!=(const TemplateRegistryKey&amp; other) const { return m_hash != other.m_hash || m_rawStrings != other.m_rawStrings; }
</span><span class="lines">@@ -66,22 +67,22 @@
</span><span class="cx">     ~TemplateRegistryKey();
</span><span class="cx"> 
</span><span class="cx"> private:
</span><del>-    static Ref&lt;TemplateRegistryKey&gt; create(const StringVector&amp; rawStrings, const StringVector&amp; cookedStrings)
</del><ins>+    static Ref&lt;TemplateRegistryKey&gt; create(StringVector&amp;&amp; rawStrings, OptionalStringVector&amp;&amp; cookedStrings)
</ins><span class="cx">     {
</span><del>-        return adoptRef(*new TemplateRegistryKey(rawStrings, cookedStrings));
</del><ins>+        return adoptRef(*new TemplateRegistryKey(WTFMove(rawStrings), WTFMove(cookedStrings)));
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    TemplateRegistryKey(const StringVector&amp; rawStrings, const StringVector&amp; cookedStrings);
</del><ins>+    TemplateRegistryKey(StringVector&amp;&amp; rawStrings, OptionalStringVector&amp;&amp; cookedStrings);
</ins><span class="cx"> 
</span><span class="cx">     TemplateRegistryKeyTable* m_table { nullptr };
</span><span class="cx">     StringVector m_rawStrings;
</span><del>-    StringVector m_cookedStrings;
</del><ins>+    OptionalStringVector m_cookedStrings;
</ins><span class="cx">     unsigned m_hash { 0 };
</span><span class="cx"> };
</span><span class="cx"> 
</span><del>-inline TemplateRegistryKey::TemplateRegistryKey(const StringVector&amp; rawStrings, const StringVector&amp; cookedStrings)
-    : m_rawStrings(rawStrings)
-    , m_cookedStrings(cookedStrings)
</del><ins>+inline TemplateRegistryKey::TemplateRegistryKey(StringVector&amp;&amp; rawStrings, OptionalStringVector&amp;&amp; cookedStrings)
+    : m_rawStrings(WTFMove(rawStrings))
+    , m_cookedStrings(WTFMove(cookedStrings))
</ins><span class="cx">     , m_hash(calculateHash(rawStrings))
</span><span class="cx"> {
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeTemplateRegistryKeyTablecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/TemplateRegistryKeyTable.cpp (211318 => 211319)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/TemplateRegistryKeyTable.cpp        2017-01-28 02:27:56 UTC (rev 211318)
+++ trunk/Source/JavaScriptCore/runtime/TemplateRegistryKeyTable.cpp        2017-01-28 03:09:12 UTC (rev 211319)
</span><span class="lines">@@ -42,9 +42,9 @@
</span><span class="cx">         key-&gt;m_table = nullptr;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-Ref&lt;TemplateRegistryKey&gt; TemplateRegistryKeyTable::createKey(const TemplateRegistryKey::StringVector&amp; rawStrings, const TemplateRegistryKey::StringVector&amp; cookedStrings)
</del><ins>+Ref&lt;TemplateRegistryKey&gt; TemplateRegistryKeyTable::createKey(TemplateRegistryKey::StringVector&amp;&amp; rawStrings, TemplateRegistryKey::OptionalStringVector&amp;&amp; cookedStrings)
</ins><span class="cx"> {
</span><del>-    auto key = TemplateRegistryKey::create(rawStrings, cookedStrings);
</del><ins>+    auto key = TemplateRegistryKey::create(WTFMove(rawStrings), WTFMove(cookedStrings));
</ins><span class="cx">     auto addResult = m_atomicTable.add&lt;TemplateRegistryKeyTranslator&gt;(key.ptr());
</span><span class="cx">     if (addResult.isNewEntry)
</span><span class="cx">         (*addResult.iterator)-&gt;m_table = this;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeTemplateRegistryKeyTableh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/TemplateRegistryKeyTable.h (211318 => 211319)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/TemplateRegistryKeyTable.h        2017-01-28 02:27:56 UTC (rev 211318)
+++ trunk/Source/JavaScriptCore/runtime/TemplateRegistryKeyTable.h        2017-01-28 03:09:12 UTC (rev 211319)
</span><span class="lines">@@ -36,10 +36,11 @@
</span><span class="cx">     WTF_MAKE_NONCOPYABLE(TemplateRegistryKeyTable);
</span><span class="cx"> public:
</span><span class="cx">     using StringVector = Vector&lt;String, 4&gt;;
</span><ins>+    using OptionalStringVector = Vector&lt;std::optional&lt;String&gt;, 4&gt;;
</ins><span class="cx"> 
</span><span class="cx">     TemplateRegistryKeyTable() = default;
</span><span class="cx"> 
</span><del>-    Ref&lt;TemplateRegistryKey&gt; createKey(const StringVector&amp; rawStrings, const StringVector&amp; cookedStrings);
</del><ins>+    Ref&lt;TemplateRegistryKey&gt; createKey(StringVector&amp;&amp; rawStrings, OptionalStringVector&amp;&amp; cookedStrings);
</ins><span class="cx"> 
</span><span class="cx">     void unregister(TemplateRegistryKey&amp;);
</span><span class="cx"> 
</span></span></pre>
</div>
</div>

</body>
</html>