Changeset 278589 in webkit


Ignore:
Timestamp:
Jun 7, 2021, 6:53:46 PM (4 years ago)
Author:
Alexey Shvayka
Message:

Unreviewed, reland r276592 with a fix for put() override in prototype chain of a JSProxy
https://bugs.webkit.org/show_bug.cgi?id=226185

JSTests:

  • microbenchmarks/put-slow-no-cache-array.js: Added.
  • microbenchmarks/put-slow-no-cache-function.js: Added.
  • microbenchmarks/put-slow-no-cache-js-proxy.js: Added.
  • microbenchmarks/put-slow-no-cache-long-prototype-chain.js: Added.
  • microbenchmarks/put-slow-no-cache.js: Added.
  • microbenchmarks/reflect-set-with-receiver.js: Added.
  • stress/custom-get-set-proto-chain-put.js:
  • stress/module-namespace-access-set-fails.js: Added.
  • stress/put-non-reified-static-accessor-or-custom.js: Added.
  • stress/put-non-reified-static-function-or-custom.js: Added.
  • stress/put-to-primitive-non-reified-static-custom.js: Added.
  • stress/put-to-primitive.js: Added.
  • stress/put-to-proto-chain-overrides-put.js:

Rework to always test new objects, add JSProxy coverage, and assert that receiver has own property.

  • stress/typed-array-canonical-numeric-index-string-set.js: Added.

LayoutTests/imported/w3c:

  • web-platform-tests/WebIDL/ecmascript-binding/global-object-implicit-this-value.any-expected.txt:
  • web-platform-tests/WebIDL/ecmascript-binding/interface-object-set-receiver-expected.txt: Added.
  • web-platform-tests/WebIDL/ecmascript-binding/interface-object-set-receiver.html: Added.
  • web-platform-tests/WebIDL/ecmascript-binding/interface-prototype-constructor-set-receiver-expected.txt:
  • web-platform-tests/WebIDL/ecmascript-binding/interface-prototype-constructor-set-receiver.html:

Source/JavaScriptCore:

The API test added in r278366 revealed a flaw in JSObject::definePropertyOnReceiver()
that caused putDirectInternal() to be performed on a JSProxy instead of it's target.
Remedies that via a type check, ensuring the test and iOS apps are functional.

The issue was originally missed because the prototype chain of a global object is immutable
and none of the global object's prototypes override put(). OpaqueJSClass::prototype() sets
the Prototype directly, ignoring the IsImmutablePrototypeExoticObject type info flag.

Also, excludes an invariant from the original patch that required put() to be overriden
when implementing custom DefineOwnProperty. It is now broken by WindowProperties object.

  • API/JSCallbackObject.h:
  • API/JSCallbackObjectFunctions.h:

(JSC::JSCallbackObject<Parent>::put):

  • API/tests/testapiScripts/testapi.js:
  • debugger/DebuggerScope.h:
  • runtime/ClassInfo.h:
  • runtime/ClonedArguments.h:
  • runtime/CustomGetterSetter.cpp:

(JSC::callCustomSetter): Deleted.

  • runtime/CustomGetterSetter.h:
  • runtime/ErrorConstructor.h:
  • runtime/ErrorInstance.h:
  • runtime/GenericArguments.h:
  • runtime/GenericArgumentsInlines.h:

(JSC::GenericArguments<Type>::put):

  • runtime/GetterSetter.h:
  • runtime/JSArray.cpp:

(JSC::JSArray::put):

  • runtime/JSArray.h:
  • runtime/JSArrayBufferView.cpp:

(JSC::JSArrayBufferView::put): Deleted.

  • runtime/JSArrayBufferView.h:
  • runtime/JSCJSValue.cpp:

(JSC::JSValue::putToPrimitive):

  • runtime/JSCell.cpp:

(JSC::JSCell::doPutPropertySecurityCheck): Deleted.

  • runtime/JSCell.h:
  • runtime/JSFunction.cpp:

(JSC::JSFunction::put):

  • runtime/JSFunction.h:
  • runtime/JSGenericTypedArrayView.h:
  • runtime/JSGlobalLexicalEnvironment.h:
  • runtime/JSGlobalObject.cpp:

(JSC::JSGlobalObject::put):

  • runtime/JSGlobalObject.h:
  • runtime/JSLexicalEnvironment.h:
  • runtime/JSModuleEnvironment.h:
  • runtime/JSModuleNamespaceObject.h:
  • runtime/JSObject.cpp:

(JSC::JSObject::getOwnPropertySlot):
(JSC::JSObject::putInlineSlow):
(JSC::definePropertyOnReceiverSlow):
(JSC::JSObject::definePropertyOnReceiver):
(JSC::JSObject::putInlineFastReplacingStaticPropertyIfNeeded):
(JSC::JSObject::doPutPropertySecurityCheck): Deleted.
(JSC::JSObject::prototypeChainMayInterceptStoreTo): Deleted.

  • runtime/JSObject.h:

(JSC::JSObject::putByIndexInline):
(JSC::JSObject::hasNonReifiedStaticProperties):
(JSC::JSObject::getOwnPropertySlot):
(JSC::JSObject::putDirect):
(JSC::JSObject::doPutPropertySecurityCheck): Deleted.

  • runtime/JSObjectInlines.h:

(JSC::JSObject::canPerformFastPutInlineExcludingProto):
(JSC::JSObject::putInlineForJSObject):
(JSC::JSObject::putInlineFast):
(JSC::JSObject::putDirectInternal):

  • runtime/JSProxy.h:
  • runtime/JSTypeInfo.h:

(JSC::TypeInfo::hasStaticPropertyTable const):
(JSC::TypeInfo::overridesPut const):
(JSC::TypeInfo::getOwnPropertySlotMayBeWrongAboutDontEnum const):
(JSC::TypeInfo::hasPutPropertySecurityCheck const): Deleted.

  • runtime/Lookup.h:

(JSC::putEntry): Deleted.
(JSC::lookupPut): Deleted.

  • runtime/PropertySlot.h:
  • runtime/ProxyObject.cpp:

(JSC::ProxyObject::put):

  • runtime/ProxyObject.h:
  • runtime/PutPropertySlot.h:

(JSC::PutPropertySlot::PutPropertySlot):
(JSC::PutPropertySlot::context const):
(JSC::PutPropertySlot::isTaintedByOpaqueObject const):
(JSC::PutPropertySlot::setIsTaintedByOpaqueObject):

  • runtime/ReflectObject.cpp:

(JSC::JSC_DEFINE_HOST_FUNCTION):

  • runtime/RegExpObject.cpp:

(JSC::RegExpObject::put):

  • runtime/RegExpObject.h:
  • runtime/StringObject.cpp:

(JSC::StringObject::put):

  • runtime/StringObject.h:
  • runtime/StringPrototype.cpp:

(JSC::StringPrototype::finishCreation):
(JSC::StringPrototype::create):

  • runtime/StringPrototype.h:
  • runtime/Structure.cpp:

(JSC::Structure::validateFlags):

  • runtime/Structure.h:

(JSC::Structure::hasNonReifiedStaticProperties const):

  • tools/JSDollarVM.cpp:

Source/WebCore:

Tests: js/dom/script-tests/reflect-set-onto-dom.js

imported/w3c/web-platform-tests/WebIDL/ecmascript-binding/interface-object-set-receiver.html
http/tests/security/cross-frame-access-object-getPrototypeOf-in-put.html

  • bindings/js/JSDOMWindowCustom.cpp:

(WebCore::JSDOMWindow::put):
(WebCore::JSDOMWindow::doPutPropertySecurityCheck): Deleted.

  • bindings/js/JSLocationCustom.cpp:

(WebCore::JSLocation::doPutPropertySecurityCheck): Deleted.

  • bindings/js/JSRemoteDOMWindowCustom.cpp:

(WebCore::JSRemoteDOMWindow::put):

  • bindings/scripts/CodeGeneratorJS.pm:

(GeneratePut):
(GenerateHeader):

  • bindings/scripts/test/JS/*: Updated.
  • bridge/objc/objc_runtime.h:
  • bridge/runtime_array.h:
  • bridge/runtime_object.h:

Source/WebKit:

  • WebProcess/Plugins/Netscape/JSNPObject.h:

LayoutTests:

  • http/tests/security/cross-frame-access-object-getPrototypeOf-in-put-expected.txt:
  • http/tests/security/cross-frame-access-object-getPrototypeOf-in-put.html:
  • js/dom/reflect-set-onto-dom-expected.txt:
  • js/dom/script-tests/reflect-set-onto-dom.js:
Location:
trunk
Files:
15 added
103 edited

Legend:

Unmodified
Added
Removed
  • trunk/JSTests/ChangeLog

    r278578 r278589  
     12021-06-07  Alexey Shvayka  <shvaikalesh@gmail.com>
     2
     3        Unreviewed, reland r276592 with a fix for put() override in prototype chain of a JSProxy
     4        https://bugs.webkit.org/show_bug.cgi?id=226185
     5
     6        * microbenchmarks/put-slow-no-cache-array.js: Added.
     7        * microbenchmarks/put-slow-no-cache-function.js: Added.
     8        * microbenchmarks/put-slow-no-cache-js-proxy.js: Added.
     9        * microbenchmarks/put-slow-no-cache-long-prototype-chain.js: Added.
     10        * microbenchmarks/put-slow-no-cache.js: Added.
     11        * microbenchmarks/reflect-set-with-receiver.js: Added.
     12        * stress/custom-get-set-proto-chain-put.js:
     13        * stress/module-namespace-access-set-fails.js: Added.
     14        * stress/put-non-reified-static-accessor-or-custom.js: Added.
     15        * stress/put-non-reified-static-function-or-custom.js: Added.
     16        * stress/put-to-primitive-non-reified-static-custom.js: Added.
     17        * stress/put-to-primitive.js: Added.
     18        * stress/put-to-proto-chain-overrides-put.js:
     19        Rework to always test new objects, add JSProxy coverage, and assert that receiver has own property.
     20
     21        * stress/typed-array-canonical-numeric-index-string-set.js: Added.
     22
    1232021-06-07  Saam Barati  <sbarati@apple.com>
    224
  • trunk/JSTests/stress/custom-get-set-proto-chain-put.js

    r277665 r278589  
    3838        Object.create(customTestGetterSetter),
    3939        Object.create(Object.create(customTestGetterSetter)),
    40         // FIXME: ordinarySetSlow() should handle Custom{Accessor,Value} descriptors.
    41         // new Proxy(customTestGetterSetter, {}),
     40        Object.create(new Proxy(customTestGetterSetter, {})),
     41        Object.create($vm.createProxy(customTestGetterSetter)),
    4242    ];
    4343}
     
    8686
    8787// CustomValue: setter returns |false|
     88// FIXME: Once legacy RegExp features are implemented, there would be no use case for calling CustomValue setter if receiver is altered.
    8889(() => {
    8990    for (let base of getBases()) {
    9091        for (let i = 0; i < 100; ++i)
    9192            base.customValue = 1;
    92         // This is weird, but it isn't exposed to userland code:
    9393        assert(!base.hasOwnProperty("customValue"));
    94         assert(!Reflect.set(Object(base), "customValue", 1));
     94        assert(Reflect.set(Object(base), "customValue", 1));
    9595    }
    9696})();
  • trunk/LayoutTests/ChangeLog

    r278585 r278589  
     12021-06-07  Alexey Shvayka  <shvaikalesh@gmail.com>
     2
     3        Unreviewed, reland r276592 with a fix for put() override in prototype chain of a JSProxy
     4        https://bugs.webkit.org/show_bug.cgi?id=226185
     5
     6        * http/tests/security/cross-frame-access-object-getPrototypeOf-in-put-expected.txt:
     7        * http/tests/security/cross-frame-access-object-getPrototypeOf-in-put.html:
     8        * js/dom/reflect-set-onto-dom-expected.txt:
     9        * js/dom/script-tests/reflect-set-onto-dom.js:
     10
    1112021-06-07  Alexey Shvayka  <shvaikalesh@gmail.com>
    212
  • trunk/LayoutTests/http/tests/security/cross-frame-access-object-getPrototypeOf-in-put-expected.txt

    r277665 r278589  
    11This tests that you can't get the prototype of the window during [[Put]] operation.
    22
     3PASS array.cocoa = cocoaValue threw exception SecurityError: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a cross-origin frame. Protocols, domains, and ports must match..
     4PASS 'str'.cocoa = cocoaValue threw exception SecurityError: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a cross-origin frame. Protocols, domains, and ports must match..
    35PASS: successfullyParsed should be 'true' and is.
    46
  • trunk/LayoutTests/http/tests/security/cross-frame-access-object-getPrototypeOf-in-put.html

    r277665 r278589  
    1616        {
    1717            targetWindow = document.getElementById("target").contentWindow;
    18             var array = [];
     18            array = [];
    1919            array.__proto__.__proto__ = targetWindow;
    2020            array[0] = 11.11;
     
    2525                }
    2626            };
    27             array["cocoa"] = {
     27            cocoaValue = {
    2828                toString() {
    2929                    testFailed("toString is called by cocoa setter");
    3030                }
    3131            };
     32            shouldThrowErrorName("array.cocoa = cocoaValue", "SecurityError");
     33
     34            Object.setPrototypeOf(String.prototype, targetWindow);
     35            shouldThrowErrorName("'str'.cocoa = cocoaValue", "SecurityError");
    3236            finishJSTest();
    3337        }
  • trunk/LayoutTests/imported/w3c/ChangeLog

    r278585 r278589  
     12021-06-07  Alexey Shvayka  <shvaikalesh@gmail.com>
     2
     3        Unreviewed, reland r276592 with a fix for put() override in prototype chain of a JSProxy
     4        https://bugs.webkit.org/show_bug.cgi?id=226185
     5
     6        * web-platform-tests/WebIDL/ecmascript-binding/global-object-implicit-this-value.any-expected.txt:
     7        * web-platform-tests/WebIDL/ecmascript-binding/interface-object-set-receiver-expected.txt: Added.
     8        * web-platform-tests/WebIDL/ecmascript-binding/interface-object-set-receiver.html: Added.
     9        * web-platform-tests/WebIDL/ecmascript-binding/interface-prototype-constructor-set-receiver-expected.txt:
     10        * web-platform-tests/WebIDL/ecmascript-binding/interface-prototype-constructor-set-receiver.html:
     11
    1122021-06-07  Alexey Shvayka  <shvaikalesh@gmail.com>
    213
  • trunk/LayoutTests/imported/w3c/web-platform-tests/WebIDL/ecmascript-binding/global-object-implicit-this-value.any-expected.txt

    r277830 r278589  
    11
    22PASS Global object's getter throws when called on incompatible object
    3 FAIL Global object's setter throws when called on incompatible object assert_throws_js: function "() => { Object.create(globalThis).origin = origin; }" did not throw
     3PASS Global object's setter throws when called on incompatible object
    44PASS Global object's operation throws when called on incompatible object
    55PASS Global object's getter throws when called on incompatible object (document.all)
  • trunk/LayoutTests/imported/w3c/web-platform-tests/WebIDL/ecmascript-binding/interface-prototype-constructor-set-receiver-expected.txt

    r277665 r278589  
    11
    2 PASS Window, Location, Navigator, HTMLDocument, and HTMLHeadElement
    3 PASS All window.* constructors
     2PASS Direct [[Set]] preserves [[Enumerable]]: false property attribute
     3PASS Prototype chain [[Set]] creates property on receiver
    44
  • trunk/LayoutTests/imported/w3c/web-platform-tests/WebIDL/ecmascript-binding/interface-prototype-constructor-set-receiver.html

    r277665 r278589  
    77<script>
    88"use strict";
     9const testValue = Object.freeze(function() {});
    910
    1011test(() => {
    11   window.constructor = null;
     12  Location.prototype.constructor = testValue;
     13  assert_false(Location.prototype.propertyIsEnumerable("constructor"));
     14
     15  HTMLDocument.prototype.constructor = testValue;
     16  assert_false(HTMLDocument.prototype.propertyIsEnumerable("constructor"));
     17
     18  HTMLDivElement.prototype.constructor = testValue;
     19  assert_false(HTMLDivElement.prototype.propertyIsEnumerable("constructor"));
     20}, "Direct [[Set]] preserves [[Enumerable]]: false property attribute");
     21
     22test(() => {
     23  window.constructor = testValue;
     24  assert_equals(window.constructor, testValue);
    1225  assert_equals(Window.prototype.constructor, Window);
    1326
    14   location.constructor = false;
    15   assert_equals(Location.prototype.constructor, Location);
    16 
    17   navigator.constructor = 1;
     27  navigator.constructor = testValue;
     28  assert_equals(navigator.constructor, testValue);
    1829  assert_equals(Navigator.prototype.constructor, Navigator);
    1930
    20   document.constructor = {};
    21   assert_equals(HTMLDocument.prototype.constructor, HTMLDocument);
    22 
    23   document.head.constructor = [];
    24   assert_equals(HTMLHeadElement.prototype.constructor, HTMLHeadElement);
    25 }, "Window, Location, Navigator, HTMLDocument, and HTMLHeadElement");
    26 
    27 test(() => {
    28   for (let key of Object.getOwnPropertyNames(window)) {
    29     if (!/^[A-Z]/.test(key)) continue;
    30 
    31     let desc = Object.getOwnPropertyDescriptor(window, key);
    32     if (!desc || desc.enumerable) continue;
    33     let {value} = desc;
    34     if (typeof value !== "function") continue;
    35     let {prototype} = value;
    36     if (!prototype) continue;
    37 
    38     let heir = Object.create(prototype);
    39     let newConstructor = function() {};
    40     heir.constructor = newConstructor;
    41 
    42     assert_not_equals(prototype.constructor, newConstructor, key);
    43     assert_own_property(heir, "constructor", key);
    44     assert_equals(heir.constructor, newConstructor, key);
    45   }
    46 }, "All window.* constructors");
     31  const span = document.createElement("span");
     32  span.constructor = testValue;
     33  assert_equals(span.constructor, testValue);
     34  assert_equals(HTMLSpanElement.prototype.constructor, HTMLSpanElement);
     35}, "Prototype chain [[Set]] creates property on receiver");
    4736</script>
  • trunk/LayoutTests/js/dom/reflect-set-onto-dom-expected.txt

    r277665 r278589  
    9494PASS Reflect.set(document.body.dataset, 0, "sweet") is true
    9595PASS Reflect.get(document.body.dataset, 0) is "sweet"
    96 DOMStringMap ignores the receiver. These putDelegate only work with ::put (not ::defineOwnProperty). So they behave as the special setter, we should not fallback to the OrdinarySet.
     96DOMStringMap falls back to OrdinarySet if receiver is altered.
    9797PASS Reflect.set(document.body.dataset, "cocoa", "ok", receiver) is true
    98 PASS Reflect.get(document.body.dataset, "cocoa") is "ok"
    99 PASS Reflect.get(receiver, "cocoa") is undefined
     98PASS Reflect.get(document.body.dataset, "cocoa") is "sweet"
     99PASS Reflect.get(receiver, "cocoa") is "ok"
    100100PASS Reflect.set(document.body.dataset, 0, "ok", receiver) is true
    101 PASS Reflect.get(document.body.dataset, 0) is "ok"
    102 PASS Reflect.get(receiver, 0) is undefined
     101PASS Reflect.get(document.body.dataset, 0) is "sweet"
     102PASS Reflect.get(receiver, 0) is "ok"
    103103CustomIndexedSetter
    104104PASS Reflect.get(select, 0).value is "cocoa"
     
    112112PASS Reflect.get(select, 44).value is "kilimanjaro"
    113113PASS Reflect.set(select, 20, "Kilimanjaro") threw exception TypeError: Type error.
    114 CustomIndexedSetter ignores the receiver. These methods only work with ::put (not ::defineOwnProperty). So they behave as the special setter, we should not fallback to the OrdinarySet.
     114CustomIndexedSetter falls back to OrdinarySet if receiver is altered.
    115115PASS Reflect.set(select, 0, option3, receiver) is true
    116 PASS Reflect.get(receiver, 0) is undefined
    117 PASS Reflect.get(select, 0) is option3
     116PASS Reflect.get(receiver, 0) is option3
     117PASS Reflect.get(select, 0) is select.children[0]
    118118PASS successfullyParsed is true
    119119
  • trunk/LayoutTests/js/dom/script-tests/reflect-set-onto-dom.js

    r277665 r278589  
    117117shouldBe(`Reflect.get(document.body.dataset, 0)`, `"sweet"`);
    118118
    119 debug("DOMStringMap ignores the receiver. These putDelegate only work with ::put (not ::defineOwnProperty). So they behave as the special setter, we should not fallback to the OrdinarySet.");
     119debug("DOMStringMap falls back to OrdinarySet if receiver is altered.");
    120120var receiver = {};
    121121shouldBe(`Reflect.set(document.body.dataset, "cocoa", "ok", receiver)`, `true`);
    122 shouldBe(`Reflect.get(document.body.dataset, "cocoa")`, `"ok"`);
    123 shouldBe(`Reflect.get(receiver, "cocoa")`, `undefined`);
     122shouldBe(`Reflect.get(document.body.dataset, "cocoa")`, `"sweet"`);
     123shouldBe(`Reflect.get(receiver, "cocoa")`, `"ok"`);
    124124var receiver = {};
    125125shouldBe(`Reflect.set(document.body.dataset, 0, "ok", receiver)`, `true`);
    126 shouldBe(`Reflect.get(document.body.dataset, 0)`, `"ok"`);
    127 shouldBe(`Reflect.get(receiver, 0)`, `undefined`);
     126shouldBe(`Reflect.get(document.body.dataset, 0)`, `"sweet"`);
     127shouldBe(`Reflect.get(receiver, 0)`, `"ok"`);
    128128
    129129debug("CustomIndexedSetter");
     
    147147shouldThrow(`Reflect.set(select, 20, "Kilimanjaro")`);
    148148
    149 debug("CustomIndexedSetter ignores the receiver. These methods only work with ::put (not ::defineOwnProperty). So they behave as the special setter, we should not fallback to the OrdinarySet.");
     149debug("CustomIndexedSetter falls back to OrdinarySet if receiver is altered.");
    150150var option3 = document.createElement("option");
    151151option3.value = "rabbit";
     
    153153var receiver = {};
    154154shouldBe(`Reflect.set(select, 0, option3, receiver)`, `true`);
    155 shouldBe(`Reflect.get(receiver, 0)`, `undefined`);
    156 shouldBe(`Reflect.get(select, 0)`, `option3`);
     155shouldBe(`Reflect.get(receiver, 0)`, `option3`);
     156shouldBe(`Reflect.get(select, 0)`, `select.children[0]`);
  • trunk/Source/JavaScriptCore/API/JSCallbackObject.h

    r277920 r278589  
    130130public:
    131131    using Base = Parent;
    132     static constexpr unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | OverridesGetOwnSpecialPropertyNames | OverridesGetCallData | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | ImplementsHasInstance | ProhibitsPropertyCaching | GetOwnPropertySlotMayBeWrongAboutDontEnum;
     132    static constexpr unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | OverridesGetOwnSpecialPropertyNames | OverridesGetCallData | OverridesPut | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | ImplementsHasInstance | ProhibitsPropertyCaching | GetOwnPropertySlotMayBeWrongAboutDontEnum;
    133133    static_assert(!(StructureFlags & ImplementsDefaultHasInstance), "using customHasInstance");
    134134
  • trunk/Source/JavaScriptCore/API/JSCallbackObjectFunctions.h

    r278253 r278589  
    272272    RefPtr<OpaqueJSString> propertyNameRef;
    273273    JSValueRef valueRef = toRef(globalObject, value);
     274
     275    if (UNLIKELY(isThisValueAltered(slot, thisObject)))
     276        RELEASE_AND_RETURN(scope, Parent::put(thisObject, globalObject, propertyName, value, slot));
    274277   
    275278    if (StringImpl* name = propertyName.uid()) {
  • trunk/Source/JavaScriptCore/API/tests/testapiScripts/testapi.js

    r276660 r278589  
    247247shouldBe("MyObject[Symbol.toPrimitive]('bar')", null);
    248248
     249var MyObjectHeir = Object.create(MyObject);
     250MyObjectHeir.throwOnSet = 22;
     251var MyObjectHeirThrowOnSetDescriptor = Object.getOwnPropertyDescriptor(MyObjectHeir, "throwOnSet");
     252shouldBe("typeof MyObjectHeirThrowOnSetDescriptor", "object");
     253shouldBe("MyObjectHeirThrowOnSetDescriptor.value", 22);
     254shouldBe("MyObjectHeirThrowOnSetDescriptor.writable", true);
     255shouldBe("MyObjectHeirThrowOnSetDescriptor.enumerable", true);
     256shouldBe("MyObjectHeirThrowOnSetDescriptor.configurable", true);
     257shouldThrow("MyObject.throwOnSet = 22");
     258
    249259derived = new Derived();
    250260
  • trunk/Source/JavaScriptCore/ChangeLog

    r278588 r278589  
     12021-06-07  Alexey Shvayka  <shvaikalesh@gmail.com>
     2
     3        Unreviewed, reland r276592 with a fix for put() override in prototype chain of a JSProxy
     4        https://bugs.webkit.org/show_bug.cgi?id=226185
     5
     6        The API test added in r278366 revealed a flaw in JSObject::definePropertyOnReceiver()
     7        that caused putDirectInternal() to be performed on a JSProxy instead of it's target.
     8        Remedies that via a type check, ensuring the test and iOS apps are functional.
     9
     10        The issue was originally missed because the prototype chain of a global object is immutable
     11        and none of the global object's prototypes override put(). OpaqueJSClass::prototype() sets
     12        the [[Prototype]] directly, ignoring the IsImmutablePrototypeExoticObject type info flag.
     13
     14        Also, excludes an invariant from the original patch that required put() to be overriden
     15        when implementing custom [[DefineOwnProperty]]. It is now broken by WindowProperties object.
     16
     17        * API/JSCallbackObject.h:
     18        * API/JSCallbackObjectFunctions.h:
     19        (JSC::JSCallbackObject<Parent>::put):
     20        * API/tests/testapiScripts/testapi.js:
     21        * debugger/DebuggerScope.h:
     22        * runtime/ClassInfo.h:
     23        * runtime/ClonedArguments.h:
     24        * runtime/CustomGetterSetter.cpp:
     25        (JSC::callCustomSetter): Deleted.
     26        * runtime/CustomGetterSetter.h:
     27        * runtime/ErrorConstructor.h:
     28        * runtime/ErrorInstance.h:
     29        * runtime/GenericArguments.h:
     30        * runtime/GenericArgumentsInlines.h:
     31        (JSC::GenericArguments<Type>::put):
     32        * runtime/GetterSetter.h:
     33        * runtime/JSArray.cpp:
     34        (JSC::JSArray::put):
     35        * runtime/JSArray.h:
     36        * runtime/JSArrayBufferView.cpp:
     37        (JSC::JSArrayBufferView::put): Deleted.
     38        * runtime/JSArrayBufferView.h:
     39        * runtime/JSCJSValue.cpp:
     40        (JSC::JSValue::putToPrimitive):
     41        * runtime/JSCell.cpp:
     42        (JSC::JSCell::doPutPropertySecurityCheck): Deleted.
     43        * runtime/JSCell.h:
     44        * runtime/JSFunction.cpp:
     45        (JSC::JSFunction::put):
     46        * runtime/JSFunction.h:
     47        * runtime/JSGenericTypedArrayView.h:
     48        * runtime/JSGlobalLexicalEnvironment.h:
     49        * runtime/JSGlobalObject.cpp:
     50        (JSC::JSGlobalObject::put):
     51        * runtime/JSGlobalObject.h:
     52        * runtime/JSLexicalEnvironment.h:
     53        * runtime/JSModuleEnvironment.h:
     54        * runtime/JSModuleNamespaceObject.h:
     55        * runtime/JSObject.cpp:
     56        (JSC::JSObject::getOwnPropertySlot):
     57        (JSC::JSObject::putInlineSlow):
     58        (JSC::definePropertyOnReceiverSlow):
     59        (JSC::JSObject::definePropertyOnReceiver):
     60        (JSC::JSObject::putInlineFastReplacingStaticPropertyIfNeeded):
     61        (JSC::JSObject::doPutPropertySecurityCheck): Deleted.
     62        (JSC::JSObject::prototypeChainMayInterceptStoreTo): Deleted.
     63        * runtime/JSObject.h:
     64        (JSC::JSObject::putByIndexInline):
     65        (JSC::JSObject::hasNonReifiedStaticProperties):
     66        (JSC::JSObject::getOwnPropertySlot):
     67        (JSC::JSObject::putDirect):
     68        (JSC::JSObject::doPutPropertySecurityCheck): Deleted.
     69        * runtime/JSObjectInlines.h:
     70        (JSC::JSObject::canPerformFastPutInlineExcludingProto):
     71        (JSC::JSObject::putInlineForJSObject):
     72        (JSC::JSObject::putInlineFast):
     73        (JSC::JSObject::putDirectInternal):
     74        * runtime/JSProxy.h:
     75        * runtime/JSTypeInfo.h:
     76        (JSC::TypeInfo::hasStaticPropertyTable const):
     77        (JSC::TypeInfo::overridesPut const):
     78        (JSC::TypeInfo::getOwnPropertySlotMayBeWrongAboutDontEnum const):
     79        (JSC::TypeInfo::hasPutPropertySecurityCheck const): Deleted.
     80        * runtime/Lookup.h:
     81        (JSC::putEntry): Deleted.
     82        (JSC::lookupPut): Deleted.
     83        * runtime/PropertySlot.h:
     84        * runtime/ProxyObject.cpp:
     85        (JSC::ProxyObject::put):
     86        * runtime/ProxyObject.h:
     87        * runtime/PutPropertySlot.h:
     88        (JSC::PutPropertySlot::PutPropertySlot):
     89        (JSC::PutPropertySlot::context const):
     90        (JSC::PutPropertySlot::isTaintedByOpaqueObject const):
     91        (JSC::PutPropertySlot::setIsTaintedByOpaqueObject):
     92        * runtime/ReflectObject.cpp:
     93        (JSC::JSC_DEFINE_HOST_FUNCTION):
     94        * runtime/RegExpObject.cpp:
     95        (JSC::RegExpObject::put):
     96        * runtime/RegExpObject.h:
     97        * runtime/StringObject.cpp:
     98        (JSC::StringObject::put):
     99        * runtime/StringObject.h:
     100        * runtime/StringPrototype.cpp:
     101        (JSC::StringPrototype::finishCreation):
     102        (JSC::StringPrototype::create):
     103        * runtime/StringPrototype.h:
     104        * runtime/Structure.cpp:
     105        (JSC::Structure::validateFlags):
     106        * runtime/Structure.h:
     107        (JSC::Structure::hasNonReifiedStaticProperties const):
     108        * tools/JSDollarVM.cpp:
     109
    11102021-06-07  Alexey Shvayka  <shvaikalesh@gmail.com>
    2111
  • trunk/Source/JavaScriptCore/debugger/DebuggerScope.h

    r277665 r278589  
    3737public:
    3838    using Base = JSNonFinalObject;
    39     static constexpr unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | OverridesGetOwnPropertyNames;
     39    static constexpr unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | OverridesGetOwnPropertyNames | OverridesPut;
    4040
    4141    template<typename CellType, SubspaceAccess mode>
  • trunk/Source/JavaScriptCore/runtime/ClassInfo.h

    r278253 r278589  
    6868    using GetOwnPropertySlotByIndexFunctionPtr = bool (*)(JSObject*, JSGlobalObject*, unsigned, PropertySlot&);
    6969    GetOwnPropertySlotByIndexFunctionPtr METHOD_TABLE_ENTRY(getOwnPropertySlotByIndex);
    70 
    71     using DoPutPropertySecurityCheckFunctionPtr = void (*)(JSObject*, JSGlobalObject*, PropertyName, PutPropertySlot&);
    72     DoPutPropertySecurityCheckFunctionPtr METHOD_TABLE_ENTRY(doPutPropertySecurityCheck);
    7370
    7471    using ToThisFunctionPtr = JSValue (*)(JSCell*, JSGlobalObject*, ECMAMode);
     
    156153        &ClassName::getOwnPropertySlot, \
    157154        &ClassName::getOwnPropertySlotByIndex, \
    158         &ClassName::doPutPropertySecurityCheck, \
    159155        &ClassName::toThis, \
    160156        &ClassName::getOwnPropertyNames, \
  • trunk/Source/JavaScriptCore/runtime/ClonedArguments.h

    r277665 r278589  
    4141public:
    4242    using Base = JSNonFinalObject;
    43     static constexpr unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | OverridesGetOwnSpecialPropertyNames;
     43    static constexpr unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | OverridesGetOwnSpecialPropertyNames | OverridesPut;
    4444
    4545    template<typename CellType, SubspaceAccess mode>
  • trunk/Source/JavaScriptCore/runtime/CustomGetterSetter.cpp

    r277665 r278589  
    2727#include "CustomGetterSetter.h"
    2828
    29 #include "JSCJSValueInlines.h"
    30 #include <wtf/Assertions.h>
    31 
    3229namespace JSC {
    3330
     
    3633const ClassInfo CustomGetterSetter::s_info = { "CustomGetterSetter", nullptr, nullptr, nullptr, CREATE_METHOD_TABLE(CustomGetterSetter) };
    3734
    38 TriState callCustomSetter(JSGlobalObject* globalObject, CustomGetterSetter::CustomSetter setter, bool isAccessor, JSObject* slotBase, JSValue thisValue, JSValue value, PropertyName propertyName)
    39 {
    40     if (isAccessor) {
    41         if (!setter)
    42             return TriState::False;
    43         setter(globalObject, JSValue::encode(thisValue), JSValue::encode(value), propertyName);
    44         // Always return true if there is a setter and it is observed as an accessor to users.
    45         return TriState::True;
    46     }
    47 
    48     if (!setter)
    49         return TriState::Indeterminate;
    50     return triState(setter(globalObject, JSValue::encode(slotBase), JSValue::encode(value), propertyName));
    51 }
    52 
    5335} // namespace JSC
  • trunk/Source/JavaScriptCore/runtime/CustomGetterSetter.h

    r277665 r278589  
    7777};
    7878
    79 JS_EXPORT_PRIVATE TriState callCustomSetter(JSGlobalObject*, CustomGetterSetter::CustomSetter, bool isAccessor, JSObject* slotBase, JSValue thisValue, JSValue, PropertyName);
    80 
    8179} // namespace JSC
  • trunk/Source/JavaScriptCore/runtime/ErrorConstructor.h

    r277665 r278589  
    3131public:
    3232    using Base = InternalFunction;
     33    static constexpr unsigned StructureFlags = Base::StructureFlags | OverridesPut;
    3334
    3435    static ErrorConstructor* create(VM& vm, Structure* structure, ErrorPrototype* errorPrototype, GetterSetter*)
  • trunk/Source/JavaScriptCore/runtime/ErrorInstance.h

    r277665 r278589  
    3131public:
    3232    using Base = JSNonFinalObject;
    33     static constexpr unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | OverridesGetOwnSpecialPropertyNames;
     33    static constexpr unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | OverridesGetOwnSpecialPropertyNames | OverridesPut;
    3434    static constexpr bool needsDestruction = true;
    3535
  • trunk/Source/JavaScriptCore/runtime/GenericArguments.h

    r277665 r278589  
    3737public:
    3838    typedef JSNonFinalObject Base;
    39     static constexpr unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | OverridesGetOwnPropertyNames | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero;
     39    static constexpr unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | OverridesGetOwnPropertyNames | OverridesPut | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero;
    4040
    4141protected:
  • trunk/Source/JavaScriptCore/runtime/GenericArgumentsInlines.h

    r278253 r278589  
    135135    // https://tc39.github.io/ecma262/#sec-arguments-exotic-objects-set-p-v-receiver
    136136    // Fall back to the OrdinarySet when the receiver is altered from the thisObject.
    137     if (UNLIKELY(isThisValueAltered(slot, thisObject)))
    138         RELEASE_AND_RETURN(scope, ordinarySetSlow(globalObject, thisObject, ident, value, slot.thisValue(), slot.isStrictMode()));
     137    if (UNLIKELY(slot.thisValue() != thisObject))
     138        RELEASE_AND_RETURN(scope, Base::put(thisObject, globalObject, ident, value, slot));
    139139   
    140140    std::optional<uint32_t> index = parseIndex(ident);
     
    144144    }
    145145
    146     auto result = Base::put(thisObject, globalObject, ident, value, slot);
    147     RETURN_IF_EXCEPTION(scope, false);
    148     RELEASE_AND_RETURN(scope, result);
     146    RELEASE_AND_RETURN(scope, Base::put(thisObject, globalObject, ident, value, slot));
    149147}
    150148
  • trunk/Source/JavaScriptCore/runtime/GetterSetter.h

    r277665 r278589  
    5555public:
    5656
    57     static constexpr unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | StructureIsImmortal;
     57    static constexpr unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | OverridesPut | StructureIsImmortal;
    5858
    5959    template<typename CellType, SubspaceAccess>
  • trunk/Source/JavaScriptCore/runtime/JSArray.cpp

    r278369 r278589  
    239239
    240240    JSArray* thisObject = jsCast<JSArray*>(cell);
    241 
    242     if (UNLIKELY(isThisValueAltered(slot, thisObject)))
    243         RELEASE_AND_RETURN(scope, ordinarySetSlow(globalObject, thisObject, propertyName, value, slot.thisValue(), slot.isStrictMode()));
    244 
    245241    thisObject->ensureWritable(vm);
    246242
     
    251247            return false;
    252248        }
     249
     250        if (UNLIKELY(slot.thisValue() != thisObject))
     251            RELEASE_AND_RETURN(scope, JSObject::definePropertyOnReceiver(globalObject, propertyName, value, slot));
    253252
    254253        unsigned newLength = value.toUInt32(globalObject);
  • trunk/Source/JavaScriptCore/runtime/JSArray.h

    r277665 r278589  
    4141public:
    4242    typedef JSNonFinalObject Base;
    43     static constexpr unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | OverridesGetOwnSpecialPropertyNames;
     43    static constexpr unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | OverridesGetOwnSpecialPropertyNames | OverridesPut;
    4444
    4545    static size_t allocationSize(Checked<size_t> inlineCapacity)
  • trunk/Source/JavaScriptCore/runtime/JSArrayBufferView.cpp

    r277909 r278589  
    173173DEFINE_VISIT_CHILDREN(JSArrayBufferView);
    174174
    175 bool JSArrayBufferView::put(
    176     JSCell* cell, JSGlobalObject* globalObject, PropertyName propertyName, JSValue value,
    177     PutPropertySlot& slot)
    178 {
    179     JSArrayBufferView* thisObject = jsCast<JSArrayBufferView*>(cell);
    180 
    181     if (UNLIKELY(isThisValueAltered(slot, thisObject)))
    182         return ordinarySetSlow(globalObject, thisObject, propertyName, value, slot.thisValue(), slot.isStrictMode());
    183    
    184     return Base::put(thisObject, globalObject, propertyName, value, slot);
    185 }
    186 
    187175ArrayBuffer* JSArrayBufferView::unsharedBuffer()
    188176{
  • trunk/Source/JavaScriptCore/runtime/JSArrayBufferView.h

    r278253 r278589  
    170170    JS_EXPORT_PRIVATE JSArrayBufferView(VM&, ConstructionContext&);
    171171    JS_EXPORT_PRIVATE void finishCreation(VM&);
    172    
    173     static bool put(JSCell*, JSGlobalObject*, PropertyName, JSValue, PutPropertySlot&);
    174172
    175173    DECLARE_VISIT_CHILDREN;
  • trunk/Source/JavaScriptCore/runtime/JSCJSValue.cpp

    r278253 r278589  
    213213}
    214214
    215 // ECMA 8.7.2
     215// https://tc39.es/ecma262/#sec-ordinaryset
    216216bool JSValue::putToPrimitive(JSGlobalObject* globalObject, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
    217217{
     
    222222        RELEASE_AND_RETURN(scope, putToPrimitiveByIndex(globalObject, index.value(), value, slot.isStrictMode()));
    223223
     224    if (isString() && propertyName.uid() == vm.propertyNames->length.impl())
     225        return typeError(globalObject, scope, slot.isStrictMode(), ReadonlyPropertyWriteError);
    224226    // Check if there are any setters or getters in the prototype chain
    225227    JSObject* obj = synthesizePrototype(globalObject);
     
    227229    if (UNLIKELY(!obj))
    228230        return false;
    229     JSValue prototype;
    230     if (propertyName != vm.propertyNames->underscoreProto) {
    231         while (true) {
    232             Structure* structure = obj->structure(vm);
    233             if (structure->hasReadOnlyOrGetterSetterPropertiesExcludingProto() || structure->typeInfo().hasPutPropertySecurityCheck())
    234                 break;
    235             if (obj->type() == ProxyObjectType) {
    236                 auto* proxy = jsCast<ProxyObject*>(obj);
    237                 RELEASE_AND_RETURN(scope, proxy->ProxyObject::put(proxy, globalObject, propertyName, value, slot));
    238             }
    239             prototype = obj->getPrototype(vm, globalObject);
    240             RETURN_IF_EXCEPTION(scope, false);
    241 
    242             if (prototype.isNull())
    243                 return typeError(globalObject, scope, slot.isStrictMode(), ReadonlyPropertyWriteError);
    244             obj = asObject(prototype);
    245         }
    246     }
    247 
    248     for (; ; obj = asObject(prototype)) {
    249         Structure* structure = obj->structure(vm);
    250         if (UNLIKELY(structure->typeInfo().hasPutPropertySecurityCheck())) {
    251             obj->methodTable(vm)->doPutPropertySecurityCheck(obj, globalObject, propertyName, slot);
    252             RETURN_IF_EXCEPTION(scope, false);
    253         }
    254         unsigned attributes;
    255         PropertyOffset offset = structure->get(vm, propertyName, attributes);
    256         if (offset != invalidOffset) {
    257             if (attributes & PropertyAttribute::ReadOnly)
    258                 return typeError(globalObject, scope, slot.isStrictMode(), ReadonlyPropertyWriteError);
    259 
    260             JSValue gs = obj->getDirect(offset);
    261             if (gs.isGetterSetter())
    262                 RELEASE_AND_RETURN(scope, jsCast<GetterSetter*>(gs)->callSetter(globalObject, *this, value, slot.isStrictMode()));
    263 
    264             if (gs.isCustomGetterSetter()) {
    265                 auto setter = jsCast<CustomGetterSetter*>(gs.asCell())->setter();
    266                 bool isAccessor = attributes & PropertyAttribute::CustomAccessor;
    267                 auto result = callCustomSetter(globalObject, setter, isAccessor, obj, slot.thisValue(), value, propertyName);
    268                 if (result != TriState::Indeterminate)
    269                     RELEASE_AND_RETURN(scope, result == TriState::True);
    270             }
    271 
    272             // If there's an existing property on the object or one of its
    273             // prototypes it should be replaced, so break here.
    274             break;
    275         }
    276         if (obj->type() == ProxyObjectType) {
    277             auto* proxy = jsCast<ProxyObject*>(obj);
    278             RELEASE_AND_RETURN(scope, proxy->ProxyObject::put(proxy, globalObject, propertyName, value, slot));
    279         }
    280         prototype = obj->getPrototype(vm, globalObject);
    281         RETURN_IF_EXCEPTION(scope, false);
    282         if (prototype.isNull())
    283             break;
    284     }
    285    
    286     return typeError(globalObject, scope, slot.isStrictMode(), ReadonlyPropertyWriteError);
     231    RELEASE_AND_RETURN(scope, obj->methodTable(vm)->put(obj, globalObject, propertyName, value, slot));
    287232}
    288233
  • trunk/Source/JavaScriptCore/runtime/JSCell.cpp

    r277665 r278589  
    201201}
    202202
    203 void JSCell::doPutPropertySecurityCheck(JSObject*, JSGlobalObject*, PropertyName, PutPropertySlot&)
    204 {
    205     RELEASE_ASSERT_NOT_REACHED();
    206 }
    207 
    208203void JSCell::getOwnPropertyNames(JSObject*, JSGlobalObject*, PropertyNameArray&, DontEnumPropertiesMode)
    209204{
  • trunk/Source/JavaScriptCore/runtime/JSCell.h

    r277909 r278589  
    258258    static bool getOwnPropertySlot(JSObject*, JSGlobalObject*, PropertyName, PropertySlot&);
    259259    static bool getOwnPropertySlotByIndex(JSObject*, JSGlobalObject*, unsigned propertyName, PropertySlot&);
    260     static NO_RETURN_DUE_TO_CRASH void doPutPropertySecurityCheck(JSObject*, JSGlobalObject*, PropertyName, PutPropertySlot&);
    261260
    262261private:
  • trunk/Source/JavaScriptCore/runtime/JSFunction.cpp

    r278462 r278589  
    546546    }
    547547
    548     if (UNLIKELY(isThisValueAltered(slot, thisObject)))
    549         RELEASE_AND_RETURN(scope, ordinarySetSlow(globalObject, thisObject, propertyName, value, slot.thisValue(), slot.isStrictMode()));
    550 
    551 
    552548    if (thisObject->isHostOrBuiltinFunction()) {
    553549        PropertyStatus propertyType = thisObject->reifyLazyPropertyForHostOrBuiltinIfNeeded(vm, globalObject, propertyName);
  • trunk/Source/JavaScriptCore/runtime/JSFunction.h

    r278462 r278589  
    7171   
    7272    typedef JSCallee Base;
    73     static constexpr unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | OverridesGetOwnSpecialPropertyNames | OverridesGetCallData;
     73    static constexpr unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | OverridesGetOwnSpecialPropertyNames | OverridesGetCallData | OverridesPut;
    7474
    7575    static size_t allocationSize(Checked<size_t> inlineCapacity)
  • trunk/Source/JavaScriptCore/runtime/JSGenericTypedArrayView.h

    r278253 r278589  
    100100    static constexpr TypedArrayContentType contentType = Adaptor::contentType;
    101101
    102     static constexpr unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | OverridesGetOwnPropertyNames | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero;
     102    static constexpr unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | OverridesGetOwnPropertyNames | OverridesPut | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero;
    103103
    104104    static constexpr unsigned elementSize = sizeof(typename Adaptor::Type);
  • trunk/Source/JavaScriptCore/runtime/JSGlobalLexicalEnvironment.h

    r277665 r278589  
    3434    using Base = JSSegmentedVariableObject;
    3535
    36     static constexpr unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot;
     36    static constexpr unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | OverridesPut;
    3737
    3838    template<typename CellType, SubspaceAccess mode>
  • trunk/Source/JavaScriptCore/runtime/JSGlobalObject.cpp

    r278243 r278589  
    15771577    ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(thisObject));
    15781578
    1579     if (UNLIKELY(isThisValueAltered(slot, thisObject)))
    1580         RELEASE_AND_RETURN(scope, ordinarySetSlow(globalObject, thisObject, propertyName, value, slot.thisValue(), slot.isStrictMode()));
     1579    if (UNLIKELY(isThisValueAltered(slot, thisObject))) {
     1580        SymbolTableEntry::Fast entry = thisObject->symbolTable()->get(propertyName.uid());
     1581        if (!entry.isNull()) {
     1582            if (entry.isReadOnly())
     1583                return typeError(globalObject, scope, slot.isStrictMode(), ReadonlyPropertyWriteError);
     1584            RELEASE_AND_RETURN(scope, JSObject::definePropertyOnReceiver(globalObject, propertyName, value, slot));
     1585        }
     1586        RELEASE_AND_RETURN(scope, Base::put(thisObject, globalObject, propertyName, value, slot));
     1587    }
    15811588
    15821589    bool shouldThrowReadOnlyError = slot.isStrictMode();
  • trunk/Source/JavaScriptCore/runtime/JSGlobalObject.h

    r278253 r278589  
    597597public:
    598598    using Base = JSSegmentedVariableObject;
    599     static constexpr unsigned StructureFlags = Base::StructureFlags | HasStaticPropertyTable | OverridesGetOwnPropertySlot | IsImmutablePrototypeExoticObject;
     599    static constexpr unsigned StructureFlags = Base::StructureFlags | HasStaticPropertyTable | OverridesGetOwnPropertySlot | OverridesPut | IsImmutablePrototypeExoticObject;
    600600
    601601    static constexpr bool needsDestruction = true;
  • trunk/Source/JavaScriptCore/runtime/JSLexicalEnvironment.h

    r278338 r278589  
    4949
    5050    using Base = JSSymbolTableObject;
    51     static constexpr unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | OverridesGetOwnSpecialPropertyNames;
     51    static constexpr unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | OverridesGetOwnSpecialPropertyNames | OverridesPut;
    5252
    5353    WriteBarrierBase<Unknown>* variables()
  • trunk/Source/JavaScriptCore/runtime/JSModuleEnvironment.h

    r277665 r278589  
    4141public:
    4242    using Base = JSLexicalEnvironment;
    43     static constexpr unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | OverridesGetOwnSpecialPropertyNames;
     43    static constexpr unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | OverridesGetOwnSpecialPropertyNames | OverridesPut;
    4444
    4545    static JSModuleEnvironment* create(VM& vm, JSGlobalObject* globalObject, JSScope* currentScope, SymbolTable* symbolTable, JSValue initialValue, AbstractModuleRecord* moduleRecord)
  • trunk/Source/JavaScriptCore/runtime/JSModuleNamespaceObject.h

    r277665 r278589  
    3535public:
    3636    using Base = JSNonFinalObject;
    37     static constexpr unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | OverridesGetOwnPropertyNames | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | GetOwnPropertySlotIsImpureForPropertyAbsence | IsImmutablePrototypeExoticObject;
     37    static constexpr unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | OverridesGetOwnPropertyNames | OverridesPut | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | GetOwnPropertySlotIsImpureForPropertyAbsence | IsImmutablePrototypeExoticObject;
    3838
    3939    static constexpr bool needsDestruction = true;
  • trunk/Source/JavaScriptCore/runtime/JSObject.cpp

    r278253 r278589  
    647647    return getOwnPropertySlotImpl(object, globalObject, propertyName, slot);
    648648}
    649 
    650 void JSObject::doPutPropertySecurityCheck(JSObject*, JSGlobalObject*, PropertyName, PutPropertySlot&)
    651 {
    652 }
    653649#endif // ASSERT_ENABLED
    654650
     
    759755}
    760756
    761 // ECMA 8.6.2.2
     757// https://tc39.es/ecma262/#sec-ordinaryset
    762758bool JSObject::put(JSCell* cell, JSGlobalObject* globalObject, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
    763759{
     
    767763bool JSObject::putInlineSlow(JSGlobalObject* globalObject, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
    768764{
    769     ASSERT(!isThisValueAltered(slot, this));
     765    ASSERT(!parseIndex(propertyName));
    770766
    771767    VM& vm = globalObject->vm();
    772768    auto scope = DECLARE_THROW_SCOPE(vm);
     769
     770    if (UNLIKELY(!vm.isSafeToRecurseSoft())) {
     771        throwStackOverflowError(globalObject, scope);
     772        return false;
     773    }
    773774
    774775    JSObject* obj = this;
    775776    for (;;) {
    776777        Structure* structure = obj->structure(vm);
    777         if (UNLIKELY(structure->typeInfo().hasPutPropertySecurityCheck())) {
    778             obj->methodTable(vm)->doPutPropertySecurityCheck(obj, globalObject, propertyName, slot);
    779             RETURN_IF_EXCEPTION(scope, false);
    780         }
     778        if (obj != this && structure->typeInfo().overridesPut())
     779            RELEASE_AND_RETURN(scope, obj->methodTable(vm)->put(obj, globalObject, propertyName, value, slot));
     780
     781        bool hasProperty = false;
    781782        unsigned attributes;
     783        PutPropertySlot::PutValueFunc customSetter = nullptr;
    782784        PropertyOffset offset = structure->get(vm, propertyName, attributes);
    783785        if (isValidOffset(offset)) {
    784             if (attributes & PropertyAttribute::ReadOnly) {
    785                 ASSERT(this->prototypeChainMayInterceptStoreTo(vm, propertyName) || obj == this);
     786            hasProperty = true;
     787            if (attributes & PropertyAttribute::CustomAccessorOrValue)
     788                customSetter = jsCast<CustomGetterSetter*>(obj->getDirect(offset))->setter();
     789        } else if (structure->hasNonReifiedStaticProperties()) {
     790            if (auto entry = structure->findPropertyHashEntry(propertyName)) {
     791                hasProperty = true;
     792                attributes = entry->value->attributes();
     793
     794                // FIXME: Remove this after writable accessors are introduced to static hash tables.
     795                if (attributes & PropertyAttribute::Accessor)
     796                    attributes |= PropertyAttribute::ReadOnly;
     797                // FIXME: Remove this after we stop defaulting to CustomValue in static hash tables.
     798                if (!(attributes & (PropertyAttribute::CustomAccessor | PropertyAttribute::BuiltinOrFunctionOrAccessorOrLazyPropertyOrConstant)))
     799                    attributes |= PropertyAttribute::CustomValue;
     800
     801                if (attributes & PropertyAttribute::CustomAccessorOrValue)
     802                    customSetter = entry->value->propertyPutter();
     803            }
     804        }
     805
     806        if (hasProperty) {
     807            if (attributes & PropertyAttribute::ReadOnly)
    786808                return typeError(globalObject, scope, slot.isStrictMode(), ReadonlyPropertyWriteError);
    787             }
    788 
    789             JSValue gs = obj->getDirect(offset);
    790             if (gs.isGetterSetter()) {
     809            if (attributes & PropertyAttribute::Accessor) {
     810                ASSERT(isValidOffset(offset));
    791811                // We need to make sure that we decide to cache this property before we potentially execute aribitrary JS.
    792812                if (!this->structure(vm)->isUncacheableDictionary())
     
    794814                RELEASE_AND_RETURN(scope, jsCast<GetterSetter*>(obj->getDirect(offset))->callSetter(globalObject, slot.thisValue(), value, slot.isStrictMode()));
    795815            }
    796             if (gs.isCustomGetterSetter()) {
    797                 bool isAccessor = attributes & PropertyAttribute::CustomAccessor;
    798                 auto setter = jsCast<CustomGetterSetter*>(gs.asCell())->setter();
     816            if (attributes & PropertyAttribute::CustomAccessor) {
     817                // FIXME: Remove this after WebIDL generator is fixed to set ReadOnly for [RuntimeConditionallyReadWrite] attributes.
     818                if (!customSetter)
     819                    return false;
     820                ASSERT(customSetter);
    799821                // FIXME: We should only be caching these if we're not an uncacheable dictionary:
    800822                // https://bugs.webkit.org/show_bug.cgi?id=215347
    801 
    802                 // We need to make sure that we decide to cache this property before we potentially execute aribitrary JS.
    803                 if (isAccessor)
    804                     slot.setCustomAccessor(obj, setter);
    805                 else
    806                     slot.setCustomValue(obj, setter);
    807 
    808                 auto result = callCustomSetter(globalObject, setter, isAccessor, obj, slot.thisValue(), value, propertyName);
    809                 RETURN_IF_EXCEPTION(scope, false);
    810                 if (result != TriState::Indeterminate)
    811                     return result == TriState::True;
     823                slot.setCustomAccessor(obj, customSetter);
     824                scope.release();
     825                customSetter(globalObject, JSValue::encode(slot.thisValue()), JSValue::encode(value), propertyName);
     826                return true;
    812827            }
    813             ASSERT(!(attributes & PropertyAttribute::Accessor));
    814 
    815             // If there's an existing property on the base object, or on one of its
    816             // prototypes, we should store the property on the *base* object.
     828            if (attributes & PropertyAttribute::CustomValue) {
     829                // FIXME: Once legacy RegExp features are implemented, there would be no use case for calling CustomValue setter if receiver is altered.
     830                if (customSetter && !(isThisValueAltered(slot, obj) && slot.context() == PutPropertySlot::ReflectSet)) {
     831                    // FIXME: We should only be caching these if we're not an uncacheable dictionary:
     832                    // https://bugs.webkit.org/show_bug.cgi?id=215347
     833                    slot.setCustomValue(obj, customSetter);
     834                    RELEASE_AND_RETURN(scope, customSetter(globalObject, JSValue::encode(obj), JSValue::encode(value), propertyName));
     835                }
     836                if (!isThisValueAltered(slot, obj)) {
     837                    // Avoid PutModePut because it fails for non-extensible structures.
     838                    obj->putDirect(vm, propertyName, value, attributesForStructure(attributes) & ~PropertyAttribute::CustomValue, slot);
     839                    return true;
     840                }
     841            }
     842            if (attributes & PropertyAttribute::BuiltinOrFunctionOrLazyProperty) {
     843                if (!isThisValueAltered(slot, obj)) {
     844                    // Avoid PutModePut because it fails for non-extensible structures.
     845                    obj->putDirect(vm, propertyName, value, attributesForStructure(attributes), slot);
     846                    return true;
     847                }
     848            }
     849            // If there's an existing writable property on the base object, or on one of its
     850            // prototypes, we should attempt to store the property on the receiver.
    817851            break;
    818852        }
    819         if (!obj->staticPropertiesReified(vm)) {
    820             if (obj->classInfo(vm)->hasStaticSetterOrReadonlyProperties()) {
    821                 if (auto entry = obj->findPropertyHashEntry(vm, propertyName))
    822                     RELEASE_AND_RETURN(scope, putEntry(globalObject, entry->table->classForThis, entry->value, obj, this, propertyName, value, slot));
    823             }
    824         }
    825         if (obj->type() == ProxyObjectType) {
    826             auto* proxy = jsCast<ProxyObject*>(obj);
    827             RELEASE_AND_RETURN(scope, proxy->ProxyObject::put(proxy, globalObject, propertyName, value, slot));
    828         }
     853
    829854        JSValue prototype = obj->getPrototype(vm, globalObject);
    830855        RETURN_IF_EXCEPTION(scope, false);
     
    834859    }
    835860
    836     if (!putDirectInternal<PutModePut>(vm, propertyName, value, 0, slot))
     861    scope.release();
     862    if (UNLIKELY(isThisValueAltered(slot, this)))
     863        return definePropertyOnReceiver(globalObject, propertyName, value, slot);
     864    return putInlineFast(globalObject, propertyName, value, slot);
     865}
     866
     867static NEVER_INLINE bool definePropertyOnReceiverSlow(JSGlobalObject* globalObject, PropertyName propertyName, JSValue value, JSObject* receiver, bool shouldThrow)
     868{
     869    VM& vm = globalObject->vm();
     870    auto scope = DECLARE_THROW_SCOPE(vm);
     871
     872    PropertySlot slot(receiver, PropertySlot::InternalMethodType::GetOwnProperty);
     873    bool hasProperty = receiver->methodTable(vm)->getOwnPropertySlot(receiver, globalObject, propertyName, slot);
     874    RETURN_IF_EXCEPTION(scope, false);
     875
     876    PropertyDescriptor descriptor;
     877    if (hasProperty) {
     878        // FIXME: For an accessor with setter, the error message is misleading.
     879        if (slot.attributes() & PropertyAttribute::ReadOnlyOrAccessorOrCustomAccessor)
     880            return typeError(globalObject, scope, shouldThrow, ReadonlyPropertyWriteError);
     881        descriptor.setValue(value);
     882    } else
     883        descriptor.setDescriptor(value, static_cast<unsigned>(PropertyAttribute::None));
     884
     885    RELEASE_AND_RETURN(scope, receiver->methodTable(vm)->defineOwnProperty(receiver, globalObject, propertyName, descriptor, shouldThrow));
     886}
     887
     888// https://tc39.es/ecma262/#sec-ordinaryset (step 3)
     889bool JSObject::definePropertyOnReceiver(JSGlobalObject* globalObject, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
     890{
     891    ASSERT(!parseIndex(propertyName));
     892
     893    VM& vm = globalObject->vm();
     894    auto scope = DECLARE_THROW_SCOPE(vm);
     895
     896    JSObject* receiver = slot.thisValue().getObject();
     897    // FIXME: For a failure due to primitive receiver, the error message is misleading.
     898    if (!receiver)
    837899        return typeError(globalObject, scope, slot.isStrictMode(), ReadonlyPropertyWriteError);
    838     return true;
     900    scope.release();
     901    if (receiver->type() == PureForwardingProxyType)
     902        receiver = jsCast<JSProxy*>(receiver)->target();
     903
     904    if (slot.isTaintedByOpaqueObject() || slot.context() == PutPropertySlot::ReflectSet) {
     905        if (receiver->methodTable(vm)->defineOwnProperty != JSObject::defineOwnProperty)
     906            return definePropertyOnReceiverSlow(globalObject, propertyName, value, receiver, slot.isStrictMode());
     907    }
     908
     909    if (UNLIKELY(receiver->hasNonReifiedStaticProperties(vm)))
     910        return receiver->putInlineFastReplacingStaticPropertyIfNeeded(globalObject, propertyName, value, slot);
     911    return receiver->putInlineFast(globalObject, propertyName, value, slot);
     912}
     913
     914bool JSObject::putInlineFastReplacingStaticPropertyIfNeeded(JSGlobalObject* globalObject, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
     915{
     916    ASSERT(!parseIndex(propertyName));
     917
     918    VM& vm = globalObject->vm();
     919    auto scope = DECLARE_THROW_SCOPE(vm);
     920
     921    Structure* structure = this->structure(vm);
     922    ASSERT(structure->hasNonReifiedStaticProperties());
     923    if (!isValidOffset(structure->get(vm, propertyName))) {
     924        if (auto entry = structure->findPropertyHashEntry(propertyName)) {
     925            if (entry->value->attributes() & PropertyAttribute::ReadOnlyOrAccessorOrCustomAccessor) {
     926                ASSERT(slot.context() == PutPropertySlot::ReflectSet);
     927                // FIXME: For an accessor with setter, the error message is misleading.
     928                return typeError(globalObject, scope, slot.isStrictMode(), ReadonlyPropertyWriteError);
     929            }
     930            // Avoid PutModePut because it fails for non-extensible structures.
     931            putDirect(vm, propertyName, value, attributesForStructure(entry->value->attributes()) & ~PropertyAttribute::CustomValue, slot);
     932            return true;
     933        }
     934    }
     935
     936    RELEASE_AND_RETURN(scope, putInlineFast(globalObject, propertyName, value, slot));
    839937}
    840938
     
    38453943}
    38463944
    3847 bool JSObject::prototypeChainMayInterceptStoreTo(VM& vm, PropertyName propertyName)
    3848 {
    3849     if (parseIndex(propertyName))
    3850         return anyObjectInChainMayInterceptIndexedAccesses(vm);
    3851    
    3852     for (JSObject* current = this; ;) {
    3853         JSValue prototype = current->getPrototypeDirect(vm);
    3854         if (prototype.isNull())
    3855             return false;
    3856        
    3857         current = asObject(prototype);
    3858        
    3859         unsigned attributes;
    3860         PropertyOffset offset = current->structure(vm)->get(vm, propertyName, attributes);
    3861         if (!JSC::isValidOffset(offset))
    3862             continue;
    3863        
    3864         if (attributes & (PropertyAttribute::ReadOnly | PropertyAttribute::Accessor))
    3865             return true;
    3866        
    3867         return false;
    3868     }
    3869 }
    3870 
    38713945bool JSObject::needsSlowPutIndexing(VM& vm) const
    38723946{
  • trunk/Source/JavaScriptCore/runtime/JSObject.h

    r278338 r278589  
    172172    JS_EXPORT_PRIVATE static bool getOwnPropertySlotByIndex(JSObject*, JSGlobalObject*, unsigned propertyName, PropertySlot&);
    173173    bool getOwnPropertySlotInline(JSGlobalObject*, PropertyName, PropertySlot&);
    174     JS_EXPORT_PRIVATE_IF_ASSERT_ENABLED static void doPutPropertySecurityCheck(JSObject*, JSGlobalObject*, PropertyName, PutPropertySlot&);
    175174
    176175    // The key difference between this and getOwnPropertySlot is that getOwnPropertySlot
     
    205204   
    206205    JS_EXPORT_PRIVATE static bool put(JSCell*, JSGlobalObject*, PropertyName, JSValue, PutPropertySlot&);
     206    JS_EXPORT_PRIVATE NEVER_INLINE static bool definePropertyOnReceiver(JSGlobalObject*, PropertyName, JSValue, PutPropertySlot&);
    207207    // putByIndex assumes that the receiver is this JSCell object.
    208208    JS_EXPORT_PRIVATE static bool putByIndex(JSCell*, JSGlobalObject*, unsigned propertyName, JSValue, bool shouldThrow);
     
    221221    ALWAYS_INLINE bool putByIndexInline(JSGlobalObject* globalObject, uint64_t propertyName, JSValue value, bool shouldThrow)
    222222    {
     223        VM& vm = getVM(globalObject);
    223224        if (LIKELY(propertyName <= MAX_ARRAY_INDEX))
    224225            return putByIndexInline(globalObject, static_cast<uint32_t>(propertyName), value, shouldThrow);
     
    226227        ASSERT(propertyName <= maxSafeInteger());
    227228        PutPropertySlot slot(this, shouldThrow);
    228         return putInlineForJSObject(this, globalObject, Identifier::from(getVM(globalObject), propertyName), value, slot);
     229        return methodTable(vm)->put(this, globalObject, Identifier::from(vm, propertyName), value, slot);
    229230    }
    230231       
     
    645646    //  - the property name is assumed to not be an index.
    646647    bool putDirect(VM&, PropertyName, JSValue, unsigned attributes = 0);
     648    bool putDirect(VM&, PropertyName, JSValue, unsigned attributes, PutPropertySlot&);
    647649    bool putDirect(VM&, PropertyName, JSValue, PutPropertySlot&);
    648650    void putDirectWithoutTransition(VM&, PropertyName, JSValue, unsigned attributes = 0);
     
    770772    bool hasGetterSetterProperties(VM& vm) { return structure(vm)->hasGetterSetterProperties(); }
    771773    bool hasCustomGetterSetterProperties(VM& vm) { return structure(vm)->hasCustomGetterSetterProperties(); }
     774
     775    bool hasNonReifiedStaticProperties(VM& vm)
     776    {
     777        return TypeInfo::hasStaticPropertyTable(inlineTypeFlags()) && !structure(vm)->staticPropertiesReified();
     778    }
    772779
    773780    // putOwnDataProperty has 'put' like semantics, however this method:
     
    817824
    818825    JS_EXPORT_PRIVATE bool anyObjectInChainMayInterceptIndexedAccesses(VM&) const;
    819     JS_EXPORT_PRIVATE bool prototypeChainMayInterceptStoreTo(VM&, PropertyName);
    820826    bool needsSlowPutIndexing(VM&) const;
    821827
     
    11101116
    11111117    JS_EXPORT_PRIVATE NEVER_INLINE bool putInlineSlow(JSGlobalObject*, PropertyName, JSValue, PutPropertySlot&);
     1118    JS_EXPORT_PRIVATE NEVER_INLINE bool putInlineFastReplacingStaticPropertyIfNeeded(JSGlobalObject*, PropertyName, JSValue, PutPropertySlot&);
     1119    bool putInlineFast(JSGlobalObject*, PropertyName, JSValue, PutPropertySlot&);
    11121120
    11131121    bool getNonIndexPropertySlot(JSGlobalObject*, PropertyName, PropertySlot&);
     
    14411449{
    14421450    return getOwnPropertySlotImpl(object, globalObject, propertyName, slot);
    1443 }
    1444 
    1445 ALWAYS_INLINE void JSObject::doPutPropertySecurityCheck(JSObject*, JSGlobalObject*, PropertyName, PutPropertySlot&)
    1446 {
    14471451}
    14481452#endif
     
    15411545}
    15421546
     1547inline bool JSObject::putDirect(VM& vm, PropertyName propertyName, JSValue value, unsigned attributes, PutPropertySlot& slot)
     1548{
     1549    ASSERT(!value.isGetterSetter());
     1550    ASSERT(!value.isCustomGetterSetter());
     1551    return putDirectInternal<PutModeDefineOwnProperty>(vm, propertyName, value, attributes, slot);
     1552}
     1553
    15431554inline bool JSObject::putDirect(VM& vm, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
    15441555{
  • trunk/Source/JavaScriptCore/runtime/JSObjectInlines.h

    r278253 r278589  
    6969        Structure* structure = obj->structure(vm);
    7070        if (structure->hasReadOnlyOrGetterSetterPropertiesExcludingProto() || structure->typeInfo().overridesGetPrototype())
     71            return false;
     72        if (obj != this && structure->typeInfo().overridesPut())
    7173            return false;
    7274
     
    250252}
    251253
    252 // ECMA 8.6.2.2
     254// https://tc39.es/ecma262/#sec-ordinaryset
    253255ALWAYS_INLINE bool JSObject::putInlineForJSObject(JSCell* cell, JSGlobalObject* globalObject, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
    254256{
    255257    VM& vm = getVM(globalObject);
    256     auto scope = DECLARE_THROW_SCOPE(vm);
    257258
    258259    JSObject* thisObject = jsCast<JSObject*>(cell);
     
    260261    ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(thisObject));
    261262
    262     if (UNLIKELY(isThisValueAltered(slot, thisObject)))
    263         RELEASE_AND_RETURN(scope, ordinarySetSlow(globalObject, thisObject, propertyName, value, slot.thisValue(), slot.isStrictMode()));
    264 
    265263    // Try indexed put first. This is required for correctness, since loads on property names that appear like
    266264    // valid indices will never look in the named property storage.
    267     if (std::optional<uint32_t> index = parseIndex(propertyName))
    268         RELEASE_AND_RETURN(scope, putByIndex(thisObject, globalObject, index.value(), value, slot.isStrictMode()));
    269 
    270     if (thisObject->canPerformFastPutInline(vm, propertyName)) {
    271         ASSERT(!thisObject->prototypeChainMayInterceptStoreTo(vm, propertyName));
    272         if (!thisObject->putDirectInternal<PutModePut>(vm, propertyName, value, 0, slot))
    273             return typeError(globalObject, scope, slot.isStrictMode(), ReadonlyPropertyWriteError);
    274         return true;
    275     }
    276 
    277     RELEASE_AND_RETURN(scope, thisObject->putInlineSlow(globalObject, propertyName, value, slot));
     265    if (std::optional<uint32_t> index = parseIndex(propertyName)) {
     266        if (UNLIKELY(isThisValueAltered(slot, thisObject)))
     267            return ordinarySetSlow(globalObject, thisObject, propertyName, value, slot.thisValue(), slot.isStrictMode());
     268        return thisObject->methodTable(vm)->putByIndex(thisObject, globalObject, index.value(), value, slot.isStrictMode());
     269    }
     270
     271    if (!thisObject->canPerformFastPutInline(vm, propertyName))
     272        return thisObject->putInlineSlow(globalObject, propertyName, value, slot);
     273    if (UNLIKELY(isThisValueAltered(slot, thisObject)))
     274        return definePropertyOnReceiver(globalObject, propertyName, value, slot);
     275    if (UNLIKELY(thisObject->hasNonReifiedStaticProperties(vm)))
     276        return thisObject->putInlineFastReplacingStaticPropertyIfNeeded(globalObject, propertyName, value, slot);
     277    return thisObject->putInlineFast(globalObject, propertyName, value, slot);
     278}
     279
     280ALWAYS_INLINE bool JSObject::putInlineFast(JSGlobalObject* globalObject, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
     281{
     282    VM& vm = getVM(globalObject);
     283    auto scope = DECLARE_THROW_SCOPE(vm);
     284
     285    // FIXME: For a failure due to non-extensible structure, the error message is misleading.
     286    if (!putDirectInternal<PutModePut>(vm, propertyName, value, 0, slot))
     287        return typeError(globalObject, scope, slot.isStrictMode(), ReadonlyPropertyWriteError);
     288    return true;
    278289}
    279290
     
    318329        PropertyOffset offset = structure->get(vm, propertyName, currentAttributes);
    319330        if (offset != invalidOffset) {
    320             if ((mode == PutModePut) && currentAttributes & PropertyAttribute::ReadOnly)
     331            if ((mode == PutModePut) && currentAttributes & PropertyAttribute::ReadOnlyOrAccessorOrCustomAccessor)
    321332                return false;
    322333
     
    377388    offset = structure->get(vm, propertyName, currentAttributes);
    378389    if (offset != invalidOffset) {
    379         if ((mode == PutModePut) && currentAttributes & PropertyAttribute::ReadOnly)
     390        if ((mode == PutModePut) && currentAttributes & PropertyAttribute::ReadOnlyOrAccessorOrCustomAccessor)
    380391            return false;
    381392
  • trunk/Source/JavaScriptCore/runtime/JSProxy.h

    r277665 r278589  
    3333public:
    3434    using Base = JSNonFinalObject;
    35     static constexpr unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | OverridesGetOwnPropertyNames | OverridesGetPrototype | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero;
     35    static constexpr unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | OverridesGetOwnPropertyNames | OverridesPut | OverridesGetPrototype | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero;
    3636
    3737    template<typename CellType, SubspaceAccess>
  • trunk/Source/JavaScriptCore/runtime/JSTypeInfo.h

    r277665 r278589  
    5858static constexpr unsigned InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero = 1 << 16;
    5959static constexpr unsigned StructureIsImmortal = 1 << 17;
    60 static constexpr unsigned HasPutPropertySecurityCheck = 1 << 18;
     60static constexpr unsigned OverridesPut = 1 << 18;
    6161static constexpr unsigned OverridesGetPrototype = 1 << 19;
    6262static constexpr unsigned GetOwnPropertySlotMayBeWrongAboutDontEnum = 1 << 20;
     
    9595    bool overridesGetCallData() const { return isSetOnFlags1<OverridesGetCallData>(); }
    9696    bool overridesGetOwnPropertySlot() const { return overridesGetOwnPropertySlot(inlineTypeFlags()); }
     97    bool hasStaticPropertyTable() const { return isSetOnFlags1<HasStaticPropertyTable>(); }
    9798    static bool overridesGetOwnPropertySlot(InlineTypeFlags flags) { return flags & OverridesGetOwnPropertySlot; }
    9899    static bool hasStaticPropertyTable(InlineTypeFlags flags) { return flags & HasStaticPropertyTable; }
     
    103104    bool overridesGetOwnSpecialPropertyNames() const { return isSetOnFlags2<OverridesGetOwnSpecialPropertyNames>(); }
    104105    bool overridesAnyFormOfGetOwnPropertyNames() const { return overridesGetOwnPropertyNames() || overridesGetOwnSpecialPropertyNames(); }
     106    bool overridesPut() const { return isSetOnFlags2<OverridesPut>(); }
    105107    bool overridesGetPrototype() const { return isSetOnFlags2<OverridesGetPrototype>(); }
    106108    bool prohibitsPropertyCaching() const { return isSetOnFlags2<ProhibitsPropertyCaching>(); }
     
    108110    bool getOwnPropertySlotIsImpureForPropertyAbsence() const { return isSetOnFlags2<GetOwnPropertySlotIsImpureForPropertyAbsence>(); }
    109111    bool getOwnPropertySlotMayBeWrongAboutDontEnum() const { return isSetOnFlags2<GetOwnPropertySlotMayBeWrongAboutDontEnum>(); }
    110     bool hasPutPropertySecurityCheck() const { return isSetOnFlags2<HasPutPropertySecurityCheck>(); }
    111112    bool newImpurePropertyFiresWatchpoints() const { return isSetOnFlags2<NewImpurePropertyFiresWatchpoints>(); }
    112113    bool isImmutablePrototypeExoticObject() const { return isSetOnFlags2<IsImmutablePrototypeExoticObject>(); }
  • trunk/Source/JavaScriptCore/runtime/Lookup.h

    r277665 r278589  
    263263}
    264264
    265 // 'base' means the object holding the property (possibly in the prototype chain of the object put was called on).
    266 // 'thisValue' is the object that put is being applied to (in the case of a proxy, the proxy target).
    267 // 'slot.thisValue()' is the object the put was originally performed on (in the case of a proxy, the proxy itself).
    268 inline bool putEntry(JSGlobalObject* globalObject, const ClassInfo*, const HashTableValue* entry, JSObject* base, JSObject* thisValue, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
    269 {
    270     VM& vm = getVM(globalObject);
    271     auto scope = DECLARE_THROW_SCOPE(vm);
    272 
    273     if (entry->attributes() & PropertyAttribute::BuiltinOrFunctionOrLazyProperty) {
    274         if (!(entry->attributes() & PropertyAttribute::ReadOnly)) {
    275             // If this is a function or lazy property put then we just do the put because
    276             // logically the object already had the property, so this is just a replace.
    277             // FIXME: thisValue may be an object with non-extensible structure we must throw for.
    278             if (JSObject* thisObject = jsDynamicCast<JSObject*>(vm, thisValue))
    279                 thisObject->putDirect(vm, propertyName, value);
    280             return true;
    281         }
    282         return typeError(globalObject, scope, slot.isStrictMode(), ReadonlyPropertyWriteError);
    283     }
    284 
    285     if (entry->attributes() & PropertyAttribute::Accessor)
    286         return typeError(globalObject, scope, slot.isStrictMode(), ReadonlyPropertyWriteError);
    287 
    288     if (!(entry->attributes() & PropertyAttribute::ReadOnly)) {
    289         ASSERT_WITH_MESSAGE(!(entry->attributes() & PropertyAttribute::DOMJITAttribute), "DOMJITAttribute supports readonly attributes currently.");
    290         bool isAccessor = entry->attributes() & PropertyAttribute::CustomAccessor;
    291         // FIXME: We should only be caching these if we're not an uncacheable dictionary:
    292         // https://bugs.webkit.org/show_bug.cgi?id=215347
    293         // We need to make sure that we decide to cache this property before we potentially execute aribitrary JS.
    294         if (isAccessor)
    295             slot.setCustomAccessor(base, entry->propertyPutter());
    296         else
    297             slot.setCustomValue(base, entry->propertyPutter());
    298 
    299         auto result = callCustomSetter(globalObject, entry->propertyPutter(), isAccessor, base, slot.thisValue(), value, propertyName);
    300         RETURN_IF_EXCEPTION(scope, false);
    301         if (result != TriState::Indeterminate)
    302             return result == TriState::True;
    303 
    304         // FIXME: thisValue may be an object with non-extensible structure we must throw for.
    305         if (JSObject* thisObject = jsDynamicCast<JSObject*>(vm, thisValue))
    306             thisObject->putDirect(vm, propertyName, value);
    307         return true;
    308     }
    309 
    310     return typeError(globalObject, scope, slot.isStrictMode(), ReadonlyPropertyWriteError);
    311 }
    312 
    313 /**
    314  * This one is for "put".
    315  * It looks up a hash entry for the property to be set.  If an entry
    316  * is found it sets the value and returns true, else it returns false.
    317  */
    318 inline bool lookupPut(JSGlobalObject* globalObject, PropertyName propertyName, JSObject* base, JSValue value, const HashTable& table, PutPropertySlot& slot, bool& putResult)
    319 {
    320     const HashTableValue* entry = table.entry(propertyName);
    321 
    322     if (!entry)
    323         return false;
    324 
    325     putResult = putEntry(globalObject, table.classForThis, entry, base, base, propertyName, value, slot);
    326     return true;
    327 }
    328 
    329265inline void reifyStaticProperty(VM& vm, const ClassInfo* classInfo, const PropertyName& propertyName, const HashTableValue& value, JSObject& thisObj)
    330266{
  • trunk/Source/JavaScriptCore/runtime/PropertySlot.h

    r278253 r278589  
    4848    CustomAccessorOrValue = CustomAccessor | CustomValue,
    4949    AccessorOrCustomAccessorOrValue = Accessor | CustomAccessor | CustomValue,
     50    ReadOnlyOrAccessorOrCustomAccessor = ReadOnly | Accessor | CustomAccessor,
    5051
    5152    // Things that are used by static hashtables are not in the attributes byte in PropertyMapEntry.
  • trunk/Source/JavaScriptCore/runtime/ProxyObject.cpp

    r277665 r278589  
    465465    VM& vm = globalObject->vm();
    466466    slot.disableCaching();
     467    slot.setIsTaintedByOpaqueObject();
    467468
    468469    ProxyObject* thisObject = jsCast<ProxyObject*>(cell);
  • trunk/Source/JavaScriptCore/runtime/ProxyObject.h

    r277665 r278589  
    3535    typedef JSNonFinalObject Base;
    3636
    37     static constexpr unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | OverridesGetOwnPropertyNames | OverridesGetPrototype | OverridesGetCallData | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | ProhibitsPropertyCaching;
     37    static constexpr unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | OverridesGetOwnPropertyNames | OverridesGetPrototype | OverridesGetCallData | OverridesPut | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | ProhibitsPropertyCaching;
    3838
    3939    template<typename CellType, SubspaceAccess mode>
  • trunk/Source/JavaScriptCore/runtime/PutPropertySlot.h

    r277665 r278589  
    3838public:
    3939    enum Type : uint8_t { Uncachable, ExistingProperty, NewProperty, SetterProperty, CustomValue, CustomAccessor };
    40     enum Context { UnknownContext, PutById, PutByIdEval };
     40    enum Context : uint8_t { UnknownContext, PutById, PutByIdEval, ReflectSet };
    4141    using PutValueFunc = JSC::PutValueFunc;
    4242    using PutValueFuncWithPtr = JSC::PutValueFuncWithPtr;
     
    4848        , m_isStrictMode(isStrictMode)
    4949        , m_isInitialization(isInitialization)
     50        , m_isTaintedByOpaqueObject(false)
    5051        , m_type(Uncachable)
    5152        , m_context(context)
     
    105106    }
    106107
    107     Context context() const { return static_cast<Context>(m_context); }
    108 
    109108    Type type() const { return m_type; }
     109    Context context() const { return m_context; }
    110110    JSObject* base() const { return m_base; }
    111111    JSValue thisValue() const { return m_thisValue; }
     
    117117    bool isCustomAccessor() const { return isCacheable() && m_type == CustomAccessor; }
    118118    bool isInitialization() const { return m_isInitialization; }
     119    bool isTaintedByOpaqueObject() const { return m_isTaintedByOpaqueObject; }
     120    void setIsTaintedByOpaqueObject() { m_isTaintedByOpaqueObject = true; }
    119121
    120122    PropertyOffset cachedOffset() const
     
    136138    bool m_isStrictMode : 1;
    137139    bool m_isInitialization : 1;
     140    bool m_isTaintedByOpaqueObject : 1;
    138141    Type m_type;
    139     uint8_t m_context;
     142    Context m_context;
    140143    CacheabilityType m_cacheability;
    141144    FunctionPtr<CustomAccessorPtrTag> m_putFunction;
  • trunk/Source/JavaScriptCore/runtime/ReflectObject.cpp

    r278185 r278589  
    261261    // Do not raise any readonly errors that happen in strict mode.
    262262    bool shouldThrowIfCantSet = false;
    263     PutPropertySlot slot(receiver, shouldThrowIfCantSet);
     263    PutPropertySlot slot(receiver, shouldThrowIfCantSet, PutPropertySlot::ReflectSet);
    264264    RELEASE_AND_RETURN(scope, JSValue::encode(jsBoolean(targetObject->methodTable(vm)->put(targetObject, globalObject, propertyName, callFrame->argument(2), slot))));
    265265}
  • trunk/Source/JavaScriptCore/runtime/RegExpObject.cpp

    r277665 r278589  
    135135{
    136136    VM& vm = globalObject->vm();
     137    auto scope = DECLARE_THROW_SCOPE(vm);
    137138    RegExpObject* thisObject = jsCast<RegExpObject*>(cell);
    138139
    139     if (UNLIKELY(isThisValueAltered(slot, thisObject)))
    140         return ordinarySetSlow(globalObject, thisObject, propertyName, value, slot.thisValue(), slot.isStrictMode());
     140    if (propertyName == vm.propertyNames->lastIndex) {
     141        if (!thisObject->lastIndexIsWritable())
     142            return typeError(globalObject, scope, slot.isStrictMode(), ReadonlyPropertyWriteError);
    141143
    142     if (propertyName == vm.propertyNames->lastIndex) {
     144        if (UNLIKELY(slot.thisValue() != thisObject))
     145            RELEASE_AND_RETURN(scope, JSObject::definePropertyOnReceiver(globalObject, propertyName, value, slot));
     146
    143147        bool result = thisObject->setLastIndex(globalObject, value, slot.isStrictMode());
     148        RETURN_IF_EXCEPTION(scope, false);
    144149        slot.setCustomValue(thisObject, slot.isStrictMode()
    145150            ? regExpObjectSetLastIndexStrict
     
    147152        return result;
    148153    }
    149     return Base::put(cell, globalObject, propertyName, value, slot);
     154    RELEASE_AND_RETURN(scope, Base::put(cell, globalObject, propertyName, value, slot));
    150155}
    151156
  • trunk/Source/JavaScriptCore/runtime/RegExpObject.h

    r277665 r278589  
    3131public:
    3232    using Base = JSNonFinalObject;
    33     static constexpr unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | OverridesGetOwnSpecialPropertyNames;
     33    static constexpr unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | OverridesGetOwnSpecialPropertyNames | OverridesPut;
    3434
    3535    template<typename CellType, SubspaceAccess mode>
  • trunk/Source/JavaScriptCore/runtime/StringObject.cpp

    r278253 r278589  
    6969    StringObject* thisObject = jsCast<StringObject*>(cell);
    7070
    71     if (UNLIKELY(isThisValueAltered(slot, thisObject)))
    72         RELEASE_AND_RETURN(scope, ordinarySetSlow(globalObject, thisObject, propertyName, value, slot.thisValue(), slot.isStrictMode()));
    73 
    7471    if (propertyName == vm.propertyNames->length)
    7572        return typeError(globalObject, scope, slot.isStrictMode(), ReadonlyPropertyWriteError);
     73    if (UNLIKELY(slot.thisValue() != thisObject))
     74        RELEASE_AND_RETURN(scope, JSObject::put(cell, globalObject, propertyName, value, slot));
    7675    if (std::optional<uint32_t> index = parseIndex(propertyName))
    7776        RELEASE_AND_RETURN(scope, putByIndex(cell, globalObject, index.value(), value, slot.isStrictMode()));
  • trunk/Source/JavaScriptCore/runtime/StringObject.h

    r277665 r278589  
    2929public:
    3030    using Base = JSWrapperObject;
    31     static constexpr unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | OverridesGetOwnPropertyNames | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero;
     31    static constexpr unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | OverridesGetOwnPropertyNames | OverridesPut | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero;
    3232
    3333    template<typename, SubspaceAccess mode>
  • trunk/Source/JavaScriptCore/runtime/StringPrototype.cpp

    r278351 r278589  
    122122}
    123123
    124 void StringPrototype::finishCreation(VM& vm, JSGlobalObject* globalObject, JSString* nameAndMessage)
    125 {
    126     Base::finishCreation(vm, nameAndMessage);
     124void StringPrototype::finishCreation(VM& vm, JSGlobalObject* globalObject)
     125{
     126    Base::finishCreation(vm, jsEmptyString(vm));
    127127    ASSERT(inherits(vm, info()));
    128128
     
    166166
    167167    // The constructor will be added later, after StringConstructor has been built
    168     putDirectWithoutTransition(vm, vm.propertyNames->length, jsNumber(0), PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly | PropertyAttribute::DontEnum);
    169168}
    170169
    171170StringPrototype* StringPrototype::create(VM& vm, JSGlobalObject* globalObject, Structure* structure)
    172171{
    173     JSString* empty = jsEmptyString(vm);
    174172    StringPrototype* prototype = new (NotNull, allocateCell<StringPrototype>(vm.heap)) StringPrototype(vm, structure);
    175     prototype->finishCreation(vm, globalObject, empty);
     173    prototype->finishCreation(vm, globalObject);
    176174    return prototype;
    177175}
  • trunk/Source/JavaScriptCore/runtime/StringPrototype.h

    r277665 r278589  
    4646private:
    4747    StringPrototype(VM&, Structure*);
    48     void finishCreation(VM&, JSGlobalObject*, JSString*);
     48    void finishCreation(VM&, JSGlobalObject*);
    4949};
    5050STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(StringPrototype, StringObject);
  • trunk/Source/JavaScriptCore/runtime/Structure.cpp

    r278253 r278589  
    191191        RELEASE_ASSERT(typeInfo().interceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero());
    192192
    193     bool overridesPutPropertySecurityCheck =
    194         methodTable.doPutPropertySecurityCheck != JSObject::doPutPropertySecurityCheck
    195         && methodTable.doPutPropertySecurityCheck != JSCell::doPutPropertySecurityCheck;
    196     RELEASE_ASSERT(overridesPutPropertySecurityCheck == typeInfo().hasPutPropertySecurityCheck());
    197 
    198193    bool overridesGetOwnPropertyNames =
    199194        methodTable.getOwnPropertyNames != JSObject::getOwnPropertyNames
     
    210205        && methodTable.getPrototype != JSCell::getPrototype;
    211206    RELEASE_ASSERT(overridesGetPrototype == typeInfo().overridesGetPrototype());
     207
     208    bool overridesPut =
     209        methodTable.put != JSObject::put
     210        && methodTable.put != JSCell::put;
     211    RELEASE_ASSERT(overridesPut == typeInfo().overridesPut());
    212212}
    213213#else
  • trunk/Source/JavaScriptCore/runtime/Structure.h

    r278253 r278589  
    269269        return typeInfo().getOwnPropertySlotIsImpure();
    270270    }
     271
     272    bool hasNonReifiedStaticProperties() const
     273    {
     274        return typeInfo().hasStaticPropertyTable() && !staticPropertiesReified();
     275    }
    271276   
    272277    // Type accessors.
  • trunk/Source/JavaScriptCore/tools/JSDollarVM.cpp

    r278553 r278589  
    691691}
    692692
    693 static const struct CompactHashIndex staticCustomAccessorTableIndex[2] = {
    694     { 0, -1 },
    695     { -1, -1 },
    696 };
    697 
    698693static JSC_DECLARE_CUSTOM_GETTER(testStaticAccessorGetter);
    699694static JSC_DECLARE_CUSTOM_SETTER(testStaticAccessorPutter);
     
    720715    auto scope = DECLARE_THROW_SCOPE(vm);
    721716   
    722     JSObject* thisObject = jsDynamicCast<JSObject*>(vm, JSValue::decode(thisValue));
    723     if (!thisObject)
    724         return throwVMTypeError(globalObject, scope);
     717    JSValue receiver = JSValue::decode(thisValue);
     718    JSObject* thisObject = receiver.isObject() ? asObject(receiver) : receiver.synthesizePrototype(globalObject);
     719    RETURN_IF_EXCEPTION(scope, false);
     720    RELEASE_ASSERT(thisObject);
    725721
    726722    return thisObject->putDirect(vm, PropertyName(Identifier::fromString(vm, "testField")), JSValue::decode(value));
    727723}
    728724
    729 static const struct HashTableValue staticCustomAccessorTableValues[1] = {
     725static const struct CompactHashIndex staticCustomAccessorTableIndex[9] = {
     726    { -1, -1 },
     727    { -1, -1 },
     728    { 2, -1 },
     729    { -1, -1 },
     730    { 0, 8 },
     731    { -1, -1 },
     732    { -1, -1 },
     733    { -1, -1 },
     734    { 1, -1 },
     735};
     736
     737static const struct HashTableValue staticCustomAccessorTableValues[3] = {
    730738    { "testStaticAccessor", static_cast<unsigned>(PropertyAttribute::CustomAccessor), NoIntrinsic, { (intptr_t)static_cast<PropertySlot::GetValueFunc>(testStaticAccessorGetter), (intptr_t)static_cast<PutPropertySlot::PutValueFunc>(testStaticAccessorPutter) } },
     739    { "testStaticAccessorDontEnum", PropertyAttribute::CustomAccessor | PropertyAttribute::DontEnum, NoIntrinsic, { (intptr_t)static_cast<GetValueFunc>(testStaticAccessorGetter), (intptr_t)static_cast<PutValueFunc>(testStaticAccessorPutter) } },
     740    { "testStaticAccessorReadOnly", PropertyAttribute::CustomAccessor | PropertyAttribute::DontEnum | PropertyAttribute::ReadOnly, NoIntrinsic, { (intptr_t)static_cast<GetValueFunc>(testStaticAccessorGetter), 0 } },
    731741};
    732742
    733743static const struct HashTable staticCustomAccessorTable =
    734     { 1, 1, true, nullptr, staticCustomAccessorTableValues, staticCustomAccessorTableIndex };
     744    { 3, 7, true, nullptr, staticCustomAccessorTableValues, staticCustomAccessorTableIndex };
    735745
    736746class StaticCustomAccessor : public JSNonFinalObject {
     
    799809}
    800810
    801 static const struct CompactHashIndex staticCustomValueTableIndex[2] = {
     811static const struct CompactHashIndex staticCustomValueTableIndex[8] = {
     812    { 1, -1 },
     813    { -1, -1 },
     814    { -1, -1 },
     815    { -1, -1 },
     816    { -1, -1 },
     817    { 2, -1 },
    802818    { 0, -1 },
    803819    { -1, -1 },
    804820};
    805821
    806 static const struct HashTableValue staticCustomValueTableValues[1] = {
    807     { "testStaticValue", static_cast<unsigned>(PropertyAttribute::CustomAccessor), NoIntrinsic, { (intptr_t)static_cast<PropertySlot::GetValueFunc>(testStaticValueGetter), (intptr_t)static_cast<PutPropertySlot::PutValueFunc>(testStaticValuePutter) } },
     822static const struct HashTableValue staticCustomValueTableValues[3] = {
     823    { "testStaticValue", static_cast<unsigned>(PropertyAttribute::CustomValue), NoIntrinsic, { (intptr_t)static_cast<GetValueFunc>(testStaticValueGetter), (intptr_t)static_cast<PutValueFunc>(testStaticValuePutter) } },
     824    { "testStaticValueNoSetter", PropertyAttribute::CustomValue | PropertyAttribute::DontEnum, NoIntrinsic, { (intptr_t)static_cast<GetValueFunc>(testStaticValueGetter), 0 } },
     825    { "testStaticValueReadOnly", PropertyAttribute::CustomValue | PropertyAttribute::DontEnum | PropertyAttribute::ReadOnly, NoIntrinsic, { (intptr_t)static_cast<GetValueFunc>(testStaticValueGetter), 0 } },
    808826};
    809827
    810828static const struct HashTable staticCustomValueTable =
    811     { 1, 1, true, nullptr, staticCustomValueTableValues, staticCustomValueTableIndex };
     829    { 3, 7, true, nullptr, staticCustomValueTableValues, staticCustomValueTableIndex };
    812830
    813831class StaticCustomValue : public JSNonFinalObject {
     
    847865class ObjectDoingSideEffectPutWithoutCorrectSlotStatus : public JSNonFinalObject {
    848866    using Base = JSNonFinalObject;
     867    static constexpr unsigned StructureFlags = Base::StructureFlags | OverridesPut;
    849868public:
    850869    template<typename CellType, SubspaceAccess>
  • trunk/Source/WebCore/ChangeLog

    r278586 r278589  
     12021-06-07  Alexey Shvayka  <shvaikalesh@gmail.com>
     2
     3        Unreviewed, reland r276592 with a fix for put() override in prototype chain of a JSProxy
     4        https://bugs.webkit.org/show_bug.cgi?id=226185
     5
     6        Tests: js/dom/script-tests/reflect-set-onto-dom.js
     7               imported/w3c/web-platform-tests/WebIDL/ecmascript-binding/interface-object-set-receiver.html
     8               http/tests/security/cross-frame-access-object-getPrototypeOf-in-put.html
     9
     10        * bindings/js/JSDOMWindowCustom.cpp:
     11        (WebCore::JSDOMWindow::put):
     12        (WebCore::JSDOMWindow::doPutPropertySecurityCheck): Deleted.
     13        * bindings/js/JSLocationCustom.cpp:
     14        (WebCore::JSLocation::doPutPropertySecurityCheck): Deleted.
     15        * bindings/js/JSRemoteDOMWindowCustom.cpp:
     16        (WebCore::JSRemoteDOMWindow::put):
     17        * bindings/scripts/CodeGeneratorJS.pm:
     18        (GeneratePut):
     19        (GenerateHeader):
     20        * bindings/scripts/test/JS/*: Updated.
     21        * bridge/objc/objc_runtime.h:
     22        * bridge/runtime_array.h:
     23        * bridge/runtime_object.h:
     24
    1252021-06-07  Devin Rousso  <drousso@apple.com>
    226
  • trunk/Source/WebCore/bindings/js/JSDOMWindowCustom.cpp

    r278585 r278589  
    257257}
    258258
    259 void JSDOMWindow::doPutPropertySecurityCheck(JSObject* cell, JSGlobalObject* lexicalGlobalObject, PropertyName propertyName, PutPropertySlot&)
     259bool JSDOMWindow::put(JSCell* cell, JSGlobalObject* lexicalGlobalObject, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
    260260{
    261261    VM& vm = lexicalGlobalObject->vm();
     
    264264    auto* thisObject = jsCast<JSDOMWindow*>(cell);
    265265
    266     String errorMessage;
    267     if (!BindingSecurity::shouldAllowAccessToDOMWindow(*lexicalGlobalObject, thisObject->wrapped(), errorMessage)) {
     266    if (propertyName != static_cast<JSVMClientData*>(vm.clientData)->builtinNames().locationPublicName()) {
    268267        // We only allow setting "location" attribute cross-origin.
    269         if (propertyName == static_cast<JSVMClientData*>(vm.clientData)->builtinNames().locationPublicName())
    270             return;
    271         throwSecurityError(*lexicalGlobalObject, scope, errorMessage);
    272         return;
    273     }
    274 }
    275 
    276 bool JSDOMWindow::put(JSCell* cell, JSGlobalObject* lexicalGlobalObject, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
    277 {
    278     VM& vm = lexicalGlobalObject->vm();
    279     auto scope = DECLARE_THROW_SCOPE(vm);
    280 
    281     auto* thisObject = jsCast<JSDOMWindow*>(cell);
    282 
    283     String errorMessage;
    284     if (!BindingSecurity::shouldAllowAccessToDOMWindow(*lexicalGlobalObject, thisObject->wrapped(), errorMessage)) {
    285         // We only allow setting "location" attribute cross-origin.
    286         if (propertyName == static_cast<JSVMClientData*>(vm.clientData)->builtinNames().locationPublicName()) {
    287             bool putResult = false;
    288             if (lookupPut(lexicalGlobalObject, propertyName, thisObject, value, *s_info.staticPropHashTable, slot, putResult))
    289                 return putResult;
     268        if (!BindingSecurity::shouldAllowAccessToDOMWindow(lexicalGlobalObject, thisObject->wrapped(), ThrowSecurityError))
    290269            return false;
    291         }
    292         throwSecurityError(*lexicalGlobalObject, scope, errorMessage);
    293         return false;
    294270    }
    295271
  • trunk/Source/WebCore/bindings/js/JSLocationCustom.cpp

    r277665 r278589  
    109109}
    110110
    111 void JSLocation::doPutPropertySecurityCheck(JSObject* object, JSGlobalObject* lexicalGlobalObject, PropertyName propertyName, PutPropertySlot&)
    112 {
    113     auto* thisObject = jsCast<JSLocation*>(object);
    114     ASSERT_GC_OBJECT_INHERITS(thisObject, info());
    115 
    116     VM& vm = lexicalGlobalObject->vm();
    117 
    118     // Always allow assigning to the whole location.
    119     // However, alllowing assigning of pieces might inadvertently disclose parts of the original location.
    120     // So fall through to the access check for those.
    121     if (propertyName == static_cast<JSVMClientData*>(vm.clientData)->builtinNames().hrefPublicName())
    122         return;
    123 
    124     // Block access and throw if there is a security error.
    125     BindingSecurity::shouldAllowAccessToDOMWindow(lexicalGlobalObject, thisObject->wrapped().window(), ThrowSecurityError);
    126 }
    127 
    128111bool JSLocation::put(JSCell* cell, JSGlobalObject* lexicalGlobalObject, PropertyName propertyName, JSValue value, PutPropertySlot& putPropertySlot)
    129112{
  • trunk/Source/WebCore/bindings/js/JSRemoteDOMWindowCustom.cpp

    r278253 r278589  
    6969    // We only allow setting "location" attribute cross-origin.
    7070    if (propertyName == static_cast<JSVMClientData*>(vm.clientData)->builtinNames().locationPublicName()) {
    71         bool putResult = false;
    72         if (lookupPut(lexicalGlobalObject, propertyName, thisObject, value, *s_info.staticPropHashTable, slot, putResult))
    73             return putResult;
    74         return false;
     71        auto* setter = s_info.staticPropHashTable->entry(propertyName)->propertyPutter();
     72        scope.release();
     73        setter(lexicalGlobalObject, JSValue::encode(slot.thisValue()), JSValue::encode(value), propertyName);
     74        return true;
    7575    }
     76
    7677    throwSecurityError(*lexicalGlobalObject, scope, errorMessage);
    7778    return false;
  • trunk/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm

    r278253 r278589  
    11741174    push(@$outputArray, "    auto* thisObject = jsCast<${className}*>(cell);\n");
    11751175    push(@$outputArray, "    ASSERT_GC_OBJECT_INHERITS(thisObject, info());\n\n");
     1176    push(@$outputArray, "    if (UNLIKELY(thisObject != putPropertySlot.thisValue()))\n");
     1177    push(@$outputArray, "        return JSObject::put(thisObject, lexicalGlobalObject, propertyName, value, putPropertySlot);\n");
    11761178
    11771179    push(@$outputArray, "    auto throwScope = DECLARE_THROW_SCOPE(lexicalGlobalObject->vm());\n\n");
     
    29502952    }
    29512953
    2952     if ($interface->extendedAttributes->{CheckSecurity}) {
    2953         push(@headerContent, "    static void doPutPropertySecurityCheck(JSC::JSObject*, JSC::JSGlobalObject*, JSC::PropertyName, JSC::PutPropertySlot&);\n");
    2954         $structureFlags{"JSC::HasPutPropertySecurityCheck"} = 1;
    2955     }
    2956 
    29572954    if ($interface->extendedAttributes->{Plugin} || GetNamedSetterOperation($interface)) {
    29582955        $structureFlags{"JSC::ProhibitsPropertyCaching"} = 1;
     
    29672964        push(@headerContent, "    static bool put(JSC::JSCell*, JSC::JSGlobalObject*, JSC::PropertyName, JSC::JSValue, JSC::PutPropertySlot&);\n");
    29682965        push(@headerContent, "    static bool putByIndex(JSC::JSCell*, JSC::JSGlobalObject*, unsigned propertyName, JSC::JSValue, bool shouldThrow);\n");
     2966        $structureFlags{"JSC::OverridesPut"} = 1;
    29692967    }
    29702968   
  • trunk/Source/WebCore/bindings/scripts/test/JS/JSTestDomainSecurity.h

    r277665 r278589  
    4040    static JSC::JSObject* prototype(JSC::VM&, JSDOMGlobalObject&);
    4141    static TestDomainSecurity* toWrapped(JSC::VM&, JSC::JSValue);
    42     static void doPutPropertySecurityCheck(JSC::JSObject*, JSC::JSGlobalObject*, JSC::PropertyName, JSC::PutPropertySlot&);
    4342    static void destroy(JSC::JSCell*);
    4443
     
    6059    static void analyzeHeap(JSCell*, JSC::HeapAnalyzer&);
    6160public:
    62     static constexpr unsigned StructureFlags = Base::StructureFlags | JSC::HasPutPropertySecurityCheck | JSC::HasStaticPropertyTable;
     61    static constexpr unsigned StructureFlags = Base::StructureFlags | JSC::HasStaticPropertyTable;
    6362protected:
    6463    JSTestDomainSecurity(JSC::Structure*, JSDOMGlobalObject&, Ref<TestDomainSecurity>&&);
  • trunk/Source/WebCore/bindings/scripts/test/JS/JSTestIndexedSetterNoIdentifier.cpp

    r277665 r278589  
    200200    ASSERT_GC_OBJECT_INHERITS(thisObject, info());
    201201
     202    if (UNLIKELY(thisObject != putPropertySlot.thisValue()))
     203        return JSObject::put(thisObject, lexicalGlobalObject, propertyName, value, putPropertySlot);
    202204    auto throwScope = DECLARE_THROW_SCOPE(lexicalGlobalObject->vm());
    203205
  • trunk/Source/WebCore/bindings/scripts/test/JS/JSTestIndexedSetterNoIdentifier.h

    r277665 r278589  
    6565    static void analyzeHeap(JSCell*, JSC::HeapAnalyzer&);
    6666public:
    67     static constexpr unsigned StructureFlags = Base::StructureFlags | JSC::InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | JSC::OverridesGetOwnPropertyNames | JSC::OverridesGetOwnPropertySlot;
     67    static constexpr unsigned StructureFlags = Base::StructureFlags | JSC::InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | JSC::OverridesGetOwnPropertyNames | JSC::OverridesGetOwnPropertySlot | JSC::OverridesPut;
    6868protected:
    6969    JSTestIndexedSetterNoIdentifier(JSC::Structure*, JSDOMGlobalObject&, Ref<TestIndexedSetterNoIdentifier>&&);
  • trunk/Source/WebCore/bindings/scripts/test/JS/JSTestIndexedSetterThrowingException.cpp

    r277665 r278589  
    200200    ASSERT_GC_OBJECT_INHERITS(thisObject, info());
    201201
     202    if (UNLIKELY(thisObject != putPropertySlot.thisValue()))
     203        return JSObject::put(thisObject, lexicalGlobalObject, propertyName, value, putPropertySlot);
    202204    auto throwScope = DECLARE_THROW_SCOPE(lexicalGlobalObject->vm());
    203205
  • trunk/Source/WebCore/bindings/scripts/test/JS/JSTestIndexedSetterThrowingException.h

    r277665 r278589  
    6565    static void analyzeHeap(JSCell*, JSC::HeapAnalyzer&);
    6666public:
    67     static constexpr unsigned StructureFlags = Base::StructureFlags | JSC::InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | JSC::OverridesGetOwnPropertyNames | JSC::OverridesGetOwnPropertySlot;
     67    static constexpr unsigned StructureFlags = Base::StructureFlags | JSC::InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | JSC::OverridesGetOwnPropertyNames | JSC::OverridesGetOwnPropertySlot | JSC::OverridesPut;
    6868protected:
    6969    JSTestIndexedSetterThrowingException(JSC::Structure*, JSDOMGlobalObject&, Ref<TestIndexedSetterThrowingException>&&);
  • trunk/Source/WebCore/bindings/scripts/test/JS/JSTestIndexedSetterWithIdentifier.cpp

    r277830 r278589  
    209209    ASSERT_GC_OBJECT_INHERITS(thisObject, info());
    210210
     211    if (UNLIKELY(thisObject != putPropertySlot.thisValue()))
     212        return JSObject::put(thisObject, lexicalGlobalObject, propertyName, value, putPropertySlot);
    211213    auto throwScope = DECLARE_THROW_SCOPE(lexicalGlobalObject->vm());
    212214
  • trunk/Source/WebCore/bindings/scripts/test/JS/JSTestIndexedSetterWithIdentifier.h

    r277665 r278589  
    6565    static void analyzeHeap(JSCell*, JSC::HeapAnalyzer&);
    6666public:
    67     static constexpr unsigned StructureFlags = Base::StructureFlags | JSC::InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | JSC::OverridesGetOwnPropertyNames | JSC::OverridesGetOwnPropertySlot;
     67    static constexpr unsigned StructureFlags = Base::StructureFlags | JSC::InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | JSC::OverridesGetOwnPropertyNames | JSC::OverridesGetOwnPropertySlot | JSC::OverridesPut;
    6868protected:
    6969    JSTestIndexedSetterWithIdentifier(JSC::Structure*, JSDOMGlobalObject&, Ref<TestIndexedSetterWithIdentifier>&&);
  • trunk/Source/WebCore/bindings/scripts/test/JS/JSTestInterface.h

    r277665 r278589  
    8484    JSC::JSValue supplementalMethod3(JSC::JSGlobalObject&, JSC::CallFrame&);
    8585#endif
     86public:
     87    static constexpr unsigned StructureFlags = Base::StructureFlags | JSC::OverridesPut;
    8688protected:
    8789    JSTestInterface(JSC::Structure*, JSDOMGlobalObject&, Ref<TestInterface>&&);
  • trunk/Source/WebCore/bindings/scripts/test/JS/JSTestNamedAndIndexedSetterNoIdentifier.cpp

    r277665 r278589  
    226226    ASSERT_GC_OBJECT_INHERITS(thisObject, info());
    227227
     228    if (UNLIKELY(thisObject != putPropertySlot.thisValue()))
     229        return JSObject::put(thisObject, lexicalGlobalObject, propertyName, value, putPropertySlot);
    228230    auto throwScope = DECLARE_THROW_SCOPE(lexicalGlobalObject->vm());
    229231
  • trunk/Source/WebCore/bindings/scripts/test/JS/JSTestNamedAndIndexedSetterNoIdentifier.h

    r277665 r278589  
    6565    static void analyzeHeap(JSCell*, JSC::HeapAnalyzer&);
    6666public:
    67     static constexpr unsigned StructureFlags = Base::StructureFlags | JSC::GetOwnPropertySlotIsImpureForPropertyAbsence | JSC::InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | JSC::OverridesGetOwnPropertyNames | JSC::OverridesGetOwnPropertySlot | JSC::ProhibitsPropertyCaching;
     67    static constexpr unsigned StructureFlags = Base::StructureFlags | JSC::GetOwnPropertySlotIsImpureForPropertyAbsence | JSC::InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | JSC::OverridesGetOwnPropertyNames | JSC::OverridesGetOwnPropertySlot | JSC::OverridesPut | JSC::ProhibitsPropertyCaching;
    6868protected:
    6969    JSTestNamedAndIndexedSetterNoIdentifier(JSC::Structure*, JSDOMGlobalObject&, Ref<TestNamedAndIndexedSetterNoIdentifier>&&);
  • trunk/Source/WebCore/bindings/scripts/test/JS/JSTestNamedAndIndexedSetterThrowingException.cpp

    r277665 r278589  
    226226    ASSERT_GC_OBJECT_INHERITS(thisObject, info());
    227227
     228    if (UNLIKELY(thisObject != putPropertySlot.thisValue()))
     229        return JSObject::put(thisObject, lexicalGlobalObject, propertyName, value, putPropertySlot);
    228230    auto throwScope = DECLARE_THROW_SCOPE(lexicalGlobalObject->vm());
    229231
  • trunk/Source/WebCore/bindings/scripts/test/JS/JSTestNamedAndIndexedSetterThrowingException.h

    r277665 r278589  
    6565    static void analyzeHeap(JSCell*, JSC::HeapAnalyzer&);
    6666public:
    67     static constexpr unsigned StructureFlags = Base::StructureFlags | JSC::GetOwnPropertySlotIsImpureForPropertyAbsence | JSC::InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | JSC::OverridesGetOwnPropertyNames | JSC::OverridesGetOwnPropertySlot | JSC::ProhibitsPropertyCaching;
     67    static constexpr unsigned StructureFlags = Base::StructureFlags | JSC::GetOwnPropertySlotIsImpureForPropertyAbsence | JSC::InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | JSC::OverridesGetOwnPropertyNames | JSC::OverridesGetOwnPropertySlot | JSC::OverridesPut | JSC::ProhibitsPropertyCaching;
    6868protected:
    6969    JSTestNamedAndIndexedSetterThrowingException(JSC::Structure*, JSDOMGlobalObject&, Ref<TestNamedAndIndexedSetterThrowingException>&&);
  • trunk/Source/WebCore/bindings/scripts/test/JS/JSTestNamedAndIndexedSetterWithIdentifier.cpp

    r277830 r278589  
    237237    ASSERT_GC_OBJECT_INHERITS(thisObject, info());
    238238
     239    if (UNLIKELY(thisObject != putPropertySlot.thisValue()))
     240        return JSObject::put(thisObject, lexicalGlobalObject, propertyName, value, putPropertySlot);
    239241    auto throwScope = DECLARE_THROW_SCOPE(lexicalGlobalObject->vm());
    240242
  • trunk/Source/WebCore/bindings/scripts/test/JS/JSTestNamedAndIndexedSetterWithIdentifier.h

    r277665 r278589  
    6565    static void analyzeHeap(JSCell*, JSC::HeapAnalyzer&);
    6666public:
    67     static constexpr unsigned StructureFlags = Base::StructureFlags | JSC::GetOwnPropertySlotIsImpureForPropertyAbsence | JSC::InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | JSC::OverridesGetOwnPropertyNames | JSC::OverridesGetOwnPropertySlot | JSC::ProhibitsPropertyCaching;
     67    static constexpr unsigned StructureFlags = Base::StructureFlags | JSC::GetOwnPropertySlotIsImpureForPropertyAbsence | JSC::InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | JSC::OverridesGetOwnPropertyNames | JSC::OverridesGetOwnPropertySlot | JSC::OverridesPut | JSC::ProhibitsPropertyCaching;
    6868protected:
    6969    JSTestNamedAndIndexedSetterWithIdentifier(JSC::Structure*, JSDOMGlobalObject&, Ref<TestNamedAndIndexedSetterWithIdentifier>&&);
  • trunk/Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterNoIdentifier.cpp

    r277665 r278589  
    205205    ASSERT_GC_OBJECT_INHERITS(thisObject, info());
    206206
     207    if (UNLIKELY(thisObject != putPropertySlot.thisValue()))
     208        return JSObject::put(thisObject, lexicalGlobalObject, propertyName, value, putPropertySlot);
    207209    auto throwScope = DECLARE_THROW_SCOPE(lexicalGlobalObject->vm());
    208210
  • trunk/Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterNoIdentifier.h

    r277665 r278589  
    6565    static void analyzeHeap(JSCell*, JSC::HeapAnalyzer&);
    6666public:
    67     static constexpr unsigned StructureFlags = Base::StructureFlags | JSC::GetOwnPropertySlotIsImpureForPropertyAbsence | JSC::InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | JSC::OverridesGetOwnPropertyNames | JSC::OverridesGetOwnPropertySlot | JSC::ProhibitsPropertyCaching;
     67    static constexpr unsigned StructureFlags = Base::StructureFlags | JSC::GetOwnPropertySlotIsImpureForPropertyAbsence | JSC::InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | JSC::OverridesGetOwnPropertyNames | JSC::OverridesGetOwnPropertySlot | JSC::OverridesPut | JSC::ProhibitsPropertyCaching;
    6868protected:
    6969    JSTestNamedSetterNoIdentifier(JSC::Structure*, JSDOMGlobalObject&, Ref<TestNamedSetterNoIdentifier>&&);
  • trunk/Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterThrowingException.cpp

    r277665 r278589  
    205205    ASSERT_GC_OBJECT_INHERITS(thisObject, info());
    206206
     207    if (UNLIKELY(thisObject != putPropertySlot.thisValue()))
     208        return JSObject::put(thisObject, lexicalGlobalObject, propertyName, value, putPropertySlot);
    207209    auto throwScope = DECLARE_THROW_SCOPE(lexicalGlobalObject->vm());
    208210
  • trunk/Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterThrowingException.h

    r277665 r278589  
    6565    static void analyzeHeap(JSCell*, JSC::HeapAnalyzer&);
    6666public:
    67     static constexpr unsigned StructureFlags = Base::StructureFlags | JSC::GetOwnPropertySlotIsImpureForPropertyAbsence | JSC::InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | JSC::OverridesGetOwnPropertyNames | JSC::OverridesGetOwnPropertySlot | JSC::ProhibitsPropertyCaching;
     67    static constexpr unsigned StructureFlags = Base::StructureFlags | JSC::GetOwnPropertySlotIsImpureForPropertyAbsence | JSC::InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | JSC::OverridesGetOwnPropertyNames | JSC::OverridesGetOwnPropertySlot | JSC::OverridesPut | JSC::ProhibitsPropertyCaching;
    6868protected:
    6969    JSTestNamedSetterThrowingException(JSC::Structure*, JSDOMGlobalObject&, Ref<TestNamedSetterThrowingException>&&);
  • trunk/Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterWithIdentifier.cpp

    r277830 r278589  
    213213    ASSERT_GC_OBJECT_INHERITS(thisObject, info());
    214214
     215    if (UNLIKELY(thisObject != putPropertySlot.thisValue()))
     216        return JSObject::put(thisObject, lexicalGlobalObject, propertyName, value, putPropertySlot);
    215217    auto throwScope = DECLARE_THROW_SCOPE(lexicalGlobalObject->vm());
    216218
  • trunk/Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterWithIdentifier.h

    r277665 r278589  
    6565    static void analyzeHeap(JSCell*, JSC::HeapAnalyzer&);
    6666public:
    67     static constexpr unsigned StructureFlags = Base::StructureFlags | JSC::GetOwnPropertySlotIsImpureForPropertyAbsence | JSC::InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | JSC::OverridesGetOwnPropertyNames | JSC::OverridesGetOwnPropertySlot | JSC::ProhibitsPropertyCaching;
     67    static constexpr unsigned StructureFlags = Base::StructureFlags | JSC::GetOwnPropertySlotIsImpureForPropertyAbsence | JSC::InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | JSC::OverridesGetOwnPropertyNames | JSC::OverridesGetOwnPropertySlot | JSC::OverridesPut | JSC::ProhibitsPropertyCaching;
    6868protected:
    6969    JSTestNamedSetterWithIdentifier(JSC::Structure*, JSDOMGlobalObject&, Ref<TestNamedSetterWithIdentifier>&&);
  • trunk/Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterWithIndexedGetter.cpp

    r277830 r278589  
    237237    ASSERT_GC_OBJECT_INHERITS(thisObject, info());
    238238
     239    if (UNLIKELY(thisObject != putPropertySlot.thisValue()))
     240        return JSObject::put(thisObject, lexicalGlobalObject, propertyName, value, putPropertySlot);
    239241    auto throwScope = DECLARE_THROW_SCOPE(lexicalGlobalObject->vm());
    240242
  • trunk/Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterWithIndexedGetter.h

    r277665 r278589  
    6565    static void analyzeHeap(JSCell*, JSC::HeapAnalyzer&);
    6666public:
    67     static constexpr unsigned StructureFlags = Base::StructureFlags | JSC::GetOwnPropertySlotIsImpureForPropertyAbsence | JSC::InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | JSC::OverridesGetOwnPropertyNames | JSC::OverridesGetOwnPropertySlot | JSC::ProhibitsPropertyCaching;
     67    static constexpr unsigned StructureFlags = Base::StructureFlags | JSC::GetOwnPropertySlotIsImpureForPropertyAbsence | JSC::InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | JSC::OverridesGetOwnPropertyNames | JSC::OverridesGetOwnPropertySlot | JSC::OverridesPut | JSC::ProhibitsPropertyCaching;
    6868protected:
    6969    JSTestNamedSetterWithIndexedGetter(JSC::Structure*, JSDOMGlobalObject&, Ref<TestNamedSetterWithIndexedGetter>&&);
  • trunk/Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterWithIndexedGetterAndSetter.cpp

    r277830 r278589  
    237237    ASSERT_GC_OBJECT_INHERITS(thisObject, info());
    238238
     239    if (UNLIKELY(thisObject != putPropertySlot.thisValue()))
     240        return JSObject::put(thisObject, lexicalGlobalObject, propertyName, value, putPropertySlot);
    239241    auto throwScope = DECLARE_THROW_SCOPE(lexicalGlobalObject->vm());
    240242
  • trunk/Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterWithIndexedGetterAndSetter.h

    r277665 r278589  
    6565    static void analyzeHeap(JSCell*, JSC::HeapAnalyzer&);
    6666public:
    67     static constexpr unsigned StructureFlags = Base::StructureFlags | JSC::GetOwnPropertySlotIsImpureForPropertyAbsence | JSC::InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | JSC::OverridesGetOwnPropertyNames | JSC::OverridesGetOwnPropertySlot | JSC::ProhibitsPropertyCaching;
     67    static constexpr unsigned StructureFlags = Base::StructureFlags | JSC::GetOwnPropertySlotIsImpureForPropertyAbsence | JSC::InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | JSC::OverridesGetOwnPropertyNames | JSC::OverridesGetOwnPropertySlot | JSC::OverridesPut | JSC::ProhibitsPropertyCaching;
    6868protected:
    6969    JSTestNamedSetterWithIndexedGetterAndSetter(JSC::Structure*, JSDOMGlobalObject&, Ref<TestNamedSetterWithIndexedGetterAndSetter>&&);
  • trunk/Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterWithLegacyOverrideBuiltIns.cpp

    r277665 r278589  
    205205    ASSERT_GC_OBJECT_INHERITS(thisObject, info());
    206206
     207    if (UNLIKELY(thisObject != putPropertySlot.thisValue()))
     208        return JSObject::put(thisObject, lexicalGlobalObject, propertyName, value, putPropertySlot);
    207209    auto throwScope = DECLARE_THROW_SCOPE(lexicalGlobalObject->vm());
    208210
  • trunk/Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterWithLegacyOverrideBuiltIns.h

    r277665 r278589  
    6565    static void analyzeHeap(JSCell*, JSC::HeapAnalyzer&);
    6666public:
    67     static constexpr unsigned StructureFlags = Base::StructureFlags | JSC::GetOwnPropertySlotIsImpure | JSC::InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | JSC::OverridesGetOwnPropertyNames | JSC::OverridesGetOwnPropertySlot | JSC::ProhibitsPropertyCaching;
     67    static constexpr unsigned StructureFlags = Base::StructureFlags | JSC::GetOwnPropertySlotIsImpure | JSC::InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | JSC::OverridesGetOwnPropertyNames | JSC::OverridesGetOwnPropertySlot | JSC::OverridesPut | JSC::ProhibitsPropertyCaching;
    6868protected:
    6969    JSTestNamedSetterWithLegacyOverrideBuiltIns(JSC::Structure*, JSDOMGlobalObject&, Ref<TestNamedSetterWithLegacyOverrideBuiltIns>&&);
  • trunk/Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterWithLegacyUnforgeableProperties.cpp

    r277830 r278589  
    231231    ASSERT_GC_OBJECT_INHERITS(thisObject, info());
    232232
     233    if (UNLIKELY(thisObject != putPropertySlot.thisValue()))
     234        return JSObject::put(thisObject, lexicalGlobalObject, propertyName, value, putPropertySlot);
    233235    auto throwScope = DECLARE_THROW_SCOPE(lexicalGlobalObject->vm());
    234236
  • trunk/Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterWithLegacyUnforgeableProperties.h

    r277665 r278589  
    6565    static void analyzeHeap(JSCell*, JSC::HeapAnalyzer&);
    6666public:
    67     static constexpr unsigned StructureFlags = Base::StructureFlags | JSC::GetOwnPropertySlotIsImpureForPropertyAbsence | JSC::HasStaticPropertyTable | JSC::InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | JSC::OverridesGetOwnPropertyNames | JSC::OverridesGetOwnPropertySlot | JSC::ProhibitsPropertyCaching;
     67    static constexpr unsigned StructureFlags = Base::StructureFlags | JSC::GetOwnPropertySlotIsImpureForPropertyAbsence | JSC::HasStaticPropertyTable | JSC::InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | JSC::OverridesGetOwnPropertyNames | JSC::OverridesGetOwnPropertySlot | JSC::OverridesPut | JSC::ProhibitsPropertyCaching;
    6868protected:
    6969    JSTestNamedSetterWithLegacyUnforgeableProperties(JSC::Structure*, JSDOMGlobalObject&, Ref<TestNamedSetterWithLegacyUnforgeableProperties>&&);
  • trunk/Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterWithLegacyUnforgeablePropertiesAndLegacyOverrideBuiltIns.cpp

    r277830 r278589  
    231231    ASSERT_GC_OBJECT_INHERITS(thisObject, info());
    232232
     233    if (UNLIKELY(thisObject != putPropertySlot.thisValue()))
     234        return JSObject::put(thisObject, lexicalGlobalObject, propertyName, value, putPropertySlot);
    233235    auto throwScope = DECLARE_THROW_SCOPE(lexicalGlobalObject->vm());
    234236
  • trunk/Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterWithLegacyUnforgeablePropertiesAndLegacyOverrideBuiltIns.h

    r277665 r278589  
    6565    static void analyzeHeap(JSCell*, JSC::HeapAnalyzer&);
    6666public:
    67     static constexpr unsigned StructureFlags = Base::StructureFlags | JSC::GetOwnPropertySlotIsImpure | JSC::HasStaticPropertyTable | JSC::InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | JSC::OverridesGetOwnPropertyNames | JSC::OverridesGetOwnPropertySlot | JSC::ProhibitsPropertyCaching;
     67    static constexpr unsigned StructureFlags = Base::StructureFlags | JSC::GetOwnPropertySlotIsImpure | JSC::HasStaticPropertyTable | JSC::InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | JSC::OverridesGetOwnPropertyNames | JSC::OverridesGetOwnPropertySlot | JSC::OverridesPut | JSC::ProhibitsPropertyCaching;
    6868protected:
    6969    JSTestNamedSetterWithLegacyUnforgeablePropertiesAndLegacyOverrideBuiltIns(JSC::Structure*, JSDOMGlobalObject&, Ref<TestNamedSetterWithLegacyUnforgeablePropertiesAndLegacyOverrideBuiltIns>&&);
  • trunk/Source/WebCore/bindings/scripts/test/JS/JSTestPluginInterface.cpp

    r277665 r278589  
    182182    ASSERT_GC_OBJECT_INHERITS(thisObject, info());
    183183
     184    if (UNLIKELY(thisObject != putPropertySlot.thisValue()))
     185        return JSObject::put(thisObject, lexicalGlobalObject, propertyName, value, putPropertySlot);
    184186    auto throwScope = DECLARE_THROW_SCOPE(lexicalGlobalObject->vm());
    185187
  • trunk/Source/WebCore/bindings/scripts/test/JS/JSTestPluginInterface.h

    r277665 r278589  
    6868    static void analyzeHeap(JSCell*, JSC::HeapAnalyzer&);
    6969public:
    70     static constexpr unsigned StructureFlags = Base::StructureFlags | JSC::InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | JSC::OverridesGetCallData | JSC::OverridesGetOwnPropertySlot | JSC::ProhibitsPropertyCaching;
     70    static constexpr unsigned StructureFlags = Base::StructureFlags | JSC::InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | JSC::OverridesGetCallData | JSC::OverridesGetOwnPropertySlot | JSC::OverridesPut | JSC::ProhibitsPropertyCaching;
    7171protected:
    7272    JSTestPluginInterface(JSC::Structure*, JSDOMGlobalObject&, Ref<TestPluginInterface>&&);
  • trunk/Source/WebCore/bridge/objc/objc_runtime.h

    r277665 r278589  
    9292public:
    9393    using Base = JSDestructibleObject;
    94     static constexpr unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | OverridesGetCallData;
     94    static constexpr unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | OverridesGetCallData | OverridesPut;
    9595    static constexpr bool needsDestruction = true;
    9696
  • trunk/Source/WebCore/bridge/runtime_array.h

    r277665 r278589  
    3636public:
    3737    using Base = JSArray;
    38     static constexpr unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | OverridesGetOwnPropertyNames | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero;
     38    static constexpr unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | OverridesGetOwnPropertyNames | OverridesPut | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero;
    3939    static constexpr bool needsDestruction = true;
    4040
  • trunk/Source/WebCore/bridge/runtime_object.h

    r277665 r278589  
    3838public:
    3939    using Base = JSNonFinalObject;
    40     static constexpr unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | OverridesGetOwnPropertyNames | OverridesGetCallData | GetOwnPropertySlotMayBeWrongAboutDontEnum;
     40    static constexpr unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | OverridesGetOwnPropertyNames | OverridesGetCallData | OverridesPut | GetOwnPropertySlotMayBeWrongAboutDontEnum;
    4141    static constexpr bool needsDestruction = true;
    4242
  • trunk/Source/WebKit/ChangeLog

    r278575 r278589  
     12021-06-07  Alexey Shvayka  <shvaikalesh@gmail.com>
     2
     3        Unreviewed, reland r276592 with a fix for put() override in prototype chain of a JSProxy
     4        https://bugs.webkit.org/show_bug.cgi?id=226185
     5
     6        * WebProcess/Plugins/Netscape/JSNPObject.h:
     7
    182021-06-07  Wenson Hsieh  <wenson_hsieh@apple.com>
    29
  • trunk/Source/WebKit/WebProcess/Plugins/Netscape/JSNPObject.h

    r277665 r278589  
    4545public:
    4646    using Base = JSC::JSDestructibleObject;
    47     static constexpr unsigned StructureFlags = Base::StructureFlags | JSC::OverridesGetOwnPropertySlot | JSC::OverridesGetOwnPropertyNames | JSC::OverridesGetCallData | JSC::GetOwnPropertySlotMayBeWrongAboutDontEnum;
     47    static constexpr unsigned StructureFlags = Base::StructureFlags | JSC::OverridesGetOwnPropertySlot | JSC::OverridesGetOwnPropertyNames | JSC::OverridesGetCallData | JSC::OverridesPut | JSC::GetOwnPropertySlotMayBeWrongAboutDontEnum;
    4848
    4949    template<typename CellType, JSC::SubspaceAccess>
Note: See TracChangeset for help on using the changeset viewer.