Bug 223613 - JSGlobalObject's m_customGetterFunctionMap and m_customSetterFunctionMap should be sets, not maps, and should use both the identifier and function pointer as the key
Summary: JSGlobalObject's m_customGetterFunctionMap and m_customSetterFunctionMap shou...
Status: RESOLVED FIXED
Alias: None
Product: WebKit
Classification: Unclassified
Component: JavaScriptCore (show other bugs)
Version: Other
Hardware: Unspecified Unspecified
: P2 Normal
Assignee: Sam Weinig
URL:
Keywords: InRadar
Depends on:
Blocks: 222518
  Show dependency treegraph
 
Reported: 2021-03-22 17:04 PDT by Sam Weinig
Modified: 2021-03-30 19:55 PDT (History)
16 users (show)

See Also:


Attachments
Patch (45.92 KB, patch)
2021-03-27 11:29 PDT, Sam Weinig
ews-feeder: commit-queue-
Details | Formatted Diff | Diff
Patch (46.46 KB, patch)
2021-03-27 18:38 PDT, Sam Weinig
ews-feeder: commit-queue-
Details | Formatted Diff | Diff
Patch (47.13 KB, patch)
2021-03-27 18:47 PDT, Sam Weinig
no flags Details | Formatted Diff | Diff
Patch (47.44 KB, patch)
2021-03-28 09:18 PDT, Sam Weinig
no flags Details | Formatted Diff | Diff
Patch (47.19 KB, patch)
2021-03-28 11:42 PDT, Sam Weinig
no flags Details | Formatted Diff | Diff
Patch (47.22 KB, patch)
2021-03-30 13:56 PDT, Sam Weinig
ews-feeder: commit-queue-
Details | Formatted Diff | Diff
Patch (47.22 KB, patch)
2021-03-30 14:10 PDT, Sam Weinig
no flags Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Sam Weinig 2021-03-22 17:04:47 PDT
JSGlobalObject's m_customGetterFunctionMap and m_customSetterFunctionMap should be sets, not maps, and should use both the identifier and function pointer as the key.

This will allow WebCore to use the same custom getter and setter functions for multiple attributes, as is needed for CSSStyleDeclaration.
Comment 1 Alexey Shvayka 2021-03-22 17:11:34 PDT
(In reply to Sam Weinig from comment #0)
> JSGlobalObject's m_customGetterFunctionMap and m_customSetterFunctionMap
> should be sets, not maps, and should use both the identifier and function
> pointer as the key.

Could please expand why they need to be sets, and if so, how JSFunctions would be stored? Agreed on the second part though.
Comment 2 Sam Weinig 2021-03-22 17:17:21 PDT
(In reply to Alexey Shvayka from comment #1)
> (In reply to Sam Weinig from comment #0)
> > JSGlobalObject's m_customGetterFunctionMap and m_customSetterFunctionMap
> > should be sets, not maps, and should use both the identifier and function
> > pointer as the key.
> 
> Could please expand why they need to be sets, and if so, how JSFunctions
> would be stored? Agreed on the second part though.

Right, I forgot to explain that part :).

If we just change m_customGetterFunctionMap (and m_customSetterFunctionMap) from:

WeakGCMap<GetValueFunc, JSCustomGetterFunction>

to

WeakGCMap<std::pair<PropertyName, GetValueFunc>, JSCustomGetterFunction> 

we would increase the size of the maps considerably.

But, if we can use a set instead, we could take advantage of the fact that the JSCustomGetterFunction already stores the PropertyName and GetValueFunc. And thus, rather than increase size, we could actually make these a bit smaller, since the buckets would now just be Weak<JSCustomGetterFunction>.

The problem is there isn't a WeakGCSet class yet, so I'll have to figure out if it's possible to make one for a case like this.
Comment 3 Alexey Shvayka 2021-03-22 17:25:07 PDT
(In reply to Sam Weinig from comment #2)
> But, if we can use a set instead, we could take advantage of the fact that
> the JSCustomGetterFunction already stores the PropertyName and GetValueFunc.
> And thus, rather than increase size, we could actually make these a bit
> smaller, since the buckets would now just be Weak<JSCustomGetterFunction>.

Oh, thanks, makes total sense.

Wouldn't that slow down the value lookup to O(N)? If so, I guess it's tolerable for Object.getOwnPropertyDescriptor().
Comment 4 Sam Weinig 2021-03-22 17:34:54 PDT
(In reply to Alexey Shvayka from comment #3)
> (In reply to Sam Weinig from comment #2)
> > But, if we can use a set instead, we could take advantage of the fact that
> > the JSCustomGetterFunction already stores the PropertyName and GetValueFunc.
> > And thus, rather than increase size, we could actually make these a bit
> > smaller, since the buckets would now just be Weak<JSCustomGetterFunction>.
> 
> Oh, thanks, makes total sense.
> 
> Wouldn't that slow down the value lookup to O(N)? If so, I guess it's
> tolerable for Object.getOwnPropertyDescriptor().

I don't think so, but perhaps you are thinking of something I have missed. It should still be O(1). It's essentially just going from 

   HashMap<GetValueFunc, Weak<JSCustomGetterFunction>> 

to 

   HashSet<Weak<JSCustomGetterFunction>, CustomHashTraits>


The question is, can I figure out how to make that work (I am not convinced I can).
Comment 5 Alexey Shvayka 2021-03-22 17:43:34 PDT
(In reply to Sam Weinig from comment #4)
> I don't think so, but perhaps you are thinking of something I have missed.
> It should still be O(1). It's essentially just going from 

To preserve identity, JSObject::getOwnPropertyDescriptor() tries to lookup already created JSCustomGetterFunction by given GetValueFunc.

I might be totally missing something obvious, but is it possible to do that quickly with HashSet<Weak<JSCustomGetterFunction>, CustomHashTraits>, without iterating all the entries?
Comment 6 Alexey Shvayka 2021-03-22 17:47:34 PDT
(In reply to Alexey Shvayka from comment #5)
> I might be totally missing something obvious, but is it possible to do that
> quickly with HashSet<Weak<JSCustomGetterFunction>, CustomHashTraits>,
> without iterating all the entries?

Oh, I see, we can use CustomHashTraits for that.
Comment 7 Alexey Shvayka 2021-03-22 17:53:25 PDT
(In reply to Sam Weinig from comment #4)
>    HashSet<Weak<JSCustomGetterFunction>, CustomHashTraits>
> 
> 
> The question is, can I figure out how to make that work (I am not convinced
> I can).

Yeah, we could also use this approach to replace WeakGCMaps that were introduced in r274528; their std::pair<> keys are stored unnecessarily.
Comment 8 Sam Weinig 2021-03-22 17:55:35 PDT
An amusing list of all the classes that are not really what I want here:

JSC::WeakSet
JSC::WeakMapImpl
JSC::WeakGCMap
JSC::JSWeakSet
JSC::JSWeakMap
WTF::WeakHashSet
Comment 9 Yusuke Suzuki 2021-03-22 18:05:20 PDT
Note that JITThunks is doing this for NativeExecutable.
Comment 10 Sam Weinig 2021-03-27 11:29:37 PDT
Created attachment 424459 [details]
Patch
Comment 11 Sam Weinig 2021-03-27 11:30:07 PDT
Ok, here is an initial shot at this, let's see how badly this breaks things.
Comment 12 Sam Weinig 2021-03-27 18:16:16 PDT
(In reply to Sam Weinig from comment #11)
> Ok, here is an initial shot at this, let's see how badly this breaks things.

Looks like reinserting on hash table expand is asserting. I'm guessing I didn't get WeakCustomGetterOrSetterHash::equal quite right.
Comment 13 Sam Weinig 2021-03-27 18:18:55 PDT
(In reply to Sam Weinig from comment #12)
> (In reply to Sam Weinig from comment #11)
> > Ok, here is an initial shot at this, let's see how badly this breaks things.
> 
> Looks like reinserting on hash table expand is asserting. I'm guessing I
> didn't get WeakCustomGetterOrSetterHash::equal quite right.

Interesting, there is generic support in WTF::HashTable added for WeakPtr, which allows removing reaped weak pointers on expand. Seems useful, but not needed since we have the pruning.
Comment 14 Sam Weinig 2021-03-27 18:38:41 PDT Comment hidden (obsolete)
Comment 15 Sam Weinig 2021-03-27 18:47:15 PDT
Created attachment 424479 [details]
Patch
Comment 16 Alexey Shvayka 2021-03-28 03:50:07 PDT
Comment on attachment 424479 [details]
Patch

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

This patch looks great! Really appreciate your detailed ChangeLogs. I would defer r+ to a reviewer more knowledgeable on Source/WTF though.

> Source/JavaScriptCore/runtime/WeakGCSet.h:74
> +        return result.iterator->get();

WeakGCMap::ensureValue() has a null check here; without it, a few LayoutTests were crashing (https://bugs.webkit.org/show_bug.cgi?id=222739#c14).
r274911 fixed functor not to invoke GC, but did it eliminate the possibility of returning a zombie (non-pruned) value here?
If so, should we add an ASSERT here and, maybe, remove the null check from WeakGCMap::ensureValue()
Comment 17 Sam Weinig 2021-03-28 09:18:56 PDT
Created attachment 424499 [details]
Patch
Comment 18 Sam Weinig 2021-03-28 09:19:58 PDT
(In reply to Sam Weinig from comment #17)
> Created attachment 424499 [details]
> Patch

Added a version that utilizes the HashTraits::isReleasedWeakValue() function ensure released weak values don't survive rehashes.
Comment 19 Sam Weinig 2021-03-28 09:21:14 PDT
(In reply to Alexey Shvayka from comment #16)
> Comment on attachment 424479 [details]
> Patch
> 
> View in context:
> https://bugs.webkit.org/attachment.cgi?id=424479&action=review
> 
> This patch looks great! Really appreciate your detailed ChangeLogs. I would
> defer r+ to a reviewer more knowledgeable on Source/WTF though.
> 
> > Source/JavaScriptCore/runtime/WeakGCSet.h:74
> > +        return result.iterator->get();
> 
> WeakGCMap::ensureValue() has a null check here; without it, a few
> LayoutTests were crashing
> (https://bugs.webkit.org/show_bug.cgi?id=222739#c14).
> r274911 fixed functor not to invoke GC, but did it eliminate the possibility
> of returning a zombie (non-pruned) value here?
> If so, should we add an ASSERT here and, maybe, remove the null check from
> WeakGCMap::ensureValue()

I think that only matters for the map version, since the key can still match if the weak value has been released. In the set version, that can't happen as the key is the value, and therefor if it got released, it can't possibly match.
Comment 20 Sam Weinig 2021-03-28 11:42:47 PDT
Created attachment 424505 [details]
Patch
Comment 21 Radar WebKit Bug Importer 2021-03-29 17:05:20 PDT
<rdar://problem/75980689>
Comment 22 Saam Barati 2021-03-30 13:44:46 PDT
Comment on attachment 424505 [details]
Patch

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

Nice. r=me

> Source/JavaScriptCore/runtime/JSObject.cpp:3528
> +    using Key = std::tuple<PropertyName, typename T::CustomFunctionPointer>;

nit: std::pair might be a smidge nicer?

> Source/JavaScriptCore/runtime/WeakGCSet.h:36
> +template<typename T> struct WeakGCSetHashTraits : HashTraits<Weak<T>> {

style nit: Maybe  "template<typename T>" on its own line?

> Source/WTF/ChangeLog:8
> +        Adds a heterogenous HashSet::ensure, which allows lazy construction of the value to

nice!
Comment 23 Sam Weinig 2021-03-30 13:56:26 PDT
Created attachment 424690 [details]
Patch
Comment 24 Sam Weinig 2021-03-30 14:10:45 PDT
Created attachment 424694 [details]
Patch
Comment 25 Alexey Shvayka 2021-03-30 14:21:38 PDT
idlharness.js uses Object.getOwnPropertyDescriptor() to tests getter / setter presence, and it's also heavy on memory. Can this flaky failures (not timeouts) be related to the change?

imported/w3c/web-platform-tests/xhr/idlharness.any.worker.html:

  https://ews-build.webkit.org/#/builders/56/builds/4449
  https://ews-build.webkit.org/#/builders/56/builds/4471
  https://ews-build.webkit.org/#/builders/56/builds/4475

imported/w3c/web-platform-tests/FileAPI/idlharness.worker.html:

  https://ews-build.webkit.org/#/builders/56/builds/4471

Should we run these tests locally with --slowPathAllocsBetweenGCs=10 JSC option and --repeat-each=100 to ensure that all descriptors are correctly reported?
Comment 26 Sam Weinig 2021-03-30 14:39:32 PDT
Eek, good catch. Seems possible.
Comment 27 Sam Weinig 2021-03-30 14:40:24 PDT
Any idea how to see those failures? I can no longer understand the results website well enough to figure out where to find them.
Comment 28 Alexey Shvayka 2021-03-30 14:51:27 PDT
(In reply to Sam Weinig from comment #27)
> Any idea how to see those failures? I can no longer understand the results
> website well enough to figure out where to find them.

According to the log, EWS does create pretty diffs of flaky failures but doesn't upload them if there no confirmed regressions.
Comment 29 Sam Weinig 2021-03-30 15:48:28 PDT
(In reply to Alexey Shvayka from comment #28)
> (In reply to Sam Weinig from comment #27)
> > Any idea how to see those failures? I can no longer understand the results
> > website well enough to figure out where to find them.
> 
> According to the log, EWS does create pretty diffs of flaky failures but
> doesn't upload them if there no confirmed regressions.

Ok, will rebuild locally and see if I can repro.
Comment 30 Sam Weinig 2021-03-30 19:25:44 PDT
(In reply to Alexey Shvayka from comment #25)
> idlharness.js uses Object.getOwnPropertyDescriptor() to tests getter /
> setter presence, and it's also heavy on memory. Can this flaky failures (not
> timeouts) be related to the change?
> 
> imported/w3c/web-platform-tests/xhr/idlharness.any.worker.html:
> 
>   https://ews-build.webkit.org/#/builders/56/builds/4449
>   https://ews-build.webkit.org/#/builders/56/builds/4471
>   https://ews-build.webkit.org/#/builders/56/builds/4475
> 
> imported/w3c/web-platform-tests/FileAPI/idlharness.worker.html:
> 
>   https://ews-build.webkit.org/#/builders/56/builds/4471
> 
> Should we run these tests locally with --slowPathAllocsBetweenGCs=10 JSC
> option and --repeat-each=100 to ensure that all descriptors are correctly
> reported?

What does one do to get --slowPathAllocsBetweenGCs=10 in WTR? I could just set it in code and recompile, but if there is a way to enable it from the command line, that would be great (I don't see it in run-webkit-tests --help).
Comment 31 Sam Weinig 2021-03-30 19:27:30 PDT
(In reply to Sam Weinig from comment #29)
> (In reply to Alexey Shvayka from comment #28)
> > (In reply to Sam Weinig from comment #27)
> > > Any idea how to see those failures? I can no longer understand the results
> > > website well enough to figure out where to find them.
> > 
> > According to the log, EWS does create pretty diffs of flaky failures but
> > doesn't upload them if there no confirmed regressions.
> 
> Ok, will rebuild locally and see if I can repro.

I'm not seeing it locally, so I am just going to land this and see if shows up. Might have been unrelated.
Comment 32 EWS 2021-03-30 19:55:43 PDT
Committed r275261: <https://commits.webkit.org/r275261>

All reviewed patches have been landed. Closing bug and clearing flags on attachment 424694 [details].