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.opt.inlining;
014
015import org.jikesrvm.classloader.RVMMethod;
016import org.jikesrvm.compilers.opt.OptOptions;
017
018/**
019 * Instances of this class represent decisions to inline.
020 */
021public final class InlineDecision {
022  private enum Code {
023    /**
024     * Symbolic constant coding internal state.
025     */
026    DECIDE_NO,
027    /**
028     * Symbolic constant coding internal state.
029     */
030    DECIDE_YES,
031    /**
032     * Symbolic constant coding internal state.
033     */
034    GUARDED_YES
035  }
036
037  /**
038   * Rationale for this decision
039   */
040  private final String rationale;
041  /**
042   * Holds characterization of this decision.
043   */
044  private final Code code;
045  /**
046   * The set of methods to inline.
047   */
048  private final RVMMethod[] targets;
049  /**
050   * The set of guards to use (only valid when code == GUARDED_YES)
051   */
052  private final byte[] guards;
053
054  /**
055   * Should the test-failed block be replaced with an OSR point?
056   */
057  private boolean testFailedOSR = false;
058
059  /**
060   * @param targets   The methods to inline
061   * @param guards the chosen guards. will be {@code null} if no guards are necessary
062   * @param code the decision code
063   * @param reason a string rationale
064   */
065  private InlineDecision(RVMMethod[] targets, byte[] guards, Code code, String reason) {
066    this.code = code;
067    this.rationale = reason;
068    this.targets = targets;
069    this.guards = guards;
070  }
071
072  /**
073   * Return a decision NOT to inline.
074   *
075   * @param target the method that is not being inlined.
076   * @param reason a rationale for not inlining
077   * @return a decision NOT to inline
078   */
079  public static InlineDecision NO(RVMMethod target, String reason) {
080    RVMMethod[] targets = new RVMMethod[1];
081    targets[0] = target;
082    return new InlineDecision(targets, null, Code.DECIDE_NO, reason);
083  }
084
085  /**
086   * Return a decision NOT to inline.
087   *
088   * @param reason a rationale for not inlining
089   * @return a decision NOT to inline
090   */
091  public static InlineDecision NO(String reason) {
092    return new InlineDecision(null, null, Code.DECIDE_NO, reason);
093  }
094
095  /**
096   * Return a decision to inline without a guard.
097   * @param target the method to inline
098   * @param reason a rationale for inlining
099   * @return a decision YES to inline
100   */
101  public static InlineDecision YES(RVMMethod target, String reason) {
102    RVMMethod[] targets = new RVMMethod[1];
103    targets[0] = target;
104    return new InlineDecision(targets, null, Code.DECIDE_YES, reason);
105  }
106
107  /**
108   * Return a decision YES to do a guarded inline.
109   *
110   * @param target the method to inline
111   * @param guard  the type of guard to use
112   * @param reason a rationale for inlining
113   * @return a decision YES to inline, but it is not always safe.
114   */
115  public static InlineDecision guardedYES(RVMMethod target, byte guard, String reason) {
116    RVMMethod[] targets = new RVMMethod[1];
117    byte[] guards = new byte[1];
118    targets[0] = target;
119    guards[0] = guard;
120    return new InlineDecision(targets, guards, Code.GUARDED_YES, reason);
121  }
122
123  /**
124   * Return a decision YES to do a guarded inline.
125   *
126   * @param targets   The methods to inline
127   * @param guards  the types of guard to use
128   * @param reason   A rationale for inlining
129   * @return a decision YES to inline, but it is not always safe.
130   */
131  public static InlineDecision guardedYES(RVMMethod[] targets, byte[] guards, String reason) {
132    return new InlineDecision(targets, guards, Code.GUARDED_YES, reason);
133  }
134
135  /**
136   * @return whether this inline decision is a YES
137   */
138  public boolean isYES() {
139    return !isNO();
140  }
141
142  /**
143   * @return whether this inline decision is a NO
144   */
145  public boolean isNO() {
146    return (code == Code.DECIDE_NO);
147  }
148
149  /**
150   * @return whether this inline site needs a guard
151   */
152  public boolean needsGuard() {
153    return (code == Code.GUARDED_YES);
154  }
155
156  /**
157   * @return the methods to inline according to this decision.
158   */
159  public RVMMethod[] getTargets() {
160    return targets;
161  }
162
163  /**
164   * @return the guards to use according to this decision.
165   */
166  public byte[] getGuards() {
167    return guards;
168  }
169
170  /**
171   * @return the number methods to inline
172   */
173  public int getNumberOfTargets() {
174    if (targets == null) {
175      return 0;
176    }
177    return targets.length;
178  }
179
180  public void setOSRTestFailed() {
181    testFailedOSR = true;
182  }
183
184  public boolean OSRTestFailed() {
185    return testFailedOSR;
186  }
187
188  @Override
189  public String toString() {
190    StringBuilder s = new StringBuilder(code.toString());
191    if (testFailedOSR) {
192      s.append("(OSR off-branch)");
193    }
194    s.append(':');
195    s.append(rationale);
196    if (targets != null) {
197      for (int i = 0; i < targets.length; i++) {
198        s.append(' ');
199        s.append(targets[i]);
200        if (guards != null) {
201          switch (guards[i]) {
202            case OptOptions.INLINE_GUARD_METHOD_TEST:
203              s.append(" (method test)");
204              break;
205            case OptOptions.INLINE_GUARD_CLASS_TEST:
206              s.append(" (class test)");
207              break;
208            case OptOptions.INLINE_GUARD_CODE_PATCH:
209              s.append(" (code patch)");
210              break;
211          }
212        }
213      }
214    }
215    return s.toString();
216  }
217}