A zero generated code XPConnect proposal
See here for further details about XPConnect
This proposal is presented as an alternative to my (old and hastily written!) zero-ASM proposal. This proposal presents a plan for implementing XPConnect without any per interface generated code. It also suggests putting InterfaceInfo information (generated by the xpidl compiler) into a non-compiled XP file format. This is a minimal footprint solution at the cost of requiring some platform specific assembly code for marshalling params and dispatching calls from C++ to JS and from JS to C++.
InterfaceInfo files and objects
XPIDL, the IDL compiler, will generate header files for inclusion in C++ code, interface documentation files, and - for XPConnect - InterfaceInfo files. InterfaceInfo files will be non-platform specific files which contain all pertinent information about the XPCOM interface described in the IDL description expressed in a format which can be efficiently accessed at runtime. Each InterfaceInfo file will contain information about one or more interfaces. We will likely build tools to merge multiple InterfaceInfo files together. InterfaceInfo files will be comparable to MS typelib files. Tools to convert one to the other may be written. I do not see it as necessary to try to be otherwise compatible with Microsoft's typelib implementation.
InterfaceInfo files will consist of sets of tables describing interfaces, their methods, and the methods' parameters. The tables will be indexed for quick access. A main table will link UUIDs to the offsets in the file of the information about a given UUID's interface. A constant pool will be used to minimize overlap of shared data. Appropriate versioning information will be stored.
InterfaceInfo files will be platform independent. A factory class will be implemented which when given a UUID can return a pointer to an nsIInterfaceInfo object. the factory and the nsIInterfaceInfo objects will hide all of the file oriented details.
nsIInterfaceInfo objects will contain all the information needed at runtime to dynamically build XPConnect glue and allow for introspection of the interface hierarchy. nsIInterfaceInfo objects will be reference counted and shared. There need be only one implementation; i.e. the same C++ class will be instantiated to represent various sorts of InterfaceInfo types. A linked hierarchy representing the interface inheritance schema of the target interfaces will be reflected in the instantiation of these nsIInterfaceInfo objects; i.e. if nsIFoo inherits from nsISupports, then when asked for an nsIInterfaceInfo object for nsIFoo the factory will return one to represent nsIFoo and that objects will have setup a link to another nsIInterfaceInfo object representing nsISupports.
The factory object that provides nsIInterfaceInfo may have access to any number of InterfaceInfo files from which it builds the requested nsIInterfaceInfo objects.
These two classes of proxies will be able to be instantiated to support any XPCOM interface. They use nsIInterfaceInfo objects to configure themselves to appropriately wrap objects and forward calls. They handle the details of supporting the nsISupports QueryInterface and reference counting transparently. These proxies are automatically used to wrap nsISupports derived object pointers as they are passed as parameters or return values.
NOTE: I'm not real excited about the names JS2CPPProxy and CPP2JSProxy.
Getters, setters, and method stubs will forward their params (either as explicit jsvals or as argc/argv for methods) to a method which will use the the proxy's associated InterfaceInfo object to determine how to convert and validate the params. The output of this conversion could be one of two forms:
Here we see the big cost of this whole approach - we would need to port the assembly code for marshalling params and calling C++ objects to each platform we choose to support. This is not, however, a great deal of code.
- Alternately, we could skip the IDispatch part and do data conversions one by one directly into the space used for marshalling params for the method call. This is somewhat simpler.
The implementation of the stubs and the shared param extraction code will be quite platform specific. On some platforms this can be mostly in C++ with a bit of inline assembly. Other platforms may require more of it to be written in assembly.
Finding the method/param information necessary to dispatch a given call will sometimes require walking the chain of InterfaceInfo objects. The InterfaceInfo object should transparently return method info for any given method 'slot' even if that method is part of a superinterface.
Finding and instantiating proxies
Whenever interface pointers are passes across the XPConnect boundary (in either direction) they will be automatically wrapped by proxies. This may require some additional QueryInterface invocations for determining identity with 'known' wrapped objects and also some tables to map known wrapped objects to their wrappers. There are tradeoffs between unfailingly reusing existing wrappers and sometimes synthesizing redundant wrappers. This needs to be further worked out and may be resolved with the benefit of empirical evidence. Regardless, it is critical that the COM identity rules be followed.
It is not clear (to me) if supporting an IDispatch interface is worth the trouble
There are potential cycle problems with reference chains that bridge the gap between the reference counted side and the garbage collected side more than once.
It is not clear if InterfaceInfo objects should be reference counted and disposed of immediately when the count goes to zero, allowed to accumulate unchecked (though always reused), or 'occasionally' be collect if they have zero reference counts. Since they are presumably relatively expensive to build from file, we would hate to see patterns where the 'same' object is repeatedly built and destroyed.
TBD add more issues
The big tradeoff question is: should we use this scheme that gives up no per interface code but requires porting to each platform, or a different scheme that has per interface code and no porting. (I vote for this scheme)
We could expose introspection of interfaces
We could support MSCOM compatible IDispatch (even IDispatchEx?)
We could build InterfaceInfo inspection tools
TBD add more enhancements