WebKit Bugzilla
New
Browse
Log In
×
Sign in with GitHub
or
Remember my login
Create Account
·
Forgot Password
Forgotten password account recovery
RESOLVED FIXED
168295
Expose Symbol.toPrimitive / valueOf on Location instances
https://bugs.webkit.org/show_bug.cgi?id=168295
Summary
Expose Symbol.toPrimitive / valueOf on Location instances
Anne van Kesteren
Reported
2017-02-14 01:06:06 PST
Test:
http://web-platform.test:8000/html/browsers/history/the-location-interface/location-symbol-toprimitive.html
.
Attachments
Patch
(7.95 KB, patch)
2017-02-14 10:20 PST
,
Chris Dumez
no flags
Details
Formatted Diff
Diff
Patch
(15.37 KB, patch)
2017-02-14 13:28 PST
,
Chris Dumez
no flags
Details
Formatted Diff
Diff
Patch
(15.96 KB, patch)
2017-02-14 13:52 PST
,
Chris Dumez
no flags
Details
Formatted Diff
Diff
Patch
(16.00 KB, patch)
2017-02-14 14:00 PST
,
Chris Dumez
no flags
Details
Formatted Diff
Diff
Show Obsolete
(3)
View All
Add attachment
proposed patch, testcase, etc.
Anne van Kesteren
Comment 1
2017-02-14 01:11:12 PST
The same goes for valueOf:
http://web-platform.test:8000/html/browsers/history/the-location-interface/location-valueof.html
. (Let me know if you need a separate bug.)
Chris Dumez
Comment 2
2017-02-14 08:42:50 PST
To create a Location object, run these steps: Let location be a new Location platform object. Perform ! location.[[DefineOwnProperty]]("valueOf", { [[Value]]: %ObjProto_valueOf%, [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: false }). Perform ! location.[[DefineOwnProperty]](@@toPrimitive, { [[Value]]: undefined, [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: false }). Set the value of the [[DefaultProperties]] internal slot of location to location.[[OwnPropertyKeys]](). Return location.
Chris Dumez
Comment 3
2017-02-14 08:43:20 PST
Will take a look soon.
Chris Dumez
Comment 4
2017-02-14 10:20:37 PST
Created
attachment 301516
[details]
Patch
Darin Adler
Comment 5
2017-02-14 10:58:34 PST
Comment on
attachment 301516
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=301516&action=review
> Source/WebCore/bindings/scripts/CodeGeneratorJS.pm:3430 > + push(@implContent, " auto objProtoValueOf = globalObject()->objectPrototype()->getDirect(vm, vm.propertyNames->valueOf);\n");
Please just spell out "object" instead of using "obj".
> Source/WebCore/bindings/scripts/CodeGeneratorJS.pm:3432 > + push(@implContent, " putDirect(vm, vm.propertyNames->valueOf, objProtoValueOf, DontDelete | ReadOnly | DontEnum);\n");
Is this correct if the object prototype valueOf property’s value changes after creating the Location interface? Do we have test cases covered?
Geoffrey Garen
Comment 6
2017-02-14 11:02:13 PST
> Source/WebCore/bindings/scripts/CodeGeneratorJS.pm:3431 > + push(@implContent, " auto objProtoValueOf = globalObject()->objectPrototype()->getDirect(vm, vm.propertyNames->valueOf);\n"); > + push(@implContent, " ASSERT(objProtoValueOf);\n");
It's possible to change or delete this property, so I don't think this is correct. In cases where we might later need the original value of a certain property, we provide an accessor on JSGlobalObject, such as: // The following accessors return pristine values, even if a script // replaces the global object's associated property. GetterSetter* speciesGetterSetter() const { return m_speciesGetterSetter.get(); } RegExpConstructor* regExpConstructor() const { return m_regExpConstructor.get(); } ErrorConstructor* errorConstructor() const { return m_errorConstructor.get(); } ArrayConstructor* arrayConstructor() const { return m_arrayConstructor.get(); } ObjectConstructor* objectConstructor() const { return m_objectConstructor.get(); } JSPromiseConstructor* promiseConstructor() const { return m_promiseConstructor.get(); } JSInternalPromiseConstructor* internalPromiseConstructor() const { return m_internalPromiseConstructor.get(); } NativeErrorConstructor* evalErrorConstructor() const { return m_evalErrorConstructor.get(this); } NativeErrorConstructor* rangeErrorConstructor() const { return m_rangeErrorConstructor.get(); } NativeErrorConstructor* referenceErrorConstructor() const { return m_referenceErrorConstructor.get(this); } NativeErrorConstructor* syntaxErrorConstructor() const { return m_syntaxErrorConstructor.get(this); } NativeErrorConstructor* typeErrorConstructor() const { return m_typeErrorConstructor.get(); } NativeErrorConstructor* URIErrorConstructor() const { return m_URIErrorConstructor.get(this); } NullGetterFunction* nullGetterFunction() const { return m_nullGetterFunction.get(); } NullSetterFunction* nullSetterFunction() const { return m_nullSetterFunction.get(); } JSFunction* parseIntFunction() const { return m_parseIntFunction.get(); } JSFunction* evalFunction() const { return m_evalFunction.get(); } JSFunction* callFunction() const { return m_callFunction.get(); } JSFunction* applyFunction() const { return m_applyFunction.get(); } JSFunction* throwTypeErrorFunction() const { return m_throwTypeErrorFunction.get(); } JSFunction* arrayProtoToStringFunction() const { return m_arrayProtoToStringFunction.get(this); } JSFunction* arrayProtoValuesFunction() const { return m_arrayProtoValuesFunction.get(this); } JSFunction* initializePromiseFunction() const { return m_initializePromiseFunction.get(this); } JSFunction* iteratorProtocolFunction() const { return m_iteratorProtocolFunction.get(this); } JSFunction* newPromiseCapabilityFunction() const { return m_newPromiseCapabilityFunction.get(); } JSFunction* functionProtoHasInstanceSymbolFunction() const { return m_functionProtoHasInstanceSymbolFunction.get(); } JSObject* regExpProtoExecFunction() const { return m_regExpProtoExec.get(); } JSObject* regExpProtoSymbolReplaceFunction() const { return m_regExpProtoSymbolReplace.get(); } JSObject* regExpProtoGlobalGetter() const { return m_regExpProtoGlobalGetter.get(); } JSObject* regExpProtoUnicodeGetter() const { return m_regExpProtoUnicodeGetter.get(); }
Chris Dumez
Comment 7
2017-02-14 11:03:35 PST
(In reply to
comment #6
)
> > Source/WebCore/bindings/scripts/CodeGeneratorJS.pm:3431 > > + push(@implContent, " auto objProtoValueOf = globalObject()->objectPrototype()->getDirect(vm, vm.propertyNames->valueOf);\n"); > > + push(@implContent, " ASSERT(objProtoValueOf);\n"); > > It's possible to change or delete this property, so I don't think this is > correct. > > In cases where we might later need the original value of a certain property, > we provide an accessor on JSGlobalObject, such as: > > // The following accessors return pristine values, even if a script > // replaces the global object's associated property. > > GetterSetter* speciesGetterSetter() const { return > m_speciesGetterSetter.get(); } > > RegExpConstructor* regExpConstructor() const { return > m_regExpConstructor.get(); } > > ErrorConstructor* errorConstructor() const { return > m_errorConstructor.get(); } > ArrayConstructor* arrayConstructor() const { return > m_arrayConstructor.get(); } > ObjectConstructor* objectConstructor() const { return > m_objectConstructor.get(); } > JSPromiseConstructor* promiseConstructor() const { return > m_promiseConstructor.get(); } > JSInternalPromiseConstructor* internalPromiseConstructor() const { > return m_internalPromiseConstructor.get(); } > NativeErrorConstructor* evalErrorConstructor() const { return > m_evalErrorConstructor.get(this); } > NativeErrorConstructor* rangeErrorConstructor() const { return > m_rangeErrorConstructor.get(); } > NativeErrorConstructor* referenceErrorConstructor() const { return > m_referenceErrorConstructor.get(this); } > NativeErrorConstructor* syntaxErrorConstructor() const { return > m_syntaxErrorConstructor.get(this); } > NativeErrorConstructor* typeErrorConstructor() const { return > m_typeErrorConstructor.get(); } > NativeErrorConstructor* URIErrorConstructor() const { return > m_URIErrorConstructor.get(this); } > > NullGetterFunction* nullGetterFunction() const { return > m_nullGetterFunction.get(); } > NullSetterFunction* nullSetterFunction() const { return > m_nullSetterFunction.get(); } > > JSFunction* parseIntFunction() const { return m_parseIntFunction.get(); } > > JSFunction* evalFunction() const { return m_evalFunction.get(); } > JSFunction* callFunction() const { return m_callFunction.get(); } > JSFunction* applyFunction() const { return m_applyFunction.get(); } > JSFunction* throwTypeErrorFunction() const { return > m_throwTypeErrorFunction.get(); } > JSFunction* arrayProtoToStringFunction() const { return > m_arrayProtoToStringFunction.get(this); } > JSFunction* arrayProtoValuesFunction() const { return > m_arrayProtoValuesFunction.get(this); } > JSFunction* initializePromiseFunction() const { return > m_initializePromiseFunction.get(this); } > JSFunction* iteratorProtocolFunction() const { return > m_iteratorProtocolFunction.get(this); } > JSFunction* newPromiseCapabilityFunction() const { return > m_newPromiseCapabilityFunction.get(); } > JSFunction* functionProtoHasInstanceSymbolFunction() const { return > m_functionProtoHasInstanceSymbolFunction.get(); } > JSObject* regExpProtoExecFunction() const { return > m_regExpProtoExec.get(); } > JSObject* regExpProtoSymbolReplaceFunction() const { return > m_regExpProtoSymbolReplace.get(); } > JSObject* regExpProtoGlobalGetter() const { return > m_regExpProtoGlobalGetter.get(); } > JSObject* regExpProtoUnicodeGetter() const { return > m_regExpProtoUnicodeGetter.get(); }
Thanks, I'll update.
Darin Adler
Comment 8
2017-02-14 11:03:44 PST
(In reply to
comment #6
)
> It's possible to change or delete this property, so I don't think this is > correct.
We should verify this with test cases: one that changes and another that deletes the property.
Chris Dumez
Comment 9
2017-02-14 11:13:49 PST
(In reply to
comment #8
)
> (In reply to
comment #6
) > > It's possible to change or delete this property, so I don't think this is > > correct. > > We should verify this with test cases: one that changes and another that > deletes the property.
Will do.
Chris Dumez
Comment 10
2017-02-14 13:28:17 PST
Created
attachment 301539
[details]
Patch
Chris Dumez
Comment 11
2017-02-14 13:28:41 PST
Take #2.
Geoffrey Garen
Comment 12
2017-02-14 13:40:05 PST
Comment on
attachment 301539
[details]
Patch r=me
Keith Miller
Comment 13
2017-02-14 13:41:10 PST
Comment on
attachment 301539
[details]
Patch r=me too.
Mark Lam
Comment 14
2017-02-14 13:43:19 PST
Comment on
attachment 301539
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=301539&action=review
> Source/JavaScriptCore/runtime/JSGlobalObject.cpp:461 > + m_objectProtoValueOfFunction.set(vm, this, jsCast<JSFunction*>(objectPrototype()->getDirect(vm, vm.propertyNames->valueOf)));
You also need to visit m_objectProtoValueOfFunction in JSGlobalObject::visitChildren().
Chris Dumez
Comment 15
2017-02-14 13:52:56 PST
Created
attachment 301543
[details]
Patch
Chris Dumez
Comment 16
2017-02-14 13:53:30 PST
(In reply to
comment #14
)
> Comment on
attachment 301539
[details]
> Patch > > View in context: >
https://bugs.webkit.org/attachment.cgi?id=301539&action=review
> > > Source/JavaScriptCore/runtime/JSGlobalObject.cpp:461 > > + m_objectProtoValueOfFunction.set(vm, this, jsCast<JSFunction*>(objectPrototype()->getDirect(vm, vm.propertyNames->valueOf))); > > You also need to visit m_objectProtoValueOfFunction in > JSGlobalObject::visitChildren().
Sorry, I completely forgot to do this. This is fixed in the latest iteration.
Chris Dumez
Comment 17
2017-02-14 14:00:19 PST
Created
attachment 301544
[details]
Patch
Darin Adler
Comment 18
2017-02-14 14:19:49 PST
Comment on
attachment 301544
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=301544&action=review
> Source/JavaScriptCore/runtime/JSGlobalObject.cpp:461 > + m_objectProtoValueOfFunction.set(vm, this, jsCast<JSFunction*>(objectPrototype()->getDirect(vm, vm.propertyNames->valueOf)));
It would be nicer to find a way to do this without the cast; there must be code that originally allocated this that knows it’s a JSFunction.
Chris Dumez
Comment 19
2017-02-14 14:35:57 PST
Comment on
attachment 301544
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=301544&action=review
>> Source/JavaScriptCore/runtime/JSGlobalObject.cpp:461 >> + m_objectProtoValueOfFunction.set(vm, this, jsCast<JSFunction*>(objectPrototype()->getDirect(vm, vm.propertyNames->valueOf))); > > It would be nicer to find a way to do this without the cast; there must be code that originally allocated this that knows it’s a JSFunction.
I am not sure how to do that. We use putDirectNativeFunctionWithoutTransition() to create the JSFunction from the NativeFunction and put in on the object for us. But then, on getting via get/getDirect, we get a JSValue (Also note that I do not want to create a new JSFunction because I need to preserve identity between Object.prototype.valueOf and location.valueOf).
Darin Adler
Comment 20
2017-02-14 14:50:03 PST
Comment on
attachment 301544
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=301544&action=review
>>> Source/JavaScriptCore/runtime/JSGlobalObject.cpp:461 >>> + m_objectProtoValueOfFunction.set(vm, this, jsCast<JSFunction*>(objectPrototype()->getDirect(vm, vm.propertyNames->valueOf))); >> >> It would be nicer to find a way to do this without the cast; there must be code that originally allocated this that knows it’s a JSFunction. > > I am not sure how to do that. We use putDirectNativeFunctionWithoutTransition() to create the JSFunction from the NativeFunction and put in on the object for us. > But then, on getting via get/getDirect, we get a JSValue (Also note that I do not want to create a new JSFunction because I need to preserve identity between Object.prototype.valueOf and location.valueOf).
One idea: Could add a JSFunction* return value to putDirectNativeFunctionWithoutTransition, ignored by other callers, but used in this case.
Chris Dumez
Comment 21
2017-02-14 14:53:28 PST
(In reply to
comment #20
)
> Comment on
attachment 301544
[details]
> Patch > > View in context: >
https://bugs.webkit.org/attachment.cgi?id=301544&action=review
> > >>> Source/JavaScriptCore/runtime/JSGlobalObject.cpp:461 > >>> + m_objectProtoValueOfFunction.set(vm, this, jsCast<JSFunction*>(objectPrototype()->getDirect(vm, vm.propertyNames->valueOf))); > >> > >> It would be nicer to find a way to do this without the cast; there must be code that originally allocated this that knows it’s a JSFunction. > > > > I am not sure how to do that. We use putDirectNativeFunctionWithoutTransition() to create the JSFunction from the NativeFunction and put in on the object for us. > > But then, on getting via get/getDirect, we get a JSValue (Also note that I do not want to create a new JSFunction because I need to preserve identity between Object.prototype.valueOf and location.valueOf). > > One idea: Could add a JSFunction* return value to > putDirectNativeFunctionWithoutTransition, ignored by other callers, but used > in this case.
putDirectNativeFunctionWithoutTransition() is called inside ObjectPrototype::finishCreation(). I need access to it in the JSGlobalObject after the ObjectPrototype has been constructed.
Chris Dumez
Comment 22
2017-02-14 14:54:55 PST
(In reply to
comment #21
)
> (In reply to
comment #20
) > > Comment on
attachment 301544
[details]
> > Patch > > > > View in context: > >
https://bugs.webkit.org/attachment.cgi?id=301544&action=review
> > > > >>> Source/JavaScriptCore/runtime/JSGlobalObject.cpp:461 > > >>> + m_objectProtoValueOfFunction.set(vm, this, jsCast<JSFunction*>(objectPrototype()->getDirect(vm, vm.propertyNames->valueOf))); > > >> > > >> It would be nicer to find a way to do this without the cast; there must be code that originally allocated this that knows it’s a JSFunction. > > > > > > I am not sure how to do that. We use putDirectNativeFunctionWithoutTransition() to create the JSFunction from the NativeFunction and put in on the object for us. > > > But then, on getting via get/getDirect, we get a JSValue (Also note that I do not want to create a new JSFunction because I need to preserve identity between Object.prototype.valueOf and location.valueOf). > > > > One idea: Could add a JSFunction* return value to > > putDirectNativeFunctionWithoutTransition, ignored by other callers, but used > > in this case. > > putDirectNativeFunctionWithoutTransition() is called inside > ObjectPrototype::finishCreation(). I need access to it in the JSGlobalObject > after the ObjectPrototype has been constructed.
c.f. void ObjectPrototype::finishCreation(VM& vm, JSGlobalObject* globalObject) { Base::finishCreation(vm); ASSERT(inherits(vm, info())); // ... JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->valueOf, objectProtoFuncValueOf, DontEnum, 0); // ... }
Mark Lam
Comment 23
2017-02-14 15:15:58 PST
Comment on
attachment 301544
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=301544&action=review
>>>>>> Source/JavaScriptCore/runtime/JSGlobalObject.cpp:461 >>>>>> + m_objectProtoValueOfFunction.set(vm, this, jsCast<JSFunction*>(objectPrototype()->getDirect(vm, vm.propertyNames->valueOf))); >>>>> >>>>> It would be nicer to find a way to do this without the cast; there must be code that originally allocated this that knows it’s a JSFunction. >>>> >>>> I am not sure how to do that. We use putDirectNativeFunctionWithoutTransition() to create the JSFunction from the NativeFunction and put in on the object for us. >>>> But then, on getting via get/getDirect, we get a JSValue (Also note that I do not want to create a new JSFunction because I need to preserve identity between Object.prototype.valueOf and location.valueOf). >>> >>> One idea: Could add a JSFunction* return value to putDirectNativeFunctionWithoutTransition, ignored by other callers, but used in this case. >> >> putDirectNativeFunctionWithoutTransition() is called inside ObjectPrototype::finishCreation(). I need access to it in the JSGlobalObject after the ObjectPrototype has been constructed. > > c.f. > void ObjectPrototype::finishCreation(VM& vm, JSGlobalObject* globalObject) > { > Base::finishCreation(vm); > ASSERT(inherits(vm, info())); > // ... > JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->valueOf, objectProtoFuncValueOf, DontEnum, 0); > // ... > }
Some details to consider: 1. JSGlobalObject::init() (this function) doesn't itself call putDirectNativeFunctionWithoutTransition() to create the Function that it is trying to cache. 2. JSGlobalObject::init() instantiates m_objectPrototype above. It's the ObjectPrototype factory that creates the function. 3. It would be strange for ObjectPrototype::finishCreation() to cache the function in the globalObject. This creates a tighter coupling between ObjectPrototype and JSGlobalObject. For these reasons, I think the way Chris implemented it is just fine. I suggest we move forward with this patch.
WebKit Commit Bot
Comment 24
2017-02-15 10:20:40 PST
Comment on
attachment 301544
[details]
Patch Rejecting
attachment 301544
[details]
from commit-queue. Failed to run "['/Volumes/Data/EWS/WebKit/Tools/Scripts/webkit-patch', '--status-host=webkit-queues.webkit.org', '--bot-id=webkit-cq-02', 'land-attachment', '--force-clean', '--non-interactive', '--parent-command=commit-queue', 301544, '--port=mac']" exit_code: 1 cwd: /Volumes/Data/EWS/WebKit Last 500 characters of output: ckout/scm/scm.py", line 77, in run decode_output=decode_output) File "/Volumes/Data/EWS/WebKit/Tools/Scripts/webkitpy/common/system/executive.py", line 443, in run_command output = output.decode(self._child_process_encoding()) File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/encodings/utf_8.py", line 16, in decode return codecs.utf_8_decode(input, errors, True) UnicodeDecodeError: 'utf8' codec can't decode byte 0xad in position 142: invalid start byte Full output:
http://webkit-queues.webkit.org/results/3122689
Chris Dumez
Comment 25
2017-02-15 10:25:15 PST
Comment on
attachment 301544
[details]
Patch Clearing flags on attachment: 301544 Committed
r212378
: <
http://trac.webkit.org/changeset/212378
>
Chris Dumez
Comment 26
2017-02-15 10:25:24 PST
All reviewed patches have been landed. Closing bug.
Note
You need to
log in
before you can comment on or make changes to this bug.
Top of Page
Format For Printing
XML
Clone This Bug