Calling async arrow function which is in a class's member function will cause error
authorgskachkov@gmail.com <gskachkov@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 10 Jan 2017 21:13:33 +0000 (21:13 +0000)
committergskachkov@gmail.com <gskachkov@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 10 Jan 2017 21:13:33 +0000 (21:13 +0000)
https://bugs.webkit.org/show_bug.cgi?id=166879

Reviewed by Saam Barati.

JSTests:

* stress/async-arrow-functions-lexical-binding-in-class.js: Added.
(shouldBe):
(shouldBeAsync):
(BaseClass.prototype.baseClassValue):
(BaseClass.prototype.get property):
(BaseClass):
(runSomething):
(ChildClass.prototype.classValue):
(ChildClass.prototype.get classProperty):
(ChildClass.prototype.asyncValueExp):
(ChildClass.prototype.asyncValueBody):
(ChildClass.prototype.asyncThisPropExp):
(ChildClass.prototype.asyncThisPropBody):
(ChildClass.prototype.asyncThisPropInEvalExp):
(ChildClass.prototype.asyncThisPropInEvalBody):
(ChildClass.prototype.asyncThisValueExp):
(ChildClass.prototype.asyncThisValueBody):
(ChildClass.prototype.asyncThisValueInEvalExp):
(ChildClass.prototype.asyncThisValueInEvalBody):
(ChildClass):
(ChildClass2):
(ChildClass2.prototype.classValue):
(ChildClass2.prototype.get classProperty):
* stress/async-arrow-functions-lexical-super-binding.js:

Source/JavaScriptCore:

Current patch fixed loading 'super' in async arrow function. Errored appear becuase
super was loaded always nevertherless if it used in async arrow function or not, but bytecompiler
put to arrow function context only if it used within arrow function. So to fix this issue we need to
check if super was used in arrow function.

* bytecompiler/BytecodeGenerator.h:
* bytecompiler/NodesCodegen.cpp:
(JSC::FunctionNode::emitBytecode):

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

JSTests/ChangeLog
JSTests/stress/async-arrow-functions-lexical-binding-in-class.js [new file with mode: 0644]
JSTests/stress/async-arrow-functions-lexical-super-binding.js
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp

index b41efdd..cd54fa0 100644 (file)
@@ -1,3 +1,35 @@
+2017-01-10  Skachkov Oleksandr  <gskachkov@gmail.com>
+
+        Calling async arrow function which is in a class's member function will cause error
+        https://bugs.webkit.org/show_bug.cgi?id=166879
+
+        Reviewed by Saam Barati.
+
+        * stress/async-arrow-functions-lexical-binding-in-class.js: Added.
+        (shouldBe):
+        (shouldBeAsync):
+        (BaseClass.prototype.baseClassValue):
+        (BaseClass.prototype.get property):
+        (BaseClass):
+        (runSomething):
+        (ChildClass.prototype.classValue):
+        (ChildClass.prototype.get classProperty):
+        (ChildClass.prototype.asyncValueExp):
+        (ChildClass.prototype.asyncValueBody):
+        (ChildClass.prototype.asyncThisPropExp):
+        (ChildClass.prototype.asyncThisPropBody):
+        (ChildClass.prototype.asyncThisPropInEvalExp):
+        (ChildClass.prototype.asyncThisPropInEvalBody):
+        (ChildClass.prototype.asyncThisValueExp):
+        (ChildClass.prototype.asyncThisValueBody):
+        (ChildClass.prototype.asyncThisValueInEvalExp):
+        (ChildClass.prototype.asyncThisValueInEvalBody):
+        (ChildClass):
+        (ChildClass2):
+        (ChildClass2.prototype.classValue):
+        (ChildClass2.prototype.get classProperty):
+        * stress/async-arrow-functions-lexical-super-binding.js:
+
 2017-01-09  Yusuke Suzuki  <utatane.tea@gmail.com>
 
         [JSC] Prototype dynamic-import
diff --git a/JSTests/stress/async-arrow-functions-lexical-binding-in-class.js b/JSTests/stress/async-arrow-functions-lexical-binding-in-class.js
new file mode 100644 (file)
index 0000000..16fc0df
--- /dev/null
@@ -0,0 +1,103 @@
+function shouldBe(expected, actual, msg) {
+    if (msg === void 0)
+        msg = "";
+    else
+        msg = " for " + msg;
+    if (actual !== expected)
+        throw new Error("bad value" + msg + ": " + actual + ". Expected " + expected);
+}
+
+function shouldBeAsync(expected, run, msg) {
+    let actual;
+    var hadError = false;
+    run().then(function(value) { actual = value; },
+               function(error) { hadError = true; actual = error; });
+    drainMicrotasks();
+
+    if (hadError)
+        throw actual;
+
+    shouldBe(expected, actual, msg);
+}
+
+class BaseClass {
+    baseClassValue() {
+        return "BaseClassValue";
+    }
+    get property() {
+        return "test!";
+    }
+}
+
+function runSomething(callback) {
+    callback();
+}
+
+class ChildClass extends BaseClass {
+    classValue() {
+        return "classValue";
+    }
+    get classProperty() {
+        return "classProperty";
+    }
+    asyncValueExp() {
+        return async x => 'value';
+    }
+    asyncValueBody() {
+        return async x => { return 'value'; };
+    }
+    asyncThisPropExp() {
+        return async x => this.classProperty;
+    }
+    asyncThisPropBody() {
+        return async x => { return this.classProperty; };
+    }
+    asyncThisPropInEvalExp() {
+        return async x => eval('this.classProperty');
+    }
+    asyncThisPropInEvalBody() {
+        return async x => { return eval('this.classProperty'); };
+    }
+    asyncThisValueExp() {
+        return async x => this.classValue();
+    }
+    asyncThisValueBody() {
+        return async x => { return this.classValue(); };
+    }
+    asyncThisValueInEvalExp() {
+        return async x => eval('this.classValue()');
+    }
+    asyncThisValueInEvalBody() {
+        return async x => { return eval('this.classValue()'); };
+    }
+}
+
+shouldBeAsync("value", new ChildClass().asyncValueExp());
+shouldBeAsync("value", new ChildClass().asyncValueBody());
+
+shouldBeAsync("classProperty", new ChildClass().asyncThisPropExp());
+shouldBeAsync("classProperty", new ChildClass().asyncThisPropBody());
+
+shouldBeAsync("classProperty", new ChildClass().asyncThisPropInEvalExp());
+shouldBeAsync("classProperty", new ChildClass().asyncThisPropInEvalBody());
+
+shouldBeAsync("classValue", new ChildClass().asyncThisValueExp());
+shouldBeAsync("classValue", new ChildClass().asyncThisValueBody());
+
+shouldBeAsync("classValue", new ChildClass().asyncThisValueInEvalExp());
+shouldBeAsync("classValue", new ChildClass().asyncThisValueInEvalBody());
+
+class ChildClass2 extends BaseClass {
+    constructor() {
+        super();
+        return async () => this.classValue() + ' ' + this.classProperty;
+    }
+    classValue() {
+        return "classValue";
+    }
+    get classProperty() {
+        return "classProperty";
+    }
+}
+
+shouldBeAsync("classValue classProperty", new ChildClass2());
index f7ffee1..a000463 100644 (file)
@@ -38,7 +38,6 @@ class ChildClass extends BaseClass {
     }
 }
 
-// FIXME: super bindings in async arrow functions are broken
 shouldBeAsync("BaseClassValue", new ChildClass().asyncSuperProp());
 shouldBeAsync("BaseClassValue", new ChildClass().asyncSuperProp2());
 
index 64c0f5b..50fc8c1 100644 (file)
@@ -1,3 +1,19 @@
+2017-01-10  Skachkov Oleksandr  <gskachkov@gmail.com>
+
+        Calling async arrow function which is in a class's member function will cause error
+        https://bugs.webkit.org/show_bug.cgi?id=166879
+
+        Reviewed by Saam Barati.
+
+        Current patch fixed loading 'super' in async arrow function. Errored appear becuase 
+        super was loaded always nevertherless if it used in async arrow function or not, but bytecompiler
+        put to arrow function context only if it used within arrow function. So to fix this issue we need to 
+        check if super was used in arrow function. 
+
+        * bytecompiler/BytecodeGenerator.h:
+        * bytecompiler/NodesCodegen.cpp:
+        (JSC::FunctionNode::emitBytecode):
+
 2017-01-10  Commit Queue  <commit-queue@webkit.org>
 
         Unreviewed, rolling out r210537.
index 5f547ae..bc71d26 100644 (file)
@@ -905,10 +905,10 @@ namespace JSC {
         void emitNewFunctionExpressionCommon(RegisterID*, FunctionMetadataNode*);
         
         bool isNewTargetUsedInInnerArrowFunction();
-        bool isSuperUsedInInnerArrowFunction();
         bool isArgumentsUsedInInnerArrowFunction();
 
     public:
+        bool isSuperUsedInInnerArrowFunction();
         bool isSuperCallUsedInInnerArrowFunction();
         bool isThisUsedInInnerArrowFunction();
         void pushLexicalScope(VariableEnvironmentNode*, TDZCheckOptimization, NestedScopeType = NestedScopeType::IsNotNested, RegisterID** constantSymbolTableResult = nullptr, bool shouldInitializeBlockScopedFunctions = true);
index 5744d58..dfe5b91 100644 (file)
@@ -3502,8 +3502,7 @@ void FunctionNode::emitBytecode(BytecodeGenerator& generator, RegisterID*)
         RefPtr<RegisterID> next = generator.newTemporary();
         generator.emitNode(next.get(), funcExpr);
 
-        if (generator.superBinding() == SuperBinding::Needed || generator.parseMode() == SourceParseMode::AsyncArrowFunctionMode) {
-            // FIXME: Don't always load home object for async arrows
+        if (generator.superBinding() == SuperBinding::Needed || (generator.parseMode() == SourceParseMode::AsyncArrowFunctionMode && generator.isSuperUsedInInnerArrowFunction())) {
             RefPtr<RegisterID> homeObject = emitHomeObjectForCallee(generator);
             emitPutHomeObject(generator, next.get(), homeObject.get());
         }