Bug 1503994 - Fixup js Proxy doc comments r=jandem

Differential Revision: https://phabricator.services.mozilla.com/D10716

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Ted Campbell 2018-11-05 09:09:45 +00:00
parent ca7afcc659
commit 8c500290c1
2 changed files with 55 additions and 36 deletions

View File

@ -45,7 +45,7 @@ class JS_FRIEND_API(Wrapper);
* wanted. Proxies are used to implement:
*
* - the scope objects used by the Debugger's frame.eval() method
* (see js::GetDebugScopeForFunction)
* (see js::GetDebugEnvironment)
*
* - the khuey hack, whereby a whole compartment can be blown away
* even if other compartments hold references to objects in it
@ -62,9 +62,9 @@ class JS_FRIEND_API(Wrapper);
*
* ### Proxies and internal methods
*
* ES2016 specifies 13 internal methods. The runtime semantics of just
* about everything a script can do to an object is specified in terms
* of these internal methods. For example:
* ES2019 specifies 13 internal methods. The runtime semantics of just about
* everything a script can do to an object is specified in terms of these
* internal methods. For example:
*
* JS code ES6 internal method that gets called
* --------------------------- --------------------------------
@ -75,22 +75,30 @@ class JS_FRIEND_API(Wrapper);
* With regard to the implementation of these internal methods, there are three
* very different kinds of object in SpiderMonkey.
*
* 1. Native objects' internal methods are implemented in vm/NativeObject.cpp,
* with duplicate (but functionally identical) implementations scattered
* through the ICs and JITs.
* 1. Native objects cover most objects and contain both internal slots and
* properties. ClassOps and ObjectOps may be used to override certain
* default behaviors.
*
* 2. Certain non-native objects have internal methods that are implemented as
* magical js::ObjectOps hooks. We're trying to get rid of these.
* 2. Proxy objects are composed of internal slots and a ProxyHandler. The
* handler contains C++ methods that can implement these standard (and
* non-standard) internal methods. ClassOps and ObjectOps for the base
* ProxyObject invoke the handler methods as appropriate.
*
* 3. All other objects are proxies. A proxy's internal methods are
* implemented in C++, as the virtual methods of a C++ object stored on the
* proxy, known as its handler.
* 3. Objects with custom layouts like TypedObjects. These rely on ClassOps
* and ObjectOps to implement internal methods.
*
* This means that just about anything you do to a proxy will end up going
* through a C++ virtual method call. Possibly several. There's no reason the
* JITs and ICs can't specialize for particular proxies, based on the handler;
* but currently we don't do much of this, so the virtual method overhead
* typically is actually incurred.
* Native objects with custom ClassOps / ObjectOps are used when the object
* behaves very similar to a normal object such as the ArrayObject and it's
* length property. Most usages wrapping a C++ or other type should prefer
* using a Proxy. Using the proxy approach makes it much easier to create an
* ECMAScript and JIT compatible object, particularly if using an appropriate
* base class.
*
* Just about anything you do to a proxy will end up going through a C++
* virtual method call. Possibly several. There's no reason the JITs and ICs
* can't specialize for particular proxies, based on the handler; but currently
* we don't do much of this, so the virtual method overhead typically is
* actually incurred.
*
* ### The proxy handler hierarchy
*
@ -104,40 +112,47 @@ class JS_FRIEND_API(Wrapper);
*
* BaseProxyHandler
* |
* Wrapper // has a target, can be unwrapped to reveal
* | // target (see js::CheckedUnwrap)
* ForwardingProxyHandler // has a target and forwards internal methods
* |
* Wrapper // can be unwrapped to reveal target
* | // (see js::CheckedUnwrap)
* |
* CrossCompartmentWrapper // target is in another compartment;
* // implements membrane between compartments
*
* Example: Some DOM objects (including all the arraylike DOM objects) are
* implemented as proxies. Since these objects don't need to forward operations
* to any underlying JS object, DOMJSProxyHandler directly subclasses
* to any underlying JS object, BaseDOMProxyHandler directly subclasses
* BaseProxyHandler.
*
* Gecko's security wrappers are examples of cross-compartment wrappers.
*
* ### Proxy prototype chains
*
* In addition to the normal methods, there are two models for proxy prototype
* chains.
* While most ECMAScript internal methods are handled by simply calling the
* handler method, the [[GetPrototypeOf]] / [[SetPrototypeOf]] behaviors may
* follow one of two models:
*
* 1. Proxies can use the standard prototype mechanism used throughout the
* engine. To do so, simply pass a prototype to NewProxyObject() at
* creation time. All prototype accesses will then "just work" to treat the
* proxy as a "normal" object.
* 1. A concrete prototype object (or null) is passed to object construction
* and ordinary prototype read and write applies. The prototype-related
* handler hooks are never called in this case. The [[Prototype]] slot is
* used to store the current prototype value.
*
* 2. A proxy can implement more complicated prototype semantics (if, for
* example, it wants to delegate the prototype lookup to a wrapped object)
* by passing Proxy::LazyProto as the prototype at create time. This
* guarantees that the getPrototype() handler method will be called every
* time the object's prototype chain is accessed.
* 2. TaggedProto::LazyProto is passed to NewProxyObject (or the
* ProxyOptions::lazyProto flag is set). Each read or write of the
* prototype will invoke the handler. This dynamic prototype behavior may
* be useful for wrapper-like objects. If this mode is used the
* getPrototype handler at a minimum must be implemented.
*
* This system is implemented with two methods: {get,set}Prototype. The
* default implementation of setPrototype throws a TypeError. Since it is
* not possible to create an object without a sense of prototype chain,
* handlers must implement getPrototype if opting in to the dynamic
* prototype system.
* NOTE: In this mode the [[Prototype]] internal slot is unavailable and
* must be simulated if needed. This is non-standard, but an
* appropriate handler can hide this implementation detail.
*
* One subtlety here is that ECMAScript has a notion of "ordinary" prototypes.
* An object that doesn't override [[GetPrototypeOf]] is considered to have an
* ordinary prototype. The getPrototypeIfOrdinary handler must be implemented
* by you or your base class. Typically model 1 will be considered "ordinary"
* and model 2 will not.
*/
/*

View File

@ -3157,6 +3157,10 @@ js::DefineDataElement(JSContext* cx, HandleObject obj, uint32_t index, HandleVal
/*** SpiderMonkey nonstandard internal methods ***************************************************/
// Mark an object as having an immutable prototype
//
// NOTE: This does not correspond to the SetImmutablePrototype ECMAScript
// method.
bool
js::SetImmutablePrototype(JSContext* cx, HandleObject obj, bool* succeeded)
{