Currently LazyScripts and JSScripts form a messy sort of partial bijection of pointers. Each LazyScript delazifies to a specific JSScript -- which may already exist. Some JSScripts can relazify back to a specific LazyScript that was our previous lazy form.
These types are two forms that a single abstract interpreted-script morphs between. I propose we unify them into a single type with a single pointer identity.
Looking at the contents of these structs, we see that 6 x uint32_t and 1 x GCPtr are directly duplicates when both scripts exists (non-lazy leaf functions). There is also a GCPtr in each type pointing to each other that would be shared. This would give some amount of memory savings on pages with lots of JS.
One concern of sharing types is that we might end up with the maximum size of both types. We can mitigate this by realizing that every JSScript has a required variable-length allocation for PrivateScriptData into which we would more many JSScript fields. A number of JSScript fields are also planned to move to SharedScriptData in Bug 1471062. In a LazyScript we have an optional |void* table_| for non-trivial cases where data could be stored. This brings us down to roughly three fields that may be candidates for a simple union.
The primary motivation for this change is to simplify the engines handling of script representation. The following are a few areas that simplify.
A JSFunction uses flags to decide if its current target is a LazyScript or JSScript and requires de-/re-lazification to update those bits. One very large wrinkle here is that function cloning can lead to many JSFunctions having a different (transient) notion of the current status. Currently there is a lot of complexity to keep this all working. When JSScript / LazyScript become fused, we can transfer the flag out of the JSFunction and confirm lazy-status to script itself. This should also allow non-leaf functions to safely lazify.
One big area of difficulty is that we have many script flags for various reasons -- parsing, embedding, runtime, optimization -- that exist in different forms and different subsets on LazyScript and JSScript. This is further compounded heavily by the multiple ways we create scripts: Parsing, BinAST, Cloning, XDR. This is even further exacerbated by GC/debugger/code-coverage using CellIters and accessing this constructs in partial states. Unsurprisingly, there have been many frustrating bugs around these flags and continue to be (I've found three more this week..). In the merged data type, JSScript::ImmutableFlags/MutableFlags are shared by both lazy and non-lazy states.
We will also be able to easily move jitCodeRaw_ to the shared structure and add an automatic delazification trampoline (similar to the interpreter one) for the JITs to use instead of de-optimizing.
Feedback welcome. Many of the patches I'm working on are worth landing regardless because they fix bugs and simplify existing code.