Bug 208382

Summary: Garbage collection prevents FontFace.loaded promise from getting resolved
Product: WebKit Reporter: Alexey Proskuryakov <ap>
Component: TextAssignee: Chris Dumez <cdumez>
Status: RESOLVED FIXED    
Severity: Normal CC: cdumez, commit-queue, esprehn+autocc, ews-watchlist, glenn, gyuyoung.kim, keith_miller, kondapallykalyan, macpherson, mark.lam, menard, mmaxfield, rniwa, webkit-bug-importer, ysuzuki
Priority: P2 Keywords: InRadar
Version: Other   
Hardware: Unspecified   
OS: Unspecified   
See Also: https://bugs.webkit.org/show_bug.cgi?id=208383
Attachments:
Description Flags
layout test
none
Patch
none
Patch
none
Patch
none
Patch none

Description Alexey Proskuryakov 2020-02-28 10:39:20 PST
Created attachment 391991 [details]
layout test

We have some tests that use FontFace.loaded, and they fail (time out) when frequent garbage collection is forced with JSC_slowPathAllocsBetweenGCs=10. They also fail flakily on other bots.

Steps to reproduce:

Put attached test into LayoutTests, and run as:

run-webkit-tests --no-retry --dump-render-tree --additional-env-var=JSC_slowPathAllocsBetweenGCs=10 font-promises-gc.html

It should not time out, and should say "SUCCESS".
Comment 1 Alexey Proskuryakov 2020-02-28 10:48:11 PST
Presumably the promise needs to keep FontFace wrapper alive. I am not familiar with modern GC code enough to fix this in a reasonable amount of time.
Comment 2 Ryosuke Niwa 2020-02-28 11:17:35 PST
FontFace probably needs to be an active DOM object and make it have a pending activity while there is font loading happening
Comment 3 Ryosuke Niwa 2020-02-28 11:18:49 PST
We also need to make sure the promise object itself is kept alive in each DOM wrapper world too
Comment 4 Alexey Proskuryakov 2020-02-28 11:26:14 PST
> FontFace probably needs to be an active DOM object and make it have a pending activity while there is font loading happening

I'm not sure if that would be sufficient. Doesn't promise resolving need to work even when loading isn't happening (either not started, or already finished)?

As an aside, I found that custom properties on FontFace wrappers don't survive GC either.
Comment 5 Ryosuke Niwa 2020-02-28 11:56:50 PST
(In reply to Alexey Proskuryakov from comment #4)
> > FontFace probably needs to be an active DOM object and make it have a pending activity while there is font loading happening
> 
> I'm not sure if that would be sufficient. Doesn't promise resolving need to
> work even when loading isn't happening (either not started, or already
> finished)?

Sure.

> As an aside, I found that custom properties on FontFace wrappers don't
> survive GC either.

Not surprised. Almost all DOM objects have this bug because people don't know how GC works. FontFace isn't an ActiveDOMObject nor is it reachable from anything so yeah, it'd get GC'ed immediately.
Comment 6 Chris Dumez 2020-02-28 12:21:52 PST
Created attachment 392005 [details]
Patch
Comment 7 Keith Miller 2020-02-28 12:41:56 PST
(In reply to Ryosuke Niwa from comment #5)
> (In reply to Alexey Proskuryakov from comment #4)
> > As an aside, I found that custom properties on FontFace wrappers don't
> > survive GC either.
> 
> Not surprised. Almost all DOM objects have this bug because people don't
> know how GC works. FontFace isn't an ActiveDOMObject nor is it reachable
> from anything so yeah, it'd get GC'ed immediately.

I thought wrappers were handled by the wrapper map, which is careful to not GC wrappers when it would be observable?
Comment 8 Alexey Proskuryakov 2020-02-28 13:02:59 PST
Comment on attachment 392005 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=392005&action=review

> LayoutTests/fast/text/font-promises-gc.html:46
> +setInterval(function() {
> +    document.fonts.forEach(function(f) {
> +        console.log("Font status: " + f.status);
> +    });
> +}, 5000);

Delete this? Five seconds is hard to hit, but not impossible on a very busy bot.
Comment 9 Chris Dumez 2020-02-28 13:31:21 PST
Created attachment 392014 [details]
Patch
Comment 10 Chris Dumez 2020-02-28 13:31:38 PST
(In reply to Alexey Proskuryakov from comment #8)
> Comment on attachment 392005 [details]
> Patch
> 
> View in context:
> https://bugs.webkit.org/attachment.cgi?id=392005&action=review
> 
> > LayoutTests/fast/text/font-promises-gc.html:46
> > +setInterval(function() {
> > +    document.fonts.forEach(function(f) {
> > +        console.log("Font status: " + f.status);
> > +    });
> > +}, 5000);
> 
> Delete this? Five seconds is hard to hit, but not impossible on a very busy
> bot.

My bad :)
Comment 11 Ryosuke Niwa 2020-02-28 13:41:10 PST
Comment on attachment 392014 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=392014&action=review

> Source/WebCore/css/FontFace.cpp:490
> +    return !isContextStopped() && m_isScriptPotentiallyInterestedInLoad && !m_loadedPromise->isFulfilled();

Should we clear m_isScriptPotentiallyInterestedInLoad when we're fulfilled the promise?
Comment 12 Chris Dumez 2020-02-28 13:43:23 PST
Comment on attachment 392014 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=392014&action=review

>> Source/WebCore/css/FontFace.cpp:490
>> +    return !isContextStopped() && m_isScriptPotentiallyInterestedInLoad && !m_loadedPromise->isFulfilled();
> 
> Should we clear m_isScriptPotentiallyInterestedInLoad when we're fulfilled the promise?

It would not be observable since we call m_loadedPromise->isFulfilled() here. Are you concerned about someone using this boolean for something else later?
Comment 13 Ryosuke Niwa 2020-02-28 13:52:20 PST
(In reply to Chris Dumez from comment #12)
> Comment on attachment 392014 [details]
> Patch
> 
> View in context:
> https://bugs.webkit.org/attachment.cgi?id=392014&action=review
> 
> >> Source/WebCore/css/FontFace.cpp:490
> >> +    return !isContextStopped() && m_isScriptPotentiallyInterestedInLoad && !m_loadedPromise->isFulfilled();
> > 
> > Should we clear m_isScriptPotentiallyInterestedInLoad when we're fulfilled the promise?
> 
> It would not be observable since we call m_loadedPromise->isFulfilled()
> here. Are you concerned about someone using this boolean for something else
> later?

Yeah. Also, I also thought it's a misleading.

Maybe we can rename the variable to something like m_isPromisePotentiallyScriptObservable?
Comment 14 Ryosuke Niwa 2020-02-28 13:52:56 PST
I think the confusing part of m_isScriptPotentiallyInterestedInLoad is that it sort of implies the load hasn't happened yet.
Comment 15 Chris Dumez 2020-02-28 13:55:33 PST
Created attachment 392015 [details]
Patch
Comment 16 Chris Dumez 2020-02-28 16:26:25 PST
Created attachment 392031 [details]
Patch
Comment 17 WebKit Commit Bot 2020-02-28 17:48:32 PST
Comment on attachment 392031 [details]
Patch

Clearing flags on attachment: 392031

Committed r257676: <https://trac.webkit.org/changeset/257676>
Comment 18 WebKit Commit Bot 2020-02-28 17:48:34 PST
All reviewed patches have been landed.  Closing bug.
Comment 19 Radar WebKit Bug Importer 2020-02-28 17:49:16 PST
<rdar://problem/59910670>
Comment 20 Alexey Proskuryakov 2020-02-29 12:40:45 PST
This also fixed fast/text/font-weight-fallback.html when running with JSC_slowPathAllocsBetweenGCs. It's using the same pattern, didn't notice it for he workaround in bug 208383.