
org.opalj.br.cfg.BasicBlock.scala Maven / Gradle / Ivy
The newest version!
/* BSD 2-Clause License - see OPAL/LICENSE for details. */
package org.opalj.br.cfg
import org.opalj.br.Code
/**
* Represents a basic block of a method's control flow graph (CFG). The basic block
* is identified by referring to the first and last instruction belonging to the
* basic block.
*
* @param startPC The pc of the first instruction belonging to the `BasicBlock`.
*
* @author Erich Wittenbeck
* @author Michael Eichberg
*/
// IMPROVE create specialized implementations for the most common cases: (1) just one instruction and just on predecessor, (2) just one predecessor, (3) just one successor
final class BasicBlock(
val startPC: Int, // <= determines this basic blocks' hash value!
private[cfg] var _endPC: Int = Int.MinValue
) extends CFGNode {
def this(startPC: Int, successors: Set[CFGNode]) = {
this(startPC, Int.MinValue)
this.setSuccessors(successors)
}
final override def nodeId: Int = startPC
def copy(
startPC: Int = this.startPC,
endPC: Int = this.endPC,
predecessors: Set[CFGNode] = this.predecessors,
successors: Set[CFGNode] = this.successors
): BasicBlock = {
val newBB = new BasicBlock(startPC, endPC)
newBB.setPredecessors(predecessors)
newBB.setSuccessors(successors)
newBB
}
final override def isCatchNode: Boolean = false
final override def isExitNode: Boolean = false
final override def isAbnormalReturnExitNode: Boolean = false
final override def isNormalReturnExitNode: Boolean = false
final override def isBasicBlock: Boolean = true
final override def asBasicBlock: this.type = this
def endPC_=(pc: Int): Unit = {
_endPC = pc
}
/**
* The pc of the last instruction belonging to this basic block.
*/
def endPC: Int = _endPC
private[this] var _isStartOfSubroutine: Boolean = false // will be initialized at construction time
def setIsStartOfSubroutine(): Unit = {
_isStartOfSubroutine = true
}
def isStartOfSubroutine: Boolean = _isStartOfSubroutine
/**
* Returns the index of an instruction – identified by its program counter (pc) –
* in a basic block.
*
* ==Example==
* Given a basic block which has five instructions which have the following
* program counters: {0,1,3,5,6}. In this case the index of the instruction with
* program counter 3 will be 2 and in case of the instruction with pc 6 the index
* will be 4.
*
* @param pc The program counter of the instruction for which the index is needed.
* `pc` has to satisfy: `startPC <= pc <= endPC`.
* @param code The code to which this basic block belongs.
*/
def index(pc: Int)(implicit code: Code): Int = {
assert(pc >= startPC && pc <= endPC)
var index = 0
var currentPC = startPC
while (currentPC < pc) {
currentPC = code.pcOfNextInstruction(currentPC)
index += 1
}
index
}
/**
* Calls the function `f` for all instructions - identified by their respective
* pcs - of a basic block.
*
* @param f The function that will be called.
* @param code The [[org.opalj.br.Code]]` object to which this `BasicBlock` implicitly
* belongs.
*/
def foreach[U](f: Int => U)(implicit code: Code): Unit = {
val instructions = code.instructions
var pc = this.startPC
val endPC = this.endPC
while (pc <= endPC) {
f(pc)
pc = instructions(pc).indexOfNextInstruction(pc)
}
}
/**
* Counts the instructions of this basic block.
*/
def countInstructions(implicit code: Code): Int = {
val instructions = code.instructions
var count = 1
val startPC = this.startPC
var pc = instructions(startPC).indexOfNextInstruction(startPC)
val endPC = this.endPC
while (pc <= endPC) {
count += 1
pc = instructions(pc).indexOfNextInstruction(pc)
}
count
}
//
// FOR DEBUGGING/VISUALIZATION PURPOSES
//
override def toString: String = s"BasicBlock(start=$startPC,end=$endPC)"
override def toHRR: Option[String] = Some(s"[$startPC,$endPC]#=${endPC - startPC + 1}")
override def visualProperties: Map[String, String] = {
var visualProperties = Map("shape" -> "box", "labelloc" -> "l")
if (startPC == 0) {
visualProperties += "fillcolor" -> "green"
visualProperties += "style" -> "filled"
}
if (!hasSuccessors) { // in this case something is very broken (internally)...
visualProperties += "shape" -> "octagon"
visualProperties += "fillcolor" -> "gray"
visualProperties += "style" -> "filled"
}
visualProperties
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy