/* * This file is part of the Jikes RVM project (http://jikesrvm.org). * * This file is licensed to You under the Eclipse Public License (EPL); * You may not use this file except in compliance with the License. You * may obtain a copy of the License at * * http://www.opensource.org/licenses/eclipse-1.0.php * * See the COPYRIGHT.txt file distributed with this work for information * regarding copyright ownership. */ package org.jikesrvm.compilers.opt.ir.operand; import org.jikesrvm.classloader.RVMField; import org.jikesrvm.VM; import org.jikesrvm.classloader.MemberReference; import org.jikesrvm.classloader.RVMMethod; import org.jikesrvm.classloader.MethodReference; import org.jikesrvm.classloader.RVMType; import org.jikesrvm.classloader.TypeReference; import org.jikesrvm.compilers.opt.specialization.SpecializedMethod; import org.vmmagic.unboxed.Offset; /** * Refers to a method. Used for method call instructions. * Contains a RVMMethod (which may or may not have been resolved yet.) * <p> * TODO: Create subclasses of MethodOperand for internal & specialized * targets. * * @see Operand * @see RVMMethod */ public final class MethodOperand extends Operand { /* Enumeration of types of invokes */ private static final byte STATIC = 0; private static final byte SPECIAL = 1; private static final byte VIRTUAL = 2; private static final byte INTERFACE = 3; /** * Member reference for target.<p> * * Usually a MethodReference, but may be a FieldReference for * internal methods that don't have 'real' Java method but come from * OutOfLineMachineCode. */ final MemberReference memRef; /** * Target RVMMethod of invocation. */ RVMMethod target; /** * Is target exactly the method being invoked by this call, or is it * a representative for a family of virtual/interface methods? */ boolean isPreciseTarget; /** * Is this the operand of a call that never returns? */ boolean isNonReturningCall; /** * Is this the operand of a call that is the off-branch of a guarded inline? */ boolean isGuardedInlineOffBranch; /** * The type of the invoke (STATIC, SPECIAL, VIRTUAL, INTERFACE) */ byte type = -1; private boolean designatedOffset = false; public Offset jtocOffset; /** * @param ref MemberReference of method to call * @param tar the RVMMethod to call (may be null) * @param t the type of invoke used to call it (STATIC, SPECIAL, VIRTUAL, INTERFACE) */ private MethodOperand(MemberReference ref, RVMMethod tar, byte t) { memRef = ref; target = tar; type = t; setPreciseTarget(); } private void setPreciseTarget() { if (isVirtual()) { isPreciseTarget = target != null && (target.isFinal() || target.getDeclaringClass().isFinal()); } else { isPreciseTarget = !isInterface(); } } /** * Returns a method operand representing a compiled method with designated * JTOC offset. (used by ConvertToLowLevelIR) * @param callee the callee method * @param offset designated jtop offset of compiled method of callee * @return the method operand */ public static MethodOperand COMPILED(RVMMethod callee, Offset offset) { byte type = callee.isStatic() ? STATIC : VIRTUAL; MethodOperand op = new MethodOperand(callee.getMemberRef(), callee, type); op.jtocOffset = offset; op.designatedOffset = true; op.isPreciseTarget = true; return op; } public boolean hasDesignatedTarget() { return this.designatedOffset; } /** * create a method operand for an INVOKE_SPECIAL bytecode * * @param ref MemberReference of method to call * @param target the RVMMethod to call (may be null) * @return the newly created method operand */ public static MethodOperand SPECIAL(MethodReference ref, RVMMethod target) { return new MethodOperand(ref, target, SPECIAL); } /** * create a method operand for an INVOKE_STATIC bytecode * * @param ref MemberReference of method to call * @param target the RVMMethod to call (may be null) * @return the newly created method operand */ public static MethodOperand STATIC(MethodReference ref, RVMMethod target) { return new MethodOperand(ref, target, STATIC); } /** * create a method operand for an INVOKE_STATIC bytecode * where the target method is known at compile time. * * @param target the RVMMethod to call * @return the newly created method operand */ public static MethodOperand STATIC(RVMMethod target) { MethodOperand ans = new MethodOperand(target.getMemberRef(), target, STATIC); return ans; } /** * Creates a method operand for an INVOKESTATIC bytecode * where the target method is known at compile time AND * where the target method doesn't have Java source code. * * @param target field that has the address of the method * to call * @return the newly created method operand */ public static MethodOperand STATIC(RVMField target) { TypeReference type = target.getType(); if (VM.VerifyAssertions) VM._assert(type.isCodeArrayType() || type == TypeReference.Address); return new MethodOperand(target.getMemberRef(), null, STATIC); } /** * create a method operand for an INVOKE_VIRTUAL bytecode * * @param ref MemberReference of method to call * @param target the RVMMethod to call (may be null) * @return the newly created method operand */ public static MethodOperand VIRTUAL(MethodReference ref, RVMMethod target) { return new MethodOperand(ref, target, VIRTUAL); } /** * create a method operand for an INVOKE_INTERFACE bytecode * * @param ref MemberReference of method to call * @param target the RVMMethod to call (may be null) * @return the newly created method operand */ public static MethodOperand INTERFACE(MethodReference ref, RVMMethod target) { return new MethodOperand(ref, target, INTERFACE); } public boolean isStatic() { return type == STATIC; } public boolean isVirtual() { return type == VIRTUAL; } public boolean isSpecial() { return type == SPECIAL; } public boolean isInterface() { return type == INTERFACE; } public boolean hasTarget() { return target != null; } public boolean hasPreciseTarget() { return target != null && isPreciseTarget; } public RVMMethod getTarget() { return target; } public MemberReference getMemberRef() { return memRef; } /** * Get whether this operand represents a method call that never * returns (such as a call to athrow()); * * @return Does this op represent a call that never returns? */ public boolean isNonReturningCall() { return isNonReturningCall; } /** * Records whether this operand represents a method call that never * returns (such as a call to athrow()). * * @param neverReturns whether this function will return */ public void setIsNonReturningCall(boolean neverReturns) { isNonReturningCall = neverReturns; } /** * @return whether this operand is the off branch of a guarded inline */ public boolean isGuardedInlineOffBranch() { return isGuardedInlineOffBranch; } /** * Record that this operand is the off branch of a guarded inline * * @param f if the operand is in the off branch of a guarded inline */ public void setIsGuardedInlineOffBranch(boolean f) { isGuardedInlineOffBranch = f; } /** * Refines the target information. Used to reduce the set of * targets for an invokevirtual. * * @param target method to use for refining of information */ public void refine(RVMMethod target) { this.target = target; setPreciseTarget(); } /** * Refines the target information. Used to reduce the set of * targets for an invokevirtual. * * @param targetClass class to use for refining of information */ public void refine(RVMType targetClass) { this.target = targetClass.findVirtualMethod(memRef.getName(), memRef.getDescriptor()); setPreciseTarget(); } /** * Refine the target information. Used to reduce the set of * targets for an invokevirtual. * * @param target the target method * @param isPreciseTarget whether the target is precise */ public void refine(RVMMethod target, boolean isPreciseTarget) { this.target = target; if (isPreciseTarget) { this.isPreciseTarget = isPreciseTarget; } else { setPreciseTarget(); } } @Override public Operand copy() { MethodOperand mo = new MethodOperand(memRef, target, type); mo.isPreciseTarget = isPreciseTarget; mo.isNonReturningCall = isNonReturningCall; mo.isGuardedInlineOffBranch = isGuardedInlineOffBranch; return mo; } @Override public boolean similar(Operand op) { if (op instanceof MethodOperand) { MethodOperand mop = (MethodOperand) op; return memRef == mop.memRef && target == mop.target && isPreciseTarget == mop.isPreciseTarget; } else { return false; } } /** * Returns the string representation of this operand. * * @return a string representation of this operand. */ @Override public String toString() { String s = ""; switch (type) { case STATIC: s += "static"; break; case SPECIAL: s += "special"; break; case VIRTUAL: s += "virtual"; break; case INTERFACE: s += "interface"; break; } if (isPreciseTarget && (type != STATIC)) { s += "_exact"; } if (hasSpecialVersion()) { return s + "\"" + spMethod + "\""; } if (target != null) { return s + "\"" + target + "\""; } else { return s + "<" + memRef + ">"; } } /* * SPECIALIZATION SUPPORT */ public SpecializedMethod spMethod; public boolean hasSpecialVersion() { return spMethod != null; } }