Title: [280289] trunk
Revision
280289
Author
[email protected]
Date
2021-07-25 15:32:20 -0700 (Sun, 25 Jul 2021)

Log Message

Partly implement Function.prototype.{caller,arguments} reflection proposal
https://bugs.webkit.org/show_bug.cgi?id=158116

Reviewed by Yusuke Suzuki.

JSTests:

* ChakraCore/test/strict/19.function.baseline:
* ChakraCore/test/strict/22.callerCalleeArguments.baseline-jsc:
* microbenchmarks/function-prototype-get.js: Added.
* microbenchmarks/reflect-own-keys-function.js: Added.
* stress/for-in-shadow-non-enumerable.js:
* stress/function-hidden-as-caller.js:
* stress/has-own-property-arguments.js:
* stress/object-assign-fast-path.js:
* stress/put-to-proto-chain-overrides-put.js:
* stress/reflect-set.js:
* test262/config.yaml: Skip 3 test cases that are now incorrect.
* test262/expectations.yaml: Mark 2 test cases as passing.

Source/_javascript_Core:

To ensure web-compatibility, only the safe subset of Function.prototype.{caller,arguments}
reflection proposal [1] is implemented, which is currently shipped in SpiderMonkey.

Complete list of differences from the proposed spec:

  1. Cross-realm receiver function is allowed instead of throwing a TypeError.

     Throwing is likely safe to ship, but #225997 needs to be fixed first for
     custom properties to receive correct global object.

  2. Cross-realm caller function is returned instead of `null`.

     Hiding cross-realm caller may break things: we currently have a test for
     the opposite behavior.

  3. Defines "caller" and "arguments" setters that throw for disallowed receivers,
     instead failing silently in sloppy mode.

     This is actually more restrictive than the spec, which is preferable,
     and aligns with V8 and SM.

Most importantly, this patch removes own "caller" and "arguments" properties from
sloppy mode ES5 functions. They were non-configurable, making it harder to use
their holder as a [[ProxyTarget]]. They were also non-writable, with a constantly
changing [[Value]], which violated the invariants of internal methods [2].

As a result, JSFunction methods are greatly simplified, especially defineOwnProperty()
and getOwnSpecialPropertyNames(). The latter is now 2.1x faster according to the
provided microbenchmark. Also, removes double "prototype" lookup from [[Get]],
which is a 10% progression.

[1]: https://github.com/claudepache/es-legacy-function-reflection
[2]: https://tc39.es/ecma262/#sec-invariants-of-the-essential-internal-methods

* runtime/ClonedArguments.cpp:
(JSC::ClonedArguments::getOwnPropertySlot):
(JSC::ClonedArguments::materializeSpecials):
* runtime/FunctionExecutable.h:
* runtime/FunctionPrototype.cpp:
(JSC::FunctionPrototype::addFunctionProperties):
(JSC::isAllowedReceiverFunctionForCallerAndArguments):
(JSC::RetrieveArgumentsFunctor::RetrieveArgumentsFunctor):
(JSC::RetrieveArgumentsFunctor::result const):
(JSC::RetrieveArgumentsFunctor::operator() const):
(JSC::retrieveArguments):
(JSC::JSC_DEFINE_CUSTOM_GETTER):
(JSC::RetrieveCallerFunctionFunctor::RetrieveCallerFunctionFunctor):
(JSC::RetrieveCallerFunctionFunctor::result const):
(JSC::RetrieveCallerFunctionFunctor::operator() const):
(JSC::retrieveCallerFunction):
(JSC::JSC_DEFINE_CUSTOM_SETTER):
(JSC::FunctionPrototype::initRestrictedProperties): Deleted.
* runtime/FunctionPrototype.h:
* runtime/JSFunction.cpp:
(JSC::JSFunction::getOwnPropertySlot):
(JSC::JSFunction::getOwnSpecialPropertyNames):
(JSC::JSFunction::put):
(JSC::JSFunction::deleteProperty):
(JSC::JSFunction::defineOwnProperty):
(JSC::RetrieveArgumentsFunctor::RetrieveArgumentsFunctor): Deleted.
(JSC::RetrieveArgumentsFunctor::result const): Deleted.
(JSC::RetrieveArgumentsFunctor::operator() const): Deleted.
(JSC::retrieveArguments): Deleted.
(JSC::JSC_DEFINE_CUSTOM_GETTER): Deleted.
(JSC::RetrieveCallerFunctionFunctor::RetrieveCallerFunctionFunctor): Deleted.
(JSC::RetrieveCallerFunctionFunctor::result const): Deleted.
(JSC::RetrieveCallerFunctionFunctor::operator() const): Deleted.
(JSC::retrieveCallerFunction): Deleted.
* runtime/JSGlobalObject.cpp:
(JSC::JSGlobalObject::init):
(JSC::JSGlobalObject::visitChildrenImpl):
* runtime/JSGlobalObject.h:
Remove unused m_throwTypeErrorGetterSetter and make [[ThrowTypeError]] lazily-created.

* runtime/JSGlobalObjectFunctions.cpp:
(JSC::JSC_DEFINE_HOST_FUNCTION):
* runtime/JSGlobalObjectFunctions.h:
* runtime/JSObject.cpp:
(JSC::JSObject::putDirectCustomGetterSetterWithoutTransition):
* runtime/JSObject.h:

LayoutTests:

* inspector/model/remote-object-get-properties-expected.txt:
* inspector/runtime/getDisplayableProperties-expected.txt:
* inspector/runtime/getProperties-expected.txt:
* js/Object-getOwnPropertyNames-expected.txt:
* js/basic-strict-mode-expected.txt:
* js/kde/function_arguments-expected.txt:
* js/kde/script-tests/function_arguments.js:
* js/non-strict-function-properties-expected.txt:
* js/script-tests/Object-getOwnPropertyNames.js:
* js/script-tests/basic-strict-mode.js:
* js/script-tests/non-strict-function-properties.js:
* js/script-tests/throw-type-error-is-unique.js:

Modified Paths

Added Paths

Diff

Modified: trunk/JSTests/ChakraCore/test/strict/19.function.baseline (280288 => 280289)


--- trunk/JSTests/ChakraCore/test/strict/19.function.baseline	2021-07-25 19:40:36 UTC (rev 280288)
+++ trunk/JSTests/ChakraCore/test/strict/19.function.baseline	2021-07-25 22:32:20 UTC (rev 280289)
@@ -2,17 +2,5 @@
 Return: function.caller set
 Return: function.arguments get
 Return: function.arguments get
-Test5.caller:configurable : false
-Test5.caller:enumerable   : false
-Test5.caller:writable     : false
-Test5.caller:getter       : undefined
-Test5.caller:setter       : undefined
-Test5.caller:value        : null
-Return: function.caller get
-Test6.arguments:configurable : false
-Test6.arguments:enumerable   : false
-Test6.arguments:writable     : false
-Test6.arguments:getter       : undefined
-Test6.arguments:setter       : undefined
-Test6.arguments:value        : [object Arguments]
-Return: function.arguments get
+Exception: function.caller get TypeError
+Exception: function.arguments get TypeError

Modified: trunk/JSTests/ChakraCore/test/strict/22.callerCalleeArguments.baseline-jsc (280288 => 280289)


--- trunk/JSTests/ChakraCore/test/strict/22.callerCalleeArguments.baseline-jsc	2021-07-25 19:40:36 UTC (rev 280288)
+++ trunk/JSTests/ChakraCore/test/strict/22.callerCalleeArguments.baseline-jsc	2021-07-25 22:32:20 UTC (rev 280289)
@@ -2,19 +2,19 @@
 hasOwnProperty(caller): false
 
 var foo = function(){};(function(){echo("hasOwnProperty(caller): ", foo.hasOwnProperty("caller"));})();
-hasOwnProperty(caller): true
+hasOwnProperty(caller): false
 
 var foo = function(){};(function(){"use strict";echo("hasOwnProperty(caller): ", foo.hasOwnProperty("caller"));})();
-hasOwnProperty(caller): true
+hasOwnProperty(caller): false
 
 (function(){echo("hasOwnProperty(callee): ", arguments.hasOwnProperty("callee"));})();
 hasOwnProperty(callee): true
 
 var foo = function(){};(function(){echo("hasOwnProperty(arguments): ", foo.hasOwnProperty("arguments"));})();
-hasOwnProperty(arguments): true
+hasOwnProperty(arguments): false
 
 var foo = function(){};(function(){"use strict";echo("hasOwnProperty(arguments): ", foo.hasOwnProperty("arguments"));})();
-hasOwnProperty(arguments): true
+hasOwnProperty(arguments): false
 
 (function(){arguments.caller;})();
 
@@ -33,7 +33,6 @@
 var foo = function(){};(function(){foo.caller = 0;})();
 
 var foo = function(){};(function(){"use strict";foo.caller = 0;})();
-TypeError: Attempted to assign to readonly property.
 
 (function(){arguments.callee = 0;})();
 
@@ -40,34 +39,33 @@
 var foo = function(){};(function(){foo.arguments = 0;})();
 
 var foo = function(){};(function(){"use strict";foo.arguments = 0;})();
-TypeError: Attempted to assign to readonly property.
 
 (function(){Object.defineProperty(arguments, "caller", {value: 0});})();
 
 var foo = function(){};(function(){Object.defineProperty(foo, "caller", {value: 0});})();
-TypeError: Attempting to change value of a readonly property.
 
 var foo = function(){};(function(){"use strict";Object.defineProperty(foo, "caller", {value: 0});})();
-TypeError: Attempting to change value of a readonly property.
 
 (function(){Object.defineProperty(arguments, "callee", {value: 0});})();
 
 var foo = function(){};(function(){Object.defineProperty(foo, "arguments", {value: 0});})();
-TypeError: Attempting to change value of a readonly property.
 
 var foo = function(){};(function(){"use strict";Object.defineProperty(foo, "arguments", {value: 0});})();
-TypeError: Attempting to change value of a readonly property.
 
 (function(){var descriptor = Object.getOwnPropertyDescriptor(arguments, "caller");if(descriptor.hasOwnProperty("get")) safeCall(descriptor.get);if(descriptor.hasOwnProperty("set")) safeCall(descriptor.set);})();
 TypeError: undefined is not an object (evaluating 'descriptor.hasOwnProperty')
 
 var foo = function(){};(function(){var descriptor = Object.getOwnPropertyDescriptor(foo, "caller");if(descriptor.hasOwnProperty("get")) safeCall(descriptor.get);if(descriptor.hasOwnProperty("set")) safeCall(descriptor.set);})();
+TypeError: undefined is not an object (evaluating 'descriptor.hasOwnProperty')
 
 var foo = function(){};(function(){"use strict";var descriptor = Object.getOwnPropertyDescriptor(foo, "caller");if(descriptor.hasOwnProperty("get")) safeCall(descriptor.get);if(descriptor.hasOwnProperty("set")) safeCall(descriptor.set);})();
+TypeError: undefined is not an object (evaluating 'descriptor.hasOwnProperty')
 
 (function(){var descriptor = Object.getOwnPropertyDescriptor(arguments, "callee");if(descriptor.hasOwnProperty("get")) safeCall(descriptor.get);if(descriptor.hasOwnProperty("set")) safeCall(descriptor.set);})();
 
 var foo = function(){};(function(){var descriptor = Object.getOwnPropertyDescriptor(foo, "arguments");if(descriptor.hasOwnProperty("get")) safeCall(descriptor.get);if(descriptor.hasOwnProperty("set")) safeCall(descriptor.set);})();
+TypeError: undefined is not an object (evaluating 'descriptor.hasOwnProperty')
 
 var foo = function(){};(function(){"use strict";var descriptor = Object.getOwnPropertyDescriptor(foo, "arguments");if(descriptor.hasOwnProperty("get")) safeCall(descriptor.get);if(descriptor.hasOwnProperty("set")) safeCall(descriptor.set);})();
+TypeError: undefined is not an object (evaluating 'descriptor.hasOwnProperty')
 

Modified: trunk/JSTests/ChangeLog (280288 => 280289)


--- trunk/JSTests/ChangeLog	2021-07-25 19:40:36 UTC (rev 280288)
+++ trunk/JSTests/ChangeLog	2021-07-25 22:32:20 UTC (rev 280289)
@@ -1,3 +1,23 @@
+2021-07-25  Alexey Shvayka  <[email protected]>
+
+        Partly implement Function.prototype.{caller,arguments} reflection proposal
+        https://bugs.webkit.org/show_bug.cgi?id=158116
+
+        Reviewed by Yusuke Suzuki.
+
+        * ChakraCore/test/strict/19.function.baseline:
+        * ChakraCore/test/strict/22.callerCalleeArguments.baseline-jsc:
+        * microbenchmarks/function-prototype-get.js: Added.
+        * microbenchmarks/reflect-own-keys-function.js: Added.
+        * stress/for-in-shadow-non-enumerable.js:
+        * stress/function-hidden-as-caller.js:
+        * stress/has-own-property-arguments.js:
+        * stress/object-assign-fast-path.js:
+        * stress/put-to-proto-chain-overrides-put.js:
+        * stress/reflect-set.js:
+        * test262/config.yaml: Skip 3 test cases that are now incorrect.
+        * test262/expectations.yaml: Mark 2 test cases as passing.
+
 2021-07-23  Yusuke Suzuki  <[email protected]>
 
         [JSC] Add Speedometer2 jQuery-TodoMVC RegExp microbenchmark

Added: trunk/JSTests/microbenchmarks/function-prototype-get.js (0 => 280289)


--- trunk/JSTests/microbenchmarks/function-prototype-get.js	                        (rev 0)
+++ trunk/JSTests/microbenchmarks/function-prototype-get.js	2021-07-25 22:32:20 UTC (rev 280289)
@@ -0,0 +1,7 @@
+(function() {
+    var prototype;
+    for (var i = 0; i < 2e5; ++i)
+        prototype = (function() {}).prototype;
+    if (!prototype)
+        throw new Error("Bad assertion!");
+})();

Added: trunk/JSTests/microbenchmarks/reflect-own-keys-function.js (0 => 280289)


--- trunk/JSTests/microbenchmarks/reflect-own-keys-function.js	                        (rev 0)
+++ trunk/JSTests/microbenchmarks/reflect-own-keys-function.js	2021-07-25 22:32:20 UTC (rev 280289)
@@ -0,0 +1,9 @@
+noInline(Reflect.ownKeys);
+
+(function() {
+    var keys;
+    for (var i = 0; i < 1e5; ++i)
+        keys = Reflect.ownKeys(function() {});
+    if (!keys)
+        throw new Error("Bad assertion!");
+})();

Modified: trunk/JSTests/stress/for-in-shadow-non-enumerable.js (280288 => 280289)


--- trunk/JSTests/stress/for-in-shadow-non-enumerable.js	2021-07-25 19:40:36 UTC (rev 280288)
+++ trunk/JSTests/stress/for-in-shadow-non-enumerable.js	2021-07-25 22:32:20 UTC (rev 280289)
@@ -28,7 +28,7 @@
   {
     name: "Function (non-strict)",
     createObject: () => function() {},
-    dontEnumKeys: ["arguments", "caller", "length", "name", "prototype"],
+    dontEnumKeys: ["length", "name", "prototype"],
   },
   {
     name: "RegExp",

Modified: trunk/JSTests/stress/function-hidden-as-caller.js (280288 => 280289)


--- trunk/JSTests/stress/function-hidden-as-caller.js	2021-07-25 19:40:36 UTC (rev 280288)
+++ trunk/JSTests/stress/function-hidden-as-caller.js	2021-07-25 22:32:20 UTC (rev 280289)
@@ -3,11 +3,13 @@
         throw new Error(`Bad value: ${actual} (${testInfo})`);
 }
 
+const functionPrototypeCallerGetter = Object.getOwnPropertyDescriptor(Function.prototype, "caller").get;
+
 let callerViaGet;
 let callerViaGetOwnProperty;
 function updateCaller() {
     callerViaGet = updateCaller.caller;
-    callerViaGetOwnProperty = Object.getOwnPropertyDescriptor(updateCaller, "caller").value;
+    callerViaGetOwnProperty = functionPrototypeCallerGetter.call(updateCaller);
 }
 noInline(updateCaller);
 

Modified: trunk/JSTests/stress/has-own-property-arguments.js (280288 => 280289)


--- trunk/JSTests/stress/has-own-property-arguments.js	2021-07-25 19:40:36 UTC (rev 280288)
+++ trunk/JSTests/stress/has-own-property-arguments.js	2021-07-25 22:32:20 UTC (rev 280289)
@@ -5,4 +5,4 @@
 
 class A extends Function {}
 shouldBe(new A("'use strict';").hasOwnProperty('arguments'), false);
-shouldBe(new A().hasOwnProperty('arguments'), true);
+shouldBe(new A().hasOwnProperty('arguments'), false);

Modified: trunk/JSTests/stress/object-assign-fast-path.js (280288 => 280289)


--- trunk/JSTests/stress/object-assign-fast-path.js	2021-07-25 19:40:36 UTC (rev 280288)
+++ trunk/JSTests/stress/object-assign-fast-path.js	2021-07-25 22:32:20 UTC (rev 280289)
@@ -40,7 +40,7 @@
         ok: 42
     });
 
-    shouldBe(JSON.stringify(Object.getOwnPropertyNames(result).sort()), `["arguments","caller","length","name","ok","prototype"]`);
+    shouldBe(JSON.stringify(Object.getOwnPropertyNames(result).sort()), `["length","name","ok","prototype"]`);
     checkProperty(result, "ok", 42);
 }
 {

Modified: trunk/JSTests/stress/put-to-proto-chain-overrides-put.js (280288 => 280289)


--- trunk/JSTests/stress/put-to-proto-chain-overrides-put.js	2021-07-25 19:40:36 UTC (rev 280288)
+++ trunk/JSTests/stress/put-to-proto-chain-overrides-put.js	2021-07-25 22:32:20 UTC (rev 280289)
@@ -60,9 +60,6 @@
     false,
 );
 
-testSetResult(() => function() {}, "arguments", false);
-testSetResult(() => function() {}, "caller", false);
-
 // === harness ===
 
 function testSetResult(getTarget, key, expectedResult) {

Modified: trunk/JSTests/stress/reflect-set.js (280288 => 280289)


--- trunk/JSTests/stress/reflect-set.js	2021-07-25 19:40:36 UTC (rev 280288)
+++ trunk/JSTests/stress/reflect-set.js	2021-07-25 22:32:20 UTC (rev 280289)
@@ -1204,11 +1204,11 @@
 (function functionCase() {
     var func = function () { };
     shouldBe(Reflect.get(func, 'arguments'), null);
-    shouldBe(Reflect.set(func, 'arguments', 42), false);
+    shouldBe(Reflect.set(func, 'arguments', 42), true);
     shouldBe(Reflect.get(func, 'arguments'), null);
 
     shouldBe(Reflect.get(func, 'caller'), null);
-    shouldBe(Reflect.set(func, 'caller', 42), false);
+    shouldBe(Reflect.set(func, 'caller', 42), true);
     shouldBe(Reflect.get(func, 'caller'), null);
 
     receiverTest(function () {}, function () {});
@@ -1219,11 +1219,16 @@
     receiverTestIndexed(function () {}, {});
 
     var receiver = {};
-    shouldBe(Reflect.set(func, 'arguments', 'V', receiver), false);
+    shouldThrow(() => {
+        Reflect.set(func, 'arguments', 'V', receiver);
+    }, `TypeError: 'arguments', 'callee', and 'caller' cannot be accessed in this context.`);
     shouldBe(Reflect.get(receiver, 'arguments'), undefined);
     shouldBe(receiver.hasOwnProperty('arguments'), false);
     shouldBe(Reflect.get(func, 'arguments'), null);
-    shouldBe(Reflect.set(func, 'caller', 'V', receiver), false);
+
+    shouldThrow(() => {
+        Reflect.set(func, 'caller', 'V', receiver);
+    }, `TypeError: 'arguments', 'callee', and 'caller' cannot be accessed in this context.`);
     shouldBe(Reflect.get(receiver, 'caller'), undefined);
     shouldBe(receiver.hasOwnProperty('caller'), false);
     shouldBe(Reflect.get(func, 'caller'), null);

Modified: trunk/JSTests/test262/config.yaml (280288 => 280289)


--- trunk/JSTests/test262/config.yaml	2021-07-25 19:40:36 UTC (rev 280288)
+++ trunk/JSTests/test262/config.yaml	2021-07-25 22:32:20 UTC (rev 280289)
@@ -32,6 +32,11 @@
     - json-modules
   paths:
   files:
+    # https://github.com/claudepache/es-legacy-function-reflection
+    - test/built-ins/ThrowTypeError/unique-per-realm-function-proto.js
+    - test/built-ins/Function/prototype/restricted-property-arguments.js
+    - test/built-ins/Function/prototype/restricted-property-caller.js
+
     # Slightly different formatting. We should update test262 side.
     - test/intl402/DateTimeFormat/prototype/formatRangeToParts/en-US.js
     - test/intl402/DateTimeFormat/prototype/formatRangeToParts/fractionalSecondDigits.js

Modified: trunk/JSTests/test262/expectations.yaml (280288 => 280289)


--- trunk/JSTests/test262/expectations.yaml	2021-07-25 19:40:36 UTC (rev 280288)
+++ trunk/JSTests/test262/expectations.yaml	2021-07-25 22:32:20 UTC (rev 280289)
@@ -762,10 +762,6 @@
 test/built-ins/Object/entries/order-after-define-property.js:
   default: 'Test262Error: Expected [a, name] and [name, a] to have the same contents. '
   strict mode: 'Test262Error: Expected [a, name] and [name, a] to have the same contents. '
-test/built-ins/Object/internals/DefineOwnProperty/consistent-value-function-arguments.js:
-  default: 'Test262Error: Expected SameValue(«null», «[object Arguments]») to be true'
-test/built-ins/Object/internals/DefineOwnProperty/consistent-value-function-caller.js:
-  default: 'Test262Error: Expected SameValue(«null», «function g() {'
 test/built-ins/Object/internals/DefineOwnProperty/consistent-value-regexp-dollar1.js:
   default: 'Test262Error: Expected SameValue(«», «x») to be true'
   strict mode: 'Test262Error: Expected SameValue(«», «x») to be true'

Modified: trunk/LayoutTests/ChangeLog (280288 => 280289)


--- trunk/LayoutTests/ChangeLog	2021-07-25 19:40:36 UTC (rev 280288)
+++ trunk/LayoutTests/ChangeLog	2021-07-25 22:32:20 UTC (rev 280289)
@@ -1,3 +1,23 @@
+2021-07-25  Alexey Shvayka  <[email protected]>
+
+        Partly implement Function.prototype.{caller,arguments} reflection proposal
+        https://bugs.webkit.org/show_bug.cgi?id=158116
+
+        Reviewed by Yusuke Suzuki.
+
+        * inspector/model/remote-object-get-properties-expected.txt:
+        * inspector/runtime/getDisplayableProperties-expected.txt:
+        * inspector/runtime/getProperties-expected.txt:
+        * js/Object-getOwnPropertyNames-expected.txt:
+        * js/basic-strict-mode-expected.txt:
+        * js/kde/function_arguments-expected.txt:
+        * js/kde/script-tests/function_arguments.js:
+        * js/non-strict-function-properties-expected.txt:
+        * js/script-tests/Object-getOwnPropertyNames.js:
+        * js/script-tests/basic-strict-mode.js:
+        * js/script-tests/non-strict-function-properties.js:
+        * js/script-tests/throw-type-error-is-unique.js:
+
 2021-07-25  Wenson Hsieh  <[email protected]>
 
         [iOS] Unified field is unselected after focusing URL bar if text was selected in a fixed position container

Modified: trunk/LayoutTests/inspector/model/remote-object-get-properties-expected.txt (280288 => 280289)


--- trunk/LayoutTests/inspector/model/remote-object-get-properties-expected.txt	2021-07-25 19:40:36 UTC (rev 280288)
+++ trunk/LayoutTests/inspector/model/remote-object-get-properties-expected.txt	2021-07-25 22:32:20 UTC (rev 280289)
@@ -365,31 +365,29 @@
 description: function () { console.log(arguments); }
 
 OWN PROPERTIES:
-    arguments
-    caller
+    prototype
     length
     name
-    prototype
     __proto__
 
 DISPLAYABLE PROPERTIES:
+    prototype
+    length
+    name
     arguments
     caller
-    length
-    name
-    prototype
     __proto__
 
 ALL PROPERTIES:
-    arguments
-    caller
+    prototype
     length
     name
-    prototype
     toString
     apply
     call
     bind
+    arguments
+    caller
     constructor
     Symbol(Symbol.hasInstance)
     toLocaleString
@@ -422,8 +420,8 @@
 DISPLAYABLE PROPERTIES:
     length
     name
+    arguments
     caller
-    arguments
     __proto__
     targetFunction
     boundThis
@@ -436,8 +434,8 @@
     apply
     call
     bind
+    arguments
     caller
-    arguments
     constructor
     Symbol(Symbol.hasInstance)
     toLocaleString

Modified: trunk/LayoutTests/inspector/runtime/getDisplayableProperties-expected.txt (280288 => 280289)


--- trunk/LayoutTests/inspector/runtime/getDisplayableProperties-expected.txt	2021-07-25 19:40:36 UTC (rev 280288)
+++ trunk/LayoutTests/inspector/runtime/getDisplayableProperties-expected.txt	2021-07-25 22:32:20 UTC (rev 280289)
@@ -25,8 +25,8 @@
     "length"     =>  0 (number)  [configurable | isOwn]
     "prototype"  =>  "Test" (object)  [isOwn]
     "name"       =>  "Test" (string)  [configurable | isOwn]
+    "arguments"  =>  "TypeError: 'arguments', 'callee', and 'caller' cannot be accessed in this context." (object error)  [wasThrown]
     "caller"     =>  "TypeError: 'arguments', 'callee', and 'caller' cannot be accessed in this context." (object error)  [wasThrown]
-    "arguments"  =>  "TypeError: 'arguments', 'callee', and 'caller' cannot be accessed in this context." (object error)  [wasThrown]
     "__proto__"  =>  "function () {\n    [native code]\n}" (function)  [writable | configurable | isOwn]
 
 -- Running test case: Runtime.getDisplayableProperties.BoundConstructor
@@ -35,8 +35,8 @@
 Properties:
     "length"     =>  0 (number)  [configurable | isOwn]
     "name"       =>  "bound Test" (string)  [configurable | isOwn]
+    "arguments"  =>  "TypeError: 'arguments', 'callee', and 'caller' cannot be accessed in this context." (object error)  [wasThrown]
     "caller"     =>  "TypeError: 'arguments', 'callee', and 'caller' cannot be accessed in this context." (object error)  [wasThrown]
-    "arguments"  =>  "TypeError: 'arguments', 'callee', and 'caller' cannot be accessed in this context." (object error)  [wasThrown]
     "__proto__"  =>  "function () {\n    [native code]\n}" (function)  [writable | configurable | isOwn]
 Internal Properties:
     "targetFunction"  =>  "class Test { }" (function class)  []
@@ -48,8 +48,8 @@
 Properties:
     "length"     =>  0 (number)  [configurable | isOwn]
     "name"       =>  "bound Test" (string)  [configurable | isOwn]
+    "arguments"  =>  "TypeError: 'arguments', 'callee', and 'caller' cannot be accessed in this context." (object error)  [wasThrown]
     "caller"     =>  "TypeError: 'arguments', 'callee', and 'caller' cannot be accessed in this context." (object error)  [wasThrown]
-    "arguments"  =>  "TypeError: 'arguments', 'callee', and 'caller' cannot be accessed in this context." (object error)  [wasThrown]
     "__proto__"  =>  "function () {\n    [native code]\n}" (function)  [writable | configurable | isOwn]
 Internal Properties:
     "targetFunction"  =>  "class Test { }" (function class)  []
@@ -60,11 +60,11 @@
 Evaluating _expression_...
 Getting displayable properties...
 Properties:
-    "arguments"  =>  null (object null)  [isOwn]
-    "caller"     =>  null (object null)  [isOwn]
     "length"     =>  3 (number)  [configurable | isOwn]
     "name"       =>  "" (string)  [configurable | isOwn]
     "prototype"  =>  "Object" (object)  [writable | isOwn]
+    "arguments"  =>  null (object null)  [configurable | nativeGetter]
+    "caller"     =>  null (object null)  [configurable | nativeGetter]
     "__proto__"  =>  "function () {\n    [native code]\n}" (function)  [writable | configurable | isOwn]
 
 -- Running test case: Runtime.getDisplayableProperties.FunctionNoParameters
@@ -71,11 +71,11 @@
 Evaluating _expression_...
 Getting displayable properties...
 Properties:
-    "arguments"  =>  null (object null)  [isOwn]
-    "caller"     =>  null (object null)  [isOwn]
     "length"     =>  0 (number)  [configurable | isOwn]
     "name"       =>  "" (string)  [configurable | isOwn]
     "prototype"  =>  "Object" (object)  [writable | isOwn]
+    "arguments"  =>  null (object null)  [configurable | nativeGetter]
+    "caller"     =>  null (object null)  [configurable | nativeGetter]
     "__proto__"  =>  "function () {\n    [native code]\n}" (function)  [writable | configurable | isOwn]
 
 -- Running test case: Runtime.getDisplayableProperties.BoundFunction
@@ -84,8 +84,8 @@
 Properties:
     "length"     =>  3 (number)  [configurable | isOwn]
     "name"       =>  "bound " (string)  [configurable | isOwn]
+    "arguments"  =>  "TypeError: 'arguments', 'callee', and 'caller' cannot be accessed in this context." (object error)  [wasThrown]
     "caller"     =>  "TypeError: 'arguments', 'callee', and 'caller' cannot be accessed in this context." (object error)  [wasThrown]
-    "arguments"  =>  "TypeError: 'arguments', 'callee', and 'caller' cannot be accessed in this context." (object error)  [wasThrown]
     "__proto__"  =>  "function () {\n    [native code]\n}" (function)  [writable | configurable | isOwn]
 Internal Properties:
     "targetFunction"  =>  "function (a, b, c){}" (function)  []
@@ -97,8 +97,8 @@
 Properties:
     "length"     =>  0 (number)  [configurable | isOwn]
     "name"       =>  "bound " (string)  [configurable | isOwn]
+    "arguments"  =>  "TypeError: 'arguments', 'callee', and 'caller' cannot be accessed in this context." (object error)  [wasThrown]
     "caller"     =>  "TypeError: 'arguments', 'callee', and 'caller' cannot be accessed in this context." (object error)  [wasThrown]
-    "arguments"  =>  "TypeError: 'arguments', 'callee', and 'caller' cannot be accessed in this context." (object error)  [wasThrown]
     "__proto__"  =>  "function () {\n    [native code]\n}" (function)  [writable | configurable | isOwn]
 Internal Properties:
     "targetFunction"  =>  "function (a, b, c){}" (function)  []
@@ -111,8 +111,8 @@
 Properties:
     "length"     =>  0 (number)  [configurable | isOwn]
     "name"       =>  "bound " (string)  [configurable | isOwn]
+    "arguments"  =>  "TypeError: 'arguments', 'callee', and 'caller' cannot be accessed in this context." (object error)  [wasThrown]
     "caller"     =>  "TypeError: 'arguments', 'callee', and 'caller' cannot be accessed in this context." (object error)  [wasThrown]
-    "arguments"  =>  "TypeError: 'arguments', 'callee', and 'caller' cannot be accessed in this context." (object error)  [wasThrown]
     "__proto__"  =>  "function () {\n    [native code]\n}" (function)  [writable | configurable | isOwn]
 Internal Properties:
     "targetFunction"  =>  "function (){}" (function)  []
@@ -124,8 +124,8 @@
 Properties:
     "length"     =>  0 (number)  [configurable | isOwn]
     "name"       =>  "bound " (string)  [configurable | isOwn]
+    "arguments"  =>  "TypeError: 'arguments', 'callee', and 'caller' cannot be accessed in this context." (object error)  [wasThrown]
     "caller"     =>  "TypeError: 'arguments', 'callee', and 'caller' cannot be accessed in this context." (object error)  [wasThrown]
-    "arguments"  =>  "TypeError: 'arguments', 'callee', and 'caller' cannot be accessed in this context." (object error)  [wasThrown]
     "__proto__"  =>  "function () {\n    [native code]\n}" (function)  [writable | configurable | isOwn]
 Internal Properties:
     "targetFunction"  =>  "function (){}" (function)  []

Modified: trunk/LayoutTests/inspector/runtime/getProperties-expected.txt (280288 => 280289)


--- trunk/LayoutTests/inspector/runtime/getProperties-expected.txt	2021-07-25 19:40:36 UTC (rev 280288)
+++ trunk/LayoutTests/inspector/runtime/getProperties-expected.txt	2021-07-25 22:32:20 UTC (rev 280289)
@@ -54,8 +54,6 @@
 Evaluating _expression_...
 Getting own properties...
 Properties:
-    "arguments"  =>  null (object null)  [isOwn]
-    "caller"     =>  null (object null)  [isOwn]
     "length"     =>  3 (number)  [configurable | isOwn]
     "name"       =>  "" (string)  [configurable | isOwn]
     "prototype"  =>  "Object" (object)  [writable | isOwn]
@@ -65,8 +63,6 @@
 Evaluating _expression_...
 Getting own properties...
 Properties:
-    "arguments"  =>  null (object null)  [isOwn]
-    "caller"     =>  null (object null)  [isOwn]
     "length"     =>  0 (number)  [configurable | isOwn]
     "name"       =>  "" (string)  [configurable | isOwn]
     "prototype"  =>  "Object" (object)  [writable | isOwn]

Modified: trunk/LayoutTests/js/Object-getOwnPropertyNames-expected.txt (280288 => 280289)


--- trunk/LayoutTests/js/Object-getOwnPropertyNames-expected.txt	2021-07-25 19:40:36 UTC (rev 280288)
+++ trunk/LayoutTests/js/Object-getOwnPropertyNames-expected.txt	2021-07-25 22:32:20 UTC (rev 280289)
@@ -11,8 +11,8 @@
 PASS getSortedOwnPropertyNames({__proto__:[1,2,3]}) is []
 PASS getSortedOwnPropertyNames(Object.create({}, { 'a': { 'value': 1, 'enumerable': false } })) is ['a']
 PASS getSortedOwnPropertyNames(Object.create([1,2,3], { 'a': { 'value': 1, 'enumerable': false } })) is ['a']
-PASS getSortedOwnPropertyNames(new Function()) is ['arguments', 'caller', 'length', 'name', 'prototype']
-PASS getSortedOwnPropertyNames((function(){var x=new Function();x.__proto__=[1,2,3];return x;})()) is ['arguments', 'caller', 'length', 'name', 'prototype']
+PASS getSortedOwnPropertyNames(new Function()) is ['length', 'name', 'prototype']
+PASS getSortedOwnPropertyNames((function(){var x=new Function();x.__proto__=[1,2,3];return x;})()) is ['length', 'name', 'prototype']
 PASS getSortedOwnPropertyNames(new String('')) is ['length']
 PASS getSortedOwnPropertyNames(new String('a')) is ['0', 'length']
 PASS getSortedOwnPropertyNames(new String('abc')) is ['0', '1', '2', 'length']

Modified: trunk/LayoutTests/js/basic-strict-mode-expected.txt (280288 => 280289)


--- trunk/LayoutTests/js/basic-strict-mode-expected.txt	2021-07-25 19:40:36 UTC (rev 280288)
+++ trunk/LayoutTests/js/basic-strict-mode-expected.txt	2021-07-25 22:32:20 UTC (rev 280289)
@@ -186,8 +186,8 @@
 PASS (function f(arg){'use strict'; return Object.getOwnPropertyDescriptor(arguments, 'callee').value; })() is undefined.
 PASS (function f(arg){'use strict'; return Object.getOwnPropertyDescriptor(arguments, 'caller'); })() is undefined.
 PASS (function f(arg){'use strict'; var descriptor = Object.getOwnPropertyDescriptor(arguments, 'callee'); return descriptor.get === descriptor.set; })() is true
-PASS (function f(arg){'use strict'; var descriptor = Object.getOwnPropertyDescriptor(f.__proto__, 'caller'); return descriptor.get === descriptor.set; })() is true
-PASS (function f(arg){'use strict'; var descriptor = Object.getOwnPropertyDescriptor(f.__proto__, 'arguments'); return descriptor.get === descriptor.set; })() is true
+PASS (function f(arg){'use strict'; var descriptor = Object.getOwnPropertyDescriptor(f.__proto__, 'caller'); return descriptor.get === descriptor.set; })() is false
+PASS (function f(arg){'use strict'; var descriptor = Object.getOwnPropertyDescriptor(f.__proto__, 'arguments'); return descriptor.get === descriptor.set; })() is false
 PASS 'use strict'; (function f() { for(var i in this); })(); true; is true
 PASS 'use strict'̻ threw exception SyntaxError: Invalid character '\u033b'.
 PASS (function(){'use strict'̻}) threw exception SyntaxError: Invalid character '\u033b'.
@@ -213,7 +213,7 @@
 PASS try { throw 1; } catch (e) { aGlobal = true; } is true
 PASS (function () { try { throw 1; } catch (e) { aGlobal = true; }})(); aGlobal; is true
 PASS (function () {try { throw 1; } catch (e) { aGlobal = true; }})(); aGlobal; is true
-PASS String(Object.getOwnPropertyDescriptor((function() { "use strict"; }).__proto__, "caller").get) is 'function () {\n    [native code]\n}'
+PASS String(Object.getOwnPropertyDescriptor((function() { "use strict"; }).__proto__, "caller").get) is 'function caller() {\n    [native code]\n}'
 PASS successfullyParsed is true
 
 TEST COMPLETE

Modified: trunk/LayoutTests/js/kde/function_arguments-expected.txt (280288 => 280289)


--- trunk/LayoutTests/js/kde/function_arguments-expected.txt	2021-07-25 19:40:36 UTC (rev 280288)
+++ trunk/LayoutTests/js/kde/function_arguments-expected.txt	2021-07-25 22:32:20 UTC (rev 280289)
@@ -13,9 +13,8 @@
 PASS mf.arguments[0] is expected[expno++]
 PASS mf.arguments[0] is expected[expno++]
 PASS mf.arguments is expected[expno++]
-PASS ReadOnlyOK is true
-PASS DontDeleteOK is true
-PASS DontEnumOK is true
+PASS f.hasOwnProperty('arguments') is false
+PASS f.hasOwnProperty('caller') is false
 PASS arg0 is 1
 PASS arg1 is 2
 PASS arg2 is 3

Modified: trunk/LayoutTests/js/kde/script-tests/function_arguments.js (280288 => 280289)


--- trunk/LayoutTests/js/kde/script-tests/function_arguments.js	2021-07-25 19:40:36 UTC (rev 280288)
+++ trunk/LayoutTests/js/kde/script-tests/function_arguments.js	2021-07-25 22:32:20 UTC (rev 280289)
@@ -16,42 +16,12 @@
 mf(99);
 shouldBe("mf.arguments", "expected[expno++]");
 
-
-// check internal properties of arguments
-
-// Delete
-
-
-// DontEnum
-var foundArgs = false;
-
-var ReadOnlyOK = false;
-var DontDeleteOK = false;
-var DontEnumOK = false;
+// Check that sloppy mode ES5 function doesn't have own 'arguments' and 'caller' properties
 function f(a,b,c) {
-
-  // ReadOnly
-  var newargs = new Object();
-  f.arguments = newargs;
-  ReadOnlyOK = (f.arguments != newargs);
-
-  // DontDelete
-  DontDeleteOK = !delete(f.arguments);
-  if (f.arguments == undefined || !f.__proto__.hasOwnProperty("arguments"))
-    DontDeleteOK = false;
-
-  // DontEnum
-  var foundArgs = false;
-  for (i in f) {
-    if (f == "arguments")
-      foundArgs = true;
-  }
-  DontEnumOK = !foundArgs;
+  shouldBeFalse("f.hasOwnProperty('arguments')");
+  shouldBeFalse("f.hasOwnProperty('caller')");
 }
 f(1,2,3);
-shouldBeTrue("ReadOnlyOK");
-shouldBeTrue("DontDeleteOK");
-shouldBeTrue("DontEnumOK");
 
 // Check that parameter variables are bound to the corresponding
 // elements in the arguments array

Modified: trunk/LayoutTests/js/non-strict-function-properties-expected.txt (280288 => 280289)


--- trunk/LayoutTests/js/non-strict-function-properties-expected.txt	2021-07-25 19:40:36 UTC (rev 280288)
+++ trunk/LayoutTests/js/non-strict-function-properties-expected.txt	2021-07-25 22:32:20 UTC (rev 280289)
@@ -3,15 +3,15 @@
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
 
 
-PASS Object.getOwnPropertyNames(function () {}).length is 5
-PASS Object.getOwnPropertyNames(function () {}).includes("caller") is true
-PASS Object.getOwnPropertyNames(function () {}).includes("arguments") is true
-PASS (function(){}).hasOwnProperty("caller") is true
+PASS Object.getOwnPropertyNames(function () {}).length is 3
+PASS Object.getOwnPropertyNames(function () {}).includes("caller") is false
+PASS Object.getOwnPropertyNames(function () {}).includes("arguments") is false
+PASS (function(){}).hasOwnProperty("caller") is false
 PASS (function(){}).__proto__.hasOwnProperty("caller") is true
-PASS (function(){}).hasOwnProperty("arguments") is true
+PASS (function(){}).hasOwnProperty("arguments") is false
 PASS (function(){}).__proto__.hasOwnProperty("arguments") is true
-PASS typeof Object.getOwnPropertyDescriptor(foo, "arguments") is "object"
-PASS typeof Object.getOwnPropertyDescriptor(foo, "caller") is "object"
+PASS typeof Object.getOwnPropertyDescriptor(foo, "arguments") is "undefined"
+PASS typeof Object.getOwnPropertyDescriptor(foo, "caller") is "undefined"
 PASS foo.caller is null
 PASS foo.arguments is null
 PASS foo.caller is null

Modified: trunk/LayoutTests/js/script-tests/Object-getOwnPropertyNames.js (280288 => 280289)


--- trunk/LayoutTests/js/script-tests/Object-getOwnPropertyNames.js	2021-07-25 19:40:36 UTC (rev 280288)
+++ trunk/LayoutTests/js/script-tests/Object-getOwnPropertyNames.js	2021-07-25 22:32:20 UTC (rev 280289)
@@ -12,8 +12,8 @@
     "Object.create({}, { 'a': { 'value': 1, 'enumerable': false } })": "['a']",
     "Object.create([1,2,3], { 'a': { 'value': 1, 'enumerable': false } })": "['a']",
 // Function objects
-    "new Function()": "['arguments', 'caller', 'length', 'name', 'prototype']",
-    "(function(){var x=new Function();x.__proto__=[1,2,3];return x;})()": "['arguments', 'caller', 'length', 'name', 'prototype']",
+    "new Function()": "['length', 'name', 'prototype']",
+    "(function(){var x=new Function();x.__proto__=[1,2,3];return x;})()": "['length', 'name', 'prototype']",
 // String objects
     "new String('')": "['length']",
     "new String('a')": "['0', 'length']",

Modified: trunk/LayoutTests/js/script-tests/basic-strict-mode.js (280288 => 280289)


--- trunk/LayoutTests/js/script-tests/basic-strict-mode.js	2021-07-25 19:40:36 UTC (rev 280288)
+++ trunk/LayoutTests/js/script-tests/basic-strict-mode.js	2021-07-25 22:32:20 UTC (rev 280289)
@@ -187,8 +187,8 @@
 shouldBeUndefined("(function f(arg){'use strict'; return Object.getOwnPropertyDescriptor(arguments, 'callee').value; })()");
 shouldBeUndefined("(function f(arg){'use strict'; return Object.getOwnPropertyDescriptor(arguments, 'caller'); })()");
 shouldBeTrue("(function f(arg){'use strict'; var descriptor = Object.getOwnPropertyDescriptor(arguments, 'callee'); return descriptor.get === descriptor.set; })()");
-shouldBeTrue("(function f(arg){'use strict'; var descriptor = Object.getOwnPropertyDescriptor(f.__proto__, 'caller'); return descriptor.get === descriptor.set; })()");
-shouldBeTrue("(function f(arg){'use strict'; var descriptor = Object.getOwnPropertyDescriptor(f.__proto__, 'arguments'); return descriptor.get === descriptor.set; })()");
+shouldBeFalse("(function f(arg){'use strict'; var descriptor = Object.getOwnPropertyDescriptor(f.__proto__, 'caller'); return descriptor.get === descriptor.set; })()");
+shouldBeFalse("(function f(arg){'use strict'; var descriptor = Object.getOwnPropertyDescriptor(f.__proto__, 'arguments'); return descriptor.get === descriptor.set; })()");
 shouldBeTrue("'use strict'; (function f() { for(var i in this); })(); true;")
 
 shouldBeSyntaxError("'use strict'\u033b");
@@ -215,4 +215,4 @@
 shouldBeTrue("(function () {try { throw 1; } catch (e) { aGlobal = true; }})(); aGlobal;");
 
 // Make sure this doesn't crash!
-shouldBe('String(Object.getOwnPropertyDescriptor((function() { "use strict"; }).__proto__, "caller").get)', "'function () {\\n    [native code]\\n}'");
+shouldBe('String(Object.getOwnPropertyDescriptor((function() { "use strict"; }).__proto__, "caller").get)', "'function caller() {\\n    [native code]\\n}'");

Modified: trunk/LayoutTests/js/script-tests/non-strict-function-properties.js (280288 => 280289)


--- trunk/LayoutTests/js/script-tests/non-strict-function-properties.js	2021-07-25 19:40:36 UTC (rev 280288)
+++ trunk/LayoutTests/js/script-tests/non-strict-function-properties.js	2021-07-25 22:32:20 UTC (rev 280289)
@@ -4,19 +4,19 @@
     return 1;
 }
 
-shouldBe('Object.getOwnPropertyNames(function () {}).length','5');
+shouldBe('Object.getOwnPropertyNames(function () {}).length', '3');
 
-shouldBeTrue('Object.getOwnPropertyNames(function () {}).includes("caller")');
-shouldBeTrue('Object.getOwnPropertyNames(function () {}).includes("arguments")');
+shouldBeFalse('Object.getOwnPropertyNames(function () {}).includes("caller")');
+shouldBeFalse('Object.getOwnPropertyNames(function () {}).includes("arguments")');
 
-shouldBeTrue('(function(){}).hasOwnProperty("caller")');
+shouldBeFalse('(function(){}).hasOwnProperty("caller")');
 shouldBeTrue('(function(){}).__proto__.hasOwnProperty("caller")');
 
-shouldBeTrue('(function(){}).hasOwnProperty("arguments")');
+shouldBeFalse('(function(){}).hasOwnProperty("arguments")');
 shouldBeTrue('(function(){}).__proto__.hasOwnProperty("arguments")');
 
-shouldBe('typeof Object.getOwnPropertyDescriptor(foo, "arguments")', '"object"');
-shouldBe('typeof Object.getOwnPropertyDescriptor(foo, "caller")', '"object"');
+shouldBe('typeof Object.getOwnPropertyDescriptor(foo, "arguments")', '"undefined"');
+shouldBe('typeof Object.getOwnPropertyDescriptor(foo, "caller")', '"undefined"');
 
 shouldBe('foo.caller', 'null');
 shouldBe('foo.arguments', 'null');

Modified: trunk/LayoutTests/js/script-tests/throw-type-error-is-unique.js (280288 => 280289)


--- trunk/LayoutTests/js/script-tests/throw-type-error-is-unique.js	2021-07-25 19:40:36 UTC (rev 280288)
+++ trunk/LayoutTests/js/script-tests/throw-type-error-is-unique.js	2021-07-25 22:32:20 UTC (rev 280289)
@@ -47,13 +47,8 @@
     let baseThrowTypeErrorFunction = Object.getOwnPropertyDescriptor(arguments, "callee").get;
 
     let sources = [
-        new ThrowTypeErrorSource("Function.prototype", Function.prototype, ["arguments", "caller"]),
-        new ThrowTypeErrorSource("Array.prototype.push (builtin)", arrayProtoPush, ["arguments", "caller"]),
-        new ThrowTypeErrorSource("Strict function arguments", strictArguments, ["arguments", "caller"]),
-        new ThrowTypeErrorSource("Sloppy function arguments", sloppyArguments, ["arguments", "caller"]),
-        new ThrowTypeErrorSource("Strict arguments", strictArguments(), ["callee", "caller"]),
-        new ThrowTypeErrorSource("Sloppy arguments", sloppyArguments(), ["callee", "caller"]),
-        new ThrowTypeErrorSource("Class constructor", (new A()).constructor, ["arguments", "caller"])
+        new ThrowTypeErrorSource("Strict arguments", strictArguments(), ["callee"]),
+        new ThrowTypeErrorSource("Sloppy arguments", sloppyArguments(), ["callee"]),
     ];
 
     let errors = 0;

Modified: trunk/Source/_javascript_Core/ChangeLog (280288 => 280289)


--- trunk/Source/_javascript_Core/ChangeLog	2021-07-25 19:40:36 UTC (rev 280288)
+++ trunk/Source/_javascript_Core/ChangeLog	2021-07-25 22:32:20 UTC (rev 280289)
@@ -1,3 +1,91 @@
+2021-07-25  Alexey Shvayka  <[email protected]>
+
+        Partly implement Function.prototype.{caller,arguments} reflection proposal
+        https://bugs.webkit.org/show_bug.cgi?id=158116
+
+        Reviewed by Yusuke Suzuki.
+
+        To ensure web-compatibility, only the safe subset of Function.prototype.{caller,arguments}
+        reflection proposal [1] is implemented, which is currently shipped in SpiderMonkey.
+
+        Complete list of differences from the proposed spec:
+
+          1. Cross-realm receiver function is allowed instead of throwing a TypeError.
+
+             Throwing is likely safe to ship, but #225997 needs to be fixed first for
+             custom properties to receive correct global object.
+
+          2. Cross-realm caller function is returned instead of `null`.
+
+             Hiding cross-realm caller may break things: we currently have a test for
+             the opposite behavior.
+
+          3. Defines "caller" and "arguments" setters that throw for disallowed receivers,
+             instead failing silently in sloppy mode.
+
+             This is actually more restrictive than the spec, which is preferable,
+             and aligns with V8 and SM.
+
+        Most importantly, this patch removes own "caller" and "arguments" properties from
+        sloppy mode ES5 functions. They were non-configurable, making it harder to use
+        their holder as a [[ProxyTarget]]. They were also non-writable, with a constantly
+        changing [[Value]], which violated the invariants of internal methods [2].
+
+        As a result, JSFunction methods are greatly simplified, especially defineOwnProperty()
+        and getOwnSpecialPropertyNames(). The latter is now 2.1x faster according to the
+        provided microbenchmark. Also, removes double "prototype" lookup from [[Get]],
+        which is a 10% progression.
+
+        [1]: https://github.com/claudepache/es-legacy-function-reflection
+        [2]: https://tc39.es/ecma262/#sec-invariants-of-the-essential-internal-methods
+
+        * runtime/ClonedArguments.cpp:
+        (JSC::ClonedArguments::getOwnPropertySlot):
+        (JSC::ClonedArguments::materializeSpecials):
+        * runtime/FunctionExecutable.h:
+        * runtime/FunctionPrototype.cpp:
+        (JSC::FunctionPrototype::addFunctionProperties):
+        (JSC::isAllowedReceiverFunctionForCallerAndArguments):
+        (JSC::RetrieveArgumentsFunctor::RetrieveArgumentsFunctor):
+        (JSC::RetrieveArgumentsFunctor::result const):
+        (JSC::RetrieveArgumentsFunctor::operator() const):
+        (JSC::retrieveArguments):
+        (JSC::JSC_DEFINE_CUSTOM_GETTER):
+        (JSC::RetrieveCallerFunctionFunctor::RetrieveCallerFunctionFunctor):
+        (JSC::RetrieveCallerFunctionFunctor::result const):
+        (JSC::RetrieveCallerFunctionFunctor::operator() const):
+        (JSC::retrieveCallerFunction):
+        (JSC::JSC_DEFINE_CUSTOM_SETTER):
+        (JSC::FunctionPrototype::initRestrictedProperties): Deleted.
+        * runtime/FunctionPrototype.h:
+        * runtime/JSFunction.cpp:
+        (JSC::JSFunction::getOwnPropertySlot):
+        (JSC::JSFunction::getOwnSpecialPropertyNames):
+        (JSC::JSFunction::put):
+        (JSC::JSFunction::deleteProperty):
+        (JSC::JSFunction::defineOwnProperty):
+        (JSC::RetrieveArgumentsFunctor::RetrieveArgumentsFunctor): Deleted.
+        (JSC::RetrieveArgumentsFunctor::result const): Deleted.
+        (JSC::RetrieveArgumentsFunctor::operator() const): Deleted.
+        (JSC::retrieveArguments): Deleted.
+        (JSC::JSC_DEFINE_CUSTOM_GETTER): Deleted.
+        (JSC::RetrieveCallerFunctionFunctor::RetrieveCallerFunctionFunctor): Deleted.
+        (JSC::RetrieveCallerFunctionFunctor::result const): Deleted.
+        (JSC::RetrieveCallerFunctionFunctor::operator() const): Deleted.
+        (JSC::retrieveCallerFunction): Deleted.
+        * runtime/JSGlobalObject.cpp:
+        (JSC::JSGlobalObject::init):
+        (JSC::JSGlobalObject::visitChildrenImpl):
+        * runtime/JSGlobalObject.h:
+        Remove unused m_throwTypeErrorGetterSetter and make [[ThrowTypeError]] lazily-created.
+
+        * runtime/JSGlobalObjectFunctions.cpp:
+        (JSC::JSC_DEFINE_HOST_FUNCTION):
+        * runtime/JSGlobalObjectFunctions.h:
+        * runtime/JSObject.cpp:
+        (JSC::JSObject::putDirectCustomGetterSetterWithoutTransition):
+        * runtime/JSObject.h:
+
 2021-07-24  Yusuke Suzuki  <[email protected]>
 
         [JSC] Change most of enum in Yarr to enum-class

Modified: trunk/Source/_javascript_Core/runtime/ClonedArguments.cpp (280288 => 280289)


--- trunk/Source/_javascript_Core/runtime/ClonedArguments.cpp	2021-07-25 19:40:36 UTC (rev 280288)
+++ trunk/Source/_javascript_Core/runtime/ClonedArguments.cpp	2021-07-25 22:32:20 UTC (rev 280289)
@@ -181,7 +181,7 @@
 
         if (ident == vm.propertyNames->callee) {
             if (isStrictMode || executable->usesNonSimpleParameterList()) {
-                slot.setGetterSlot(thisObject, PropertyAttribute::DontDelete | PropertyAttribute::DontEnum | PropertyAttribute::Accessor, thisObject->globalObject(vm)->throwTypeErrorArgumentsCalleeAndCallerGetterSetter());
+                slot.setGetterSlot(thisObject, PropertyAttribute::DontDelete | PropertyAttribute::DontEnum | PropertyAttribute::Accessor, thisObject->globalObject(vm)->throwTypeErrorArgumentsCalleeGetterSetter());
                 return true;
             }
             slot.setValue(thisObject, 0, thisObject->m_callee.get());
@@ -252,7 +252,7 @@
     bool isStrictMode = executable->isInStrictContext();
     
     if (isStrictMode || executable->usesNonSimpleParameterList())
-        putDirectAccessor(globalObject, vm.propertyNames->callee, this->globalObject(vm)->throwTypeErrorArgumentsCalleeAndCallerGetterSetter(), PropertyAttribute::DontDelete | PropertyAttribute::DontEnum | PropertyAttribute::Accessor);
+        putDirectAccessor(globalObject, vm.propertyNames->callee, this->globalObject(vm)->throwTypeErrorArgumentsCalleeGetterSetter(), PropertyAttribute::DontDelete | PropertyAttribute::DontEnum | PropertyAttribute::Accessor);
     else
         putDirect(vm, vm.propertyNames->callee, JSValue(m_callee.get()));
 

Modified: trunk/Source/_javascript_Core/runtime/FunctionExecutable.h (280288 => 280289)


--- trunk/Source/_javascript_Core/runtime/FunctionExecutable.h	2021-07-25 19:40:36 UTC (rev 280288)
+++ trunk/Source/_javascript_Core/runtime/FunctionExecutable.h	2021-07-25 22:32:20 UTC (rev 280289)
@@ -139,12 +139,6 @@
     bool isGenerator() const { return isGeneratorParseMode(parseMode()); }
     bool isAsyncGenerator() const { return isAsyncGeneratorParseMode(parseMode()); }
     bool isMethod() const { return parseMode() == SourceParseMode::MethodMode; }
-    bool hasCallerAndArgumentsProperties() const
-    {
-        // Per https://tc39.github.io/ecma262/#sec-forbidden-extensions, only sloppy-mode non-builtin functions in old-style (pre-ES6) syntactic forms can contain
-        // "caller" and "arguments".
-        return !isInStrictContext() && parseMode() == SourceParseMode::NormalFunctionMode && !isClassConstructorFunction();
-    }
     bool hasPrototypeProperty() const
     {
         return SourceParseModeSet(

Modified: trunk/Source/_javascript_Core/runtime/FunctionPrototype.cpp (280288 => 280289)


--- trunk/Source/_javascript_Core/runtime/FunctionPrototype.cpp	2021-07-25 19:40:36 UTC (rev 280288)
+++ trunk/Source/_javascript_Core/runtime/FunctionPrototype.cpp	2021-07-25 22:32:20 UTC (rev 280289)
@@ -22,8 +22,10 @@
 #include "FunctionPrototype.h"
 
 #include "BuiltinNames.h"
+#include "ClonedArguments.h"
 #include "FunctionExecutable.h"
 #include "IntegrityInlines.h"
+#include "JSBoundFunction.h"
 #include "JSCInlines.h"
 
 namespace JSC {
@@ -35,6 +37,10 @@
 static JSC_DECLARE_HOST_FUNCTION(functionProtoFuncToString);
 static JSC_DECLARE_HOST_FUNCTION(callFunctionPrototype);
 
+static JSC_DECLARE_CUSTOM_GETTER(argumentsGetter);
+static JSC_DECLARE_CUSTOM_GETTER(callerGetter);
+static JSC_DECLARE_CUSTOM_SETTER(callerAndArgumentsSetter);
+
 // https://tc39.es/ecma262/#sec-properties-of-the-function-prototype-object
 JSC_DEFINE_HOST_FUNCTION(callFunctionPrototype, (JSGlobalObject*, CallFrame*))
 {
@@ -60,16 +66,12 @@
     *callFunction = putDirectBuiltinFunctionWithoutTransition(vm, globalObject, vm.propertyNames->builtinNames().callPublicName(), functionPrototypeCallCodeGenerator(vm), static_cast<unsigned>(PropertyAttribute::DontEnum));
     putDirectBuiltinFunctionWithoutTransition(vm, globalObject, vm.propertyNames->bind, functionPrototypeBindCodeGenerator(vm), static_cast<unsigned>(PropertyAttribute::DontEnum));
 
+    putDirectCustomGetterSetterWithoutTransition(vm, vm.propertyNames->arguments, CustomGetterSetter::create(vm, argumentsGetter, callerAndArgumentsSetter), PropertyAttribute::DontEnum | PropertyAttribute::CustomAccessor);
+    putDirectCustomGetterSetterWithoutTransition(vm, vm.propertyNames->caller, CustomGetterSetter::create(vm, callerGetter, callerAndArgumentsSetter), PropertyAttribute::DontEnum | PropertyAttribute::CustomAccessor);
+
     *hasInstanceSymbolFunction = JSFunction::create(vm, functionPrototypeSymbolHasInstanceCodeGenerator(vm), globalObject);
     putDirectWithoutTransition(vm, vm.propertyNames->hasInstanceSymbol, *hasInstanceSymbolFunction, PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly | PropertyAttribute::DontEnum);
 }
-    
-void FunctionPrototype::initRestrictedProperties(VM& vm, JSGlobalObject* globalObject)
-{
-    GetterSetter* errorGetterSetter = globalObject->throwTypeErrorArgumentsCalleeAndCallerGetterSetter();
-    putDirectNonIndexAccessorWithoutTransition(vm, vm.propertyNames->caller, errorGetterSetter, PropertyAttribute::DontEnum | PropertyAttribute::Accessor);
-    putDirectNonIndexAccessorWithoutTransition(vm, vm.propertyNames->arguments, errorGetterSetter, PropertyAttribute::DontEnum | PropertyAttribute::Accessor);
-}
 
 JSC_DEFINE_HOST_FUNCTION(functionProtoFuncToString, (JSGlobalObject* globalObject, CallFrame* callFrame))
 {
@@ -99,4 +101,161 @@
     return throwVMTypeError(globalObject, scope);
 }
 
+// https://github.com/claudepache/es-legacy-function-reflection/blob/master/spec.md#isallowedreceiverfunctionforcallerandargumentsfunc-expectedrealm (except step 3)
+static ALWAYS_INLINE bool isAllowedReceiverFunctionForCallerAndArguments(JSFunction* function)
+{
+    if (function->isHostOrBuiltinFunction())
+        return false;
+
+    FunctionExecutable* executable = function->jsExecutable();
+    return !executable->isInStrictContext() && executable->parseMode() == SourceParseMode::NormalFunctionMode && !executable->isClassConstructorFunction();
+}
+
+class RetrieveArgumentsFunctor {
+public:
+    RetrieveArgumentsFunctor(VM& vm, JSFunction* functionObj)
+        : m_vm(vm)
+        , m_targetCallee(functionObj)
+        , m_result(jsNull())
+    {
+    }
+
+    JSValue result() const { return m_result; }
+
+    StackVisitor::Status operator()(StackVisitor& visitor) const
+    {
+        if (!visitor->callee().isCell())
+            return StackVisitor::Continue;
+
+        JSCell* callee = visitor->callee().asCell();
+        if (callee != m_targetCallee)
+            return StackVisitor::Continue;
+
+        m_result = JSValue(visitor->createArguments(m_vm));
+        return StackVisitor::Done;
+    }
+
+private:
+    VM& m_vm;
+    JSObject* m_targetCallee;
+    mutable JSValue m_result;
+};
+
+static JSValue retrieveArguments(VM& vm, CallFrame* callFrame, JSFunction* functionObj)
+{
+    RetrieveArgumentsFunctor functor(vm, functionObj);
+    if (callFrame)
+        callFrame->iterate(vm, functor);
+    return functor.result();
+}
+
+// https://github.com/claudepache/es-legacy-function-reflection/blob/master/spec.md#get-functionprototypearguments
+JSC_DEFINE_CUSTOM_GETTER(argumentsGetter, (JSGlobalObject* globalObject, EncodedJSValue thisValue, PropertyName))
+{
+    VM& vm = globalObject->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
+    JSFunction* thisObj = jsDynamicCast<JSFunction*>(vm, JSValue::decode(thisValue));
+    if (!thisObj || !isAllowedReceiverFunctionForCallerAndArguments(thisObj))
+        return throwVMTypeError(globalObject, scope, RestrictedPropertyAccessError);
+
+    return JSValue::encode(retrieveArguments(vm, vm.topCallFrame, thisObj));
+}
+
+class RetrieveCallerFunctionFunctor {
+public:
+    RetrieveCallerFunctionFunctor(JSFunction* functionObj)
+        : m_targetCallee(functionObj)
+        , m_hasFoundFrame(false)
+        , m_hasSkippedToCallerFrame(false)
+        , m_result(jsNull())
+    {
+    }
+
+    JSValue result() const { return m_result; }
+
+    StackVisitor::Status operator()(StackVisitor& visitor) const
+    {
+        if (!visitor->callee().isCell())
+            return StackVisitor::Continue;
+
+        JSCell* callee = visitor->callee().asCell();
+
+        if (callee && callee->inherits<JSBoundFunction>(callee->vm()))
+            return StackVisitor::Continue;
+
+        if (!m_hasFoundFrame && callee != m_targetCallee)
+            return StackVisitor::Continue;
+
+        m_hasFoundFrame = true;
+        if (!m_hasSkippedToCallerFrame) {
+            m_hasSkippedToCallerFrame = true;
+            return StackVisitor::Continue;
+        }
+
+        if (callee)
+            m_result = callee;
+        return StackVisitor::Done;
+    }
+
+private:
+    JSObject* m_targetCallee;
+    mutable bool m_hasFoundFrame;
+    mutable bool m_hasSkippedToCallerFrame;
+    mutable JSValue m_result;
+};
+
+static JSValue retrieveCallerFunction(VM& vm, CallFrame* callFrame, JSFunction* functionObj)
+{
+    RetrieveCallerFunctionFunctor functor(functionObj);
+    if (callFrame)
+        callFrame->iterate(vm, functor);
+    return functor.result();
+}
+
+// https://github.com/claudepache/es-legacy-function-reflection/blob/master/spec.md#get-functionprototypecaller
+JSC_DEFINE_CUSTOM_GETTER(callerGetter, (JSGlobalObject* globalObject, EncodedJSValue thisValue, PropertyName))
+{
+    VM& vm = globalObject->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
+    JSFunction* thisObj = jsDynamicCast<JSFunction*>(vm, JSValue::decode(thisValue));
+    if (!thisObj || !isAllowedReceiverFunctionForCallerAndArguments(thisObj))
+        return throwVMTypeError(globalObject, scope, RestrictedPropertyAccessError);
+
+    JSValue caller = retrieveCallerFunction(vm, vm.topCallFrame, thisObj);
+    if (caller.isNull())
+        return JSValue::encode(jsNull());
+
+    // 11. If caller is not an ECMAScript function object, return null.
+    JSFunction* function = jsDynamicCast<JSFunction*>(vm, caller);
+    if (!function || function->isHostOrBuiltinFunction())
+        return JSValue::encode(jsNull());
+
+    // 12. If caller.[[Strict]] is true, return null.
+    if (function->jsExecutable()->isInStrictContext())
+        return JSValue::encode(jsNull());
+
+    // Prevent bodies (private implementations) of generator / async functions from being exposed.
+    // They expect to be called by @generatorResume() & friends with certain arguments, and crash otherwise.
+    // 14. If caller.[[ECMAScriptCode]] is a GeneratorBody, an AsyncFunctionBody, an AsyncGeneratorBody, or an AsyncConciseBody, return null.
+    SourceParseMode parseMode = function->jsExecutable()->parseMode();
+    if (isGeneratorParseMode(parseMode) || isAsyncFunctionParseMode(parseMode))
+        return JSValue::encode(jsNull());
+
+    return JSValue::encode(caller);
+}
+
+JSC_DEFINE_CUSTOM_SETTER(callerAndArgumentsSetter, (JSGlobalObject* globalObject, EncodedJSValue thisValue, EncodedJSValue, PropertyName))
+{
+    VM& vm = globalObject->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
+    JSFunction* thisObj = jsDynamicCast<JSFunction*>(vm, JSValue::decode(thisValue));
+    if (!thisObj || !isAllowedReceiverFunctionForCallerAndArguments(thisObj))
+        throwTypeError(globalObject, scope, RestrictedPropertyAccessError);
+
+    return true;
+}
+
 } // namespace JSC

Modified: trunk/Source/_javascript_Core/runtime/FunctionPrototype.h (280288 => 280289)


--- trunk/Source/_javascript_Core/runtime/FunctionPrototype.h	2021-07-25 19:40:36 UTC (rev 280288)
+++ trunk/Source/_javascript_Core/runtime/FunctionPrototype.h	2021-07-25 22:32:20 UTC (rev 280289)
@@ -37,8 +37,6 @@
 
     void addFunctionProperties(VM&, JSGlobalObject*, JSFunction** callFunction, JSFunction** applyFunction, JSFunction** hasInstanceSymbolFunction);
 
-    void initRestrictedProperties(VM&, JSGlobalObject*);
-
     static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto)
     {
         return Structure::create(vm, globalObject, proto, TypeInfo(InternalFunctionType, StructureFlags), info());

Modified: trunk/Source/_javascript_Core/runtime/JSFunction.cpp (280288 => 280289)


--- trunk/Source/_javascript_Core/runtime/JSFunction.cpp	2021-07-25 19:40:36 UTC (rev 280288)
+++ trunk/Source/_javascript_Core/runtime/JSFunction.cpp	2021-07-25 22:32:20 UTC (rev 280289)
@@ -29,7 +29,6 @@
 #include "AsyncGeneratorPrototype.h"
 #include "BuiltinNames.h"
 #include "CatchScope.h"
-#include "ClonedArguments.h"
 #include "CommonIdentifiers.h"
 #include "CallFrame.h"
 #include "GeneratorPrototype.h"
@@ -53,9 +52,6 @@
     return throwVMError(globalObject, scope, createNotAConstructorError(globalObject, callFrame->jsCallee()));
 }
 
-static JSC_DECLARE_CUSTOM_GETTER(argumentsGetter);
-static JSC_DECLARE_CUSTOM_GETTER(callerGetter);
-
 const ClassInfo JSFunction::s_info = { "Function", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSFunction) };
 const ClassInfo JSStrictFunction::s_info = { "Function", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSStrictFunction) };
 const ClassInfo JSSloppyFunction::s_info = { "Function", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSSloppyFunction) };
@@ -300,139 +296,6 @@
     return callData;
 }
 
-class RetrieveArgumentsFunctor {
-public:
-    RetrieveArgumentsFunctor(VM& vm, JSFunction* functionObj)
-        : m_vm(vm)
-        , m_targetCallee(functionObj)
-        , m_result(jsNull())
-    {
-    }
-
-    JSValue result() const { return m_result; }
-
-    StackVisitor::Status operator()(StackVisitor& visitor) const
-    {
-        if (!visitor->callee().isCell())
-            return StackVisitor::Continue;
-
-        JSCell* callee = visitor->callee().asCell();
-        if (callee != m_targetCallee)
-            return StackVisitor::Continue;
-
-        m_result = JSValue(visitor->createArguments(m_vm));
-        return StackVisitor::Done;
-    }
-
-private:
-    VM& m_vm;
-    JSObject* m_targetCallee;
-    mutable JSValue m_result;
-};
-
-static JSValue retrieveArguments(VM& vm, CallFrame* callFrame, JSFunction* functionObj)
-{
-    RetrieveArgumentsFunctor functor(vm, functionObj);
-    if (callFrame)
-        callFrame->iterate(vm, functor);
-    return functor.result();
-}
-
-JSC_DEFINE_CUSTOM_GETTER(argumentsGetter, (JSGlobalObject* globalObject, EncodedJSValue thisValue, PropertyName))
-{
-    VM& vm = globalObject->vm();
-    JSFunction* thisObj = jsCast<JSFunction*>(JSValue::decode(thisValue));
-    ASSERT(!thisObj->isHostFunction());
-
-    return JSValue::encode(retrieveArguments(vm, vm.topCallFrame, thisObj));
-}
-
-class RetrieveCallerFunctionFunctor {
-public:
-    RetrieveCallerFunctionFunctor(JSFunction* functionObj)
-        : m_targetCallee(functionObj)
-        , m_hasFoundFrame(false)
-        , m_hasSkippedToCallerFrame(false)
-        , m_result(jsNull())
-    {
-    }
-
-    JSValue result() const { return m_result; }
-
-    StackVisitor::Status operator()(StackVisitor& visitor) const
-    {
-        if (!visitor->callee().isCell())
-            return StackVisitor::Continue;
-
-        JSCell* callee = visitor->callee().asCell();
-
-        if (callee && callee->inherits<JSBoundFunction>(callee->vm()))
-            return StackVisitor::Continue;
-
-        if (!m_hasFoundFrame && (callee != m_targetCallee))
-            return StackVisitor::Continue;
-
-        m_hasFoundFrame = true;
-        if (!m_hasSkippedToCallerFrame) {
-            m_hasSkippedToCallerFrame = true;
-            return StackVisitor::Continue;
-        }
-
-        if (callee)
-            m_result = callee;
-        return StackVisitor::Done;
-    }
-
-private:
-    JSObject* m_targetCallee;
-    mutable bool m_hasFoundFrame;
-    mutable bool m_hasSkippedToCallerFrame;
-    mutable JSValue m_result;
-};
-
-static JSValue retrieveCallerFunction(VM& vm, CallFrame* callFrame, JSFunction* functionObj)
-{
-    RetrieveCallerFunctionFunctor functor(functionObj);
-    if (callFrame)
-        callFrame->iterate(vm, functor);
-    return functor.result();
-}
-
-JSC_DEFINE_CUSTOM_GETTER(callerGetter, (JSGlobalObject* globalObject, EncodedJSValue thisValue, PropertyName))
-{
-    VM& vm = globalObject->vm();
-
-    JSFunction* thisObj = jsCast<JSFunction*>(JSValue::decode(thisValue));
-    ASSERT(!thisObj->isHostFunction());
-    JSValue caller = retrieveCallerFunction(vm, vm.topCallFrame, thisObj);
-
-    // See ES5.1 15.3.5.4 - Function.caller may not be used to retrieve a strict caller.
-    if (!caller.isObject() || !asObject(caller)->inherits<JSFunction>(vm)) {
-        // It isn't a JSFunction, but if it is a JSCallee from a program or eval call or an internal constructor, return null.
-        if (jsDynamicCast<JSCallee*>(vm, caller) || jsDynamicCast<InternalFunction*>(vm, caller))
-            return JSValue::encode(jsNull());
-        return JSValue::encode(caller);
-    }
-    JSFunction* function = jsCast<JSFunction*>(caller);
-
-    // Firefox returns null for native code callers, so we match that behavior.
-    if (function->isHostOrBuiltinFunction())
-        return JSValue::encode(jsNull());
-
-    if (function->jsExecutable()->isInStrictContext())
-        return JSValue::encode(jsNull());
-
-    // Prevent bodies (private implementations) of generator / async functions from being exposed.
-    // They are called by @generatorResume() & friends, expecting certain arguments, and crash otherwise.
-    // Also, hide generator / async function wrappers for consistency and because it's on standards track:
-    // https://github.com/claudepache/es-legacy-function-reflection/blob/master/spec.md#get-functionprototypecaller (step 14)
-    SourceParseMode parseMode = function->jsExecutable()->parseMode();
-    if (isGeneratorParseMode(parseMode) || isAsyncFunctionParseMode(parseMode))
-        return JSValue::encode(jsNull());
-
-    return JSValue::encode(caller);
-}
-
 bool JSFunction::getOwnPropertySlot(JSObject* object, JSGlobalObject* globalObject, PropertyName propertyName, PropertySlot& slot)
 {
     VM& vm = globalObject->vm();
@@ -475,21 +338,7 @@
             ASSERT(isValidOffset(offset));
         }
         slot.setValue(thisObject, attributes, thisObject->getDirect(offset), offset);
-    }
-
-    if (propertyName == vm.propertyNames->arguments) {
-        if (!thisObject->jsExecutable()->hasCallerAndArgumentsProperties())
-            RELEASE_AND_RETURN(scope, Base::getOwnPropertySlot(thisObject, globalObject, propertyName, slot));
-        
-        slot.setCacheableCustom(thisObject, PropertyAttribute::ReadOnly | PropertyAttribute::DontEnum | PropertyAttribute::DontDelete, argumentsGetter);
         return true;
-
-    } else if (propertyName == vm.propertyNames->caller) {
-        if (!thisObject->jsExecutable()->hasCallerAndArgumentsProperties())
-            RELEASE_AND_RETURN(scope, Base::getOwnPropertySlot(thisObject, globalObject, propertyName, slot));
-
-        slot.setCacheableCustom(thisObject, PropertyAttribute::ReadOnly | PropertyAttribute::DontEnum | PropertyAttribute::DontDelete, callerGetter);
-        return true;
     }
 
     thisObject->reifyLazyPropertyIfNeeded(vm, globalObject, propertyName);
@@ -502,31 +351,14 @@
 {
     JSFunction* thisObject = jsCast<JSFunction*>(object);
     VM& vm = globalObject->vm();
-    auto scope = DECLARE_THROW_SCOPE(vm);
 
     if (mode == DontEnumPropertiesMode::Include) {
-        if (!thisObject->isHostOrBuiltinFunction()) {
-            // Make sure prototype has been reified.
-            PropertySlot slot(thisObject, PropertySlot::InternalMethodType::VMInquiry, &vm);
-            thisObject->methodTable(vm)->getOwnPropertySlot(thisObject, globalObject, vm.propertyNames->prototype, slot);
-            RETURN_IF_EXCEPTION(scope, void());
-
-            if (thisObject->jsExecutable()->hasCallerAndArgumentsProperties()) {
-                propertyNames.add(vm.propertyNames->arguments);
-                propertyNames.add(vm.propertyNames->caller);
-            }
-            if (!thisObject->hasReifiedLength())
-                propertyNames.add(vm.propertyNames->length);
-            if (!thisObject->hasReifiedName())
-                propertyNames.add(vm.propertyNames->name);
-        } else {
-            if (thisObject->isBuiltinFunction() || thisObject->inherits<JSBoundFunction>(vm)) {
-                if (!thisObject->hasReifiedLength())
-                    propertyNames.add(vm.propertyNames->length);
-                if (!thisObject->hasReifiedName())
-                    propertyNames.add(vm.propertyNames->name);
-            }
-        }
+        if (!thisObject->hasReifiedLength())
+            propertyNames.add(vm.propertyNames->length);
+        if (!thisObject->hasReifiedName())
+            propertyNames.add(vm.propertyNames->name);
+        if (!thisObject->isHostOrBuiltinFunction() && thisObject->jsExecutable()->hasPrototypeProperty())
+            propertyNames.add(vm.propertyNames->prototype);
     }
 }
 
@@ -566,13 +398,6 @@
         RELEASE_AND_RETURN(scope, Base::put(thisObject, globalObject, propertyName, value, slot));
     }
 
-    if (propertyName == vm.propertyNames->arguments || propertyName == vm.propertyNames->caller) {
-        if (!thisObject->jsExecutable()->hasCallerAndArgumentsProperties())
-            RELEASE_AND_RETURN(scope, Base::put(thisObject, globalObject, propertyName, value, slot));
-
-        slot.disableCaching();
-        return typeError(globalObject, scope, slot.isStrictMode(), ReadonlyPropertyWriteError);
-    }
     PropertyStatus propertyType = thisObject->reifyLazyPropertyIfNeeded(vm, globalObject, propertyName);
     if (isLazy(propertyType))
         slot.disableCaching();
@@ -598,14 +423,9 @@
         RETURN_IF_EXCEPTION(scope, false);
     } else if (vm.deletePropertyMode() != VM::DeletePropertyMode::IgnoreConfigurable) {
         // For non-host functions, don't let these properties by deleted - except by DefineOwnProperty.
-        FunctionExecutable* executable = thisObject->jsExecutable();
-        
-        if ((propertyName == vm.propertyNames->caller || propertyName == vm.propertyNames->arguments) && executable->hasCallerAndArgumentsProperties())
+        if (propertyName == vm.propertyNames->prototype && thisObject->jsExecutable()->hasPrototypeProperty())
             return false;
 
-        if (propertyName == vm.propertyNames->prototype && executable->hasPrototypeProperty())
-            return false;
-
         thisObject->reifyLazyPropertyIfNeeded(vm, globalObject, propertyName);
         RETURN_IF_EXCEPTION(scope, false);
     }
@@ -643,45 +463,12 @@
         if (FunctionRareData* rareData = thisObject->rareData())
             rareData->clear("Store to prototype property of a function");
         slot.disallowVMEntry.reset();
-        RELEASE_AND_RETURN(scope, Base::defineOwnProperty(object, globalObject, propertyName, descriptor, throwException));
-    }
-
-    bool valueCheck;
-    if (propertyName == vm.propertyNames->arguments) {
-        if (!thisObject->jsExecutable()->hasCallerAndArgumentsProperties())
-            RELEASE_AND_RETURN(scope, Base::defineOwnProperty(object, globalObject, propertyName, descriptor, throwException));
-
-        valueCheck = !descriptor.value();
-        if (!valueCheck) {
-            valueCheck = sameValue(globalObject, descriptor.value(), retrieveArguments(vm, vm.topCallFrame, thisObject));
-            RETURN_IF_EXCEPTION(scope, false);
-        }
-    } else if (propertyName == vm.propertyNames->caller) {
-        if (!thisObject->jsExecutable()->hasCallerAndArgumentsProperties())
-            RELEASE_AND_RETURN(scope, Base::defineOwnProperty(object, globalObject, propertyName, descriptor, throwException));
-
-        valueCheck = !descriptor.value();
-        if (!valueCheck) {
-            valueCheck = sameValue(globalObject, descriptor.value(), retrieveCallerFunction(vm, vm.topCallFrame, thisObject));
-            RETURN_IF_EXCEPTION(scope, false);
-        }
     } else {
         thisObject->reifyLazyPropertyIfNeeded(vm, globalObject, propertyName);
         RETURN_IF_EXCEPTION(scope, false);
-        RELEASE_AND_RETURN(scope, Base::defineOwnProperty(object, globalObject, propertyName, descriptor, throwException));
     }
-     
-    if (descriptor.configurablePresent() && descriptor.configurable())
-        return typeError(globalObject, scope, throwException, UnconfigurablePropertyChangeConfigurabilityError);
-    if (descriptor.enumerablePresent() && descriptor.enumerable())
-        return typeError(globalObject, scope, throwException, UnconfigurablePropertyChangeEnumerabilityError);
-    if (descriptor.isAccessorDescriptor())
-        return typeError(globalObject, scope, throwException, UnconfigurablePropertyChangeAccessMechanismError);
-    if (descriptor.writablePresent() && descriptor.writable())
-        return typeError(globalObject, scope, throwException, UnconfigurablePropertyChangeWritabilityError);
-    if (!valueCheck)
-        return typeError(globalObject, scope, throwException, ReadonlyPropertyChangeError);
-    return true;
+
+    RELEASE_AND_RETURN(scope, Base::defineOwnProperty(object, globalObject, propertyName, descriptor, throwException));
 }
 
 // ECMA 13.2.2 [[Construct]]

Modified: trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp (280288 => 280289)


--- trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp	2021-07-25 19:40:36 UTC (rev 280288)
+++ trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp	2021-07-25 22:32:20 UTC (rev 280289)
@@ -781,12 +781,6 @@
         });
 
     m_functionProtoHasInstanceSymbolFunction.set(vm, this, hasInstanceSymbolFunction);
-    m_throwTypeErrorGetterSetter.initLater(
-        [] (const Initializer<GetterSetter>& init) {
-            JSFunction* thrower = init.owner->throwTypeErrorFunction();
-            GetterSetter* getterSetter = GetterSetter::create(init.vm, init.owner, thrower, thrower);
-            init.set(getterSetter);
-        });
 
     m_nullGetterFunction.set(vm, this, NullGetterFunction::create(vm, NullGetterFunction::createStructure(vm, this, m_functionPrototype.get())));
     Structure* nullSetterFunctionStructure = NullSetterFunction::createStructure(vm, this, m_functionPrototype.get());
@@ -802,16 +796,15 @@
     m_functionPrototype->structure(vm)->setPrototypeWithoutTransition(vm, m_objectPrototype.get());
     m_objectStructureForObjectConstructor.set(vm, this, vm.structureCache.emptyObjectStructureForPrototype(this, m_objectPrototype.get(), JSFinalObject::defaultInlineCapacity()));
     m_objectProtoValueOfFunction.set(vm, this, jsCast<JSFunction*>(objectPrototype()->getDirect(vm, vm.propertyNames->valueOf)));
-    
-    JSFunction* thrower = JSFunction::create(vm, this, 0, emptyString(), globalFuncThrowTypeErrorArgumentsCalleeAndCaller);
-    thrower->freeze(vm);
-    GetterSetter* getterSetter = GetterSetter::create(vm, this, thrower, thrower);
-    m_throwTypeErrorArgumentsCalleeAndCallerGetterSetter.set(vm, this, getterSetter);
-    
-    m_functionPrototype->initRestrictedProperties(vm, this);
 
     m_speciesGetterSetter.set(vm, this, GetterSetter::create(vm, this, JSFunction::create(vm, globalOperationsSpeciesGetterCodeGenerator(vm), this), nullptr));
 
+    m_throwTypeErrorArgumentsCalleeGetterSetter.initLater(
+        [] (const Initializer<GetterSetter>& init) {
+            JSFunction* thrower = JSFunction::create(init.vm, init.owner, 0, emptyString(), globalFuncThrowTypeErrorArgumentsCalleeAndCaller);
+            thrower->freeze(init.vm);
+            init.set(GetterSetter::create(init.vm, init.owner, thrower, thrower));
+        });
     m_typedArrayProto.initLater(
         [] (const Initializer<JSTypedArrayViewPrototype>& init) {
             init.set(JSTypedArrayViewPrototype::create(init.vm, init.owner, JSTypedArrayViewPrototype::createStructure(init.vm, init.owner, init.owner->m_objectPrototype.get())));
@@ -2108,9 +2101,8 @@
     visitor.append(thisObject->m_objectProtoValueOfFunction);
     thisObject->m_numberProtoToStringFunction.visit(visitor);
     visitor.append(thisObject->m_functionProtoHasInstanceSymbolFunction);
-    thisObject->m_throwTypeErrorGetterSetter.visit(visitor);
     visitor.append(thisObject->m_regExpProtoSymbolReplace);
-    visitor.append(thisObject->m_throwTypeErrorArgumentsCalleeAndCallerGetterSetter);
+    thisObject->m_throwTypeErrorArgumentsCalleeGetterSetter.visit(visitor);
     thisObject->m_moduleLoader.visit(visitor);
 
     visitor.append(thisObject->m_objectPrototype);

Modified: trunk/Source/_javascript_Core/runtime/JSGlobalObject.h (280288 => 280289)


--- trunk/Source/_javascript_Core/runtime/JSGlobalObject.h	2021-07-25 19:40:36 UTC (rev 280288)
+++ trunk/Source/_javascript_Core/runtime/JSGlobalObject.h	2021-07-25 22:32:20 UTC (rev 280289)
@@ -340,9 +340,8 @@
     LazyProperty<JSGlobalObject, JSFunction> m_numberProtoToStringFunction;
     WriteBarrier<JSFunction> m_objectProtoValueOfFunction;
     WriteBarrier<JSFunction> m_functionProtoHasInstanceSymbolFunction;
-    LazyProperty<JSGlobalObject, GetterSetter> m_throwTypeErrorGetterSetter;
     WriteBarrier<JSObject> m_regExpProtoSymbolReplace;
-    WriteBarrier<GetterSetter> m_throwTypeErrorArgumentsCalleeAndCallerGetterSetter;
+    LazyProperty<JSGlobalObject, GetterSetter> m_throwTypeErrorArgumentsCalleeGetterSetter;
 
     LazyProperty<JSGlobalObject, JSModuleLoader> m_moduleLoader;
 
@@ -696,10 +695,7 @@
     JSObject* regExpProtoSymbolReplaceFunction() const { return m_regExpProtoSymbolReplace.get(); }
     GetterSetter* regExpProtoGlobalGetter() const;
     GetterSetter* regExpProtoUnicodeGetter() const;
-    GetterSetter* throwTypeErrorArgumentsCalleeAndCallerGetterSetter()
-    {
-        return m_throwTypeErrorArgumentsCalleeAndCallerGetterSetter.get();
-    }
+    GetterSetter* throwTypeErrorArgumentsCalleeGetterSetter() const { return m_throwTypeErrorArgumentsCalleeGetterSetter.get(this); }
     
     JSModuleLoader* moduleLoader() const { return m_moduleLoader.get(this); }
 

Modified: trunk/Source/_javascript_Core/runtime/JSGlobalObjectFunctions.cpp (280288 => 280289)


--- trunk/Source/_javascript_Core/runtime/JSGlobalObjectFunctions.cpp	2021-07-25 19:40:36 UTC (rev 280288)
+++ trunk/Source/_javascript_Core/runtime/JSGlobalObjectFunctions.cpp	2021-07-25 22:32:20 UTC (rev 280289)
@@ -49,6 +49,7 @@
 namespace JSC {
 
 const ASCIILiteral ObjectProtoCalledOnNullOrUndefinedError { "Object.prototype.__proto__ called on null or undefined"_s };
+const ASCIILiteral RestrictedPropertyAccessError { "'arguments', 'callee', and 'caller' cannot be accessed in this context."_s };
 
 template<unsigned charactersCount>
 static Bitmap<256> makeCharacterBitmap(const char (&characters)[charactersCount])
@@ -693,7 +694,7 @@
 {
     VM& vm = globalObject->vm();
     auto scope = DECLARE_THROW_SCOPE(vm);
-    return throwVMTypeError(globalObject, scope, "'arguments', 'callee', and 'caller' cannot be accessed in this context.");
+    return throwVMTypeError(globalObject, scope, RestrictedPropertyAccessError);
 }
 
 JSC_DEFINE_HOST_FUNCTION(globalFuncMakeTypeError, (JSGlobalObject* globalObject, CallFrame* callFrame))

Modified: trunk/Source/_javascript_Core/runtime/JSGlobalObjectFunctions.h (280288 => 280289)


--- trunk/Source/_javascript_Core/runtime/JSGlobalObjectFunctions.h	2021-07-25 19:40:36 UTC (rev 280288)
+++ trunk/Source/_javascript_Core/runtime/JSGlobalObjectFunctions.h	2021-07-25 22:32:20 UTC (rev 280289)
@@ -36,6 +36,7 @@
 // is a 0.5% reduction.
 
 extern const ASCIILiteral ObjectProtoCalledOnNullOrUndefinedError;
+extern const ASCIILiteral RestrictedPropertyAccessError;
 
 JSC_DECLARE_HOST_FUNCTION(globalFuncEval);
 JSC_DECLARE_HOST_FUNCTION(globalFuncParseInt);

Modified: trunk/Source/_javascript_Core/runtime/JSObject.cpp (280288 => 280289)


--- trunk/Source/_javascript_Core/runtime/JSObject.cpp	2021-07-25 19:40:36 UTC (rev 280288)
+++ trunk/Source/_javascript_Core/runtime/JSObject.cpp	2021-07-25 22:32:20 UTC (rev 280289)
@@ -2000,6 +2000,22 @@
     return result;
 }
 
+void JSObject::putDirectCustomGetterSetterWithoutTransition(VM& vm, PropertyName propertyName, JSValue value, unsigned attributes)
+{
+    ASSERT(!parseIndex(propertyName));
+    ASSERT(value.isCustomGetterSetter());
+    ASSERT(attributes & PropertyAttribute::CustomAccessorOrValue);
+
+    StructureID structureID = this->structureID();
+    Structure* structure = vm.heap.structureIDTable().get(structureID);
+    PropertyOffset offset = prepareToPutDirectWithoutTransition(vm, propertyName, attributes, structureID, structure);
+    putDirect(vm, offset, value);
+
+    if (attributes & PropertyAttribute::ReadOnly)
+        structure->setContainsReadOnlyProperties();
+    structure->setHasCustomGetterSetterPropertiesWithProtoCheck(propertyName == vm.propertyNames->underscoreProto);
+}
+
 bool JSObject::putDirectNonIndexAccessor(VM& vm, PropertyName propertyName, GetterSetter* accessor, unsigned attributes)
 {
     ASSERT(attributes & PropertyAttribute::Accessor);

Modified: trunk/Source/_javascript_Core/runtime/JSObject.h (280288 => 280289)


--- trunk/Source/_javascript_Core/runtime/JSObject.h	2021-07-25 19:40:36 UTC (rev 280288)
+++ trunk/Source/_javascript_Core/runtime/JSObject.h	2021-07-25 22:32:20 UTC (rev 280289)
@@ -652,6 +652,7 @@
     void putDirectNonIndexAccessorWithoutTransition(VM&, PropertyName, GetterSetter*, unsigned attributes);
     bool putDirectAccessor(JSGlobalObject*, PropertyName, GetterSetter*, unsigned attributes);
     JS_EXPORT_PRIVATE bool putDirectCustomAccessor(VM&, PropertyName, JSValue, unsigned attributes);
+    void putDirectCustomGetterSetterWithoutTransition(VM&, PropertyName, JSValue, unsigned attributes);
 
     bool putGetter(JSGlobalObject*, PropertyName, JSValue, unsigned attributes);
     bool putSetter(JSGlobalObject*, PropertyName, JSValue, unsigned attributes);
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to