JSObject Makeover

From MozillaWiki
Jump to: navigation, search

Spun out from [1].

JSObject background/notes

  • at first the GC allocated only pairs (cons cells), all slots were dslots
  • split dslots from fslots, then class into its own classword
    • no point in scanning PRIVATE-tagged class fslot
    • DELEGATE and SYSTEM bits fit in classword
  • GC size class limitations eliminated for fslots split, but still few classes
  • map -> scope is not needed for small objects
    • optimization to avoid scope hashtable could be taken further: store lastProp in object instead of scope

JSObjectOps background/notes

  • came years after JSClass
    • hence optional JSClass.getObjectOps, "upside-down" new object protocol
  • leaky abstraction to let LiveConnect specialize object behavior not hooked via JSClass
  • object (scope) locking if JS_THREADSAFE under the JSObjectOps layer
    • generally; again the layering broke down in a few places
    • making upper layer lock-free still a worthwhile goal -- atomic object ops, fine grained locking, lock-free objects
  • reluctance to add more ops back in the ABI-matters-for-Netscape (servers as well as client) days

Possible JSObject changes

  • ops belongs on obj, not map
  • shape belongs on obj, not map, for cache-ready object types
    • this makes a many-from-one update problem when regenerating shape
    • alternative idea: share scope among all same-shaped objects in a thread
  • obj should be something we can easily subclass, as we do with JSFunction
    • this may require more size classes in the GC allocator

Possible JSObjectOps changes

  • New ops "getPropertyForCache", etc. that populate the property cache. The interpreter/recorder would only call these on a cache miss.
  • New ops for stuff like "hasInstance", "hasProperty", "hasOwnProperty", so that (a) lookupProperty isn't quite so overloaded and thus doesn't have to use cx->resolveFlags and bytecode inspection; (b) we can do everything we need to do to an object via ops, so objects are wrappable and ops are easily stackable.
  • Another alternative is to replace JSObjectOps with a tag describing nature of the object and then call specialized methods based on the tag and types of arguments. This would closely reflect what the current code is doing with explicit _IS_NATIVE or _IS_XML checks. It would also match the tracer with its generation of explicit guards on object's type.

Note that the current machinery avoids recursing on the C stack by iterating instead when the prototype _IS_NATIVE. If we plan to wrap and stack freely, we'll want to avoid recursion in a less hackish way, e.g. by designing the ops to do tail calls or by making some ops refer only to "own" properties.

(The lookup design has to be able to optimize across same-ops proto chains. This is the requirement that results in what may seem hackish but is (as you suggest) really tail call flattening into iteration. You can see where a non-native object along the chain causes js_LookupPropertyWithFlags to vector off into the foreign ops' lookupProperty hook. /be)

Possible JSAPI changes

  • Stop exposing JSObjectOps via jsapi.h. bug 483473
    • Huzzah! let's do this now.
  • Start phasing out JSClass from the API too. Deprecate JSExtendedClass. (Once we have ops for everything, I think we can mostly stop using JSClass internally too. Depends on a few things.)
  • Add a stable API (to replace JS_InitClass) for creating a constructor from a static class-description. This would create a new JSObjectOps behind the scenes. Individual class-description features could come and go without requiring API changes that would affect code not using those features.
  • Add an API for creating objects from constructors, as though with new constructor(args).
  • Add a stable API for wrapping objects (and maybe for hacking objects via stackable JSObjectOps).
  • Kill resolve flags, of course. Deprecate JS_LookupPropertyWithFlags.
    • The DOM requires JSRESOLVE_ASSIGNING and JSRESOLVE_QUALIFIED or equivalents; don't reinvent as round a wheel!
    • If we need the resolve advice for the DOM, is this really about killing bytecode inspection?