Title: [223124] trunk
Revision
223124
Author
[email protected]
Date
2017-10-09 22:53:12 -0700 (Mon, 09 Oct 2017)

Log Message

`async` should be able to be used as an imported binding name
https://bugs.webkit.org/show_bug.cgi?id=176573

Reviewed by Saam Barati.

JSTests:

* modules/import-default-async.js: Added.
* modules/import-named-async-as.js: Added.
* modules/import-named-async.js: Added.
* modules/import-named-async/target.js: Added.
* modules/import-namespace-async.js: Added.
* test262.yaml:

Source/_javascript_Core:

Previously, we have ASYNC keyword in the parser. This is introduced only for performance,
and ECMA262 spec does not categorize "async" to keyword. This makes parser code complicated,
since ASYNC should be handled as IDENT. If we missed this ASYNC keyword, we cause a bug.
For example, import declaration failed to bind imported binding to the name "async" because
the parser considered ASYNC as keyword.

This patch removes ASYNC keyword from the parser. By carefully handling ASYNC, we can keep
the current performance without using this ASYNC keyword.

We also add `escaped` field to token data since contextual keyword is valid only if it does
not contain any escape sequences. We fix bunch of contextual keyword use with this fix too
e.g. `of in for-of`. This improves test262 score.

* parser/Keywords.table:
* parser/Lexer.cpp:
(JSC::Lexer<LChar>::parseIdentifier):
(JSC::Lexer<UChar>::parseIdentifier):
(JSC::Lexer<CharacterType>::parseIdentifierSlowCase):
* parser/Parser.cpp:
(JSC::Parser<LexerType>::parseStatementListItem):
(JSC::Parser<LexerType>::parseForStatement):
(JSC::Parser<LexerType>::parseStatement):
(JSC::Parser<LexerType>::maybeParseAsyncFunctionDeclarationStatement):
(JSC::Parser<LexerType>::parseClass):
(JSC::Parser<LexerType>::parseExportDeclaration):
(JSC::Parser<LexerType>::parseAssignmentExpression):
(JSC::Parser<LexerType>::parseProperty):
(JSC::Parser<LexerType>::parsePrimaryExpression):
(JSC::Parser<LexerType>::parseMemberExpression):
(JSC::Parser<LexerType>::printUnexpectedTokenText):
* parser/Parser.h:
(JSC::Parser::matchContextualKeyword):
* parser/ParserTokens.h:
* runtime/CommonIdentifiers.h:

Modified Paths

Added Paths

Diff

Modified: trunk/JSTests/ChangeLog (223123 => 223124)


--- trunk/JSTests/ChangeLog	2017-10-10 05:11:27 UTC (rev 223123)
+++ trunk/JSTests/ChangeLog	2017-10-10 05:53:12 UTC (rev 223124)
@@ -1,3 +1,17 @@
+2017-10-09  Yusuke Suzuki  <[email protected]>
+
+        `async` should be able to be used as an imported binding name
+        https://bugs.webkit.org/show_bug.cgi?id=176573
+
+        Reviewed by Saam Barati.
+
+        * modules/import-default-async.js: Added.
+        * modules/import-named-async-as.js: Added.
+        * modules/import-named-async.js: Added.
+        * modules/import-named-async/target.js: Added.
+        * modules/import-namespace-async.js: Added.
+        * test262.yaml:
+
 2017-09-29  Filip Pizlo  <[email protected]>
 
         Enable gigacage on iOS

Added: trunk/JSTests/modules/import-default-async.js (0 => 223124)


--- trunk/JSTests/modules/import-default-async.js	                        (rev 0)
+++ trunk/JSTests/modules/import-default-async.js	2017-10-10 05:53:12 UTC (rev 223124)
@@ -0,0 +1,6 @@
+import { shouldBe } from "./resources/assert.js";
+import async from "./import-default-async.js"
+
+export default 42;
+
+shouldBe(async, 42);

Added: trunk/JSTests/modules/import-named-async/target.js (0 => 223124)


--- trunk/JSTests/modules/import-named-async/target.js	                        (rev 0)
+++ trunk/JSTests/modules/import-named-async/target.js	2017-10-10 05:53:12 UTC (rev 223124)
@@ -0,0 +1 @@
+export let async = 42;

Added: trunk/JSTests/modules/import-named-async-as.js (0 => 223124)


--- trunk/JSTests/modules/import-named-async-as.js	                        (rev 0)
+++ trunk/JSTests/modules/import-named-async-as.js	2017-10-10 05:53:12 UTC (rev 223124)
@@ -0,0 +1,6 @@
+import { shouldBe } from "./resources/assert.js";
+import { Cocoa as async } from "./import-named-async-as.js"
+
+export let Cocoa = 42;
+shouldBe(async, 42);
+shouldBe(Cocoa, 42);

Added: trunk/JSTests/modules/import-named-async.js (0 => 223124)


--- trunk/JSTests/modules/import-named-async.js	                        (rev 0)
+++ trunk/JSTests/modules/import-named-async.js	2017-10-10 05:53:12 UTC (rev 223124)
@@ -0,0 +1,4 @@
+import { shouldBe } from "./resources/assert.js";
+import { async } from "./import-named-async/target.js"
+
+shouldBe(async, 42);

Added: trunk/JSTests/modules/import-namespace-async.js (0 => 223124)


--- trunk/JSTests/modules/import-namespace-async.js	                        (rev 0)
+++ trunk/JSTests/modules/import-namespace-async.js	2017-10-10 05:53:12 UTC (rev 223124)
@@ -0,0 +1,5 @@
+import { shouldBe } from "./resources/assert.js";
+import * as async from "./import-namespace-async.js"
+
+export let Cocoa = 42;
+shouldBe(async.Cocoa, 42);

Modified: trunk/JSTests/test262.yaml (223123 => 223124)


--- trunk/JSTests/test262.yaml	2017-10-10 05:11:27 UTC (rev 223123)
+++ trunk/JSTests/test262.yaml	2017-10-10 05:53:12 UTC (rev 223124)
@@ -58868,11 +58868,11 @@
 - path: test262/test/language/eval-code/indirect/var-env-var-strict.js
   cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js"], [:strict]
 - path: test262/test/language/export/escaped-as-export-specifier.js
-  cmd: runTest262 :fail, "SyntaxError", ["../../../harness/assert.js", "../../../harness/sta.js"], [:module]
+  cmd: runTest262 :normal, "SyntaxError", ["../../../harness/assert.js", "../../../harness/sta.js"], [:module]
 - path: test262/test/language/export/escaped-default.js
   cmd: runTest262 :normal, "SyntaxError", ["../../../harness/assert.js", "../../../harness/sta.js"], [:module]
 - path: test262/test/language/export/escaped-from.js
-  cmd: runTest262 :fail, "SyntaxError", ["../../../harness/assert.js", "../../../harness/sta.js"], [:module]
+  cmd: runTest262 :normal, "SyntaxError", ["../../../harness/assert.js", "../../../harness/sta.js"], [:module]
 - path: test262/test/language/expressions/addition/S11.6.1_A1.js
   cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js"], []
 - path: test262/test/language/expressions/addition/S11.6.1_A1.js
@@ -77142,9 +77142,9 @@
 - path: test262/test/language/expressions/new.target/escaped-new.js
   cmd: runTest262 :normal, "SyntaxError", ["../../../../harness/assert.js", "../../../../harness/sta.js"], [:strict]
 - path: test262/test/language/expressions/new.target/escaped-target.js
-  cmd: runTest262 :fail, "SyntaxError", ["../../../../harness/assert.js", "../../../../harness/sta.js"], []
+  cmd: runTest262 :normal, "SyntaxError", ["../../../../harness/assert.js", "../../../../harness/sta.js"], []
 - path: test262/test/language/expressions/new.target/escaped-target.js
-  cmd: runTest262 :fail, "SyntaxError", ["../../../../harness/assert.js", "../../../../harness/sta.js"], [:strict]
+  cmd: runTest262 :normal, "SyntaxError", ["../../../../harness/assert.js", "../../../../harness/sta.js"], [:strict]
 - path: test262/test/language/expressions/new.target/value-via-call.js
   cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js"], []
 - path: test262/test/language/expressions/new.target/value-via-call.js
@@ -84264,11 +84264,11 @@
 - path: test262/test/language/import/dup-bound-names.js
   cmd: runTest262 :normal, "SyntaxError", ["../../../harness/assert.js", "../../../harness/sta.js"], [:module]
 - path: test262/test/language/import/escaped-as-import-specifier.js
-  cmd: runTest262 :fail, "SyntaxError", ["../../../harness/assert.js", "../../../harness/sta.js"], [:module]
+  cmd: runTest262 :normal, "SyntaxError", ["../../../harness/assert.js", "../../../harness/sta.js"], [:module]
 - path: test262/test/language/import/escaped-as-namespace-import.js
-  cmd: runTest262 :fail, "SyntaxError", ["../../../harness/assert.js", "../../../harness/sta.js"], [:module]
+  cmd: runTest262 :normal, "SyntaxError", ["../../../harness/assert.js", "../../../harness/sta.js"], [:module]
 - path: test262/test/language/import/escaped-from.js
-  cmd: runTest262 :fail, "SyntaxError", ["../../../harness/assert.js", "../../../harness/sta.js"], [:module]
+  cmd: runTest262 :normal, "SyntaxError", ["../../../harness/assert.js", "../../../harness/sta.js"], [:module]
 - path: test262/test/language/keywords/ident-ref-break.js
   cmd: runTest262 :normal, "SyntaxError", ["../../../harness/assert.js", "../../../harness/sta.js"], []
 - path: test262/test/language/keywords/ident-ref-break.js
@@ -102026,9 +102026,9 @@
 - path: test262/test/language/statements/for-await-of/async-gen-dstr-var-obj-ptrn-rest-val-obj.js
   cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js", "../../../../harness/propertyHelper.js", "../../../../harness/doneprintHandle.js"], [:strict, :async]
 - path: test262/test/language/statements/for-await-of/escaped-of.js
-  cmd: runTest262 :fail, "SyntaxError", ["../../../../harness/assert.js", "../../../../harness/sta.js"], []
+  cmd: runTest262 :normal, "SyntaxError", ["../../../../harness/assert.js", "../../../../harness/sta.js"], []
 - path: test262/test/language/statements/for-await-of/escaped-of.js
-  cmd: runTest262 :fail, "SyntaxError", ["../../../../harness/assert.js", "../../../../harness/sta.js"], [:strict]
+  cmd: runTest262 :normal, "SyntaxError", ["../../../../harness/assert.js", "../../../../harness/sta.js"], [:strict]
 - path: test262/test/language/statements/for-await-of/let-array-with-newline.js
   cmd: runTest262 :fail, "SyntaxError", ["../../../../harness/assert.js", "../../../../harness/sta.js"], []
 - path: test262/test/language/statements/for-await-of/let-block-with-newline.js
@@ -104616,9 +104616,9 @@
 - path: test262/test/language/statements/for-of/dstr-var-obj-ptrn-rest-val-obj.js
   cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js", "../../../../harness/propertyHelper.js"], [:strict]
 - path: test262/test/language/statements/for-of/escaped-of.js
-  cmd: runTest262 :fail, "SyntaxError", ["../../../../harness/assert.js", "../../../../harness/sta.js"], []
+  cmd: runTest262 :normal, "SyntaxError", ["../../../../harness/assert.js", "../../../../harness/sta.js"], []
 - path: test262/test/language/statements/for-of/escaped-of.js
-  cmd: runTest262 :fail, "SyntaxError", ["../../../../harness/assert.js", "../../../../harness/sta.js"], [:strict]
+  cmd: runTest262 :normal, "SyntaxError", ["../../../../harness/assert.js", "../../../../harness/sta.js"], [:strict]
 - path: test262/test/language/statements/for-of/float32array-mutate.js
   cmd: runTest262 :normal, "NoException", ["../../../../harness/assert.js", "../../../../harness/sta.js"], []
 - path: test262/test/language/statements/for-of/float32array-mutate.js

Modified: trunk/Source/_javascript_Core/ChangeLog (223123 => 223124)


--- trunk/Source/_javascript_Core/ChangeLog	2017-10-10 05:11:27 UTC (rev 223123)
+++ trunk/Source/_javascript_Core/ChangeLog	2017-10-10 05:53:12 UTC (rev 223124)
@@ -1,3 +1,45 @@
+2017-10-09  Yusuke Suzuki  <[email protected]>
+
+        `async` should be able to be used as an imported binding name
+        https://bugs.webkit.org/show_bug.cgi?id=176573
+
+        Reviewed by Saam Barati.
+
+        Previously, we have ASYNC keyword in the parser. This is introduced only for performance,
+        and ECMA262 spec does not categorize "async" to keyword. This makes parser code complicated,
+        since ASYNC should be handled as IDENT. If we missed this ASYNC keyword, we cause a bug.
+        For example, import declaration failed to bind imported binding to the name "async" because
+        the parser considered ASYNC as keyword.
+
+        This patch removes ASYNC keyword from the parser. By carefully handling ASYNC, we can keep
+        the current performance without using this ASYNC keyword.
+
+        We also add `escaped` field to token data since contextual keyword is valid only if it does
+        not contain any escape sequences. We fix bunch of contextual keyword use with this fix too
+        e.g. `of in for-of`. This improves test262 score.
+
+        * parser/Keywords.table:
+        * parser/Lexer.cpp:
+        (JSC::Lexer<LChar>::parseIdentifier):
+        (JSC::Lexer<UChar>::parseIdentifier):
+        (JSC::Lexer<CharacterType>::parseIdentifierSlowCase):
+        * parser/Parser.cpp:
+        (JSC::Parser<LexerType>::parseStatementListItem):
+        (JSC::Parser<LexerType>::parseForStatement):
+        (JSC::Parser<LexerType>::parseStatement):
+        (JSC::Parser<LexerType>::maybeParseAsyncFunctionDeclarationStatement):
+        (JSC::Parser<LexerType>::parseClass):
+        (JSC::Parser<LexerType>::parseExportDeclaration):
+        (JSC::Parser<LexerType>::parseAssignmentExpression):
+        (JSC::Parser<LexerType>::parseProperty):
+        (JSC::Parser<LexerType>::parsePrimaryExpression):
+        (JSC::Parser<LexerType>::parseMemberExpression):
+        (JSC::Parser<LexerType>::printUnexpectedTokenText):
+        * parser/Parser.h:
+        (JSC::Parser::matchContextualKeyword):
+        * parser/ParserTokens.h:
+        * runtime/CommonIdentifiers.h:
+
 2017-10-09  Saam Barati  <[email protected]>
 
         We don't need to clearEmptyObjectStructureForPrototype because JSGlobalObject* is part of the cache's key

Modified: trunk/Source/_javascript_Core/parser/Keywords.table (223123 => 223124)


--- trunk/Source/_javascript_Core/parser/Keywords.table	2017-10-10 05:11:27 UTC (rev 223123)
+++ trunk/Source/_javascript_Core/parser/Keywords.table	2017-10-10 05:53:12 UTC (rev 223124)
@@ -7,7 +7,6 @@
 false		FALSETOKEN
 
 # Keywords.
-async       ASYNC
 await       AWAIT
 break		BREAK
 case		CASE

Modified: trunk/Source/_javascript_Core/parser/Lexer.cpp (223123 => 223124)


--- trunk/Source/_javascript_Core/parser/Lexer.cpp	2017-10-10 05:11:27 UTC (rev 223123)
+++ trunk/Source/_javascript_Core/parser/Lexer.cpp	2017-10-10 05:53:12 UTC (rev 223124)
@@ -935,6 +935,7 @@
 template <>
 template <bool shouldCreateIdentifier> ALWAYS_INLINE JSTokenType Lexer<LChar>::parseIdentifier(JSTokenData* tokenData, unsigned lexerFlags, bool strictMode)
 {
+    tokenData->escaped = false;
     const ptrdiff_t remaining = m_codeEnd - m_code;
     if ((remaining >= maxTokenLength) && !(lexerFlags & LexerFlagsIgnoreReservedWords)) {
         JSTokenType keyword = parseKeyword<shouldCreateIdentifier>(tokenData);
@@ -959,7 +960,7 @@
         return parseIdentifierSlowCase<shouldCreateIdentifier>(tokenData, lexerFlags, strictMode);
     }
 
-    const Identifier* ident = 0;
+    const Identifier* ident = nullptr;
     
     if (shouldCreateIdentifier || m_parsingBuiltinFunction) {
         int identifierLength = currentSourcePtr() - identifierStart;
@@ -978,7 +979,7 @@
         }
         tokenData->ident = ident;
     } else
-        tokenData->ident = 0;
+        tokenData->ident = nullptr;
 
     if (UNLIKELY((remaining < maxTokenLength) && !(lexerFlags & LexerFlagsIgnoreReservedWords)) && !isPrivateName) {
         ASSERT(shouldCreateIdentifier);
@@ -999,6 +1000,7 @@
 template <>
 template <bool shouldCreateIdentifier> ALWAYS_INLINE JSTokenType Lexer<UChar>::parseIdentifier(JSTokenData* tokenData, unsigned lexerFlags, bool strictMode)
 {
+    tokenData->escaped = false;
     const ptrdiff_t remaining = m_codeEnd - m_code;
     if ((remaining >= maxTokenLength) && !(lexerFlags & LexerFlagsIgnoreReservedWords)) {
         JSTokenType keyword = parseKeyword<shouldCreateIdentifier>(tokenData);
@@ -1033,7 +1035,7 @@
     if (!(orAllChars & ~0xff))
         isAll8Bit = true;
 
-    const Identifier* ident = 0;
+    const Identifier* ident = nullptr;
     
     if (shouldCreateIdentifier || m_parsingBuiltinFunction) {
         int identifierLength = currentSourcePtr() - identifierStart;
@@ -1055,7 +1057,7 @@
         }
         tokenData->ident = ident;
     } else
-        tokenData->ident = 0;
+        tokenData->ident = nullptr;
     
     if (UNLIKELY((remaining < maxTokenLength) && !(lexerFlags & LexerFlagsIgnoreReservedWords)) && !isPrivateName) {
         ASSERT(shouldCreateIdentifier);
@@ -1075,6 +1077,7 @@
 
 template<typename CharacterType> template<bool shouldCreateIdentifier> JSTokenType Lexer<CharacterType>::parseIdentifierSlowCase(JSTokenData* tokenData, unsigned lexerFlags, bool strictMode)
 {
+    tokenData->escaped = true;
     auto identifierStart = currentSourcePtr();
     bool bufferRequired = false;
 

Modified: trunk/Source/_javascript_Core/parser/Parser.cpp (223123 => 223124)


--- trunk/Source/_javascript_Core/parser/Parser.cpp	2017-10-10 05:11:27 UTC (rev 223123)
+++ trunk/Source/_javascript_Core/parser/Parser.cpp	2017-10-10 05:53:12 UTC (rev 223124)
@@ -657,19 +657,19 @@
     case FUNCTION:
         result = parseFunctionDeclaration(context);
         break;
-    case ASYNC: {
-        // Eagerly parse as AsyncFunctionDeclaration. This is the uncommon case,
-        // but could be mistakenly parsed as an AsyncFunctionExpression.
-        SavePoint savePoint = createSavePoint();
-        next();
-        if (UNLIKELY(match(FUNCTION) && !m_lexer->prevTerminator())) {
-            result = parseAsyncFunctionDeclaration(context);
-            break;
+    case IDENT:
+        if (UNLIKELY(*m_token.m_data.ident == m_vm->propertyNames->async && !m_token.m_data.escaped)) {
+            // Eagerly parse as AsyncFunctionDeclaration. This is the uncommon case,
+            // but could be mistakenly parsed as an AsyncFunctionExpression.
+            SavePoint savePoint = createSavePoint();
+            next();
+            if (UNLIKELY(match(FUNCTION) && !m_lexer->prevTerminator())) {
+                result = parseAsyncFunctionDeclaration(context);
+                break;
+            }
+            restoreSavePoint(savePoint);
         }
-        restoreSavePoint(savePoint);
         FALLTHROUGH;
-    }
-    case IDENT:
     case AWAIT:
     case YIELD: {
         // This is a convenient place to notice labeled statements
@@ -1349,7 +1349,7 @@
         JSTextPosition inLocation = tokenStartPosition();
         bool isOfEnumeration = false;
         if (!match(INTOKEN)) {
-            failIfFalse(match(IDENT) && *m_token.m_data.ident == m_vm->propertyNames->of, "Expected either 'in' or 'of' in enumeration syntax");
+            failIfFalse(matchContextualKeyword(m_vm->propertyNames->of), "Expected either 'in' or 'of' in enumeration syntax");
             isOfEnumeration = true;
             next();
         } else {
@@ -1399,7 +1399,7 @@
             declsStart = tokenStartPosition();
             pattern = tryParseDestructuringPatternExpression(context, AssignmentContext::DeclarationStatement);
             declsEnd = lastTokenEndPosition();
-            if (pattern && (match(INTOKEN) || (match(IDENT) && *m_token.m_data.ident == m_vm->propertyNames->of)))
+            if (pattern && (match(INTOKEN) || matchContextualKeyword(m_vm->propertyNames->of)))
                 goto enumerationLoop;
             pattern = TreeDestructuringPattern(0);
             restoreSavePoint(savePoint);
@@ -1454,7 +1454,7 @@
     failIfFalse(nonLHSCount == m_parserState.nonLHSCount, "Expected a reference on the left hand side of an enumeration statement");
     bool isOfEnumeration = false;
     if (!match(INTOKEN)) {
-        failIfFalse(match(IDENT) && *m_token.m_data.ident == m_vm->propertyNames->of, "Expected either 'in' or 'of' in enumeration syntax");
+        failIfFalse(matchContextualKeyword(m_vm->propertyNames->of), "Expected either 'in' or 'of' in enumeration syntax");
         isOfEnumeration = true;
         next();
     } else {
@@ -1899,11 +1899,12 @@
             goto identcase;
         goto defaultCase;
     }
-    case ASYNC:
-        if (maybeParseAsyncFunctionDeclarationStatement(context, result, parentAllowsFunctionDeclarationAsStatement))
-            break;
+    case IDENT:
+        if (UNLIKELY(*m_token.m_data.ident == m_vm->propertyNames->async && !m_token.m_data.escaped)) {
+            if (maybeParseAsyncFunctionDeclarationStatement(context, result, parentAllowsFunctionDeclarationAsStatement))
+                break;
+        }
         FALLTHROUGH;
-    case IDENT:
     case AWAIT:
     case YIELD: {
         identcase:
@@ -1988,7 +1989,7 @@
 template <typename LexerType>
 template <class TreeBuilder> bool Parser<LexerType>::maybeParseAsyncFunctionDeclarationStatement(TreeBuilder& context, TreeStatement& result, bool parentAllowsFunctionDeclarationAsStatement)
 {
-    ASSERT(match(ASYNC));
+    ASSERT(matchContextualKeyword(m_vm->propertyNames->async));
     SavePoint savePoint = createSavePoint();
     next();
     if (match(FUNCTION) && !m_lexer->prevTerminator()) {
@@ -2835,20 +2836,21 @@
             ASSERT(ident);
             next();
             break;
-        case ASYNC:
-            if (!isGeneratorMethodParseMode(parseMode) && !isAsyncMethodParseMode(parseMode)) {
-                ident = m_token.m_data.ident;
-                next();
-                if (match(OPENPAREN) || match(COLON) || match(EQUAL) || m_lexer->prevTerminator())
-                    break;
-                if (Options::useAsyncIterator() && UNLIKELY(consume(TIMES)))
-                    parseMode = SourceParseMode::AsyncGeneratorWrapperMethodMode;
-                else
-                    parseMode = SourceParseMode::AsyncMethodMode;
-                goto parseMethod;
+        case IDENT:
+            if (UNLIKELY(*m_token.m_data.ident == m_vm->propertyNames->async && !m_token.m_data.escaped)) {
+                if (!isGeneratorMethodParseMode(parseMode) && !isAsyncMethodParseMode(parseMode)) {
+                    ident = m_token.m_data.ident;
+                    next();
+                    if (match(OPENPAREN) || match(COLON) || match(EQUAL) || m_lexer->prevTerminator())
+                        break;
+                    if (Options::useAsyncIterator() && UNLIKELY(consume(TIMES)))
+                        parseMode = SourceParseMode::AsyncGeneratorWrapperMethodMode;
+                    else
+                        parseMode = SourceParseMode::AsyncMethodMode;
+                    goto parseMethod;
+                }
             }
             FALLTHROUGH;
-        case IDENT:
         case AWAIT:
             ident = m_token.m_data.ident;
             ASSERT(ident);
@@ -3369,7 +3371,7 @@
             if (match(IDENT))
                 localName = m_token.m_data.ident;
             restoreSavePoint(savePoint);
-        } else if (match(ASYNC)) {
+        } else if (matchContextualKeyword(m_vm->propertyNames->async)) {
             SavePoint savePoint = createSavePoint();
             next();
             if (match(FUNCTION) && !m_lexer->prevTerminator()) {
@@ -3393,7 +3395,7 @@
             } else if (match(CLASSTOKEN)) {
                 result = parseClassDeclaration(context, ExportType::NotExported, DeclarationDefaultContext::ExportDefault);
             } else {
-                ASSERT(match(ASYNC));
+                ASSERT(matchContextualKeyword(m_vm->propertyNames->async));
                 next();
                 DepthManager statementDepth(&m_statementDepth);
                 m_statementDepth = 1;
@@ -3514,15 +3516,16 @@
             result = parseClassDeclaration(context, ExportType::Exported);
             break;
 
-        case ASYNC: {
-            next();
-            semanticFailIfFalse(match(FUNCTION) && !m_lexer->prevTerminator(), "Expected 'function' keyword following 'async' keyword with no preceding line terminator");
-            DepthManager statementDepth(&m_statementDepth);
-            m_statementDepth = 1;
-            result = parseAsyncFunctionDeclaration(context, ExportType::Exported);
-            break;
-        }
-
+        case IDENT:
+            if (*m_token.m_data.ident == m_vm->propertyNames->async && !m_token.m_data.escaped) {
+                next();
+                semanticFailIfFalse(match(FUNCTION) && !m_lexer->prevTerminator(), "Expected 'function' keyword following 'async' keyword with no preceding line terminator");
+                DepthManager statementDepth(&m_statementDepth);
+                m_statementDepth = 1;
+                result = parseAsyncFunctionDeclaration(context, ExportType::Exported);
+                break;
+            }
+            FALLTHROUGH;
         default:
             failWithMessage("Expected either a declaration or a variable statement");
             break;
@@ -3620,7 +3623,7 @@
             restoreSavePoint(savePoint);
             bool isAsyncArrow = false;
             if (UNLIKELY(classifier.indicatesPossibleAsyncArrowFunction())) {
-                ASSERT(match(ASYNC));
+                ASSERT(matchContextualKeyword(m_vm->propertyNames->async));
                 next();
                 isAsyncArrow = !m_lexer->prevTerminator();
             }
@@ -3888,26 +3891,27 @@
 
 parseProperty:
     switch (m_token.m_type) {
-    case ASYNC:
-        if (parseMode == SourceParseMode::MethodMode) {
-            SavePoint savePoint = createSavePoint();
-            next();
+    case IDENT:
+        if (UNLIKELY(*m_token.m_data.ident == m_vm->propertyNames->async && !m_token.m_data.escaped)) {
+            if (parseMode == SourceParseMode::MethodMode) {
+                SavePoint savePoint = createSavePoint();
+                next();
 
-            if (match(COLON) || match(OPENPAREN) || match(COMMA) || match(CLOSEBRACE)) {
-                restoreSavePoint(savePoint);
-                wasIdent = true;
-                goto namedProperty;
+                if (match(COLON) || match(OPENPAREN) || match(COMMA) || match(CLOSEBRACE)) {
+                    restoreSavePoint(savePoint);
+                    wasIdent = true;
+                    goto namedProperty;
+                }
+
+                failIfTrue(m_lexer->prevTerminator(), "Expected a property name following keyword 'async'");
+                if (Options::useAsyncIterator() && UNLIKELY(consume(TIMES)))
+                    parseMode = SourceParseMode::AsyncGeneratorWrapperMethodMode;
+                else
+                    parseMode = SourceParseMode::AsyncMethodMode;
+                goto parseProperty;
             }
-
-            failIfTrue(m_lexer->prevTerminator(), "Expected a property name following keyword 'async'");
-            if (Options::useAsyncIterator() && UNLIKELY(consume(TIMES)))
-                parseMode = SourceParseMode::AsyncGeneratorWrapperMethodMode;
-            else
-                parseMode = SourceParseMode::AsyncMethodMode;
-            goto parseProperty;
         }
         FALLTHROUGH;
-    case IDENT:
     case YIELD:
     case AWAIT:
         wasIdent = true;
@@ -4448,22 +4452,22 @@
             return parseAwaitExpression(context);
 
         goto identifierExpression;
-    case ASYNC: {
-        JSTextPosition start = tokenStartPosition();
-        const Identifier* ident = m_token.m_data.ident;
-        JSTokenLocation location(tokenLocation());
-        next();
-        if (match(FUNCTION) && !m_lexer->prevTerminator())
-            return parseAsyncFunctionExpression(context);
+    case IDENT: {
+        if (UNLIKELY(*m_token.m_data.ident == m_vm->propertyNames->async && !m_token.m_data.escaped)) {
+            JSTextPosition start = tokenStartPosition();
+            const Identifier* ident = m_token.m_data.ident;
+            JSTokenLocation location(tokenLocation());
+            next();
+            if (match(FUNCTION) && !m_lexer->prevTerminator())
+                return parseAsyncFunctionExpression(context);
 
-        // Avoid using variable if it is an arrow function parameter
-        if (UNLIKELY(match(ARROWFUNCTION)))
-            return 0;
+            // Avoid using variable if it is an arrow function parameter
+            if (UNLIKELY(match(ARROWFUNCTION)))
+                return 0;
 
-        const bool isEval = false;
-        return createResolveAndUseVariable(context, ident, isEval, start, location);
-    }
-    case IDENT: {
+            const bool isEval = false;
+            return createResolveAndUseVariable(context, ident, isEval, start, location);
+        }
     identifierExpression:
         JSTextPosition start = tokenStartPosition();
         const Identifier* ident = m_token.m_data.ident;
@@ -4649,23 +4653,21 @@
     bool baseIsNewTarget = false;
     if (newCount && match(DOT)) {
         next();
-        if (match(IDENT)) {
-            const Identifier* ident = m_token.m_data.ident;
-            if (m_vm->propertyNames->target == *ident) {
-                ScopeRef closestOrdinaryFunctionScope = closestParentOrdinaryFunctionNonLexicalScope();
-                semanticFailIfFalse(currentScope()->isFunction() || closestOrdinaryFunctionScope->evalContextType() == EvalContextType::FunctionEvalContext, "new.target is only valid inside functions");
-                baseIsNewTarget = true;
-                if (currentScope()->isArrowFunction()) {
-                    semanticFailIfFalse(!closestOrdinaryFunctionScope->isGlobalCodeScope() || closestOrdinaryFunctionScope->evalContextType() == EvalContextType::FunctionEvalContext, "new.target is not valid inside arrow functions in global code");
-                    currentScope()->setInnerArrowFunctionUsesNewTarget();
-                }
-                base = context.createNewTargetExpr(location);
-                newCount--;
-                next();
-            } else
-                failWithMessage("\"new.\" can only followed with target");
-        } else
+        if (matchContextualKeyword(m_vm->propertyNames->target)) {
+            ScopeRef closestOrdinaryFunctionScope = closestParentOrdinaryFunctionNonLexicalScope();
+            semanticFailIfFalse(currentScope()->isFunction() || closestOrdinaryFunctionScope->evalContextType() == EvalContextType::FunctionEvalContext, "new.target is only valid inside functions");
+            baseIsNewTarget = true;
+            if (currentScope()->isArrowFunction()) {
+                semanticFailIfFalse(!closestOrdinaryFunctionScope->isGlobalCodeScope() || closestOrdinaryFunctionScope->evalContextType() == EvalContextType::FunctionEvalContext, "new.target is not valid inside arrow functions in global code");
+                currentScope()->setInnerArrowFunctionUsesNewTarget();
+            }
+            base = context.createNewTargetExpr(location);
+            newCount--;
+            next();
+        } else {
+            failIfTrue(match(IDENT), "\"new.\" can only followed with target");
             failDueToUnexpectedToken();
+        }
     }
 
     bool baseIsAsyncKeyword = false;
@@ -4691,17 +4693,16 @@
         next();
         JSTextPosition expressionEnd = lastTokenEndPosition();
         if (consume(DOT)) {
-            if (!match(IDENT))
+            if (matchContextualKeyword(m_vm->propertyNames->builtinNames().metaPublicName())) {
+                semanticFailIfFalse(m_scriptMode == JSParserScriptMode::Module, "import.meta is only valid inside modules");
+
+                JSTokenLocation location(tokenLocation());
+                base = createResolveAndUseVariable(context, &m_vm->propertyNames->builtinNames().metaPrivateName(), false, expressionStart, location);
+                next();
+            } else {
+                failIfTrue(match(IDENT), "\"import.\" can only followed with meta");
                 failDueToUnexpectedToken();
-            const Identifier* ident = m_token.m_data.ident;
-            if (m_vm->propertyNames->builtinNames().metaPublicName() != *ident)
-                failWithMessage("\"import.\" can only followed with meta");
-
-            semanticFailIfFalse(m_scriptMode == JSParserScriptMode::Module, "import.meta is only valid inside modules");
-
-            JSTokenLocation location(tokenLocation());
-            base = createResolveAndUseVariable(context, &m_vm->propertyNames->builtinNames().metaPrivateName(), false, expressionStart, location);
-            next();
+            }
         } else {
             consumeOrFail(OPENPAREN, "import call expects exactly one argument");
             TreeExpression expr = parseAssignmentExpression(context);
@@ -4710,7 +4711,7 @@
             base = context.createImportExpr(location, expr, expressionStart, expressionEnd, lastTokenEndPosition());
         }
     } else if (!baseIsNewTarget) {
-        const bool isAsync = match(ASYNC);
+        const bool isAsync = matchContextualKeyword(m_vm->propertyNames->async);
 
         base = parsePrimaryExpression(context);
         failIfFalse(base, "Cannot parse base _expression_");
@@ -5067,7 +5068,6 @@
         out.print("Invalid private name '", getToken(), "'");
         return;
             
-    case ASYNC:
     case AWAIT:
     case IDENT:
         out.print("Unexpected identifier '", getToken(), "'");

Modified: trunk/Source/_javascript_Core/parser/Parser.h (223123 => 223124)


--- trunk/Source/_javascript_Core/parser/Parser.h	2017-10-10 05:11:27 UTC (rev 223123)
+++ trunk/Source/_javascript_Core/parser/Parser.h	2017-10-10 05:53:12 UTC (rev 223124)
@@ -1370,7 +1370,7 @@
     
     ALWAYS_INLINE bool matchContextualKeyword(const Identifier& identifier)
     {
-        return m_token.m_type == IDENT && *m_token.m_data.ident == identifier;
+        return m_token.m_type == IDENT && *m_token.m_data.ident == identifier && !m_token.m_data.escaped;
     }
 
     ALWAYS_INLINE bool matchIdentifierOrKeyword()

Modified: trunk/Source/_javascript_Core/parser/ParserTokens.h (223123 => 223124)


--- trunk/Source/_javascript_Core/parser/ParserTokens.h	2017-10-10 05:11:27 UTC (rev 223123)
+++ trunk/Source/_javascript_Core/parser/ParserTokens.h	2017-10-10 05:53:12 UTC (rev 223124)
@@ -93,10 +93,9 @@
     LET,
     YIELD,
     AWAIT,
-    ASYNC,
 
     FirstContextualKeywordToken = LET,
-    LastContextualKeywordToken = ASYNC,
+    LastContextualKeywordToken = AWAIT,
     FirstSafeContextualKeywordToken = AWAIT,
     LastSafeContextualKeywordToken = LastContextualKeywordToken,
 
@@ -214,8 +213,11 @@
         uint32_t lineStartOffset;
     };
     double doubleValue;
-    const Identifier* ident;
     struct {
+        const Identifier* ident;
+        bool escaped;
+    };
+    struct {
         const Identifier* cooked;
         const Identifier* raw;
         bool isTail;

Modified: trunk/Source/_javascript_Core/runtime/CommonIdentifiers.h (223123 => 223124)


--- trunk/Source/_javascript_Core/runtime/CommonIdentifiers.h	2017-10-10 05:11:27 UTC (rev 223123)
+++ trunk/Source/_javascript_Core/runtime/CommonIdentifiers.h	2017-10-10 05:53:12 UTC (rev 223124)
@@ -79,6 +79,7 @@
     macro(arguments) \
     macro(as) \
     macro(assign) \
+    macro(async) \
     macro(back) \
     macro(bind) \
     macro(buffer) \
@@ -219,7 +220,6 @@
     macro(year)
 
 #define JSC_COMMON_IDENTIFIERS_EACH_KEYWORD(macro) \
-    macro(async) \
     macro(await) \
     macro(break) \
     macro(case) \
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to