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