下面列出了org.objectweb.asm.Opcodes# INVOKEINTERFACE 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
@Override
public void transform(ClassNode classNode, String name) {
for (MethodNode methodNode : classNode.methods) {
if (TransformerMethod.printChatMessageWithOptionalDeletion.matches(methodNode)) {
// Objective:
// Find: chatComponent.getUnformattedText();
// Replace With: GuiNewChatHook.getUnformattedText(chatComponent);
Iterator<AbstractInsnNode> iterator = methodNode.instructions.iterator();
while (iterator.hasNext()) {
AbstractInsnNode abstractNode = iterator.next();
if (abstractNode instanceof MethodInsnNode && abstractNode.getOpcode() == Opcodes.INVOKEINTERFACE) {
MethodInsnNode methodInsnNode = (MethodInsnNode) abstractNode;
if (methodInsnNode.owner.equals(TransformerClass.IChatComponent.getNameRaw()) && TransformerMethod.getUnformattedText.matches(methodInsnNode)) {
methodNode.instructions.insertBefore(abstractNode, new MethodInsnNode(Opcodes.INVOKESTATIC, "codes/biscuit/skyblockaddons/asm/hooks/GuiNewChatHook",
"getUnformattedText", "("+TransformerClass.IChatComponent.getName()+")Ljava/lang/String;", false)); // GuiNewChatHook.getUnformattedText(chatComponent);
iterator.remove(); // Remove the old line.
break;
}
}
}
}
}
}
private void doVisitMethodInsn(
final int opcode,
final String owner,
final String name,
final String descriptor,
final boolean isInterface) {
switch (opcode) {
case Opcodes.INVOKESPECIAL:
invokespecial(owner, name, descriptor, isInterface);
break;
case Opcodes.INVOKEVIRTUAL:
invokevirtual(owner, name, descriptor, isInterface);
break;
case Opcodes.INVOKESTATIC:
invokestatic(owner, name, descriptor, isInterface);
break;
case Opcodes.INVOKEINTERFACE:
invokeinterface(owner, name, descriptor);
break;
default:
throw new IllegalArgumentException();
}
}
static String normalizeInterfaceMethodName(String name, boolean isLambda, int opcode) {
if (isLambda) {
// Rename lambda method to reflect the new owner. Not doing so confuses LambdaDesugaring
// if it's run over this class again. LambdaDesugaring has already renamed the method from
// its original name to include the interface name at this point.
return name + DependencyCollector.INTERFACE_COMPANION_SUFFIX;
}
switch (opcode) {
case Opcodes.INVOKESPECIAL:
// Rename static methods holding default method implementations since their descriptor
// differs from the original method (due to explicit receiver parameter). This avoids
// possible clashes with static interface methods or generated stubs for default methods
// that could otherwise have the same name and descriptor by coincidence.
return name + DEFAULT_COMPANION_METHOD_SUFFIX;
case Opcodes.INVOKESTATIC: // moved but with same name
return name + "$$STATIC$$"; // TODO(b/117453106): Stop renaming static interface methods
case Opcodes.INVOKEINTERFACE: // not moved
case Opcodes.INVOKEVIRTUAL: // tolerate being called for non-interface methods
return name;
default:
throw new IllegalArgumentException("Unexpected opcode calling " + name + ": " + opcode);
}
}
private void doVisitMethodInsn(
final int opcode,
final String owner,
final String name,
final String descriptor,
final boolean isInterface) {
switch (opcode) {
case Opcodes.INVOKESPECIAL:
invokespecial(owner, name, descriptor, isInterface);
break;
case Opcodes.INVOKEVIRTUAL:
invokevirtual(owner, name, descriptor, isInterface);
break;
case Opcodes.INVOKESTATIC:
invokestatic(owner, name, descriptor, isInterface);
break;
case Opcodes.INVOKEINTERFACE:
invokeinterface(owner, name, descriptor);
break;
default:
throw new IllegalArgumentException();
}
}
private void doVisitMethodInsn(
final int opcode,
final String owner,
final String name,
final String descriptor,
final boolean isInterface) {
checkVisitCodeCalled();
checkVisitMaxsNotCalled();
checkOpcodeMethod(opcode, Method.VISIT_METHOD_INSN);
if (opcode != Opcodes.INVOKESPECIAL || !"<init>".equals(name)) {
checkMethodIdentifier(version, name, "name");
}
checkInternalName(version, owner, "owner");
checkMethodDescriptor(version, descriptor);
if (opcode == Opcodes.INVOKEVIRTUAL && isInterface) {
throw new IllegalArgumentException("INVOKEVIRTUAL can't be used with interfaces");
}
if (opcode == Opcodes.INVOKEINTERFACE && !isInterface) {
throw new IllegalArgumentException("INVOKEINTERFACE can't be used with classes");
}
if (opcode == Opcodes.INVOKESPECIAL && isInterface && (version & 0xFFFF) < Opcodes.V1_8) {
throw new IllegalArgumentException(
"INVOKESPECIAL can't be used with interfaces prior to Java 8");
}
// Calling super.visitMethodInsn requires to call the correct version depending on this.api
// (otherwise infinite loops can occur). To simplify and to make it easier to automatically
// remove the backward compatibility code, we inline the code of the overridden method here.
if (mv != null) {
mv.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
}
++insnCount;
}
public static boolean isCallOnContextAware(final AbstractInsnNode insn)
{
Objects.requireNonNull(insn, "insn");
if (insn.getOpcode() != Opcodes.INVOKEVIRTUAL
&& insn.getOpcode() != Opcodes.INVOKEINTERFACE)
return false;
final MethodInsnNode mi = (MethodInsnNode) insn;
return isAssignableTo(mi.owner, ContextAware.class);
}
@Override
public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) {
if (opcode == Opcodes.INVOKESPECIAL && "<init>".equals(name)) {
int argumentSize = (Type.getArgumentsAndReturnSizes(desc) >> 2);
InferredType receiverType = getTypeOfOperandFromTop(argumentSize - 1);
if (receiverType.isUninitialized()) {
InferredType realType = InferredType.create('L' + owner + ';');
replaceUninitializedTypeInStack(receiverType, realType);
}
}
switch (opcode) {
case Opcodes.INVOKESPECIAL:
case Opcodes.INVOKEVIRTUAL:
case Opcodes.INVOKESTATIC:
case Opcodes.INVOKEINTERFACE:
popDescriptor(desc);
if (opcode != Opcodes.INVOKESTATIC) {
pop(); // Pop receiver.
}
pushDescriptor(desc);
break;
default:
throw new RuntimeException(
String.format(
"Unhandled opcode %s, owner=%s, name=%s, desc=%s, itf=%s",
opcode, owner, name, desc, itf));
}
super.visitMethodInsn(opcode, owner, name, desc, itf);
}
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.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;
}
public static void start(BytecodeGennerator bv, Type toAdd) {
String vo = toAdd.getBytecodeType();
if(!vo.equals("Ljava/lang/String;"))
{
if(toAdd.hasArrayLevels())
{
append(bv, toAdd);
bv.bcoutputter.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/String", "valueOf", "(Ljava/lang/String;)Ljava/lang/String;");
}
else if(toAdd instanceof PrimativeType)
{
bv.bcoutputter.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/String", "valueOf", "("+vo+")Ljava/lang/String;");
}
else if(toAdd instanceof NamedType && TypeCheckUtils.isTypedActor(bv.errorRaisableSupressionFromSatc, (NamedType)toAdd)){
String callOn = toAdd.getCheckCastType();
int opcode = Opcodes.INVOKEVIRTUAL;
if(callOn.equals("com/concurnas/lang/Actor") || callOn.equals("com/concurnas/lang/TypedActor")){
callOn = "x" + ((NamedType)toAdd).getGenTypes().get(0).getCheckCastType() + "$$ActorIterface";
opcode=Opcodes.INVOKEINTERFACE;
}
bv.bcoutputter.visitMethodInsn(opcode, callOn, "toString$ActorCall", "()Ljava/lang/String;");
}
else
{
//bv.mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/String", "valueOf", "(Ljava/lang/Object;)Ljava/lang/String;");
//below is better
bv.bcoutputter.visitMethodInsn(Opcodes.INVOKESTATIC, "com/concurnas/bootstrap/lang/Stringifier", "stringify", "(Ljava/lang/Object;)Ljava/lang/String;");
}
}
bv.bcoutputter.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/StringBuilder", "<init>", "(Ljava/lang/String;)V");
}
private static int resolveASMOpcode(CallType t) {
switch (t) {
case SPECIAL:
return Opcodes.INVOKESPECIAL;
case VIRTUAL:
return Opcodes.INVOKEVIRTUAL;
case INTERFACE:
return Opcodes.INVOKEINTERFACE;
default:
throw new IllegalArgumentException(t.toString());
}
}
public static CallType resolveCallType(int asmOpcode) {
switch (asmOpcode) {
case Opcodes.INVOKEVIRTUAL:
return CallType.VIRTUAL;
case Opcodes.INVOKESPECIAL:
return CallType.SPECIAL;
case Opcodes.INVOKEINTERFACE:
return CallType.INTERFACE;
default:
throw new IllegalArgumentException(String.valueOf(asmOpcode));
}
}
public MethodAssignableValue(TypeWidget type, Class ownerClass, String name, BytecodeExpression target) {
this.type = type;
this.target = target;
this.ownerName = Type.getInternalName(ownerClass);
this.name = name;
this.op = ownerClass.isInterface() ? Opcodes.INVOKEINTERFACE : Opcodes.INVOKEVIRTUAL;
this.desc = Type.getMethodDescriptor(type.getJVMType());
}
@Override
public void addDependencies(List<String> dependencyList) {
String t = owner.replace('.', '_').replace('/', '_').replace('$', '_');
t = unarray(t);
if(t != null && !dependencyList.contains(t)) {
dependencyList.add(t);
}
StringBuilder bld = new StringBuilder();
if(opcode != Opcodes.INVOKEINTERFACE && opcode != Opcodes.INVOKEVIRTUAL) {
return;
}
bld.append(owner.replace('/', '_').replace('$', '_'));
bld.append("_");
if(name.equals("<init>")) {
bld.append("__INIT__");
} else {
if(name.equals("<clinit>")) {
bld.append("__CLINIT__");
} else {
bld.append(name);
}
}
bld.append("__");
ArrayList<String> args = new ArrayList<String>();
String returnVal = BytecodeMethod.appendMethodSignatureSuffixFromDesc(desc, bld, args);
String str = bld.toString();
BytecodeMethod.addVirtualMethodsInvoked(str);
}
public void visitMethodInsn(
final int opcode,
final String owner,
final String name,
final String desc)
{
boolean itf = opcode == Opcodes.INVOKEINTERFACE;
cp.newMethod(owner, name, desc, itf);
mv.visitMethodInsn(opcode, owner, name, desc);
}
/**
* Returns true if the mirror contains a method that mirrors
* <code>methodName</code>. The mirror method should be static, have the
* same name, and have the exact same arguments excepting an argument of
* type
*/
public boolean hasMethod(final String owner, final String methodName, final String methodDescriptor, final int opcode) {
Type[] types = Type.getArgumentTypes(methodDescriptor);
if (opcode == Opcodes.INVOKEVIRTUAL || opcode == Opcodes.INVOKEINTERFACE) {
Type[] newTypes = new Type[types.length + 1];
newTypes[0] = Type.getType("L" + owner + ";");
System.arraycopy(types, 0, newTypes, 1, types.length);
types = newTypes;
}
outer_loop:
for (Method m : class_.getDeclaredMethods()) {
final Type[] methodTypes = Type.getArgumentTypes(m);
if (!m.getName().equals(methodName)
|| methodTypes.length != types.length) {
continue;
}
for (int i = 0; i < types.length; ++i) {
if (!types[i].equals(methodTypes[i])) {
continue outer_loop;
}
}
return true;
}
return false;
}
@Override
public void addDependencies(List<String> dependencyList) {
String t = owner.replace('.', '_').replace('/', '_').replace('$', '_');
t = unarray(t);
if(t != null && !dependencyList.contains(t)) {
dependencyList.add(t);
}
StringBuilder bld = new StringBuilder();
if(origOpcode != Opcodes.INVOKEINTERFACE && origOpcode != Opcodes.INVOKEVIRTUAL) {
return;
}
bld.append(owner.replace('/', '_').replace('$', '_'));
bld.append("_");
if(name.equals("<init>")) {
bld.append("__INIT__");
} else {
if(name.equals("<clinit>")) {
bld.append("__CLINIT__");
} else {
bld.append(name);
}
}
bld.append("__");
ArrayList<String> args = new ArrayList<String>();
String returnVal = BytecodeMethod.appendMethodSignatureSuffixFromDesc(desc, bld, args);
String str = bld.toString();
BytecodeMethod.addVirtualMethodsInvoked(str);
}
public int getOpcode(InstanceMethodInvoke.Type type) {
switch (type) {
case INTERFACE:
return Opcodes.INVOKEINTERFACE;
case SPECIAL:
return Opcodes.INVOKESPECIAL;
case VIRTUAL:
default:
return Opcodes.INVOKEVIRTUAL;
}
}
public static void append(BytecodeGennerator bv, Type tryingToPassType, boolean supressSB){
//supressSB is a hack lol
boolean callToString = false;
if(!tryingToPassType.hasArrayLevels() && tryingToPassType instanceof NamedType){
NamedType asNamed = (NamedType)tryingToPassType;
if(!TypeCheckUtils.objectNT.equals(asNamed)){
if(null == TypeCheckUtils.checkSubType(bv.errorRaisableSupressionFromSatc, ScopeAndTypeChecker.map_object, asNamed, 42, 42, 42, 42) &&
null == TypeCheckUtils.checkSubType(bv.errorRaisableSupressionFromSatc, ScopeAndTypeChecker.list_object, asNamed, 42, 42, 42, 42) &&
null == TypeCheckUtils.checkSubType(bv.errorRaisableSupressionFromSatc, ScopeAndTypeChecker.set_object, asNamed, 42, 42, 42, 42))
{//if not map and not list
callToString=true;
}
}
}
String bcType;
if(tryingToPassType instanceof PrimativeType && tryingToPassType.hasArrayLevels()){
bcType="Ljava/lang/Object;";
}
else{
bcType= (tryingToPassType instanceof GenericType || tryingToPassType instanceof NamedType || tryingToPassType instanceof FuncType || (tryingToPassType instanceof PrimativeType)&& ((PrimativeType)tryingToPassType).type == PrimativeTypeEnum.LAMBDA )?"Ljava/lang/Object;":tryingToPassType.getBytecodeType();
}
if(bcType.equals("S")){
bcType = "I";//short cast to int
}
if(callToString || TypeCheckUtils.isNonArrayStringOrPrimative(tryingToPassType)){//JPT: imperfectly unit tested, anything which has no functional impact is here... :(
//primative with no array or a String - no need to call stringifier
if(tryingToPassType instanceof NamedType && TypeCheckUtils.isTypedActor(bv.errorRaisableSupressionFromSatc, (NamedType)tryingToPassType)){
String callOn = tryingToPassType.getCheckCastType();
int opcode = Opcodes.INVOKEVIRTUAL;
if(callOn.equals("com/concurnas/lang/Actor") || callOn.equals("com/concurnas/lang/TypedActor")){
callOn = "x" + ((NamedType)tryingToPassType).getGenTypes().get(0).getCheckCastType() + "$$ActorIterface";
opcode=Opcodes.INVOKEINTERFACE;
}
bv.bcoutputter.visitMethodInsn(opcode, callOn, "toString$ActorCall", "()Ljava/lang/String;");
}
if(!supressSB){
doAppend(bv, bcType);
}
}
else{//uh oh, something tricky, call stringifier
bv.bcoutputter.visitMethodInsn(Opcodes.INVOKESTATIC, "com/concurnas/bootstrap/lang/Stringifier", "stringify", String.format("(%s)Ljava/lang/String;",bcType)) ;
bcType = "Ljava/lang/String;";
if(!supressSB){
doAppend(bv, bcType);
}
}
}
@Override
public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) {
// Assume that any static interface methods on the classpath are moved
if ((itf || owner.equals(interfaceName)) && !bootclasspath.isKnown(owner)) {
if (name.startsWith("lambda$")) {
// Redirect lambda invocations to completely remove all lambda methods from interfaces.
checkArgument(
!owner.endsWith(DependencyCollector.INTERFACE_COMPANION_SUFFIX),
"shouldn't consider %s an interface",
owner);
if (opcode == Opcodes.INVOKEINTERFACE) {
opcode = Opcodes.INVOKESTATIC;
desc = companionDefaultMethodDescriptor(owner, desc);
} else {
checkArgument(
opcode == Opcodes.INVOKESTATIC,
"Unexpected opcode %s to invoke %s.%s",
opcode,
owner,
name);
}
// Reflect that InterfaceDesugaring moves and renames the lambda body method
name = normalizeInterfaceMethodName(name, /*isLambda=*/ true, opcode);
owner += DependencyCollector.INTERFACE_COMPANION_SUFFIX;
itf = false;
// Record dependency on companion class
depsCollector.assumeCompanionClass(declaringClass, owner);
String expectedLambdaMethodName = LambdaDesugaring.uniqueInPackage(owner, name);
checkState(
name.equals(expectedLambdaMethodName),
"Unexpected lambda body method name for %s: real=%s, expected=%s",
owner,
name,
expectedLambdaMethodName);
} else if ((opcode == Opcodes.INVOKESTATIC || opcode == Opcodes.INVOKESPECIAL)) {
checkArgument(
!owner.endsWith(DependencyCollector.INTERFACE_COMPANION_SUFFIX),
"shouldn't consider %s an interface",
owner);
if (opcode == Opcodes.INVOKESPECIAL) {
// Turn Interface.super.m() into DefiningInterface$$CC.m(receiver). Note that owner
// always refers to the current type's immediate super-interface, but the default method
// may be inherited by that interface, so we have to figure out where the method is
// defined and invoke it in the corresponding companion class (b/73355452). Note that
// we're always dealing with interfaces here, and all interface methods are public,
// so using Class.getMethods should suffice to find inherited methods. Also note this
// can only be a default method invocation, no abstract method invocation.
owner =
findDefaultMethod(owner, name, desc)
.getDeclaringClass()
.getName()
.replace('.', '/');
desc = companionDefaultMethodDescriptor(owner, desc);
}
name = normalizeInterfaceMethodName(name, /*isLambda=*/ false, opcode);
owner += DependencyCollector.INTERFACE_COMPANION_SUFFIX;
opcode = Opcodes.INVOKESTATIC;
itf = false;
// Record dependency on companion class
depsCollector.assumeCompanionClass(declaringClass, owner);
} // else non-lambda INVOKEINTERFACE, which needs no rewriting
}
super.visitMethodInsn(opcode, owner, name, desc, itf);
}
/**
* Method instruction. See
* {@link org.objectweb.asm.MethodVisitor#visitMethodInsn}.
*
* @param opcode
* the opcode of the type instruction to be visited. This opcode is
* either INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC or
* INVOKEINTERFACE.
* @param owner
* the internal name of the method's owner class (see
* {@link org.objectweb.asm.Type#getInternalName() getInternalName}).
* @param name
* the method's name.
* @param desc
* the method's descriptor (see {@link org.objectweb.asm.Type Type}).
* @param itf
* if the method's owner class is an interface.
*/
public void visitMethodInsn(final int opcode, final String owner, final String name, final String desc, final boolean itf) {
if (api < Opcodes.ASM5) {
if (itf != (opcode == Opcodes.INVOKEINTERFACE)) {
throw new IllegalArgumentException("INVOKESPECIAL/STATIC on interfaces require ASM 5");
}
visitMethodInsn(opcode, owner, name, desc);
return;
}
throw new RuntimeException("Must be overriden");
}