XPConnect Scriptable proposal
DefinitionsI speak here about three sorts of properties (where 'property' means both methods and attributes):
- static - Static properties are those defined in xpidl. Static methods are immutable. The set of static attributes can not change, though the values of static attributes might.
- dynamic - Dynamic properties are the set of reflected properties of the XPCOM object that might be added or removed at runtime. They are not declared in xpidl. The XPCOM object should exert control over what properties can be dynamically added, removed, or changed.
- arbitrary - Arbitrary properties are the set of properties that are
neither static nor dynamic (as defined above). These are properties that can be
aggregated to the wrapper object (which reflects the XPCOM object into
object. For instance...
document.form.element = new Button("push me");...is an example of manipulating a dynamic property because it has semantic meaning to the wrapped xpcom object. While...
document.foo = "Hi there";... is an example of manipulating an arbitrary property because it just adds a plain named object to the wrapped xpcom object. It is really up to the xpcom object being wrapped to distinguish between dynamic and arbitrary properties.
ProposalI propose to declare an interface called
nsIXPCScriptable. Any xpcom object can implement that interface and expose it via
QueryInterfaceif it so chooses. When XPConnect wraps any xpcom object it will query for
nsIXPCScriptableand act accordingly if that interface is supported by the object.
nsIXPCScriptable will include methods that mirror the
jsObjectOps methods used by XPConnect to reflect the xpcom object into
engine to the
nsIXPCScriptable interface of the wrapped xpcom
object when appropriate. This will allow the xpcom object to customize how it
These methods will include:
lookupProperty defineProperty getPropertyById setPropertyById getAttributes setAttributes deleteProperty defaultValue newEnumerate checkAccess construct call convertIn addition to the normal params of these JS methods we'll also pass a reference to the wrapper itself. These methods will return a value indicating one of:
- 'I handled it without error'
- 'I didn't handle it, pass the request along'
- 'Return an error'
Some addtional methods will be added to this interface. For instance, the xpcom
nsIXPCScriptable should be able to indicate the
call order between the three sets of handlers: The 'static' XPCOM reflection,
the 'dynamic' reflection using
nsIXPCScriptable, and the
'arbitrary' property handling implemented by treating the wrapper like a plain
JSObject. A method on
nsIXPCScriptable will be called when the
wrapper is constructed to find out which order of these three handlers should be
used for all calls. The order controls which sets properties can shadow and hide
which other sets of properties.
Suppose that the call order is set to: "static, dynamic, arbitrary" and a
setPropertyById call comes in from the JS engine. XPConnect will
check to see if the property in question is one of the static properties. If it
is then it will be handled. If not, then the call is forwarded to
nsIXPCScriptable::setPropertyById. This gives the xpcom object an
opportunity to do whatever it wants to do. Likely it will look to see if this is
a property to which it ascribes any special semantic meaning. If it is not such
a property, then the object likely returns 'not handled' and then XPConnect
calls the 'plain' JSObject methods to set the property on the wrapper. Else, if
the xpcom object does care about this property than it might examine the
value being set into the property. That value might be a wrapped xpcom object
itself. It can use the XPConnect api methods to unwrap the object and do as it
chooses. It might return 'I handled it' or it might update its own internal
representation and still want that value to be aggregated to the wrapper
object by the plain JSObject code. There is a lot of flexibility here.
nsIXPCScriptable will also allow the reflected object to do
things that would not necessarily be supported (or at least not as flexibly) in
the static reflection using XPConnect. Such as... using the object as a
constructor or synthesizing a function object so that the object could be used
with the 'new' operator or with the function call '()' operator. It could also
support custom type conversions and 'toString' handling.
IssuesMy prefered scheme for doing all this is to implement the WrappedNative JS class such that it supports both the low level jsObjectOps and also forwards to the 'standard' handlers via the js_ObjectOps 'vtbl'; i.e.
js_ObjectOps.xxx();. I've played with this and it works, but there may be cases where it will blow up. There is a discussion on news://news.mozilla.org/netscape.public.mozilla.jseng regarding whether or not this approach is viable.
One alternative is to not use the jsObjectOps at all and instead do everything through the classic jsclass interface. This would likely be a real performance limitation on the static reflection of xpcom objects (the main thing that XPConnect lives to do).
Another alternative I considered is to use the jsObjectOps and the
nsIXPCScriptable interface as suggested above but make it the
nsIXPCScriptable interface's problem to handle arbitrary
properties. We could write some shared code to which it could forward calls that
would handle managing properties and rooting them, etc. This totally fails to
leverage the powerful code for just this function in the JS engine and has gc
drawbacks. But it would work. I like the main proposal a lot better if it
I would very much like to hear feedback, ideas, and requirements. Please respond to: news://news.mozilla.org/netscape.public.mozilla.xpcom
01 Feb 1999 - jband -initial creation of document