VDBInstructionBasicBlock.st
author Jan Vrany <jan.vrany@fit.cvut.cz>
Mon, 10 Jun 2019 15:22:49 +0100
changeset 166 d55f55ac977b
parent 98 8601c1b9e7ba
child 237 53a7322c7128
permissions -rw-r--r--
plugins/bee: add symbol filter to quickly search through (possibly long) list of symbols.

"
jv:vdb - Visual / VM Debugger
Copyright (C) 2015-now Jan Vrany

This software is licensed under 'Creative Commons Attribution-NonCommercial 4.0 International License'

You may find a full license text in LICENSE.txt or at http://creativecommons.org/licenses/by-nc/4.0/
"
"{ Package: 'jv:vdb' }"

"{ NameSpace: Smalltalk }"

Object subclass:#VDBInstructionBasicBlock
	instanceVariableNames:'instructions precedessors successor1 successor2'
	classVariableNames:''
	poolDictionaries:''
	category:'VDB-UI-Support'
!

!VDBInstructionBasicBlock class methodsFor:'documentation'!

copyright
"
jv:vdb - Visual / VM Debugger
Copyright (C) 2015-now Jan Vrany

This software is licensed under 'Creative Commons Attribution-NonCommercial 4.0 International License'

You may find a full license text in LICENSE.txt or at http://creativecommons.org/licenses/by-nc/4.0/
"
! !

!VDBInstructionBasicBlock class methodsFor:'utilities'!

analyze: instructions
    "
    Analyzes `instructions`, create and connect basic blocks and return
    them in a collection.

    `instructions` parameter should be a list of GDBInstruction or 
    polymorphic objects).
    "
    | blocks curBB firstI |

    "/ Pass 1, initial blocks by cutting after each branch
    "/ or return instruction.
    blocks := OrderedCollection new.
    curBB := VDBInstructionBasicBlock new.
    instructions withIndexDo:[:last :lastI | 
        firstI isNil ifTrue:[
            firstI := lastI
        ].
        last isBranch ifTrue:[
            | prevBB |
            curBB setInstructions: (instructions copyFrom: firstI to: lastI).
            blocks add: curBB.
            prevBB := curBB.
            curBB := VDBInstructionBasicBlock new.
            prevBB setSuccessor1: curBB.
            firstI := nil.
        ] ifFalse:[
        last isReturn ifTrue:[
            curBB setInstructions: (instructions copyFrom: firstI to: lastI).
            blocks add: curBB.
            curBB := VDBInstructionBasicBlock new.
            firstI := nil.
        ]].
    ].
    firstI notNil ifTrue:[
        curBB setInstructions: (instructions copyFrom: firstI).
        blocks add: curBB.
    ].

    "/ Pass 2: iterate ober basic blocks and connect successor2 based on
    "/ last instructions #branchTargetAddress. If target address points in
    "/ the middle of basic block, split it.
    blocks copy do:[:bb | 
        bb last isBranch ifTrue:[
            | targetAddress succBB |

            targetAddress := bb last branchTarget.
            targetAddress notNil ifTrue:[
                "/ Find successor block. Note, that we may found none if the branch target is
                "/ outside given coce.
                succBB := blocks detect:[:e | e includesAddress: targetAddress ] ifNone: [ nil ].
                succBB notNil ifTrue:[ 
                    "/ If `targetAddress` points into the middle of `succBB` we have to split
                    "/ succBB into two.
                    succBB firstAddress < targetAddress ifTrue:[ 
                        | succBBs |

                        succBBs := succBB splitAtAddress: targetAddress.
                        blocks remove: succBB; addAll: succBBs.
                        succBB := succBBs last.
                    ].
                    bb setSuccessor2: succBB.
                ].
            ]
        ].
    ].

    "/ Jo done!!
    ^ blocks.



    ^ blocks

    "Created: / 27-06-2018 / 13:03:16 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 31-08-2018 / 23:50:44 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!VDBInstructionBasicBlock methodsFor:'accessing'!

first
    ^ instructions first

    "Created: / 27-06-2018 / 15:41:58 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

firstAddress
    ^ self first address

    "Created: / 27-06-2018 / 15:41:34 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

last
    ^ instructions last

    "Created: / 27-06-2018 / 15:42:09 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

lastAddress
    ^ self last address

    "Created: / 27-06-2018 / 15:41:38 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

precedessors
    ^ precedessors ? #()

    "Modified: / 16-08-2018 / 11:47:38 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

successor1
    ^ successor1
!

successor2
    ^ successor2
! !

!VDBInstructionBasicBlock methodsFor:'initialization'!

addPrecedessor: aVDBInstructionBlock
    precedessors isNil ifTrue:[ 
        precedessors := Array with: aVDBInstructionBlock.
    ] ifFalse:[ 
        precedessors := precedessors copyWith: aVDBInstructionBlock
    ].

    "Created: / 27-06-2018 / 15:29:27 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

setInstructions: aCollection
    instructions := aCollection

    "Created: / 27-06-2018 / 14:59:31 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

setSuccessor1: aVDBInstructionBasicBlock
    successor1 := aVDBInstructionBasicBlock.
    successor1 addPrecedessor: self.

    "Created: / 27-06-2018 / 15:28:21 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

setSuccessor2: aVDBInstructionBasicBlock
    successor2 := aVDBInstructionBasicBlock.
    successor2 addPrecedessor: self.

    "Created: / 27-06-2018 / 15:28:27 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!VDBInstructionBasicBlock methodsFor:'printing & storing'!

printOn:aStream
    "append a printed representation of the receiver to the argument, aStream"

    super printOn:aStream.
    aStream nextPut: $(.
    self firstAddress printOn: aStream base: 16 size: 15 fill: $0.
    aStream nextPutAll: ' - '.
    self lastAddress printOn: aStream base: 16 size: 15 fill: $0.
    successor1 notNil ifTrue:[ 
        aStream nextPutAll: ' 1> '.
        successor1 firstAddress printOn: aStream base: 16 size: 15 fill: $0.
    ].
    successor2 notNil ifTrue:[ 
        aStream nextPutAll: ' 2> '.
        successor2 firstAddress printOn: aStream base: 16 size: 15 fill: $0.
    ].

    aStream nextPut: $)

    "Modified: / 16-08-2018 / 13:18:37 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!VDBInstructionBasicBlock methodsFor:'queries'!

includes: instruction
    ^ instructions includes: instruction

    "Created: / 27-06-2018 / 15:37:23 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

includesAddress: address
    "Return `true`, if this basic block includes an instruction
     with given address, false otherwise."

    ^ (address between: instructions first address and: instructions last address)

    "Created: / 27-06-2018 / 15:40:55 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!VDBInstructionBasicBlock methodsFor:'utilities'!

splitAtAddress: address
    | splitIdx bb1 bb2 |

    splitIdx := instructions indexOf: (instructions detect:[:e | e address = address ] ifNone:[ nil ]).
    "/ Note, that thhere might not be any instruction with that address, such as
    "/ when ill-code jumps into the middle of instruction...
    splitIdx == 0 ifTrue:[ 
        "/ ...in that case, make no split and return self so this case is 
        "/ transparent to users.
        ^Array with: self.
    ].
    bb1 := self class new setInstructions: (instructions copyTo: splitIdx - 1).
    bb2 := self class new setInstructions: (instructions copyFrom: splitIdx).
    bb1 setSuccessor1: bb2.

    precedessors notEmptyOrNil ifTrue:[
        precedessors do:[:precedessor | 
            precedessor successor1 == self ifTrue:[ 
                precedessor setSuccessor1: bb1.
            ].
            precedessor successor2 == self ifTrue:[ 
                precedessor setSuccessor2: bb1.
            ].
        ].
    ].
    ^ Array with: bb1 with: bb2.

    "Created: / 27-06-2018 / 16:00:17 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 30-08-2018 / 10:57:26 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!VDBInstructionBasicBlock class methodsFor:'documentation'!

version_HG

    ^ '$Changeset: <not expanded> $'
! !