[ES6] Arrow function. Some not used byte code is emited
authorgskachkov@gmail.com <gskachkov@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 1 Mar 2016 21:28:45 +0000 (21:28 +0000)
committergskachkov@gmail.com <gskachkov@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 1 Mar 2016 21:28:45 +0000 (21:28 +0000)
https://bugs.webkit.org/show_bug.cgi?id=154639

Reviewed by Saam Barati.

Currently bytecode that is generated for arrow function is not optimal.
Current fix removed following unnecessary bytecode:
1.create_lexical_environment not emited always for arrow function, only if some of
features(this/super/arguments/eval) is used inside of the arrow function.
2.load 'this' from arrow function scope in constructor is done only if super
contains in arrow function

* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::BytecodeGenerator):
(JSC::BytecodeGenerator::isSuperCallUsedInInnerArrowFunction):
* bytecompiler/BytecodeGenerator.h:
* bytecompiler/NodesCodegen.cpp:
(JSC::ThisNode::emitBytecode):
(JSC::FunctionNode::emitBytecode):
* parser/Nodes.h:
(JSC::ScopeNode::doAnyInnerArrowFunctionsUseAnyFeature):
* tests/stress/arrowfunction-lexical-bind-supercall-4.js:

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

Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
Source/JavaScriptCore/parser/Nodes.h
Source/JavaScriptCore/tests/stress/arrowfunction-lexical-bind-supercall-4.js

index b1d1c1d..22c7865 100644 (file)
@@ -1,3 +1,28 @@
+2016-03-01  Skachkov Oleksandr  <gskachkov@gmail.com>
+
+        [ES6] Arrow function. Some not used byte code is emited
+        https://bugs.webkit.org/show_bug.cgi?id=154639
+
+        Reviewed by Saam Barati.
+
+        Currently bytecode that is generated for arrow function is not optimal. 
+        Current fix removed following unnecessary bytecode:
+        1.create_lexical_environment not emited always for arrow function, only if some of 
+        features(this/super/arguments/eval) is used inside of the arrow function. 
+        2.load 'this' from arrow function scope in constructor is done only if super 
+        contains in arrow function 
+
+        * bytecompiler/BytecodeGenerator.cpp:
+        (JSC::BytecodeGenerator::BytecodeGenerator):
+        (JSC::BytecodeGenerator::isSuperCallUsedInInnerArrowFunction):
+        * bytecompiler/BytecodeGenerator.h:
+        * bytecompiler/NodesCodegen.cpp:
+        (JSC::ThisNode::emitBytecode):
+        (JSC::FunctionNode::emitBytecode):
+        * parser/Nodes.h:
+        (JSC::ScopeNode::doAnyInnerArrowFunctionsUseAnyFeature):
+        * tests/stress/arrowfunction-lexical-bind-supercall-4.js:
+
 2016-02-29  Filip Pizlo  <fpizlo@apple.com>
 
         Turn String.prototype.replace into an intrinsic
index 1114852..42f2a7f 100644 (file)
@@ -239,7 +239,7 @@ BytecodeGenerator::BytecodeGenerator(VM& vm, FunctionNode* functionNode, Unlinke
 
     SourceParseMode parseMode = codeBlock->parseMode();
 
-    bool containsArrowOrEvalButNotInArrowBlock = ((functionNode->usesArrowFunction() && functionNode->doAnyInnerArrowFunctionUseAnyFeature()) || functionNode->usesEval()) && !m_codeBlock->isArrowFunction();
+    bool containsArrowOrEvalButNotInArrowBlock = ((functionNode->usesArrowFunction() && functionNode->doAnyInnerArrowFunctionsUseAnyFeature()) || functionNode->usesEval()) && !m_codeBlock->isArrowFunction();
     bool shouldCaptureSomeOfTheThings = m_shouldEmitDebugHooks || functionNode->needsActivation() || containsArrowOrEvalButNotInArrowBlock;
 
     bool shouldCaptureAllOfTheThings = m_shouldEmitDebugHooks || codeBlock->usesEval();
@@ -4055,6 +4055,11 @@ bool BytecodeGenerator::isSuperUsedInInnerArrowFunction()
     return m_scopeNode->doAnyInnerArrowFunctionsUseSuperCall() || m_scopeNode->doAnyInnerArrowFunctionsUseSuperProperty();
 }
 
+bool BytecodeGenerator::isSuperCallUsedInInnerArrowFunction()
+{
+    return m_scopeNode->doAnyInnerArrowFunctionsUseSuperCall();
+}
+    
 void BytecodeGenerator::emitPutNewTargetToArrowFunctionContextScope()
 {
     if (isNewTargetUsedInInnerArrowFunction()) {
index 5f8ba1e..80eee7c 100644 (file)
@@ -723,6 +723,7 @@ namespace JSC {
         bool isArgumentsUsedInInnerArrowFunction();
 
     public:
+        bool isSuperCallUsedInInnerArrowFunction();
         bool isThisUsedInInnerArrowFunction();
         void pushLexicalScope(VariableEnvironmentNode*, TDZCheckOptimization, NestedScopeType = NestedScopeType::IsNotNested, RegisterID** constantSymbolTableResult = nullptr);
         void popLexicalScope(VariableEnvironmentNode*);
index c1d9546..9b84b00 100644 (file)
@@ -146,7 +146,7 @@ RegisterID* RegExpNode::emitBytecode(BytecodeGenerator& generator, RegisterID* d
 
 RegisterID* ThisNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
 {
-    if (generator.constructorKind() == ConstructorKind::Derived && generator.needsToUpdateArrowFunctionContext() && generator.isThisUsedInInnerArrowFunction())
+    if (generator.constructorKind() == ConstructorKind::Derived && generator.needsToUpdateArrowFunctionContext() && generator.isSuperCallUsedInInnerArrowFunction())
         generator.emitLoadThisFromArrowFunctionLexicalEnvironment();
 
     if (m_shouldAlwaysEmitTDZCheck || generator.constructorKind() == ConstructorKind::Derived || generator.isDerivedConstructorContext())
@@ -3138,7 +3138,7 @@ void FunctionNode::emitBytecode(BytecodeGenerator& generator, RegisterID*)
 
         // If there is no return we must automatically insert one.
         if (!returnNode) {
-            if (generator.constructorKind() == ConstructorKind::Derived && generator.needsToUpdateArrowFunctionContext() && generator.isThisUsedInInnerArrowFunction())
+            if (generator.constructorKind() == ConstructorKind::Derived && generator.needsToUpdateArrowFunctionContext() && generator.isSuperCallUsedInInnerArrowFunction())
                 generator.emitLoadThisFromArrowFunctionLexicalEnvironment(); // Arrow function can invoke 'super' in constructor and before leave constructor we need load 'this' from lexical arrow function environment
             
             RegisterID* r0 = generator.isConstructor() ? generator.thisRegister() : generator.emitLoad(0, jsUndefined());
index 57686d7..449dd88 100644 (file)
@@ -1569,13 +1569,13 @@ namespace JSC {
         void setFeatures(CodeFeatures features) { m_features = features; }
         CodeFeatures features() { return m_features; }
         InnerArrowFunctionCodeFeatures innerArrowFunctionCodeFeatures() { return m_innerArrowFunctionCodeFeatures; }
+        bool doAnyInnerArrowFunctionsUseAnyFeature() { return m_innerArrowFunctionCodeFeatures != NoInnerArrowFunctionFeatures; }
         bool doAnyInnerArrowFunctionsUseArguments() { return m_innerArrowFunctionCodeFeatures & ArgumentsInnerArrowFunctionFeature; }
         bool doAnyInnerArrowFunctionsUseSuperCall() { return m_innerArrowFunctionCodeFeatures & SuperCallInnerArrowFunctionFeature; }
         bool doAnyInnerArrowFunctionsUseSuperProperty() { return m_innerArrowFunctionCodeFeatures & SuperPropertyInnerArrowFunctionFeature; }
         bool doAnyInnerArrowFunctionsUseEval() { return m_innerArrowFunctionCodeFeatures & EvalInnerArrowFunctionFeature; }
         bool doAnyInnerArrowFunctionsUseThis() { return m_innerArrowFunctionCodeFeatures & ThisInnerArrowFunctionFeature; }
         bool doAnyInnerArrowFunctionsUseNewTarget() { return m_innerArrowFunctionCodeFeatures & NewTargetInnerArrowFunctionFeature; }
-        bool doAnyInnerArrowFunctionUseAnyFeature() { return m_innerArrowFunctionCodeFeatures != NoInnerArrowFunctionFeatures; }
 
         bool usesEval() const { return m_features & EvalFeature; }
         bool usesArguments() const { return (m_features & ArgumentsFeature) && !(m_features & ShadowsArgumentsFeature); }
index b06ffef..d93be38 100644 (file)
@@ -82,3 +82,60 @@ var testException = function (value, index) {
 for (var i=0; i < 1000; i++) {
     testException(false, i);
 }
+
+class F extends A {
+    constructor() {
+      var arr_after = () => {
+        this.idValue  = 'this-value';
+      };
+      var arr_before = () => {
+        return 'not-some-value';
+      };
+      arr_before();
+      super();
+      arr_after();
+    }
+}
+
+let f = new F();
+testCase(f.idValue, 'this-value', 'Error: not correct binding of this in constructor');
+
+class G extends A {
+    constructor() {
+        var arr_simple = () => {
+            return 'not-some-value';
+        };
+        var arr_super = () => {
+            super();
+        };
+        arr_simple();
+        arr_super();
+    }
+}
+
+let g = new G();
+testCase(g.idValue, testValue, 'Error: not correct binding super&this in constructor');
+
+class A_this_Prop extends A {
+    getValue () {
+        return this.idValue;
+    }
+}
+
+class H extends A_this_Prop {
+    constructor() {
+        var arr_simple = () => {
+            return 'not-some-value';
+        };
+        var arr_super = () => {
+            super();
+        };
+        var arr_value = () => super.getValue();
+        arr_simple();
+        arr_super();
+        this.someValue = arr_value();
+    }
+}
+
+let h = new H();
+testCase(h.someValue, testValue, 'Error: not correct binding superProperty&this in constructor');