[JSC] Generate new.target register only when it is used
authorysuzuki@apple.com <ysuzuki@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 30 Aug 2019 18:53:26 +0000 (18:53 +0000)
committerysuzuki@apple.com <ysuzuki@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 30 Aug 2019 18:53:26 +0000 (18:53 +0000)
https://bugs.webkit.org/show_bug.cgi?id=201335

Reviewed by Mark Lam.

JSTests:

* stress/ensure-new-register-allocated.js: Added.
(shouldBe):
(basic):
(arrow):
(Base):
(Derived):
(evaluate):

Source/JavaScriptCore:

Since bytecode generator knows whether new.target register can be used, we should emit and use new.target register
only when it is actually required.

* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::BytecodeGenerator):
* bytecompiler/BytecodeGenerator.h:
(JSC::BytecodeGenerator::newTarget):
* parser/Nodes.h:
(JSC::ScopeNode::needsNewTargetRegisterForThisScope const):

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

JSTests/ChangeLog
JSTests/stress/ensure-new-register-allocated.js [new file with mode: 0644]
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
Source/JavaScriptCore/parser/Nodes.h

index af813d6..3f7b130 100644 (file)
@@ -1,5 +1,20 @@
 2019-08-30  Yusuke Suzuki  <ysuzuki@apple.com>
 
+        [JSC] Generate new.target register only when it is used
+        https://bugs.webkit.org/show_bug.cgi?id=201335
+
+        Reviewed by Mark Lam.
+
+        * stress/ensure-new-register-allocated.js: Added.
+        (shouldBe):
+        (basic):
+        (arrow):
+        (Base):
+        (Derived):
+        (evaluate):
+
+2019-08-30  Yusuke Suzuki  <ysuzuki@apple.com>
+
         [JSC] DFG ByteCodeParser should not copy JIT-related part of SimpleJumpTable
         https://bugs.webkit.org/show_bug.cgi?id=201331
 
diff --git a/JSTests/stress/ensure-new-register-allocated.js b/JSTests/stress/ensure-new-register-allocated.js
new file mode 100644 (file)
index 0000000..ddcb8fc
--- /dev/null
@@ -0,0 +1,44 @@
+function shouldBe(actual, expected) {
+    if (actual !== expected)
+        throw new Error('bad value: ' + actual);
+}
+
+(function () {
+    function basic() {
+        return new.target;
+    }
+
+    shouldBe(basic(), undefined);
+    shouldBe(new basic(), basic);
+
+    function arrow() {
+        return () => new.target;
+    }
+
+    shouldBe(arrow()(), undefined);
+    shouldBe(new arrow()(), arrow);
+
+    class Base {
+        constructor()
+        {
+            this.value = new.target;
+        }
+    }
+
+    class Derived extends Base {
+        constructor()
+        {
+            super();
+        }
+    }
+
+    var derived = new Derived();
+    shouldBe(derived.value, Derived);
+}());
+(function () {
+    function evaluate() {
+        return eval(`new.target`);
+    }
+    shouldBe(evaluate(), undefined);
+    shouldBe(new evaluate(), evaluate);
+}());
index 5493138..793509b 100644 (file)
@@ -1,5 +1,22 @@
 2019-08-30  Yusuke Suzuki  <ysuzuki@apple.com>
 
+        [JSC] Generate new.target register only when it is used
+        https://bugs.webkit.org/show_bug.cgi?id=201335
+
+        Reviewed by Mark Lam.
+
+        Since bytecode generator knows whether new.target register can be used, we should emit and use new.target register
+        only when it is actually required.
+
+        * bytecompiler/BytecodeGenerator.cpp:
+        (JSC::BytecodeGenerator::BytecodeGenerator):
+        * bytecompiler/BytecodeGenerator.h:
+        (JSC::BytecodeGenerator::newTarget):
+        * parser/Nodes.h:
+        (JSC::ScopeNode::needsNewTargetRegisterForThisScope const):
+
+2019-08-30  Yusuke Suzuki  <ysuzuki@apple.com>
+
         [JSC] DFG ByteCodeParser should not copy JIT-related part of SimpleJumpTable
         https://bugs.webkit.org/show_bug.cgi?id=201331
 
index d332a2f..1c22ccd 100644 (file)
@@ -667,7 +667,9 @@ BytecodeGenerator::BytecodeGenerator(VM& vm, FunctionNode* functionNode, Unlinke
     }
 
 
-    m_newTargetRegister = addVar();
+    if (functionNode->needsNewTargetRegisterForThisScope() || isNewTargetUsedInInnerArrowFunction() || codeBlock->usesEval())
+        m_newTargetRegister = addVar();
+
     switch (parseMode) {
     case SourceParseMode::GeneratorWrapperFunctionMode:
     case SourceParseMode::GeneratorWrapperMethodMode:
@@ -725,14 +727,16 @@ BytecodeGenerator::BytecodeGenerator(VM& vm, FunctionNode* functionNode, Unlinke
     case SourceParseMode::AsyncArrowFunctionBodyMode:
     case SourceParseMode::GeneratorBodyMode: {
         // |this| is already filled correctly before here.
-        emitLoad(m_newTargetRegister, jsUndefined());
+        if (m_newTargetRegister)
+            emitLoad(m_newTargetRegister, jsUndefined());
         break;
     }
 
     default: {
         if (SourceParseMode::ArrowFunctionMode != parseMode) {
             if (isConstructor()) {
-                move(m_newTargetRegister, &m_thisRegister);
+                if (m_newTargetRegister)
+                    move(m_newTargetRegister, &m_thisRegister);
                 if (constructorKind() == ConstructorKind::Extends) {
                     moveEmptyValue(&m_thisRegister);
                 } else
@@ -772,7 +776,7 @@ BytecodeGenerator::BytecodeGenerator(VM& vm, FunctionNode* functionNode, Unlinke
         if (functionNode->usesThis() || functionNode->usesSuperProperty())
             emitLoadThisFromArrowFunctionLexicalEnvironment();
 
-        if (m_scopeNode->usesNewTarget() || m_scopeNode->usesSuperCall())
+        if (m_scopeNode->needsNewTargetRegisterForThisScope())
             emitLoadNewTargetFromArrowFunctionLexicalEnvironment();
     }
 
@@ -829,7 +833,7 @@ BytecodeGenerator::BytecodeGenerator(VM& vm, FunctionNode* functionNode, Unlinke
         if (functionNode->usesThis() || functionNode->usesSuperProperty())
             emitLoadThisFromArrowFunctionLexicalEnvironment();
     
-        if (m_scopeNode->usesNewTarget() || m_scopeNode->usesSuperCall())
+        if (m_scopeNode->needsNewTargetRegisterForThisScope())
             emitLoadNewTargetFromArrowFunctionLexicalEnvironment();
     }
     
@@ -899,13 +903,13 @@ BytecodeGenerator::BytecodeGenerator(VM& vm, EvalNode* evalNode, UnlinkedEvalCod
     codeBlock->adoptVariables(variables);
     codeBlock->adoptFunctionHoistingCandidates(WTFMove(hoistedFunctions));
     
-    if (evalNode->usesSuperCall() || evalNode->usesNewTarget())
+    if (evalNode->needsNewTargetRegisterForThisScope())
         m_newTargetRegister = addVar();
 
     if (codeBlock->isArrowFunctionContext() && (evalNode->usesThis() || evalNode->usesSuperProperty()))
         emitLoadThisFromArrowFunctionLexicalEnvironment();
 
-    if (evalNode->usesSuperCall() || evalNode->usesNewTarget())
+    if (evalNode->needsNewTargetRegisterForThisScope())
         emitLoadNewTargetFromArrowFunctionLexicalEnvironment();
 
     if (needsToUpdateArrowFunctionContext() && !codeBlock->isArrowFunctionContext() && !isDerivedConstructorContext()) {
index 5558ff7..1c6a185 100644 (file)
@@ -423,6 +423,7 @@ namespace JSC {
         RegisterID* argumentsRegister() { return m_argumentsRegister; }
         RegisterID* newTarget()
         {
+            ASSERT(m_newTargetRegister);
             return m_newTargetRegister;
         }
 
index 0e77e62..47aa057 100644 (file)
@@ -1799,6 +1799,11 @@ namespace JSC {
         bool captures(const Identifier& ident) { return captures(ident.impl()); }
         bool hasSloppyModeHoistedFunction(UniquedStringImpl* uid) const { return m_sloppyModeHoistedFunctions.contains(uid); }
 
+        bool needsNewTargetRegisterForThisScope() const
+        {
+            return usesSuperCall() || usesNewTarget();
+        }
+
         VariableEnvironment& varDeclarations() { return m_varDeclarations; }
 
         int neededConstants()