237 lines
10 KiB
HTML
237 lines
10 KiB
HTML
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
|
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
|
|
|
<html>
|
|
<head>
|
|
<title>xptcall Porting Guide</title>
|
|
</head>
|
|
<body bgcolor="white">
|
|
<h2><center>xptcall Porting Guide</center></h2>
|
|
|
|
<h3>Overview</h3>
|
|
|
|
<blockquote>
|
|
<a href="http://www.mozilla.org/scriptable/xptcall-faq.html"> xptcall</a>
|
|
is a library that supports both invoking methods on arbitrary xpcom
|
|
objects and implementing classes whose objects can impersonate any xpcom
|
|
interface. It does this using platform specific assembly language code.
|
|
This code needs to be ported to all platforms that want to support xptcall
|
|
(and thus mozilla).
|
|
</blockquote>
|
|
|
|
<h3>The tree</h3>
|
|
|
|
<blockquote>
|
|
<pre>
|
|
<a href="http://lxr.mozilla.org/mozilla/source/xpcom/reflect/xptcall">mozilla/xpcom/reflect/xptcall</a>
|
|
+--<a href="http://lxr.mozilla.org/mozilla/source/xpcom/reflect/xptcall/public">public</a> // exported headers
|
|
+--<a href="http://lxr.mozilla.org/mozilla/source/xpcom/reflect/xptcall/src">src</a> // core source
|
|
| \--<a href="http://lxr.mozilla.org/mozilla/source/xpcom/reflect/xptcall/md">md</a> // platform specific parts
|
|
| +--<a href="http://lxr.mozilla.org/mozilla/source/xpcom/reflect/xptcall/md/mac">mac</a> // mac ppc
|
|
| +--<a href="http://lxr.mozilla.org/mozilla/source/xpcom/reflect/xptcall/md/unix">unix</a> // all unix
|
|
| \--<a href="http://lxr.mozilla.org/mozilla/source/xpcom/reflect/xptcall/md/win32">win32</a> // win32
|
|
| +--<a href="http://lxr.mozilla.org/mozilla/source/xpcom/reflect/xptcall/md/test">test</a> // simple tests to get started
|
|
\--<a href="http://lxr.mozilla.org/mozilla/source/xpcom/reflect/xptcall/tests">tests</a> // full tests via api
|
|
</pre>
|
|
|
|
Porters are free to create subdirectories under the base <code>md</code>
|
|
directory for their given platforms and to integrate into the build system
|
|
as appropriate for their platform.
|
|
</blockquote>
|
|
|
|
<h3>Theory of operation</h3>
|
|
|
|
<blockquote>
|
|
There are really two pieces of functionality: <i>invoke</i> and
|
|
<i>stubs</i>...
|
|
|
|
<p>
|
|
The <b><i>invoke</i></b> functionality requires the implementation of
|
|
the following on each platform (from
|
|
<a
|
|
href="http://lxr.mozilla.org/mozilla/source/xpcom/reflect/xptcall/xptcall.h"
|
|
>xptcall/xptcall.h</a
|
|
>):
|
|
</p>
|
|
|
|
<pre>
|
|
XPTC_PUBLIC_API(nsresult)
|
|
NS_InvokeByIndex(nsISupports* that, uint32_t methodIndex,
|
|
uint32_t paramCount, nsXPTCVariant* params);
|
|
</pre
|
|
>
|
|
|
|
Calling code is expected to supply an array of
|
|
<code>nsXPTCVariant</code> structs. These are discriminated unions
|
|
describing the type and value of each parameter of the target function.
|
|
The platform specific code then builds a call frame and invokes the method
|
|
indicated by the index <code>methodIndex</code> on the xpcom interface
|
|
<code>that</code>.
|
|
|
|
<p>
|
|
Here are examples of this implementation for
|
|
<a
|
|
href="http://lxr.mozilla.org/mozilla/source/xpcom/reflect/xptcall/md/win32/xptcinvoke.cpp"
|
|
>Win32</a
|
|
>
|
|
and
|
|
<a
|
|
href="http://lxr.mozilla.org/mozilla/source/xpcom/reflect/xptcall/md/unix/xptcinvoke_unixish_x86.cpp"
|
|
>Linux x86, NetBSD x86, and FreeBSD</a
|
|
>. Both of these implementations use the basic strategy of: figure out
|
|
how much stack space is needed for the params, make the space in a new
|
|
frame, copy the params to that space, invoke the method, cleanup and
|
|
return. C++ is used where appropriate, Assembly language is used where
|
|
necessary. Inline assembly language is used here, but it is equally
|
|
valid to use separate assembly language source files. Porters can decide
|
|
how best to do this for their platforms.
|
|
</p>
|
|
|
|
<p>
|
|
The <b><i>stubs</i></b> functionality is more complex. The goal here is
|
|
a class whose vtbl can look like the vtbl of any arbitrary xpcom
|
|
interface. Objects of this class can then be built to impersonate any
|
|
xpcom object. The base interface for this is (from
|
|
<a
|
|
href="http://lxr.mozilla.org/mozilla/source/xpcom/reflect/xptcall/xptcall.h"
|
|
>xptcall/xptcall.h</a
|
|
>):
|
|
</p>
|
|
|
|
<pre>
|
|
class nsXPTCStubBase : public nsISupports
|
|
{
|
|
public:
|
|
// Include generated vtbl stub declarations.
|
|
// These are virtual and *also* implemented by this class..
|
|
#include "xptcstubsdecl.inc"
|
|
|
|
// The following methods must be provided by inheritor of this class.
|
|
|
|
// return a refcounted pointer to the InterfaceInfo for this object
|
|
// NOTE: on some platforms this MUST not fail or we crash!
|
|
NS_IMETHOD GetInterfaceInfo(const nsXPTInterfaceInfo** info) = 0;
|
|
|
|
// call this method and return result
|
|
NS_IMETHOD CallMethod(uint16_t methodIndex,
|
|
const nsXPTMethodInfo* info,
|
|
nsXPTCMiniVariant* params) = 0;
|
|
};
|
|
</pre
|
|
>
|
|
|
|
Code that wishes to make use of this <i>stubs</i> functionality (such as
|
|
<a href="http://www.mozilla.org/scriptable/">XPConnect</a>) implement a
|
|
class which inherits from <code>nsXPTCStubBase</code> and implements the
|
|
<code>GetInterfaceInfo</code> and <code>CallMethod</code> to let the
|
|
platform specific code know how to get interface information and how to
|
|
dispatch methods once their parameters have been pulled out of the
|
|
platform specific calling frame.
|
|
|
|
<p>
|
|
Porters of this functionality implement the platform specific code for
|
|
the
|
|
<i>stub</i> methods that fill the vtbl for this class. The idea here is
|
|
that the class has a vtbl full of a large number of generic stubs. All
|
|
instances of this class share that vtbl and the same stubs. The stubs
|
|
forward calls to a platform specific method that uses the interface
|
|
information supplied by the overridden <code>GetInterfaceInfo</code> to
|
|
extract the parameters and build an array of platform independent
|
|
<code>nsXPTCMiniVariant</code> structs which are in turn passed on to
|
|
the overridden <code>CallMethod</code>. The platform dependent code is
|
|
responsible for doing any cleanup and returning.
|
|
</p>
|
|
|
|
<p>
|
|
The stub methods are declared in
|
|
<a
|
|
href="http://lxr.mozilla.org/mozilla/source/xpcom/reflect/xptcall/xptcstubsdecl.inc"
|
|
>xptcall/xptcstubsdecl.inc</a
|
|
>. These are '#included' into the declaration of
|
|
<code>nsXPTCStubBase</code>. A similar include file (<a
|
|
href="http://lxr.mozilla.org/mozilla/source/xpcom/reflect/xptcall/xptcstubsdef.inc"
|
|
>xptcall/xptcstubsdef.inc</a
|
|
>) is expanded using platform specific macros to define the stub
|
|
functions. These '.inc' files are checked into cvs. However, they can be
|
|
regenerated as necessary (i.e. to change the number of stubs or to
|
|
change their specific declaration) using the Perl script
|
|
<a
|
|
href="http://lxr.mozilla.org/mozilla/source/xpcom/reflect/xptcall/genstubs.pl"
|
|
>xptcall/genstubs.pl</a
|
|
>.
|
|
</p>
|
|
|
|
<p>
|
|
Here are examples of this implementation for
|
|
<a
|
|
href="http://lxr.mozilla.org/mozilla/source/xpcom/reflect/xptcall/md/win32/xptcstubs.cpp"
|
|
>Win32</a
|
|
>
|
|
and
|
|
<a
|
|
href="http://lxr.mozilla.org/mozilla/source/xpcom/reflect/xptcall/md/unix/xptcstubs_unixish_x86.cpp"
|
|
>Linux x86, NetBSD x86, and FreeBSD</a
|
|
>. Both of these examples use inline assembly language. That is just how
|
|
I decided to do it. You can do it as you choose.
|
|
</p>
|
|
|
|
<p>
|
|
The Win32 version is somewhat tighter because the __declspec(naked)
|
|
feature allows for very small stubs. However, the __stdcall requires the
|
|
callee to clean up the stack, so it is imperative that the interface
|
|
information scheme allow the code to determine the correct stack pointer
|
|
fixup for return without fail, else the process will crash.
|
|
</p>
|
|
|
|
<p>
|
|
I opted to use inline assembler for the gcc Linux x86 port. I ended up
|
|
with larger stubs than I would have preferred rather than battle the
|
|
compiler over what would happen to the stack before my asm code began
|
|
running.
|
|
</p>
|
|
|
|
<p>
|
|
I believe that the non-assembly parts of these files can be copied and
|
|
reused with minimal (but not zero) platform specific tweaks. Feel free
|
|
to copy and paste as necessary. Please remember that safety and
|
|
reliability are more important than speed optimizations. This code is
|
|
primarily used to connect XPCOM components with JavaScript; function
|
|
call overhead is a <b>tiny</b> part of the time involved.
|
|
</p>
|
|
|
|
<p>
|
|
I put together
|
|
<a
|
|
href="http://lxr.mozilla.org/mozilla/source/xpcom/reflect/xptcall/md/test"
|
|
>xptcall/md/test
|
|
</a>
|
|
as a place to evolve the basic functionality as a port is coming
|
|
together. Not all of the functionality is exercised, but it is a place
|
|
to get started.
|
|
<a
|
|
href="http://lxr.mozilla.org/mozilla/source/xpcom/reflect/xptcall/tests"
|
|
>xptcall/tests
|
|
</a>
|
|
has an api level test for <code>NS_InvokeByIndex</code>, but no tests
|
|
for the <i>stubs</i> functionality. Such a test ought to be written, but
|
|
this has not yet been done.
|
|
</p>
|
|
|
|
<p>
|
|
A full 'test' at this point requires building the client and running the
|
|
XPConnect test called <i>TestXPC</i> in
|
|
<a href="http://lxr.mozilla.org/mozilla/source/js/xpconnect/tests"
|
|
>mozilla/js/xpconnect/tests </a
|
|
>.
|
|
</p>
|
|
</blockquote>
|
|
|
|
<hr />
|
|
<b>Author:</b>
|
|
<a href="mailto:jband@netscape.com"
|
|
>John Bandhauer <jband@netscape.com></a
|
|
><br />
|
|
<b>Last modified:</b> 31 May 1999
|
|
</body>
|
|
</html>
|