/******************************************************************************* * Copyright (c) 2002 - 2006 IBM Corporation. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package com.ibm.wala.classLoader; import com.ibm.wala.ipa.callgraph.CGNode; import com.ibm.wala.ipa.callgraph.ContextItem; import com.ibm.wala.shrikeBT.BytecodeConstants; import com.ibm.wala.shrikeBT.IInvokeInstruction; import com.ibm.wala.ssa.IR; import com.ibm.wala.types.MethodReference; import com.ibm.wala.util.debug.Assertions; /** * Simple object that represents a static call site (ie., an invoke instruction in the bytecode) * * Note that the identity of a call site reference depends on two things: the program counter, and the containing IR. Thus, it * suffices to define equals() and hashCode() from {@link ProgramCounter}, since this class does not maintain a pointer to the * containing {@link IR} (or {@link CGNode}) anyway. If using a hashtable of CallSiteReference from different IRs, you probably want * to use a wrapper which also holds a pointer to the governing CGNode. */ public abstract class CallSiteReference extends ProgramCounter implements BytecodeConstants, ContextItem { final private MethodReference declaredTarget; /** * @param programCounter Index into bytecode describing this instruction * @param declaredTarget The method target as declared at the call site */ protected CallSiteReference(int programCounter, MethodReference declaredTarget) { super(programCounter); this.declaredTarget = declaredTarget; } @Override public int hashCode() { final int prime = 31; int result = super.hashCode(); result = prime * result + ((declaredTarget == null) ? 0 : declaredTarget.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (!super.equals(obj)) return false; if (getClass() != obj.getClass()) return false; CallSiteReference other = (CallSiteReference) obj; if (declaredTarget == null) { if (other.declaredTarget != null) return false; } else if (!declaredTarget.equals(other.declaredTarget)) return false; return true; } // the following atrocities are needed to save a word of space by // declaring these classes static, so they don't keep a pointer // to the enclosing environment // Java makes you type! static class StaticCall extends CallSiteReference { StaticCall(int programCounter, MethodReference declaredTarget) { super(programCounter, declaredTarget); } @Override public IInvokeInstruction.IDispatch getInvocationCode() { return IInvokeInstruction.Dispatch.STATIC; } } static class SpecialCall extends CallSiteReference { SpecialCall(int programCounter, MethodReference declaredTarget) { super(programCounter, declaredTarget); } @Override public IInvokeInstruction.IDispatch getInvocationCode() { return IInvokeInstruction.Dispatch.SPECIAL; } } static class VirtualCall extends CallSiteReference { VirtualCall(int programCounter, MethodReference declaredTarget) { super(programCounter, declaredTarget); } @Override public IInvokeInstruction.IDispatch getInvocationCode() { return IInvokeInstruction.Dispatch.VIRTUAL; } } static class InterfaceCall extends CallSiteReference { InterfaceCall(int programCounter, MethodReference declaredTarget) { super(programCounter, declaredTarget); } @Override public IInvokeInstruction.IDispatch getInvocationCode() { return IInvokeInstruction.Dispatch.INTERFACE; } } /** * This factory method plays a little game to avoid storing the invocation code in the object; this saves a byte (probably * actually a whole word) in each created object. * * TODO: Consider canonicalization? */ public static CallSiteReference make(int programCounter, MethodReference declaredTarget, IInvokeInstruction.IDispatch invocationCode) { if (invocationCode == IInvokeInstruction.Dispatch.SPECIAL) return new SpecialCall(programCounter, declaredTarget); if (invocationCode == IInvokeInstruction.Dispatch.VIRTUAL) return new VirtualCall(programCounter, declaredTarget); if (invocationCode == IInvokeInstruction.Dispatch.INTERFACE) return new InterfaceCall(programCounter, declaredTarget); if (invocationCode == IInvokeInstruction.Dispatch.STATIC) return new StaticCall(programCounter, declaredTarget); throw new IllegalArgumentException("unsupported code: " + invocationCode); } /** * Return the Method that this call site calls. This represents the method declared in the invoke instruction only. */ public MethodReference getDeclaredTarget() { return declaredTarget; } /** * Return one of INVOKESPECIAL, INVOKESTATIC, INVOKEVIRTUAL, or INVOKEINTERFACE */ abstract public IInvokeInstruction.IDispatch getInvocationCode(); @Override public String toString() { return "invoke" + getInvocationString(getInvocationCode()) + " " + declaredTarget + "@" + getProgramCounter(); } protected String getInvocationString(IInvokeInstruction.IDispatch invocationCode) { if (invocationCode == IInvokeInstruction.Dispatch.STATIC) return "static"; if (invocationCode == IInvokeInstruction.Dispatch.SPECIAL) return "special"; if (invocationCode == IInvokeInstruction.Dispatch.VIRTUAL) return "virtual"; if (invocationCode == IInvokeInstruction.Dispatch.INTERFACE) return "interface"; Assertions.UNREACHABLE(); return null; } public String getInvocationString() { return getInvocationString(getInvocationCode()); } /** * Is this an invokeinterface call site? */ public final boolean isInterface() { return (getInvocationCode() == IInvokeInstruction.Dispatch.INTERFACE); } /** * Is this an invokevirtual call site? */ public final boolean isVirtual() { return (getInvocationCode() == IInvokeInstruction.Dispatch.VIRTUAL); } /** * Is this an invokespecial call site? */ public final boolean isSpecial() { return (getInvocationCode() == IInvokeInstruction.Dispatch.SPECIAL); } /** * Is this an invokestatic call site? */ public boolean isStatic() { return (getInvocationCode() == IInvokeInstruction.Dispatch.STATIC); } public boolean isFixed() { return isStatic() || isSpecial(); } public boolean isDispatch() { return isVirtual() || isInterface(); } }