Title: [271119] trunk
Revision
271119
Author
[email protected]
Date
2021-01-02 10:41:47 -0800 (Sat, 02 Jan 2021)

Log Message

Don't throw if `function.caller` is a non-strict / generator / async function
https://bugs.webkit.org/show_bug.cgi?id=220216

Reviewed by Yusuke Suzuki.

JSTests:

* stress/function-caller-async-arrow-function-body.js: Removed.
* stress/function-caller-async-function-body.js: Removed.
* stress/function-caller-async-generator-body.js: Removed.
* stress/function-caller-generator-body.js: Removed.
* stress/function-caller-generator-method-body.js: Removed.
* stress/function-hidden-as-caller.js: Added.
* stress/polymorphic-access-exception-handler-should-not-clobber-used-register.js:
* stress/tail-call-recognize.js:
* test262/expectations.yaml: Mark 45 test cases as passing.

Source/_javascript_Core:

The spec forbids [1] ES6+ and strict mode functions from having their own "caller"
property. r230662 went even further, throwing TypeError if `function.caller` attempts
to return non-strict / generator / async function, which doesn't contradict ECMA-262,
but diverges from V8 and SpiderMonkey (they just return the caller).

Since throwing TypeError causes quite a lot test262 failures and is a bit dangerous
(legacy library which uses `function.caller` is called from ES6 code), this patch
replaces it with `null` return.

Given that r230662 appears to be web-compatible, this change preserves its intent
to limit `function.caller` API as much as possible by returning `null` for all ES6+
functions, including methods, accessors, and arrow functions.

[1]: https://tc39.es/ecma262/#sec-forbidden-extensions (paragraphs 1-2)

* runtime/JSFunction.cpp:
(JSC::JSC_DEFINE_CUSTOM_GETTER):

LayoutTests:

* js/caller-property-expected.txt:
* js/script-tests/caller-property.js:

Modified Paths

Added Paths

Removed Paths

Diff

Modified: trunk/JSTests/ChangeLog (271118 => 271119)


--- trunk/JSTests/ChangeLog	2021-01-02 08:09:41 UTC (rev 271118)
+++ trunk/JSTests/ChangeLog	2021-01-02 18:41:47 UTC (rev 271119)
@@ -1,3 +1,20 @@
+2021-01-02  Alexey Shvayka  <[email protected]>
+
+        Don't throw if `function.caller` is a non-strict / generator / async function
+        https://bugs.webkit.org/show_bug.cgi?id=220216
+
+        Reviewed by Yusuke Suzuki.
+
+        * stress/function-caller-async-arrow-function-body.js: Removed.
+        * stress/function-caller-async-function-body.js: Removed.
+        * stress/function-caller-async-generator-body.js: Removed.
+        * stress/function-caller-generator-body.js: Removed.
+        * stress/function-caller-generator-method-body.js: Removed.
+        * stress/function-hidden-as-caller.js: Added.
+        * stress/polymorphic-access-exception-handler-should-not-clobber-used-register.js:
+        * stress/tail-call-recognize.js:
+        * test262/expectations.yaml: Mark 45 test cases as passing.
+
 2020-12-31  Alexey Shvayka  <[email protected]>
 
         JSFunction::deleteProperty() fails to delete a non-existent "prototype" property

Deleted: trunk/JSTests/stress/function-caller-async-arrow-function-body.js (271118 => 271119)


--- trunk/JSTests/stress/function-caller-async-arrow-function-body.js	2021-01-02 08:09:41 UTC (rev 271118)
+++ trunk/JSTests/stress/function-caller-async-arrow-function-body.js	2021-01-02 18:41:47 UTC (rev 271119)
@@ -1,26 +0,0 @@
-//@ runDefault
-
-(function thingy() {
-    function bar()
-    {
-        return bar.caller;
-    }
-    
-    var ok = false;
-    var badError = null;
-    var foo = async () => {
-        try {
-            bar();
-            ok = true;
-        } catch (e) {
-            if (e.toString() != "TypeError: Function.caller used to retrieve async function body")
-                badError = e;
-        }
-    }
-    
-    foo();
-    if (ok)
-        throw "Error: did not throw error";
-    if (badError)
-        throw "Bad error: " + badError;
-})();

Deleted: trunk/JSTests/stress/function-caller-async-function-body.js (271118 => 271119)


--- trunk/JSTests/stress/function-caller-async-function-body.js	2021-01-02 08:09:41 UTC (rev 271118)
+++ trunk/JSTests/stress/function-caller-async-function-body.js	2021-01-02 18:41:47 UTC (rev 271119)
@@ -1,27 +0,0 @@
-//@ runDefault
-
-(function thingy() {
-    function bar()
-    {
-        return bar.caller;
-    }
-    
-    var ok = false;
-    var badError = null;
-    async function foo()
-    {
-        try {
-            bar();
-            ok = true;
-        } catch (e) {
-            if (e.toString() != "TypeError: Function.caller used to retrieve async function body")
-                badError = e;
-        }
-    }
-    
-    foo();
-    if (ok)
-        throw "Error: did not throw error";
-    if (badError)
-        throw "Bad error: " + badError;
-})();

Deleted: trunk/JSTests/stress/function-caller-async-generator-body.js (271118 => 271119)


--- trunk/JSTests/stress/function-caller-async-generator-body.js	2021-01-02 08:09:41 UTC (rev 271118)
+++ trunk/JSTests/stress/function-caller-async-generator-body.js	2021-01-02 18:41:47 UTC (rev 271119)
@@ -1,27 +0,0 @@
-//@ runDefault
-
-(function thingy() {
-    function bar()
-    {
-        return bar.caller;
-    }
-    
-    var ok = false;
-    var badError = null;
-    async function* foo()
-    {
-        try {
-            bar();
-            ok = true;
-        } catch (e) {
-            if (e.toString() != "TypeError: Function.caller used to retrieve generator body")
-                badError = e;
-        }
-    }
-    
-    foo().next();
-    if (ok)
-        throw "Error: did not throw error";
-    if (badError)
-        throw "Bad error: " + badError;
-})();

Deleted: trunk/JSTests/stress/function-caller-generator-body.js (271118 => 271119)


--- trunk/JSTests/stress/function-caller-generator-body.js	2021-01-02 08:09:41 UTC (rev 271118)
+++ trunk/JSTests/stress/function-caller-generator-body.js	2021-01-02 18:41:47 UTC (rev 271119)
@@ -1,24 +0,0 @@
-//@ runDefault
-
-(function thingy() {
-    function bar()
-    {
-        return bar.caller;
-    }
-    
-    function* foo()
-    {
-        bar();
-    }
-    
-    var ok = false;
-    try {
-        foo().next();
-        ok = true;
-    } catch (e) {
-        if (e.toString() != "TypeError: Function.caller used to retrieve generator body")
-            throw "Error: bad error: " + e;
-    }
-    if (ok)
-        throw "Error: did not throw error";
-})();

Deleted: trunk/JSTests/stress/function-caller-generator-method-body.js (271118 => 271119)


--- trunk/JSTests/stress/function-caller-generator-method-body.js	2021-01-02 08:09:41 UTC (rev 271118)
+++ trunk/JSTests/stress/function-caller-generator-method-body.js	2021-01-02 18:41:47 UTC (rev 271119)
@@ -1,26 +0,0 @@
-//@ runDefault
-
-(function thingy() {
-    function bar()
-    {
-        return bar.caller;
-    }
-    
-    class C {
-        *foo()
-        {
-            bar();
-        }
-    }
-        
-    var ok = false;
-    try {
-        new C().foo().next();
-        ok = true;
-    } catch (e) {
-        if (e.toString() != "TypeError: Function.caller used to retrieve generator body")
-            throw "Error: bad error: " + e;
-    }
-    if (ok)
-        throw "Error: did not throw error";
-})();

Added: trunk/JSTests/stress/function-hidden-as-caller.js (0 => 271119)


--- trunk/JSTests/stress/function-hidden-as-caller.js	                        (rev 0)
+++ trunk/JSTests/stress/function-hidden-as-caller.js	2021-01-02 18:41:47 UTC (rev 271119)
@@ -0,0 +1,63 @@
+function shouldBe(actual, expected, testInfo) {
+    if (actual !== expected)
+        throw new Error(`Bad value: ${actual} (${testInfo})`);
+}
+
+let caller = null;
+function updateCaller() {
+    caller = updateCaller.caller;
+}
+noInline(updateCaller);
+
+function normalStrictFunction() { "use strict"; updateCaller(); }
+
+const { get, set } = Object.getOwnPropertyDescriptor({
+    get accessor() { updateCaller(); },
+    set accessor(_v) { updateCaller(); },
+}, "accessor");
+
+const arrowFunction = () => { updateCaller(); };
+const asyncArrowFunction = async () => { updateCaller(); };
+
+const functionsHiddenAsCallers = [
+    normalStrictFunction,
+    normalStrictFunction.bind(),
+    get,
+    set,
+    arrowFunction,
+    asyncArrowFunction,
+    function* syncGenerator() { updateCaller(); },
+    { * syncGeneratorMethod() { updateCaller(); } }.syncGeneratorMethod,
+    { method() { updateCaller(); } }.method,
+    async function asyncFunction() { updateCaller(); },
+    { async asyncMethod() { updateCaller(); } }.asyncMethod,
+    async function* asyncGenerator() { updateCaller(); },
+    { async * asyncGeneratorMethod() { updateCaller(); } }.asyncGeneratorMethod,
+];
+
+const constructorsHiddenAsCallers = [
+    class baseConstructor {
+        constructor() { updateCaller(); }
+    },
+    class derivedConstructor extends Array {
+        constructor() { super(); updateCaller(); }
+    },
+];
+
+(function hiddenAsCallers() {
+    for (const fn of functionsHiddenAsCallers) {
+        for (let i = 0; i < 1e4; ++i) {
+            caller = null;
+            fn();
+            shouldBe(caller, null, fn.name);
+        }
+    }
+
+    for (const C of constructorsHiddenAsCallers) {
+        for (let i = 0; i < 1e4; ++i) {
+            caller = null;
+            new C();
+            shouldBe(caller, null, C.name);
+        }
+    }
+})();

Modified: trunk/JSTests/stress/polymorphic-access-exception-handler-should-not-clobber-used-register.js (271118 => 271119)


--- trunk/JSTests/stress/polymorphic-access-exception-handler-should-not-clobber-used-register.js	2021-01-02 08:09:41 UTC (rev 271118)
+++ trunk/JSTests/stress/polymorphic-access-exception-handler-should-not-clobber-used-register.js	2021-01-02 18:41:47 UTC (rev 271119)
@@ -1,6 +1,7 @@
 //@ runDefault("--useConcurrentJIT=0", "--useRandomizingFuzzerAgent=1", "--airRandomizeRegs=1", "--airRandomizeRegsSeed=3421187372", "--jitPolicyScale=0")
 
 function foo() {
+    'use strict';
     try {
         foo.caller;
     } catch (e) {

Modified: trunk/JSTests/stress/tail-call-recognize.js (271118 => 271119)


--- trunk/JSTests/stress/tail-call-recognize.js	2021-01-02 08:09:41 UTC (rev 271118)
+++ trunk/JSTests/stress/tail-call-recognize.js	2021-01-02 18:41:47 UTC (rev 271119)
@@ -4,13 +4,7 @@
 }
 
 function callerMustBeStrict() {
-    var errorThrown = false;
-    try {
-        callerMustBeStrict.caller;
-    } catch (e) {
-        errorThrown = true;
-    }
-    if (!errorThrown)
+    if (!Object.is(callerMustBeStrict.caller, null))
         throw Error("Wrong caller, expected strict caller but got ", callerMustBeStrict.caller);
 }
 

Modified: trunk/JSTests/test262/expectations.yaml (271118 => 271119)


--- trunk/JSTests/test262/expectations.yaml	2021-01-02 08:09:41 UTC (rev 271118)
+++ trunk/JSTests/test262/expectations.yaml	2021-01-02 18:41:47 UTC (rev 271119)
@@ -1334,12 +1334,6 @@
   strict mode: 'Test262Error: Expected SameValue(«function TypeError() {'
 test/language/expressions/arrow-function/eval-var-scope-syntax-err.js:
   default: 'Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all'
-test/language/expressions/arrow-function/forbidden-ext/b2/arrow-function-forbidden-ext-indirect-access-own-prop-caller-get.js:
-  default: 'TypeError: Function.caller used to retrieve strict caller'
-test/language/expressions/arrow-function/forbidden-ext/b2/arrow-function-forbidden-ext-indirect-access-own-prop-caller-value.js:
-  default: 'TypeError: Function.caller used to retrieve strict caller'
-test/language/expressions/arrow-function/forbidden-ext/b2/arrow-function-forbidden-ext-indirect-access-prop-caller.js:
-  default: 'TypeError: Function.caller used to retrieve strict caller'
 test/language/expressions/arrow-function/scope-body-lex-distinct.js:
   default: 'Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all'
 test/language/expressions/arrow-function/scope-param-rest-elem-var-open.js:
@@ -1506,30 +1500,6 @@
 test/language/expressions/class/elements/nested-private-direct-eval-err-contains-arguments.js:
   default: 'Test262Error: Expected a SyntaxError but got a ReferenceError'
   strict mode: 'Test262Error: Expected a SyntaxError but got a ReferenceError'
-test/language/expressions/class/gen-method-static/forbidden-ext/b2/cls-expr-gen-meth-static-forbidden-ext-indirect-access-own-prop-caller-get.js:
-  default: 'TypeError: Function.caller used to retrieve generator body'
-test/language/expressions/class/gen-method-static/forbidden-ext/b2/cls-expr-gen-meth-static-forbidden-ext-indirect-access-own-prop-caller-value.js:
-  default: 'TypeError: Function.caller used to retrieve generator body'
-test/language/expressions/class/gen-method-static/forbidden-ext/b2/cls-expr-gen-meth-static-forbidden-ext-indirect-access-prop-caller.js:
-  default: 'TypeError: Function.caller used to retrieve generator body'
-test/language/expressions/class/gen-method/forbidden-ext/b2/cls-expr-gen-meth-forbidden-ext-indirect-access-own-prop-caller-get.js:
-  default: 'TypeError: Function.caller used to retrieve generator body'
-test/language/expressions/class/gen-method/forbidden-ext/b2/cls-expr-gen-meth-forbidden-ext-indirect-access-own-prop-caller-value.js:
-  default: 'TypeError: Function.caller used to retrieve generator body'
-test/language/expressions/class/gen-method/forbidden-ext/b2/cls-expr-gen-meth-forbidden-ext-indirect-access-prop-caller.js:
-  default: 'TypeError: Function.caller used to retrieve generator body'
-test/language/expressions/class/method-static/forbidden-ext/b2/cls-expr-meth-static-forbidden-ext-indirect-access-own-prop-caller-get.js:
-  default: 'TypeError: Function.caller used to retrieve strict caller'
-test/language/expressions/class/method-static/forbidden-ext/b2/cls-expr-meth-static-forbidden-ext-indirect-access-own-prop-caller-value.js:
-  default: 'TypeError: Function.caller used to retrieve strict caller'
-test/language/expressions/class/method-static/forbidden-ext/b2/cls-expr-meth-static-forbidden-ext-indirect-access-prop-caller.js:
-  default: 'TypeError: Function.caller used to retrieve strict caller'
-test/language/expressions/class/method/forbidden-ext/b2/cls-expr-meth-forbidden-ext-indirect-access-own-prop-caller-get.js:
-  default: 'TypeError: Function.caller used to retrieve strict caller'
-test/language/expressions/class/method/forbidden-ext/b2/cls-expr-meth-forbidden-ext-indirect-access-own-prop-caller-value.js:
-  default: 'TypeError: Function.caller used to retrieve strict caller'
-test/language/expressions/class/method/forbidden-ext/b2/cls-expr-meth-forbidden-ext-indirect-access-prop-caller.js:
-  default: 'TypeError: Function.caller used to retrieve strict caller'
 test/language/expressions/compound-assignment/S11.13.2_A5.10_T1.js:
   default: "ReferenceError: Can't find variable: x"
 test/language/expressions/compound-assignment/S11.13.2_A5.10_T2.js:
@@ -1638,12 +1608,6 @@
   strict mode: 'Test262:AsyncTestFailure:Test262Error: Test262Error: f Expected SameValue(«null», «foo») to be true'
 test/language/expressions/function/eval-var-scope-syntax-err.js:
   default: 'Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all'
-test/language/expressions/function/forbidden-ext/b2/func-expr-forbidden-ext-indirect-access-own-prop-caller-get.js:
-  default: 'TypeError: Function.caller used to retrieve strict caller'
-test/language/expressions/function/forbidden-ext/b2/func-expr-forbidden-ext-indirect-access-own-prop-caller-value.js:
-  default: 'TypeError: Function.caller used to retrieve strict caller'
-test/language/expressions/function/forbidden-ext/b2/func-expr-forbidden-ext-indirect-access-prop-caller.js:
-  default: 'TypeError: Function.caller used to retrieve strict caller'
 test/language/expressions/function/scope-body-lex-distinct.js:
   default: 'Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all'
 test/language/expressions/function/scope-param-rest-elem-var-open.js:
@@ -1650,12 +1614,6 @@
   default: 'Test262Error: Expected SameValue(«outside», «inside») to be true'
 test/language/expressions/generators/eval-var-scope-syntax-err.js:
   default: 'Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all'
-test/language/expressions/generators/forbidden-ext/b2/gen-func-expr-forbidden-ext-indirect-access-own-prop-caller-get.js:
-  default: 'TypeError: Function.caller used to retrieve generator body'
-test/language/expressions/generators/forbidden-ext/b2/gen-func-expr-forbidden-ext-indirect-access-own-prop-caller-value.js:
-  default: 'TypeError: Function.caller used to retrieve generator body'
-test/language/expressions/generators/forbidden-ext/b2/gen-func-expr-forbidden-ext-indirect-access-prop-caller.js:
-  default: 'TypeError: Function.caller used to retrieve generator body'
 test/language/expressions/generators/generator-created-after-decl-inst.js:
   default: 'Test262Error: Expected SameValue(«[object Generator]», «[object Generator]») to be false'
   strict mode: 'Test262Error: Expected SameValue(«[object Generator]», «[object Generator]») to be false'
@@ -1683,18 +1641,6 @@
   strict mode: 'Test262Error: production including Arguments Expected a TypeError but got a TypeError'
 test/language/expressions/object/method-definition/async-gen-meth-eval-var-scope-syntax-err.js:
   default: 'Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all'
-test/language/expressions/object/method-definition/forbidden-ext/b2/gen-meth-forbidden-ext-indirect-access-own-prop-caller-get.js:
-  default: 'TypeError: Function.caller used to retrieve generator body'
-test/language/expressions/object/method-definition/forbidden-ext/b2/gen-meth-forbidden-ext-indirect-access-own-prop-caller-value.js:
-  default: 'TypeError: Function.caller used to retrieve generator body'
-test/language/expressions/object/method-definition/forbidden-ext/b2/gen-meth-forbidden-ext-indirect-access-prop-caller.js:
-  default: 'TypeError: Function.caller used to retrieve generator body'
-test/language/expressions/object/method-definition/forbidden-ext/b2/meth-forbidden-ext-indirect-access-own-prop-caller-get.js:
-  default: 'TypeError: Function.caller used to retrieve strict caller'
-test/language/expressions/object/method-definition/forbidden-ext/b2/meth-forbidden-ext-indirect-access-own-prop-caller-value.js:
-  default: 'TypeError: Function.caller used to retrieve strict caller'
-test/language/expressions/object/method-definition/forbidden-ext/b2/meth-forbidden-ext-indirect-access-prop-caller.js:
-  default: 'TypeError: Function.caller used to retrieve strict caller'
 test/language/expressions/object/method-definition/gen-meth-eval-var-scope-syntax-err.js:
   default: 'Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all'
 test/language/expressions/object/method-definition/meth-eval-var-scope-syntax-err.js:
@@ -1819,30 +1765,6 @@
 test/language/statements/class/elements/nested-private-direct-eval-err-contains-arguments.js:
   default: 'Test262Error: Expected a SyntaxError but got a ReferenceError'
   strict mode: 'Test262Error: Expected a SyntaxError but got a ReferenceError'
-test/language/statements/class/gen-method-static/forbidden-ext/b2/cls-decl-gen-meth-static-forbidden-ext-indirect-access-own-prop-caller-get.js:
-  default: 'TypeError: Function.caller used to retrieve generator body'
-test/language/statements/class/gen-method-static/forbidden-ext/b2/cls-decl-gen-meth-static-forbidden-ext-indirect-access-own-prop-caller-value.js:
-  default: 'TypeError: Function.caller used to retrieve generator body'
-test/language/statements/class/gen-method-static/forbidden-ext/b2/cls-decl-gen-meth-static-forbidden-ext-indirect-access-prop-caller.js:
-  default: 'TypeError: Function.caller used to retrieve generator body'
-test/language/statements/class/gen-method/forbidden-ext/b2/cls-decl-gen-meth-forbidden-ext-indirect-access-own-prop-caller-get.js:
-  default: 'TypeError: Function.caller used to retrieve generator body'
-test/language/statements/class/gen-method/forbidden-ext/b2/cls-decl-gen-meth-forbidden-ext-indirect-access-own-prop-caller-value.js:
-  default: 'TypeError: Function.caller used to retrieve generator body'
-test/language/statements/class/gen-method/forbidden-ext/b2/cls-decl-gen-meth-forbidden-ext-indirect-access-prop-caller.js:
-  default: 'TypeError: Function.caller used to retrieve generator body'
-test/language/statements/class/method-static/forbidden-ext/b2/cls-decl-meth-static-forbidden-ext-indirect-access-own-prop-caller-get.js:
-  default: 'TypeError: Function.caller used to retrieve strict caller'
-test/language/statements/class/method-static/forbidden-ext/b2/cls-decl-meth-static-forbidden-ext-indirect-access-own-prop-caller-value.js:
-  default: 'TypeError: Function.caller used to retrieve strict caller'
-test/language/statements/class/method-static/forbidden-ext/b2/cls-decl-meth-static-forbidden-ext-indirect-access-prop-caller.js:
-  default: 'TypeError: Function.caller used to retrieve strict caller'
-test/language/statements/class/method/forbidden-ext/b2/cls-decl-meth-forbidden-ext-indirect-access-own-prop-caller-get.js:
-  default: 'TypeError: Function.caller used to retrieve strict caller'
-test/language/statements/class/method/forbidden-ext/b2/cls-decl-meth-forbidden-ext-indirect-access-own-prop-caller-value.js:
-  default: 'TypeError: Function.caller used to retrieve strict caller'
-test/language/statements/class/method/forbidden-ext/b2/cls-decl-meth-forbidden-ext-indirect-access-prop-caller.js:
-  default: 'TypeError: Function.caller used to retrieve strict caller'
 test/language/statements/const/dstr/ary-init-iter-get-err-array-prototype.js:
   default: 'TypeError: Spread syntax requires ...iterable[Symbol.iterator] to be a function'
   strict mode: 'TypeError: Spread syntax requires ...iterable[Symbol.iterator] to be a function'
@@ -1965,12 +1887,6 @@
   strict mode: 'Test262Error: Expected SameValue(«inside», «outside») to be true'
 test/language/statements/function/eval-var-scope-syntax-err.js:
   default: 'Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all'
-test/language/statements/function/forbidden-ext/b2/func-decl-forbidden-ext-indirect-access-own-prop-caller-get.js:
-  default: 'TypeError: Function.caller used to retrieve strict caller'
-test/language/statements/function/forbidden-ext/b2/func-decl-forbidden-ext-indirect-access-own-prop-caller-value.js:
-  default: 'TypeError: Function.caller used to retrieve strict caller'
-test/language/statements/function/forbidden-ext/b2/func-decl-forbidden-ext-indirect-access-prop-caller.js:
-  default: 'TypeError: Function.caller used to retrieve strict caller'
 test/language/statements/function/scope-body-lex-distinct.js:
   default: 'Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all'
 test/language/statements/function/scope-param-rest-elem-var-open.js:
@@ -1977,12 +1893,6 @@
   default: 'Test262Error: Expected SameValue(«outside», «inside») to be true'
 test/language/statements/generators/eval-var-scope-syntax-err.js:
   default: 'Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all'
-test/language/statements/generators/forbidden-ext/b2/gen-func-decl-forbidden-ext-indirect-access-own-prop-caller-get.js:
-  default: 'TypeError: Function.caller used to retrieve generator body'
-test/language/statements/generators/forbidden-ext/b2/gen-func-decl-forbidden-ext-indirect-access-own-prop-caller-value.js:
-  default: 'TypeError: Function.caller used to retrieve generator body'
-test/language/statements/generators/forbidden-ext/b2/gen-func-decl-forbidden-ext-indirect-access-prop-caller.js:
-  default: 'TypeError: Function.caller used to retrieve generator body'
 test/language/statements/generators/generator-created-after-decl-inst.js:
   default: 'Test262Error: Expected SameValue(«[object Generator]», «[object Generator]») to be false'
   strict mode: 'Test262Error: Expected SameValue(«[object Generator]», «[object Generator]») to be false'

Modified: trunk/LayoutTests/ChangeLog (271118 => 271119)


--- trunk/LayoutTests/ChangeLog	2021-01-02 08:09:41 UTC (rev 271118)
+++ trunk/LayoutTests/ChangeLog	2021-01-02 18:41:47 UTC (rev 271119)
@@ -1,3 +1,13 @@
+2021-01-02  Alexey Shvayka  <[email protected]>
+
+        Don't throw if `function.caller` is a non-strict / generator / async function
+        https://bugs.webkit.org/show_bug.cgi?id=220216
+
+        Reviewed by Yusuke Suzuki.
+
+        * js/caller-property-expected.txt:
+        * js/script-tests/caller-property.js:
+
 2020-12-30  Zalan Bujtas  <[email protected]>
 
         [Legacy Line Layout] Remove unnecessary 'vertical-align: middle' integral rounding

Modified: trunk/LayoutTests/js/caller-property-expected.txt (271118 => 271119)


--- trunk/LayoutTests/js/caller-property-expected.txt	2021-01-02 08:09:41 UTC (rev 271118)
+++ trunk/LayoutTests/js/caller-property-expected.txt	2021-01-02 18:41:47 UTC (rev 271119)
@@ -8,13 +8,13 @@
 PASS childHasCallerWhenCalledFromWithinParent is true
 PASS nonStrictCaller(nonStrictCallee) is nonStrictCaller
 PASS nonStrictCaller(strictCallee) threw exception TypeError: 'arguments', 'callee', and 'caller' cannot be accessed in this context..
-PASS strictCaller(nonStrictCallee) threw exception TypeError: Function.caller used to retrieve strict caller.
+PASS strictCaller(nonStrictCallee) is null
 PASS strictCaller(strictCallee) threw exception TypeError: 'arguments', 'callee', and 'caller' cannot be accessed in this context..
 PASS strictTailCaller(nonStrictCallee) is null
 PASS strictTailCaller(strictCallee) threw exception TypeError: 'arguments', 'callee', and 'caller' cannot be accessed in this context..
 PASS nonStrictCaller(boundNonStrictCallee) is nonStrictCaller
 PASS nonStrictCaller(boundStrictCallee) threw exception TypeError: 'arguments', 'callee', and 'caller' cannot be accessed in this context..
-PASS strictCaller(boundNonStrictCallee) threw exception TypeError: Function.caller used to retrieve strict caller.
+PASS strictCaller(boundNonStrictCallee) is null
 PASS strictCaller(boundStrictCallee) threw exception TypeError: 'arguments', 'callee', and 'caller' cannot be accessed in this context..
 PASS strictTailCaller(boundNonStrictCallee) is null
 PASS strictTailCaller(boundStrictCallee) threw exception TypeError: 'arguments', 'callee', and 'caller' cannot be accessed in this context..

Modified: trunk/LayoutTests/js/script-tests/caller-property.js (271118 => 271119)


--- trunk/LayoutTests/js/script-tests/caller-property.js	2021-01-02 08:09:41 UTC (rev 271118)
+++ trunk/LayoutTests/js/script-tests/caller-property.js	2021-01-02 18:41:47 UTC (rev 271119)
@@ -28,7 +28,7 @@
 function strictTailCaller(x) { "use strict"; return x(); }
 shouldBe("nonStrictCaller(nonStrictCallee)", "nonStrictCaller");
 shouldThrow("nonStrictCaller(strictCallee)", '"TypeError: \'arguments\', \'callee\', and \'caller\' cannot be accessed in this context."');
-shouldThrow("strictCaller(nonStrictCallee)");
+shouldBe("strictCaller(nonStrictCallee)", "null");
 shouldThrow("strictCaller(strictCallee)", '"TypeError: \'arguments\', \'callee\', and \'caller\' cannot be accessed in this context."');
 shouldBe("strictTailCaller(nonStrictCallee)", "null");
 shouldThrow("strictTailCaller(strictCallee)");
@@ -38,7 +38,7 @@
 var boundStrictCallee = strictCallee.bind();
 shouldBe("nonStrictCaller(boundNonStrictCallee)", "nonStrictCaller");
 shouldThrow("nonStrictCaller(boundStrictCallee)");
-shouldThrow("strictCaller(boundNonStrictCallee)", '"TypeError: Function.caller used to retrieve strict caller"');
+shouldBe("strictCaller(boundNonStrictCallee)", "null");
 shouldThrow("strictCaller(boundStrictCallee)");
 shouldBe("strictTailCaller(boundNonStrictCallee)", "null");
 shouldThrow("strictTailCaller(boundStrictCallee)");

Modified: trunk/Source/_javascript_Core/ChangeLog (271118 => 271119)


--- trunk/Source/_javascript_Core/ChangeLog	2021-01-02 08:09:41 UTC (rev 271118)
+++ trunk/Source/_javascript_Core/ChangeLog	2021-01-02 18:41:47 UTC (rev 271119)
@@ -1,3 +1,28 @@
+2021-01-02  Alexey Shvayka  <[email protected]>
+
+        Don't throw if `function.caller` is a non-strict / generator / async function
+        https://bugs.webkit.org/show_bug.cgi?id=220216
+
+        Reviewed by Yusuke Suzuki.
+
+        The spec forbids [1] ES6+ and strict mode functions from having their own "caller"
+        property. r230662 went even further, throwing TypeError if `function.caller` attempts
+        to return non-strict / generator / async function, which doesn't contradict ECMA-262,
+        but diverges from V8 and SpiderMonkey (they just return the caller).
+
+        Since throwing TypeError causes quite a lot test262 failures and is a bit dangerous
+        (legacy library which uses `function.caller` is called from ES6 code), this patch
+        replaces it with `null` return.
+
+        Given that r230662 appears to be web-compatible, this change preserves its intent
+        to limit `function.caller` API as much as possible by returning `null` for all ES6+
+        functions, including methods, accessors, and arrow functions. 
+
+        [1]: https://tc39.es/ecma262/#sec-forbidden-extensions (paragraphs 1-2)
+
+        * runtime/JSFunction.cpp:
+        (JSC::JSC_DEFINE_CUSTOM_GETTER):
+
 2020-12-31  Alexey Shvayka  <[email protected]>
 
         JSFunction::deleteProperty() fails to delete a non-existent "prototype" property

Modified: trunk/Source/_javascript_Core/runtime/JSFunction.cpp (271118 => 271119)


--- trunk/Source/_javascript_Core/runtime/JSFunction.cpp	2021-01-02 08:09:41 UTC (rev 271118)
+++ trunk/Source/_javascript_Core/runtime/JSFunction.cpp	2021-01-02 18:41:47 UTC (rev 271119)
@@ -380,7 +380,6 @@
 JSC_DEFINE_CUSTOM_GETTER(callerGetter, (JSGlobalObject* globalObject, EncodedJSValue thisValue, PropertyName))
 {
     VM& vm = globalObject->vm();
-    auto scope = DECLARE_THROW_SCOPE(vm);
 
     JSFunction* thisObj = jsCast<JSFunction*>(JSValue::decode(thisValue));
     ASSERT(!thisObj->isHostFunction());
@@ -398,35 +397,11 @@
     // Firefox returns null for native code callers, so we match that behavior.
     if (function->isHostOrBuiltinFunction())
         return JSValue::encode(jsNull());
-    SourceParseMode parseMode = function->jsExecutable()->parseMode();
-    switch (parseMode) {
-    case SourceParseMode::GeneratorBodyMode:
-    case SourceParseMode::AsyncGeneratorBodyMode:
-        return JSValue::encode(throwTypeError(globalObject, scope, "Function.caller used to retrieve generator body"_s));
-    case SourceParseMode::AsyncFunctionBodyMode:
-    case SourceParseMode::AsyncArrowFunctionBodyMode:
-        return JSValue::encode(throwTypeError(globalObject, scope, "Function.caller used to retrieve async function body"_s));
-    case SourceParseMode::NormalFunctionMode:
-    case SourceParseMode::GeneratorWrapperFunctionMode:
-    case SourceParseMode::GetterMode:
-    case SourceParseMode::SetterMode:
-    case SourceParseMode::MethodMode:
-    case SourceParseMode::ArrowFunctionMode:
-    case SourceParseMode::AsyncFunctionMode:
-    case SourceParseMode::AsyncMethodMode:
-    case SourceParseMode::AsyncArrowFunctionMode:
-    case SourceParseMode::ProgramMode:
-    case SourceParseMode::ModuleAnalyzeMode:
-    case SourceParseMode::ModuleEvaluateMode:
-    case SourceParseMode::AsyncGeneratorWrapperFunctionMode:
-    case SourceParseMode::AsyncGeneratorWrapperMethodMode:
-    case SourceParseMode::GeneratorWrapperMethodMode:
-    case SourceParseMode::ClassFieldInitializerMode:
-        if (!function->jsExecutable()->isInStrictContext())
-            return JSValue::encode(caller);
-        return JSValue::encode(throwTypeError(globalObject, scope, "Function.caller used to retrieve strict caller"_s));
-    }
-    RELEASE_ASSERT_NOT_REACHED();
+
+    if (!function->jsExecutable()->hasCallerAndArgumentsProperties())
+        return JSValue::encode(jsNull());
+
+    return JSValue::encode(caller);
 }
 
 bool JSFunction::getOwnPropertySlot(JSObject* object, JSGlobalObject* globalObject, PropertyName propertyName, PropertySlot& slot)
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to