1 cananian 1.1.2.1  // CALL.java, created Wed Aug  5 06:48:50 1998 by cananian
  2 cananian 1.1.2.1  // Copyright (C) 1998 C. Scott Ananian <cananian@alumni.princeton.edu>
  3 cananian 1.1.2.1  // Licensed under the terms of the GNU GPL; see COPYING for details.
  4 cananian 1.1.2.1  package harpoon.IR.Quads;
  5 cananian 1.1.2.1  
  6 cananian 1.1.2.1  import java.lang.reflect.Modifier;
  7 cananian 1.1.2.1  
  8 cananian 1.1.2.9  import harpoon.ClassFile.HClass;
  9 cananian 1.1.2.9  import harpoon.ClassFile.HCodeElement;
 10 cananian 1.1.2.9  import harpoon.ClassFile.HConstructor;
 11 cananian 1.1.2.9  import harpoon.ClassFile.HMethod;
 12 cananian 1.1.2.1  import harpoon.Temp.Temp;
 13 cananian 1.1.2.1  import harpoon.Temp.TempMap;
 14 cananian 1.1.2.1  import harpoon.Util.Util;
 15 cananian 1.1.2.2  
 16 cananian 1.1.2.1  /**
 17 cananian 1.1.2.11  * <code>CALL</code> objects represent method invocations. <p>
 18 cananian 1.1.2.1   * The <code>retval</code> field will be <code>null</code>
 19 cananian 1.1.2.1   * for <code>void</code> methods.  For non-static methods, the
 20 cananian 1.1.2.1   * method receiver (object reference on which to invoke the method)
 21 cananian 1.1.2.13  * is the first parameter in the <code>params</code> array.
 22 cananian 1.1.2.13  * <p>
 23 cananian 1.1.2.13  * <code>CALL</code> behaves like a conditional branch: if
 24 cananian 1.1.2.13  * no exception is thrown by the called method, the <code>Temp</code>
 25 cananian 1.1.2.13  * specified by <code>retval</code> will be assigned the return
 26 cananian 1.1.2.13  * value, if any, and execution will follow the first outgoing
 27 cananian 1.1.2.13  * edge, <code>nextEdge(0)</code>.  If an exception is thrown
 28 cananian 1.1.2.13  * then the <code>Temp</code> specified by <code>retex</code> will
 29 cananian 1.1.2.13  * be assigned the non-null reference to the thrown exception
 30 cananian 1.1.2.13  * and execution will follow the second outgoing edge,
 31 cananian 1.1.2.13  * <code>nextEdge(1)</code>.  Calls with explicit exception
 32 cananian 1.1.2.13  * handling always have exactly two outgoing edges.
 33 cananian 1.1.2.13  * <p>
 34 cananian 1.1.2.13  * In quad-with-try form, the <code>CALL</code> has only one
 35 cananian 1.1.2.13  * outgoing edge, and exceptions are handled by an implicit
 36 cananian 1.1.2.13  * control transfer to an appropriate <code>HANDLER</code> quad.
 37 cananian 1.1.2.13  * The <code>retex</code> field should be <code>null</code> in
 38 cananian 1.1.2.13  * this case (and only in this case).
 39 cananian 1.1.2.13  * <p>
 40 cananian 1.1.2.13  * Note that <b>exactly one</b> of { <code>retval</code>, <code>retex</code> }
 41 cananian 1.1.2.20  * will be defined after the execution of <code>CALL</code>; thus it is 
 42 cananian 1.1.2.20  * <b>perfectly
 43 cananian 1.1.2.13  * valid for <code>retval</code> and <code>retex</code> to be identical</b>.
 44 cananian 1.1.2.15  * Of course, for type-safety the return type cannot be primitive if this
 45 cananian 1.1.2.13  * is so.
 46 cananian 1.1.2.18  * <p>
 47 cananian 1.1.2.18  * The <code>Temp</code> not defined by the <code>CALL</code> 
 48 cananian 1.1.2.18  * (if the <code>retex</code> and <code>retval</code> <code>Temp</code>s
 49 cananian 1.1.2.20  *  are different) is <i>undefined</i> --- that is, it may have
 50 cananian 1.1.2.20  * <i>any value at all</i> after the <code>CALL</code>.  Both
 51 cananian 1.1.2.20  * <code>IR.LowQuad.PCALL</code> and <code>IR.Tree.CALL</code> also
 52 cananian 1.1.2.20  * behave this way.
 53 cananian 1.1.2.1   *
 54 cananian 1.1.2.1   * @author  C. Scott Ananian <cananian@alumni.princeton.edu>
 55 cananian 1.5       * @version $Id: CALL.java,v 1.5 2002/04/11 04:00:31 cananian Exp $ 
 56 cananian 1.1.2.1   */
 57 cananian 1.1.2.13 public class CALL extends SIGMA {
 58 cananian 1.1.2.1      /** The method to invoke. */
 59 cananian 1.1.2.2      final protected HMethod method;
 60 cananian 1.1.2.1      /** Parameters to pass to the method. 
 61 cananian 1.1.2.1       *  The object on which to invoke the method is the first element in 
 62 cananian 1.1.2.1       *  the parameter list of a virtual method. */
 63 cananian 1.1.2.2      protected Temp[] params;
 64 cananian 1.1.2.1      /** Destination for the method's return value; 
 65 cananian 1.1.2.1       *  <code>null</code> for <code>void</code> methods. */
 66 cananian 1.1.2.2      protected Temp retval;
 67 cananian 1.1.2.1      /** Destination for any exception thrown by the method. 
 68 cananian 1.1.2.5       *  If <code>null</code> exceptions are thrown, not caught. */
 69 cananian 1.1.2.2      protected Temp retex;
 70 cananian 1.1.2.2      /** Special flag for non-virtual methods.
 71 cananian 1.1.2.2       *  (INVOKESPECIAL has different invoke semantics) */
 72 cananian 1.1.2.2      final protected boolean isVirtual;
 73 cananian 1.1.2.16     /** Special flag for tail calls. */
 74 cananian 1.1.2.14     final protected boolean isTailCall;
 75 cananian 1.1.2.2  
 76 cananian 1.1.2.13     /** Creates a <code>CALL</code> quad representing a method invocation
 77 cananian 1.1.2.13      *  with explicit exception handling.
 78 cananian 1.1.2.2       * @param method
 79 cananian 1.1.2.2       *        the method to invoke.
 80 cananian 1.1.2.2       * @param params
 81 cananian 1.1.2.2       *        an array of <code>Temp</code>s containing the parameters
 82 cananian 1.1.2.2       *        to pass to the method.  The object on which to invoke the 
 83 cananian 1.1.2.2       *        method is the first element in the parameter list of a
 84 cananian 1.1.2.15      *        non-static method; static methods do not need to specify a
 85 cananian 1.1.2.15      *        receiver.  For static methods, <code>params</code>
 86 cananian 1.1.2.2       *        should match exactly the number and types of parameters in 
 87 cananian 1.1.2.15      *        the method descriptor.  For non-static methods, the receiver
 88 cananian 1.1.2.2       *        object (which is not included in the descriptor) is element
 89 cananian 1.1.2.2       *        zero of the <code>params</code> array.
 90 cananian 1.1.2.2       * @param retval
 91 cananian 1.1.2.2       *        the destination <code>Temp</code> for the method's return
 92 cananian 1.1.2.2       *        value, or <code>null</code> if the method returns no
 93 cananian 1.1.2.2       *        value (return type is <code>void</code>.
 94 cananian 1.1.2.2       * @param retex
 95 cananian 1.1.2.2       *        the destination <code>Temp</code> for any exception thrown
 96 cananian 1.1.2.13      *        by the called method.  If <code>null</code> then this
 97 cananian 1.1.2.13      *        <code>CALL</code> has arity one and handles exceptions
 98 cananian 1.1.2.13      *        implicitly; else it has arity two and exception handling
 99 cananian 1.1.2.13      *        is explicit.
100 cananian 1.1.2.2       * @param isVirtual
101 cananian 1.1.2.2       *        <code>true</code> if invocation semantics are that of a
102 cananian 1.1.2.10      *        virtual method; <code>false</code> for constructors,
103 cananian 1.1.2.10      *        private methods, and static initializers, which have
104 cananian 1.1.2.10      *        non-virtual invocation semantics.
105 cananian 1.1.2.15      *        Value doesn't matter for static methods; the
106 cananian 1.1.2.2       *        <code>isVirtual()</code> method will always return 
107 cananian 1.1.2.2       *        <code>false</code> in this case.
108 cananian 1.1.2.14      * @param isTailCall
109 cananian 1.1.2.14      *        <code>true</code> if this method should return the same
110 cananian 1.1.2.14      *        value the callee returns or throw whatever exception the
111 cananian 1.1.2.14      *        callee throws (in which case we can get rid of our stack
112 cananian 1.1.2.14      *        and let the callee return directly to our caller.
113 cananian 1.1.2.14      *        Usually <code>false</code>.
114 cananian 1.1.2.13      * @param dst
115 cananian 1.1.2.13      *        the elements of the pairs on the left-hand side of
116 cananian 1.1.2.13      *        the sigma function assignment block associated with
117 cananian 1.1.2.13      *        this <code>CALL</code>.
118 cananian 1.1.2.13      * @param src
119 cananian 1.1.2.13      *        the arguments to the sigma functions associated with
120 cananian 1.1.2.13      *        this <code>CALL</code>.
121 cananian 1.1.2.2       */
122 cananian 1.1.2.4      public CALL(QuadFactory qf, HCodeElement source,
123 cananian 1.1.2.4                  HMethod method, Temp[] params, Temp retval, Temp retex,
124 cananian 1.1.2.14                 boolean isVirtual, boolean isTailCall,
125 cananian 1.1.2.14                 Temp[][] dst, Temp[] src) {
126 cananian 1.1.2.13         super(qf, source, dst, src, retex==null?1:2);
127 cananian 1.3.2.1          assert method!=null; // assert early, before call to isStatic()
128 cananian 1.1.2.1          this.method = method;
129 cananian 1.1.2.1          this.params = params;
130 cananian 1.1.2.1          this.retval = retval;
131 cananian 1.1.2.1          this.retex  = retex;
132 cananian 1.1.2.2          // static methods are not virtual.
133 cananian 1.1.2.2          this.isVirtual = isStatic()?false:isVirtual;
134 cananian 1.1.2.14         this.isTailCall = isTailCall;
135 cananian 1.1.2.2  
136 cananian 1.1.2.2          // VERIFY legality of this CALL.
137 cananian 1.3.2.1          assert method!=null && params!=null;
138 cananian 1.1.2.2          /* if !isVirtual, then the method is either static, a constructor,
139 cananian 1.1.2.2           * private, or a the declaring class of the method is a superclass
140 cananian 1.1.2.2           * of the current method.   This is hard to check, so we do it
141 cananian 1.1.2.2           * the other way round. */
142 cananian 1.1.2.2          if (this.isVirtual) 
143 cananian 1.3.2.1              assert !method.isStatic() && 
144 cananian 1.1.2.2                          !(method instanceof HConstructor) &&
145 cananian 1.3.2.1                          !Modifier.isPrivate(method.getModifiers()) : "meaning of final parameter to CALL constructor "+
146 cananian 1.1.2.2                          "has been inverted.  isVirtual should be true "+
147 cananian 1.1.2.2                          "unless the called method is a constructor, static, "+
148 cananian 1.1.2.2                          "private, or declared in a superclass of the "+
149 cananian 1.3.2.1                          "current method.";
150 cananian 1.1.2.2          // check params and retval against method.
151 cananian 1.3.2.1          assert (method.getReturnType()==HClass.Void
152 cananian 1.3.2.1                      ? retval==null : retval!=null) : "retval not consistent with return type.";
153 cananian 1.3.2.1          assert (method.getParameterTypes().length + (isStatic()?0:1)) ==
154 cananian 1.3.2.1                      params.length;
155 cananian 1.3.2.1          assert !isStatic() || isVirtual()==false : "method can't be both static and virtual";
156 cananian 1.1.2.13         // check that retval and retex are different if return val is primitive
157 cananian 1.3.2.1          assert !(retval==retex && retex!=null &&
158 cananian 1.3.2.1                        method.getReturnType().isPrimitive()) : "can't merge a primitive and a Throwable w/o violating "+
159 cananian 1.3.2.1                      "type safety.";
160 cananian 1.1.2.1          // I guess it's legal, then.
161 cananian 1.1.2.1      }
162 cananian 1.1.2.13     // convenience constructor.
163 cananian 1.1.2.13     /** Creates a <code>CALL</code> with an empty <code>dst</code> array
164 cananian 1.1.2.13      *  of the proper size.  Other arguments as above. */
165 cananian 1.1.2.13     public CALL(QuadFactory qf, HCodeElement source,
166 cananian 1.1.2.13                 HMethod method, Temp[] params, Temp retval, Temp retex,
167 cananian 1.1.2.14                 boolean isVirtual, boolean isTailCall, Temp[] src) {
168 cananian 1.1.2.14         this(qf, source, method, params, retval, retex, isVirtual, isTailCall,
169 cananian 1.1.2.13              new Temp[src.length][retex==null?1:2], src);
170 cananian 1.1.2.13     }
171 cananian 1.1.2.13     
172 cananian 1.1.2.2      // ACCESSOR METHODS:
173 cananian 1.1.2.2      /** Returns the method invoked by this <code>CALL</code>. */
174 cananian 1.1.2.2      public HMethod method() { return method; }
175 cananian 1.1.2.2      /** Returns the parameters of this method invocation. */
176 cananian 1.1.2.2      public Temp[] params()
177 cananian 1.1.2.2      { return (Temp[]) Util.safeCopy(Temp.arrayFactory, params); }
178 cananian 1.1.2.2      /** Returns a specified parameter in the <code>params</code> array. */
179 cananian 1.1.2.2      public Temp params(int i) { return params[i]; }
180 cananian 1.1.2.2      /** Returns the number of parameters in the <code>params</code> array. */
181 cananian 1.1.2.2      public int paramsLength() { return params.length; }
182 cananian 1.1.2.8      /** Returns the type of the specified parameter. */
183 cananian 1.1.2.8      public HClass paramType(int i) {
184 cananian 1.1.2.8          if (isStatic()) return method.getParameterTypes()[i];
185 cananian 1.1.2.8          else if (i==0) return method.getDeclaringClass();
186 cananian 1.1.2.8          else return method.getParameterTypes()[i-1];
187 cananian 1.1.2.8      }
188 cananian 1.1.2.2      /** Returns the <code>Temp</code> which will hold the return value of
189 cananian 1.1.2.2       *  the method, or the value <code>null</code> if the method returns
190 cananian 1.1.2.2       *  no value. */
191 cananian 1.1.2.2      public Temp retval() { return retval; }
192 cananian 1.1.2.2      /** Returns the <code>Temp</code> which will get any exception thrown
193 cananian 1.1.2.5       *  by the called method, or <code>null</code> if exceptions are
194 cananian 1.1.2.5       *  not caught. */
195 cananian 1.1.2.2      public Temp retex() { return retex; }
196 cananian 1.1.2.2      /** Returns <code>true</code> if the method is dispatched virtually,
197 cananian 1.1.2.2       *  or <code>false</code> otherwise.  Static methods return 
198 cananian 1.1.2.2       *  <code>false</code>, constructors and static initializers return
199 cananian 1.1.2.2       *  <code>false</code>, and all other method types return 
200 cananian 1.1.2.2       *  <code>true</code>. */
201 cananian 1.1.2.2      public boolean isVirtual() { return isVirtual; }
202 cananian 1.1.2.14     /** Returns <code>true</code> if this method should return the
203 cananian 1.1.2.14      *  same value the callee returns or throw whatever
204 cananian 1.1.2.14      *  exception the callee throws (in which case we can get
205 cananian 1.1.2.14      *  rid of our stack and let the callee return directly to
206 cananian 1.1.2.14      *  our caller.  Usually <code>false</code>. */
207 cananian 1.1.2.14     public boolean isTailCall() { return isTailCall; }
208 cananian 1.1.2.1  
209 cananian 1.1.2.1      /** Returns all the Temps used by this Quad. 
210 cananian 1.1.2.1       * @return the <code>params</code> array.
211 cananian 1.1.2.1       */
212 cananian 1.1.2.1      public Temp[] use() {
213 cananian 1.1.2.13         Temp[] u = super.use();
214 cananian 1.1.2.13         Temp[] r = new Temp[u.length+params.length];
215 cananian 1.1.2.13         System.arraycopy(u,      0, r, 0,        u.length);
216 cananian 1.1.2.13         System.arraycopy(params, 0, r, u.length, params.length);
217 cananian 1.1.2.13         return r;
218 cananian 1.1.2.1      }
219 cananian 1.1.2.1      /** Returns all the Temps defined by this Quad. 
220 cananian 1.1.2.5       * @return The non-null members of <code>{ retval, retex }</code>.
221 cananian 1.1.2.1       */
222 cananian 1.1.2.1      public Temp[] def() {
223 cananian 1.1.2.13         Temp[] d = super.def();
224 cananian 1.1.2.13         int len = d.length;
225 cananian 1.1.2.13         if (retval!=null) len++;
226 cananian 1.1.2.13         if (retex !=null) len++;
227 cananian 1.1.2.13         Temp[] r = new Temp[len];
228 cananian 1.1.2.13         System.arraycopy(d, 0, r, 0, d.length);
229 cananian 1.1.2.13         if (retval!=null) r[--len]=retval;
230 cananian 1.1.2.13         if (retex !=null) r[--len]=retex;
231 cananian 1.1.2.13         return r;
232 cananian 1.1.2.1      }
233 cananian 1.1.2.1  
234 cananian 1.1.2.3      public int kind() { return QuadKind.CALL; }
235 cananian 1.1.2.3  
236 cananian 1.1.2.6      public Quad rename(QuadFactory qqf, TempMap defMap, TempMap useMap) {
237 cananian 1.1.2.6          return new CALL(qqf, this, method, map(useMap, params),
238 cananian 1.1.2.14                         map(defMap,retval),map(defMap, retex),
239 cananian 1.1.2.14                         isVirtual, isTailCall,
240 cananian 1.1.2.13                         map(defMap, dst), map(useMap, src));
241 cananian 1.1.2.3      }
242 cananian 1.1.2.6      /** Rename all used variables in this Quad according to a mapping.
243 cananian 1.1.2.6       * @deprecated does not preserve immutability. */
244 cananian 1.1.2.3      void renameUses(TempMap tm) {
245 cananian 1.1.2.13         super.renameUses(tm);
246 cananian 1.1.2.1          for (int i=0; i<params.length; i++)
247 cananian 1.1.2.1              params[i] = tm.tempMap(params[i]);
248 cananian 1.1.2.1      }
249 cananian 1.1.2.6      /** Rename all defined variables in this Quad according to a mapping.
250 cananian 1.1.2.6       * @deprecated does not preserve immutability. */
251 cananian 1.1.2.3      void renameDefs(TempMap tm) {
252 cananian 1.1.2.13         super.renameDefs(tm);
253 cananian 1.1.2.1          if (retval!=null)
254 cananian 1.1.2.1              retval = tm.tempMap(retval);
255 cananian 1.1.2.5          if (retex!=null)
256 cananian 1.1.2.5              retex  = tm.tempMap(retex);
257 cananian 1.1.2.1      }
258 cananian 1.1.2.1  
259 cananian 1.1.2.12     public void accept(QuadVisitor v) { v.visit(this); }
260 cananian 1.5          public <T> T accept(QuadValueVisitor<T> v) { return v.visit(this); }
261 cananian 1.1.2.1  
262 cananian 1.1.2.1      /** Returns human-readable representation. */
263 cananian 1.1.2.1      public String toString() {
264 cananian 1.1.2.1          StringBuffer sb = new StringBuffer();
265 cananian 1.1.2.1          if (retval!=null)
266 cananian 1.1.2.1              sb.append(retval.toString() + " = ");
267 cananian 1.1.2.1          sb.append("CALL ");
268 cananian 1.1.2.2          if (!isVirtual)
269 cananian 1.1.2.2              sb.append("(non-virtual) ");
270 cananian 1.1.2.14         if (isTailCall)
271 cananian 1.1.2.14             sb.append("[tail call] ");
272 cananian 1.1.2.1          if (isStatic())
273 cananian 1.1.2.1              sb.append("static ");
274 cananian 1.1.2.1          sb.append(method.getDeclaringClass().getName()+"."+method.getName());
275 cananian 1.1.2.1          sb.append('(');
276 cananian 1.1.2.1          for (int i=0; i<params.length; i++) {
277 cananian 1.1.2.1              sb.append(params[i].toString());
278 cananian 1.1.2.1              if (i<params.length-1)
279 cananian 1.1.2.1                  sb.append(", ");
280 cananian 1.1.2.1          }
281 cananian 1.1.2.1          sb.append(')');
282 cananian 1.1.2.5          if (retex!=null)
283 cananian 1.1.2.5              sb.append(" exceptions in "+retex);
284 cananian 1.1.2.5          else
285 cananian 1.1.2.13             sb.append(" exceptions THROWN DIRECTLY");
286 cananian 1.1.2.13         sb.append(" / "); sb.append(super.toString());
287 cananian 1.1.2.1          return sb.toString();
288 cananian 1.1.2.1      }
289 cananian 1.1.2.1      // Other information that might be useful.  Or might not.  Who knows?
290 cananian 1.1.2.1      /** Determines whether this <code>CALL</code> is to an interface method. */
291 cananian 1.1.2.1      public boolean isInterfaceMethod() { return method.isInterfaceMethod(); }
292 cananian 1.1.2.1      /** Determines whether this <code>CALL</code> is to a static method. */
293 cananian 1.1.2.2      public boolean isStatic() { return method.isStatic(); }
294 cananian 1.2      }