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.ir.operand; 014 015import org.jikesrvm.classloader.RVMField; 016import org.jikesrvm.classloader.MemberReference; 017import org.jikesrvm.classloader.RVMMethod; 018import org.jikesrvm.classloader.MethodReference; 019import org.jikesrvm.classloader.RVMType; 020import org.jikesrvm.compilers.opt.specialization.SpecializedMethod; 021import org.vmmagic.unboxed.Offset; 022 023/** 024 * Refers to a method. Used for method call instructions. 025 * Contains a RVMMethod (which may or may not have been resolved yet.) 026 * <p> 027 * TODO: Create subclasses of MethodOperand for internal & specialized 028 * targets. 029 * 030 * @see Operand 031 * @see RVMMethod 032 */ 033public final class MethodOperand extends Operand { 034 035 /* Enumeration of types of invokes */ 036 private static final byte STATIC = 0; 037 private static final byte SPECIAL = 1; 038 private static final byte VIRTUAL = 2; 039 private static final byte INTERFACE = 3; 040 041 /** 042 * Member reference for target.<p> 043 * 044 * Usually a MethodReference, but may be a FieldReference for 045 * internal methods that don't have 'real' Java method but come from 046 * OutOfLineMachineCode. 047 */ 048 final MemberReference memRef; 049 050 /** 051 * Target RVMMethod of invocation. 052 */ 053 RVMMethod target; 054 055 /** 056 * Is target exactly the method being invoked by this call, or is it 057 * a representative for a family of virtual/interface methods? 058 */ 059 boolean isPreciseTarget; 060 061 /** 062 * Is this the operand of a call that never returns? 063 */ 064 boolean isNonReturningCall; 065 066 /** 067 * Is this the operand of a call that is the off-branch of a guarded inline? 068 */ 069 boolean isGuardedInlineOffBranch; 070 071 /** 072 * The type of the invoke (STATIC, SPECIAL, VIRTUAL, INTERFACE) 073 */ 074 byte type = -1; 075 076 private boolean designatedOffset = false; 077 public Offset jtocOffset; 078 079 /** 080 * @param ref MemberReference of method to call 081 * @param tar the RVMMethod to call (may be null) 082 * @param t the type of invoke used to call it (STATIC, SPECIAL, VIRTUAL, INTERFACE) 083 */ 084 private MethodOperand(MemberReference ref, RVMMethod tar, byte t) { 085 memRef = ref; 086 target = tar; 087 type = t; 088 setPreciseTarget(); 089 } 090 091 private void setPreciseTarget() { 092 if (isVirtual()) { 093 isPreciseTarget = target != null && (target.isFinal() || target.getDeclaringClass().isFinal()); 094 } else { 095 isPreciseTarget = !isInterface(); 096 } 097 } 098 099 /** 100 * Returns a method operand representing a compiled method with designated 101 * JTOC offset. (used by ConvertToLowLevelIR) 102 * @param callee the callee method 103 * @param offset designated jtop offset of compiled method of callee 104 * @return the method operand 105 */ 106 public static MethodOperand COMPILED(RVMMethod callee, Offset offset) { 107 byte type = callee.isStatic() ? STATIC : VIRTUAL; 108 MethodOperand op = new MethodOperand(callee.getMemberRef(), callee, type); 109 op.jtocOffset = offset; 110 op.designatedOffset = true; 111 op.isPreciseTarget = true; 112 return op; 113 } 114 115 public boolean hasDesignatedTarget() { 116 return this.designatedOffset; 117 } 118 119 /** 120 * create a method operand for an INVOKE_SPECIAL bytecode 121 * 122 * @param ref MemberReference of method to call 123 * @param target the RVMMethod to call (may be null) 124 * @return the newly created method operand 125 */ 126 public static MethodOperand SPECIAL(MethodReference ref, RVMMethod target) { 127 return new MethodOperand(ref, target, SPECIAL); 128 } 129 130 /** 131 * create a method operand for an INVOKE_STATIC bytecode 132 * 133 * @param ref MemberReference of method to call 134 * @param target the RVMMethod to call (may be null) 135 * @return the newly created method operand 136 */ 137 public static MethodOperand STATIC(MethodReference ref, RVMMethod target) { 138 return new MethodOperand(ref, target, STATIC); 139 } 140 141 /** 142 * create a method operand for an INVOKE_STATIC bytecode 143 * where the target method is known at compile time. 144 * 145 * @param target the RVMMethod to call 146 * @return the newly created method operand 147 */ 148 public static MethodOperand STATIC(RVMMethod target) { 149 MethodOperand ans = new MethodOperand(target.getMemberRef(), target, STATIC); 150 return ans; 151 } 152 153 /** 154 * create a method operand for an INVOKE_STATIC bytecode 155 * where the target method is known at compile time. 156 * 157 * @param target the RVMMethod to call 158 * @return the newly created method operand 159 */ 160 public static MethodOperand STATIC(RVMField target) { 161 return new MethodOperand(target.getMemberRef(), null, STATIC); 162 } 163 164 /** 165 * create a method operand for an INVOKE_VIRTUAL bytecode 166 * 167 * @param ref MemberReference of method to call 168 * @param target the RVMMethod to call (may be null) 169 * @return the newly created method operand 170 */ 171 public static MethodOperand VIRTUAL(MethodReference ref, RVMMethod target) { 172 return new MethodOperand(ref, target, VIRTUAL); 173 } 174 175 /** 176 * create a method operand for an INVOKE_INTERFACE bytecode 177 * 178 * @param ref MemberReference of method to call 179 * @param target the RVMMethod to call (may be null) 180 * @return the newly created method operand 181 */ 182 public static MethodOperand INTERFACE(MethodReference ref, RVMMethod target) { 183 return new MethodOperand(ref, target, INTERFACE); 184 } 185 186 public boolean isStatic() { 187 return type == STATIC; 188 } 189 190 public boolean isVirtual() { 191 return type == VIRTUAL; 192 } 193 194 public boolean isSpecial() { 195 return type == SPECIAL; 196 } 197 198 public boolean isInterface() { 199 return type == INTERFACE; 200 } 201 202 public boolean hasTarget() { 203 return target != null; 204 } 205 206 public boolean hasPreciseTarget() { 207 return target != null && isPreciseTarget; 208 } 209 210 public RVMMethod getTarget() { 211 return target; 212 } 213 214 public MemberReference getMemberRef() { 215 return memRef; 216 } 217 218 /** 219 * Get whether this operand represents a method call that never 220 * returns (such as a call to athrow()); 221 * 222 * @return Does this op represent a call that never returns? 223 */ 224 public boolean isNonReturningCall() { 225 return isNonReturningCall; 226 } 227 228 /** 229 * Records whether this operand represents a method call that never 230 * returns (such as a call to athrow()). 231 * 232 * @param neverReturns whether this function will return 233 */ 234 public void setIsNonReturningCall(boolean neverReturns) { 235 isNonReturningCall = neverReturns; 236 } 237 238 /** 239 * @return whether this operand is the off branch of a guarded inline 240 */ 241 public boolean isGuardedInlineOffBranch() { 242 return isGuardedInlineOffBranch; 243 } 244 245 /** 246 * Record that this operand is the off branch of a guarded inline 247 * 248 * @param f if the operand is in the off branch of a guarded inline 249 */ 250 public void setIsGuardedInlineOffBranch(boolean f) { 251 isGuardedInlineOffBranch = f; 252 } 253 254 /** 255 * Refines the target information. Used to reduce the set of 256 * targets for an invokevirtual. 257 * 258 * @param target method to use for refining of information 259 */ 260 public void refine(RVMMethod target) { 261 this.target = target; 262 setPreciseTarget(); 263 } 264 265 /** 266 * Refines the target information. Used to reduce the set of 267 * targets for an invokevirtual. 268 * 269 * @param targetClass class to use for refining of information 270 */ 271 public void refine(RVMType targetClass) { 272 this.target = targetClass.findVirtualMethod(memRef.getName(), memRef.getDescriptor()); 273 setPreciseTarget(); 274 } 275 276 /** 277 * Refine the target information. Used to reduce the set of 278 * targets for an invokevirtual. 279 * 280 * @param target the target method 281 * @param isPreciseTarget whether the target is precise 282 */ 283 public void refine(RVMMethod target, boolean isPreciseTarget) { 284 this.target = target; 285 if (isPreciseTarget) { 286 this.isPreciseTarget = isPreciseTarget; 287 } else { 288 setPreciseTarget(); 289 } 290 } 291 292 @Override 293 public Operand copy() { 294 MethodOperand mo = new MethodOperand(memRef, target, type); 295 mo.isPreciseTarget = isPreciseTarget; 296 mo.isNonReturningCall = isNonReturningCall; 297 mo.isGuardedInlineOffBranch = isGuardedInlineOffBranch; 298 return mo; 299 } 300 301 @Override 302 public boolean similar(Operand op) { 303 if (op instanceof MethodOperand) { 304 MethodOperand mop = (MethodOperand) op; 305 return memRef == mop.memRef && target == mop.target && isPreciseTarget == mop.isPreciseTarget; 306 } else { 307 return false; 308 } 309 } 310 311 /** 312 * Returns the string representation of this operand. 313 * 314 * @return a string representation of this operand. 315 */ 316 @Override 317 public String toString() { 318 String s = ""; 319 switch (type) { 320 case STATIC: 321 s += "static"; 322 break; 323 case SPECIAL: 324 s += "special"; 325 break; 326 case VIRTUAL: 327 s += "virtual"; 328 break; 329 case INTERFACE: 330 s += "interface"; 331 break; 332 } 333 if (isPreciseTarget && (type != STATIC)) { 334 s += "_exact"; 335 } 336 if (hasSpecialVersion()) { 337 return s + "\"" + spMethod + "\""; 338 } 339 if (target != null) { 340 return s + "\"" + target + "\""; 341 } else { 342 return s + "<" + memRef + ">"; 343 } 344 } 345 346 /* 347 * SPECIALIZATION SUPPORT 348 */ 349 public SpecializedMethod spMethod; 350 351 public boolean hasSpecialVersion() { 352 return spMethod != null; 353 } 354}