Tuesday, February 3, 2009

Optimized DEX files

One of the less publicized ability of the Dalvik virtual machine is that it is able to execute "optimized" DEX files (or ODEX files). "Optimizing" a DEX file speeds up its execution but also ties it to the hardware platform on which the optimization was performed. ODEX optimization relies on unsafe bytecode instructions. Unsafe instructions are much faster to execute, on the other hand, malicious use of these instructions can crash the virtual machine. Dalvik has an additional layer of security, process separation and file permissions of the underlying Linux platform so this price is not that high. It is important to note, however, that much of the security normally associated to the Java virtual machine e.g. in J2ME is now provided by the underlying Linux platform.

I remember the resistance when I proposed unsafe instruction for garbage collection performance optimization on mobile platforms. The critics argued that 1. the Java bytecode is not allowed to be modified and 2. the bytecode safety must be preserved at all costs. Seemingly, Dalvik designers have done away with both ortodoxies.

The optimization is carried out on the target platform, by the target platform's virtual machine. The command to invoke the optimizer is called dexopt. There is no point in invoking this command on the emulator as it would create an optimized DEX that can be executed only on the emulator. The most important transformations are the replacement of the method indexes with vtable indexes and the field indexes with memory offsets. So instead of invoking a method by name, it is invoked by vtable index using a set of special instructions not specified in the Dalvik instruction set.

For example:

invoke-virtual-quick {v1,v2},vtable #0x3b

(Note: if anyone reads this who is knowledgeable in the way the vtable index is computed, please, drop me a comment or mail :-))

Also, for fields:

iget-object-quick v0,v2,[obj+0x100]

The dedexer tool was updated and now provides a limited support for ODEX files. Sadly, I was not able to figure out, how to calculate method or field names out of vtable indexes and byte offsets which clearly limits the usefulness of the disassembled ODEX sources. When I was at it, I also implemented debug information processing that generates line number and local variable information like this:

.var 0 is intent Landroid/content/Intent; from l144ac to l144c8
const-class v3,com/android/vending/SubCategoryListActivity
const-string v2,"android.intent.action.VIEW"
.line 180

The Dalvik opcode list was also updated with the description of the "quick" instructions.


Chinna said...

Optimized dex files can be generated during compile time to get ODEX files for each app. But is this supported in 2.2 R1 ? or only in 2.3?

Gabor Paller said...

Chinna, could you provide some details? I thought ODEX can be generated only by the Dalvik virtual machine as ODEX is optimized for the particular Dalvik version that runs the DEX:

Anonymous said...

I believe they can be generated as part of the full system build - unlike the SDK, that has the exact jars on which they depend available (because it just built them)