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