RESOLVED FIXED 93872
[Qt] Replace use of internal Weak smart pointer with JSWeakObjectMap
https://bugs.webkit.org/show_bug.cgi?id=93872
Summary [Qt] Replace use of internal Weak smart pointer with JSWeakObjectMap
Simon Hausmann
Reported 2012-08-13 11:19:10 PDT
[Qt] Replace use of internal Weak smart pointer with JSWeakObjectMap
Attachments
Patch (6.52 KB, patch)
2012-08-13 11:37 PDT, Simon Hausmann
no flags
Patch (6.58 KB, patch)
2012-08-13 11:59 PDT, Simon Hausmann
no flags
Patch (6.54 KB, patch)
2012-08-13 12:27 PDT, Simon Hausmann
no flags
Patch (8.85 KB, patch)
2012-08-16 07:02 PDT, Simon Hausmann
no flags
Patch (8.79 KB, patch)
2012-08-17 01:59 PDT, Simon Hausmann
kenneth: review+
Simon Hausmann
Comment 1 2012-08-13 11:37:07 PDT
Kenneth Rohde Christiansen
Comment 2 2012-08-13 11:51:43 PDT
Comment on attachment 158057 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=158057&action=review > Source/WebCore/ChangeLog:16 > + The intent of replacing the use of the internal Weak smart pointer with > + public JSC C API is slightly more complex. JSWeakObjectMap is special > + in the sense that its life-time is tied to the life-time of the JS > + global object, which in turn is subject to garbage collection. In order > + to maximize re-use of the same map across different JSContextRef instances, > + we use the associated global context ref as owner of the weak maps. The key > + in the weak map is the identity (pointer) of the runtime method object itself. > + The iteration through the maps is tedious, but should usually not go beyond > + just a few. Would be nice if you wrote about the advantage of switching to the JSWeakObjectMap. Like what does it solve
Simon Hausmann
Comment 3 2012-08-13 11:59:18 PDT
Created attachment 158064 [details] Patch New version explaining the motivation :)
Caio Marcelo de Oliveira Filho
Comment 4 2012-08-13 12:16:35 PDT
Comment on attachment 158064 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=158064&action=review > Source/WebCore/bridge/qt/qt_runtime.cpp:1320 > + if (obj) { > + JSObjectSetPrivate(obj, 0); > + JSWeakObjectMapRemove(it->first, it->second, this); Since we don't expect obj to be in more than one map, could we return here after finding one?
Kenneth Rohde Christiansen
Comment 5 2012-08-13 12:23:20 PDT
Comment on attachment 158064 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=158064&action=review > Source/WebCore/bridge/qt/qt_runtime.cpp:1303 > + > + double newline :-) > Source/WebCore/bridge/qt/qt_runtime.cpp:1316 > + for (WeakRuntimeMethodMap::const_iterator it = weakRuntimeMethodCache.begin(), end = weakRuntimeMethodCache.end(); > + it != end; ++it) { I know this looks nice, but it differs from how to normally do it. Apparently I was pointed out that the style guide says to not use iterators when being able to iterate knowing the size. I am not sure I agree with that, but just pointing out > Source/WebCore/bridge/qt/qt_runtime.cpp:1318 > + JSObjectRef obj = JSWeakObjectMapGet(it->first, it->second, this); > + if (obj) { merge to one line? > Source/WebCore/bridge/qt/qt_runtime.cpp:1374 > + JSObjectRef cachedMethod = JSWeakObjectMapGet(cache->first, cache->second, this); > + if (cachedMethod) Merge to one line? > Source/WebCore/bridge/qt/qt_runtime.cpp:1412 > + JSWeakObjectMapRef map = 0; why = 0 when you are setting it both places
Simon Hausmann
Comment 6 2012-08-13 12:24:27 PDT
(In reply to comment #4) > (From update of attachment 158064 [details]) > View in context: https://bugs.webkit.org/attachment.cgi?id=158064&action=review > > > Source/WebCore/bridge/qt/qt_runtime.cpp:1320 > > + if (obj) { > > + JSObjectSetPrivate(obj, 0); > > + JSWeakObjectMapRemove(it->first, it->second, this); > > Since we don't expect obj to be in more than one map, could we return here after finding one? Right now that is indeed not possible, given that the same QObject exposed in two different script environments leads to two different QtInstance objects and thus different RuntimeMethod objects. But in the future we're going to remove QtInstance.
Simon Hausmann
Comment 7 2012-08-13 12:27:11 PDT
Comment on attachment 158064 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=158064&action=review Thanks for the review :) >> Source/WebCore/bridge/qt/qt_runtime.cpp:1316 >> + it != end; ++it) { > > I know this looks nice, but it differs from how to normally do it. Apparently I was pointed out that the style guide says to not use iterators when being able to iterate knowing the size. I am not sure I agree with that, but just pointing out The data structure in question is a set, so the iterators are the only way to efficiently iterate. I agree that for vectors indexing is preferred. >> Source/WebCore/bridge/qt/qt_runtime.cpp:1318 >> + if (obj) { > > merge to one line? Good idea, I need to make that pattern a habit :) >> Source/WebCore/bridge/qt/qt_runtime.cpp:1412 >> + JSWeakObjectMapRef map = 0; > > why = 0 when you are setting it both places Unnecessary paranoia :) - I'll remove the initialization.
Simon Hausmann
Comment 8 2012-08-13 12:27:45 PDT
Caio Marcelo de Oliveira Filho
Comment 9 2012-08-13 13:29:44 PDT
LGTM.
Simon Hausmann
Comment 10 2012-08-13 13:45:27 PDT
Simon Hausmann
Comment 11 2012-08-13 14:37:38 PDT
Reverted r125444 for reason: Broke some tests Committed r125452: <http://trac.webkit.org/changeset/125452>
Simon Hausmann
Comment 13 2012-08-14 07:29:23 PDT
Another way to reproduce the crash: gdb --args /path/to/DRT `find LayoutTests/fast/js`
Simon Hausmann
Comment 14 2012-08-16 06:59:53 PDT
The crash is caused by accessing the weak map that is associated with a global object that's been deleted already. The solution appears to be to have a separate js context for the weak map that is created in the same context _group_. It is allowed to share objects across contexts in the same group. The weak map has no destructor, it is GC'ed when the context's global object is collected. Therefore we simply refcount on the context that "owns" the weak map. New patch coming up.
Simon Hausmann
Comment 15 2012-08-16 07:02:14 PDT
Kenneth Rohde Christiansen
Comment 16 2012-08-16 07:22:17 PDT
Comment on attachment 158805 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=158805&action=review r=me... but you already filled that in > Source/WebCore/bridge/qt/qt_instance.cpp:50 > + // Deleted by GC when m_context's globalObject gets collected Missed . though > Source/WebCore/bridge/qt/qt_instance.cpp:67 > + // Just us and the ref in the weakMaps left? Why is this a question?
Simon Hausmann
Comment 17 2012-08-16 07:33:50 PDT
Comment on attachment 158805 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=158805&action=review >> Source/WebCore/bridge/qt/qt_instance.cpp:50 >> + // Deleted by GC when m_context's globalObject gets collected > > Missed . though Oops, will fix. >> Source/WebCore/bridge/qt/qt_instance.cpp:67 >> + // Just us and the ref in the weakMaps left? > > Why is this a question? Ok, got the hint ;). Will be a bit more elaborate when landing. Basically if this is the last WeakMap instance left, then we should delete the context from the global weakMaps.
Caio Marcelo de Oliveira Filho
Comment 18 2012-08-16 08:44:05 PDT
Comment on attachment 158805 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=158805&action=review > Source/WebCore/bridge/qt/qt_instance.cpp:56 > + if (m_context) Simon, it's not clear to me when this could happen. > Source/WebCore/bridge/qt/qt_instance.cpp:83 > + WeakMapSet::iterator cachedMap = weakMaps.find(group); > + if (cachedMap == weakMaps.end()) { > + m_impl = adoptRef(new WeakMapImpl(group)); > + weakMaps.add(group, m_impl); > + } else > + m_impl = cachedMap->second; Minor suggestion: you could use the HashMap::add idiom here. Instead of find() use add() passing 0 (or nullptr) as new value, if its a new entry you set directly in the value (second) of the iterator add() gives you back.
Caio Marcelo de Oliveira Filho
Comment 19 2012-08-16 08:57:18 PDT
Comment on attachment 158805 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=158805&action=review >> Source/WebCore/bridge/qt/qt_instance.cpp:56 >> + if (m_context) > > Simon, it's not clear to me when this could happen. Sorry. I meant to say: when this couldn't happen. I don't see m_context being cleared and I don't think JSC clears it behind our back, so even if the context goes away I would expect this to evaluate to true... Could it even go away while we still hold a retained ref (implicitly retained by Create call)?
Simon Hausmann
Comment 20 2012-08-17 00:43:37 PDT
Comment on attachment 158805 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=158805&action=review >>> Source/WebCore/bridge/qt/qt_instance.cpp:56 >>> + if (m_context) >> >> Simon, it's not clear to me when this could happen. > > Sorry. I meant to say: when this couldn't happen. I don't see m_context being cleared and I don't think JSC clears it behind our back, so even if the context goes away I would expect this to evaluate to true... Could it even go away while we still hold a retained ref (implicitly retained by Create call)? You're right, this was a left-over from moving the code around a few iterations earlier. The if is indeed redundant, I'll remove it. Thanks :) >> Source/WebCore/bridge/qt/qt_instance.cpp:83 >> + m_impl = cachedMap->second; > > Minor suggestion: you could use the HashMap::add idiom here. Instead of find() use add() passing 0 (or nullptr) as new value, if its a new entry you set directly in the value (second) of the iterator add() gives you back. Lovely, I'll go for that.
Simon Hausmann
Comment 21 2012-08-17 01:59:21 PDT
Created attachment 159049 [details] Patch Updated patch for review, taking Caio's comments into account
Simon Hausmann
Comment 22 2012-08-17 02:43:02 PDT
Caio Marcelo de Oliveira Filho
Comment 23 2012-08-17 05:21:23 PDT
Comment on attachment 159049 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=159049&action=review > Source/WebCore/bridge/qt/qt_instance.cpp:80 > + entry.iterator->second = new WeakMapImpl(group); It seems to me that we still need the adoptRef() here. Optionally, we could have a WeakMapImpl::create that calls adoptRef(new ...) and returns a PassRefPtr.
Simon Hausmann
Comment 24 2012-08-17 05:26:10 PDT
Comment on attachment 159049 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=159049&action=review >> Source/WebCore/bridge/qt/qt_instance.cpp:80 >> + entry.iterator->second = new WeakMapImpl(group); > > It seems to me that we still need the adoptRef() here. > > Optionally, we could have a WeakMapImpl::create that calls adoptRef(new ...) and returns a PassRefPtr. Argh, good catch! I'll land a quick follow-up fix right away with adoptRef.
Simon Hausmann
Comment 25 2012-08-17 05:32:20 PDT
Note You need to log in before you can comment on or make changes to this bug.