New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Constructor & prototype reform #133
Comments
I've personally done some testing with the heaviest-weight solution, which is reconstructing the entire set of wrapper classes for each realm. As you have predicted, it didn't quite scale too well even after enabling compile cache support through VM module, both in terms of memory and in processing time. (It did work though.) I'd like to raise an additional potential goal for this. We are currently failing many WPTs since the TypeErrors we throw are in fact from the root realm / global context, so If possible, I'd like to approach this iteratively, like finishing the first approach first and building the second on top of that work. The removal of WebIDL2JSFactory ext attr is enough of a win to me. I'd refrain from saying it is fully spec-compliant however, since based on what I'm reading |
Thanks for the feedback @TimothyGu. I wrote a proof-concept of the 2 approaches in an iterable fashion to flush out implementation uncertainties about those proposals. Approach 1: New constructor / Same prototypeCode changesObservationsAs expected more than 100 tests start failing. There are 2 types of test failures:
In light of those test failures, I don't think this approach is viable. Approach 2: New constructor / New prototypeCode changesObservationsThe approach 2 changes are layered on top of the approach 1 changes. Making this approach works in JSDOM requires a lot of changes (needed to touch more than 50 files). However, 100% of the WPT is now passing. Here is a couple of interesting finding regarding this proof-of-concept:
One of the areas of uncertainty was the performance impact of such change. This approach increases the interface creation time by 15% and increases the window object creation time by 75% (raw data). IMO, this is a fair price to pay to get isolation between realms. |
Glad to hear about the progress! I think the performance decrease is fine – certainly much better than my full isolation approach. The 100% passing WPT with phase 2 is especially encouraging. |
Thank you so much for looking in to this @pmdartus. This is truly heroic work on the foundational issues of jsdom that have been with us since the beginning, and it's so exciting and encouraging that you've been tackling them. I tend to agree new constructor / same prototype isn't really viable, and we should proceed with new constructor / new prototype. The remaining question is whether we want to preserve any mode of same constructor / same prototype, as in jsdom today. I guess such a mode would not have custom elements support, in exchange for faster operation. My initial gut feeling is that we should not preserve such a mode. We should just make the next major jsdom release have new constructors / new prototypes everywhere. Here are the contributing factors:
I know in jsdom/jsdom#2548 we were discussing a flag in order to land custom elements sooner. Given that I'd prefer not to do a release of jsdom with such a flag, what do you think the sequencing should be? Should we review + land custom elements first, then do constructor reform? Or should we review and land constructor reform first, and do custom elements on top of it? |
Based on the encouraging result of the constructor reform investigation, I think the most reasonable approach is to make it land before the custom elements. I will try to create a draft PR soon for us to discuss the new webidl2js API shape. |
This fixes #133 by implementing the proposal therein, which changes webidl2js's overall architecture. Now, the code generated by webidl2js installs new constructors and prototypes on a given global object, instead of exporting classes directly. See the updated README for more usage details, but a quick summary of the changes: * The generated files for interfaces now export an install(globalObject) function, instead of an interface property. * The create() and createImpl() exports now take a global object as their new first parameter, making the signature (globalObject, constructorArgs, privateData). * Similarly, impl class constructors now also take a global object as their first argument, given them the same signature. * The expose export was removed, as it was not generally used. We may introduce better support for exposure in the future, probably as an option to the install() export. * [WebIDL2JSFactory] was removed, as it is no longer necessary: all interfaces are now per-global object.
Context
Currently, the constructor and prototype chains are shared between all the realms. This approach has multiple downstream impacts:
[HTMLConstructor]
. WebIDL2JS also had to implement the[WebIDL2JSFactory]
IDL extended attribute to generate wrapper class per window object.While recreating a brand new wrapper class for each new realm won't scale, I think there might be other alternatives worth exploring.
Approach 1: New constructor / Same prototype
This approach consists of recreating a brand new constructor per realm and reuse the same prototype. WebIDL2JS would generate for all the interfaces annotated with the
[Exposed]
IDL extended attribute would aninstall
method that would be in charge of creating the interface in the context of the realm.You can find here an experimental branch with the code change: pmdartus/constructor
Pros:
[WebIDL2JSFactory]
anymore.[NamedConstructor]
.Cons:
(new Test()).constructor
points toTestGlobal
instead ofTest
, since the prototype is shared. When running the experimental WebIDL2JS against jsdom test, this issue made 5 tests failed.Approach 2: New constructor / New prototype
In this approach, a brand new constructor and prototype chain is created per realm. Instead of creating a brand new wrapper class per realm, like
[WebIDL2JSFactory]
, we would instead only create a new prototype chain but reuse the existing property descriptors. It also reuses the concept ofinstall
showed in proposal 1.The assumption here is that the performance cost of the creation of a prototype chain while reusing the existing descriptors is way lower than re-creating a brand new class per realm.
Pros:
[WebIDL2JSFactory]
anymore.[NamedConstructor]
.Cons:
create()
andcreateImpl()
invocations, for it to retrieve the right prototype associated with the realm.Before diving deeper into this, I would like getting some initial feedback on both approaches and see if it worth pursuing.
/cc @domenic @TimothyGu @Sebmaster @Zirro
The text was updated successfully, but these errors were encountered: