Bug 211595 - Code pattern in GC tests in LayoutTests is broken
Summary: Code pattern in GC tests in LayoutTests is broken
Status: RESOLVED FIXED
Alias: None
Product: WebKit
Classification: Unclassified
Component: DOM (show other bugs)
Version: WebKit Nightly Build
Hardware: Unspecified Unspecified
: P2 Normal
Assignee: Yusuke Suzuki
URL:
Keywords: InRadar
Depends on:
Blocks:
 
Reported: 2020-05-07 14:19 PDT by Yusuke Suzuki
Modified: 2020-05-08 12:58 PDT (History)
11 users (show)

See Also:


Attachments
Patch (29.06 KB, patch)
2020-05-07 17:58 PDT, Yusuke Suzuki
sbarati: review+
Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Yusuke Suzuki 2020-05-07 14:19:17 PDT
A lot of GC tests in LayoutTests are broken, they are not assuming that JavaScriptCore is using conservative GC.
Comment 1 Radar WebKit Bug Importer 2020-05-07 14:26:28 PDT
<rdar://problem/62993121>
Comment 2 Yusuke Suzuki 2020-05-07 14:33:46 PDT
These tests are doing,

1. Allocate one object
2. Invoking GC repeatedly until we observe that (1)'s object is collected

This is not the right approach. If we allocate only one object without using loop, it is very possible that this one object's address exists in some of CPU register in some case, and it is kept alive.

The right approach is,

1. Allocating many objects with loop. This ensures that stack / register can only include some of them. Not all of them. If the objects are allocated in a loop, then it is super possible that next iteration can overwrite the same register / stack location with new object, and old object is not in the conservative root (that's why we recommend using loop for GC test).
2. Invoking GC repeatedly, and check one of (1) is at least collected.
Comment 3 Yusuke Suzuki 2020-05-07 14:42:45 PDT
For example, LayoutTests/resize-observer/element-leak.html is great.
Comment 4 Yusuke Suzuki 2020-05-07 17:58:36 PDT
Created attachment 398820 [details]
Patch
Comment 5 Saam Barati 2020-05-07 18:24:16 PDT
Comment on attachment 398820 [details]
Patch

r=me
Comment 6 Keith Miller 2020-05-07 18:30:20 PDT
Comment on attachment 398820 [details]
Patch

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

r=me with some comments.

> LayoutTests/ChangeLog:19
> +        This is not being a problem in practice. Web pages are executing various kind of code and they clobber conservative roots. However, tests in

Typo: This is not being a => This is not a

> LayoutTests/ChangeLog:30
> +            3. Repeatedly invoke GC and test whether *one of (1) iframes* gets collected at least. Theoretically this is still possible that completely
> +               unrelated integer value in conservative roots can point to the reference of (1). By allocating many iframes in (1) and testing one of them,
> +               we can reduce the possibility of this conflict.

I have a minor quip with this approach. I think you should only have to invoke GC once. If the first GC fails I doubt any subsequent ones will do any better. Ideally, it would also be an async GC so as much of the stack can be cleared as possible. Maybe we should provide such an API to WebCore? It could be as simple as `setTimeout(syncGC, 0)`

> LayoutTests/http/tests/resources/gc.js:53
> +        await waitFor(50);

Why do we need the await? isn't gc() sync?
Comment 7 Yusuke Suzuki 2020-05-07 18:47:48 PDT
Comment on attachment 398820 [details]
Patch

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

>> LayoutTests/ChangeLog:19
>> +        This is not being a problem in practice. Web pages are executing various kind of code and they clobber conservative roots. However, tests in
> 
> Typo: This is not being a => This is not a

Fixed.

>> LayoutTests/ChangeLog:30
>> +               we can reduce the possibility of this conflict.
> 
> I have a minor quip with this approach. I think you should only have to invoke GC once. If the first GC fails I doubt any subsequent ones will do any better. Ideally, it would also be an async GC so as much of the stack can be cleared as possible. Maybe we should provide such an API to WebCore? It could be as simple as `setTimeout(syncGC, 0)`

I think it would be possible that multiple GC cycles can be effective.
For example,

1. An object has Strong<> or something in its field while it is correctly handled to make non-cyclic leak
2. First GC makes this object dead
3. The destructor of (2) will destroy Strong<>
4. Then, the second GC makes held object of Strong<> dead

>> LayoutTests/http/tests/resources/gc.js:53
>> +        await waitFor(50);
> 
> Why do we need the await? isn't gc() sync?

Three reasons,

1. This `gc()` is async
2. Want to continue the next iteration in the new macro-task (setTimeout) to ensure that RunLoop is iterated (and stack is once cleared)
3. Because the original code was using this :)
Comment 8 Yusuke Suzuki 2020-05-08 10:14:24 PDT
Committed r261391: <https://trac.webkit.org/changeset/261391>
Comment 9 Yusuke Suzuki 2020-05-08 12:58:40 PDT
Note that I picked 20 iframe count which comes from resize-observer/element-leak.html.
And I've ensured that this is enough at least for Release builds in my local environment. But not sure how it is in Debug builds (it will generate code which uses CPU registers / stack in a different manner).
At least, in EWS, they are not failing. But if we still see the flakiness, we will increase it a bit. But I believe 20 is enough.