下面列出了org.objectweb.asm.Opcodes# H_INVOKEVIRTUAL 实例代码,或者点击链接到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);
}
}
@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 + ".");
}
}
/**
* Mutates a handle within an invoke virtual.
*/
private Handle mutateHandle(Handle handle) {
int opcode = handle.getTag();
String owner = handle.getOwner();
String name = handle.getName();
String descriptor = handle.getDesc();
if (owner.equals(expectedOwner) && opcode == Opcodes.H_INVOKEVIRTUAL) {
if (REPLACEMENTS.containsKey(name)) {
Replacement replacement = REPLACEMENTS.get(name);
if (replacement.descriptor.equals(descriptor)) {
MutationIdentifier id = context.registerMutation(factory, replacement.toString());
if (context.shouldMutate(id)) {
return new Handle(
opcode,
owner,
replacement.destinationName,
descriptor,
handle.isInterface());
}
}
}
}
return 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 static CompiledLambda defineLambdaMethod(
RowExpressionCompiler innerExpressionCompiler,
ClassDefinition classDefinition,
String methodName,
List<Parameter> inputParameters,
LambdaDefinitionExpression lambda)
{
checkCondition(inputParameters.size() <= 254, NOT_SUPPORTED, "Too many arguments for lambda expression");
Class<?> returnType = Primitives.wrap(lambda.getBody().getType().getJavaType());
MethodDefinition method = classDefinition.declareMethod(a(PUBLIC), methodName, type(returnType), inputParameters);
Scope scope = method.getScope();
Variable wasNull = scope.declareVariable(boolean.class, "wasNull");
BytecodeNode compiledBody = innerExpressionCompiler.compile(lambda.getBody(), scope);
method.getBody()
.putVariable(wasNull, false)
.append(compiledBody)
.append(boxPrimitiveIfNecessary(scope, returnType))
.ret(returnType);
Handle lambdaAsmHandle = new Handle(
Opcodes.H_INVOKEVIRTUAL,
method.getThis().getType().getClassName(),
method.getName(),
method.getMethodDescriptor(),
false);
return new CompiledLambda(
lambdaAsmHandle,
method.getReturnType(),
method.getParameterTypes());
}
@Override
public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) {
if (!name.equals(lambdaInfo.methodReference().getName())
|| !desc.equals(lambdaInfo.methodReference().getDesc())) {
super.visitMethodInsn(opcode, owner, name, desc, itf);
return;
}
boolean useBridgeMethod = false;
if (owner.equals(lambdaInfo.methodReference().getOwner())) {
if (lambdaInfo.methodReference().getTag() == Opcodes.H_NEWINVOKESPECIAL
&& lambdaInfo.bridgeMethod().getTag() != Opcodes.H_NEWINVOKESPECIAL) {
// We're changing a constructor call to a factory method call, so we unfortunately need
// to go find the NEW/DUP pair preceding the constructor call and remove it
removeLastAllocation();
}
useBridgeMethod = true;
} else if ((lambdaInfo.methodReference().getTag() == Opcodes.H_INVOKEVIRTUAL
|| lambdaInfo.methodReference().getTag() == Opcodes.H_INVOKESPECIAL)
&& hasAssignableRelation(owner, lambdaInfo.methodReference().getOwner())) {
// For rewriting instance methods calls, we consider the class hierarchy.
// This is for JDK 9: (b/62218600).
// TODO(cnsun): revisit this to make sure Desugar is fully compatible with this change
// in JDK: http://hg.openjdk.java.net/jdk9/dev/jdk/rev/a3b3c7b6464d
useBridgeMethod = true;
}
if (useBridgeMethod) {
super.visitMethodInsn(
LambdaDesugaring.invokeOpcode(lambdaInfo.bridgeMethod()),
lambdaInfo.bridgeMethod().getOwner(),
lambdaInfo.bridgeMethod().getName(),
lambdaInfo.bridgeMethod().getDesc(),
lambdaInfo.bridgeMethod().isInterface());
} else {
super.visitMethodInsn(opcode, owner, name, desc, 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);
}
}
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);
}
}
/**
* 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");
}
}
/**
* 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 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");
}
}