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

201 lines
6.1 KiB
Java

/******************************************************************************
* Copyright (c) 2002 - 2014 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;
import java.lang.invoke.CallSite;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodHandles.Lookup;
import java.lang.invoke.MethodType;
import java.lang.reflect.Field;
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;
}
ConstantPoolReader getLazyConstantPool() {
return null;
}
@Override
public boolean isPEI() {
return true;
}
@Override
public Dispatch 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;
}
@Override
ConstantPoolReader getLazyConstantPool() {
return cp;
}
}
public CallSite bootstrap(Class cl) throws ClassNotFoundException, NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchFieldException {
ClassLoader classLoader = cl.getClassLoader();
ClassLoader bootstrapCL = classLoader;
Class<?> bootstrapClass = Class.forName(getBootstrap().methodClass().replace('/', '.'), false, bootstrapCL);
MethodType bt = makeMethodType( bootstrapCL, bootstrap.methodType());
Method bootstrap = bootstrapClass.getMethod(this.bootstrap.methodName(), bt.parameterList().toArray(new Class[ bt.parameterCount() ]));
Object[] args = new Object[ bt.parameterCount() ];
Lookup myLookup = MethodHandles.lookup().in(cl);
Field impl_lookup = Lookup.class.getDeclaredField("IMPL_LOOKUP"); // get the required field via reflections
impl_lookup.setAccessible(true); // set it accessible
Lookup lutrusted = (Lookup) impl_lookup.get(myLookup); // get the value of IMPL_LOOKUP from the Lookup instance and save it in a new Lookup object
args[0] = lutrusted;
args[1] = getMethodName();
args[2] = makeMethodType(classLoader, getMethodSignature());
for(int i = 3; i < bt.parameterCount(); i++) {
args[i] = getBootstrap().callArgument(bootstrapCL,i-3);
}
bootstrap.setAccessible(true);
System.err.println(cl + " : " + bootstrap);
return (CallSite) bootstrap.invoke(null, args);
}
public static MethodType makeMethodType(ClassLoader classLoader, String descriptor) throws ClassNotFoundException {
String returnType = Util.makeClass(Util.getReturnType(descriptor));
Class returnClass = Class.forName(returnType, false, classLoader);
String[] paramTypes = Util.getParamsTypes(null, descriptor);
Class[] paramClasses = new Class[ paramTypes.length ];
for(int i = 0; i < paramTypes.length; i++) {
paramClasses[i] = Class.forName(Util.makeClass(paramTypes[i]), false, classLoader);
}
MethodType mt = MethodType.methodType(returnClass, paramClasses);
return mt;
}
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);
}
}