Bug 136839

Summary: Generate Element casting helper functions
Product: WebKit Reporter: Chris Dumez <cdumez>
Component: DOMAssignee: Chris Dumez <cdumez>
Status: RESOLVED FIXED    
Severity: Normal CC: benjamin, bfulgham, commit-queue, darin, gyuyoung.kim, kling, koivisto, rniwa
Priority: P2    
Version: 528+ (Nightly build)   
Hardware: Unspecified   
OS: Unspecified   
Bug Depends on:    
Bug Blocks: 137004, 137007, 137015, 137056    
Attachments:
Description Flags
WIP Patch
none
WIP Patch
none
WIP Patch
none
WIP Patch
none
WIP Patch
none
Patch
none
Patch
none
Patch
none
Patch
none
Patch
none
Patch
none
Patch none

Chris Dumez
Reported 2014-09-15 14:53:41 PDT
We are currently generating the isHTML*Element() type checking helpers in HTMLElementTypeHelpers.h. However, the corresponding toHTML*Element() casting helpers are being generated by the NODE_TYPE_CASTS() macro. It would be nice if we could generate those helpers automatically, so that we no longer need to use NODE_TYPE_CASTS() for most HTML / SVG / MathML types. I think those were generated in the past but the change got reverted because the forward declarations for the HTML Elements were forcing the use of reinterpret_cast instead of static_cast, which is unsafe due to multiple inheritance. My proposal to make it work using static_cast would be to: - Define the following templated functions in Element.h *** template<typename T> inline T& toElement(Node& node) { ASSERT_WITH_SECURITY_IMPLICATION(isElementOfType<const T>(node)); return static_cast<T&>(node); } template<typename T> inline T* toElement(Node* node) { ASSERT_WITH_SECURITY_IMPLICATION(!node || isElementOfType<const T>(*node)); return static_cast<T*>(node); } template<typename T> inline const T& toElement(const Node& node) { ASSERT_WITH_SECURITY_IMPLICATION(isElementOfType<const T>(node)); return static_cast<const T&>(node); } template<typename T> inline const T* toElement(const Node* node) { ASSERT_WITH_SECURITY_IMPLICATION(!node || isElementOfType<const T>(*node)); return static_cast<const T*>(node); } *** - Generate toHTML*Element() macros in HTMLElementTypeHelpers.h that call toElement<>() so that we don't need to update existing code. They would look like: #define toHTMLDivElement(x) WebCore::toElement<WebCore::HTMLDivElement>(x) Any opinion on this?
Attachments
WIP Patch (77.28 KB, patch)
2014-09-16 16:46 PDT, Chris Dumez
no flags
WIP Patch (78.01 KB, patch)
2014-09-16 17:05 PDT, Chris Dumez
no flags
WIP Patch (124.65 KB, patch)
2014-09-16 17:24 PDT, Chris Dumez
no flags
WIP Patch (125.26 KB, patch)
2014-09-16 17:36 PDT, Chris Dumez
no flags
WIP Patch (126.83 KB, patch)
2014-09-17 14:37 PDT, Chris Dumez
no flags
Patch (152.69 KB, patch)
2014-09-17 14:52 PDT, Chris Dumez
no flags
Patch (152.16 KB, patch)
2014-09-18 13:18 PDT, Chris Dumez
no flags
Patch (153.42 KB, patch)
2014-09-18 16:10 PDT, Chris Dumez
no flags
Patch (158.94 KB, patch)
2014-09-18 17:07 PDT, Chris Dumez
no flags
Patch (159.60 KB, patch)
2014-09-18 18:26 PDT, Chris Dumez
no flags
Patch (160.05 KB, patch)
2014-09-21 16:23 PDT, Chris Dumez
no flags
Patch (160.85 KB, patch)
2014-09-21 20:02 PDT, Chris Dumez
no flags
Gyuyoung Kim
Comment 1 2014-09-15 18:45:11 PDT
(In reply to comment #0) > We are currently generating the isHTML*Element() type checking helpers in HTMLElementTypeHelpers.h. However, the corresponding toHTML*Element() casting helpers are being generated by the NODE_TYPE_CASTS() macro. It would be nice if we could generate those helpers automatically, so that we no longer need to use NODE_TYPE_CASTS() for most HTML / SVG / MathML types. > > I think those were generated in the past but the change got reverted because the forward declarations for the HTML Elements were forcing the use of reinterpret_cast instead of static_cast, which is unsafe due to multiple inheritance. > > My proposal to make it work using static_cast would be to: > - Define the following templated functions in Element.h > *** > template<typename T> inline T& toElement(Node& node) > { > ASSERT_WITH_SECURITY_IMPLICATION(isElementOfType<const T>(node)); > return static_cast<T&>(node); > } > template<typename T> inline T* toElement(Node* node) > { > ASSERT_WITH_SECURITY_IMPLICATION(!node || isElementOfType<const T>(*node)); > return static_cast<T*>(node); > } > template<typename T> inline const T& toElement(const Node& node) > { > ASSERT_WITH_SECURITY_IMPLICATION(isElementOfType<const T>(node)); > return static_cast<const T&>(node); > } > template<typename T> inline const T* toElement(const Node* node) > { > ASSERT_WITH_SECURITY_IMPLICATION(!node || isElementOfType<const T>(*node)); > return static_cast<const T*>(node); > } > *** > > - Generate toHTML*Element() macros in HTMLElementTypeHelpers.h that call toElement<>() so that we don't need to update existing code. They would look like: > #define toHTMLDivElement(x) WebCore::toElement<WebCore::HTMLDivElement>(x) > > Any opinion on this? Chris, looks good idea ! As you said, I reverted previous toFoo generation patch because of reinterpret_cast's security problem. BTW, I wonder whether this approach can handle multiple tags which are processed by same HTMLFooElement interface.
Chris Dumez
Comment 2 2014-09-15 18:54:08 PDT
(In reply to comment #1) > (In reply to comment #0) > > We are currently generating the isHTML*Element() type checking helpers in HTMLElementTypeHelpers.h. However, the corresponding toHTML*Element() casting helpers are being generated by the NODE_TYPE_CASTS() macro. It would be nice if we could generate those helpers automatically, so that we no longer need to use NODE_TYPE_CASTS() for most HTML / SVG / MathML types. > > > > I think those were generated in the past but the change got reverted because the forward declarations for the HTML Elements were forcing the use of reinterpret_cast instead of static_cast, which is unsafe due to multiple inheritance. > > > > My proposal to make it work using static_cast would be to: > > - Define the following templated functions in Element.h > > *** > > template<typename T> inline T& toElement(Node& node) > > { > > ASSERT_WITH_SECURITY_IMPLICATION(isElementOfType<const T>(node)); > > return static_cast<T&>(node); > > } > > template<typename T> inline T* toElement(Node* node) > > { > > ASSERT_WITH_SECURITY_IMPLICATION(!node || isElementOfType<const T>(*node)); > > return static_cast<T*>(node); > > } > > template<typename T> inline const T& toElement(const Node& node) > > { > > ASSERT_WITH_SECURITY_IMPLICATION(isElementOfType<const T>(node)); > > return static_cast<const T&>(node); > > } > > template<typename T> inline const T* toElement(const Node* node) > > { > > ASSERT_WITH_SECURITY_IMPLICATION(!node || isElementOfType<const T>(*node)); > > return static_cast<const T*>(node); > > } > > *** > > > > - Generate toHTML*Element() macros in HTMLElementTypeHelpers.h that call toElement<>() so that we don't need to update existing code. They would look like: > > #define toHTMLDivElement(x) WebCore::toElement<WebCore::HTMLDivElement>(x) > > > > Any opinion on this? > > Chris, looks good idea ! As you said, I reverted previous toFoo generation patch because of reinterpret_cast's security problem. BTW, I wonder whether this approach can handle multiple tags which are processed by same HTMLFooElement interface. For HTML / SVG elements that need special handling (such as the case you mentioned), we would still need to use a macro. Those types already need a ElementTypeTraits specialization to be defined for them. The macro would define that specialization as well.
Benjamin Poulain
Comment 3 2014-09-15 20:09:35 PDT
Personally I like the template better than NODE_TYPE_CASTS. What we must avoid is mixing both. We can either 1) Make a new styleRule enforcing toXXXElement over toElement<XXX>. Update the style checker accordingly. 2) Get rid of toXXXElement() and update the whole code base. I don't think (2) is that bad, that's something one can land over a weekend when there is less activity.
Chris Dumez
Comment 4 2014-09-15 20:27:05 PDT
(In reply to comment #3) > Personally I like the template better than NODE_TYPE_CASTS. > > What we must avoid is mixing both. We can either > 1) Make a new styleRule enforcing toXXXElement over toElement<XXX>. Update the style checker accordingly. > 2) Get rid of toXXXElement() and update the whole code base. > > I don't think (2) is that bad, that's something one can land over a weekend when there is less activity. I think people are used to the toHTML*Element() helpers so I would prefer to go with 1). I prefer not to have developers learn something new if we can avoid it. Also, it is a lot less work and noise in the code.
Chris Dumez
Comment 5 2014-09-16 16:46:48 PDT
Created attachment 238220 [details] WIP Patch
Chris Dumez
Comment 6 2014-09-16 17:05:59 PDT
Created attachment 238223 [details] WIP Patch GTK and EFL build fixes
Chris Dumez
Comment 7 2014-09-16 17:24:53 PDT
Created attachment 238226 [details] WIP Patch Rebaseline bindings tests and speculative GTK build fix.
Chris Dumez
Comment 8 2014-09-16 17:36:54 PDT
Created attachment 238229 [details] WIP Patch
Chris Dumez
Comment 9 2014-09-17 14:37:32 PDT
Created attachment 238265 [details] WIP Patch
Chris Dumez
Comment 10 2014-09-17 14:52:04 PDT
Chris Dumez
Comment 11 2014-09-17 14:59:00 PDT
Comment on attachment 238267 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=238267&action=review > Source/WebCore/bindings/scripts/test/JS/JSTestEventTarget.h:42 > + static TestEventTarget* toImpl(JSC::JSValue); The reason I did not use a templated to<XXX>() function (and specializations) for these is that: - Some classes provide a custom implementation in their *Custom.cpp custom binding file - The prototype actually changes quite a bit from one class to another: * SVG types often return different TearOff types * Some classes require additional arguments (vm / execState)
Chris Dumez
Comment 12 2014-09-18 10:43:02 PDT
I don't quite get the errors on the win-ews: 1>..\accessibility\AccessibilityMenuListPopup.cpp(105): error C2819: type 'WebCore::HTMLSelectElement' does not have an overloaded member 'operator ->' C:\cygwin\home\buildbot\WebKit\Source\WebCore\html\HTMLSelectElement.h(39) : see declaration of 'WebCore::HTMLSelectElement' did you intend to use '.' instead? 1>..\accessibility\AccessibilityMenuListPopup.cpp(105): error C2232: '->WebCore::HTMLSelectElement::listItems' : left operand has 'class' type, use '.' 1>..\accessibility\AccessibilityMenuListPopup.cpp(106): error C2065: 'listItem' : undeclared identifier BarProp.cpp 1>c:\cygwin\home\buildbot\webkit\source\webcore\accessibility\AXObjectCache.cpp(180): error C2664: 'WebCore::AccessibilityObject *WebCore::AXObjectCache::focusedImageMapUIElement(WebCore::HTMLAreaElement *)' : cannot convert argument 1 from 'WebCore::HTMLAreaElement' to 'WebCore::HTMLAreaElement *' (..\accessibility\AccessibilityAllInOne.cpp) No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called 1>c:\cygwin\home\buildbot\webkit\source\webcore\accessibility\AXObjectCache.cpp(951): error C2819: type 'WebCore::HTMLLabelElement' does not have an overloaded member 'operator ->' (..\accessibility\AccessibilityAllInOne.cpp) It looks like toHTML*Element(Node*) returns a reference instead of a pointer? I don't get how this is possible yet, especially with msvc only.
Chris Dumez
Comment 13 2014-09-18 11:03:03 PDT
(In reply to comment #12) > I don't quite get the errors on the win-ews: > 1>..\accessibility\AccessibilityMenuListPopup.cpp(105): error C2819: type 'WebCore::HTMLSelectElement' does not have an overloaded member 'operator ->' > C:\cygwin\home\buildbot\WebKit\Source\WebCore\html\HTMLSelectElement.h(39) : see declaration of 'WebCore::HTMLSelectElement' > did you intend to use '.' instead? > 1>..\accessibility\AccessibilityMenuListPopup.cpp(105): error C2232: '->WebCore::HTMLSelectElement::listItems' : left operand has 'class' type, use '.' > 1>..\accessibility\AccessibilityMenuListPopup.cpp(106): error C2065: 'listItem' : undeclared identifier > BarProp.cpp > 1>c:\cygwin\home\buildbot\webkit\source\webcore\accessibility\AXObjectCache.cpp(180): error C2664: 'WebCore::AccessibilityObject *WebCore::AXObjectCache::focusedImageMapUIElement(WebCore::HTMLAreaElement *)' : cannot convert argument 1 from 'WebCore::HTMLAreaElement' to 'WebCore::HTMLAreaElement *' (..\accessibility\AccessibilityAllInOne.cpp) > No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called > 1>c:\cygwin\home\buildbot\webkit\source\webcore\accessibility\AXObjectCache.cpp(951): error C2819: type 'WebCore::HTMLLabelElement' does not have an overloaded member 'operator ->' (..\accessibility\AccessibilityAllInOne.cpp) > > It looks like toHTML*Element(Node*) returns a reference instead of a pointer? I don't get how this is possible yet, especially with msvc only. Ah, msvc is using the wrong downcast<>() overload, it is using the "Target& downcast(Source& source)" one with Source=HTMLSelectElement* instead of using the "Target* downcast(Source* source)" one with Source=HTMLSelectElement. I need to address this.
Chris Dumez
Comment 14 2014-09-18 13:18:27 PDT
Chris Dumez
Comment 15 2014-09-18 13:19:04 PDT
(In reply to comment #14) > Created an attachment (id=238321) [details] > Patch Hopefully, this one fixes the win-ews build.
Chris Dumez
Comment 16 2014-09-18 16:10:48 PDT
Chris Dumez
Comment 17 2014-09-18 17:07:52 PDT
Chris Dumez
Comment 18 2014-09-18 18:26:00 PDT
Chris Dumez
Comment 19 2014-09-18 19:35:11 PDT
Comment on attachment 238345 [details] Patch And the windows bot is finally green. Please take a look.
Darin Adler
Comment 20 2014-09-21 12:53:56 PDT
Comment on attachment 238345 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=238345&action=review Looks like a step in the right direction. But one last thing: For me it’s unpleasant to see so many new call sites using the non-word “impl”. I don’t really think of the thing that’s wrapped by a wrapper as an “impl” even though we make some use of that name today. I think we should consider the function name unwrap() or even toWrapped() instead of toImpl(). > Source/WebCore/bindings/js/JSDOMFormDataCustom.cpp:55 > HTMLFormElement* form = 0; > if (exec->argumentCount() > 0) > - form = toHTMLFormElement(exec->argument(0)); > + form = toHTMLFormElementOrNull(exec->argument(0)); If there are no arguments, exec->argument(0) will return undefined and we would get null from toHTMLFormElementOrNull so we don’t really need the if statement. Also should use nullptr.
Chris Dumez
Comment 21 2014-09-21 16:23:52 PDT
Chris Dumez
Comment 22 2014-09-21 20:02:40 PDT
WebKit Commit Bot
Comment 23 2014-09-21 20:52:02 PDT
Comment on attachment 238445 [details] Patch Clearing flags on attachment: 238445 Committed r173804: <http://trac.webkit.org/changeset/173804>
WebKit Commit Bot
Comment 24 2014-09-21 20:52:07 PDT
All reviewed patches have been landed. Closing bug.
Brent Fulgham
Comment 25 2014-09-22 17:55:26 PDT
Note: This broke 64-bit Windows builds. Working on a patch.
Brent Fulgham
Comment 26 2014-09-23 16:27:22 PDT
Build fix checked in for Windows in r173878 <http://trac.webkit.org/changeset/173878>
Chris Dumez
Comment 27 2014-09-23 16:30:59 PDT
(In reply to comment #26) > Build fix checked in for Windows in r173878 <http://trac.webkit.org/changeset/173878> Thanks Brent, and sorry about the breakage. I did fix the win-ews before landing but my symbol exporting wasn't entirely correct apparently.
Darin Adler
Comment 28 2014-10-03 09:09:04 PDT
Are we going to do something similar for the render tree?
Chris Dumez
Comment 29 2014-10-03 10:01:48 PDT
(In reply to comment #28) > Are we going to do something similar for the render tree? Render objects are still using the TYPE_CASTS_BASE() macro + a isRendererOfType template specialization. My short-term plan is to port them to the new SPECIALIZE_TYPE_TRAITS_*() macro so that: - We can use is<>() / downcast<>() on render objects - We can likely drop the isRendererOfType template specialization as we will likely be able to leverage the TypeCastTraits specialization instead. I don't know if you were talking about generating the traits specializations without macros (like we do for most HTML / SVG / MathML elements). This part I haven't thought about yet. Right now I am still in the process of porting CSS objects over to is<>() / downcast<>().
Darin Adler
Comment 30 2014-10-03 21:29:29 PDT
(In reply to comment #29) > My short-term plan is to port them to the new SPECIALIZE_TYPE_TRAITS_*() macro Great. > I don't know if you were talking about generating the traits specializations without macros (like we do for most HTML / SVG / MathML elements). I wasn’t.
Note You need to log in before you can comment on or make changes to this bug.