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.classloader.NormalMethod;
017    import org.jikesrvm.compilers.opt.ir.Instruction;
018    import org.jikesrvm.compilers.opt.util.Stack;
019    
020    /**
021     * Represents an inlining sequence.
022     * Used to uniquely identify program locations.
023     */
024    public final class InlineSequence {
025      /**
026       * Current method.
027       */
028      public final NormalMethod method;
029    
030      /**
031       * Caller info. {@code null} if none.
032       */
033      public final InlineSequence caller;
034    
035      /**
036       * bytecode index (in caller) of call site
037       */
038      public int bcIndex;
039    
040      /**
041       * We need more detailed information of call site than bcIndex.
042       */
043      final Instruction callSite;
044    
045      /**
046       * @return contents of {@link #method}
047       */
048      public NormalMethod getMethod() {
049        return method;
050      }
051    
052      /**
053       * @return contents of {@link #caller}
054       */
055      public InlineSequence getCaller() {
056        return caller;
057      }
058    
059      /**
060       * Constructs a new top-level inline sequence operand.
061       *
062       * @param method current method
063       */
064      public InlineSequence(NormalMethod method) {
065        this(method, null, -1);
066      }
067    
068      /**
069       * Constructs a new inline sequence operand.
070       *
071       * @param method current method
072       * @param caller caller info
073       * @param bcIndex bytecode index of call site
074       */
075      InlineSequence(NormalMethod method, InlineSequence caller, int bcIndex) {
076        this.method = method;
077        this.caller = caller;
078        this.callSite = null;
079        this.bcIndex = bcIndex;
080      }
081    
082      /**
083       * Constructs a new inline sequence operand.
084       *
085       * @param method current method
086       * @param caller caller info
087       * @param callsite the call site instruction of this callee
088       */
089      public InlineSequence(NormalMethod method, InlineSequence caller, Instruction callsite) {
090        this.method = method;
091        this.caller = caller;
092        this.callSite = callsite;
093        this.bcIndex = callsite.bcIndex;
094      }
095    
096      public Instruction getCallSite() {
097        return this.callSite;
098      }
099    
100      /**
101       * Returns the string representation of this inline sequence.
102       */
103      @Override
104      public String toString() {
105        StringBuilder sb = new StringBuilder(" ");
106        for (InlineSequence is = this; is != null; is = is.caller) {
107          sb.append(is.method.getDeclaringClass().getDescriptor()).append(" ").
108              append(is.method.getName()).append(" ").
109              append(is.method.getDescriptor()).append(" ").
110              append(is.bcIndex).append(" ");
111        }
112        return sb.toString();
113      }
114    
115      /**
116       * return the depth of inlining: (0 corresponds to no inlining)
117       */
118      public int getInlineDepth() {
119        int depth = 0;
120        InlineSequence parent = this.caller;
121        while (parent != null) {
122          depth++;
123          parent = parent.caller;
124        }
125        return depth;
126      }
127    
128      /**
129       * Return the root method of this inline sequence
130       */
131      public NormalMethod getRootMethod() {
132        InlineSequence parent = this;
133        while (parent.caller != null) {
134          parent = parent.caller;
135        }
136        return parent.method;
137      }
138    
139      /**
140       * Does this inline sequence contain a given method?
141       */
142      public boolean containsMethod(RVMMethod m) {
143        if (method == m) return true;
144        if (caller == null) return false;
145        return (caller.containsMethod(m));
146      }
147    
148      public java.util.Enumeration<InlineSequence> enumerateFromRoot() {
149        return new java.util.Enumeration<InlineSequence>() {
150          Stack<InlineSequence> stack;
151    
152          {
153            stack = new Stack<InlineSequence>();
154            InlineSequence parent = InlineSequence.this;
155            while (parent.caller != null) {
156              stack.push(parent);
157              parent = parent.caller;
158            }
159          }
160    
161          @Override
162          public boolean hasMoreElements() {
163            return !stack.isEmpty();
164          }
165    
166          @Override
167          public InlineSequence nextElement() {
168            return stack.pop();
169          }
170        };
171      }
172    
173      @Override
174      public int hashCode() {
175        final int prime = 31;
176        int result = 1;
177        result = prime * result + bcIndex;
178        result = prime * result + ((caller == null) ? 0 : caller.hashCode());
179        result = prime * result + ((method == null) ? 0 : method.hashCode());
180        return result;
181      }
182    
183      @Override
184      public boolean equals(Object obj) {
185        if (this == obj)
186          return true;
187        if (obj == null)
188          return false;
189        if (getClass() != obj.getClass())
190          return false;
191        InlineSequence other = (InlineSequence) obj;
192        if (bcIndex != other.bcIndex)
193          return false;
194        if (caller == null) {
195          if (other.caller != null)
196            return false;
197        } else if (!caller.equals(other.caller))
198          return false;
199        if (method == null) {
200          if (other.method != null)
201            return false;
202        } else if (!method.equals(other.method))
203          return false;
204        return true;
205      }
206    
207    }