WALA/com.ibm.wala.shrike/src/com/ibm/wala/shrikeCT/BootstrapMethodsReader.java

164 lines
5.4 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.shrikeCT;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodHandles.Lookup;
import java.lang.invoke.MethodType;
import java.lang.reflect.Method;
import com.ibm.wala.shrikeCT.ClassReader.AttrIterator;
public class BootstrapMethodsReader extends AttributeReader {
public interface BootstrapMethod {
int invokeType();
String methodClass();
String methodName();
String methodType();
int callArgumentCount();
Object callArgument(ClassLoader cl, int i);
int callArgumentIndex(int i);
int callArgumentKind(int i);
}
private BootstrapMethod entries[];
protected BootstrapMethodsReader(AttrIterator attr) throws InvalidClassFileException {
super(attr, "BootstrapMethods");
readBootstrapEntries();
}
private void readBootstrapEntries() throws InvalidClassFileException {
final ConstantPoolParser cp = cr.getCP();
entries = new BootstrapMethod[cr.getUShort(attr + 6)];
int base = 8;
for(int i = 0; i < entries.length; i++) {
final int methodHandleOffset = cr.getUShort(attr + base);
final int argsBase = attr + base + 4;
final int argumentCount = cr.getUShort(attr + base + 2);
entries[i] = new BootstrapMethod() {
private final int invokeType = cp.getCPHandleKind(methodHandleOffset);
private final String methodClass = cp.getCPHandleClass(methodHandleOffset);
private final String methodName = cp.getCPHandleName(methodHandleOffset);
private final String methodType = cp.getCPHandleType(methodHandleOffset);
@Override
public String toString() {
return methodClass + ":" + methodName + methodType;
}
@Override
public int invokeType() {
return invokeType;
}
@Override
public String methodClass() {
return methodClass;
}
@Override
public String methodName() {
return methodName;
}
@Override
public String methodType() {
return methodType;
}
@Override
public int callArgumentCount() {
return argumentCount;
}
@Override
public int callArgumentKind(int i) {
return cp.getItemType(callArgumentIndex(i));
}
@Override
public int callArgumentIndex(int i) {
assert 0 <= i && i < argumentCount;
int index = argsBase + (2*i);
return cr.getUShort(index);
}
@Override
public Object callArgument(ClassLoader cl, int i) {
try {
int index = callArgumentIndex(i);
int t = callArgumentKind(i);
switch (t) {
case ClassConstants.CONSTANT_Utf8:
return cp.getCPUtf8(index);
case ClassConstants.CONSTANT_Class:
return cp.getCPClass(index);
case ClassConstants.CONSTANT_String:
return cp.getCPString(index);
case ClassConstants.CONSTANT_Integer:
return cp.getCPInt(index);
case ClassConstants.CONSTANT_Float:
return cp.getCPFloat(index);
case ClassConstants.CONSTANT_Double:
return cp.getCPDouble(index);
case ClassConstants.CONSTANT_Long:
return cp.getCPLong(index);
case ClassConstants.CONSTANT_MethodHandle:
String className = cp.getCPHandleClass(index);
Class<?> cls = Class.forName(className.replace('/', '.'), false, cl);
String eltName = cp.getCPHandleName(index);
String eltDesc = cp.getCPHandleType(index);
MethodType type = MethodType.fromMethodDescriptorString(eltDesc, cl);
Method m = cls.getDeclaredMethod(eltName, type.parameterList().toArray(new Class[type.parameterCount()]));
Lookup lk = MethodHandles.lookup().in(cls);
m.setAccessible(true);
return lk.unreflect(m);
case ClassConstants.CONSTANT_MethodType:
return MethodType.fromMethodDescriptorString(cp.getCPMethodType(index), cl);
default:
assert false : "invalid type " + t;
}
} catch (IllegalArgumentException e) {
assert false : e;
} catch (InvalidClassFileException e) {
assert false : e;
} catch (ClassNotFoundException e) {
assert false : e;
} catch (NoSuchMethodException e) {
assert false : e;
} catch (SecurityException e) {
assert false : e;
} catch (IllegalAccessException e) {
assert false : e;
}
return null;
}
};
base += (argumentCount*2) + 4;
}
}
public int count() {
return entries.length;
}
public BootstrapMethod getEntry(int i) {
return entries[i];
}
}