Title: [211319] trunk
Revision
211319
Author
utatane....@gmail.com
Date
2017-01-27 19:09:12 -0800 (Fri, 27 Jan 2017)

Log Message

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/_javascript_Core:

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<CharacterType>::parseUnicodeEscape):
(JSC::Lexer<T>::parseTemplateLiteral):
(JSC::Lexer<T>::lex):
(JSC::Lexer<T>::scanTemplateString):
(JSC::Lexer<T>::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<LexerType>::parseAssignmentElement):
(JSC::Parser<LexerType>::parseTemplateString):
(JSC::Parser<LexerType>::parseTemplateLiteral):
(JSC::Parser<LexerType>::parsePrimaryExpression):
(JSC::Parser<LexerType>::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:

Modified Paths

Added Paths

Diff

Modified: trunk/JSTests/ChakraCore/test/es6/unicode_6_identifier_Blue524737.baseline-jsc (211318 => 211319)


--- 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)
@@ -1,2 +1,2 @@
-Exception: SyntaxError: Invalid unicode escape in identifier: '\u{13407'
+Exception: SyntaxError: Invalid unicode escape in identifier: '\u{134071'
 at unicode_6_identifier_Blue524737.js:6

Modified: trunk/JSTests/ChangeLog (211318 => 211319)


--- trunk/JSTests/ChangeLog	2017-01-28 02:27:56 UTC (rev 211318)
+++ trunk/JSTests/ChangeLog	2017-01-28 03:09:12 UTC (rev 211319)
@@ -1,3 +1,19 @@
+2017-01-27  Yusuke Suzuki  <utatane....@gmail.com>
+
+        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:
+
 2017-01-26  Mark Lam  <mark....@apple.com>
 
         Fix missing exception check in genericTypedArrayViewProtoFuncSet().

Added: trunk/JSTests/stress/lift-template-literal.js (0 => 211319)


--- 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)
@@ -0,0 +1,69 @@
+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!}}`, `{"cooked":["\\newcommand{\\fun}{\\textbf{Fun!}}"],"raw":["\\\\newcommand{\\\\fun}{\\\\textbf{Fun!}}"]}`);
+shouldBe(dump`\newcommand{\unicode}{\textbf{Unicode!}}`, `{"cooked":[null],"raw":["\\\\newcommand{\\\\unicode}{\\\\textbf{Unicode!}}"]}`);
+shouldBe(dump`\newcommand{\xerxes}{\textbf{King!}}`, `{"cooked":[null],"raw":["\\\\newcommand{\\\\xerxes}{\\\\textbf{King!}}"]}`);
+shouldBe(dump`Breve over the h goes \u{h}ere`, `{"cooked":[null],"raw":["Breve over the h goes \\\\u{h}ere"]}`);
+
+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) => shouldBe(callSite[index], value));
+        expected.raw.forEach((value, index) => shouldBe(callSite.raw[index], value));
+    }
+}
+
+testTag({
+    cooked: [ undefined ],
+    raw: [ "\\unicode and \\u{55}" ],
+})`\unicode and \u{55}`;
+
+testTag({
+    cooked: [ undefined, "test" ],
+    raw: [ "\\unicode and \\u{55}", "test" ],
+})`\unicode and \u{55}${42}test`;
+
+testTag({
+    cooked: [ undefined, undefined, "Cocoa" ],
+    raw: [ "\\unicode and \\u{55}", "\\uhello", "Cocoa" ],
+})`\unicode and \u{55}${42}\uhello${42}Cocoa`;
+
+testTag({
+    cooked: [ "Cocoa", undefined, undefined, "Cocoa" ],
+    raw: [ "Cocoa", "\\unicode and \\u{55}", "\\uhello", "Cocoa" ],
+})`Cocoa${42}\unicode and \u{55}${42}\uhello${42}Cocoa`;
+
+testTag({
+    cooked: [ "Cocoa", undefined, undefined, "Cocoa" ],
+    raw: [ "Cocoa", "\\unicode and \\u{55}", "\\uhello", "Cocoa" ],
+})`Cocoa${42}\unicode and \u{55}${42}\uhello${42}Cocoa`;
+
+testTag({
+    cooked: [ undefined, undefined, undefined ],
+    raw: [ "\\00", "\\01", "\\1" ]
+})`\00${42}\01${42}\1`;
+
+testTag({
+    cooked: [ undefined, undefined ],
+    raw: [ "\\xo", "\\x0o" ]
+})`\xo${42}\x0o`;
+
+testTag({
+    cooked: [ undefined, undefined, undefined, undefined ],
+    raw: [ "\\uo", "\\u0o", "\\u00o", "\\u000o" ]
+})`\uo${42}\u0o${42}\u00o${42}\u000o`;
+
+testTag({
+    cooked: [ undefined, undefined, undefined ],
+    raw: [ "\\u{o", "\\u{0o", "\\u{110000o" ]
+})`\u{o${42}\u{0o${42}\u{110000o`;

Modified: trunk/JSTests/stress/template-literal-syntax.js (211318 => 211319)


--- 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)
@@ -46,6 +46,19 @@
 testSyntax("`\\\n`");
 testSyntax("`\\\r\n`");
 testSyntax("`\\\r`");
+testSyntax("Hello`bad escape sequence: \\unicode`");
+testSyntax("Hello`\\00`");
+testSyntax("Hello`\\01`");
+testSyntax("Hello`\\1`");
+testSyntax("Hello`\\xo`");
+testSyntax("Hello`\\x0o`");
+testSyntax("Hello`\\uo`");
+testSyntax("Hello`\\u0o`");
+testSyntax("Hello`\\u00o`");
+testSyntax("Hello`\\u000o`");
+testSyntax("Hello`\\u{o`");
+testSyntax("Hello`\\u{0o`");
+testSyntax("Hello`\\u{110000o`");
 
 testSyntaxError("`Hello", "SyntaxError: Unexpected EOF");
 testSyntaxError("`Hello${expr}", "SyntaxError: Unexpected EOF");
@@ -81,3 +94,18 @@
 testSyntaxError("`${expr}\\u20`", "SyntaxError: \\u can only be followed by a Unicode character sequence");
 testSyntaxError("`\\u202`", "SyntaxError: \\u can only be followed by a Unicode character sequence");
 testSyntaxError("`${expr}\\u202`", "SyntaxError: \\u can only be followed by a Unicode character sequence");
+
+testSyntaxError("`bad escape sequence: \\unicode`", "SyntaxError: \\u can only be followed by a Unicode character sequence");
+
+testSyntaxError("`\\00`", "SyntaxError: The only valid numeric escape in strict mode is '\\0'");
+testSyntaxError("`\\01`", "SyntaxError: The only valid numeric escape in strict mode is '\\0'");
+testSyntaxError("`\\1`", "SyntaxError: The only valid numeric escape in strict mode is '\\0'");
+testSyntaxError("`\\xo`", "SyntaxError: \\x can only be followed by a hex character sequence");
+testSyntaxError("`\\x0o`", "SyntaxError: \\x can only be followed by a hex character sequence");
+testSyntaxError("`\\uo`", "SyntaxError: \\u can only be followed by a Unicode character sequence");
+testSyntaxError("`\\u0o`", "SyntaxError: \\u can only be followed by a Unicode character sequence");
+testSyntaxError("`\\u00o`", "SyntaxError: \\u can only be followed by a Unicode character sequence");
+testSyntaxError("`\\u000o`", "SyntaxError: \\u can only be followed by a Unicode character sequence");
+testSyntaxError("`\\u{o`", "SyntaxError: \\u can only be followed by a Unicode character sequence");
+testSyntaxError("`\\u{0o`", "SyntaxError: \\u can only be followed by a Unicode character sequence");
+testSyntaxError("`\\u{110000o`", "SyntaxError: \\u can only be followed by a Unicode character sequence");

Modified: trunk/LayoutTests/ChangeLog (211318 => 211319)


--- trunk/LayoutTests/ChangeLog	2017-01-28 02:27:56 UTC (rev 211318)
+++ trunk/LayoutTests/ChangeLog	2017-01-28 03:09:12 UTC (rev 211319)
@@ -1,5 +1,17 @@
 2017-01-27  Yusuke Suzuki  <utatane....@gmail.com>
 
+        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  <utatane....@gmail.com>
+
         setTimeout / setInterval's string execution should inherit SourceOrigin correctly
         https://bugs.webkit.org/show_bug.cgi?id=167097
 

Modified: trunk/LayoutTests/inspector/runtime/parse-expected.txt (211318 => 211319)


--- 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)
@@ -67,9 +67,9 @@
 
 PASS: Should be SyntaxErrorType UnterminatedLiteral.
 Source: var \u007
-            ^~
-Error Message: Incomplete unicode escape in identifier: '\u'
-Range: {"startOffset":4,"endOffset":6}
+            ^~~~~
+Error Message: Incomplete unicode escape in identifier: '\u007'
+Range: {"startOffset":4,"endOffset":9}
 
 
 -- Running test case: SyntaxErrorType.Recoverable

Modified: trunk/LayoutTests/js/unicode-escape-sequences-expected.txt (211318 => 211319)


--- 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)
@@ -58,9 +58,9 @@
 PASS codeUnits(function \u{}(){}.name) threw exception SyntaxError: Invalid unicode escape in identifier: '\u{'.
 PASS codeUnits(function \u{G}(){}.name) threw exception SyntaxError: Invalid unicode escape in identifier: '\u{'.
 PASS codeUnits(function \u{1G}(){}.name) threw exception SyntaxError: Invalid unicode escape in identifier: '\u{1'.
-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'.
+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'.
 PASS codeUnits(function x\u{41}(){}.name.substring(1)) is "0041"
 PASS codeUnits(function x\u{10000}(){}.name.substring(1)) is "D800,DC00"
 PASS codeUnits(function x\u{10001}(){}.name.substring(1)) is "D800,DC01"
@@ -87,9 +87,9 @@
 PASS codeUnits(function x\u{}(){}.name.substring(1)) threw exception SyntaxError: Invalid unicode escape in identifier: 'x\u{'.
 PASS codeUnits(function x\u{G}(){}.name.substring(1)) threw exception SyntaxError: Invalid unicode escape in identifier: 'x\u{'.
 PASS codeUnits(function x\u{1G}(){}.name.substring(1)) threw exception SyntaxError: Invalid unicode escape in identifier: 'x\u{1'.
-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'.
+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'.
 PASS successfullyParsed is true
 
 TEST COMPLETE

Modified: trunk/Source/_javascript_Core/ChangeLog (211318 => 211319)


--- trunk/Source/_javascript_Core/ChangeLog	2017-01-28 02:27:56 UTC (rev 211318)
+++ trunk/Source/_javascript_Core/ChangeLog	2017-01-28 03:09:12 UTC (rev 211319)
@@ -1,3 +1,68 @@
+2017-01-27  Yusuke Suzuki  <utatane....@gmail.com>
+
+        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<CharacterType>::parseUnicodeEscape):
+        (JSC::Lexer<T>::parseTemplateLiteral):
+        (JSC::Lexer<T>::lex):
+        (JSC::Lexer<T>::scanTemplateString):
+        (JSC::Lexer<T>::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<LexerType>::parseAssignmentElement):
+        (JSC::Parser<LexerType>::parseTemplateString):
+        (JSC::Parser<LexerType>::parseTemplateLiteral):
+        (JSC::Parser<LexerType>::parsePrimaryExpression):
+        (JSC::Parser<LexerType>::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:
+
 2017-01-27  Saam Barati  <sbar...@apple.com>
 
         Make the CLI for the sampling profiler better for inlined call site indices

Modified: trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.cpp (211318 => 211319)


--- trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.cpp	2017-01-28 02:27:56 UTC (rev 211318)
+++ trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.cpp	2017-01-28 03:09:12 UTC (rev 211319)
@@ -4253,17 +4253,22 @@
 RegisterID* BytecodeGenerator::emitGetTemplateObject(RegisterID* dst, TaggedTemplateNode* taggedTemplate)
 {
     TemplateRegistryKey::StringVector rawStrings;
-    TemplateRegistryKey::StringVector cookedStrings;
+    TemplateRegistryKey::OptionalStringVector cookedStrings;
 
     TemplateStringListNode* templateString = taggedTemplate->templateLiteral()->templateStrings();
     for (; templateString; templateString = templateString->next()) {
-        rawStrings.append(templateString->value()->raw().impl());
-        cookedStrings.append(templateString->value()->cooked().impl());
+        auto* string = templateString->value();
+        ASSERT(string->raw());
+        rawStrings.append(string->raw()->impl());
+        if (!string->cooked())
+            cookedStrings.append(std::nullopt);
+        else
+            cookedStrings.append(string->cooked()->impl());
     }
 
     RefPtr<RegisterID> getTemplateObject = emitGetGlobalPrivate(newTemporary(), propertyNames().builtinNames().getTemplateObjectPrivateName());
     CallArguments arguments(*this, nullptr);
-    emitLoad(arguments.thisRegister(), JSValue(addTemplateRegistryKeyConstant(m_vm->templateRegistryKeyTable().createKey(rawStrings, cookedStrings))));
+    emitLoad(arguments.thisRegister(), JSValue(addTemplateRegistryKeyConstant(m_vm->templateRegistryKeyTable().createKey(WTFMove(rawStrings), WTFMove(cookedStrings)))));
     return emitCall(dst, getTemplateObject.get(), NoExpectedFunction, arguments, taggedTemplate->divot(), taggedTemplate->divotStart(), taggedTemplate->divotEnd(), DebuggableCall::No);
 }
 

Modified: trunk/Source/_javascript_Core/bytecompiler/NodesCodegen.cpp (211318 => 211319)


--- trunk/Source/_javascript_Core/bytecompiler/NodesCodegen.cpp	2017-01-28 02:27:56 UTC (rev 211318)
+++ trunk/Source/_javascript_Core/bytecompiler/NodesCodegen.cpp	2017-01-28 03:09:12 UTC (rev 211319)
@@ -246,7 +246,8 @@
 {
     if (dst == generator.ignoredResult())
         return nullptr;
-    return generator.emitLoad(dst, JSValue(generator.addStringConstant(cooked())));
+    ASSERT(cooked());
+    return generator.emitLoad(dst, JSValue(generator.addStringConstant(*cooked())));
 }
 
 // ------------------------------ TemplateLiteralNode -----------------------------------
@@ -265,7 +266,8 @@
     TemplateExpressionListNode* templateExpression = m_templateExpressions;
     for (; templateExpression; templateExpression = templateExpression->next(), templateString = templateString->next()) {
         // Evaluate TemplateString.
-        if (!templateString->value()->cooked().isEmpty()) {
+        ASSERT(templateString->value()->cooked());
+        if (!templateString->value()->cooked()->isEmpty()) {
             temporaryRegisters.append(generator.newTemporary());
             generator.emitNode(temporaryRegisters.last().get(), templateString->value());
         }
@@ -277,7 +279,8 @@
     }
 
     // Evaluate tail TemplateString.
-    if (!templateString->value()->cooked().isEmpty()) {
+    ASSERT(templateString->value()->cooked());
+    if (!templateString->value()->cooked()->isEmpty()) {
         temporaryRegisters.append(generator.newTemporary());
         generator.emitNode(temporaryRegisters.last().get(), templateString->value());
     }

Modified: trunk/Source/_javascript_Core/parser/ASTBuilder.h (211318 => 211319)


--- trunk/Source/_javascript_Core/parser/ASTBuilder.h	2017-01-28 02:27:56 UTC (rev 211318)
+++ trunk/Source/_javascript_Core/parser/ASTBuilder.h	2017-01-28 03:09:12 UTC (rev 211319)
@@ -275,7 +275,7 @@
         return node;
     }
 
-    TemplateStringNode* createTemplateString(const JSTokenLocation& location, const Identifier& cooked, const Identifier& raw)
+    TemplateStringNode* createTemplateString(const JSTokenLocation& location, const Identifier* cooked, const Identifier* raw)
     {
         return new (m_parserArena) TemplateStringNode(location, cooked, raw);
     }

Modified: trunk/Source/_javascript_Core/parser/Lexer.cpp (211318 => 211319)


--- trunk/Source/_javascript_Core/parser/Lexer.cpp	2017-01-28 02:27:56 UTC (rev 211318)
+++ trunk/Source/_javascript_Core/parser/Lexer.cpp	2017-01-28 03:09:12 UTC (rev 211319)
@@ -633,7 +633,8 @@
     UChar32 m_value;
 };
 
-template<typename CharacterType> ParsedUnicodeEscapeValue Lexer<CharacterType>::parseUnicodeEscape()
+template<typename CharacterType>
+ParsedUnicodeEscapeValue Lexer<CharacterType>::parseUnicodeEscape()
 {
     if (m_current == '{') {
         shift();
@@ -642,8 +643,26 @@
             if (!isASCIIHexDigit(m_current))
                 return m_current ? ParsedUnicodeEscapeValue::Invalid : ParsedUnicodeEscapeValue::Incomplete;
             codePoint = (codePoint << 4) | toASCIIHexValue(m_current);
-            if (codePoint > UCHAR_MAX_VALUE)
-                return ParsedUnicodeEscapeValue::Invalid;
+            if (codePoint > 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 <= 0x10FFFF
+                //
+                // CodePoint ::
+                //     HexDigits but not if MV of HexDigits > 0x10FFFF
+                shift();
+                while (isASCIIHexDigit(m_current))
+                    shift();
+
+                return atEnd() ? ParsedUnicodeEscapeValue::Incomplete : ParsedUnicodeEscapeValue::Invalid;
+            }
             shift();
         } while (m_current != '}');
         shift();
@@ -653,8 +672,22 @@
     auto character2 = peek(1);
     auto character3 = peek(2);
     auto character4 = peek(3);
-    if (UNLIKELY(!isASCIIHexDigit(m_current) || !isASCIIHexDigit(character2) || !isASCIIHexDigit(character3) || !isASCIIHexDigit(character4)))
-        return (m_code + 4) >= m_codeEnd ? ParsedUnicodeEscapeValue::Incomplete : ParsedUnicodeEscapeValue::Invalid;
+    if (UNLIKELY(!isASCIIHexDigit(m_current) || !isASCIIHexDigit(character2) || !isASCIIHexDigit(character3) || !isASCIIHexDigit(character4))) {
+        auto result = (m_code + 4) >= 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;
+    }
+
     auto result = convertUnicode(m_current, character2, character3, character4);
     shift();
     shift();
@@ -1181,19 +1214,30 @@
 }
 
 template <typename T>
-template <bool shouldBuildStrings> ALWAYS_INLINE auto Lexer<T>::parseComplexEscape(EscapeParseMode escapeParseMode, bool strictMode, T stringQuoteCharacter) -> StringParseResult
+template <bool shouldBuildStrings, LexerEscapeParseMode escapeParseMode> ALWAYS_INLINE auto Lexer<T>::parseComplexEscape(bool strictMode, T stringQuoteCharacter) -> StringParseResult
 {
     if (m_current == 'x') {
         shift();
         if (!isASCIIHexDigit(m_current) || !isASCIIHexDigit(peek(1))) {
+            // 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));
+
             m_lexErrorMessage = ASCIILiteral("\\x can only be followed by a hex character sequence");
-            return StringCannotBeParsed;
+            return atEnd() ? StringUnterminated : StringCannotBeParsed;
         }
+
         T prev = m_current;
         shift();
         if (shouldBuildStrings)
             record16(convertHex(prev, m_current));
         shift();
+
         return StringParsedSuccessfully;
     }
 
@@ -1200,7 +1244,7 @@
     if (m_current == 'u') {
         shift();
 
-        if (escapeParseMode == EscapeParseMode::String && m_current == stringQuoteCharacter) {
+        if (escapeParseMode == LexerEscapeParseMode::String && m_current == stringQuoteCharacter) {
             if (shouldBuildStrings)
                 record16('u');
             return StringParsedSuccessfully;
@@ -1214,7 +1258,7 @@
         }
 
         m_lexErrorMessage = ASCIILiteral("\\u can only be followed by a Unicode character sequence");
-        return character.isIncomplete() ? StringUnterminated : StringCannotBeParsed;
+        return atEnd() ? StringUnterminated : StringCannotBeParsed;
     }
 
     if (strictMode) {
@@ -1223,8 +1267,16 @@
             int character1 = m_current;
             shift();
             if (character1 != '0' || isASCIIDigit(m_current)) {
+                // For raw template literal syntax, we consume `NotEscapeSequence`.
+                //
+                // NotEscapeSequence ::
+                //     0 DecimalDigit
+                //     DecimalDigit but not 0
+                if (character1 == '0')
+                    shift();
+
                 m_lexErrorMessage = ASCIILiteral("The only valid numeric escape in strict mode is '\\0'");
-                return StringCannotBeParsed;
+                return atEnd() ? StringUnterminated : StringCannotBeParsed;
             }
             if (shouldBuildStrings)
                 record16(0);
@@ -1290,7 +1342,7 @@
             } else if (UNLIKELY(isLineTerminator(m_current)))
                 shiftLineTerminator();
             else {
-                StringParseResult result = parseComplexEscape<shouldBuildStrings>(EscapeParseMode::String, strictMode, stringQuoteCharacter);
+                StringParseResult result = parseComplexEscape<shouldBuildStrings, LexerEscapeParseMode::String>(strictMode, stringQuoteCharacter);
                 if (result != StringParsedSuccessfully)
                     return result;
             }
@@ -1372,8 +1424,9 @@
 };
 
 template <typename T>
-template <bool shouldBuildStrings> typename Lexer<T>::StringParseResult Lexer<T>::parseTemplateLiteral(JSTokenData* tokenData, RawStringsBuildMode rawStringsBuildMode)
+typename Lexer<T>::StringParseResult Lexer<T>::parseTemplateLiteral(JSTokenData* tokenData, RawStringsBuildMode rawStringsBuildMode)
 {
+    bool parseCookedFailed = false;
     const T* stringStart = currentSourcePtr();
     const T* rawStringStart = currentSourcePtr();
 
@@ -1382,7 +1435,7 @@
     while (m_current != '`') {
         if (UNLIKELY(m_current == '\\')) {
             lineNumberAdder.clear();
-            if (stringStart != currentSourcePtr() && shouldBuildStrings)
+            if (stringStart != currentSourcePtr())
                 append16(stringStart, currentSourcePtr() - stringStart);
             shift();
 
@@ -1390,19 +1443,16 @@
 
             // Most common escape sequences first.
             if (escape) {
-                if (shouldBuildStrings)
-                    record16(escape);
+                record16(escape);
                 shift();
             } else if (UNLIKELY(isLineTerminator(m_current))) {
                 // Normalize <CR>, <CR><LF> to <LF>.
                 if (m_current == '\r') {
-                    if (shouldBuildStrings) {
-                        ASSERT_WITH_MESSAGE(rawStringStart != currentSourcePtr(), "We should have at least shifted the escape.");
+                    ASSERT_WITH_MESSAGE(rawStringStart != currentSourcePtr(), "We should have at least shifted the escape.");
 
-                        if (rawStringsBuildMode == RawStringsBuildMode::BuildRawStrings) {
-                            m_bufferForRawTemplateString16.append(rawStringStart, currentSourcePtr() - rawStringStart);
-                            m_bufferForRawTemplateString16.append('\n');
-                        }
+                    if (rawStringsBuildMode == RawStringsBuildMode::BuildRawStrings) {
+                        m_bufferForRawTemplateString16.append(rawStringStart, currentSourcePtr() - rawStringStart);
+                        m_bufferForRawTemplateString16.append('\n');
                     }
 
                     lineNumberAdder.add(m_current);
@@ -1419,9 +1469,13 @@
                 }
             } else {
                 bool strictMode = true;
-                StringParseResult result = parseComplexEscape<shouldBuildStrings>(EscapeParseMode::Template, strictMode, '`');
-                if (result != StringParsedSuccessfully)
-                    return result;
+                StringParseResult result = parseComplexEscape<true, LexerEscapeParseMode::Template>(strictMode, '`');
+                if (result != StringParsedSuccessfully) {
+                    if (rawStringsBuildMode == RawStringsBuildMode::BuildRawStrings && result == StringCannotBeParsed)
+                        parseCookedFailed = true;
+                    else
+                        return result;
+                }
             }
 
             stringStart = currentSourcePtr();
@@ -1445,16 +1499,14 @@
             if (isLineTerminator(m_current)) {
                 if (m_current == '\r') {
                     // Normalize <CR>, <CR><LF> to <LF>.
-                    if (shouldBuildStrings) {
-                        if (stringStart != currentSourcePtr())
-                            append16(stringStart, currentSourcePtr() - stringStart);
-                        if (rawStringStart != currentSourcePtr() && rawStringsBuildMode == RawStringsBuildMode::BuildRawStrings)
-                            m_bufferForRawTemplateString16.append(rawStringStart, currentSourcePtr() - rawStringStart);
+                    if (stringStart != currentSourcePtr())
+                        append16(stringStart, currentSourcePtr() - stringStart);
+                    if (rawStringStart != currentSourcePtr() && rawStringsBuildMode == RawStringsBuildMode::BuildRawStrings)
+                        m_bufferForRawTemplateString16.append(rawStringStart, currentSourcePtr() - rawStringStart);
 
-                        record16('\n');
-                        if (rawStringsBuildMode == RawStringsBuildMode::BuildRawStrings)
-                            m_bufferForRawTemplateString16.append('\n');
-                    }
+                    record16('\n');
+                    if (rawStringsBuildMode == RawStringsBuildMode::BuildRawStrings)
+                        m_bufferForRawTemplateString16.append('\n');
                     lineNumberAdder.add(m_current);
                     shift();
                     if (m_current == '\n') {
@@ -1478,24 +1530,22 @@
 
     bool isTail = m_current == '`';
 
-    if (shouldBuildStrings) {
-        if (currentSourcePtr() != stringStart)
-            append16(stringStart, currentSourcePtr() - stringStart);
-        if (rawStringStart != currentSourcePtr() && rawStringsBuildMode == RawStringsBuildMode::BuildRawStrings)
-            m_bufferForRawTemplateString16.append(rawStringStart, currentSourcePtr() - rawStringStart);
-    }
+    if (currentSourcePtr() != stringStart)
+        append16(stringStart, currentSourcePtr() - stringStart);
+    if (rawStringStart != currentSourcePtr() && rawStringsBuildMode == RawStringsBuildMode::BuildRawStrings)
+        m_bufferForRawTemplateString16.append(rawStringStart, currentSourcePtr() - rawStringStart);
 
-    if (shouldBuildStrings) {
+    if (!parseCookedFailed)
         tokenData->cooked = makeIdentifier(m_buffer16.data(), m_buffer16.size());
-        // Line terminator normalization (e.g. <CR> => <LF>) should be applied to both the raw and cooked representations.
-        if (rawStringsBuildMode == RawStringsBuildMode::BuildRawStrings)
-            tokenData->raw = makeIdentifier(m_bufferForRawTemplateString16.data(), m_bufferForRawTemplateString16.size());
-        else
-            tokenData->raw = makeEmptyIdentifier();
-    } else {
-        tokenData->cooked = makeEmptyIdentifier();
-        tokenData->raw = makeEmptyIdentifier();
-    }
+    else
+        tokenData->cooked = nullptr;
+
+    // Line terminator normalization (e.g. <CR> => <LF>) should be applied to both the raw and cooked representations.
+    if (rawStringsBuildMode == RawStringsBuildMode::BuildRawStrings)
+        tokenData->raw = makeIdentifier(m_bufferForRawTemplateString16.data(), m_bufferForRawTemplateString16.size());
+    else
+        tokenData->raw = nullptr;
+
     tokenData->isTail = isTail;
 
     m_buffer16.shrink(0);
@@ -2082,6 +2132,10 @@
         shift();
         token = SEMICOLON;
         break;
+    case CharacterBackQuote:
+        shift();
+        token = BACKQUOTE;
+        break;
     case CharacterOpenBrace:
         tokenData->line = lineNumber();
         tokenData->offset = currentOffset();
@@ -2234,22 +2288,6 @@
         token = STRING;
         break;
         }
-    case CharacterBackQuote: {
-        // Skip backquote.
-        shift();
-        StringParseResult result = StringCannotBeParsed;
-        if (lexerFlags & LexerFlagsDontBuildStrings)
-            result = parseTemplateLiteral<false>(tokenData, RawStringsBuildMode::BuildRawStrings);
-        else
-            result = parseTemplateLiteral<true>(tokenData, RawStringsBuildMode::BuildRawStrings);
-
-        if (UNLIKELY(result != StringParsedSuccessfully)) {
-            token = result == StringUnterminated ? UNTERMINATED_TEMPLATE_LITERAL_ERRORTOK : INVALID_TEMPLATE_LITERAL_ERRORTOK;
-            goto returnError;
-        }
-        token = TEMPLATE;
-        break;
-        }
     case CharacterIdentifierStart:
         ASSERT(isIdentStart(m_current));
         FALLTHROUGH;
@@ -2420,15 +2458,15 @@
 }
 
 template <typename T>
-JSTokenType Lexer<T>::scanTrailingTemplateString(JSToken* tokenRecord, RawStringsBuildMode rawStringsBuildMode)
+JSTokenType Lexer<T>::scanTemplateString(JSToken* tokenRecord, RawStringsBuildMode rawStringsBuildMode)
 {
     JSTokenData* tokenData = &tokenRecord->m_data;
     ASSERT(!m_error);
     ASSERT(m_buffer16.isEmpty());
 
-    // Leading closing brace } is already shifted in the previous token scan.
+    // Leading backquote ` (for template head) or closing brace } (for template trailing) are already shifted in the previous token scan.
     // So in this re-scan phase, shift() is not needed here.
-    StringParseResult result = parseTemplateLiteral<true>(tokenData, rawStringsBuildMode);
+    StringParseResult result = parseTemplateLiteral(tokenData, rawStringsBuildMode);
     JSTokenType token = ERRORTOK;
     if (UNLIKELY(result != StringParsedSuccessfully)) {
         token = result == StringUnterminated ? UNTERMINATED_TEMPLATE_LITERAL_ERRORTOK : INVALID_TEMPLATE_LITERAL_ERRORTOK;

Modified: trunk/Source/_javascript_Core/parser/Lexer.h (211318 => 211319)


--- trunk/Source/_javascript_Core/parser/Lexer.h	2017-01-28 02:27:56 UTC (rev 211318)
+++ trunk/Source/_javascript_Core/parser/Lexer.h	2017-01-28 03:09:12 UTC (rev 211319)
@@ -37,6 +37,8 @@
     LexexFlagsDontBuildKeywords = 4
 };
 
+enum class LexerEscapeParseMode { Template, String };
+
 struct ParsedUnicodeEscapeValue;
 
 bool isLexerKeyword(const Identifier&);
@@ -77,7 +79,7 @@
     bool prevTerminator() const { return m_terminator; }
     JSTokenType scanRegExp(JSToken*, UChar patternPrefix = 0);
     enum class RawStringsBuildMode { BuildRawStrings, DontBuildRawStrings };
-    JSTokenType scanTrailingTemplateString(JSToken*, RawStringsBuildMode);
+    JSTokenType scanTemplateString(JSToken*, RawStringsBuildMode);
 
     // Functions for use after parsing.
     bool sawError() const { return m_error; }
@@ -170,9 +172,8 @@
     template <bool shouldBuildStrings> ALWAYS_INLINE StringParseResult parseString(JSTokenData*, bool strictMode);
     template <bool shouldBuildStrings> NEVER_INLINE StringParseResult parseStringSlowCase(JSTokenData*, bool strictMode);
 
-    enum class EscapeParseMode { Template, String };
-    template <bool shouldBuildStrings> ALWAYS_INLINE StringParseResult parseComplexEscape(EscapeParseMode, bool strictMode, T stringQuoteCharacter);
-    template <bool shouldBuildStrings> ALWAYS_INLINE StringParseResult parseTemplateLiteral(JSTokenData*, RawStringsBuildMode);
+    template <bool shouldBuildStrings, LexerEscapeParseMode escapeParseMode> ALWAYS_INLINE StringParseResult parseComplexEscape(bool strictMode, T stringQuoteCharacter);
+    ALWAYS_INLINE StringParseResult parseTemplateLiteral(JSTokenData*, RawStringsBuildMode);
     ALWAYS_INLINE void parseHex(double& returnValue);
     ALWAYS_INLINE bool parseBinary(double& returnValue);
     ALWAYS_INLINE bool parseOctal(double& returnValue);

Modified: trunk/Source/_javascript_Core/parser/NodeConstructors.h (211318 => 211319)


--- trunk/Source/_javascript_Core/parser/NodeConstructors.h	2017-01-28 02:27:56 UTC (rev 211318)
+++ trunk/Source/_javascript_Core/parser/NodeConstructors.h	2017-01-28 03:09:12 UTC (rev 211319)
@@ -111,7 +111,7 @@
         previous->m_next = this;
     }
 
-    inline TemplateStringNode::TemplateStringNode(const JSTokenLocation& location, const Identifier& cooked, const Identifier& raw)
+    inline TemplateStringNode::TemplateStringNode(const JSTokenLocation& location, const Identifier* cooked, const Identifier* raw)
         : ExpressionNode(location)
         , m_cooked(cooked)
         , m_raw(raw)

Modified: trunk/Source/_javascript_Core/parser/Nodes.h (211318 => 211319)


--- trunk/Source/_javascript_Core/parser/Nodes.h	2017-01-28 02:27:56 UTC (rev 211318)
+++ trunk/Source/_javascript_Core/parser/Nodes.h	2017-01-28 03:09:12 UTC (rev 211319)
@@ -490,16 +490,16 @@
 
     class TemplateStringNode : public ExpressionNode {
     public:
-        TemplateStringNode(const JSTokenLocation&, const Identifier& cooked, const Identifier& raw);
+        TemplateStringNode(const JSTokenLocation&, const Identifier* cooked, const Identifier* raw);
 
-        const Identifier& cooked() { return m_cooked; }
-        const Identifier& raw() { return m_raw; }
+        const Identifier* cooked() { return m_cooked; }
+        const Identifier* raw() { return m_raw; }
 
     private:
         RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
 
-        const Identifier& m_cooked;
-        const Identifier& m_raw;
+        const Identifier* m_cooked;
+        const Identifier* m_raw;
     };
 
     class TemplateStringListNode : public ParserArenaFreeable {

Modified: trunk/Source/_javascript_Core/parser/Parser.cpp (211318 => 211319)


--- trunk/Source/_javascript_Core/parser/Parser.cpp	2017-01-28 02:27:56 UTC (rev 211318)
+++ trunk/Source/_javascript_Core/parser/Parser.cpp	2017-01-28 03:09:12 UTC (rev 211319)
@@ -904,7 +904,7 @@
     if (match(OPENBRACE) || match(OPENBRACKET)) {
         SavePoint savePoint = createSavePoint();
         assignmentTarget = parseDestructuringPattern(context, kind, exportType, duplicateIdentifier, hasDestructuringPattern, bindingContext, depth);
-        if (assignmentTarget && !match(DOT) && !match(OPENBRACKET) && !match(OPENPAREN) && !match(TEMPLATE))
+        if (assignmentTarget && !match(DOT) && !match(OPENBRACKET) && !match(OPENPAREN) && !match(BACKQUOTE))
             return assignmentTarget;
         restoreSavePoint(savePoint);
     }
@@ -4089,11 +4089,13 @@
 template <typename LexerType>
 template <class TreeBuilder> typename TreeBuilder::TemplateString Parser<LexerType>::parseTemplateString(TreeBuilder& context, bool isTemplateHead, typename LexerType::RawStringsBuildMode rawStringsBuildMode, bool& elementIsTail)
 {
-    if (!isTemplateHead) {
+    if (isTemplateHead)
+        ASSERT(match(BACKQUOTE));
+    else
         matchOrFail(CLOSEBRACE, "Expected a closing '}' following an _expression_ in template literal");
-        // Re-scan the token to recognize it as Template Element.
-        m_token.m_type = m_lexer->scanTrailingTemplateString(&m_token, rawStringsBuildMode);
-    }
+
+    // Re-scan the token to recognize it as Template Element.
+    m_token.m_type = m_lexer->scanTemplateString(&m_token, rawStringsBuildMode);
     matchOrFail(TEMPLATE, "Expected an template element");
     const Identifier* cooked = m_token.m_data.cooked;
     const Identifier* raw = m_token.m_data.raw;
@@ -4100,12 +4102,13 @@
     elementIsTail = m_token.m_data.isTail;
     JSTokenLocation location(tokenLocation());
     next();
-    return context.createTemplateString(location, *cooked, *raw);
+    return context.createTemplateString(location, cooked, raw);
 }
 
 template <typename LexerType>
 template <class TreeBuilder> typename TreeBuilder::TemplateLiteral Parser<LexerType>::parseTemplateLiteral(TreeBuilder& context, typename LexerType::RawStringsBuildMode rawStringsBuildMode)
 {
+    ASSERT(match(BACKQUOTE));
     JSTokenLocation location(tokenLocation());
     bool elementIsTail = false;
 
@@ -4268,7 +4271,7 @@
         }
         return re;
     }
-    case TEMPLATE:
+    case BACKQUOTE:
         return parseTemplateLiteral(context, LexerType::RawStringsBuildMode::DontBuildRawStrings);
     case YIELD:
         if (!strictMode() && !currentScope()->isGenerator())
@@ -4505,7 +4508,7 @@
             next();
             break;
         }
-        case TEMPLATE: {
+        case BACKQUOTE: {
             semanticFailIfTrue(baseIsSuper, "Cannot use super as tag for tagged templates");
             JSTextPosition expressionEnd = lastTokenEndPosition();
             int nonLHSCount = m_parserState.nonLHSCount;

Modified: trunk/Source/_javascript_Core/parser/ParserTokens.h (211318 => 211319)


--- trunk/Source/_javascript_Core/parser/ParserTokens.h	2017-01-28 02:27:56 UTC (rev 211318)
+++ trunk/Source/_javascript_Core/parser/ParserTokens.h	2017-01-28 03:09:12 UTC (rev 211319)
@@ -109,6 +109,7 @@
     CLOSEBRACKET,
     COMMA,
     QUESTION,
+    BACKQUOTE,
     INTEGER,
     DOUBLE,
     IDENT,

Modified: trunk/Source/_javascript_Core/parser/SyntaxChecker.h (211318 => 211319)


--- trunk/Source/_javascript_Core/parser/SyntaxChecker.h	2017-01-28 02:27:56 UTC (rev 211318)
+++ trunk/Source/_javascript_Core/parser/SyntaxChecker.h	2017-01-28 03:09:12 UTC (rev 211319)
@@ -194,7 +194,7 @@
     int createArguments() { return ArgumentsResult; }
     int createArguments(int) { return ArgumentsResult; }
     ExpressionType createSpreadExpression(const JSTokenLocation&, ExpressionType, int, int, int) { return SpreadExpr; }
-    TemplateString createTemplateString(const JSTokenLocation&, const Identifier&, const Identifier&) { return TemplateStringResult; }
+    TemplateString createTemplateString(const JSTokenLocation&, const Identifier*, const Identifier*) { return TemplateStringResult; }
     TemplateStringList createTemplateStringList(TemplateString) { return TemplateStringListResult; }
     TemplateStringList createTemplateStringList(TemplateStringList, TemplateString) { return TemplateStringListResult; }
     TemplateExpressionList createTemplateExpressionList(_expression_) { return TemplateExpressionListResult; }

Modified: trunk/Source/_javascript_Core/runtime/TemplateRegistry.cpp (211318 => 211319)


--- trunk/Source/_javascript_Core/runtime/TemplateRegistry.cpp	2017-01-28 02:27:56 UTC (rev 211318)
+++ trunk/Source/_javascript_Core/runtime/TemplateRegistry.cpp	2017-01-28 03:09:12 UTC (rev 211319)
@@ -58,8 +58,13 @@
     RETURN_IF_EXCEPTION(scope, nullptr);
 
     for (unsigned index = 0; index < count; ++index) {
-        templateObject->putDirectIndex(exec, index, jsString(exec, templateKey.cookedStrings()[index]), ReadOnly | DontDelete, PutDirectIndexLikePutDirect);
+        auto cooked = templateKey.cookedStrings()[index];
+        if (cooked)
+            templateObject->putDirectIndex(exec, index, jsString(exec, cooked.value()), ReadOnly | DontDelete, PutDirectIndexLikePutDirect);
+        else
+            templateObject->putDirectIndex(exec, index, jsUndefined(), ReadOnly | DontDelete, PutDirectIndexLikePutDirect);
         RETURN_IF_EXCEPTION(scope, nullptr);
+
         rawObject->putDirectIndex(exec, index, jsString(exec, templateKey.rawStrings()[index]), ReadOnly | DontDelete, PutDirectIndexLikePutDirect);
         RETURN_IF_EXCEPTION(scope, nullptr);
     }

Modified: trunk/Source/_javascript_Core/runtime/TemplateRegistryKey.h (211318 => 211319)


--- trunk/Source/_javascript_Core/runtime/TemplateRegistryKey.h	2017-01-28 02:27:56 UTC (rev 211318)
+++ trunk/Source/_javascript_Core/runtime/TemplateRegistryKey.h	2017-01-28 03:09:12 UTC (rev 211319)
@@ -38,6 +38,7 @@
 public:
     friend class TemplateRegistryKeyTable;
     typedef Vector<String, 4> StringVector;
+    typedef Vector<std::optional<String>, 4> OptionalStringVector;
 
     enum DeletedValueTag { DeletedValue };
     TemplateRegistryKey(DeletedValueTag);
@@ -51,7 +52,7 @@
     unsigned hash() const { return m_hash; }
 
     const StringVector& rawStrings() const { return m_rawStrings; }
-    const StringVector& cookedStrings() const { return m_cookedStrings; }
+    const OptionalStringVector& cookedStrings() const { return m_cookedStrings; }
 
     bool operator==(const TemplateRegistryKey& other) const { return m_hash == other.m_hash && m_rawStrings == other.m_rawStrings; }
     bool operator!=(const TemplateRegistryKey& other) const { return m_hash != other.m_hash || m_rawStrings != other.m_rawStrings; }
@@ -66,22 +67,22 @@
     ~TemplateRegistryKey();
 
 private:
-    static Ref<TemplateRegistryKey> create(const StringVector& rawStrings, const StringVector& cookedStrings)
+    static Ref<TemplateRegistryKey> create(StringVector&& rawStrings, OptionalStringVector&& cookedStrings)
     {
-        return adoptRef(*new TemplateRegistryKey(rawStrings, cookedStrings));
+        return adoptRef(*new TemplateRegistryKey(WTFMove(rawStrings), WTFMove(cookedStrings)));
     }
 
-    TemplateRegistryKey(const StringVector& rawStrings, const StringVector& cookedStrings);
+    TemplateRegistryKey(StringVector&& rawStrings, OptionalStringVector&& cookedStrings);
 
     TemplateRegistryKeyTable* m_table { nullptr };
     StringVector m_rawStrings;
-    StringVector m_cookedStrings;
+    OptionalStringVector m_cookedStrings;
     unsigned m_hash { 0 };
 };
 
-inline TemplateRegistryKey::TemplateRegistryKey(const StringVector& rawStrings, const StringVector& cookedStrings)
-    : m_rawStrings(rawStrings)
-    , m_cookedStrings(cookedStrings)
+inline TemplateRegistryKey::TemplateRegistryKey(StringVector&& rawStrings, OptionalStringVector&& cookedStrings)
+    : m_rawStrings(WTFMove(rawStrings))
+    , m_cookedStrings(WTFMove(cookedStrings))
     , m_hash(calculateHash(rawStrings))
 {
 }

Modified: trunk/Source/_javascript_Core/runtime/TemplateRegistryKeyTable.cpp (211318 => 211319)


--- trunk/Source/_javascript_Core/runtime/TemplateRegistryKeyTable.cpp	2017-01-28 02:27:56 UTC (rev 211318)
+++ trunk/Source/_javascript_Core/runtime/TemplateRegistryKeyTable.cpp	2017-01-28 03:09:12 UTC (rev 211319)
@@ -42,9 +42,9 @@
         key->m_table = nullptr;
 }
 
-Ref<TemplateRegistryKey> TemplateRegistryKeyTable::createKey(const TemplateRegistryKey::StringVector& rawStrings, const TemplateRegistryKey::StringVector& cookedStrings)
+Ref<TemplateRegistryKey> TemplateRegistryKeyTable::createKey(TemplateRegistryKey::StringVector&& rawStrings, TemplateRegistryKey::OptionalStringVector&& cookedStrings)
 {
-    auto key = TemplateRegistryKey::create(rawStrings, cookedStrings);
+    auto key = TemplateRegistryKey::create(WTFMove(rawStrings), WTFMove(cookedStrings));
     auto addResult = m_atomicTable.add<TemplateRegistryKeyTranslator>(key.ptr());
     if (addResult.isNewEntry)
         (*addResult.iterator)->m_table = this;

Modified: trunk/Source/_javascript_Core/runtime/TemplateRegistryKeyTable.h (211318 => 211319)


--- trunk/Source/_javascript_Core/runtime/TemplateRegistryKeyTable.h	2017-01-28 02:27:56 UTC (rev 211318)
+++ trunk/Source/_javascript_Core/runtime/TemplateRegistryKeyTable.h	2017-01-28 03:09:12 UTC (rev 211319)
@@ -36,10 +36,11 @@
     WTF_MAKE_NONCOPYABLE(TemplateRegistryKeyTable);
 public:
     using StringVector = Vector<String, 4>;
+    using OptionalStringVector = Vector<std::optional<String>, 4>;
 
     TemplateRegistryKeyTable() = default;
 
-    Ref<TemplateRegistryKey> createKey(const StringVector& rawStrings, const StringVector& cookedStrings);
+    Ref<TemplateRegistryKey> createKey(StringVector&& rawStrings, OptionalStringVector&& cookedStrings);
 
     void unregister(TemplateRegistryKey&);
 
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to