001/*
002 *  This file is part of the Jikes RVM project (http://jikesrvm.org).
003 *
004 *  This file is licensed to You under the Eclipse Public License (EPL);
005 *  You may not use this file except in compliance with the License. You
006 *  may obtain a copy of the License at
007 *
008 *      http://www.opensource.org/licenses/eclipse-1.0.php
009 *
010 *  See the COPYRIGHT.txt file distributed with this work for information
011 *  regarding copyright ownership.
012 */
013package org.jikesrvm.compilers.baseline;
014
015/**
016 * Structure to describe the basic blocks of the byte code Used in calculating
017 * stack map and local variable map for the garbage collector.
018 */
019final class BasicBlock {
020
021  // NOTE: Block number 1 is the epilog block, the only block
022  // that exits from the method. Blocks that end in a return will
023  // have the exit block as their only successor.
024  // NOTE: Block number 0 is NOT used;
025
026  // ------------------- Static Class Fields -----------------
027
028  static final int NOTBLOCK = 0;
029  static final int EXITBLOCK = 1;
030  static final int STARTPREDSIZE = 4;
031  static final int STARTBBNUMBER = 2;
032
033  static final byte JSRENTRY = 1;
034  static final byte JSREXIT = 2;
035  static final byte METHODENTRY = 4;
036  static final byte TRYSTART = 8;
037  static final byte TRYBLOCK = 16;
038  static final byte INJSR = 32;
039  static final byte TRYHANDLERSTART = 64;
040
041  // --------------------- Instance Fields ---------------------
042
043  /** ID number (index into block array) */
044  private final int blockNumber;
045  /** starting byte in byte code array */
046  private int start;
047  /** ending byte in byte code array */
048  private int end;
049  /** number of preceding basic blocks */
050  private int predcount = 0;
051  // First 2 are listed individually.
052  private short pred1;
053  private short pred2;
054  /** list of rest preceding basic blocks */
055  private short[] restPredecessors;
056  // may be bigger then predcount;
057  /** additional state info for jsr handling, and other flags */
058  private byte state = 0;
059
060  // --------------- Constructor --------------------------------
061
062  /**
063   * This should be called only from the factory.
064   *
065   * @param startval byte index where block starts
066   * @param bn the block's number
067   *  */
068  BasicBlock(int startval, int bn) {
069    blockNumber = bn;
070    start = startval;
071  }
072
073  /**
074   * This should be used when building the EXIT block EXIT is likely to have
075   * several predecessors.
076   *
077   * @param startval byte index where block starts
078   * @param endval byte index where block starts
079   * @param blockNumber the block's number
080   */
081  BasicBlock(int startval, int endval, int blockNumber) {
082    start = startval;
083    end = endval;
084    this.blockNumber = blockNumber;
085    restPredecessors = new short[STARTPREDSIZE];
086  }
087
088  // ------------------ Static Methods -------------------------
089
090  static void transferPredecessors(BasicBlock fromBB,
091      BasicBlock toBB) {
092    toBB.predcount = fromBB.predcount;
093    toBB.pred1 = fromBB.pred1;
094    toBB.pred2 = fromBB.pred2;
095    toBB.restPredecessors = fromBB.restPredecessors;
096
097    fromBB.predcount = 0;
098    fromBB.restPredecessors = null;
099  }
100
101  // -------------------------- Instance Methods ----------------
102
103  void setStart(int startval) {
104    start = startval;
105  }
106
107  void setEnd(int endval) {
108    end = endval;
109  }
110
111  void setState(byte stateval) {
112    state |= stateval;
113  }
114
115  int getStart() {
116    return start;
117  }
118
119  int getEnd() {
120    return end;
121  }
122
123  int getBlockNumber() {
124    return blockNumber;
125  }
126
127  byte getState() {
128    return state;
129  }
130
131  boolean isJSRExit() {
132    return ((state & JSREXIT) == JSREXIT);
133  }
134
135  boolean isJSREntry() {
136    return ((state & JSRENTRY) == JSRENTRY);
137  }
138
139  boolean isInJSR() {
140    return ((state & INJSR) == INJSR);
141  }
142
143  boolean isMethodEntry() {
144    return ((state & METHODENTRY) == METHODENTRY);
145  }
146
147  boolean isTryStart() {
148    return ((state & TRYSTART) == TRYSTART);
149  }
150
151  boolean isTryBlock() {
152    return ((state & TRYBLOCK) == TRYBLOCK);
153  }
154
155  boolean isTryHandlerStart() {
156    return ((state & TRYHANDLERSTART) == TRYHANDLERSTART);
157  }
158
159  void addPredecessor(BasicBlock predbb) {
160    predcount++;
161    if (predcount == 1) {
162      pred1 = (short) predbb.getBlockNumber();
163    } else if (predcount == 2) {
164      pred2 = (short) predbb.getBlockNumber();
165    } else if (restPredecessors == null) {
166      restPredecessors = new short[STARTPREDSIZE];
167      restPredecessors[predcount - 3] = (short) predbb.getBlockNumber();
168    } else {
169      if (restPredecessors.length <= predcount - 3) {
170        short[] newpreds = new short[predcount << 1];
171        int restLength = restPredecessors.length;
172        for (int i = 0; i < restLength; i++) {
173          newpreds[i] = restPredecessors[i];
174        }
175        restPredecessors = newpreds;
176        newpreds = null;
177      }
178      restPredecessors[predcount - 3] = (short) predbb.getBlockNumber();
179      // -3 to get it zero-based
180    }
181  }
182
183  /**
184   * This method first checks if a block is already on the predecessor list.
185   * Used with try blocks being added to their catch block as predecessors.
186   *
187   * @param predbb block to add as predecessor
188   */
189  void addUniquePredecessor(BasicBlock predbb) {
190    boolean dupFound = false, checkMade = false;
191    short predbbNum = (short) predbb.getBlockNumber();
192
193    if (predcount >= 1) {
194      if (pred1 == predbbNum) {
195        return;
196      }
197
198      if (predcount > 1) {
199        if (pred2 == predbbNum) {
200          return;
201        }
202
203        if (predcount > 2) {
204          if (restPredecessors.length <= predcount - 2) {
205            short[] newpreds = new short[predcount << 1];
206            int restLength = restPredecessors.length;
207            for (int i = 0; i < restLength; i++) {
208              if (restPredecessors[i] == predbbNum) {
209                dupFound = true; // finish up the copy anyway.
210              }
211              newpreds[i] = restPredecessors[i];
212            }
213            restPredecessors = newpreds;
214            newpreds = null;
215
216            if (dupFound)
217              return;
218            checkMade = true;
219          }
220
221          if (!checkMade) {
222            for (int i = 0; i < predcount - 2; i++) {
223              if (restPredecessors[i] == predbbNum) {
224                return;
225              }
226            }
227          }
228
229          predcount++;
230          restPredecessors[predcount - 3] = predbbNum;
231        } else { // predcount must be 2
232          restPredecessors = new short[STARTPREDSIZE];
233          predcount++;
234          restPredecessors[predcount - 3] = predbbNum;
235        }
236      } else {
237        // predcount must be 1
238        predcount++;
239        pred2 = predbbNum;
240      }
241    } else { // predcount must be 0
242      predcount++;
243      pred1 = predbbNum;
244    }
245  }
246
247  int[] getPredecessors() {
248    int[] preds;
249    preds = new int[predcount];
250    if (predcount >= 1) {
251      preds[0] = pred1;
252    }
253    if (predcount > 1) {
254      preds[1] = pred2;
255    }
256    for (int i = 0; i < predcount - 2; i++) {
257      preds[i + 2] = restPredecessors[i];
258    }
259    return preds;
260
261  }
262
263}