Title: [223022] trunk
Revision
223022
Author
[email protected]
Date
2017-10-07 14:16:24 -0700 (Sat, 07 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 Darin Adler.

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.

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.

* parser/Keywords.table:
* parser/Parser.cpp:
(JSC::Parser<LexerType>::parseStatementListItem):
(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/ParserTokens.h:
* runtime/CommonIdentifiers.h:

Modified Paths

Added Paths

Diff

Modified: trunk/JSTests/ChangeLog (223021 => 223022)


--- trunk/JSTests/ChangeLog	2017-10-07 19:24:04 UTC (rev 223021)
+++ trunk/JSTests/ChangeLog	2017-10-07 21:16:24 UTC (rev 223022)
@@ -1,3 +1,16 @@
+2017-10-07  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 Darin Adler.
+
+        * 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.
+
 2017-09-29  Filip Pizlo  <[email protected]>
 
         Enable gigacage on iOS

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


--- trunk/JSTests/modules/import-default-async.js	                        (rev 0)
+++ trunk/JSTests/modules/import-default-async.js	2017-10-07 21:16:24 UTC (rev 223022)
@@ -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 => 223022)


--- trunk/JSTests/modules/import-named-async/target.js	                        (rev 0)
+++ trunk/JSTests/modules/import-named-async/target.js	2017-10-07 21:16:24 UTC (rev 223022)
@@ -0,0 +1 @@
+export let async = 42;

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


--- trunk/JSTests/modules/import-named-async-as.js	                        (rev 0)
+++ trunk/JSTests/modules/import-named-async-as.js	2017-10-07 21:16:24 UTC (rev 223022)
@@ -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 => 223022)


--- trunk/JSTests/modules/import-named-async.js	                        (rev 0)
+++ trunk/JSTests/modules/import-named-async.js	2017-10-07 21:16:24 UTC (rev 223022)
@@ -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 => 223022)


--- trunk/JSTests/modules/import-namespace-async.js	                        (rev 0)
+++ trunk/JSTests/modules/import-namespace-async.js	2017-10-07 21:16:24 UTC (rev 223022)
@@ -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/Source/_javascript_Core/ChangeLog (223021 => 223022)


--- trunk/Source/_javascript_Core/ChangeLog	2017-10-07 19:24:04 UTC (rev 223021)
+++ trunk/Source/_javascript_Core/ChangeLog	2017-10-07 21:16:24 UTC (rev 223022)
@@ -1,3 +1,34 @@
+2017-10-07  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 Darin Adler.
+
+        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.
+
+        * parser/Keywords.table:
+        * parser/Parser.cpp:
+        (JSC::Parser<LexerType>::parseStatementListItem):
+        (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/ParserTokens.h:
+        * runtime/CommonIdentifiers.h:
+
 2017-09-29  Filip Pizlo  <[email protected]>
 
         Enable gigacage on iOS

Modified: trunk/Source/_javascript_Core/parser/Keywords.table (223021 => 223022)


--- trunk/Source/_javascript_Core/parser/Keywords.table	2017-10-07 19:24:04 UTC (rev 223021)
+++ trunk/Source/_javascript_Core/parser/Keywords.table	2017-10-07 21:16:24 UTC (rev 223022)
@@ -7,7 +7,6 @@
 false		FALSETOKEN
 
 # Keywords.
-async       ASYNC
 await       AWAIT
 break		BREAK
 case		CASE

Modified: trunk/Source/_javascript_Core/parser/Parser.cpp (223021 => 223022)


--- trunk/Source/_javascript_Core/parser/Parser.cpp	2017-10-07 19:24:04 UTC (rev 223021)
+++ trunk/Source/_javascript_Core/parser/Parser.cpp	2017-10-07 21:16:24 UTC (rev 223022)
@@ -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)) {
+            // 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
@@ -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)) {
+            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)) {
+                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) {
+                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)) {
+            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;
@@ -4445,22 +4449,22 @@
         if (m_parserState.functionParsePhase == FunctionParsePhase::Parameters)
             failIfFalse(m_parserState.allowAwait, "Cannot use await _expression_ within parameters");
         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)) {
+            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;
@@ -4707,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_");
@@ -5064,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/ParserTokens.h (223021 => 223022)


--- trunk/Source/_javascript_Core/parser/ParserTokens.h	2017-10-07 19:24:04 UTC (rev 223021)
+++ trunk/Source/_javascript_Core/parser/ParserTokens.h	2017-10-07 21:16:24 UTC (rev 223022)
@@ -93,10 +93,9 @@
     LET,
     YIELD,
     AWAIT,
-    ASYNC,
 
     FirstContextualKeywordToken = LET,
-    LastContextualKeywordToken = ASYNC,
+    LastContextualKeywordToken = AWAIT,
     FirstSafeContextualKeywordToken = AWAIT,
     LastSafeContextualKeywordToken = LastContextualKeywordToken,
 

Modified: trunk/Source/_javascript_Core/runtime/CommonIdentifiers.h (223021 => 223022)


--- trunk/Source/_javascript_Core/runtime/CommonIdentifiers.h	2017-10-07 19:24:04 UTC (rev 223021)
+++ trunk/Source/_javascript_Core/runtime/CommonIdentifiers.h	2017-10-07 21:16:24 UTC (rev 223022)
@@ -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