Ignore:
Timestamp:
Jul 25, 2021, 3:32:20 PM (4 years ago)
Author:
Alexey Shvayka
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/JavaScriptCore:

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.

  1. 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.

  1. 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:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp

    r279915 r280289  
    5050
    5151const ASCIILiteral ObjectProtoCalledOnNullOrUndefinedError { "Object.prototype.__proto__ called on null or undefined"_s };
     52const ASCIILiteral RestrictedPropertyAccessError { "'arguments', 'callee', and 'caller' cannot be accessed in this context."_s };
    5253
    5354template<unsigned charactersCount>
     
    694695    VM& vm = globalObject->vm();
    695696    auto scope = DECLARE_THROW_SCOPE(vm);
    696     return throwVMTypeError(globalObject, scope, "'arguments', 'callee', and 'caller' cannot be accessed in this context.");
     697    return throwVMTypeError(globalObject, scope, RestrictedPropertyAccessError);
    697698}
    698699
Note: See TracChangeset for help on using the changeset viewer.