WALA/com.ibm.wala.shrike/src/com/ibm/wala/shrikeBT/InvokeDynamicInstruction.java

157 lines
4.3 KiB
Java

package com.ibm.wala.shrikeBT;
import java.lang.invoke.CallSite;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import com.ibm.wala.shrikeCT.BootstrapMethodsReader.BootstrapMethod;
public class InvokeDynamicInstruction extends Instruction implements IInvokeInstruction {
protected BootstrapMethod bootstrap;
protected String methodName;
protected String methodType;
public InvokeDynamicInstruction(short opcode, BootstrapMethod bootstrap, String methodName, String methodType) {
super(opcode);
this.bootstrap = bootstrap;
this.methodName = methodName;
this.methodType = methodType;
}
@Override
public boolean isPEI() {
return true;
}
@Override
public IDispatch getInvocationCode() {
int invokeType = getBootstrap().invokeType();
switch (invokeType) {
case 5: return Dispatch.VIRTUAL;
case 6: return Dispatch.STATIC;
case 7: return Dispatch.SPECIAL;
case 9: return Dispatch.INTERFACE;
default:
throw new Error("unexpected dynamic invoke type " + invokeType);
}
}
@Override
final public int getPoppedCount() {
return (getInvocationCode().equals(Dispatch.STATIC) ? 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);
}
public BootstrapMethod getBootstrap() {
return bootstrap;
}
@Override
public String getMethodSignature() {
return methodType;
}
@Override
public String getMethodName() {
return methodName;
}
@Override
public String getClassType() {
return getBootstrap().methodClass();
}
@Override
public void visit(Visitor v) {
v.visitInvoke(this);
}
@Override
public String toString() {
return "InvokeDynamic [" + getBootstrap() + "] " + getMethodName() + getMethodSignature();
}
final static class Lazy extends InvokeDynamicInstruction {
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;
}
int getCPIndex() {
return index;
}
@Override
public BootstrapMethod getBootstrap() {
if (bootstrap == null) {
bootstrap = cp.getConstantPoolDynamicBootstrap(index);
}
return bootstrap;
}
@Override
public String getMethodName() {
if (methodName == null) {
methodName = cp.getConstantPoolDynamicName(index);
}
return methodName;
}
@Override
public String getMethodSignature() {
if (methodType == null) {
methodType = cp.getConstantPoolDynamicType(index);
}
return methodType;
}
}
public CallSite bootstrap(Class cl) throws ClassNotFoundException, NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
ClassLoader bootstrapCL = cl.getClassLoader();
Class<?> bootstrapClass = Class.forName(getBootstrap().methodClass().replace('/', '.'), false, bootstrapCL);
MethodType bt = MethodType.fromMethodDescriptorString(bootstrap.methodType(), bootstrapCL);
Method bootstrap = bootstrapClass.getMethod(this.bootstrap.methodName(), bt.parameterList().toArray(new Class[ bt.parameterCount() ]));
Object[] args = new Object[ bt.parameterCount() ];
args[0] = MethodHandles.lookup().in(cl);
args[1] = getMethodName();
args[2] = MethodType.fromMethodDescriptorString(getMethodSignature(), cl.getClassLoader());
for(int i = 3; i < bt.parameterCount(); i++) {
args[i] = getBootstrap().callArgument(i-3);
}
return (CallSite) bootstrap.invoke(null, args);
}
static InvokeDynamicInstruction make(ConstantPoolReader cp, int index, int mode) {
if (mode != OP_invokedynamic) {
throw new IllegalArgumentException("Unknown mode: " + mode);
}
return new Lazy((short) mode, cp, index);
}
}