OSDN Git Service

resolved conflicts for merge of 323d9152 to jb-dev-plus-aosp
[android-x86/dalvik.git] / docs / porting-guide.html
1 <html>
2 <head>
3     <title>Dalvik Porting Guide</title>
4 </head>
5
6 <body>
7 <h1>Dalvik Porting Guide</h1>
8
9 <p>
10 The Dalvik virtual machine is intended to run on a variety of platforms.
11 The baseline system is expected to be a variant of UNIX (Linux, BSD, Mac
12 OS X) running the GNU C compiler.  Little-endian CPUs have been exercised
13 the most heavily, but big-endian systems are explicitly supported.
14 </p><p>
15 There are two general categories of work: porting to a Linux system
16 with a previously unseen CPU architecture, and porting to a different
17 operating system.  This document covers the former.
18 </p><p>
19 Basic familiarity with the Android platform, source code structure, and
20 build system is assumed.
21 </p>
22
23
24 <h2>Core Libraries</h2>
25
26 <p>
27 The native code in the core libraries (chiefly <code>libcore</code>,
28 but also <code>dalvik/vm/native</code>) is written in C/C++ and is expected
29 to work without modification in a Linux environment.
30 </p><p>
31 The core libraries pull in code from many other projects, including
32 OpenSSL, zlib, and ICU.  These will also need to be ported before the VM
33 can be used.
34 </p>
35
36
37 <h2>JNI Call Bridge</h2>
38
39 <p>
40 Most of the Dalvik VM runtime is written in portable C.  The one
41 non-portable component of the runtime is the JNI call bridge.  Simply put,
42 this converts an array of integers into function arguments of various
43 types, and calls a function.  This must be done according to the C calling
44 conventions for the platform.  The task could be as simple as pushing all
45 of the arguments onto the stack, or involve complex rules for register
46 assignment and stack alignment.
47 </p><p>
48 To ease porting to new platforms, the <a href="http://sourceware.org/libffi/">
49 open-source FFI library</a> (Foreign Function Interface) is used when a
50 custom bridge is unavailable.  FFI is not as fast as a native implementation,
51 and the optional performance improvements it does offer are not used, so
52 writing a replacement is a good first step.
53 </p><p>
54 The code lives in <code>dalvik/vm/arch/*</code>, with the FFI-based version
55 in the "generic" directory.  There are two source files for each architecture.
56 One defines the call bridge itself:
57 </p><p><blockquote>
58 <code>void dvmPlatformInvoke(void* pEnv, ClassObject* clazz, int argInfo,
59 int argc, const u4* argv, const char* signature, void* func,
60 JValue* pReturn)</code>
61 </blockquote></p><p>
62 This will invoke a C/C++ function declared:
63 </p><p><blockquote>
64     <code>return_type func(JNIEnv* pEnv, Object* this [, <i>args</i>])<br></code>
65 </blockquote>or (for a "static" method):<blockquote>
66     <code>return_type func(JNIEnv* pEnv, ClassObject* clazz [, <i>args</i>])</code>
67 </blockquote></p><p>
68 The role of <code>dvmPlatformInvoke</code> is to convert the values in
69 <code>argv</code> into C-style calling conventions, call the method, and
70 then place the return type into <code>pReturn</code> (a union that holds
71 all of the basic JNI types).  The code may use the method signature
72 (a DEX "shorty" signature, with one character for the return type and one
73 per argument) to determine how to handle the values.
74 </p><p>
75 The other source file involved here defines a 32-bit "hint".  The hint
76 is computed when the method's class is loaded, and passed in as the
77 "argInfo" argument.  The hint can be used to avoid scanning the ASCII
78 method signature for things like the return value, total argument size,
79 or inter-argument 64-bit alignment restrictions.
80
81
82 <h2>Interpreter</h2>
83
84 <p>
85 The Dalvik runtime includes two interpreters, labeled "portable" and "fast".
86 The portable interpreter is largely contained within a single C function,
87 and should compile on any system that supports gcc.  (If you don't have gcc,
88 you may need to disable the "threaded" execution model, which relies on
89 gcc's "goto table" implementation; look for the THREADED_INTERP define.)
90 </p><p>
91 The fast interpreter uses hand-coded assembly fragments.  If none are
92 available for the current architecture, the build system will create an
93 interpreter out of C "stubs".  The resulting "all stubs" interpreter is
94 quite a bit slower than the portable interpreter, making "fast" something
95 of a misnomer.
96 </p><p>
97 The fast interpreter is enabled by default.  On platforms without native
98 support, you may want to switch to the portable interpreter.  This can
99 be controlled with the <code>dalvik.vm.execution-mode</code> system
100 property.  For example, if you:
101 </p><p><blockquote>
102 <code>adb shell "echo dalvik.vm.execution-mode = int:portable >> /data/local.prop"</code>
103 </blockquote></p><p>
104 and reboot, the Android app framework will start the VM with the portable
105 interpreter enabled.
106 </p>
107
108
109 <h3>Mterp Interpreter Structure</h3>
110
111 <p>
112 There may be significant performance advantages to rewriting the
113 interpreter core in assembly language, using architecture-specific
114 optimizations.  In Dalvik this can be done one instruction at a time.
115 </p><p>
116 The simplest way to implement an interpreter is to have a large "switch"
117 statement.  After each instruction is handled, the interpreter returns to
118 the top of the loop, fetches the next instruction, and jumps to the
119 appropriate label.
120 </p><p>
121 An improvement on this is called "threaded" execution.  The instruction
122 fetch and dispatch are included at the end of every instruction handler.
123 This makes the interpreter a little larger overall, but you get to avoid
124 the (potentially expensive) branch back to the top of the switch statement.
125 </p><p>
126 Dalvik mterp goes one step further, using a computed goto instead of a goto
127 table.  Instead of looking up the address in a table, which requires an
128 extra memory fetch on every instruction, mterp multiplies the opcode number
129 by a fixed value.  By default, each handler is allowed 64 bytes of space.
130 </p><p>
131 Not all handlers fit in 64 bytes.  Those that don't can have subroutines
132 or simply continue on to additional code outside the basic space.  Some of
133 this is handled automatically by Dalvik, but there's no portable way to detect
134 overflow of a 64-byte handler until the VM starts executing.
135 </p><p>
136 The choice of 64 bytes is somewhat arbitrary, but has worked out well for
137 ARM and x86.
138 </p><p>
139 In the course of development it's useful to have C and assembly
140 implementations of each handler, and be able to flip back and forth
141 between them when hunting problems down.  In mterp this is relatively
142 straightforward.  You can always see the files being fed to the compiler
143 and assembler for your platform by looking in the
144 <code>dalvik/vm/mterp/out</code> directory.
145 </p><p>
146 The interpreter sources live in <code>dalvik/vm/mterp</code>.  If you
147 haven't yet, you should read <code>dalvik/vm/mterp/README.txt</code> now.
148 </p>
149
150
151 <h3>Getting Started With Mterp</h3>
152
153 </p><p>
154 Getting started:
155 <ol>
156 <li>Decide on the name of your architecture.  For the sake of discussion,
157 let's call it <code>myarch</code>.
158 <li>Make a copy of <code>dalvik/vm/mterp/config-allstubs</code> to
159 <code>dalvik/vm/mterp/config-myarch</code>.
160 <li>Create a <code>dalvik/vm/mterp/myarch</code> directory to hold your
161 source files.
162 <li>Add <code>myarch</code> to the list in
163 <code>dalvik/vm/mterp/rebuild.sh</code>.
164 <li>Make sure <code>dalvik/vm/Android.mk</code> will find the files for
165 your architecture.  If <code>$(TARGET_ARCH)</code> is configured this
166 will happen automatically.
167 <li>Disable the Dalvik JIT.  You can do this in the general device
168 configuration, or by editing the initialization of WITH_JIT in
169 <code>dalvik/vm/Dvm.mk</code> to always be <code>false</code>.
170 </ol>
171 </p><p>
172 You now have the basic framework in place.  Whenever you make a change, you
173 need to perform two steps: regenerate the mterp output, and build the
174 core VM library.  (It's two steps because we didn't want the build system
175 to require Python 2.5.  Which, incidentally, you need to have.)
176 <ol>
177 <li>In the <code>dalvik/vm/mterp</code> directory, regenerate the contents
178 of the files in <code>dalvik/vm/mterp/out</code> by executing
179 <code>./rebuild.sh</code>.  Note there are two files, one in C and one
180 in assembly.
181 <li>In the <code>dalvik</code> directory, regenerate the
182 <code>libdvm.so</code> library with <code>mm</code>.  You can also use
183 <code>mmm dalvik/vm</code> from the top of the tree.
184 </ol>
185 </p><p>
186 This will leave you with an updated libdvm.so, which can be pushed out to
187 a device with <code>adb sync</code> or <code>adb push</code>.  If you're
188 using the emulator, you need to add <code>make snod</code> (System image,
189 NO Dependency check) to rebuild the system image file.  You should not
190 need to do a top-level "make" and rebuild the dependent binaries.
191 </p><p>
192 At this point you have an "all stubs" interpreter.  You can see how it
193 works by examining <code>dalvik/vm/mterp/cstubs/entry.c</code>.  The
194 code runs in a loop, pulling out the next opcode, and invoking the
195 handler through a function pointer.  Each handler takes a "glue" argument
196 that contains all of the useful state.
197 </p><p>
198 Your goal is to replace the entry method, exit method, and each individual
199 instruction with custom implementations.  The first thing you need to do
200 is create an entry function that calls the handler for the first instruction.
201 After that, the instructions chain together, so you don't need a loop.
202 (Look at the ARM or x86 implementation to see how they work.)
203 </p><p>
204 Once you have that, you need something to jump to.  You can't branch
205 directly to the C stub because it's expecting to be called with a "glue"
206 argument and then return.  We need a C stub "wrapper" that does the
207 setup and jumps directly to the next handler.  We write this in assembly
208 and then add it to the config file definition.
209 </p><p>
210 To see how this works, create a file called
211 <code>dalvik/vm/mterp/myarch/stub.S</code> that contains one line:
212 <pre>
213 /* stub for ${opcode} */
214 </pre>
215 Then, in <code>dalvik/vm/mterp/config-myarch</code>, add this below the
216 <code>handler-size</code> directive:
217 <pre>
218 # source for the instruction table stub
219 asm-stub myarch/stub.S
220 </pre>
221 </p><p>
222 Regenerate the sources with <code>./rebuild.sh</code>, and take a look
223 inside <code>dalvik/vm/mterp/out/InterpAsm-myarch.S</code>.  You should
224 see 256 copies of the stub function in a single large block after the
225 <code>dvmAsmInstructionStart</code> label.  The <code>stub.S</code>
226 code will be used anywhere you don't provide an assembly implementation.
227 </p><p>
228 Note that each block begins with a <code>.balign 64</code> directive.
229 This is what pads each handler out to 64 bytes.  Note also that the
230 <code>${opcode}</code> text changed into an opcode name, which should
231 be used to call the C implementation (<code>dvmMterp_${opcode}</code>).
232 </p><p>
233 The actual contents of <code>stub.S</code> are up to you to define.
234 See <code>entry.S</code> and <code>stub.S</code> in the <code>armv5te</code>
235 or <code>x86</code> directories for working examples.
236 </p><p>
237 If you're working on a variation of an existing architecture, you may be
238 able to use most of the existing code and just provide replacements for
239 a few instructions.  Look at the <code>vm/mterp/config-*</code> files
240 for examples.
241 </p>
242
243
244 <h3>Replacing Stubs</h3>
245
246 <p>
247 There are roughly 250 Dalvik opcodes, including some that are inserted by
248 <a href="dexopt.html">dexopt</a> and aren't described in the
249 <a href="dalvik-bytecode.html">Dalvik bytecode</a> documentation.  Each
250 one must perform the appropriate actions, fetch the next opcode, and
251 branch to the next handler.  The actions performed by the assembly version
252 must exactly match those performed by the C version (in
253 <code>dalvik/vm/mterp/c/OP_*</code>).
254 </p><p>
255 It is possible to customize the set of "optimized" instructions for your
256 platform.  This is possible because optimized DEX files are not expected
257 to work on multiple devices.  Adding, removing, or redefining instructions
258 is beyond the scope of this document, and for simplicity it's best to stick
259 with the basic set defined by the portable interpreter.
260 </p><p>
261 Once you have written a handler that looks like it should work, add
262 it to the config file.  For example, suppose we have a working version
263 of <code>OP_NOP</code>.  For demonstration purposes, fake it for now by
264 putting this into <code>dalvik/vm/mterp/myarch/OP_NOP.S</code>:
265 <pre>
266 /* This is my NOP handler */
267 </pre>
268 </p><p>
269 Then, in the <code>op-start</code> section of <code>config-myarch</code>, add:
270 <pre>
271     op OP_NOP myarch
272 </pre>
273 </p><p>
274 This tells the generation script to use the assembly version from the
275 <code>myarch</code> directory instead of the C version from the <code>c</code>
276 directory.
277 </p><p>
278 Execute <code>./rebuild.sh</code>.  Look at <code>InterpAsm-myarch.S</code>
279 and <code>InterpC-myarch.c</code> in the <code>out</code> directory.  You
280 will see that the <code>OP_NOP</code> stub wrapper has been replaced with our
281 new code in the assembly file, and the C stub implementation is no longer
282 included.
283 </p><p>
284 As you implement instructions, the C version and corresponding stub wrapper
285 will disappear from the output files.  Eventually you will have a 100%
286 assembly interpreter.  You may find it saves a little time to examine
287 the output of your compiler for some of the operations.  The
288 <a href="porting-proto.c.txt">porting-proto.c</a> sample code can be
289 helpful here.
290 </p>
291
292
293 <h3>Interpreter Switching</h3>
294
295 <p>
296 The Dalvik VM actually includes a third interpreter implementation: the debug
297 interpreter.  This is a variation of the portable interpreter that includes
298 support for debugging and profiling.
299 </p><p>
300 When a debugger attaches, or a profiling feature is enabled, the VM
301 will switch interpreters at a convenient point.  This is done at the
302 same time as the GC safe point check: on a backward branch, a method
303 return, or an exception throw.  Similarly, when the debugger detaches
304 or profiling is discontinued, execution transfers back to the "fast" or
305 "portable" interpreter.
306 </p><p>
307 Your entry function needs to test the "entryPoint" value in the "glue"
308 pointer to determine where execution should begin.  Your exit function
309 will need to return a boolean that indicates whether the interpreter is
310 exiting (because we reached the "bottom" of a thread stack) or wants to
311 switch to the other implementation.
312 </p><p>
313 See the <code>entry.S</code> file in <code>x86</code> or <code>armv5te</code>
314 for examples.
315 </p>
316
317
318 <h3>Testing</h3>
319
320 <p>
321 A number of VM tests can be found in <code>dalvik/tests</code>.  The most
322 useful during interpreter development is <code>003-omnibus-opcodes</code>,
323 which tests many different instructions.
324 </p><p>
325 The basic invocation is:
326 <pre>
327 $ cd dalvik/tests
328 $ ./run-test 003
329 </pre>
330 </p><p>
331 This will run test 003 on an attached device or emulator.  You can run
332 the test against your desktop VM by specifying <code>--reference</code>
333 if you suspect the test may be faulty.  You can also use
334 <code>--portable</code> and <code>--fast</code> to explictly specify
335 one Dalvik interpreter or the other.
336 </p><p>
337 Some instructions are replaced by <code>dexopt</code>, notably when
338 "quickening" field accesses and method invocations.  To ensure
339 that you are testing the basic form of the instruction, add the
340 <code>--no-optimize</code> option.
341 </p><p>
342 There is no in-built instruction tracing mechanism.  If you want
343 to know for sure that your implementation of an opcode handler
344 is being used, the easiest approach is to insert a "printf"
345 call.  For an example, look at <code>common_squeak</code> in
346 <code>dalvik/vm/mterp/armv5te/footer.S</code>.
347 </p><p>
348 At some point you need to ensure that debuggers and profiling work with
349 your interpreter.  The easiest way to do this is to simply connect a
350 debugger or toggle profiling.  (A future test suite may include some
351 tests for this.)
352 </p>
353
354
355 <h2>Other Performance Issues</h2>
356
357 <p>
358 The <code>System.arraycopy()</code> function is heavily used.  The
359 implementation relies on the bionic C library to provide a fast,
360 platform-optimized data copy function for arrays with elements wider
361 than one byte.  If you're not using bionic, or your platform does not
362 have an implementation of this method, Dalvik will use correct but
363 sub-optimal algorithms instead.  For best performance you will want
364 to provide your own version.
365 </p><p>
366 See the comments in <code>dalvik/vm/native/java_lang_System.c</code>
367 for details.
368 </p>
369
370 <p>
371 <address>Copyright &copy; 2009 The Android Open Source Project</address>
372
373 </body>
374 </html>