Package ghidra.pcode.emu.jit

# Class JitPcodeThread

java.lang.Object
ghidra.pcode.emu.DefaultPcodeThread<byte[]>
ghidra.pcode.emu.ModifiedPcodeThread<byte[]>
ghidra.pcode.emu.BytesPcodeThread
ghidra.pcode.emu.jit.JitPcodeThread

All Implemented Interfaces:
  `PcodeThread<byte[]>`

public class JitPcodeThread extends BytesPcodeThread
A JIT-accelerated thread of p-code emulation

This class implements the actual JIT-accelerated execution loop. In contrast to the normal per-instruction Fetch-Execute-Store loop inherited from `DefaultPcodeThread`, this thread's `run()` method implements a per-passage Fetch-Decode-Translate-Execute loop.

## Fetch

The Fetch step involves checking the code cache for an existing translation at the thread's current counter and decode context. Cache entries are keyed by passage entry point, that is an address (and context reg value, if applicable) within a passage where execution is permitted to enter. This typically consists of the passage's seed as well as each branch target in the same passage. If one is found, we skip the Decode and Translate steps, and proceed directly to Execute.

## Decode

The Decode step involves decoding and selecting several instructions into a passage. A passage may comprise of several instructions connected by control flow. Often it is a few long strides of instructions connected by a few branches. The decoder will avoid selecting instructions that are already included in an existing translated passage. The reason for this complexity is that JVM bytecode cannot be rewritten or patched once loaded. For more details, see `JitPassageDecoder`.

## Translate

The Translate step involves translating the selected passage of instructions. The result of this translation implements `JitCompiledPassage`. For details of this translation process, see `JitCompiler`. The compiled passage provides a list of its entry points. Each is added to the emulator's code cache. Among those should be the seed required by this iteration of the execution loop, and so that entry point is chosen.

## Execute

The chosen entry point is then executed. This step is as simple as invoking the `JitCompiledPassage.EntryPoint.run()` method. This, in turn, invokes `JitCompiledPassage.run(int)`, providing the entry point's index as an argument. The index identifies to the translated passage the desired address of entry, and so it jumps directly to the corresponding translation. That translation performs all the equivalent operations of the selected instructions, adhering to any control flow within. When control flow exits the passage, the method returns, and the loop repeats.

- ## Nested Class Summary

  ## Nested classes/interfaces inherited from class ghidra.pcode.emu.ModifiedPcodeThread

  `ModifiedPcodeThread.GlueEmulate, ModifiedPcodeThread.ModifierUseropLibrary`

  ## Nested classes/interfaces inherited from class ghidra.pcode.emu.DefaultPcodeThread

  `DefaultPcodeThread.PcodeEmulationLibrary<T>, DefaultPcodeThread.PcodeThreadExecutor<T>`

- ## Field Summary

  Fields
  Modifier and Type
  Field
  Description
  `protected final Map<JitPassage.AddrCtx,JitCompiledPassage.EntryPoint>`
  `codeCache`
  This thread's cache of translations instantiated for this thread.
  `protected final JitPassageDecoder`
  `passageDecoder`
  This thread's passage decoder, which is based on its `instruction decoder`.

  ### Fields inherited from class ghidra.pcode.emu.ModifiedPcodeThread

  `emulate, modifier`

  ### Fields inherited from class ghidra.pcode.emu.DefaultPcodeThread

  `arithmetic, contextreg, decoder, defaultContext, executor, frame, injects, instruction, language, pc, state`

- ## Constructor Summary

  Constructors
  Constructor
  Description
  `JitPcodeThread(String name, JitPcodeEmulator machine)`
  Create a thread

- ## Method Summary

  Modifier and Type
  Method
  Description
  `void`
  `count(int instructions, int trailingOps)`
  This is called before each basic block is executed.
  `protected JitPassageDecoder`
  `createPassageDecoder()`
  Create the passage decoder
  `protected ThreadPcodeExecutorState<byte[]>`
  `createThreadState(PcodeExecutorState<byte[]> sharedState, PcodeExecutorState<byte[]> localState)`
  A factory method for the thread's (multiplexed) state
  `InstructionDecoder`
  `getDecoder()`
  An accessor so the passage decoder can retrieve its thread's instruction decoder.
  `ProgramContext`
  `getDefaultContext()`
  An accessor so the passage decoder can query the language's default program context.
  `JitCompiledPassage.EntryPoint`
  `getEntry(JitPassage.AddrCtx pcCtx)`
  Get the translated and instantiated entry point for the given address and contextreg value.
  `PcodeProgram`
  `getInject(Address address)`
  Check for a p-code injection (override) at the given address
  `JitPcodeEmulator`
  `getMachine()`
  Get the machine within which this thread executes
  `JitThreadBytesPcodeExecutorState`
  `getState()`
  Get the thread's memory and register state
  `boolean`
  `hasEntry(JitPassage.AddrCtx pcCtx)`
  Check if the emulator has an entry prototype for the given address and contextreg value.
  `void`
  `inject(Address address, String source)`
  Override the p-code at the given address with the given Sleigh source for only this thread
  `void`
  `run()`
  Emulate indefinitely
  `void`
  `setCounterAndContext(Address counter, RegisterValue context)`
  Set the emulator's counter and context without affecting its machine state
  `void`
  `writeCounterAndContext(Address counter, RegisterValue context)`
  Write the given counter and context to the emulator and its machine state

  ### Methods inherited from class ghidra.pcode.emu.ModifiedPcodeThread

  `createModifier, createUseropLibrary, overrideCounter, postExecuteInstruction`

  ### Methods inherited from class ghidra.pcode.emu.DefaultPcodeThread

  `advanceAfterFinished, assertCompletedInstruction, assertMidInstruction, assignContext, beginInstructionOrInject, branchToAddress, checkLoad, checkStore, clearAllInjects, clearInject, createExecutor, createInstructionDecoder, doPluggableInitialization, dropInstruction, executeInstruction, finishInstruction, getArithmetic, getContext, getContextAfterCommits, getContextAfterCommits, getCounter, getExecutor, getFrame, getInstruction, getLanguage, getName, getUseropLibrary, isSuspended, onMissingUseropDef, overrideContext, overrideContextWithDefault, preExecuteInstruction, reInitialize, setCounter, setSuspended, skipInstruction, skipPcodeOp, stepInstruction, stepPatch, stepPcodeOp, stepped, swi, writeContext, writeCounter`

  ### Methods inherited from class java.lang.Object

  `clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait`

  ### Methods inherited from interface ghidra.pcode.emu.PcodeThread

  `stepInstruction, stepPcodeOp`

- ## Field Details

  - ### passageDecoder

    protected final JitPassageDecoder passageDecoder
    This thread's passage decoder, which is based on its `instruction decoder`.

  - ### codeCache

    protected final Map<JitPassage.AddrCtx,JitCompiledPassage.EntryPoint> codeCache
    This thread's cache of translations instantiated for this thread.

    As an optimization, the translator generates classes which pre-fetch portions of the thread's state. Thus, the class must be instantiated for each particular thread needing to execute it.

    TODO: Invalidation of entries. There are several reasons an entry may need to be invalidated: Expiration, eviction, or perhaps because the `JitCompiledPassage.EntryPointPrototype` (from the emulator) was invalidated.

- ## Constructor Details

  - ### JitPcodeThread

    public JitPcodeThread(String name, JitPcodeEmulator machine)
    Create a thread

    This should only be called by the emulator and its test suites.

    Parameters:
      `name` - the name of the thread
      `machine` - the machine creating the thread

- ## Method Details

  - ### createThreadState

    protected ThreadPcodeExecutorState<byte[]> createThreadState(PcodeExecutorState<byte[]> sharedState, PcodeExecutorState<byte[]> localState)
    Description copied from class: `DefaultPcodeThread`
    A factory method for the thread's (multiplexed) state
    Overrides:
      `createThreadState` in class `DefaultPcodeThread<byte[]>`
    Parameters:
      `sharedState` - the shared part of the state
      `localState` - the thread-local part of the state
    Returns:
      the complete state

  - ### createPassageDecoder

    protected JitPassageDecoder createPassageDecoder()
    Create the passage decoder

    This is an extension point in case the decoder needs to be replaced with a further extension.

    Returns:
      the new passage decoder

  - ### getMachine

    public JitPcodeEmulator getMachine()
    Description copied from interface: `PcodeThread`
    Get the machine within which this thread executes
    Specified by:
      `getMachine` in interface `PcodeThread<byte[]>`
    Overrides:
      `getMachine` in class `DefaultPcodeThread<byte[]>`
    Returns:
      the containing machine

  - ### getState

    public JitThreadBytesPcodeExecutorState getState()
    Description copied from interface: `PcodeThread`
    Get the thread's memory and register state

    The memory part of this state is shared among all threads in the same machine. See `PcodeMachine.getSharedState()`.

    Specified by:
      `getState` in interface `PcodeThread<byte[]>`
    Overrides:
      `getState` in class `DefaultPcodeThread<byte[]>`
    Returns:
      the state

  - ### getInject

    public PcodeProgram getInject(Address address)
    Description copied from class: `DefaultPcodeThread`
    Check for a p-code injection (override) at the given address

    This checks this thread's particular injects and then defers to the machine's injects.

    Overrides:
      `getInject` in class `DefaultPcodeThread<byte[]>`
    Parameters:
      `address` - the address, usually the program counter
    Returns:
      the injected program, most likely `null`

  - ### getDecoder

    public InstructionDecoder getDecoder()
    An accessor so the passage decoder can retrieve its thread's instruction decoder.
    Returns:
      the decoder

  - ### getDefaultContext

    public ProgramContext getDefaultContext()
    An accessor so the passage decoder can query the language's default program context.
    Returns:
      the context

  - ### inject

    public void inject(Address address, String source)
    Description copied from interface: `PcodeThread`
    Override the p-code at the given address with the given Sleigh source for only this thread

    This works the same `PcodeMachine.inject(Address, String)` but on a per-thread basis. Where there is both a machine-level and thread-level inject the thread inject takes precedence. Furthermore, the machine-level inject cannot be accessed by the thread-level inject.

    Specified by:
      `inject` in interface `PcodeThread<byte[]>`
    Overrides:
      `inject` in class `DefaultPcodeThread<byte[]>`
    Parameters:
      `address` - the address to inject at
      `source` - the Sleigh source to compile and inject

  - ### hasEntry

    public boolean hasEntry(JitPassage.AddrCtx pcCtx)
    Check if the emulator has an entry prototype for the given address and contextreg value.

    This simply passes through to the emulator. It does not matter whether or not this thread has instantiated the prototype or not. If any thread has caused the emulator to translate the given entry, this will return true.

    Parameters:
      `pcCtx` - the address and contextreg to check
    Returns:
      true if the emulator has a translation which can be entered at the given pcCtx.
    See Also:
      - `JitPcodeEmulator.hasEntryPrototype(AddrCtx)`

  - ### getEntry

    public JitCompiledPassage.EntryPoint getEntry(JitPassage.AddrCtx pcCtx)
    Get the translated and instantiated entry point for the given address and contextreg value.

    An entry point is an instance of a class representing a translated passage and an index identifying the point at which to enter the passage. In essence, it is an instance of an entry prototype for this thread.

    This will first check the cache for an existing instance. Then, it will delegate to the emulator. The emulator will check its cache for an existing translation. If one is found, we simply take it and instantiate it for this thread. Otherwise, the emulator translates a new passage at the given seed, and we instantiate it for this thread.

    Parameters:
      `pcCtx` - the counter and decoder context
    Returns:
      the entry point
    See Also:
      - `JitPcodeEmulator.getEntryPrototype(AddrCtx, JitPassageDecoder)`

  - ### run

    public void run()
    Emulate indefinitely

    This begins or resumes execution of the emulator. If there is a current instruction, that instruction is finished. By calling this method, you are "donating" the current Java thread to the emulator. This method will not likely return, but instead only terminates via exception, e.g., hitting a user breakpoint or becoming suspended. Depending on the use case, this method might be invoked from a Java thread dedicated to this emulated thread.

    We override only this method to accelerate execution using JIT translation. Implementing single stepping via JIT doesn't make much sense from an efficiency standpoint. However, this thread still supports stepping via interpretation (as inherited). Our implementation permits mixing the two execution paradigms; however, using JIT after a few single steps will incur some waste as the JIT translates an otherwise uncommon entry point. Depending on circumstances and the order of operations, the effect of this on overall efficiency may vary because of caching.

    Specified by:
      `run` in interface `PcodeThread<byte[]>`
    Overrides:
      `run` in class `DefaultPcodeThread<byte[]>`

  - ### count

    public void count(int instructions, int trailingOps)
    This is called before each basic block is executed.

    This gives the thread an opportunity to track and control execution, if desired. It provides the number of instructions and additional p-code ops about to be completed. If the counts exceed a desired schedule, or if the thread is suspended, this method may throw an exception to interrupt execution. This can be toggled in the emulator's configuration.

    Parameters:
      `instructions` - the number of instruction about to be completed
      `trailingOps` - the number of ops of a final partial instruction about to be completed. If the block does not complete any instruction, this is the number of ops continuing in the current (partial) instruction.
    See Also:
      - `JitConfiguration.emitCounters()`

  - ### writeCounterAndContext

    public void writeCounterAndContext(Address counter, RegisterValue context)
    Write the given counter and context to the emulator and its machine state
    Parameters:
      `counter` - the counter
      `context` - the context

  - ### setCounterAndContext

    public void setCounterAndContext(Address counter, RegisterValue context)
    Set the emulator's counter and context without affecting its machine state
    Parameters:
      `counter` - the counter
      `context` - the context
    Implementation Notes:
      the reasons for doing this are a bit nuanced and they deal in the setting of the pc by p-code ops whilst it also makes hazardous userop invocations. The intended value of the pc may not survive if it gets clobbered with the current counter before execution reaches the "goto pc".