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.  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      public boolean equals(Object o) {
060        if (!(o instanceof InlineSequence)) return false;
061        InlineSequence is = (InlineSequence) o;
062        if (method == null) return (is.method == null);
063        if (!method.equals(is.method)) return false;
064        if (bcIndex != is.bcIndex) return false;
065        if (caller == null) return (is.caller == null);
066        return (caller.equals(is.caller));
067      }
068    
069      /**
070       * Constructs a new top-level inline sequence operand.
071       *
072       * @param method current method
073       */
074      public InlineSequence(NormalMethod method) {
075        this(method, null, -1);
076      }
077    
078      /**
079       * Constructs a new inline sequence operand.
080       *
081       * @param method current method
082       * @param caller caller info
083       * @param bcIndex bytecode index of call site
084       */
085      InlineSequence(NormalMethod method, InlineSequence caller, int bcIndex) {
086        this.method = method;
087        this.caller = caller;
088        this.callSite = null;
089        this.bcIndex = bcIndex;
090      }
091    
092      /**
093       * Constructs a new inline sequence operand.
094       *
095       * @param method current method
096       * @param caller caller info
097       * @param callsite the call site instruction of this callee
098       */
099      public InlineSequence(NormalMethod method, InlineSequence caller, Instruction callsite) {
100        this.method = method;
101        this.caller = caller;
102        this.callSite = callsite;
103        this.bcIndex = callsite.bcIndex;
104      }
105    
106      public Instruction getCallSite() {
107        return this.callSite;
108      }
109    
110      /**
111       * Returns the string representation of this inline sequence.
112       */
113      public String toString() {
114        StringBuilder sb = new StringBuilder(" ");
115        for (InlineSequence is = this; is != null; is = is.caller) {
116          sb.append(is.method.getDeclaringClass().getDescriptor()).append(" ").
117              append(is.method.getName()).append(" ").
118              append(is.method.getDescriptor()).append(" ").
119              append(is.bcIndex).append(" ");
120        }
121        return sb.toString();
122      }
123    
124      /**
125       * return the depth of inlining: (0 corresponds to no inlining)
126       */
127      public int getInlineDepth() {
128        int depth = 0;
129        InlineSequence parent = this.caller;
130        while (parent != null) {
131          depth++;
132          parent = parent.caller;
133        }
134        return depth;
135      }
136    
137      /**
138       * Return the root method of this inline sequence
139       */
140      public NormalMethod getRootMethod() {
141        InlineSequence parent = this;
142        while (parent.caller != null) {
143          parent = parent.caller;
144        }
145        return parent.method;
146      }
147    
148      /**
149       * Does this inline sequence contain a given method?
150       */
151      public boolean containsMethod(RVMMethod m) {
152        if (method == m) return true;
153        if (caller == null) return false;
154        return (caller.containsMethod(m));
155      }
156    
157      /**
158       * Return a hashcode for this object.
159       *
160       * TODO: Figure out a better hashcode.  Efficiency doesn't matter
161       * for now.
162       *
163       * @return the hashcode for this object.
164       */
165      public int hashCode() {
166        return bcIndex;
167      }
168    
169      public java.util.Enumeration<InlineSequence> enumerateFromRoot() {
170        return new java.util.Enumeration<InlineSequence>() {
171          Stack<InlineSequence> stack;
172    
173          {
174            stack = new Stack<InlineSequence>();
175            InlineSequence parent = InlineSequence.this;
176            while (parent.caller != null) {
177              stack.push(parent);
178              parent = parent.caller;
179            }
180          }
181    
182          public boolean hasMoreElements() {
183            return !stack.isEmpty();
184          }
185    
186          public InlineSequence nextElement() {
187            return stack.pop();
188          }
189        };
190      }
191    }