/* ###
 * IP: GHIDRA
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package ghidra.pcode.emu.jit.decode;

import ghidra.app.util.PseudoInstruction;
import ghidra.pcode.emu.InstructionDecoder;
import ghidra.pcode.emu.jit.*;
import ghidra.pcode.emu.jit.JitPassage.*;
import ghidra.pcode.emu.jit.analysis.JitControlFlowModel;
import ghidra.pcode.emu.jit.analysis.JitControlFlowModel.BlockSplitter;
import ghidra.pcode.emu.jit.gen.tgt.JitCompiledPassage;
import ghidra.pcode.exec.DecodePcodeExecutionException;
import ghidra.program.model.address.Address;
import ghidra.program.model.lang.Register;
import ghidra.program.model.lang.RegisterValue;
import ghidra.program.model.listing.ProgramContext;
import ghidra.program.model.pcode.PcodeOp;

/**
 * The decoder of a {@link JitPassage} to support JIT-accelerated p-code emulation.
 * 
 * <p>
 * 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
 * {@link JitCompiledPassage#run(int) run} method for the required entry point.
 * 
 * <h2>Decoding a Passage</h2>
 * <p>
 * Decode starts with a single seed, which is the entry point required by the emulator. As such,
 * that seed <em>must</em> 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 <em>in the same passage</em>, 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.
 * 
 * <p>
 * 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 ({@link PcodeOp#BRANCH
 * branch}, {@link PcodeOp#CBRANCH cbranch}, and {@link PcodeOp#CALL 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 {@link BlockSplitter} from the
 * {@link 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 {@link JitConfiguration quota}.
 * 
 * <p>
 * The seed queue is a list of {@link ExtBranch} records. Each stride is decoded by removing a seed
 * from that queue, decoding instructions, emitting ops, and then creating an {@link IntBranch}
 * record targeting the first op of the newly-decoded instruction. The {@link Branch#from() from}
 * field is taken from the seed {@link 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 {@link JitPassage#getBranches() 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 {@link IntBranch} records, too. For indirect branches
 * ({@link PcodeOp#BRANCHIND branchind}, {@link PcodeOp#CALLIND callind}, and {@link PcodeOp#RETURN
 * return}), we create {@link IndBranch} records. For error cases (e.g.,
 * {@link PcodeOp#UNIMPLEMENTED unimplemented}), we create {@link ErrBranch} records.
 * 
 * @implNote The process described above is actually implemented in {@link DecoderForOnePassage}.
 *           This class just keeps the configuration and some other trappings, and instantiates an
 *           actual decoder upon requesting a seed.
 */
public class JitPassageDecoder {
	final JitPcodeThread thread;

	final InstructionDecoder decoder;
	final ProgramContext defaultContext;
	final Register contextreg;
	final DecoderUseropLibrary library;

	/**
	 * Construct a passage decoder
	 * 
	 * @param thread the thread whose instruction decoder, context, and userop library to use.
	 */
	public JitPassageDecoder(JitPcodeThread thread) {
		this.thread = thread;

		this.decoder = thread.getDecoder();
		this.defaultContext = thread.getDefaultContext();
		this.contextreg =
			defaultContext == null ? Register.NO_CONTEXT : defaultContext.getBaseContextRegister();
		this.library = new DecoderUseropLibrary(thread.getUseropLibrary());
	}

	/**
	 * Decode a passage starting at the given seed
	 *
	 * @param seed the seed address
	 * @param ctxIn the seed contextreg value
	 * @param maxOps the maximum-ish number of p-code ops to emit
	 * @see #decodePassage(AddrCtx, int)
	 * @return the decoded passage
	 */
	public JitPassage decodePassage(Address seed, RegisterValue ctxIn, int maxOps) {
		return decodePassage(new AddrCtx(ctxIn, seed), maxOps);
	}

	/**
	 * Decode a passage starting at the given seed
	 * 
	 * <p>
	 * We provide a {@code maxOps} parameter so that the configured
	 * {@link JitConfiguration#maxPassageOps() option} 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.
	 * 
	 * @param seed the required entry point, where decode will start
	 * @param maxOps the maximum-ish number of p-codes to emit
	 * @return the decoded passage
	 */
	public JitPassage decodePassage(AddrCtx seed, int maxOps) {
		DecoderForOnePassage forOne = new DecoderForOnePassage(this, seed, maxOps);
		forOne.decodePassage();
		return forOne.finish();
	}

	/**
	 * Decode a single instruction
	 * 
	 * @param address the address of the instruction
	 * @param ctx the input decode context
	 * @return the decoded instruction, or a {@link DecodeErrorInstruction}.
	 */
	PseudoInstruction decodeInstruction(Address address, RegisterValue ctx) {
		try {
			return decoder.decodeInstruction(address, ctx);
		}
		catch (DecodePcodeExecutionException e) {
			return JitPassage.decodeError(decoder.getLanguage(), address, ctx, e.getMessage());
		}
	}
}
