/*******************************************************************************
* 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.shrikeBT;
/**
* This class represents method invocation instructions.
*/
public class InvokeInstruction extends Instruction implements IInvokeInstruction {
protected String type;
protected String classType;
protected String methodName;
InvokeInstruction(short opcode, String type, String classType, String methodName) {
super(opcode);
this.type = type;
this.classType = classType;
this.methodName = methodName;
}
public static InvokeInstruction make(String type, String className, String methodName, Dispatch mode) throws NullPointerException {
if (type == null) {
throw new NullPointerException("type must not be null");
}
if (className == null) {
throw new NullPointerException("className must not be null");
}
if (methodName == null) {
throw new NullPointerException("methodName must not be null");
}
if (mode == null) {
throw new NullPointerException("mode must not be null");
}
short opcode = 0;
switch (mode) {
case VIRTUAL:
opcode = OP_invokevirtual;
break;
case SPECIAL:
opcode = OP_invokespecial;
break;
case STATIC:
opcode = OP_invokestatic;
break;
case INTERFACE:
opcode = OP_invokeinterface;
break;
default:
assert false;
}
return new InvokeInstruction(opcode, type, className, methodName);
}
ConstantPoolReader getLazyConstantPool() {
return null;
}
final static class Lazy extends InvokeInstruction {
final private ConstantPoolReader cp;
final private int index;
Lazy(short opcode, ConstantPoolReader cp, int index) {
super(opcode, null, null, null);
this.index = index;
this.cp = cp;
}
@Override
ConstantPoolReader getLazyConstantPool() {
return cp;
}
int getCPIndex() {
return index;
}
@Override
public String getClassType() {
if (classType == null) {
classType = cp.getConstantPoolMemberClassType(index);
}
return classType;
}
@Override
public String getMethodName() {
if (methodName == null) {
methodName = cp.getConstantPoolMemberName(index);
}
return methodName;
}
@Override
public String getMethodSignature() {
if (type == null) {
type = cp.getConstantPoolMemberType(index);
}
return type;
}
}
static InvokeInstruction make(ConstantPoolReader cp, int index, int mode) {
if (mode < OP_invokevirtual || mode > OP_invokeinterface) {
throw new IllegalArgumentException("Unknown mode: " + mode);
}
return new Lazy((short) mode, cp, index);
}
@Override
final public boolean equals(Object o) {
if (o instanceof InvokeInstruction) {
InvokeInstruction i = (InvokeInstruction) o;
return i.getMethodSignature().equals(getMethodSignature()) && i.getClassType().equals(getClassType())
&& i.getMethodName().equals(getMethodName()) && i.opcode == opcode;
} else {
return false;
}
}
@Override
public String getClassType() {
return classType;
}
@Override
public String getMethodName() {
return methodName;
}
@Override
public String getMethodSignature() {
return type;
}
final public int getInvocationMode() {
return opcode;
}
final public String getInvocationModeString() {
switch (opcode) {
case Constants.OP_invokestatic:
return "STATIC";
case Constants.OP_invokeinterface:
return "INTERFACE";
case Constants.OP_invokespecial:
return "SPECIAL";
case Constants.OP_invokevirtual:
return "VIRTUAL";
default:
throw new Error("Unknown mode: " + opcode);
}
}
@Override
final public int hashCode() {
return getMethodSignature().hashCode() + 9011 * getClassType().hashCode() + 317 * getMethodName().hashCode() + opcode * 3188;
}
@Override
final public int getPoppedCount() {
return (opcode == Constants.OP_invokestatic ? 0 : 1) + Util.getParamsCount(getMethodSignature());
}
@Override
final public String getPushedType(String[] types) {
String t = Util.getReturnType(getMethodSignature());
if (t.equals(Constants.TYPE_void)) {
return null;
} else {
return t;
}
}
@Override
final public byte getPushedWordSize() {
String t = getMethodSignature();
int index = t.lastIndexOf(')');
return Util.getWordSize(t, index + 1);
}
@Override
final public void visit(IInstruction.Visitor v) throws NullPointerException {
v.visitInvoke(this);
}
@Override
final public String toString() {
return "Invoke(" + getInvocationModeString() + "," + getClassType() + "," + getMethodName() + "," + getMethodSignature() + ")";
}
@Override
public boolean isPEI() {
return true;
}
@Override
public Dispatch getInvocationCode() {
switch (opcode) {
case Constants.OP_invokestatic:
return Dispatch.STATIC;
case Constants.OP_invokeinterface:
return Dispatch.INTERFACE;
case Constants.OP_invokespecial:
return Dispatch.SPECIAL;
case Constants.OP_invokevirtual:
return Dispatch.VIRTUAL;
default:
throw new Error("Unknown mode: " + opcode);
}
}
}