mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-28 23:31:56 +00:00
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:
parent
ca7afcc659
commit
8c500290c1
@ -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.
|
||||
*/
|
||||
|
||||
/*
|
||||
|
@ -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)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user