Class JitPassageDecoder
JitPassage
to support JIT-accelerated p-code emulation.
When the emulator encounters an address (and contextreg value) that it has not previously
translated, it must decode a passage seeded at that required entry point. It must then translate
the passage and collects all the resulting entry points, and finally invoke the passage's
run
method for the required entry point.
Decoding a Passage
Decode starts with a single seed, which is the entry point required by the emulator. As such, that seed must be among the entry points exported by the translator. Decode occurs one stride at a time. Starting with the seed, we decode a stride by disassembling linearly until: 1) We encounter an instruction without fall through, 2) there's already an entry point to a translated passage at an encountered address, or 3) a user injection fails to specify control flow. Case 1 is the normal expected case. For example, when the decoder encounters an unconditional branch, the stride is terminated. Case 2 is meant to reduce duplicative translations, but it does come at some cost during decode time. Suppose execution branches into the middle of a previously translated basic block. (Note that basic blocks are only broken apart using branches in the same passage, so it is possible some branch encountered later would jump into another passage's basic block.) That previously translated passage will not have exposed an entry point at that branch target, so the emulator will begin decoding using the branch target as the seed. Ideally, the resulting passage will consist of a single stride that terminates at an existing entry point. The emulator will translate and execute the passage, which should exit at that entry point, where the emulator can then continue execution. Case 3 is just to ensure execution does not get caught in a translated infinite loop. There will still be an infinite loop, but it can be interrupted while execution is in the emulator's logic rather than the translated logic.
As the stride decoder processes each instruction, it interprets its p-code, along with any
generated by user injects, to collect branch targets. For direct branches (branch
, cbranch
, and call
), the target address (and
appropriate contextreg value) is added to the queue of seeds, unless that target is already
decoded in this passage. A bit of control flow analysis is required to determine whether each
instruction (with user injects) has fall through. We borrow the JitControlFlowModel.BlockSplitter
from the
JitControlFlowModel
to accomplish this. We append a "probe" p-code op at the very end,
and then once we have the (miniature) control flow graph, we check if there's a path from
instruction start to the probe op. If there is, then we can fall through, so decode proceeds to
the next instruction. If not, the stride is terminated, so the decoder starts a new stride at the
next seed, unless we've met the p-code op, instruction, or stride quota
.
The seed queue is a list of JitPassage.ExtBranch
records. Each stride is decoded by removing a seed
from that queue, decoding instructions, emitting ops, and then creating an JitPassage.IntBranch
record targeting the first op of the newly-decoded instruction. The from
field is taken from the seed JitPassage.ExtBranch
record. Decode will likely terminate before this
queue is emptied, in which case, those remaining external branches will become part of the
passage's branches
. Direct branches to instructions already
included in the passage, p-code relative branches, and queued external branches to instructions
which have since been decoded all become JitPassage.IntBranch
records, too. For indirect branches
(branchind
, callind
, and return
), we create JitPassage.IndBranch
records. For error cases (e.g.,
unimplemented
), we create JitPassage.ErrBranch
records.
-
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescriptiondecodePassage
(JitPassage.AddrCtx seed, int maxOps) Decode a passage starting at the given seeddecodePassage
(Address seed, RegisterValue ctxIn, int maxOps) Decode a passage starting at the given seed
-
Constructor Details
-
JitPassageDecoder
Construct a passage decoder- Parameters:
thread
- the thread whose instruction decoder, context, and userop library to use.
-
-
Method Details
-
decodePassage
Decode a passage starting at the given seed- Parameters:
seed
- the seed addressctxIn
- the seed contextreg valuemaxOps
- the maximum-ish number of p-code ops to emit- Returns:
- the decoded passage
- See Also:
-
decodePassage
Decode a passage starting at the given seedWe provide a
maxOps
parameter so that the configuredoption
can be overridden. In particular, the bytecode emitter may exceed the maximum size of a Java method, in which case we must abort, re-decode with fewer ops, and retry. Whether this back off should persist in the configuration is yet to be determined. Output size can vary wildly depending on the number of basic blocks, scope transitions, nature of the ops, etc. We ought to be able to provide a reasonable default value that mostly avoids retries, because each retry essentially wastes an entire JIT translation. On the other hand, if we choose too small a value, we lose some of the benefits of translating the control flow and keeping variables in JVM locals.- Parameters:
seed
- the required entry point, where decode will startmaxOps
- the maximum-ish number of p-codes to emit- Returns:
- the decoded passage
-