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