下面列出了org.objectweb.asm.Opcodes# H_INVOKESTATIC 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
@Override
public void visitInvokeDynamicInsn(
final String name,
final String descriptor,
final Handle bootstrapMethodHandle,
final Object... bootstrapMethodArguments) {
checkVisitCodeCalled();
checkVisitMaxsNotCalled();
checkMethodIdentifier(version, name, "name");
checkMethodDescriptor(version, descriptor);
if (bootstrapMethodHandle.getTag() != Opcodes.H_INVOKESTATIC
&& bootstrapMethodHandle.getTag() != Opcodes.H_NEWINVOKESPECIAL) {
throw new IllegalArgumentException("invalid handle tag " + bootstrapMethodHandle.getTag());
}
for (Object bootstrapMethodArgument : bootstrapMethodArguments) {
checkLdcConstant(bootstrapMethodArgument);
}
super.visitInvokeDynamicInsn(name, descriptor, bootstrapMethodHandle, bootstrapMethodArguments);
++insnCount;
}
@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);
}
}
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());
}
}
@Override
public void visitInvokeDynamicInsn(
final String name,
final String descriptor,
final Handle bootstrapMethodHandle,
final Object... bootstrapMethodArguments) {
checkVisitCodeCalled();
checkVisitMaxsNotCalled();
checkMethodIdentifier(version, name, "name");
checkMethodDescriptor(version, descriptor);
if (bootstrapMethodHandle.getTag() != Opcodes.H_INVOKESTATIC
&& bootstrapMethodHandle.getTag() != Opcodes.H_NEWINVOKESPECIAL) {
throw new IllegalArgumentException("invalid handle tag " + bootstrapMethodHandle.getTag());
}
for (Object bootstrapMethodArgument : bootstrapMethodArguments) {
checkLdcConstant(bootstrapMethodArgument);
}
super.visitInvokeDynamicInsn(name, descriptor, bootstrapMethodHandle, bootstrapMethodArguments);
++insnCount;
}
@Override
public void visitInvokeDynamicInsn(
final String name,
final String descriptor,
final Handle bootstrapMethodHandle,
final Object... bootstrapMethodArguments) {
checkVisitCodeCalled();
checkVisitMaxsNotCalled();
checkMethodIdentifier(version, name, "name");
checkMethodDescriptor(version, descriptor);
if (bootstrapMethodHandle.getTag() != Opcodes.H_INVOKESTATIC
&& bootstrapMethodHandle.getTag() != Opcodes.H_NEWINVOKESPECIAL) {
throw new IllegalArgumentException("invalid handle tag " + bootstrapMethodHandle.getTag());
}
for (Object bootstrapMethodArgument : bootstrapMethodArguments) {
checkLdcConstant(bootstrapMethodArgument);
}
super.visitInvokeDynamicInsn(name, descriptor, bootstrapMethodHandle, bootstrapMethodArguments);
++insnCount;
}
@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 + ".");
}
}
/**
* Returns a {@code static}, {@code final} field constant.
*
* @param fieldDescription The field to represent a value of.
* @return A dynamically resolved field value constant.
*/
public static Dynamic ofField(FieldDescription.InDefinedShape fieldDescription) {
if (!fieldDescription.isStatic() || !fieldDescription.isFinal()) {
throw new IllegalArgumentException("Field must be static and final: " + fieldDescription);
}
boolean selfDeclared = fieldDescription.getType().isPrimitive()
? fieldDescription.getType().asErasure().asBoxed().equals(fieldDescription.getType().asErasure())
: fieldDescription.getDeclaringType().equals(fieldDescription.getType().asErasure());
return new Dynamic(new ConstantDynamic(fieldDescription.getInternalName(),
fieldDescription.getDescriptor(),
new Handle(Opcodes.H_INVOKESTATIC,
CONSTANT_BOOTSTRAPS,
"getStaticFinal",
selfDeclared
? "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/Object;"
: "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Class;Ljava/lang/Class;)Ljava/lang/Object;",
false), selfDeclared
? new Object[0]
: new Object[]{Type.getType(fieldDescription.getDeclaringType().getDescriptor())}), fieldDescription.getType().asErasure());
}
/**
* 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);
}
}
/**
* Returns a {@link Class} constant for a primitive type.
*
* @param typeDescription The primitive type to represent.
* @return A dynamically resolved primitive type constant.
*/
public static JavaConstant ofPrimitiveType(TypeDescription typeDescription) {
if (!typeDescription.isPrimitive()) {
throw new IllegalArgumentException("Not a primitive type: " + typeDescription);
}
return new Dynamic(new ConstantDynamic(typeDescription.getDescriptor(),
TypeDescription.CLASS.getDescriptor(),
new Handle(Opcodes.H_INVOKESTATIC,
CONSTANT_BOOTSTRAPS,
"primitiveClass",
"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/Class;",
false)), TypeDescription.CLASS);
}
@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, "", "", "");
}
@Override
public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, Object... bsmArgs) {
checkStartCode();
checkEndCode();
checkMethodIdentifier(version, name, "name");
checkMethodDesc(desc);
if (bsm.getTag() != Opcodes.H_INVOKESTATIC && bsm.getTag() != Opcodes.H_NEWINVOKESPECIAL) {
throw new IllegalArgumentException("invalid handle tag " + bsm.getTag());
}
for (int i = 0; i < bsmArgs.length; i++) {
checkLDCConstant(bsmArgs[i]);
}
super.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
++insnCount;
}
private static boolean isJavaLambdaMetafactory(Handle bsm) {
return bsm.getTag() == Opcodes.H_INVOKESTATIC
&& bsm.getOwner().equals("java/lang/invoke/LambdaMetafactory")
&& (bsm.getName().equals("metafactory")
&& bsm.getDesc().equals("(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;")
|| bsm.getName().equals("altMetafactory")
&& bsm.getDesc().equals("(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;"))
&& !bsm.isInterface();
}
/**
* Resolves a var handle constant for a field.
*
* @param fieldDescription The field to represent a var handle for.
* @return A dynamic constant that represents the created var handle constant.
*/
public static JavaConstant ofVarHandle(FieldDescription.InDefinedShape fieldDescription) {
return new Dynamic(new ConstantDynamic(fieldDescription.getInternalName(),
JavaType.VAR_HANDLE.getTypeStub().getDescriptor(),
new Handle(Opcodes.H_INVOKESTATIC,
CONSTANT_BOOTSTRAPS,
fieldDescription.isStatic()
? "staticFieldVarHandle"
: "fieldVarHandle",
"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/Class;)Ljava/lang/invoke/VarHandle;",
false),
Type.getType(fieldDescription.getDeclaringType().getDescriptor()),
Type.getType(fieldDescription.getType().asErasure().getDescriptor())), JavaType.VAR_HANDLE.getTypeStub());
}
/**
* 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");
}
}
/**
* 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");
}
}
public JDynamicInvokeExpr(SootMethodRef bootstrapMethodRef, List<? extends Value> bootstrapArgs, SootMethodRef methodRef, List<? extends Value> methodArgs){
/*
* Here the static-handle is chosen as default value, because this works for Java.
*/
this(bootstrapMethodRef, bootstrapArgs, methodRef, Opcodes.H_INVOKESTATIC, methodArgs);
}
/**
* 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");
}
}
/**
* Represents a constant that is resolved by invoking a {@code static} factory method or a constructor.
*
* @param methodDescription The method or constructor to invoke to create the represented constant value.
* @param constants The constant values passed to the bootstrap method. Values can be represented either
* as {@link TypeDescription}, as {@link JavaConstant}, as {@link String} or a primitive
* {@code int}, {@code long}, {@code float} or {@code double} represented as wrapper type.
* @return A dynamic constant that is resolved by the supplied factory method or constructor.
*/
public static Dynamic ofInvocation(MethodDescription.InDefinedShape methodDescription, List<?> constants) {
if (!methodDescription.isConstructor() && methodDescription.getReturnType().represents(void.class)) {
throw new IllegalArgumentException("Bootstrap method is no constructor or non-void static factory: " + methodDescription);
} else if (methodDescription.getParameters().size() + (methodDescription.isStatic() || methodDescription.isConstructor() ? 0 : 1) != constants.size()) {
throw new IllegalArgumentException("Cannot assign " + constants + " to " + methodDescription);
}
List<Object> arguments = new ArrayList<Object>(constants.size());
arguments.add(new Handle(methodDescription.isConstructor() ? Opcodes.H_NEWINVOKESPECIAL : Opcodes.H_INVOKESTATIC,
methodDescription.getDeclaringType().getInternalName(),
methodDescription.getInternalName(),
methodDescription.getDescriptor(),
false));
Iterator<TypeDescription> iterator = (methodDescription.isStatic() || methodDescription.isConstructor()
? methodDescription.getParameters().asTypeList().asErasures()
: CompoundList.of(methodDescription.getDeclaringType(), methodDescription.getParameters().asTypeList().asErasures())).iterator();
for (Object constant : constants) {
TypeDescription typeDescription;
if (constant instanceof JavaConstant) {
arguments.add(((JavaConstant) constant).asConstantPoolValue());
typeDescription = ((JavaConstant) constant).getType();
} else if (constant instanceof TypeDescription) {
arguments.add(Type.getType(((TypeDescription) constant).getDescriptor()));
typeDescription = TypeDescription.CLASS;
} else {
arguments.add(constant);
typeDescription = TypeDescription.ForLoadedType.of(constant.getClass()).asUnboxed();
if (JavaType.METHOD_TYPE.isInstance(constant) || JavaType.METHOD_HANDLE.isInstance(constant)) {
throw new IllegalArgumentException("Must be represented as a JavaConstant instance: " + constant);
} else if (constant instanceof Class<?>) {
throw new IllegalArgumentException("Must be represented as a TypeDescription instance: " + constant);
} else if (!typeDescription.isCompileTimeConstant()) {
throw new IllegalArgumentException("Not a compile-time constant: " + constant);
}
}
if (!typeDescription.isAssignableTo(iterator.next())) {
throw new IllegalArgumentException("Cannot assign " + constants + " to " + methodDescription);
}
}
return new Dynamic(new ConstantDynamic("invoke",
(methodDescription.isConstructor()
? methodDescription.getDeclaringType()
: methodDescription.getReturnType().asErasure()).getDescriptor(),
new Handle(Opcodes.H_INVOKESTATIC,
CONSTANT_BOOTSTRAPS,
"invoke",
"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Class;Ljava/lang/invoke/MethodHandle;[Ljava/lang/Object;)Ljava/lang/Object;",
false),
arguments.toArray()), methodDescription.isConstructor() ? methodDescription.getDeclaringType() : methodDescription.getReturnType().asErasure());
}