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.opt.inlining;
014    
015    import org.jikesrvm.classloader.RVMMethod;
016    import org.jikesrvm.compilers.opt.OptOptions;
017    
018    /**
019     * Instances of this class represent decisions to inline.
020     */
021    public 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 code the decision code
062       * @param reason a string rationale
063       */
064      private InlineDecision(RVMMethod[] targets, byte[] guards, Code code, String reason) {
065        this.code = code;
066        this.rationale = reason;
067        this.targets = targets;
068        this.guards = guards;
069      }
070    
071      /**
072       * Return a decision NOT to inline.
073       *
074       * @param target the method that is not being inlined.
075       * @param reason a rationale for not inlining
076       * @return a decision NOT to inline
077       */
078      public static InlineDecision NO(RVMMethod target, String reason) {
079        RVMMethod[] targets = new RVMMethod[1];
080        targets[0] = target;
081        return new InlineDecision(targets, null, Code.DECIDE_NO, reason);
082      }
083    
084      /**
085       * Return a decision NOT to inline.
086       *
087       * @param reason a rationale for not inlining
088       * @return a decision NOT to inline
089       */
090      public static InlineDecision NO(String reason) {
091        return new InlineDecision(null, null, Code.DECIDE_NO, reason);
092      }
093    
094      /**
095       * Return a decision to inline without a guard.
096       * @param target the method to inline
097       * @param reason a rationale for inlining
098       * @return a decision YES to inline
099       */
100      public static InlineDecision YES(RVMMethod target, String reason) {
101        RVMMethod[] targets = new RVMMethod[1];
102        targets[0] = target;
103        return new InlineDecision(targets, null, Code.DECIDE_YES, reason);
104      }
105    
106      /**
107       * Return a decision YES to do a guarded inline.
108       *
109       * @param target the method to inline
110       * @param guard  the type of guard to use
111       * @param reason a rationale for inlining
112       * @return a decision YES to inline, but it is not always safe.
113       */
114      public static InlineDecision guardedYES(RVMMethod target, byte guard, String reason) {
115        RVMMethod[] targets = new RVMMethod[1];
116        byte[] guards = new byte[1];
117        targets[0] = target;
118        guards[0] = guard;
119        return new InlineDecision(targets, guards, Code.GUARDED_YES, reason);
120      }
121    
122      /**
123       * Return a decision YES to do a guarded inline.
124       *
125       * @param targets   The methods to inline
126       * @param guards  the types of guard to use
127       * @param reason   A rationale for inlining
128       * @return a decision YES to inline, but it is not always safe.
129       */
130      public static InlineDecision guardedYES(RVMMethod[] targets, byte[] guards, String reason) {
131        return new InlineDecision(targets, guards, Code.GUARDED_YES, reason);
132      }
133    
134      /**
135       * Is this inline decision a YES?
136       */
137      public boolean isYES() {
138        return !isNO();
139      }
140    
141      /**
142       * Is this inline decision a NO?
143       */
144      public boolean isNO() {
145        return (code == Code.DECIDE_NO);
146      }
147    
148      /**
149       * Does this inline site need a guard?
150       */
151      public boolean needsGuard() {
152        return (code == Code.GUARDED_YES);
153      }
154    
155      /**
156       * Return the methods to inline according to this decision.
157       */
158      public RVMMethod[] getTargets() {
159        return targets;
160      }
161    
162      /**
163       * Return the guards to use according to this decision.
164       */
165      public byte[] getGuards() {
166        return guards;
167      }
168    
169      /**
170       * Return the number methods to inline.
171       */
172      public int getNumberOfTargets() {
173        if (targets == null) {
174          return 0;
175        }
176        return targets.length;
177      }
178    
179      public void setOSRTestFailed() { testFailedOSR = true; }
180    
181      public boolean OSRTestFailed() { return testFailedOSR; }
182    
183      @Override
184      public String toString() {
185        String s = code.toString();
186        if (testFailedOSR) {
187          s += "(OSR off-branch)";
188        }
189        s += ":" + rationale;
190        if (targets != null) {
191          for (int i = 0; i < targets.length; i++) {
192            s += " " + targets[i];
193            if (guards != null) {
194              switch (guards[i]) {
195                case OptOptions.INLINE_GUARD_METHOD_TEST:
196                  s += " (method test)";
197                  break;
198                case OptOptions.INLINE_GUARD_CLASS_TEST:
199                  s += " (class test)";
200                  break;
201                case OptOptions.INLINE_GUARD_CODE_PATCH:
202                  s += " (code patch)";
203                  break;
204              }
205            }
206          }
207        }
208        return s;
209      }
210    }