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     */
013    package org.jikesrvm.compilers.baseline;
014    
015    import org.jikesrvm.VM;
016    import org.jikesrvm.classloader.BytecodeConstants;
017    import org.jikesrvm.classloader.BytecodeStream;
018    import org.jikesrvm.classloader.NormalMethod;
019    
020    /**
021     * Profile data for all conditional branches (including switches)
022     * of a single RVMMethod.
023     */
024    public final class BranchProfiles implements BytecodeConstants {
025      private final NormalMethod method;
026      private final int numCounters;
027      private final BranchProfile[] data;
028    
029      /**
030       * Find the BranchProfile for a given bytecode index in the BranchProfile array
031       * @param bcIndex the bytecode index of the branch instruction
032       * @return the desired BranchProfile, or null if it cannot be found.
033       */
034      public BranchProfile getEntry(int bcIndex) {
035        int low = 0;
036        int high = data.length - 1;
037        while (true) {
038          int mid = (low + high) >> 1;
039          int bci = data[mid].getBytecodeIndex();
040          if (bci == bcIndex) {
041            return data[mid];
042          }
043          if (low >= high) {
044            // search failed
045            if (VM.VerifyAssertions) { VM._assert(VM.NOT_REACHED); }
046            return null;
047          }
048          if (bci > bcIndex) {
049            high = mid - 1;
050          } else {
051            low = mid + 1;
052          }
053        }
054      }
055    
056      public void print(java.io.PrintStream ps) {
057        ps.println("M " + numCounters + " " + method.getMemberRef());
058        for (BranchProfile profile : data) {
059          ps.println("\t" + profile);
060        }
061      }
062    
063      BranchProfiles(NormalMethod m, int[] cs) {
064        method = m;
065        numCounters = cs.length;
066    
067        // Originally we only allocate half of the number of edges for branch
068        // profiles, like data = new BranchProfile[cs.length/2]
069        // The conditional branch, tableswitch and lookupswitch all have at
070        // least two edges, supposingly. Then we found that the lookupswitch
071        // bytecode could have only one edge, so the number of branch profiles
072        // is not necessarily less than half of the number of edges.
073        BranchProfile[] data = new BranchProfile[cs.length];
074        BytecodeStream bcodes = m.getBytecodes();
075        int dataIdx = 0;
076        int countIdx = 0;
077    
078        // We didn't record the bytecode index in the profile data to record space.
079        // Therefore we must now recover that information.
080        // We exploit the fact that the baseline compiler generates code in
081        // a linear pass over the bytecodes to make this possible.
082        while (bcodes.hasMoreBytecodes()) {
083          int bcIndex = bcodes.index();
084          int code = bcodes.nextInstruction();
085    
086          switch (code) {
087            case JBC_ifeq:
088            case JBC_ifne:
089            case JBC_iflt:
090            case JBC_ifge:
091            case JBC_ifgt:
092            case JBC_ifle:
093            case JBC_if_icmpeq:
094            case JBC_if_icmpne:
095            case JBC_if_icmplt:
096            case JBC_if_icmpge:
097            case JBC_if_icmpgt:
098            case JBC_if_icmple:
099            case JBC_if_acmpeq:
100            case JBC_if_acmpne:
101            case JBC_ifnull:
102            case JBC_ifnonnull: {
103              if (countIdx >= cs.length) {
104                VM.sysWriteln("Warning: control flow instance encountered outside scope of available edge count array");
105                break;
106              }
107              int yea = cs[countIdx + EdgeCounts.TAKEN];
108              int nea = cs[countIdx + EdgeCounts.NOT_TAKEN];
109              int offset = bcodes.getBranchOffset();
110              boolean backwards = offset < 0;
111              countIdx += 2;
112              data[dataIdx++] = new ConditionalBranchProfile(bcIndex, yea, nea, backwards);
113              break;
114            }
115    
116            case JBC_tableswitch: {
117              if (countIdx >= cs.length) {
118                VM.sysWriteln("Warning: control flow instance encountered outside scope of available edge count array");
119                break;
120              }
121              bcodes.alignSwitch();
122              bcodes.getDefaultSwitchOffset();
123              int low = bcodes.getLowSwitchValue();
124              int high = bcodes.getHighSwitchValue();
125              int n = high - low + 1;
126              data[dataIdx++] = new SwitchBranchProfile(bcIndex, cs, countIdx, n + 1);
127              countIdx += n + 1;
128              bcodes.skipTableSwitchOffsets(n);
129              break;
130            }
131    
132            case JBC_lookupswitch: {
133              if (countIdx >= cs.length) {
134                VM.sysWriteln("Warning: control flow instance encountered outside scope of available edge count array");
135                break;
136              }
137              bcodes.alignSwitch();
138              bcodes.getDefaultSwitchOffset();
139              int numPairs = bcodes.getSwitchLength();
140              data[dataIdx++] = new SwitchBranchProfile(bcIndex, cs, countIdx, numPairs + 1);
141              countIdx += numPairs + 1;
142              bcodes.skipLookupSwitchPairs(numPairs);
143              break;
144            }
145    
146            default:
147              bcodes.skipInstruction();
148              break;
149          }
150        }
151    
152        // Make sure we are in sync
153        if (VM.VerifyAssertions) VM._assert(countIdx == cs.length);
154    
155        if (dataIdx != data.length) {
156          // We had a switch statment; shrink the array.
157          BranchProfile[] newData = new BranchProfile[dataIdx];
158          for (int i = 0; i < dataIdx; i++) {
159            newData[i] = data[i];
160          }
161          data = newData;
162        }
163        this.data = data;
164      }
165    }