Diff
Modified: trunk/LayoutTests/ChangeLog (276659 => 276660)
--- trunk/LayoutTests/ChangeLog 2021-04-27 20:55:02 UTC (rev 276659)
+++ trunk/LayoutTests/ChangeLog 2021-04-27 20:56:19 UTC (rev 276660)
@@ -1,3 +1,18 @@
+2021-04-27 Alexey Shvayka <[email protected]>
+
+ [JSC] Remove defaultValue() from the method table
+ https://bugs.webkit.org/show_bug.cgi?id=225032
+
+ Reviewed by Darin Adler.
+
+ * platform/mac/fast/dom/objc-wrapper-toprimitive-expected.txt: Added.
+ * platform/mac/fast/dom/objc-wrapper-toprimitive.html: Added.
+ * platform/wk2/TestExpectations:
+ * plugins/npruntime/tostring-expected.txt:
+ * plugins/npruntime/tostring.html:
+ * plugins/npruntime/valueof-expected.txt:
+ * plugins/npruntime/valueof.html:
+
2021-04-27 Aditya Keerthi <[email protected]>
[iOS][FCR] Add borders for better control visibility
Added: trunk/LayoutTests/platform/mac/fast/dom/objc-wrapper-toprimitive-expected.txt (0 => 276660)
--- trunk/LayoutTests/platform/mac/fast/dom/objc-wrapper-toprimitive-expected.txt (rev 0)
+++ trunk/LayoutTests/platform/mac/fast/dom/objc-wrapper-toprimitive-expected.txt 2021-04-27 20:56:19 UTC (rev 276660)
@@ -0,0 +1,65 @@
+This tests ToPrimitive performed on Objective-C wrapper object.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+RuntimeObject
+
+PASS '' + objCController is '<ObjCController>'
+PASS +objCController is 0
+PASS `${objCController}` is '<ObjCController>'
+
+PASS objCController[Symbol.toPrimitive].length is 1
+PASS objCController[Symbol.toPrimitive]('default') is '<ObjCController>'
+PASS objCController[Symbol.toPrimitive]('number') is 0
+PASS objCController[Symbol.toPrimitive]('string') is '<ObjCController>'
+PASS objCController[Symbol.toPrimitive]('foo') threw exception TypeError: Expected primitive hint to match one of 'default', 'number', 'string'..
+PASS objCController[Symbol.toPrimitive].call({}, 'default') threw exception TypeError: RuntimeObject[Symbol.toPrimitive] method called on incompatible |this| value..
+PASS (0, objCController[Symbol.toPrimitive])() threw exception TypeError: RuntimeObject[Symbol.toPrimitive] method called on incompatible |this| value..
+
+RuntimeObject (redefined Symbol.toPrimitive)
+
+PASS typeof symbolToPrimitiveDescriptor is 'object'
+PASS symbolToPrimitiveDescriptor.value is object[Symbol.toPrimitive]
+PASS symbolToPrimitiveDescriptor.writable is true
+PASS symbolToPrimitiveDescriptor.enumerable is false
+PASS symbolToPrimitiveDescriptor.configurable is true
+
+PASS object[Symbol.toPrimitive]() is 'bar'
+PASS typeof symbolToPrimitiveDescriptor is 'object'
+PASS symbolToPrimitiveDescriptor.value is newToPrimitive
+PASS symbolToPrimitiveDescriptor.writable is false
+PASS symbolToPrimitiveDescriptor.enumerable is true
+PASS symbolToPrimitiveDescriptor.configurable is true
+
+PASS object[Symbol.toPrimitive] is 123
+
+ObjcFallbackObjectImp
+
+PASS '' + fallbackObject is 'undefined'
+PASS +fallbackObject is NaN
+PASS `${fallbackObject}` is 'undefined'
+
+PASS fallbackObject[Symbol.toPrimitive].length is 0
+PASS fallbackObject[Symbol.toPrimitive]() is undefined
+PASS fallbackObject[Symbol.toPrimitive]('foo') is undefined
+PASS fallbackObject[Symbol.toPrimitive].call({}) threw exception TypeError: ObjcFallbackObject[Symbol.toPrimitive] method called on incompatible |this| value..
+PASS (0, fallbackObject[Symbol.toPrimitive])() threw exception TypeError: ObjcFallbackObject[Symbol.toPrimitive] method called on incompatible |this| value..
+
+ObjcFallbackObjectImp (redefined Symbol.toPrimitive)
+
+PASS typeof symbolToPrimitiveDescriptor is 'object'
+PASS symbolToPrimitiveDescriptor.value is object[Symbol.toPrimitive]
+PASS symbolToPrimitiveDescriptor.writable is true
+PASS symbolToPrimitiveDescriptor.enumerable is false
+PASS symbolToPrimitiveDescriptor.configurable is true
+
+PASS object[Symbol.toPrimitive]() is 'bar'
+PASS typeof symbolToPrimitiveDescriptor is 'object'
+PASS symbolToPrimitiveDescriptor.value is newToPrimitive
+PASS symbolToPrimitiveDescriptor.writable is false
+PASS symbolToPrimitiveDescriptor.enumerable is true
+PASS symbolToPrimitiveDescriptor.configurable is true
+
+PASS object[Symbol.toPrimitive] is 123
+
Added: trunk/LayoutTests/platform/mac/fast/dom/objc-wrapper-toprimitive.html (0 => 276660)
--- trunk/LayoutTests/platform/mac/fast/dom/objc-wrapper-toprimitive.html (rev 0)
+++ trunk/LayoutTests/platform/mac/fast/dom/objc-wrapper-toprimitive.html 2021-04-27 20:56:19 UTC (rev 276660)
@@ -0,0 +1,88 @@
+<!DOCTYPE html>
+<script src=""
+<body>
+<p id="description"></p>
+<div id="console"></div>
+<script>
+if (window.testRunner)
+ testRunner.waitUntilDone();
+
+function runTest()
+{
+ description("This tests ToPrimitive performed on Objective-C wrapper object.");
+ if (!window.objCController) {
+ testFailed("window.objCController does not exist. Run with --dump-render-tree.");
+ return;
+ }
+
+ debug("RuntimeObject\n");
+
+ shouldBe("'' + objCController", "'<ObjCController>'");
+ shouldBe("+objCController", "0");
+ shouldBe("`${objCController}`", "'<ObjCController>'");
+
+ debug("");
+ shouldBe("objCController[Symbol.toPrimitive].length", "1");
+ shouldBe("objCController[Symbol.toPrimitive]('default')", "'<ObjCController>'");
+ shouldBe("objCController[Symbol.toPrimitive]('number')", "0");
+ shouldBe("objCController[Symbol.toPrimitive]('string')", "'<ObjCController>'");
+ shouldThrow("objCController[Symbol.toPrimitive]('foo')");
+ shouldThrow("objCController[Symbol.toPrimitive].call({}, 'default')");
+ shouldThrow("(0, objCController[Symbol.toPrimitive])()");
+
+ debug("\nRuntimeObject (redefined Symbol.toPrimitive)\n");
+ testDefineOwnProperty(objCController);
+
+ debug("\nObjcFallbackObjectImp\n");
+
+ fallbackObject = objCController.undefinedKey;
+
+ shouldBe("'' + fallbackObject", "'undefined'");
+ shouldBe("+fallbackObject", "NaN");
+ shouldBe("`${fallbackObject}`", "'undefined'");
+
+ debug("");
+ shouldBe("fallbackObject[Symbol.toPrimitive].length", "0");
+ shouldBe("fallbackObject[Symbol.toPrimitive]()", "undefined");
+ shouldBe("fallbackObject[Symbol.toPrimitive]('foo')", "undefined");
+ shouldThrow("fallbackObject[Symbol.toPrimitive].call({})");
+ shouldThrow("(0, fallbackObject[Symbol.toPrimitive])()");
+
+ debug("\nObjcFallbackObjectImp (redefined Symbol.toPrimitive)\n");
+ testDefineOwnProperty(fallbackObject);
+
+ if (window.testRunner)
+ testRunner.notifyDone();
+}
+
+function testDefineOwnProperty(_object)
+{
+ object = _object;
+
+ symbolToPrimitiveDescriptor = Object.getOwnPropertyDescriptor(object, Symbol.toPrimitive);
+ shouldBe("typeof symbolToPrimitiveDescriptor", "'object'");
+ shouldBe("symbolToPrimitiveDescriptor.value", "object[Symbol.toPrimitive]");
+ shouldBe("symbolToPrimitiveDescriptor.writable", "true");
+ shouldBe("symbolToPrimitiveDescriptor.enumerable", "false");
+ shouldBe("symbolToPrimitiveDescriptor.configurable", "true");
+
+ debug("");
+ newToPrimitive = () => "bar";
+ Object.defineProperty(object, Symbol.toPrimitive, { value: newToPrimitive, writable: false, enumerable: true });
+ shouldBe("object[Symbol.toPrimitive]()", "'bar'");
+
+ symbolToPrimitiveDescriptor = Object.getOwnPropertyDescriptor(object, Symbol.toPrimitive);
+ shouldBe("typeof symbolToPrimitiveDescriptor", "'object'");
+ shouldBe("symbolToPrimitiveDescriptor.value", "newToPrimitive");
+ shouldBe("symbolToPrimitiveDescriptor.writable", "false");
+ shouldBe("symbolToPrimitiveDescriptor.enumerable", "true");
+ shouldBe("symbolToPrimitiveDescriptor.configurable", "true");
+
+ debug("");
+ Object.defineProperty(object, Symbol.toPrimitive, { get: () => 123 });
+ shouldBe("object[Symbol.toPrimitive]", "123");
+}
+
+window._onload_ = runTest;
+</script>
+</body>
Modified: trunk/LayoutTests/platform/wk2/TestExpectations (276659 => 276660)
--- trunk/LayoutTests/platform/wk2/TestExpectations 2021-04-27 20:55:02 UTC (rev 276659)
+++ trunk/LayoutTests/platform/wk2/TestExpectations 2021-04-27 20:56:19 UTC (rev 276660)
@@ -557,6 +557,7 @@
# WebKitTestRunner doesn't have objCController
platform/mac/fast/dom/objc-wrapper-identity.html
+platform/mac/fast/dom/objc-wrapper-toprimitive.html
platform/mac/fast/dom/wrapper-classes-objc.html
platform/mac/fast/dom/wrapper-round-tripping.html
platform/mac/fast/objc/dom-html-select-activate.html
Modified: trunk/LayoutTests/plugins/npruntime/tostring-expected.txt (276659 => 276660)
--- trunk/LayoutTests/plugins/npruntime/tostring-expected.txt 2021-04-27 20:55:02 UTC (rev 276659)
+++ trunk/LayoutTests/plugins/npruntime/tostring-expected.txt 2021-04-27 20:56:19 UTC (rev 276660)
@@ -3,6 +3,7 @@
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+PASS plugin[Symbol.toPrimitive] is undefined
PASS plugin.toString() is "TestObject"
PASS [plugin, ''].join('') is "TestObject"
PASS successfullyParsed is true
Modified: trunk/LayoutTests/plugins/npruntime/tostring.html (276659 => 276660)
--- trunk/LayoutTests/plugins/npruntime/tostring.html 2021-04-27 20:55:02 UTC (rev 276659)
+++ trunk/LayoutTests/plugins/npruntime/tostring.html 2021-04-27 20:56:19 UTC (rev 276660)
@@ -14,6 +14,7 @@
plugin.setAttribute('test', 'to-string-and-value-of-object');
document.body.appendChild(plugin);
+ shouldBe("plugin[Symbol.toPrimitive]", "undefined");
shouldBeEqualToString("plugin.toString()", "TestObject");
// Normal plugin.testObject + "" will call valueOf,
// do some tricks to make a call to implicit toString.
Modified: trunk/LayoutTests/plugins/npruntime/valueof-expected.txt (276659 => 276660)
--- trunk/LayoutTests/plugins/npruntime/valueof-expected.txt 2021-04-27 20:55:02 UTC (rev 276659)
+++ trunk/LayoutTests/plugins/npruntime/valueof-expected.txt 2021-04-27 20:56:19 UTC (rev 276660)
@@ -3,6 +3,7 @@
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+PASS plugin[Symbol.toPrimitive] is undefined
PASS plugin.valueOf() is 123456789
PASS plugin == 123456789 is true
PASS successfullyParsed is true
Modified: trunk/LayoutTests/plugins/npruntime/valueof.html (276659 => 276660)
--- trunk/LayoutTests/plugins/npruntime/valueof.html 2021-04-27 20:55:02 UTC (rev 276659)
+++ trunk/LayoutTests/plugins/npruntime/valueof.html 2021-04-27 20:56:19 UTC (rev 276660)
@@ -14,6 +14,7 @@
plugin.setAttribute('test', 'to-string-and-value-of-object');
document.body.appendChild(plugin);
+ shouldBe("plugin[Symbol.toPrimitive]", "undefined");
shouldBe("plugin.valueOf()", "123456789");
shouldBeTrue("plugin == 123456789");
var successfullyParsed = true;
Modified: trunk/Source/_javascript_Core/API/JSCallbackObject.h (276659 => 276660)
--- trunk/Source/_javascript_Core/API/JSCallbackObject.h 2021-04-27 20:55:02 UTC (rev 276659)
+++ trunk/Source/_javascript_Core/API/JSCallbackObject.h 2021-04-27 20:56:19 UTC (rev 276660)
@@ -199,7 +199,7 @@
void finishCreation(VM&);
static IsoSubspace* subspaceForImpl(VM&, SubspaceAccess);
- static JSValue defaultValue(const JSObject*, JSGlobalObject*, PreferredPrimitiveType);
+ static JSC_HOST_CALL_ATTRIBUTES EncodedJSValue customToPrimitive(JSGlobalObject*, CallFrame*);
static bool getOwnPropertySlot(JSObject*, JSGlobalObject*, PropertyName, PropertySlot&);
static bool getOwnPropertySlotByIndex(JSObject*, JSGlobalObject*, unsigned propertyName, PropertySlot&);
Modified: trunk/Source/_javascript_Core/API/JSCallbackObjectFunctions.h (276659 => 276660)
--- trunk/Source/_javascript_Core/API/JSCallbackObjectFunctions.h 2021-04-27 20:55:02 UTC (rev 276659)
+++ trunk/Source/_javascript_Core/API/JSCallbackObjectFunctions.h 2021-04-27 20:56:19 UTC (rev 276660)
@@ -112,13 +112,23 @@
void JSCallbackObject<Parent>::init(JSGlobalObject* globalObject)
{
ASSERT(globalObject);
+ VM& vm = getVM(globalObject);
+ bool hasConvertToType = false;
Vector<JSObjectInitializeCallback, 16> initRoutines;
JSClassRef jsClass = classRef();
do {
+ if (jsClass->convertToType)
+ hasConvertToType = true;
if (JSObjectInitializeCallback initialize = jsClass->initialize)
initRoutines.append(initialize);
} while ((jsClass = jsClass->parentClass));
+
+ if (hasConvertToType) {
+ this->putDirect(vm, vm.propertyNames->toPrimitiveSymbol,
+ JSFunction::create(vm, globalObject, 1, "[Symbol.toPrimitive]"_s, customToPrimitive),
+ static_cast<unsigned>(PropertyAttribute::DontEnum));
+ }
// initialize from base to derived
for (int i = static_cast<int>(initRoutines.size()) - 1; i >= 0; i--) {
@@ -217,12 +227,17 @@
}
template <class Parent>
-JSValue JSCallbackObject<Parent>::defaultValue(const JSObject* object, JSGlobalObject* globalObject, PreferredPrimitiveType hint)
+EncodedJSValue JSCallbackObject<Parent>::customToPrimitive(JSGlobalObject* globalObject, CallFrame* callFrame)
{
VM& vm = getVM(globalObject);
auto scope = DECLARE_THROW_SCOPE(vm);
- const JSCallbackObject* thisObject = jsCast<const JSCallbackObject*>(object);
+ JSCallbackObject* thisObject = jsDynamicCast<JSCallbackObject*>(vm, callFrame->thisValue());
+ if (!thisObject)
+ return throwVMTypeError(globalObject, scope, "JSCallbackObject[Symbol.toPrimitive] method called on incompatible |this| value."_s);
+ PreferredPrimitiveType hint = toPreferredPrimitiveType(globalObject, callFrame->argument(0));
+ RETURN_IF_EXCEPTION(scope, { });
+
JSContextRef ctx = toRef(globalObject);
JSObjectRef thisRef = toRef(jsCast<const JSObject*>(thisObject));
::JSType jsHint = hint == PreferString ? kJSTypeString : kJSTypeNumber;
@@ -231,16 +246,18 @@
if (JSObjectConvertToTypeCallback convertToType = jsClass->convertToType) {
JSValueRef exception = nullptr;
JSValueRef result = convertToType(ctx, thisRef, jsHint, &exception);
- if (exception) {
- throwException(globalObject, scope, toJS(globalObject, exception));
- return jsUndefined();
+ if (exception)
+ return throwVMError(globalObject, scope, toJS(globalObject, exception));
+ if (result) {
+ JSValue jsResult = toJS(globalObject, result);
+ if (UNLIKELY(jsResult.isObject()))
+ return JSValue::encode(asObject(jsResult)->ordinaryToPrimitive(globalObject, hint));
+ return JSValue::encode(jsResult);
}
- if (result)
- return toJS(globalObject, result);
}
}
- RELEASE_AND_RETURN(scope, Parent::defaultValue(object, globalObject, hint));
+ RELEASE_AND_RETURN(scope, JSValue::encode(thisObject->ordinaryToPrimitive(globalObject, hint)));
}
template <class Parent>
Modified: trunk/Source/_javascript_Core/API/tests/testapiScripts/testapi.js (276659 => 276660)
--- trunk/Source/_javascript_Core/API/tests/testapiScripts/testapi.js 2021-04-27 20:55:02 UTC (rev 276659)
+++ trunk/Source/_javascript_Core/API/tests/testapiScripts/testapi.js 2021-04-27 20:56:19 UTC (rev 276660)
@@ -228,6 +228,24 @@
shouldBe("globalObjectHeirGlobalStaticValue2Descriptor.configurable", true);
shouldBe("this.globalStaticValue2", 3);
+var symbolToPrimitiveDescriptor = Object.getOwnPropertyDescriptor(MyObject, Symbol.toPrimitive);
+shouldBe("typeof symbolToPrimitiveDescriptor", "object");
+shouldBe("symbolToPrimitiveDescriptor.value", MyObject[Symbol.toPrimitive]);
+shouldBe("symbolToPrimitiveDescriptor.writable", true);
+shouldBe("symbolToPrimitiveDescriptor.enumerable", false);
+shouldBe("symbolToPrimitiveDescriptor.configurable", true);
+
+shouldBe("MyObject[Symbol.toPrimitive]('default')", 1);
+shouldBe("MyObject[Symbol.toPrimitive]('number')", 1);
+shouldBe("MyObject[Symbol.toPrimitive]('string')", "MyObjectAsString");
+
+shouldThrow("MyObject[Symbol.toPrimitive]('foo')");
+shouldThrow("MyObject[Symbol.toPrimitive].call({}, 'default')");
+shouldThrow("(0, MyObject[Symbol.toPrimitive])('default')");
+
+MyObject[Symbol.toPrimitive] = () => null;
+shouldBe("MyObject[Symbol.toPrimitive]('bar')", null);
+
derived = new Derived();
shouldBe("derived instanceof Derived", true);
@@ -307,6 +325,11 @@
EvilExceptionObject.toStringExplicit = function f() { return f(); }
shouldThrow("String(EvilExceptionObject)");
+EvilExceptionObject.toNumber = () => ({ valueOf: () => 4815 });
+shouldBe("Number(EvilExceptionObject)", 4815);
+EvilExceptionObject.toStringExplicit = () => ({ toString: () => "foobar" });
+shouldBe("`${EvilExceptionObject}`", "foobar");
+
shouldBe("console", "[object console]");
shouldBe("typeof console.log", "function");
Modified: trunk/Source/_javascript_Core/ChangeLog (276659 => 276660)
--- trunk/Source/_javascript_Core/ChangeLog 2021-04-27 20:55:02 UTC (rev 276659)
+++ trunk/Source/_javascript_Core/ChangeLog 2021-04-27 20:56:19 UTC (rev 276660)
@@ -1,3 +1,45 @@
+2021-04-27 Alexey Shvayka <[email protected]>
+
+ [JSC] Remove defaultValue() from the method table
+ https://bugs.webkit.org/show_bug.cgi?id=225032
+
+ Reviewed by Darin Adler.
+
+ This patch not only removes the unnecessary method table entry, but also makes
+ the presence of custom ToPrimitive behavior observable to userland code.
+
+ To maintain object identity and (possibly) enable caching, Symbol.toPrimitive
+ method is stored on a structure. To avoid any potential breakage, it's made
+ replaceable and configurable, covering the case when its holder is a [[ProxyTarget]].
+
+ For JSCallbackObject, Symbol.toPrimitive method is created only if ConvertToType
+ callback is present, before initialization is performed.
+
+ Also, this change adds additional ordinaryToPrimitive() cast to fix the invariant
+ that toPrimitive() returns a primitive value, which was broken if ConvertToType
+ callback returned an object. The invariant is enforced by the spec [1][2] and is
+ validated via assertion in JSValue::toStringSlowCase().
+
+ [1]: https://tc39.es/ecma262/#sec-toprimitive (step 2.b.vi)
+ [2]: https://tc39.es/ecma262/#sec-ordinarytoprimitive (step 6)
+
+ * API/JSCallbackObject.h:
+ * API/JSCallbackObjectFunctions.h:
+ (JSC::JSCallbackObject<Parent>::init):
+ (JSC::JSCallbackObject<Parent>::customToPrimitive):
+ (JSC::JSCallbackObject<Parent>::defaultValue): Deleted.
+ * API/tests/testapiScripts/testapi.js:
+ * runtime/ClassInfo.h:
+ * runtime/JSCell.cpp:
+ (JSC::JSCell::defaultValue): Deleted.
+ * runtime/JSCell.h:
+ * runtime/JSObject.cpp:
+ (JSC::JSObject::toPrimitive const):
+ (JSC::JSObject::defaultValue): Deleted.
+ * runtime/JSObject.h:
+ * runtime/Operations.cpp:
+ (JSC::jsAddSlowCase):
+
2021-04-27 Keith Miller <[email protected]>
StructureStubInfo and PolymorphicAccess should account for their non-GC memory
Modified: trunk/Source/_javascript_Core/runtime/ClassInfo.h (276659 => 276660)
--- trunk/Source/_javascript_Core/runtime/ClassInfo.h 2021-04-27 20:55:02 UTC (rev 276659)
+++ trunk/Source/_javascript_Core/runtime/ClassInfo.h 2021-04-27 20:56:19 UTC (rev 276660)
@@ -71,9 +71,6 @@
using ToThisFunctionPtr = JSValue (*)(JSCell*, JSGlobalObject*, ECMAMode);
ToThisFunctionPtr METHOD_TABLE_ENTRY(toThis);
- using DefaultValueFunctionPtr = JSValue (*)(const JSObject*, JSGlobalObject*, PreferredPrimitiveType);
- DefaultValueFunctionPtr METHOD_TABLE_ENTRY(defaultValue);
-
using GetOwnPropertyNamesFunctionPtr = void (*)(JSObject*, JSGlobalObject*, PropertyNameArray&, DontEnumPropertiesMode);
GetOwnPropertyNamesFunctionPtr METHOD_TABLE_ENTRY(getOwnPropertyNames);
GetOwnPropertyNamesFunctionPtr METHOD_TABLE_ENTRY(getOwnSpecialPropertyNames);
@@ -156,7 +153,6 @@
&ClassName::getOwnPropertySlot, \
&ClassName::getOwnPropertySlotByIndex, \
&ClassName::toThis, \
- &ClassName::defaultValue, \
&ClassName::getOwnPropertyNames, \
&ClassName::getOwnSpecialPropertyNames, \
&ClassName::customHasInstance, \
Modified: trunk/Source/_javascript_Core/runtime/JSCell.cpp (276659 => 276660)
--- trunk/Source/_javascript_Core/runtime/JSCell.cpp 2021-04-27 20:55:02 UTC (rev 276659)
+++ trunk/Source/_javascript_Core/runtime/JSCell.cpp 2021-04-27 20:56:19 UTC (rev 276660)
@@ -183,12 +183,6 @@
ASSERT_GC_OBJECT_LOOKS_VALID(cell);
}
-JSValue JSCell::defaultValue(const JSObject*, JSGlobalObject*, PreferredPrimitiveType)
-{
- RELEASE_ASSERT_NOT_REACHED();
- return jsUndefined();
-}
-
bool JSCell::getOwnPropertySlot(JSObject*, JSGlobalObject*, PropertyName, PropertySlot&)
{
RELEASE_ASSERT_NOT_REACHED();
Modified: trunk/Source/_javascript_Core/runtime/JSCell.h (276659 => 276660)
--- trunk/Source/_javascript_Core/runtime/JSCell.h 2021-04-27 20:55:02 UTC (rev 276659)
+++ trunk/Source/_javascript_Core/runtime/JSCell.h 2021-04-27 20:56:19 UTC (rev 276660)
@@ -244,7 +244,6 @@
void finishCreation(VM&, Structure*, CreatingEarlyCellTag);
// Dummy implementations of override-able static functions for classes to put in their MethodTable
- static JSValue defaultValue(const JSObject*, JSGlobalObject*, PreferredPrimitiveType);
static NO_RETURN_DUE_TO_CRASH void getOwnPropertyNames(JSObject*, JSGlobalObject*, PropertyNameArray&, DontEnumPropertiesMode);
static NO_RETURN_DUE_TO_CRASH void getOwnSpecialPropertyNames(JSObject*, JSGlobalObject*, PropertyNameArray&, DontEnumPropertiesMode);
Modified: trunk/Source/_javascript_Core/runtime/JSObject.cpp (276659 => 276660)
--- trunk/Source/_javascript_Core/runtime/JSObject.cpp 2021-04-27 20:55:02 UTC (rev 276659)
+++ trunk/Source/_javascript_Core/runtime/JSObject.cpp 2021-04-27 20:56:19 UTC (rev 276660)
@@ -2310,11 +2310,6 @@
return throwTypeError(globalObject, scope, "No default value"_s);
}
-JSValue JSObject::defaultValue(const JSObject* object, JSGlobalObject* globalObject, PreferredPrimitiveType hint)
-{
- return object->ordinaryToPrimitive(globalObject, hint);
-}
-
JSValue JSObject::toPrimitive(JSGlobalObject* globalObject, PreferredPrimitiveType preferredType) const
{
VM& vm = globalObject->vm();
@@ -2325,7 +2320,7 @@
if (value)
return value;
- RELEASE_AND_RETURN(scope, this->methodTable(vm)->defaultValue(this, globalObject, preferredType));
+ RELEASE_AND_RETURN(scope, ordinaryToPrimitive(globalObject, preferredType));
}
bool JSObject::getOwnStaticPropertySlot(VM& vm, PropertyName propertyName, PropertySlot& slot)
Modified: trunk/Source/_javascript_Core/runtime/JSObject.h (276659 => 276660)
--- trunk/Source/_javascript_Core/runtime/JSObject.h 2021-04-27 20:55:02 UTC (rev 276659)
+++ trunk/Source/_javascript_Core/runtime/JSObject.h 2021-04-27 20:56:19 UTC (rev 276660)
@@ -664,7 +664,6 @@
bool deleteProperty(JSGlobalObject*, uint32_t propertyName);
bool deleteProperty(JSGlobalObject*, uint64_t propertyName);
- JS_EXPORT_PRIVATE static JSValue defaultValue(const JSObject*, JSGlobalObject*, PreferredPrimitiveType);
JSValue ordinaryToPrimitive(JSGlobalObject*, PreferredPrimitiveType) const;
JS_EXPORT_PRIVATE bool hasInstance(JSGlobalObject*, JSValue value, JSValue hasInstanceValue);
Modified: trunk/Source/_javascript_Core/runtime/Operations.cpp (276659 => 276660)
--- trunk/Source/_javascript_Core/runtime/Operations.cpp 2021-04-27 20:55:02 UTC (rev 276659)
+++ trunk/Source/_javascript_Core/runtime/Operations.cpp 2021-04-27 20:56:19 UTC (rev 276660)
@@ -34,7 +34,6 @@
NEVER_INLINE JSValue jsAddSlowCase(JSGlobalObject* globalObject, JSValue v1, JSValue v2)
{
- // exception for the Date exception in defaultValue()
VM& vm = globalObject->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
JSValue p1 = v1.toPrimitive(globalObject);
Modified: trunk/Source/WebCore/ChangeLog (276659 => 276660)
--- trunk/Source/WebCore/ChangeLog 2021-04-27 20:55:02 UTC (rev 276659)
+++ trunk/Source/WebCore/ChangeLog 2021-04-27 20:56:19 UTC (rev 276660)
@@ -1,3 +1,27 @@
+2021-04-27 Alexey Shvayka <[email protected]>
+
+ [JSC] Remove defaultValue() from the method table
+ https://bugs.webkit.org/show_bug.cgi?id=225032
+
+ Reviewed by Darin Adler.
+
+ Test: platform/mac/fast/dom/objc-wrapper-toprimitive.html
+
+ * bindings/js/JSPluginElementFunctions.cpp:
+ (WebCore::pluginElementCustomGetOwnPropertySlot):
+ * bridge/objc/objc_runtime.h:
+ * bridge/objc/objc_runtime.mm:
+ (JSC::Bindings::ObjcFallbackObjectImp::finishCreation):
+ (JSC::Bindings::ObjcFallbackObjectImp::getOwnPropertySlot):
+ (JSC::Bindings::JSC_DEFINE_HOST_FUNCTION):
+ (JSC::Bindings::ObjcFallbackObjectImp::defaultValue): Deleted.
+ * bridge/runtime_object.cpp:
+ (JSC::Bindings::RuntimeObject::finishCreation):
+ (JSC::Bindings::RuntimeObject::getOwnPropertySlot):
+ (JSC::Bindings::JSC_DEFINE_HOST_FUNCTION):
+ (JSC::Bindings::RuntimeObject::defaultValue): Deleted.
+ * bridge/runtime_object.h:
+
2021-04-27 Chris Dumez <[email protected]>
Copy-on-write semantics should be an internal implementation detail of StorageMap
Modified: trunk/Source/WebCore/bindings/js/JSPluginElementFunctions.cpp (276659 => 276660)
--- trunk/Source/WebCore/bindings/js/JSPluginElementFunctions.cpp 2021-04-27 20:55:02 UTC (rev 276659)
+++ trunk/Source/WebCore/bindings/js/JSPluginElementFunctions.cpp 2021-04-27 20:56:19 UTC (rev 276660)
@@ -114,10 +114,14 @@
bool pluginElementCustomGetOwnPropertySlot(JSHTMLElement* element, JSGlobalObject* lexicalGlobalObject, PropertyName propertyName, PropertySlot& slot)
{
+ VM& vm = lexicalGlobalObject->vm();
slot.setIsTaintedByOpaqueObject();
+ if (propertyName.uid() == vm.propertyNames->toPrimitiveSymbol.impl())
+ return false;
+
if (!element->globalObject()->world().isNormal()) {
- JSC::JSValue proto = element->getPrototypeDirect(lexicalGlobalObject->vm());
+ JSValue proto = element->getPrototypeDirect(vm);
if (proto.isObject() && JSC::jsCast<JSC::JSObject*>(asObject(proto))->hasProperty(lexicalGlobalObject, propertyName))
return false;
}
Modified: trunk/Source/WebCore/bridge/objc/objc_runtime.h (276659 => 276660)
--- trunk/Source/WebCore/bridge/objc/objc_runtime.h 2021-04-27 20:55:02 UTC (rev 276659)
+++ trunk/Source/WebCore/bridge/objc/objc_runtime.h 2021-04-27 20:56:19 UTC (rev 276660)
@@ -124,6 +124,8 @@
return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
}
+ ObjcInstance* getInternalObjCInstance() const { return _instance.get(); }
+
private:
ObjcFallbackObjectImp(JSGlobalObject*, Structure*, ObjcInstance*, const String& propertyName);
void finishCreation(JSGlobalObject*);
@@ -133,7 +135,6 @@
static bool put(JSCell*, JSGlobalObject*, PropertyName, JSValue, PutPropertySlot&);
static CallData getCallData(JSCell*);
static bool deleteProperty(JSCell*, JSGlobalObject*, PropertyName, DeletePropertySlot&);
- static JSValue defaultValue(const JSObject*, JSGlobalObject*, PreferredPrimitiveType);
bool toBoolean(JSGlobalObject*) const; // FIXME: Currently this is broken because none of the superclasses are marked virtual. We need to solve this in the longer term.
Modified: trunk/Source/WebCore/bridge/objc/objc_runtime.mm (276659 => 276660)
--- trunk/Source/WebCore/bridge/objc/objc_runtime.mm 2021-04-27 20:55:02 UTC (rev 276659)
+++ trunk/Source/WebCore/bridge/objc/objc_runtime.mm 2021-04-27 20:56:19 UTC (rev 276660)
@@ -45,6 +45,8 @@
namespace JSC {
namespace Bindings {
+static JSC_DECLARE_HOST_FUNCTION(convertObjCFallbackObjectToPrimitive);
+
ClassStructPtr webScriptObjectClass()
{
static ClassStructPtr<WebScriptObject> webScriptObjectClass = NSClassFromString(@"WebScriptObject");
@@ -232,10 +234,16 @@
VM& vm = globalObject->vm();
Base::finishCreation(vm);
ASSERT(inherits(vm, info()));
+ putDirect(vm, vm.propertyNames->toPrimitiveSymbol,
+ JSFunction::create(vm, globalObject, 0, "[Symbol.toPrimitive]"_s, convertObjCFallbackObjectToPrimitive),
+ static_cast<unsigned>(PropertyAttribute::DontEnum));
}
-bool ObjcFallbackObjectImp::getOwnPropertySlot(JSObject*, JSGlobalObject*, PropertyName, PropertySlot& slot)
+bool ObjcFallbackObjectImp::getOwnPropertySlot(JSObject* object, JSGlobalObject* globalObject, PropertyName propertyName, PropertySlot& slot)
{
+ VM& vm = globalObject->vm();
+ if (propertyName.uid() == vm.propertyNames->toPrimitiveSymbol.impl())
+ return JSObject::getOwnPropertySlot(object, globalObject, propertyName, slot);
// keep the prototype from getting called instead of just returning false
slot.setUndefined();
return true;
@@ -301,11 +309,17 @@
return false;
}
-JSValue ObjcFallbackObjectImp::defaultValue(const JSObject* object, JSGlobalObject* lexicalGlobalObject, PreferredPrimitiveType)
+JSC_DEFINE_HOST_FUNCTION(convertObjCFallbackObjectToPrimitive, (JSGlobalObject* lexicalGlobalObject, CallFrame* callFrame))
{
VM& vm = lexicalGlobalObject->vm();
- const ObjcFallbackObjectImp* thisObject = jsCast<const ObjcFallbackObjectImp*>(object);
- return thisObject->_instance->getValueOfUndefinedField(lexicalGlobalObject, Identifier::fromString(vm, thisObject->m_item));
+ auto scope = DECLARE_THROW_SCOPE(vm);
+
+ auto* thisObject = jsDynamicCast<ObjcFallbackObjectImp*>(vm, callFrame->thisValue());
+ if (!thisObject)
+ return throwVMTypeError(lexicalGlobalObject, scope, "ObjcFallbackObject[Symbol.toPrimitive] method called on incompatible |this| value."_s);
+
+ scope.release();
+ return JSValue::encode(thisObject->getInternalObjCInstance()->getValueOfUndefinedField(lexicalGlobalObject, Identifier::fromString(vm, thisObject->propertyName())));
}
bool ObjcFallbackObjectImp::toBoolean(JSGlobalObject*) const
Modified: trunk/Source/WebCore/bridge/runtime_object.cpp (276659 => 276660)
--- trunk/Source/WebCore/bridge/runtime_object.cpp 2021-04-27 20:55:02 UTC (rev 276659)
+++ trunk/Source/WebCore/bridge/runtime_object.cpp 2021-04-27 20:56:19 UTC (rev 276660)
@@ -38,6 +38,7 @@
WEBCORE_EXPORT const ClassInfo RuntimeObject::s_info = { "RuntimeObject", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(RuntimeObject) };
+static JSC_DECLARE_HOST_FUNCTION(convertRuntimeObjectToPrimitive);
static JSC_DECLARE_HOST_FUNCTION(callRuntimeObject);
static JSC_DECLARE_HOST_FUNCTION(callRuntimeConstructor);
@@ -55,6 +56,9 @@
{
Base::finishCreation(vm);
ASSERT(inherits(vm, info()));
+ putDirect(vm, vm.propertyNames->toPrimitiveSymbol,
+ JSFunction::create(vm, globalObject(vm), 1, "[Symbol.toPrimitive]"_s, convertRuntimeObjectToPrimitive),
+ static_cast<unsigned>(PropertyAttribute::DontEnum));
}
void RuntimeObject::destroy(JSCell* cell)
@@ -143,6 +147,9 @@
throwRuntimeObjectInvalidAccessError(lexicalGlobalObject, scope);
return false;
}
+
+ if (propertyName.uid() == vm.propertyNames->toPrimitiveSymbol.impl())
+ return JSObject::getOwnPropertySlot(thisObject, lexicalGlobalObject, propertyName, slot);
RefPtr<Instance> instance = thisObject->m_instance;
@@ -213,21 +220,24 @@
return false;
}
-JSValue RuntimeObject::defaultValue(const JSObject* object, JSGlobalObject* lexicalGlobalObject, PreferredPrimitiveType hint)
+JSC_DEFINE_HOST_FUNCTION(convertRuntimeObjectToPrimitive, (JSGlobalObject* lexicalGlobalObject, CallFrame* callFrame))
{
VM& vm = lexicalGlobalObject->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
- const RuntimeObject* thisObject = jsCast<const RuntimeObject*>(object);
- if (!thisObject->m_instance)
- return throwRuntimeObjectInvalidAccessError(lexicalGlobalObject, scope);
-
- RefPtr<Instance> instance = thisObject->m_instance;
+ auto* thisObject = jsDynamicCast<RuntimeObject*>(vm, callFrame->thisValue());
+ if (!thisObject)
+ return throwVMTypeError(lexicalGlobalObject, scope, "RuntimeObject[Symbol.toPrimitive] method called on incompatible |this| value."_s);
+ auto instance = makeRefPtr(thisObject->getInternalInstance());
+ if (!instance)
+ return JSValue::encode(throwRuntimeObjectInvalidAccessError(lexicalGlobalObject, scope));
+ auto hint = toPreferredPrimitiveType(lexicalGlobalObject, callFrame->argument(0));
+ RETURN_IF_EXCEPTION(scope, { });
instance->begin();
JSValue result = instance->defaultValue(lexicalGlobalObject, hint);
instance->end();
- return result;
+ return JSValue::encode(result);
}
JSC_DEFINE_HOST_FUNCTION(callRuntimeObject, (JSGlobalObject* globalObject, CallFrame* callFrame))
Modified: trunk/Source/WebCore/bridge/runtime_object.h (276659 => 276660)
--- trunk/Source/WebCore/bridge/runtime_object.h 2021-04-27 20:55:02 UTC (rev 276659)
+++ trunk/Source/WebCore/bridge/runtime_object.h 2021-04-27 20:56:19 UTC (rev 276660)
@@ -60,7 +60,6 @@
static bool getOwnPropertySlot(JSObject*, JSGlobalObject*, PropertyName, PropertySlot&);
static bool put(JSCell*, JSGlobalObject*, PropertyName, JSValue, PutPropertySlot&);
static bool deleteProperty(JSCell*, JSGlobalObject*, PropertyName, DeletePropertySlot&);
- static JSValue defaultValue(const JSObject*, JSGlobalObject*, PreferredPrimitiveType);
static CallData getCallData(JSCell*);
static CallData getConstructData(JSCell*);