All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.opalj.br.instructions.SimpleConditionalBranchInstruction.scala Maven / Gradle / Ivy

The newest version!
/* BSD 2-Clause License - see OPAL/LICENSE for details. */
package org.opalj
package br
package instructions

/**
 * Common superclass of all instructions that perform a conditional jump.
 *
 * @author Michael Eichberg
 */
trait SimpleConditionalBranchInstructionLike
    extends ConditionalBranchInstructionLike
    with SimpleBranchInstructionLike {

    /**
     * The comparison operator (incl. the constant) underlying the if instruction.
     * E.g., `<`, `< 0` or `!= null`.
     */
    def operator: String

    final def length: Int = 3

    final def isIsomorphic(thisPC: PC, otherPC: PC)(implicit code: Code): Boolean = {
        val other = code.instructions(otherPC)
        (this eq other) || (this == other)
    }
}

trait SimpleConditionalBranchInstruction[T <: SimpleConditionalBranchInstruction[T]]
    extends ConditionalBranchInstruction
    with SimpleBranchInstruction
    with SimpleConditionalBranchInstructionLike {

    def copy(branchoffset: Int): SimpleConditionalBranchInstruction[T]

    /**
     * Returns the IF instruction that - when compared with this if instruction -
     * performs a jump in case of a fall-through and vice-versa. I.e., given the
     * following condition: `(a < b)`, the negation is performend: `!(a < b)` which
     * is equivalent to `(a ≥ b)`. In other words,  if this IF instruction is an
     * IFGT instruction and IFLE instruction is returned.
     */
    def negate(newBranchoffset: Int = branchoffset): SimpleConditionalBranchInstruction[_]

    final override def isSimpleConditionalBranchInstruction: Boolean = true
    final override def asSimpleConditionalBranchInstruction: this.type = this

    /**
     * @inheritdoc
     *
     * A simple conditional branch instruction has two targets unless both targets point
     * to the same instruction. In that case the jump has only one target, because the state
     * - independent of the taken path - always has to be the same.
     */
    final def nextInstructions(
        currentPC:             PC,
        regularSuccessorsOnly: Boolean
    )(
        implicit
        code:           Code,
        classHierarchy: ClassHierarchy = ClassHierarchy.PreInitializedClassHierarchy
    ): List[PC] = {
        val nextInstruction = indexOfNextInstruction(currentPC)
        val jumpInstruction = currentPC + branchoffset
        if (nextInstruction == jumpInstruction)
            List(nextInstruction)
        else
            List(nextInstruction, jumpInstruction)
    }

    override def toString(currentPC: Int): String = {
        val jumpDirection = if (branchoffset >= 0) "↓" else "↑"
        s"${getClass.getSimpleName}(true=${currentPC + branchoffset}$jumpDirection, false=↓)"
    }

}
/**
 * Extractor for [[SimpleConditionalBranchInstruction]]s.
 */
object SimpleConditionalBranchInstruction {

    /**
     * Extracts the instructions branchoffset.
     */
    def unapply(i: SimpleConditionalBranchInstruction[_ <: SimpleConditionalBranchInstruction[_]]): Some[Int] = Some(i.branchoffset)

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy