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    }