summaryrefslogtreecommitdiffstats
path: root/xpcom/reflect/xptcall/porting.html
blob: a149aa144a8ea900f7f98ce6f3cf030c080fe223 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
<!-- 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 &lt;jband@netscape.com&gt;</a
    ><br />
    <b>Last modified:</b> 31 May 1999
  </body>
</html>