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.classloader.NormalMethod;
017import org.jikesrvm.compilers.opt.ir.Instruction;
018import org.jikesrvm.compilers.opt.util.Stack;
019
020/**
021 * Represents an inlining sequence.
022 * Used to uniquely identify program locations.
023 */
024public 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   * @param m the method to search for
141   * @return whether this inline sequence contains a given method
142   */
143  public boolean containsMethod(RVMMethod m) {
144    if (method == m) return true;
145    if (caller == null) return false;
146    return (caller.containsMethod(m));
147  }
148
149  public java.util.Enumeration<InlineSequence> enumerateFromRoot() {
150    return new java.util.Enumeration<InlineSequence>() {
151      Stack<InlineSequence> stack;
152
153      {
154        stack = new Stack<InlineSequence>();
155        InlineSequence parent = InlineSequence.this;
156        while (parent.caller != null) {
157          stack.push(parent);
158          parent = parent.caller;
159        }
160      }
161
162      @Override
163      public boolean hasMoreElements() {
164        return !stack.isEmpty();
165      }
166
167      @Override
168      public InlineSequence nextElement() {
169        return stack.pop();
170      }
171    };
172  }
173
174  @Override
175  public int hashCode() {
176    final int prime = 31;
177    int result = 1;
178    result = prime * result + bcIndex;
179    result = prime * result + ((caller == null) ? 0 : caller.hashCode());
180    result = prime * result + ((method == null) ? 0 : method.hashCode());
181    return result;
182  }
183
184  @Override
185  public boolean equals(Object obj) {
186    if (this == obj)
187      return true;
188    if (obj == null)
189      return false;
190    if (getClass() != obj.getClass())
191      return false;
192    InlineSequence other = (InlineSequence) obj;
193    if (bcIndex != other.bcIndex)
194      return false;
195    if (caller == null) {
196      if (other.caller != null)
197        return false;
198    } else if (!caller.equals(other.caller))
199      return false;
200    if (method == null) {
201      if (other.method != null)
202        return false;
203    } else if (!method.equals(other.method))
204      return false;
205    return true;
206  }
207
208}