findReferences(thing)
Walk the entire heap, looking for references to |thing|, and return a
"references object" describing what we found.
Each property of the references object describes one kind of reference. The
property's name is the label supplied to MarkObject, JS_CALL_TRACER, or what
have you, prefixed with "edge: " to avoid collisions with system properties
(like "toString" and "__proto__"). The property's value is an array of things
that refer to |thing| via that kind of reference. Ordinary references from
one object to another are named after the property name (with the "edge: "
prefix).
Garbage collection roots appear as references from 'null'. We use the name
given to the root (with the "edge: " prefix) as the name of the reference.
Note that the references object does record references from objects that are
only reachable via |thing| itself, not just the references reachable
themselves from roots that keep |thing| from being collected. (We could make
this distinction if it is useful.)
If any references are found by the conservative scanner, the references
object will have a property named "edge: machine stack"; the referrers will
be 'null', because they are roots.
js> var o = { x: { y: { z: {} } }}
js> findReferences(o.x.y.z)
({'edge: z':[{z:{}}], 'edge: machine stack':[null, null, null, null, null]})
js> o = { get x() { return 42 } }
({get x () {return 42;}})
js> findReferences(Object.getOwnPropertyDescriptor(o, 'x').get)
({'edge: shape; x getter':[{get x () {return 42;}}],
'edge: constructor':[{}],
'edge: machine stack':[null, null, null, null, null],
'edge: get':[{configurable:true,
enumerable:true,
get:#1=(function () {return 42;}),
set:(void 0)}]})
js> findReferences(Math.atan2)
({'edge: atan2':[Math], 'edge: machine stack':[null, null, null, null, null]})
js> findReferences(o)
({'edge: o':[{o:{get x () {return 42;}}}], 'edge: machine stack':[null, null, null, null, null]})
js>
mozalloc_undef_macro_wrappers are brittle and have side-effects that are hard
to debug and fix. The alternative is the just stick an underscore on the end of
malloc, free, etc, which is a comparatively small burden.
This changes the allocation API, in the following way:
js_malloc -> {cx->,rt->,OffTheBooks::}malloc
js_calloc -> {cx->,rt->,OffTheBooks::}calloc
js_realloc -> {cx->,rt->,OffTheBooks::}realloc
js_free -> {cx->,rt->,Foreground::,UnwantedForeground::}free
js_new -> {cx->,rt->,OffTheBooks::}new_
js_new_array -> {cx->,rt->,OffTheBooks::}new_array
js_delete -> {cx->,rt->,Foreground::,UnwantedForeground::}delete_
This is to move as many allocations as possible through a JSContext (so that they may be aken into account by gcMallocBytes) and to move as many deallocations to the background as possible (except on error paths).