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

org.jruby.compiler.ir.representations.CFG Maven / Gradle / Ivy

package org.jruby.compiler.ir.representations;

import java.util.ArrayList;
import java.util.BitSet;
import java.util.HashSet;
import java.util.HashMap;
import java.util.ListIterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Stack;

import org.jruby.compiler.ir.IRExecutionScope;
import org.jruby.compiler.ir.IRClosure;
import org.jruby.compiler.ir.IRMethod;
import org.jruby.compiler.ir.Operation;
import org.jruby.compiler.ir.Tuple;
import org.jruby.compiler.ir.instructions.BranchInstr;
import org.jruby.compiler.ir.instructions.BREAK_Instr;
import org.jruby.compiler.ir.instructions.CaseInstr;
import org.jruby.compiler.ir.instructions.CallInstr;
import org.jruby.compiler.ir.instructions.Instr;
import org.jruby.compiler.ir.instructions.JumpInstr;
import org.jruby.compiler.ir.instructions.JUMP_INDIRECT_Instr;
import org.jruby.compiler.ir.instructions.LABEL_Instr;
import org.jruby.compiler.ir.instructions.MethodLookupInstr;
import org.jruby.compiler.ir.instructions.ExceptionRegionStartMarkerInstr;
import org.jruby.compiler.ir.instructions.ExceptionRegionEndMarkerInstr;
import org.jruby.compiler.ir.instructions.ReturnInstr;
import org.jruby.compiler.ir.instructions.SET_RETADDR_Instr;
import org.jruby.compiler.ir.instructions.THROW_EXCEPTION_Instr;
import org.jruby.compiler.ir.instructions.YieldInstr;
import org.jruby.compiler.ir.operands.Nil;
import org.jruby.compiler.ir.operands.Label;
import org.jruby.compiler.ir.operands.MetaObject;
import org.jruby.compiler.ir.operands.Operand;
import org.jruby.compiler.ir.operands.Variable;
import org.jruby.compiler.ir.operands.LocalVariable;

import org.jruby.compiler.ir.dataflow.DataFlowProblem;

import org.jgrapht.*;
import org.jgrapht.graph.*;

public class CFG {
    public enum CFG_Edge_Type { REGULAR, DUMMY_EDGE, JUMP_EDGE, FALLTHRU_EDGE, FORWARD_EDGE, BACK_EDGE, EXIT_EDGE, EXCEPTION_EDGE }

    public static class CFG_Edge {
        final public BasicBlock _src;
        final public BasicBlock _dst;
        public CFG_Edge_Type _type;

        public CFG_Edge(BasicBlock s, BasicBlock d) {
            _src = s;
            _dst = d;
            _type = CFG_Edge_Type.REGULAR;   // Unknown type to start with
        }

        @Override
        public String toString() {
            return "<" + _src.getID() + " --> " + _dst.getID() + "> (" + _type + ")";
        }
    }

    IRExecutionScope _scope;   // Scope (method/closure) to which this cfg belongs
    BasicBlock _entryBB;        // Entry BB -- dummy
    BasicBlock _exitBB;         // Exit BB -- dummy
    int        _nextBBId;       // Next available basic block id
    DirectedGraph _cfg;           // The actual graph
    LinkedList              _postOrderList; // Post order traversal list of the cfg
    Map        _dfProbs;       // Map of name -> dataflow problem
    Map              _bbMap;         // Map of label -> basic blocks with that label
    BasicBlock[]                        _fallThruMap;   // Map of basic block id -> fall thru basic block
    List                    _linearizedBBList;  // Linearized list of bbs
    Map         _bbRescuerMap;  // Map of bb -> first bb of the rescue block that initiates exception handling for all exceptions thrown within this bb
    List               _outermostERs;  // Outermost exception regions

    private Instr[]       _instrs;
    private Set _definedLocalVars;  // Local variables defined in this scope
    private Set _usedLocalVars;     // Local variables used in this scope

    public CFG(IRExecutionScope s) {
        _nextBBId = 0; // Init before building basic blocks below!
        _scope = s;
        _postOrderList = null;
        _dfProbs = new HashMap();
        _bbMap = new HashMap();
        _outermostERs = new ArrayList();
        _bbRescuerMap = new HashMap();
        _instrs = null;
    }

    public DirectedGraph getGraph() {
        return _cfg;
    }

    public IRExecutionScope getScope() {
        return _scope;
    }

    public BasicBlock getEntryBB() {
        return _entryBB;
    }

    public BasicBlock getExitBB() {
        return _exitBB;
    }

    public int getNextBBID() {
        _nextBBId++;
        return _nextBBId;
    }

    public int getMaxNodeID() {
        return _nextBBId;
    }

    // NOTE: Because nodes can be removed, this may be smaller than getMaxNodeID()
    public int numNodes() {
        return _cfg.vertexSet().size();
    }

    public Set incomingEdgesOf(BasicBlock bb) {
        return _cfg.incomingEdgesOf(bb);
    }

    public Set outgoingEdgesOf(BasicBlock bb) {
        return _cfg.outgoingEdgesOf(bb);
    }

    public Set getNodes() {
        return _cfg.vertexSet();
    }

    public BasicBlock getTargetBB(Label l) {
        return _bbMap.get(l);
    }

    // SSS: For now, do this with utmost inefficiency!
    // This keeps regular code execution fast.
    public int getRescuerPC(Instr excInstr) {
        for (BasicBlock b: _linearizedBBList) {
            for (Instr i: b.getInstrs()) {
                if (i == excInstr) {
                    BasicBlock rescuerBB = _bbRescuerMap.get(b);
                    if (rescuerBB == null)
                        return -1;
                    else
                        return rescuerBB.getLabel().getTargetPC();
                }
            }
        }

        // SSS FIXME: Cannot happen! Throw runtime exception
        System.err.println("Fell through looking for rescuer ipc for " + excInstr);
        return -1;
    }

    private Label getNewLabel() {
        return _scope.getNewLabel();
    }

    private BasicBlock createNewBB(Label l, DirectedGraph g, Map bbMap, Stack nestedExceptionRegions) {
        BasicBlock b = new BasicBlock(this, l);
        bbMap.put(b._label, b);
        g.addVertex(b);
        if (!nestedExceptionRegions.empty())
            nestedExceptionRegions.peek().addBB(b);
        return b;
    }

    private BasicBlock createNewBB(DirectedGraph g, Map bbMap, Stack nestedExceptionRegions) {
        return createNewBB(getNewLabel(), g, bbMap, nestedExceptionRegions);
    }

    private void removeBB(BasicBlock b) {
        _cfg.removeVertex(b);
        _bbMap.remove(b._label);
        _bbRescuerMap.remove(b);
        // SSS FIXME: Patch up rescued regions as well??
    }

    private void addEdge(DirectedGraph g, BasicBlock src, Label tgt, Map bbMap, Map> forwardRefs) {
        BasicBlock tgtBB = bbMap.get(tgt);
        if (tgtBB != null) {
            g.addEdge(src, tgtBB);
        } else {
            // Add a forward reference from tgt -> src
            List frefs = forwardRefs.get(tgt);
            if (frefs == null) {
                frefs = new ArrayList();
                forwardRefs.put(tgt, frefs);
            }
            frefs.add(src);
        }
    }

    private DefaultDirectedGraph getNewCFG() {
        return new DefaultDirectedGraph(
                    new EdgeFactory() {
                        public CFG_Edge createEdge(BasicBlock s, BasicBlock d) { return new CFG_Edge(s, d); }
                    });
    }

    public Instr[] prepareForInterpretation() {
        if (_instrs != null) // Done
            return _instrs;

        List instrs = new ArrayList();
        List bbs = linearize();

        // Set up a bb array that maps labels to targets -- just to make sure old code continues to work! 
        setupFallThruMap();

        // Set up IPCs
        HashMap labelIPCMap = new HashMap();
        List




© 2015 - 2025 Weber Informatics LLC | Privacy Policy