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     * <p>
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.<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       * Record whether this operand represents a method call that never
230       * returns (such as a call to athrow());
231       */
232      public void setIsNonReturningCall(boolean neverReturns) {
233        isNonReturningCall = neverReturns;
234      }
235    
236      /**
237       * Return whether this operand is the off branch of a guarded inline
238       */
239      public boolean isGuardedInlineOffBranch() {
240        return isGuardedInlineOffBranch;
241      }
242    
243      /**
244       * Record that this operand is the off branch of a guarded inline
245       */
246      public void setIsGuardedInlineOffBranch(boolean f) {
247        isGuardedInlineOffBranch = f;
248      }
249    
250      /**
251       * Refine the target information. Used to reduce the set of
252       * targets for an invokevirtual.
253       */
254      public void refine(RVMMethod target) {
255        this.target = target;
256        setPreciseTarget();
257      }
258    
259      /**
260       * Refine the target information. Used to reduce the set of
261       * targets for an invokevirtual.
262       */
263      public void refine(RVMType targetClass) {
264        this.target = targetClass.findVirtualMethod(memRef.getName(), memRef.getDescriptor());
265        setPreciseTarget();
266      }
267    
268      /**
269       * Refine the target information. Used to reduce the set of
270       * targets for an invokevirtual.
271       */
272      public void refine(RVMMethod target, boolean isPreciseTarget) {
273        this.target = target;
274        if (isPreciseTarget) {
275          this.isPreciseTarget = isPreciseTarget;
276        } else {
277          setPreciseTarget();
278        }
279      }
280    
281      @Override
282      public Operand copy() {
283        MethodOperand mo = new MethodOperand(memRef, target, type);
284        mo.isPreciseTarget = isPreciseTarget;
285        mo.isNonReturningCall = isNonReturningCall;
286        mo.isGuardedInlineOffBranch = isGuardedInlineOffBranch;
287        return mo;
288      }
289    
290      @Override
291      public boolean similar(Operand op) {
292        if (op instanceof MethodOperand) {
293          MethodOperand mop = (MethodOperand) op;
294          return memRef == mop.memRef && target == mop.target && isPreciseTarget == mop.isPreciseTarget;
295        } else {
296          return false;
297        }
298      }
299    
300      /**
301       * Returns the string representation of this operand.
302       *
303       * @return a string representation of this operand.
304       */
305      @Override
306      public String toString() {
307        String s = "";
308        switch (type) {
309          case STATIC:
310            s += "static";
311            break;
312          case SPECIAL:
313            s += "special";
314            break;
315          case VIRTUAL:
316            s += "virtual";
317            break;
318          case INTERFACE:
319            s += "interface";
320            break;
321        }
322        if (isPreciseTarget && (type != STATIC)) {
323          s += "_exact";
324        }
325        if (hasSpecialVersion()) {
326          return s + "\"" + spMethod + "\"";
327        }
328        if (target != null) {
329          return s + "\"" + target + "\"";
330        } else {
331          return s + "<" + memRef + ">";
332        }
333      }
334    
335      /*
336       * SPECIALIZATION SUPPORT
337       */
338      public SpecializedMethod spMethod;
339    
340      public boolean hasSpecialVersion() { return spMethod != null; }
341    }