You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
82 lines
3.5 KiB
82 lines
3.5 KiB
4 months ago
|
==== Overview ====
|
||
|
|
||
|
The assembly source code is produced from custom python-based templates.
|
||
|
All the architecture-specific template files are concatenated to create
|
||
|
one big python script. This generated python script is then executed to
|
||
|
produced the final assembly file. The template syntax is:
|
||
|
* Lines starting with % are python code. They will be copied as-is to
|
||
|
the script (without the %) and thus executed during the generation.
|
||
|
* Other lines are text, and they are essentially syntax sugar for
|
||
|
out.write('''(line text)''') and thus they write the main output.
|
||
|
* Within a text line, $ can be used insert variables from code.
|
||
|
|
||
|
The final assembly sources are written into the "out" directory, where
|
||
|
they are picked up by the Android build system.
|
||
|
|
||
|
The best way to become familiar with the interpreter is to look at the
|
||
|
generated files in the "out" directory.
|
||
|
|
||
|
|
||
|
==== Instruction file format ====
|
||
|
|
||
|
The assembly instruction files are simply fragments of assembly sources.
|
||
|
The starting label will be provided by the generation tool, as will
|
||
|
declarations for the segment type and alignment.
|
||
|
|
||
|
The following global variables are generally available:
|
||
|
|
||
|
$opcode - opcode name, e.g. "OP_NOP"
|
||
|
$opnum - opcode number, e.g. 0 for OP_NOP
|
||
|
$handler_size_bytes - max size of an instruction handler, in bytes
|
||
|
$handler_size_bits - max size of an instruction handler, log 2
|
||
|
|
||
|
Both C and assembly sources will be passed through the C pre-processor,
|
||
|
so you can take advantage of C-style comments and preprocessor directives
|
||
|
like "#define".
|
||
|
|
||
|
The generation tool does *not* print a warning if your instructions
|
||
|
exceed "handler-size", but the VM will abort on startup if it detects an
|
||
|
oversized handler. On architectures with fixed-width instructions this
|
||
|
is easy to work with, on others this you will need to count bytes.
|
||
|
|
||
|
|
||
|
==== Using C constants from assembly sources ====
|
||
|
|
||
|
The file "art/runtime/asm_support.h" has some definitions for constant
|
||
|
values, structure sizes, and struct member offsets. The format is fairly
|
||
|
restricted, as simple macros are used to massage it for use with both C
|
||
|
(where it is verified) and assembly (where the definitions are used).
|
||
|
|
||
|
If a constant in the file becomes out of sync, the VM will log an error
|
||
|
message and abort during startup.
|
||
|
|
||
|
|
||
|
==== Rebuilding ====
|
||
|
|
||
|
If you change any of the source file fragments, you need to rebuild the
|
||
|
combined source files in the "out" directory. Make sure the files in
|
||
|
"out" are editable, then:
|
||
|
|
||
|
$ cd mterp
|
||
|
$ ./gen_mterp.py
|
||
|
|
||
|
The ultimate goal is to have the build system generate the necessary
|
||
|
output files without requiring this separate step, but we're not yet
|
||
|
ready to require Python in the build.
|
||
|
|
||
|
==== Interpreter Control ====
|
||
|
|
||
|
The mterp fast interpreter achieves much of its performance advantage
|
||
|
over the C++ interpreter through its efficient mechanism of
|
||
|
transitioning from one Dalvik bytecode to the next. Mterp for ARM targets
|
||
|
uses a computed-goto mechanism, in which the handler entrypoints are
|
||
|
located at the base of the handler table + (opcode * 128).
|
||
|
|
||
|
In normal operation, the dedicated register rIBASE
|
||
|
(r8 for ARM, edx for x86) holds a mainHandlerTable. If we need to switch
|
||
|
to a mode that requires inter-instruction checking, rIBASE is changed
|
||
|
to altHandlerTable. Note that this change is not immediate. What is actually
|
||
|
changed is the value of curHandlerTable - which is part of the interpBreak
|
||
|
structure. Rather than explicitly check for changes, each thread will
|
||
|
unconditionally refresh rIBASE at backward branches, exception throws and returns.
|