JavaScript:SpiderMonkey:GC Futures: Difference between revisions

Mark as Outdated
(Mark as Outdated)
 
(8 intermediate revisions by 3 users not shown)
Line 1: Line 1:
{{OutdatedSpiderMonkey}}
== JS GC Futures ==
== JS GC Futures ==


Line 58: Line 60:
|-
|-
| Compartmentalize Gecko
| Compartmentalize Gecko
| 2
| 3
| jorendorff
| jorendorff
|-
|-
Line 67: Line 69:
| MT wrappers
| MT wrappers
| 3
| 3
| jorendorff
| gal
|-
|-
| Lock-free allocation and slot access
| Lock-free allocation and slot access
| 1
| 1
| jorendorff
| gal
|-
|-
| Compartmental GC
| Compartmental GC
Line 88: Line 90:
'''GCSubheaps''' — Factor GC-related code into a class, js::GCHeap ({{bug|556324}}). Carve out a second class, GCSubheap, so that a single GCHeap can have several GCSubheaps, each of which handles its own set of VM pages from which individual GC things may be allocated. Give each compartment its own GCSubheap. Allocate every object, double, and string from the GCSubheap for the compartment where it will live.
'''GCSubheaps''' — Factor GC-related code into a class, js::GCHeap ({{bug|556324}}). Carve out a second class, GCSubheap, so that a single GCHeap can have several GCSubheaps, each of which handles its own set of VM pages from which individual GC things may be allocated. Give each compartment its own GCSubheap. Allocate every object, double, and string from the GCSubheap for the compartment where it will live.


'''MT wrappers''' — Implement an automatically-spreading membrane of proxy objects that allow one thread to access objects from another compartment that is running in another thread. There is some risk here because it's unclear how this should work regarding objects on the scope chain (global objects, Call and Block objects). See {{bug|558866}} comments 1-4.
'''MT wrappers''' — Implement an automatically-spreading membrane of proxy objects that allow one thread to access objects from another compartment that is running in another thread. There is some risk here because it's unclear how this should work regarding objects on the scope chain (global objects, Call and Block objects). See {{bug|558866}} comments 1-4. See also {{bug|566951}}, which has a prototype patch that addresses the scope chain issue.


'''Lock-free allocation and slot access''' — Remove locking from allocation paths. Remove scope locking everywhere. ({{bug|558866}})
'''Lock-free allocation and slot access''' — Remove locking from allocation paths. Remove scope locking everywhere. ({{bug|558866}})
Line 142: Line 144:
-->
-->


=== Compartments and wrappers - implementation details ===
=== Compartments and wrappers - API ===


Each runtime has a ''default compartment'' which contains interned strings (and, in non-compartment-aware embeddings, everything else).
Each runtime has a ''default compartment'' which contains interned strings, the empty string, +Inf, -Inf, NaN—and, in non-compartment-aware embeddings, everything else.


Each context has a ''current compartment'', initially the default compartment, and normally the compartment of JS_GetScopeChain(cx). So, for example, <code>js_Atomize(cx, name, strlen(name), 0)</code> allocates the new string from <code>cx->currentCompartment()</code>.
Each context has a ''current compartment'', initially the default compartment, and normally the compartment of JS_GetScopeChain(cx). So, for example, <code>js_Atomize(cx, name, strlen(name), 0)</code> allocates the new string from <code>cx->currentCompartment()</code>.


A tricky consequence of this is that the API function <code>JS_SetProperty(cx, obj, name, vp)</code> must put cx into obj's compartment before calling <code>js_Atomize</code>. Otherwise obj might end up with property ids in other compartments, a bad scene.
A tricky consequence of this is that in an API call <code>JS_SetProperty(cx, obj, name, vp)</code>, obj must be in <code>cx->currentCompartment()</code>, because <code>JS_SetProperty</code> calls <code>js_Atomize</code> to create the property id. Otherwise obj could end up with property ids that reside in <code>cx->currentCompartment()</code> rather than its own compartment: a violation of the rules that will lead to a crash in GC.
 
When does a context's current compartment need to change? Only when setting up a new compartment and when calling across compartment boundaries. The latter always happens in wrapper code. So this will be rare and we can require an API call and fall off trace when it happens.
 
JSCompartment *
JS_GetDefaultCompartment(JSRuntime *rt);
JSCompartment *
JS_NewCompartment(JSRuntime *rt, JSPrincipals *principals);
JSCompartment *
JS_GetCurrentCompartment(JSContext *cx);
void
JS_SetCurrentCompartment(JSContext *cx, JSCompartment *compartment);
 
All existing APIs could just assert that cx->currentCompartment() agrees with all the arguments that happen to be gc-things. The precise rule is: each gc-thing passed in must either be in <code>cx->currentCompartment()</code> or be a string or double in <code>cx->runtime->defaultCompartment</code>.
 
'''GC roots''' will be per-compartment. This means <code>JS_AddGCRootRT</code> will add a root to the default compartment. This behavior is a bit unexpected. To help embeddings get this right, GC should assert that each gc thing pointed to by a root is in the expected compartment.
 
'''API functions related to the GC heap.''' Several API functions do something that involves the GC heap: <code>JS_GC</code> and friends; <code>JS_SetGCCallback</code>; <code>JS_SetGCParameter</code>; <code>JS_TraceChildren</code> and friends; <code>JS_DumpHeap</code>; <code>JS_SetGCZeal</code>. These will need to have a mode for collecting/walking the entire heap and a separate mode where they apply to just one compartment. TBD.
 
'''Wrapper API.''' Since the cross-compartment reference from a wrapper to the wrappee is so special, we will need API for it. TBD.
 
== Emerging Invariants ==
 
This section describes invariants and rules which have emerged during initial development of the conservative GC and the compartments code. They are not likely to change, but still may.


When does a context's current compartment change? At API entry points and when a function is called across compartment boundaries (which always happens via a wrapper). So it will be rare and will not ordinarily happen on trace.
* The C stack is not scanned for GC roots when there are no contexts (suspended or otherwise) in requests on a given thread
* When doing a single-compartment GC, only the current thread's stack is scanned (unless there are no contexts in requests on that thread)
* A context's compartment is equal to JS_GetScopeChain(cx)->getCompartment. A NULL scope chain indicates the default compartment.
* Corollary: All non-default compartments have at least a global object.
* Only one thread per compartment may be in a request at any given time
52

edits