Per-zone JS holder tables for wrappercached objects
Categories
(Core :: DOM: Core & HTML, enhancement, P2)
Tracking
()
Tracking | Status | |
---|---|---|
firefox77 | --- | fixed |
People
(Reporter: mccr8, Assigned: jonco)
References
Details
Attachments
(7 files, 1 obsolete file)
47 bytes,
text/x-phabricator-request
|
Details | Review | |
47 bytes,
text/x-phabricator-request
|
Details | Review | |
47 bytes,
text/x-phabricator-request
|
Details | Review | |
47 bytes,
text/x-phabricator-request
|
Details | Review | |
47 bytes,
text/x-phabricator-request
|
Details | Review | |
47 bytes,
text/x-phabricator-request
|
Details | Review | |
47 bytes,
text/x-phabricator-request
|
Details | Review |
Assignee | ||
Comment 1•7 years ago
|
||
Updated•7 years ago
|
Reporter | ||
Comment 2•7 years ago
|
||
Comment 3•7 years ago
|
||
Reporter | ||
Comment 4•7 years ago
|
||
Reporter | ||
Comment 5•7 years ago
|
||
Reporter | ||
Updated•7 years ago
|
Comment 6•7 years ago
|
||
Updated•6 years ago
|
Assignee | ||
Comment 8•5 years ago
|
||
Currently, to remove a holder entry from a vector we swap the entry with the last one in the vector and then shrink the vector (and fix up the map). With per-zone vectors we won't have a reference to the vector to get the last entry. One solution would be to store the zone in the entry and look up the vector in a map but I'd like to avoid this if possible because of the space overhead and the extra lookup.
This patch defers clears the entry's pointers when it is removed and actually removes it when the vector is next iterated.
Assignee | ||
Comment 9•5 years ago
|
||
Depends on D68518
Assignee | ||
Comment 10•5 years ago
|
||
This is bascially the same as your original patch.
Depends on D68519
Assignee | ||
Comment 11•5 years ago
|
||
So that we can update the holders table correctly we will need to remove the wrapper from its original vector and add it to the one associated with the new zone.
I tried to make SetPreservingWrapper private but there's still a use in layout/style/Rule.cpp that I couldn't see an obvious fix for.
Depends on D68520
Assignee | ||
Comment 12•5 years ago
|
||
Currently the JS holders table is represented as a map which contains pointers to entries in a SegmentedVector. This patch keeps the single map but use a vector per zone and also has a catch-all vector for where we don't know the zone or the holder can have pointers to more than one zone.
Depends on D68521
Assignee | ||
Comment 13•5 years ago
|
||
Now that we have some per-zone vectors we can skip tracing those for zones that are not being collected.
Depends on D68522
Reporter | ||
Updated•5 years ago
|
Assignee | ||
Comment 14•5 years ago
|
||
Here is some data I gathered while browsing around to various news sites, giving the proportions of the various categories of holders (multi-zone, single zone non-wrapper, and single-zone wrapper) and the proportion of holders traced during GC. This shows that ~40% of holders are single-zone wrappers, and that these changes reduces the number of holders traced by nearly 20%.
Proportion of multi-zone holders:
Mean: 45.1% (of 223 samples)
0.0 - 0.1: 0.0%
0.1 - 0.2: 6.3% +++
0.2 - 0.3: 21.1% ++++++++++
0.3 - 0.4: 11.2% +++++
0.4 - 0.5: 17.0% ++++++++
0.5 - 0.6: 20.2% ++++++++++
0.6 - 0.7: 19.7% +++++++++
0.7 - 0.8: 2.7% +
0.8 - 0.9: 0.4%
0.9 - 1.0: 1.3%
Proportion of single-zone non-wrappers:
Mean: 15.9% (of 223 samples)
0.0 - 0.1: 30.0% +++++++++++++++
0.1 - 0.2: 40.4% ++++++++++++++++++++
0.2 - 0.3: 22.9% +++++++++++
0.3 - 0.4: 4.9% ++
0.4 - 0.5: 0.4%
0.5 - 0.6: 0.0%
0.6 - 0.7: 0.0%
0.7 - 0.8: 1.3%
0.8 - 0.9: 0.0%
0.9 - 1.0: 0.0%
Proportion of single-zone wrappers:
Mean: 39.0% (of 223 samples)
0.0 - 0.1: 9.9% ++++
0.1 - 0.2: 3.1% +
0.2 - 0.3: 25.6% ++++++++++++
0.3 - 0.4: 20.2% ++++++++++
0.4 - 0.5: 6.7% +++
0.5 - 0.6: 10.3% +++++
0.6 - 0.7: 16.1% ++++++++
0.7 - 0.8: 7.6% +++
0.8 - 0.9: 0.4%
0.9 - 1.0: 0.0%
Proportion of holders traced:
Mean: 81.5% (of 223 samples)
0.0 - 0.1: 0.0%
0.1 - 0.2: 0.0%
0.2 - 0.3: 3.1% +
0.3 - 0.4: 7.6% +++
0.4 - 0.5: 4.5% ++
0.5 - 0.6: 3.6% +
0.6 - 0.7: 10.3% +++++
0.7 - 0.8: 11.7% +++++
0.8 - 0.9: 2.2% +
0.9 - 1.0: 57.0% ++++++++++++++++++++++++++++
Comment 15•5 years ago
|
||
Comment 16•5 years ago
|
||
Backed out 6 changesets (bug 1425450) for hazard failure complaining about nsWrapperCacheInlines
Backout link: https://hg.mozilla.org/integration/autoland/rev/cd97938ad5404ec7936d8747a57e781eab9aad18
Failure log: https://treeherder.mozilla.org/logviewer.html#/jobs?job_id=296448871&repo=autoland&lineNumber=83333
[task 2020-04-06T18:02:30.952Z] Running explain to generate ('hazards.txt', 'unnecessary.txt', 'refs.txt')
[task 2020-04-06T18:02:30.952Z] ANALYZED_OBJDIR='/builds/worker/workspace/obj-analyzed' PATH="/builds/worker/fetches/sixgill/usr/bin:${PATH}" SOURCE='/builds/worker/checkouts/gecko' XDB='/builds/worker/fetches/sixgill/usr/bin/xdb.so' LD_LIBRARY_PATH="${LD_LIBRARY_PATH}:/builds/worker/workspace/obj-haz-shell/dist/bin" python2.7 /builds/worker/checkouts/gecko/js/src/devtools/rootAnalysis/explain.py rootingHazards.txt gcFunctions.txt hazards.txt unnecessary.txt refs.txt
[task 2020-04-06T18:02:33.614Z] Wrote explained_hazards.tmp
[task 2020-04-06T18:02:33.614Z] Wrote unnecessary.tmp
[task 2020-04-06T18:02:33.614Z] Wrote refs.tmp
[task 2020-04-06T18:02:33.614Z] Found 1 hazards 197 unsafe references 0 missing
[task 2020-04-06T18:02:33.615Z] Running heapwrites to generate heapWriteHazards.txt
[task 2020-04-06T18:02:33.615Z] ANALYZED_OBJDIR='/builds/worker/workspace/obj-analyzed' PATH="/builds/worker/fetches/sixgill/usr/bin:${PATH}" SOURCE='/builds/worker/checkouts/gecko' XDB='/builds/worker/fetches/sixgill/usr/bin/xdb.so' LD_LIBRARY_PATH="${LD_LIBRARY_PATH}:/builds/worker/workspace/obj-haz-shell/dist/bin" /builds/worker/workspace/obj-haz-shell/dist/bin/js /builds/worker/checkouts/gecko/js/src/devtools/rootAnalysis/analyzeHeapWrites.js > heapWriteHazards.txt
[task 2020-04-06T18:03:04.287Z] + check_hazards /builds/worker/workspace/analysis
[task 2020-04-06T18:03:04.287Z] + set +e
[task 2020-04-06T18:03:04.287Z] ++ grep -c 'Function.*has unrooted.*live across GC call' /builds/worker/workspace/analysis/rootingHazards.txt
[task 2020-04-06T18:03:04.288Z] + NUM_HAZARDS=1
[task 2020-04-06T18:03:04.289Z] ++ grep -c '^Function.*takes unsafe address of unrooted' /builds/worker/workspace/analysis/refs.txt
[task 2020-04-06T18:03:04.290Z] + NUM_UNSAFE=197
[task 2020-04-06T18:03:04.290Z] ++ grep -c '^Function.* has unnecessary root' /builds/worker/workspace/analysis/unnecessary.txt
[task 2020-04-06T18:03:04.292Z] + NUM_UNNECESSARY=1292
[task 2020-04-06T18:03:04.292Z] ++ grep -c '^Dropped CFG' /builds/worker/workspace/analysis/build_xgill.log
[task 2020-04-06T18:03:04.356Z] + NUM_DROPPED=0
[task 2020-04-06T18:03:04.356Z] ++ perl -lne 'print $1 if m!found (\d+)/\d+ allowed errors!' /builds/worker/workspace/analysis/heapWriteHazards.txt
[task 2020-04-06T18:03:04.358Z] + NUM_WRITE_HAZARDS=0
[task 2020-04-06T18:03:04.358Z] ++ grep -c '^Function.*expected hazard.*but none were found' /builds/worker/workspace/analysis/rootingHazards.txt
[task 2020-04-06T18:03:04.359Z] + NUM_MISSING=0
[task 2020-04-06T18:03:04.359Z] + set +x
[task 2020-04-06T18:03:04.359Z] TinderboxPrint: rooting hazards<br/>1
[task 2020-04-06T18:03:04.359Z] TinderboxPrint: (unsafe references to unrooted GC pointers)<br/>197
[task 2020-04-06T18:03:04.359Z] TinderboxPrint: (unnecessary roots)<br/>1292
[task 2020-04-06T18:03:04.359Z] TinderboxPrint: missing expected hazards<br/>0
[task 2020-04-06T18:03:04.359Z] TinderboxPrint: heap write hazards<br/>0
[task 2020-04-06T18:03:04.360Z] TEST-UNEXPECTED-FAIL | hazards | unrooted 'aNewWrapper' of type 'JSObject*' live across GC call at dom/base/nsWrapperCacheInlines.h:83
[task 2020-04-06T18:03:04.360Z] TEST-UNEXPECTED-FAIL | hazards | 1 rooting hazards detected
[task 2020-04-06T18:03:04.360Z] TinderboxPrint: documentation<br/><a href='https://wiki.mozilla.org/Javascript:Hazard_Builds#Diagnosing_a_rooting_hazards_failure'>static rooting hazard analysis failures</a>, visit "Inspect Task" link for hazard details
[task 2020-04-06T18:03:04.361Z] + onexit
Assignee | ||
Comment 17•5 years ago
|
||
The hazard failure is because it thinks nsWrapperCache::ReleaseWrapper can GC due to 'unresolved nsJSContext.CheckForRightParticipant'. This is a virtual method that's only present in debug builds. Steve, is can we can do to make the analysis ignore this?
Function '_ZN14nsWrapperCache25UpdateWrapperForNewGlobalI11nsISupportsEEvPT_P8JSObject$void nsWrapperCache::UpdateWrapperForNewGlobal(nsISupports*, JSObject*) [with T = nsISupports]' has unrooted 'aNewWrapper' of type 'JSObject*' live across GC call '_ZN14nsWrapperCache14ReleaseWrapperEPv$void nsWrapperCache::ReleaseWrapper(void*)' at dom/base/nsWrapperCacheInlines.h:83
nsWrapperCacheInlines.h:77: Call(1,2, preserving := this*.PreservingWrapper())
nsWrapperCacheInlines.h:79: Assume(2,3, preserving*, true)
nsWrapperCacheInlines.h:79: Call(3,4, __temp_2 := this*.GetWrapperPreserveColor())
nsWrapperCacheInlines.h:79: Call(4,5, __temp_1 := GetObjectZone(__temp_2*))
nsWrapperCacheInlines.h:80: Call(5,6, __temp_3 := GetObjectZone(aNewWrapper*))
nsWrapperCacheInlines.h:80: Assume(6,8, (__temp_1* !=p{JS::Zone} __temp_3*), false)
nsWrapperCacheInlines.h:79: Assign(8,9, zoneChanged := 0)
nsWrapperCacheInlines.h:82: Assume(9,10, zoneChanged*, true)
nsWrapperCacheInlines.h:83: Call(10,13, this*.ReleaseWrapper(aScriptObjectHolder*)) [[GC call]]
nsWrapperCacheInlines.h:88: Call(13,14, this*.SetWrapper(aNewWrapper*))
GC Function: _ZN14nsWrapperCache14ReleaseWrapperEPv$void nsWrapperCache::ReleaseWrapper(void*)
void mozilla::cyclecollector::DropJSObjectsImpl(void*)
void mozilla::CycleCollectedJSRuntime::RemoveJSHolder(void*)
nsScriptObjectTracer.Trace
void nsJSContext::cycleCollection::Trace(void*, TraceCallbacks*, void*)
nsJSContext* DowncastCCParticipant(void*) [with T = nsJSContext]
static T* DowncastCCParticipantImpl<T, true>::Run(void*) [with T = nsJSContext]
nsJSContext.CheckForRightParticipant
unresolved nsJSContext.CheckForRightParticipant
Comment 18•5 years ago
|
||
Ugh. There's no good reason for this to be unresolved. The real fix for that is bug 1531951 or one of the related patches. But that wouldn't fix this problem; there are implementations of that method that end up calling function pointers, and I'm not sure how many things I would need to annotate for that.
One option would be to make the call to CheckForRightParticipant
conditional on #if DEBUG && !defined(XGILL_PLUGIN)
. Or drop an AutoSuppressGCAnalysis
in there. Though ReleaseWrapper
is pretty broad. I'm not sure how many things you'll need to annotate away.
Assignee | ||
Comment 19•5 years ago
|
||
Currently we get a rooting hazard when nsWrapperCache::UpdateWrapperForNewGlobal calls ReleaseWrapper because the analysis can't see through the virtual method call.
Comment 20•5 years ago
|
||
Comment 21•5 years ago
|
||
bugherder |
https://hg.mozilla.org/mozilla-central/rev/a2c02d53b1cc
https://hg.mozilla.org/mozilla-central/rev/9fb011842691
https://hg.mozilla.org/mozilla-central/rev/9a855d95e393
https://hg.mozilla.org/mozilla-central/rev/9acbb61cea06
https://hg.mozilla.org/mozilla-central/rev/994b23b5ec49
https://hg.mozilla.org/mozilla-central/rev/fe4ab7f39aa3
https://hg.mozilla.org/mozilla-central/rev/b7cb030562f1
Description
•