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 }