Title: [283753] branches/safari-611.4.2.0-branch

Diff

Modified: branches/safari-611.4.2.0-branch/JSTests/ChangeLog (283752 => 283753)


--- branches/safari-611.4.2.0-branch/JSTests/ChangeLog	2021-10-07 23:05:49 UTC (rev 283752)
+++ branches/safari-611.4.2.0-branch/JSTests/ChangeLog	2021-10-07 23:12:14 UTC (rev 283753)
@@ -1,3 +1,22 @@
+2021-10-07  Russell Epstein  <[email protected]>
+
+        Apply patch. rdar://problem/83512725
+
+    2021-10-07  Mark Lam  <[email protected]>
+
+            Cherry picked r279448. rdar://problem/83512725
+
+        2021-06-30  Yusuke Suzuki  <[email protected]>
+
+                [JSC] Stop generating default parameter code if class constructor is called without 'new'
+                https://bugs.webkit.org/show_bug.cgi?id=227547
+                rdar://78821453
+
+                Reviewed by Mark Lam.
+
+                * stress/calling-non-callable-constructors.js: Added.
+                (shouldThrow):
+
 2021-08-10  Russell Epstein  <[email protected]>
 
         Cherry-pick r280507. rdar://problem/79730568

Added: branches/safari-611.4.2.0-branch/JSTests/stress/calling-non-callable-constructors.js (0 => 283753)


--- branches/safari-611.4.2.0-branch/JSTests/stress/calling-non-callable-constructors.js	                        (rev 0)
+++ branches/safari-611.4.2.0-branch/JSTests/stress/calling-non-callable-constructors.js	2021-10-07 23:12:14 UTC (rev 283753)
@@ -0,0 +1,31 @@
+function shouldThrow(func, errorMessage) {
+    var errorThrown = false;
+    var error = null;
+    try {
+        func();
+    } catch (e) {
+        errorThrown = true;
+        error = e;
+    }
+    if (!errorThrown)
+        throw new Error('not thrown');
+    if (String(error) !== errorMessage)
+        throw new Error(`bad error: ${String(error)}`);
+}
+
+shouldThrow(() => {
+    class C extends Object {
+      constructor(t = super()) {}
+    }
+
+    C();
+}, `TypeError: Cannot call a class constructor without |new|`);
+
+shouldThrow(() => {
+    Promise();
+}, `TypeError: Cannot call a constructor without |new|`);
+
+shouldThrow(() => {
+    class DerivedPromise extends Promise { }
+    DerivedPromise();
+}, `TypeError: Cannot call a class constructor without |new|`);

Modified: branches/safari-611.4.2.0-branch/Source/_javascript_Core/ChangeLog (283752 => 283753)


--- branches/safari-611.4.2.0-branch/Source/_javascript_Core/ChangeLog	2021-10-07 23:05:49 UTC (rev 283752)
+++ branches/safari-611.4.2.0-branch/Source/_javascript_Core/ChangeLog	2021-10-07 23:12:14 UTC (rev 283753)
@@ -1,3 +1,28 @@
+2021-10-07  Russell Epstein  <[email protected]>
+
+        Apply patch. rdar://problem/83512725
+
+    2021-10-07  Mark Lam  <[email protected]>
+
+            Cherry picked r279448. rdar://problem/83512725
+
+        2021-06-30  Yusuke Suzuki  <[email protected]>
+
+                [JSC] Stop generating default parameter code if class constructor is called without 'new'
+                https://bugs.webkit.org/show_bug.cgi?id=227547
+                rdar://78821453
+
+                Reviewed by Mark Lam.
+
+                We already do not generate body bytecode when class constructor is called without 'new' because many features including "super()" assume
+                that they generate bytecode only when it is called as a constructor. But we are not doing that for default parameters' bytecode generation.
+                This patch stops generating bytecode for default parameters if class constructor is called without 'new'.
+
+                * bytecompiler/BytecodeGenerator.cpp:
+                (JSC::BytecodeGenerator::generate):
+                (JSC::BytecodeGenerator::BytecodeGenerator):
+                * runtime/ConstructorKind.h:
+
 2021-08-12  Russell Epstein  <[email protected]>
 
         Cherry-pick r280996. rdar://problem/81752592

Modified: branches/safari-611.4.2.0-branch/Source/_javascript_Core/bytecompiler/BytecodeGenerator.cpp (283752 => 283753)


--- branches/safari-611.4.2.0-branch/Source/_javascript_Core/bytecompiler/BytecodeGenerator.cpp	2021-10-07 23:05:49 UTC (rev 283752)
+++ branches/safari-611.4.2.0-branch/Source/_javascript_Core/bytecompiler/BytecodeGenerator.cpp	2021-10-07 23:12:14 UTC (rev 283753)
@@ -152,68 +152,69 @@
     if (UNLIKELY(m_outOfMemoryDuringConstruction))
         return ParserError(ParserError::OutOfMemory);
 
+    bool callingNonCallableConstructor = false;
+    switch (constructorKind()) {
+    case ConstructorKind::None:
+        break;
+    case ConstructorKind::Naked:
+    case ConstructorKind::Base:
+    case ConstructorKind::Extends:
+        callingNonCallableConstructor = !isConstructor();
+        break;
+    }
+
     m_codeBlock->setThisRegister(m_thisRegister.virtualRegister());
 
     emitLogShadowChickenPrologueIfNecessary();
     
-    // If we have declared a variable named "arguments" and we are using arguments then we should
-    // perform that assignment now.
-    if (m_needToInitializeArguments)
-        initializeVariable(variable(propertyNames().arguments), m_argumentsRegister);
+    if (!callingNonCallableConstructor) {
+        // If we have declared a variable named "arguments" and we are using arguments then we should
+        // perform that assignment now.
+        if (m_needToInitializeArguments)
+            initializeVariable(variable(propertyNames().arguments), m_argumentsRegister);
 
-    if (m_restParameter)
-        m_restParameter->emit(*this);
+        if (m_restParameter)
+            m_restParameter->emit(*this);
 
-    {
-        RefPtr<RegisterID> temp = newTemporary();
-        RefPtr<RegisterID> tolLevelScope;
-        for (auto functionPair : m_functionsToInitialize) {
-            FunctionMetadataNode* metadata = functionPair.first;
-            FunctionVariableType functionType = functionPair.second;
-            emitNewFunction(temp.get(), metadata);
-            if (functionType == NormalFunctionVariable)
-                initializeVariable(variable(metadata->ident()), temp.get());
-            else if (functionType == TopLevelFunctionVariable) {
-                if (!tolLevelScope) {
-                    // We know this will resolve to the top level scope or global object because our parser/global initialization code 
-                    // doesn't allow let/const/class variables to have the same names as functions.
-                    // This is a top level function, and it's an error to ever create a top level function
-                    // name that would resolve to a lexical variable. E.g:
-                    // ```
-                    //     function f() {
-                    //         {
-                    //             let x;
-                    //             {
-                    //             //// error thrown here
-                    //                  eval("function x(){}");
-                    //             }
-                    //         }
-                    //     }
-                    // ```
-                    // Therefore, we're guaranteed to have this resolve to a top level variable.
-                    RefPtr<RegisterID> tolLevelObjectScope = emitResolveScope(nullptr, Variable(metadata->ident()));
-                    tolLevelScope = newBlockScopeVariable();
-                    move(tolLevelScope.get(), tolLevelObjectScope.get());
-                }
-                emitPutToScope(tolLevelScope.get(), Variable(metadata->ident()), temp.get(), ThrowIfNotFound, InitializationMode::NotInitialization);
-            } else
-                RELEASE_ASSERT_NOT_REACHED();
+        {
+            RefPtr<RegisterID> temp = newTemporary();
+            RefPtr<RegisterID> tolLevelScope;
+            for (auto functionPair : m_functionsToInitialize) {
+                FunctionMetadataNode* metadata = functionPair.first;
+                FunctionVariableType functionType = functionPair.second;
+                emitNewFunction(temp.get(), metadata);
+                if (functionType == NormalFunctionVariable)
+                    initializeVariable(variable(metadata->ident()), temp.get());
+                else if (functionType == TopLevelFunctionVariable) {
+                    if (!tolLevelScope) {
+                        // We know this will resolve to the top level scope or global object because our parser/global initialization code 
+                        // doesn't allow let/const/class variables to have the same names as functions.
+                        // This is a top level function, and it's an error to ever create a top level function
+                        // name that would resolve to a lexical variable. E.g:
+                        // ```
+                        //     function f() {
+                        //         {
+                        //             let x;
+                        //             {
+                        //             //// error thrown here
+                        //                  eval("function x(){}");
+                        //             }
+                        //         }
+                        //     }
+                        // ```
+                        // Therefore, we're guaranteed to have this resolve to a top level variable.
+                        RefPtr<RegisterID> tolLevelObjectScope = emitResolveScope(nullptr, Variable(metadata->ident()));
+                        tolLevelScope = newBlockScopeVariable();
+                        move(tolLevelScope.get(), tolLevelObjectScope.get());
+                    }
+                    emitPutToScope(tolLevelScope.get(), Variable(metadata->ident()), temp.get(), ThrowIfNotFound, InitializationMode::NotInitialization);
+                } else
+                    RELEASE_ASSERT_NOT_REACHED();
+            }
         }
-    }
     
-    bool callingClassConstructor = false;
-    switch (constructorKind()) {
-    case ConstructorKind::None:
-    case ConstructorKind::Naked:
-        break;
-    case ConstructorKind::Base:
-    case ConstructorKind::Extends:
-        callingClassConstructor = !isConstructor();
-        break;
-    }
-    if (!callingClassConstructor)
         m_scopeNode->emitBytecode(*this);
-    else {
+    } else {
         // At this point we would have emitted an unconditional throw followed by some nonsense that's
         // just an artifact of how this generator is structured. That code never runs, but it confuses
         // bytecode analyses because it constitutes an unterminated basic block. So, we terminate the
@@ -437,6 +438,24 @@
     allocateAndEmitScope();
 
     emitCheckTraps();
+
+    switch (constructorKind()) {
+    case ConstructorKind::None:
+        break;
+    case ConstructorKind::Naked:
+        if (!isConstructor()) {
+            emitThrowTypeError("Cannot call a constructor without |new|");
+            return;
+        }
+        break;
+    case ConstructorKind::Base:
+    case ConstructorKind::Extends:
+        if (!isConstructor()) {
+            emitThrowTypeError("Cannot call a class constructor without |new|");
+            return;
+        }
+        break;
+    }
     
     if (functionNameIsInScope(functionNode->ident(), functionNode->functionMode())) {
         ASSERT(parseMode != SourceParseMode::GeneratorBodyMode);
@@ -695,58 +714,57 @@
         break;
     }
 
+    case SourceParseMode::ArrowFunctionMode:
+        break;
+
     default: {
-        if (SourceParseMode::ArrowFunctionMode != parseMode) {
-            if (isConstructor()) {
-                if (m_newTargetRegister)
-                    move(m_newTargetRegister, &m_thisRegister);
-                switch (constructorKind()) {
-                case ConstructorKind::Naked:
-                    // Naked constructor not create |this| automatically.
-                    break;
-                case ConstructorKind::None:
-                case ConstructorKind::Base:
-                    emitCreateThis(&m_thisRegister);
-                    emitInstanceFieldInitializationIfNeeded(&m_thisRegister, &m_calleeRegister, m_scopeNode->position(), m_scopeNode->position(), m_scopeNode->position());
-                    break;
-                case ConstructorKind::Extends:
-                    moveEmptyValue(&m_thisRegister);
-                    break;
+        if (isConstructor()) {
+            if (m_newTargetRegister)
+                move(m_newTargetRegister, &m_thisRegister);
+            switch (constructorKind()) {
+            case ConstructorKind::Naked:
+                // Naked constructor not create |this| automatically.
+                break;
+            case ConstructorKind::None:
+            case ConstructorKind::Base:
+                emitCreateThis(&m_thisRegister);
+                emitInstanceFieldInitializationIfNeeded(&m_thisRegister, &m_calleeRegister, m_scopeNode->position(), m_scopeNode->position(), m_scopeNode->position());
+                break;
+            case ConstructorKind::Extends:
+                moveEmptyValue(&m_thisRegister);
+                break;
+            }
+        } else {
+            switch (constructorKind()) {
+            case ConstructorKind::None: {
+                bool shouldEmitToThis = false;
+                if (functionNode->usesThis() || codeBlock->usesEval() || m_scopeNode->doAnyInnerArrowFunctionsUseThis() || m_scopeNode->doAnyInnerArrowFunctionsUseEval())
+                    shouldEmitToThis = true;
+                else if ((functionNode->usesSuperProperty() || m_scopeNode->doAnyInnerArrowFunctionsUseSuperProperty()) && !ecmaMode.isStrict()) {
+                    // We must emit to_this when we're not in strict mode because we
+                    // will convert |this| to an object, and that object may be passed
+                    // to a strict function as |this|. This is observable because that
+                    // strict function's to_this will just return the object.
+                    //
+                    // We don't need to emit this for strict-mode code because
+                    // strict-mode code may call another strict function, which will
+                    // to_this if it directly uses this; this is OK, because we defer
+                    // to_this until |this| is used directly. Strict-mode code might
+                    // also call a sloppy mode function, and that will to_this, which
+                    // will defer the conversion, again, until necessary.
+                    shouldEmitToThis = true;
                 }
-            } else {
-                switch (constructorKind()) {
-                case ConstructorKind::None: {
-                    bool shouldEmitToThis = false;
-                    if (functionNode->usesThis() || codeBlock->usesEval() || m_scopeNode->doAnyInnerArrowFunctionsUseThis() || m_scopeNode->doAnyInnerArrowFunctionsUseEval())
-                        shouldEmitToThis = true;
-                    else if ((functionNode->usesSuperProperty() || m_scopeNode->doAnyInnerArrowFunctionsUseSuperProperty()) && !ecmaMode.isStrict()) {
-                        // We must emit to_this when we're not in strict mode because we
-                        // will convert |this| to an object, and that object may be passed
-                        // to a strict function as |this|. This is observable because that
-                        // strict function's to_this will just return the object.
-                        //
-                        // We don't need to emit this for strict-mode code because
-                        // strict-mode code may call another strict function, which will
-                        // to_this if it directly uses this; this is OK, because we defer
-                        // to_this until |this| is used directly. Strict-mode code might
-                        // also call a sloppy mode function, and that will to_this, which
-                        // will defer the conversion, again, until necessary.
-                        shouldEmitToThis = true;
-                    }
 
-                    if (shouldEmitToThis)
-                        emitToThis();
-                    break;
-                }
-                case ConstructorKind::Naked:
-                    emitThrowTypeError("Cannot call a constructor without |new|");
-                    break;
-                case ConstructorKind::Base:
-                case ConstructorKind::Extends:
-                    emitThrowTypeError("Cannot call a class constructor without |new|");
-                    break;
-                }
+                if (shouldEmitToThis)
+                    emitToThis();
+                break;
             }
+            case ConstructorKind::Naked:
+            case ConstructorKind::Base:
+            case ConstructorKind::Extends:
+                RELEASE_ASSERT_NOT_REACHED();
+                break;
+            }
         }
         break;
     }

Modified: branches/safari-611.4.2.0-branch/Source/_javascript_Core/parser/Parser.cpp (283752 => 283753)


--- branches/safari-611.4.2.0-branch/Source/_javascript_Core/parser/Parser.cpp	2021-10-07 23:05:49 UTC (rev 283752)
+++ branches/safari-611.4.2.0-branch/Source/_javascript_Core/parser/Parser.cpp	2021-10-07 23:12:14 UTC (rev 283753)
@@ -4988,16 +4988,15 @@
         next();
         failIfTrue(match(OPENPAREN) && currentScope()->evalContextType() == EvalContextType::InstanceFieldEvalContext, "super call is not valid in this context");
         ScopeRef functionScope = currentFunctionScope();
-        if (!functionScope->setNeedsSuperBinding()) {
-            // It unnecessary to check of using super during reparsing one more time. Also it can lead to syntax error
-            // in case of arrow function because during reparsing we don't know whether we currently parse the arrow function
-            // inside of the constructor or method.
-            if (!m_lexer->isReparsingFunction()) {
-                SuperBinding functionSuperBinding = !functionScope->isArrowFunction() && !closestOrdinaryFunctionScope->isEvalContext()
-                    ? functionScope->expectedSuperBinding()
-                    : closestOrdinaryFunctionScope->expectedSuperBinding();
-                semanticFailIfTrue(functionSuperBinding == SuperBinding::NotNeeded && !isClassFieldInitializer, "super is not valid in this context");
-            }
+        functionScope->setNeedsSuperBinding();
+        // It unnecessary to check of using super during reparsing one more time. Also it can lead to syntax error
+        // in case of arrow function because during reparsing we don't know whether we currently parse the arrow function
+        // inside of the constructor or method.
+        if (!m_lexer->isReparsingFunction()) {
+            SuperBinding functionSuperBinding = !functionScope->isArrowFunction() && !closestOrdinaryFunctionScope->isEvalContext()
+                ? functionScope->expectedSuperBinding()
+                : closestOrdinaryFunctionScope->expectedSuperBinding();
+            semanticFailIfTrue(functionSuperBinding == SuperBinding::NotNeeded && !isClassFieldInitializer, "super is not valid in this context");
         }
     } else if (baseIsImport) {
         next();
@@ -5106,18 +5105,17 @@
                     failIfFalse(arguments, "Cannot parse call arguments");
                     if (baseIsSuper) {
                         ScopeRef functionScope = currentFunctionScope();
-                        if (!functionScope->setHasDirectSuper()) {
-                            // It unnecessary to check of using super during reparsing one more time. Also it can lead to syntax error
-                            // in case of arrow function because during reparsing we don't know whether we currently parse the arrow function
-                            // inside of the constructor or method.
-                            if (!m_lexer->isReparsingFunction()) {
-                                ScopeRef closestOrdinaryFunctionScope = closestParentOrdinaryFunctionNonLexicalScope();
-                                ConstructorKind functionConstructorKind = !functionScope->isArrowFunction() && !closestOrdinaryFunctionScope->isEvalContext()
-                                    ? functionScope->constructorKind()
-                                    : closestOrdinaryFunctionScope->constructorKind();
-                                semanticFailIfTrue(functionConstructorKind == ConstructorKind::None, "super is not valid in this context");
-                                semanticFailIfTrue(functionConstructorKind != ConstructorKind::Extends, "super is not valid in this context");
-                            }
+                        functionScope->setHasDirectSuper();
+                        // It unnecessary to check of using super during reparsing one more time. Also it can lead to syntax error
+                        // in case of arrow function because during reparsing we don't know whether we currently parse the arrow function
+                        // inside of the constructor or method.
+                        if (!m_lexer->isReparsingFunction()) {
+                            ScopeRef closestOrdinaryFunctionScope = closestParentOrdinaryFunctionNonLexicalScope();
+                            ConstructorKind functionConstructorKind = !functionScope->isArrowFunction() && !closestOrdinaryFunctionScope->isEvalContext()
+                                ? functionScope->constructorKind()
+                                : closestOrdinaryFunctionScope->constructorKind();
+                            semanticFailIfTrue(functionConstructorKind == ConstructorKind::None, "super is not valid in this context");
+                            semanticFailIfTrue(functionConstructorKind != ConstructorKind::Extends, "super is not valid in this context");
                         }
                         if (currentScope()->isArrowFunction())
                             functionScope->setInnerArrowFunctionUsesSuperCall();

Modified: branches/safari-611.4.2.0-branch/Source/_javascript_Core/parser/Parser.h (283752 => 283753)


--- branches/safari-611.4.2.0-branch/Source/_javascript_Core/parser/Parser.h	2021-10-07 23:05:49 UTC (rev 283752)
+++ branches/safari-611.4.2.0-branch/Source/_javascript_Core/parser/Parser.h	2021-10-07 23:12:14 UTC (rev 283753)
@@ -599,10 +599,10 @@
     bool isArrowFunction() { return m_isArrowFunction; }
 
     bool hasDirectSuper() const { return m_hasDirectSuper; }
-    bool setHasDirectSuper() { return std::exchange(m_hasDirectSuper, true); }
+    void setHasDirectSuper() { m_hasDirectSuper = true; }
 
     bool needsSuperBinding() const { return m_needsSuperBinding; }
-    bool setNeedsSuperBinding() { return std::exchange(m_needsSuperBinding, true); }
+    void setNeedsSuperBinding() { m_needsSuperBinding = true; }
     
     void setEvalContextType(EvalContextType evalContextType) { m_evalContextType = evalContextType; }
     EvalContextType evalContextType() { return m_evalContextType; }

Modified: branches/safari-611.4.2.0-branch/Source/_javascript_Core/runtime/ConstructorKind.h (283752 => 283753)


--- branches/safari-611.4.2.0-branch/Source/_javascript_Core/runtime/ConstructorKind.h	2021-10-07 23:05:49 UTC (rev 283752)
+++ branches/safari-611.4.2.0-branch/Source/_javascript_Core/runtime/ConstructorKind.h	2021-10-07 23:12:14 UTC (rev 283753)
@@ -28,9 +28,9 @@
 namespace JSC {
 
 enum class ConstructorKind : uint8_t {
-    None,
-    Base,
-    Extends,
+    None, // All the other functions
+    Base, // Class base constructor
+    Extends, // Class derived constructor
     Naked, // Naked constructor, only used for builtin functions
 };
 
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to