下面列出了org.objectweb.asm.Opcodes# H_INVOKEINTERFACE 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
@Override
public Set<MethodNode> resolveTargets(InvocationResolver res) {
// this is probably like 99% of all the invokedynamics
if (bootstrapMethod.getOwner().equals("java/lang/invoke/LambdaMetafactory")
&& bootstrapMethod.getName().equals("metafactory")) {
assert (bootstrapArgs.length == 3 && bootstrapArgs[1] instanceof Handle);
Handle boundFunc = (Handle) bootstrapArgs[1];
switch (boundFunc.getTag()) {
case Opcodes.H_INVOKESTATIC:
return StaticInvocationExpr.resolveStaticCall(res, boundFunc.getOwner(), boundFunc.getName(), boundFunc.getDesc());
case Opcodes.H_INVOKESPECIAL:
assert(boundFunc.getName().equals("<init>"));
return VirtualInvocationExpr.resolveSpecialInvocation(res, boundFunc.getOwner(), boundFunc.getDesc());
case Opcodes.H_INVOKEINTERFACE:
case Opcodes.H_INVOKEVIRTUAL:
return VirtualInvocationExpr.resolveVirtualInvocation(res, boundFunc.getOwner(), boundFunc.getOwner(), boundFunc.getDesc());
default:
throw new IllegalArgumentException("Unexpected metafactory bootstrap tag?? " + boundFunc.getTag());
}
}
return new HashSet<>();
}
@Override
public void visitInvokeDynamicInsn(String origMethodName, String methodDescriptor, Handle bootstrapMethodHandle, Object... bootstrapMethodArguments) {
String methodOwner = bootstrapMethodHandle.getOwner();
if (isStringConcatIndy(methodOwner, origMethodName)) {
handleStringConcatIndy(origMethodName, methodDescriptor, bootstrapMethodHandle, bootstrapMethodArguments);
} else if (isLambdaIndy(methodOwner)) {
// AKI-130: The bootstrap methodDescriptor to this metafactory must NOT require additional arguments (since that would require dynamic class generation for each callsite - potential attack vector).
if (!methodDescriptor.startsWith("()")) {
throw RejectedClassException.invokeDynamicBootstrapMethodArguments(methodDescriptor);
}
// This is really just a specialization of the above call to check the return type (this would need to be changed if we accepted arguments).
if (!RUNNABLE_DESCRIPTOR.equals(methodDescriptor) && !FUNCTION_DESCRIPTOR.equals(methodDescriptor)) {
throw RejectedClassException.invokeDynamicLambdaType(methodDescriptor);
}
if (bootstrapMethodHandle.getTag() != Opcodes.H_INVOKEVIRTUAL && bootstrapMethodHandle.getTag() != Opcodes.H_INVOKESTATIC
&& bootstrapMethodHandle.getTag() != Opcodes.H_NEWINVOKESPECIAL && bootstrapMethodHandle.getTag() != Opcodes.H_INVOKEINTERFACE) {
throw RejectedClassException.invokeDynamicHandleType(bootstrapMethodHandle.getTag(), methodDescriptor);
}
handleLambdaIndy(origMethodName, methodDescriptor, bootstrapMethodHandle, bootstrapMethodArguments);
} else {
throw RejectedClassException.invokeDynamicUnsupportedMethodOwner(origMethodName, methodOwner);
}
}
void checkLDCConstant(final Object cst) {
if (cst instanceof Type) {
int s = ((Type) cst).getSort();
if (s != Type.OBJECT && s != Type.ARRAY && s != Type.METHOD) {
throw new IllegalArgumentException("Illegal LDC constant value");
}
if (s != Type.METHOD && (version & 0xFFFF) < Opcodes.V1_5) {
throw new IllegalArgumentException("ldc of a constant class requires at least version 1.5");
}
if (s == Type.METHOD && (version & 0xFFFF) < Opcodes.V1_7) {
throw new IllegalArgumentException("ldc of a method type requires at least version 1.7");
}
} else if (cst instanceof Handle) {
if ((version & 0xFFFF) < Opcodes.V1_7) {
throw new IllegalArgumentException("ldc of a handle requires at least version 1.7");
}
int tag = ((Handle) cst).getTag();
if (tag < Opcodes.H_GETFIELD || tag > Opcodes.H_INVOKEINTERFACE) {
throw new IllegalArgumentException("invalid handle tag " + tag);
}
} else {
checkConstant(cst);
}
}
@Override
public boolean isField() {
switch (this.handle.getTag()) {
case Opcodes.H_INVOKEVIRTUAL:
case Opcodes.H_INVOKESTATIC:
case Opcodes.H_INVOKEINTERFACE:
case Opcodes.H_INVOKESPECIAL:
case Opcodes.H_NEWINVOKESPECIAL:
return false;
case Opcodes.H_GETFIELD:
case Opcodes.H_GETSTATIC:
case Opcodes.H_PUTFIELD:
case Opcodes.H_PUTSTATIC:
return true;
default:
throw new MixinTransformerError("Invalid tag " + this.handle.getTag() + " for method handle " + this.handle + ".");
}
}
/**
* Produces a {@link MethodHandle} using either the context or {@link #targetLoader} class
* loader, depending on {@code target}.
*/
private MethodHandle toMethodHandle(Lookup lookup, Handle asmHandle, boolean target)
throws ReflectiveOperationException {
Class<?> owner = loadFromInternal(asmHandle.getOwner());
MethodType signature =
MethodType.fromMethodDescriptorString(
asmHandle.getDesc(),
target ? targetLoader : Thread.currentThread().getContextClassLoader());
switch (asmHandle.getTag()) {
case Opcodes.H_INVOKESTATIC:
return lookup.findStatic(owner, asmHandle.getName(), signature);
case Opcodes.H_INVOKEVIRTUAL:
case Opcodes.H_INVOKEINTERFACE:
return lookup.findVirtual(owner, asmHandle.getName(), signature);
case Opcodes.H_INVOKESPECIAL: // we end up calling these using invokevirtual
return lookup.findSpecial(owner, asmHandle.getName(), signature, owner);
case Opcodes.H_NEWINVOKESPECIAL:
return lookup.findConstructor(owner, signature);
default:
throw new UnsupportedOperationException("Cannot resolve " + asmHandle);
}
}
private static int toTag(MethodName method) {
switch (method.invoke) {
case Interface:
return Opcodes.H_INVOKEINTERFACE;
case Special:
case SpecialInterface:
return Opcodes.H_INVOKESPECIAL;
case Static:
case StaticInterface:
return Opcodes.H_INVOKESTATIC;
case Virtual:
case VirtualInterface:
return Opcodes.H_INVOKEVIRTUAL;
default:
throw new AssertionError();
}
}
private void registerMethodHandleType(Handle handle) {
switch (handle.getTag()) {
case Opcodes.H_GETFIELD:
case Opcodes.H_GETSTATIC:
case Opcodes.H_PUTFIELD:
case Opcodes.H_PUTSTATIC:
visitFieldInsn(Opcodes.GETFIELD, handle.getOwner(), handle.getName(), handle.getDesc());
break;
case Opcodes.H_INVOKEVIRTUAL:
case Opcodes.H_INVOKEINTERFACE:
case Opcodes.H_INVOKESPECIAL:
case Opcodes.H_INVOKESTATIC:
case Opcodes.H_NEWINVOKESPECIAL:
visitMethodInsn(
Opcodes.H_INVOKEVIRTUAL,
handle.getOwner(),
handle.getName(),
handle.getDesc(),
false);
createAdditionalMethodsForDesugar(handle);
break;
default:
throw new IllegalStateException(
"MethodHandle tag is not supported: " + handle.getTag());
}
}
private void createAdditionalMethodsForDesugar(Handle handle) {
visitMethodInsn(
Opcodes.INVOKEVIRTUAL,
"-$$Lambda$" + handle.getOwner(),
"lambda$constructor$" + handle.getName(),
handle.getDesc(),
false);
visitMethodInsn(
Opcodes.INVOKEVIRTUAL,
"-$$Lambda$" + handle.getOwner(),
"lambda$original$" + handle.getName(),
handle.getDesc(),
false);
visitMethodInsn(
Opcodes.INVOKEVIRTUAL,
"-$$Lambda$" + handle.getOwner(),
"lambda$bridge$" + handle.getName(),
handle.getDesc(),
false);
if (!(handle.getTag() == Opcodes.H_INVOKEVIRTUAL
|| handle.getTag() == Opcodes.H_INVOKEINTERFACE)) {
visitMethodInsn(
Opcodes.INVOKESTATIC,
"-$$Lambda$" + handle.getOwner(),
"lambda$forwarding$" + handle.getName(),
handle.getDesc(),
false);
}
}
@Override
public void setOpcode(int opcode) {
int tag = MemberRef.tagFromOpcode(opcode);
if (tag == 0) {
throw new MixinTransformerError("Invalid opcode " + Bytecode.getOpcodeName(opcode) + " for method handle " + this.handle + ".");
}
boolean itf = tag == Opcodes.H_INVOKEINTERFACE;
this.handle = new org.objectweb.asm.Handle(tag, this.handle.getOwner(), this.handle.getName(), this.handle.getDesc(), itf);
}
static int invokeOpcode(Handle invokedMethod) {
switch (invokedMethod.getTag()) {
case Opcodes.H_INVOKESTATIC:
return Opcodes.INVOKESTATIC;
case Opcodes.H_INVOKEVIRTUAL:
return Opcodes.INVOKEVIRTUAL;
case Opcodes.H_INVOKESPECIAL:
case Opcodes.H_NEWINVOKESPECIAL: // Must be preceded by NEW
return Opcodes.INVOKESPECIAL;
case Opcodes.H_INVOKEINTERFACE:
return Opcodes.INVOKEINTERFACE;
default:
throw new UnsupportedOperationException("Don't know how to call " + invokedMethod);
}
}
/**
* Appends a string representation of the given handle to {@link #stringBuilder}.
*
* @param handle a handle.
*/
protected void appendHandle(final Handle handle) {
int tag = handle.getTag();
stringBuilder.append("// handle kind 0x").append(Integer.toHexString(tag)).append(" : ");
boolean isMethodHandle = false;
switch (tag) {
case Opcodes.H_GETFIELD:
stringBuilder.append("GETFIELD");
break;
case Opcodes.H_GETSTATIC:
stringBuilder.append("GETSTATIC");
break;
case Opcodes.H_PUTFIELD:
stringBuilder.append("PUTFIELD");
break;
case Opcodes.H_PUTSTATIC:
stringBuilder.append("PUTSTATIC");
break;
case Opcodes.H_INVOKEINTERFACE:
stringBuilder.append("INVOKEINTERFACE");
isMethodHandle = true;
break;
case Opcodes.H_INVOKESPECIAL:
stringBuilder.append("INVOKESPECIAL");
isMethodHandle = true;
break;
case Opcodes.H_INVOKESTATIC:
stringBuilder.append("INVOKESTATIC");
isMethodHandle = true;
break;
case Opcodes.H_INVOKEVIRTUAL:
stringBuilder.append("INVOKEVIRTUAL");
isMethodHandle = true;
break;
case Opcodes.H_NEWINVOKESPECIAL:
stringBuilder.append("NEWINVOKESPECIAL");
isMethodHandle = true;
break;
default:
throw new IllegalArgumentException();
}
stringBuilder.append('\n');
stringBuilder.append(tab3);
appendDescriptor(INTERNAL_NAME, handle.getOwner());
stringBuilder.append('.');
stringBuilder.append(handle.getName());
if (!isMethodHandle) {
stringBuilder.append('(');
}
appendDescriptor(HANDLE_DESCRIPTOR, handle.getDesc());
if (!isMethodHandle) {
stringBuilder.append(')');
}
if (handle.isInterface()) {
stringBuilder.append(" itf");
}
}
/**
* Checks that the given value is a valid operand for the LDC instruction.
*
* @param value the value to be checked.
*/
private void checkLdcConstant(final Object value) {
if (value instanceof Type) {
int sort = ((Type) value).getSort();
if (sort != Type.OBJECT && sort != Type.ARRAY && sort != Type.METHOD) {
throw new IllegalArgumentException("Illegal LDC constant value");
}
if (sort != Type.METHOD && (version & 0xFFFF) < Opcodes.V1_5) {
throw new IllegalArgumentException("ldc of a constant class requires at least version 1.5");
}
if (sort == Type.METHOD && (version & 0xFFFF) < Opcodes.V1_7) {
throw new IllegalArgumentException("ldc of a method type requires at least version 1.7");
}
} else if (value instanceof Handle) {
if ((version & 0xFFFF) < Opcodes.V1_7) {
throw new IllegalArgumentException("ldc of a Handle requires at least version 1.7");
}
Handle handle = (Handle) value;
int tag = handle.getTag();
if (tag < Opcodes.H_GETFIELD || tag > Opcodes.H_INVOKEINTERFACE) {
throw new IllegalArgumentException("invalid handle tag " + tag);
}
checkInternalName(this.version, handle.getOwner(), "handle owner");
if (tag <= Opcodes.H_PUTSTATIC) {
checkDescriptor(this.version, handle.getDesc(), false);
} else {
checkMethodDescriptor(this.version, handle.getDesc());
}
String handleName = handle.getName();
if (!("<init>".equals(handleName) && tag == Opcodes.H_NEWINVOKESPECIAL)) {
checkMethodIdentifier(this.version, handleName, "handle name");
}
} else if (value instanceof ConstantDynamic) {
if ((version & 0xFFFF) < Opcodes.V11) {
throw new IllegalArgumentException("ldc of a ConstantDynamic requires at least version 11");
}
ConstantDynamic constantDynamic = (ConstantDynamic) value;
checkMethodIdentifier(this.version, constantDynamic.getName(), "constant dynamic name");
checkDescriptor(this.version, constantDynamic.getDescriptor(), false);
checkLdcConstant(constantDynamic.getBootstrapMethod());
int bootstrapMethodArgumentCount = constantDynamic.getBootstrapMethodArgumentCount();
for (int i = 0; i < bootstrapMethodArgumentCount; ++i) {
checkLdcConstant(constantDynamic.getBootstrapMethodArgument(i));
}
} else {
checkConstant(value);
}
}
/**
* @return ASM handle from AST data.
*/
public Handle compile() {
return new Handle(getTag().getTag(), getOwner().getType(), getName().getName(),
getDesc().getDesc(), getTag().getTag() == Opcodes.H_INVOKEINTERFACE);
}
/**
* Appends the information about the given handle to {@link #buf buf}.
*
* @param h
* a handle, non null.
*/
protected void appendHandle(final Handle h) {
int tag = h.getTag();
buf.append("// handle kind 0x").append(Integer.toHexString(tag)).append(" : ");
boolean isMethodHandle = false;
switch (tag) {
case Opcodes.H_GETFIELD:
buf.append("GETFIELD");
break;
case Opcodes.H_GETSTATIC:
buf.append("GETSTATIC");
break;
case Opcodes.H_PUTFIELD:
buf.append("PUTFIELD");
break;
case Opcodes.H_PUTSTATIC:
buf.append("PUTSTATIC");
break;
case Opcodes.H_INVOKEINTERFACE:
buf.append("INVOKEINTERFACE");
isMethodHandle = true;
break;
case Opcodes.H_INVOKESPECIAL:
buf.append("INVOKESPECIAL");
isMethodHandle = true;
break;
case Opcodes.H_INVOKESTATIC:
buf.append("INVOKESTATIC");
isMethodHandle = true;
break;
case Opcodes.H_INVOKEVIRTUAL:
buf.append("INVOKEVIRTUAL");
isMethodHandle = true;
break;
case Opcodes.H_NEWINVOKESPECIAL:
buf.append("NEWINVOKESPECIAL");
isMethodHandle = true;
break;
}
buf.append('\n');
buf.append(tab3);
appendDescriptor(INTERNAL_NAME, h.getOwner());
buf.append('.');
buf.append(h.getName());
if (!isMethodHandle) {
buf.append('(');
}
appendDescriptor(HANDLE_DESCRIPTOR, h.getDesc());
if (!isMethodHandle) {
buf.append(')');
}
if (h.isInterface()) {
buf.append(" itf");
}
}
/**
* Appends a string representation of the given handle to {@link #stringBuilder}.
*
* @param handle a handle.
*/
protected void appendHandle(final Handle handle) {
int tag = handle.getTag();
stringBuilder.append("// handle kind 0x").append(Integer.toHexString(tag)).append(" : ");
boolean isMethodHandle = false;
switch (tag) {
case Opcodes.H_GETFIELD:
stringBuilder.append("GETFIELD");
break;
case Opcodes.H_GETSTATIC:
stringBuilder.append("GETSTATIC");
break;
case Opcodes.H_PUTFIELD:
stringBuilder.append("PUTFIELD");
break;
case Opcodes.H_PUTSTATIC:
stringBuilder.append("PUTSTATIC");
break;
case Opcodes.H_INVOKEINTERFACE:
stringBuilder.append("INVOKEINTERFACE");
isMethodHandle = true;
break;
case Opcodes.H_INVOKESPECIAL:
stringBuilder.append("INVOKESPECIAL");
isMethodHandle = true;
break;
case Opcodes.H_INVOKESTATIC:
stringBuilder.append("INVOKESTATIC");
isMethodHandle = true;
break;
case Opcodes.H_INVOKEVIRTUAL:
stringBuilder.append("INVOKEVIRTUAL");
isMethodHandle = true;
break;
case Opcodes.H_NEWINVOKESPECIAL:
stringBuilder.append("NEWINVOKESPECIAL");
isMethodHandle = true;
break;
default:
throw new IllegalArgumentException();
}
stringBuilder.append('\n');
stringBuilder.append(tab3);
appendDescriptor(INTERNAL_NAME, handle.getOwner());
stringBuilder.append('.');
stringBuilder.append(handle.getName());
if (!isMethodHandle) {
stringBuilder.append('(');
}
appendDescriptor(HANDLE_DESCRIPTOR, handle.getDesc());
if (!isMethodHandle) {
stringBuilder.append(')');
}
if (handle.isInterface()) {
stringBuilder.append(" itf");
}
}
/**
* Checks that the given value is a valid operand for the LDC instruction.
*
* @param value the value to be checked.
*/
private void checkLdcConstant(final Object value) {
if (value instanceof Type) {
int sort = ((Type) value).getSort();
if (sort != Type.OBJECT && sort != Type.ARRAY && sort != Type.METHOD) {
throw new IllegalArgumentException("Illegal LDC constant value");
}
if (sort != Type.METHOD && (version & 0xFFFF) < Opcodes.V1_5) {
throw new IllegalArgumentException("ldc of a constant class requires at least version 1.5");
}
if (sort == Type.METHOD && (version & 0xFFFF) < Opcodes.V1_7) {
throw new IllegalArgumentException("ldc of a method type requires at least version 1.7");
}
} else if (value instanceof Handle) {
if ((version & 0xFFFF) < Opcodes.V1_7) {
throw new IllegalArgumentException("ldc of a Handle requires at least version 1.7");
}
Handle handle = (Handle) value;
int tag = handle.getTag();
if (tag < Opcodes.H_GETFIELD || tag > Opcodes.H_INVOKEINTERFACE) {
throw new IllegalArgumentException("invalid handle tag " + tag);
}
checkInternalName(this.version, handle.getOwner(), "handle owner");
if (tag <= Opcodes.H_PUTSTATIC) {
checkDescriptor(this.version, handle.getDesc(), false);
} else {
checkMethodDescriptor(this.version, handle.getDesc());
}
String handleName = handle.getName();
if (!("<init>".equals(handleName) && tag == Opcodes.H_NEWINVOKESPECIAL)) {
checkMethodIdentifier(this.version, handleName, "handle name");
}
} else if (value instanceof ConstantDynamic) {
if ((version & 0xFFFF) < Opcodes.V11) {
throw new IllegalArgumentException("ldc of a ConstantDynamic requires at least version 11");
}
ConstantDynamic constantDynamic = (ConstantDynamic) value;
checkMethodIdentifier(this.version, constantDynamic.getName(), "constant dynamic name");
checkDescriptor(this.version, constantDynamic.getDescriptor(), false);
checkLdcConstant(constantDynamic.getBootstrapMethod());
int bootstrapMethodArgumentCount = constantDynamic.getBootstrapMethodArgumentCount();
for (int i = 0; i < bootstrapMethodArgumentCount; ++i) {
checkLdcConstant(constantDynamic.getBootstrapMethodArgument(i));
}
} else {
checkConstant(value);
}
}
/**
* Appends a string representation of the given handle to {@link #stringBuilder}.
*
* @param handle a handle.
*/
protected void appendHandle(final Handle handle) {
int tag = handle.getTag();
stringBuilder.append("// handle kind 0x").append(Integer.toHexString(tag)).append(" : ");
boolean isMethodHandle = false;
switch (tag) {
case Opcodes.H_GETFIELD:
stringBuilder.append("GETFIELD");
break;
case Opcodes.H_GETSTATIC:
stringBuilder.append("GETSTATIC");
break;
case Opcodes.H_PUTFIELD:
stringBuilder.append("PUTFIELD");
break;
case Opcodes.H_PUTSTATIC:
stringBuilder.append("PUTSTATIC");
break;
case Opcodes.H_INVOKEINTERFACE:
stringBuilder.append("INVOKEINTERFACE");
isMethodHandle = true;
break;
case Opcodes.H_INVOKESPECIAL:
stringBuilder.append("INVOKESPECIAL");
isMethodHandle = true;
break;
case Opcodes.H_INVOKESTATIC:
stringBuilder.append("INVOKESTATIC");
isMethodHandle = true;
break;
case Opcodes.H_INVOKEVIRTUAL:
stringBuilder.append("INVOKEVIRTUAL");
isMethodHandle = true;
break;
case Opcodes.H_NEWINVOKESPECIAL:
stringBuilder.append("NEWINVOKESPECIAL");
isMethodHandle = true;
break;
default:
throw new IllegalArgumentException();
}
stringBuilder.append('\n');
stringBuilder.append(tab3);
appendDescriptor(INTERNAL_NAME, handle.getOwner());
stringBuilder.append('.');
stringBuilder.append(handle.getName());
if (!isMethodHandle) {
stringBuilder.append('(');
}
appendDescriptor(HANDLE_DESCRIPTOR, handle.getDesc());
if (!isMethodHandle) {
stringBuilder.append(')');
}
if (handle.isInterface()) {
stringBuilder.append(" itf");
}
}
@Override
public void setOwner(String owner) {
boolean itf = this.handle.getTag() == Opcodes.H_INVOKEINTERFACE;
this.handle = new org.objectweb.asm.Handle(this.handle.getTag(), owner, this.handle.getName(), this.handle.getDesc(), itf);
}
@Override
public void setName(String name) {
boolean itf = this.handle.getTag() == Opcodes.H_INVOKEINTERFACE;
this.handle = new org.objectweb.asm.Handle(this.handle.getTag(), this.handle.getOwner(), name, this.handle.getDesc(), itf);
}
@Override
public void setDesc(String desc) {
boolean itf = this.handle.getTag() == Opcodes.H_INVOKEINTERFACE;
this.handle = new org.objectweb.asm.Handle(this.handle.getTag(), this.handle.getOwner(), this.handle.getName(), desc, itf);
}