下面列出了org.objectweb.asm.Opcodes# INVOKEDYNAMIC 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
private void executeInvokeInsn(
final AbstractInsnNode insn, final String methodDescriptor, final Interpreter<V> interpreter)
throws AnalyzerException {
ArrayList<V> valueList = new ArrayList<>();
for (int i = Type.getArgumentTypes(methodDescriptor).length; i > 0; --i) {
valueList.add(0, pop());
}
if (insn.getOpcode() != Opcodes.INVOKESTATIC && insn.getOpcode() != Opcodes.INVOKEDYNAMIC) {
valueList.add(0, pop());
}
if (Type.getReturnType(methodDescriptor) == Type.VOID_TYPE) {
interpreter.naryOperation(insn, valueList);
} else {
push(interpreter.naryOperation(insn, valueList));
}
}
public InsnValue onMethod(AbstractInsnNode insn, List<InsnValue> values) {
String desc = "V";
if (insn.getOpcode() == Opcodes.INVOKEDYNAMIC){
desc = ((InvokeDynamicInsnNode) insn).desc;
}else{
desc = ((MethodInsnNode) insn).desc;
}
// Until I'm ready to simulate method calls the opcode here really
// doesn't matter.
/*
* switch (insn.getOpcode()) { case Opcodes.INVOKEDYNAMIC: case
* Opcodes.INVOKESPECIAL: case Opcodes.INVOKEINTERFACE: case
* Opcodes.INVOKESTATIC: case Opcodes.INVOKEVIRTUAL: }
*/
if (desc.endsWith("V")) {
return null;
}
return new InsnValue(Type.getReturnType(desc));
}
private void executeInvokeInsn(final AbstractInsnNode insn, final String methodDescriptor,
final Interpreter<V> interpreter) throws AnalyzerException {
ArrayList<V> valueList = new ArrayList<>();
for (int i = Type.getArgumentTypes(methodDescriptor).length; i > 0; --i) {
valueList.add(0, pop());
}
if (insn.getOpcode() != Opcodes.INVOKESTATIC && insn.getOpcode() != Opcodes.INVOKEDYNAMIC) {
valueList.add(0, pop());
}
if (Type.getReturnType(methodDescriptor) == Type.VOID_TYPE) {
interpreter.naryOperation(insn, valueList);
} else {
push(interpreter.naryOperation(insn, valueList));
}
}
/**
* Constructs a new {@link InvokeDynamicInsnNode}.
*
* @param name the method's name.
* @param descriptor the method's descriptor (see {@link org.objectweb.asm.Type}).
* @param bootstrapMethodHandle the bootstrap method.
* @param bootstrapMethodArguments the bootstrap method constant arguments. Each argument must be
* an {@link Integer}, {@link Float}, {@link Long}, {@link Double}, {@link String}, {@link
* org.objectweb.asm.Type} or {@link Handle} value. This method is allowed to modify the
* content of the array so a caller should expect that this array may change.
*/
public InvokeDynamicInsnNode(
final String name,
final String descriptor,
final Handle bootstrapMethodHandle,
final Object... bootstrapMethodArguments) { // NOPMD(ArrayIsStoredDirectly): public field.
super(Opcodes.INVOKEDYNAMIC);
this.name = name;
this.desc = descriptor;
this.bsm = bootstrapMethodHandle;
this.bsmArgs = bootstrapMethodArguments;
}
private void traverse()
throws Exception {
while (!methodQueue.isEmpty()) {
MethodInfo methodInfo = methodQueue.remove();
if (!methodInfo.isReachable) {
throw new Exception("This method should have been marked as reachable!");
}
for (MethodInvocation invocation : methodInfo.methodInvocations) {
ClassInfo ownerClass = classInfoMap.get(invocation.className);
// if this class isn't in the classInfoMap, it's not part of usercode, so just proceed
if (null != ownerClass) {
MethodInfo calledMethod = ownerClass.getMethodMap()
.get(invocation.methodIdentifier);
switch (invocation.invocationOpcode) {
case Opcodes.INVOKESPECIAL:
// this is the easy case: we just mark the methodInfo as reachable and enqueue it
enqueue(calledMethod);
break;
case Opcodes.INVOKEVIRTUAL:
case Opcodes.INVOKEDYNAMIC:
case Opcodes.INVOKEINTERFACE:
// INVOKESTATIC can be inherited even though it's not in the class bytecode
case Opcodes.INVOKESTATIC:
enqueueSelfAndChildren(ownerClass, invocation.methodIdentifier);
break;
default:
throw new Exception("This is not an invoke method opcode");
}
}
}
}
}
@SuppressWarnings("deprecation")
public InvokeDynamicInsnNode() {
super(Opcodes.INVOKEDYNAMIC);
name = "";
desc = "";
bsmArgs = new Object[] { Type.getType("()V"), new Handle(Opcodes.H_INVOKESTATIC, "", "", ""), Type.getType("(V") };
bsm = new Handle(Opcodes.H_INVOKESTATIC, "", "", "");
}
/**
* Constructs a new {@link InvokeDynamicInsnNode}.
*
* @param name the method's name.
* @param descriptor the method's descriptor (see {@link org.objectweb.asm.Type}).
* @param bootstrapMethodHandle the bootstrap method.
* @param bootstrapMethodArguments the bootstrap method constant arguments. Each argument must be
* an {@link Integer}, {@link Float}, {@link Long}, {@link Double}, {@link String}, {@link
* org.objectweb.asm.Type} or {@link Handle} value. This method is allowed to modify the
* content of the array so a caller should expect that this array may change.
*/
public InvokeDynamicInsnNode(
final String name,
final String descriptor,
final Handle bootstrapMethodHandle,
final Object... bootstrapMethodArguments) { // NOPMD(ArrayIsStoredDirectly): public field.
super(Opcodes.INVOKEDYNAMIC);
this.name = name;
this.desc = descriptor;
this.bsm = bootstrapMethodHandle;
this.bsmArgs = bootstrapMethodArguments;
}
/**
* Constructs a new {@link InvokeDynamicInsnNode}.
*
* @param name the method's name.
* @param descriptor the method's descriptor (see {@link org.objectweb.asm.Type}).
* @param bootstrapMethodHandle the bootstrap method.
* @param bootstrapMethodArguments the bootstrap method constant arguments. Each argument must be
* an {@link Integer}, {@link Float}, {@link Long}, {@link Double}, {@link String}, {@link
* org.objectweb.asm.Type} or {@link Handle} value. This method is allowed to modify the
* content of the array so a caller should expect that this array may change.
*/
public InvokeDynamicInsnNode(
final String name,
final String descriptor,
final Handle bootstrapMethodHandle,
final Object... bootstrapMethodArguments) { // NOPMD(ArrayIsStoredDirectly): public field.
super(Opcodes.INVOKEDYNAMIC);
this.name = name;
this.desc = descriptor;
this.bsm = bootstrapMethodHandle;
this.bsmArgs = bootstrapMethodArguments;
}
private boolean needsFrameGuard(int opcode, String owner, String name, String desc) {
if (owner.startsWith("java/") || owner.startsWith("javax/")) {
//System.out.println("SKIP:: " + owner + "." + name + desc);
return false;
}
// Always create save-point before Continuation methods (like suspend)
if (CONTINUATION_CLASS_INTERNAL_NAME.equals(owner)) {
return CONTINUATION_CLASS_CONTINUABLE_METHODS.contains(name);
}
// No need to create save-point before constructors -- it's forbidden to suspend in constructors anyway
if (opcode == Opcodes.INVOKESPECIAL && "<init>".equals(name)) {
return false;
}
if (opcode == Opcodes.INVOKEDYNAMIC) {
// TODO verify CallSite to be continuable?
return true;
}
if (opcode == Opcodes.INVOKEINTERFACE ||
opcode == Opcodes.INVOKESPECIAL ||
opcode == Opcodes.INVOKESTATIC ||
opcode == Opcodes.INVOKEVIRTUAL) {
ContinuableClassInfo classInfo;
try {
classInfo = cciResolver.resolve(owner);
} catch (IOException ex) {
throw new RuntimeException(ex);
}
return null != classInfo && classInfo.isContinuableMethod(opcode, name, desc, desc);
}
return false;
}
private boolean needsFrameGuard(int opcode, String owner, String name, String desc) {
if (owner.startsWith("java/") || owner.startsWith("javax/")) {
//System.out.println("SKIP:: " + owner + "." + name + desc);
return false;
}
// Always create save-point before Continuation methods (like suspend)
if (CONTINUATION_CLASS_INTERNAL_NAME.equals(owner)) {
return CONTINUATION_CLASS_CONTINUABLE_METHODS.contains(name);
}
// No need to create save-point before constructors -- it's forbidden to suspend in constructors anyway
if (opcode == Opcodes.INVOKESPECIAL && "<init>".equals(name)) {
return false;
}
if (opcode == Opcodes.INVOKEDYNAMIC) {
// TODO verify CallSite to be continuable?
return true;
}
if (opcode == Opcodes.INVOKEINTERFACE ||
opcode == Opcodes.INVOKESPECIAL ||
opcode == Opcodes.INVOKESTATIC ||
opcode == Opcodes.INVOKEVIRTUAL) {
ContinuableClassInfo classInfo;
try {
classInfo = cciResolver.resolve(owner);
} catch (IOException ex) {
throw new RuntimeException(ex);
}
return null != classInfo && classInfo.isContinuableMethod(opcode, name, desc, desc);
}
return false;
}
/**
* @param opcode
* @param args
* @param tgt
* @param r
* @param signatureTypes
* @return
*/
private List<Type> setupTainting ( MethodReference call, int opcode, List<BaseType> args, Object tgt, MethodReference r, Type[] signatureTypes ) {
if ( opcode != Opcodes.INVOKESTATIC && opcode != Opcodes.INVOKEDYNAMIC ) {
if ( tgt == null || ! ( tgt instanceof BaseType ) || ( (BaseType) tgt ).isTainted() ) {
r.taintCallee();
}
}
boolean foundTypes = true;
List<Type> actualTypes = new ArrayList<>();
if ( signatureTypes.length != args.size() ) {
return null;
}
for ( int i = 0; i < signatureTypes.length; i++ ) {
Object object = args.get(i);
if ( object instanceof BaseType ) {
if ( object instanceof SimpleType ) {
Type type = ( (SimpleType) object ).getType();
Set<Type> altTypes = ( (BaseType) object ).getAlternativeTypes();
Type sigType = signatureTypes[ i ];
if ( type == null ) {
actualTypes.add(sigType);
}
else if ( altTypes == null || altTypes.isEmpty() ) {
try {
Type moreConcreteType = this.parent.getAnalyzer().getMoreConcreteType(type, sigType);
if ( !moreConcreteType.equals(sigType) ) {
// log.info("Improving type to " + moreConcreteType + " for " + call + " in " +
// this.ref);
}
actualTypes.add(moreConcreteType);
}
catch ( SerianalyzerException e ) {
this.log.error("Failed to determine argument type", e); //$NON-NLS-1$
this.log.warn("Formal arguments are " + Arrays.toString(signatureTypes)); //$NON-NLS-1$
this.log.warn("Known arguments are " + args); //$NON-NLS-1$
this.log.warn("Failing arg " + i + ": " + object); //$NON-NLS-1$ //$NON-NLS-2$
this.log.warn("Failing arg type " + type); //$NON-NLS-1$
this.log.warn("Signature type " + sigType); //$NON-NLS-1$
this.log.warn("In " + this.ref); //$NON-NLS-1$
this.log.warn("Calling " + call); //$NON-NLS-1$
foundTypes = false;
}
}
}
else {
foundTypes = false;
}
if ( ( (BaseType) object ).isTainted() ) {
r.taintParameter(i);
}
if ( object instanceof BasicVariable && ( (BasicVariable) object ).isTaintReturns() ) {
r.taintParameterReturns(i);
}
}
else {
r.taintParameter(i);
foundTypes = false;
}
}
if ( foundTypes ) {
return actualTypes;
}
//
return null;
}
/**
* Constructs a new {@link InvokeDynamicInsnNode}.
*
* @param name
* the method's name.
* @param descriptor
* the method's descriptor (see {@link org.objectweb.asm.Type}).
* @param bootstrapMethodHandle
* the bootstrap method.
* @param bootstrapMethodArguments
* the bootstrap method constant arguments. Each argument must be an {@link Integer}, {@link Float}, {@link Long}, {@link Double}, {@link String}, {@link org.objectweb.asm.Type} or {@link Handle} value. This method is allowed to modify the content of the array so a caller should expect that this array may change.
*/
public InvokeDynamicInsnNode(final String name, final String descriptor, final Handle bootstrapMethodHandle,
final Object... bootstrapMethodArguments) { // NOPMD(ArrayIsStoredDirectly): public field.
super(Opcodes.INVOKEDYNAMIC);
this.name = name;
this.desc = descriptor;
this.bsm = bootstrapMethodHandle;
this.bsmArgs = bootstrapMethodArguments;
}
/**
* Constructs a new {@link InvokeDynamicInsnNode}.
*
* @param name
* invokedynamic name.
* @param desc
* invokedynamic descriptor (see {@link org.objectweb.asm.Type}).
* @param bsm
* the bootstrap method.
* @param bsmArgs
* the boostrap constant arguments.
*/
public InvokeDynamicInsnNode(final String name, final String desc, final Handle bsm, final Object... bsmArgs) {
super(Opcodes.INVOKEDYNAMIC);
this.name = name;
this.desc = desc;
this.bsm = bsm;
this.bsmArgs = bsmArgs;
}