michael@0: michael@0: michael@0: michael@0: michael@0: xptcall Porting Guide michael@0: michael@0: michael@0:

xptcall Porting Guide

michael@0: michael@0:

Overview

michael@0: michael@0:
michael@0: michael@0: xptcall is a michael@0: library that supports both invoking methods on arbitrary xpcom objects and michael@0: implementing classes whose objects can impersonate any xpcom interface. It does michael@0: this using platform specific assembly language code. This code needs to be michael@0: ported to all platforms that want to support xptcall (and thus mozilla). michael@0: michael@0:
michael@0: michael@0:

The tree

michael@0: michael@0:
michael@0:
michael@0: mozilla/xpcom/reflect/xptcall
michael@0:   +--public  // exported headers
michael@0:   +--src  // core source
michael@0:   |  \--md  // platform specific parts
michael@0:   |     +--mac  // mac ppc
michael@0:   |     +--unix  // all unix
michael@0:   |     \--win32  // win32
michael@0:   |     +--test  // simple tests to get started
michael@0:   \--tests  // full tests via api
michael@0: 
michael@0: michael@0: Porters are free to create subdirectories under the base md michael@0: directory for their given platforms and to integrate into the build system as michael@0: appropriate for their platform. michael@0: michael@0:
michael@0: michael@0:

Theory of operation

michael@0: michael@0:
michael@0: michael@0: There are really two pieces of functionality: invoke and stubs... michael@0: michael@0:

michael@0: michael@0: The invoke functionality requires the implementation of the michael@0: following on each platform (from xptcall/public/xptcall.h): michael@0: michael@0:

michael@0: XPTC_PUBLIC_API(nsresult)
michael@0: NS_InvokeByIndex(nsISupports* that, uint32_t methodIndex,
michael@0:                    uint32_t paramCount, nsXPTCVariant* params);
michael@0: 
michael@0: michael@0: Calling code is expected to supply an array of nsXPTCVariant michael@0: structs. These are discriminated unions describing the type and value of each michael@0: parameter of the target function. The platform specific code then builds a call michael@0: frame and invokes the method indicated by the index methodIndex on michael@0: the xpcom interface that. michael@0: michael@0:

michael@0: michael@0: Here are examples of this implementation for michael@0: Win32 michael@0: and michael@0: Linux x86, NetBSD x86, and FreeBSD. michael@0: michael@0: Both of these implementations use the basic strategy of: figure out how much michael@0: stack space is needed for the params, make the space in a new frame, copy the michael@0: params to that space, invoke the method, cleanup and return. C++ is used where michael@0: appropriate, Assembly language is used where necessary. Inline assembly language is used here, michael@0: but it is equally valid to use separate assembly language source files. Porters michael@0: can decide how best to do this for their platforms. michael@0: michael@0:

michael@0: michael@0: The stubs functionality is more complex. The goal here is a class michael@0: whose vtbl can look like the vtbl of any arbitrary xpcom interface. Objects of michael@0: this class can then be built to impersonate any xpcom object. The base interface michael@0: for this is (from xptcall/public/xptcall.h): michael@0: michael@0:

michael@0: class nsXPTCStubBase : public nsISupports
michael@0: {
michael@0: public:
michael@0:     // Include generated vtbl stub declarations.
michael@0:     // These are virtual and *also* implemented by this class..
michael@0: #include "xptcstubsdecl.inc"
michael@0: 
michael@0:     // The following methods must be provided by inheritor of this class.
michael@0: 
michael@0:     // return a refcounted pointer to the InterfaceInfo for this object
michael@0:     // NOTE: on some platforms this MUST not fail or we crash!
michael@0:     NS_IMETHOD GetInterfaceInfo(nsIInterfaceInfo** info) = 0;
michael@0: 
michael@0:     // call this method and return result
michael@0:     NS_IMETHOD CallMethod(uint16_t methodIndex,
michael@0:                           const nsXPTMethodInfo* info,
michael@0:                           nsXPTCMiniVariant* params) = 0;
michael@0: };
michael@0: 
michael@0: michael@0: Code that wishes to make use of this stubs functionality (such as michael@0: XPConnect) implement a class michael@0: which inherits from nsXPTCStubBase and implements the michael@0: GetInterfaceInfo and CallMethod to let the michael@0: platform specific code know how to get interface information and how to dispatch methods michael@0: once their parameters have been pulled out of the platform specific calling michael@0: frame. michael@0: michael@0:

michael@0: michael@0: Porters of this functionality implement the platform specific code for the michael@0: stub methods that fill the vtbl for this class. The idea here is that the michael@0: class has a vtbl full of a large number of generic stubs. All instances of this michael@0: class share that vtbl and the same stubs. The stubs forward calls to a platform michael@0: specific method that uses the interface information supplied by michael@0: the overridden GetInterfaceInfo to extract the parameters and build michael@0: an array of platform independent nsXPTCMiniVariant structs which michael@0: are in turn passed on to the overridden CallMethod. The michael@0: platform dependent code is responsible for doing any cleanup and returning. michael@0: michael@0:

michael@0: michael@0: The stub methods are declared in xptcall/public/xptcstubsdecl.inc. michael@0: These are '#included' into the declaration of nsXPTCStubBase. A michael@0: similar include file (xptcall/public/xptcstubsdef.inc) michael@0: is expanded using platform specific macros to define the stub functions. These michael@0: '.inc' files are checked into cvs. However, they can be regenerated as necessary michael@0: (i.e. to change the number of stubs or to change their specific declaration) michael@0: using the Perl script xptcall/public/genstubs.pl. michael@0: michael@0:

michael@0: michael@0: Here are examples of this implementation for Win32 michael@0: and Linux x86, NetBSD x86, and FreeBSD. michael@0: Both of these examples use inline assembly language. That is just how I michael@0: decided to do it. You can do it as you choose. michael@0: michael@0:

michael@0: michael@0: The Win32 version is somewhat tighter because the __declspec(naked) feature michael@0: allows for very small stubs. However, the __stdcall requires the callee to clean michael@0: up the stack, so it is imperative that the interface information scheme allow michael@0: the code to determine the correct stack pointer fixup for return without fail, michael@0: else the process will crash. michael@0: michael@0:

michael@0: michael@0: I opted to use inline assembler for the gcc Linux x86 port. I ended up with michael@0: larger stubs than I would have preferred rather than battle the compiler over michael@0: what would happen to the stack before my asm code began running. michael@0: michael@0:

michael@0: michael@0: I believe that the non-assembly parts of these files can be copied and reused michael@0: with minimal (but not zero) platform specific tweaks. Feel free to copy and michael@0: paste as necessary. Please remember that safety and reliability are more michael@0: important than speed optimizations. This code is primarily used to connect XPCOM michael@0: components with JavaScript; function call overhead is a tiny part of the michael@0: time involved. michael@0: michael@0:

michael@0: michael@0: I put together michael@0: xptcall/src/md/test michael@0: as a place to evolve the basic functionality as a port is coming together. michael@0: Not all of the functionality is exercised, but it is a place to get started. michael@0: xptcall/tests michael@0: has an api level test for NS_InvokeByIndex, but no tests for michael@0: the stubs functionality. Such a test ought to be written, but this has not michael@0: yet been done. michael@0: michael@0:

michael@0: michael@0: A full 'test' at this point requires building the client and running the michael@0: XPConnect test called TestXPC in michael@0: mozilla/js/xpconnect/tests michael@0: . michael@0: michael@0:

michael@0: michael@0: Getting these ports done is very important. Please let me know if you are interested in doing one. michael@0: I'll answer any questions as I get them. michael@0: michael@0:

michael@0: michael@0: michael@0: Porting Status michael@0: michael@0: michael@0:

michael@0: michael@0:
michael@0: Author: John Bandhauer <jband@netscape.com>
michael@0: Last modified: 31 May 1999 michael@0: michael@0: michael@0: