import.meta should not be assignable
authorutatane.tea@gmail.com <utatane.tea@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 12 Oct 2017 06:45:23 +0000 (06:45 +0000)
committerutatane.tea@gmail.com <utatane.tea@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 12 Oct 2017 06:45:23 +0000 (06:45 +0000)
https://bugs.webkit.org/show_bug.cgi?id=178202

Reviewed by Saam Barati.

JSTests:

* modules/import-meta-assignment.js: Added.
(shouldThrow):
(SyntaxError.import.meta.can.shouldThrow):

Source/JavaScriptCore:

`import.meta` cannot be used for LHS. This patch adds MetaPropertyNode
and make NewTargetNode and ImportMetaNode as derived classes of MetaPropertyNode.
We change the parser not to allow assignments for MetaPropertyNode.

* bytecompiler/NodesCodegen.cpp:
(JSC::ImportMetaNode::emitBytecode):
* parser/ASTBuilder.h:
(JSC::ASTBuilder::createImportMetaExpr):
(JSC::ASTBuilder::isMetaProperty):
(JSC::ASTBuilder::isImportMeta):
* parser/NodeConstructors.h:
(JSC::MetaPropertyNode::MetaPropertyNode):
(JSC::NewTargetNode::NewTargetNode):
(JSC::ImportMetaNode::ImportMetaNode):
* parser/Nodes.h:
(JSC::ExpressionNode::isMetaProperty const):
(JSC::ExpressionNode::isImportMeta const):
* parser/Parser.cpp:
(JSC::Parser<LexerType>::metaPropertyName):
(JSC::Parser<LexerType>::parseAssignmentExpression):
(JSC::Parser<LexerType>::parseMemberExpression):
(JSC::Parser<LexerType>::parseUnaryExpression):
* parser/Parser.h:
* parser/SyntaxChecker.h:
(JSC::SyntaxChecker::createImportMetaExpr):
(JSC::SyntaxChecker::isMetaProperty):
(JSC::SyntaxChecker::isImportMeta):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@223232 268f45cc-cd09-0410-ab3c-d52691b4dbfc

JSTests/ChangeLog
JSTests/modules/import-meta-assignment.js [new file with mode: 0644]
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
Source/JavaScriptCore/parser/ASTBuilder.h
Source/JavaScriptCore/parser/NodeConstructors.h
Source/JavaScriptCore/parser/Nodes.h
Source/JavaScriptCore/parser/Parser.cpp
Source/JavaScriptCore/parser/Parser.h
Source/JavaScriptCore/parser/SyntaxChecker.h

index 6d139a8..285363f 100644 (file)
@@ -1,3 +1,14 @@
+2017-10-11  Yusuke Suzuki  <utatane.tea@gmail.com>
+
+        import.meta should not be assignable
+        https://bugs.webkit.org/show_bug.cgi?id=178202
+
+        Reviewed by Saam Barati.
+
+        * modules/import-meta-assignment.js: Added.
+        (shouldThrow):
+        (SyntaxError.import.meta.can.shouldThrow):
+
 2017-10-11  Saam Barati  <sbarati@apple.com>
 
         Unreviewed. Actually skip certain type profiler tests in debug.
diff --git a/JSTests/modules/import-meta-assignment.js b/JSTests/modules/import-meta-assignment.js
new file mode 100644 (file)
index 0000000..3e6b93f
--- /dev/null
@@ -0,0 +1,25 @@
+import { shouldThrow } from "./resources/assert.js";
+
+shouldThrow(() => {
+    checkModuleSyntax(`import.meta = 42`);
+}, `SyntaxError: import.meta can't be the left hand side of an assignment expression.:1`);
+
+shouldThrow(() => {
+    checkModuleSyntax(`import.meta += 42`);
+}, `SyntaxError: import.meta can't be the left hand side of an assignment expression.:1`);
+
+shouldThrow(() => {
+    checkModuleSyntax(`++import.meta`);
+}, `SyntaxError: import.meta can't come after a prefix operator.:1`);
+
+shouldThrow(() => {
+    checkModuleSyntax(`--import.meta`);
+}, `SyntaxError: import.meta can't come after a prefix operator.:1`);
+
+shouldThrow(() => {
+    checkModuleSyntax(`import.meta++`);
+}, `SyntaxError: import.meta can't come before a postfix operator.:1`);
+
+shouldThrow(() => {
+    checkModuleSyntax(`import.meta--`);
+}, `SyntaxError: import.meta can't come before a postfix operator.:1`);
index dad5336..56db9d9 100644 (file)
@@ -1,3 +1,38 @@
+2017-10-11  Yusuke Suzuki  <utatane.tea@gmail.com>
+
+        import.meta should not be assignable
+        https://bugs.webkit.org/show_bug.cgi?id=178202
+
+        Reviewed by Saam Barati.
+
+        `import.meta` cannot be used for LHS. This patch adds MetaPropertyNode
+        and make NewTargetNode and ImportMetaNode as derived classes of MetaPropertyNode.
+        We change the parser not to allow assignments for MetaPropertyNode.
+
+        * bytecompiler/NodesCodegen.cpp:
+        (JSC::ImportMetaNode::emitBytecode):
+        * parser/ASTBuilder.h:
+        (JSC::ASTBuilder::createImportMetaExpr):
+        (JSC::ASTBuilder::isMetaProperty):
+        (JSC::ASTBuilder::isImportMeta):
+        * parser/NodeConstructors.h:
+        (JSC::MetaPropertyNode::MetaPropertyNode):
+        (JSC::NewTargetNode::NewTargetNode):
+        (JSC::ImportMetaNode::ImportMetaNode):
+        * parser/Nodes.h:
+        (JSC::ExpressionNode::isMetaProperty const):
+        (JSC::ExpressionNode::isImportMeta const):
+        * parser/Parser.cpp:
+        (JSC::Parser<LexerType>::metaPropertyName):
+        (JSC::Parser<LexerType>::parseAssignmentExpression):
+        (JSC::Parser<LexerType>::parseMemberExpression):
+        (JSC::Parser<LexerType>::parseUnaryExpression):
+        * parser/Parser.h:
+        * parser/SyntaxChecker.h:
+        (JSC::SyntaxChecker::createImportMetaExpr):
+        (JSC::SyntaxChecker::isMetaProperty):
+        (JSC::SyntaxChecker::isImportMeta):
+
 2017-10-11  Saam Barati  <sbarati@apple.com>
 
         Runtime disable poly proto because it may be a 3-4% Speedometer regression
index 0b6a94a..734568e 100644 (file)
@@ -211,6 +211,13 @@ RegisterID* NewTargetNode::emitBytecode(BytecodeGenerator& generator, RegisterID
     return generator.moveToDestinationIfNeeded(dst, generator.newTarget());
 }
 
+// ------------------------------ ImportMetaNode ---------------------------------
+
+RegisterID* ImportMetaNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
+{
+    return generator.emitNode(dst, m_expr);
+}
+
 // ------------------------------ ResolveNode ----------------------------------
 
 bool ResolveNode::isPure(BytecodeGenerator& generator) const
index 8d91ce8..ab95613 100644 (file)
@@ -189,7 +189,10 @@ public:
         usesNewTarget();
         return new (m_parserArena) NewTargetNode(location);
     }
+    ExpressionNode* createImportMetaExpr(const JSTokenLocation& location, ExpressionNode* expr) { return new (m_parserArena) ImportMetaNode(location, expr); }
+    bool isMetaProperty(ExpressionNode* node) { return node->isMetaProperty(); }
     bool isNewTarget(ExpressionNode* node) { return node->isNewTarget(); }
+    bool isImportMeta(ExpressionNode* node) { return node->isImportMeta(); }
     ExpressionNode* createResolve(const JSTokenLocation& location, const Identifier& ident, const JSTextPosition& start, const JSTextPosition& end)
     {
         if (m_vm->propertyNames->arguments == ident)
index 3769c95..acdac6c 100644 (file)
@@ -171,11 +171,22 @@ namespace JSC {
     {
     }
 
-    inline NewTargetNode::NewTargetNode(const JSTokenLocation& location)
+    inline MetaPropertyNode::MetaPropertyNode(const JSTokenLocation& location)
         : ExpressionNode(location)
     {
     }
 
+    inline NewTargetNode::NewTargetNode(const JSTokenLocation& location)
+        : MetaPropertyNode(location)
+    {
+    }
+
+    inline ImportMetaNode::ImportMetaNode(const JSTokenLocation& location, ExpressionNode* expr)
+        : MetaPropertyNode(location)
+        , m_expr(expr)
+    {
+    }
+
     inline ResolveNode::ResolveNode(const JSTokenLocation& location, const Identifier& ident, const JSTextPosition& start)
         : ExpressionNode(location)
         , m_ident(ident)
index 196a7ba..4110deb 100644 (file)
@@ -186,7 +186,9 @@ namespace JSC {
         virtual bool isSpreadExpression() const { return false; }
         virtual bool isSuperNode() const { return false; }
         virtual bool isImportNode() const { return false; }
+        virtual bool isMetaProperty() const { return false; }
         virtual bool isNewTarget() const { return false; }
+        virtual bool isImportMeta() const { return false; }
         virtual bool isBytecodeIntrinsicNode() const { return false; }
 
         virtual void emitBytecodeInConditionContext(BytecodeGenerator&, Label&, Label&, FallThroughMode);
@@ -584,7 +586,15 @@ namespace JSC {
         ExpressionNode* m_expr;
     };
 
-    class NewTargetNode final : public ExpressionNode {
+    class MetaPropertyNode : public ExpressionNode {
+    public:
+        MetaPropertyNode(const JSTokenLocation&);
+
+    private:
+        bool isMetaProperty() const final { return true; }
+    };
+
+    class NewTargetNode final : public MetaPropertyNode {
     public:
         NewTargetNode(const JSTokenLocation&);
 
@@ -593,6 +603,17 @@ namespace JSC {
         RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
     };
 
+    class ImportMetaNode final : public MetaPropertyNode {
+    public:
+        ImportMetaNode(const JSTokenLocation&, ExpressionNode*);
+
+    private:
+        bool isImportMeta() const final { return true; }
+        RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+
+        ExpressionNode* m_expr;
+    };
+
     class ResolveNode : public ExpressionNode {
     public:
         ResolveNode(const JSTokenLocation&, const Identifier&, const JSTextPosition& start);
index 59a7ea0..4908985 100644 (file)
@@ -3585,6 +3585,18 @@ template <typename TreeBuilder> TreeExpression Parser<LexerType>::parseAssignmen
     ExpressionErrorClassifier classifier(this);
     return parseAssignmentExpression(context, classifier);
 }
+
+
+template <typename LexerType>
+template <typename TreeBuilder> NEVER_INLINE const char* Parser<LexerType>::metaPropertyName(TreeBuilder& context, TreeExpression expr)
+{
+    if (context.isNewTarget(expr))
+        return "new.target";
+    if (context.isImportMeta(expr))
+        return "import.meta";
+    RELEASE_ASSERT_NOT_REACHED();
+    return "error";
+}
     
 template <typename LexerType>
 template <typename TreeBuilder> TreeExpression Parser<LexerType>::parseAssignmentExpression(TreeBuilder& context, ExpressionErrorClassifier& classifier)
@@ -3690,8 +3702,8 @@ template <typename TreeBuilder> TreeExpression Parser<LexerType>::parseAssignmen
         }
         m_parserState.nonTrivialExpressionCount++;
         hadAssignment = true;
-        if (UNLIKELY(context.isNewTarget(lhs)))
-            internalFailWithMessage(false, "new.target can't be the left hand side of an assignment expression");
+        if (UNLIKELY(context.isMetaProperty(lhs)))
+            internalFailWithMessage(false, metaPropertyName(context, lhs), " can't be the left hand side of an assignment expression");
         context.assignmentStackAppend(assignmentStack, lhs, start, tokenStartPosition(), m_parserState.assignmentCount, op);
         start = tokenStartPosition();
         m_parserState.assignmentCount++;
@@ -4698,7 +4710,7 @@ template <class TreeBuilder> TreeExpression Parser<LexerType>::parseMemberExpres
                 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);
+                base = context.createImportMetaExpr(location, createResolveAndUseVariable(context, &m_vm->propertyNames->builtinNames().metaPrivateName(), false, expressionStart, location));
                 next();
             } else {
                 failIfTrue(match(IDENT), "\"import.\" can only followed with meta");
@@ -4924,8 +4936,8 @@ template <class TreeBuilder> TreeExpression Parser<LexerType>::parseUnaryExpress
             failWithMessage("Cannot parse subexpression of ", operatorString(true, lastOperator), "operator");
         failWithMessage("Cannot parse member expression");
     }
-    if (UNLIKELY(isUpdateOp(static_cast<JSTokenType>(lastOperator)) && context.isNewTarget(expr)))
-        internalFailWithMessage(false, "new.target can't come after a prefix operator");
+    if (UNLIKELY(isUpdateOp(static_cast<JSTokenType>(lastOperator)) && context.isMetaProperty(expr)))
+        internalFailWithMessage(false, metaPropertyName(context, expr), " can't come after a prefix operator");
     bool isEvalOrArguments = false;
     if (strictMode() && !m_syntaxAlreadyValidated) {
         if (context.isResolve(expr))
@@ -4934,8 +4946,8 @@ template <class TreeBuilder> TreeExpression Parser<LexerType>::parseUnaryExpress
     failIfTrueIfStrict(isEvalOrArguments && modifiesExpr, "Cannot modify '", m_parserState.lastIdentifier->impl(), "' in strict mode");
     switch (m_token.m_type) {
     case PLUSPLUS:
-        if (UNLIKELY(context.isNewTarget(expr)))
-            internalFailWithMessage(false, "new.target can't come before a postfix operator");
+        if (UNLIKELY(context.isMetaProperty(expr)))
+            internalFailWithMessage(false, metaPropertyName(context, expr), " can't come before a postfix operator");
         m_parserState.nonTrivialExpressionCount++;
         m_parserState.nonLHSCount++;
         expr = context.makePostfixNode(location, expr, OpPlusPlus, subExprStart, lastTokenEndPosition(), tokenEndPosition());
@@ -4946,8 +4958,8 @@ template <class TreeBuilder> TreeExpression Parser<LexerType>::parseUnaryExpress
         next();
         break;
     case MINUSMINUS:
-        if (UNLIKELY(context.isNewTarget(expr)))
-            internalFailWithMessage(false, "new.target can't come before a postfix operator");
+        if (UNLIKELY(context.isMetaProperty(expr)))
+            internalFailWithMessage(false, metaPropertyName(context, expr), " can't come before a postfix operator");
         m_parserState.nonTrivialExpressionCount++;
         m_parserState.nonLHSCount++;
         expr = context.makePostfixNode(location, expr, OpMinusMinus, subExprStart, lastTokenEndPosition(), tokenEndPosition());
index bc03de1..750305c 100644 (file)
@@ -1612,6 +1612,8 @@ private:
 
     template <class TreeBuilder> ALWAYS_INLINE bool shouldCheckPropertyForUnderscoreProtoDuplicate(TreeBuilder&, const TreeProperty&);
 
+    template <class TreeBuilder> NEVER_INLINE const char* metaPropertyName(TreeBuilder&, TreeExpression);
+
     ALWAYS_INLINE int isBinaryOperator(JSTokenType);
     bool allowAutomaticSemicolon();
     
index fc1b8cc..8db35c7 100644 (file)
@@ -68,12 +68,13 @@ public:
     {
     }
 
-    enum { NoneExpr = 0,
+    static const constexpr int MetaPropertyBit = 0x80000000;
+    enum : int { NoneExpr = 0,
         ResolveEvalExpr, ResolveExpr, IntegerExpr, DoubleExpr, StringExpr,
         ThisExpr, NullExpr, BoolExpr, RegExpExpr, ObjectLiteralExpr,
         FunctionExpr, ClassExpr, SuperExpr, ImportExpr, BracketExpr, DotExpr, CallExpr,
         NewExpr, PreExpr, PostExpr, UnaryExpr, BinaryExpr,
-        ConditionalExpr, AssignmentExpr, TypeofExpr, NewTargetExpr,
+        ConditionalExpr, AssignmentExpr, TypeofExpr,
         DeleteExpr, ArrayLiteralExpr, BindingDestructuring, RestParameter,
         ArrayDestructuring, ObjectDestructuring, SourceElementsResult,
         FunctionBodyResult, SpreadExpr, ObjectSpreadExpr, ArgumentsResult,
@@ -85,7 +86,10 @@ public:
         TaggedTemplateExpr, YieldExpr, AwaitExpr,
         ModuleNameResult,
         ImportSpecifierResult, ImportSpecifierListResult,
-        ExportSpecifierResult, ExportSpecifierListResult
+        ExportSpecifierResult, ExportSpecifierListResult,
+
+        NewTargetExpr = MetaPropertyBit | 0,
+        ImportMetaExpr = MetaPropertyBit | 1,
     };
     typedef int ExpressionType;
 
@@ -160,7 +164,10 @@ public:
     ExpressionType createThisExpr(const JSTokenLocation&) { return ThisExpr; }
     ExpressionType createSuperExpr(const JSTokenLocation&) { return SuperExpr; }
     ExpressionType createNewTargetExpr(const JSTokenLocation&) { return NewTargetExpr; }
+    ExpressionType createImportMetaExpr(const JSTokenLocation&, ExpressionType) { return ImportMetaExpr; }
+    ALWAYS_INLINE bool isMetaProperty(ExpressionType type) { return type & MetaPropertyBit; }
     ALWAYS_INLINE bool isNewTarget(ExpressionType type) { return type == NewTargetExpr; }
+    ALWAYS_INLINE bool isImportMeta(ExpressionType type) { return type == ImportMetaExpr; }
     ExpressionType createResolve(const JSTokenLocation&, const Identifier&, int, int) { return ResolveExpr; }
     ExpressionType createObjectLiteral(const JSTokenLocation&) { return ObjectLiteralExpr; }
     ExpressionType createObjectLiteral(const JSTokenLocation&, int) { return ObjectLiteralExpr; }