List of usage examples for org.objectweb.asm Opcodes INVOKESTATIC
int INVOKESTATIC
To view the source code for org.objectweb.asm Opcodes INVOKESTATIC.
Click Source Link
From source file:com.github.malamut2.low.AllocationMethodAdapter.java
License:Apache License
private void invokeRecordAllocation(String typeName) { Matcher matcher = namePattern.matcher(typeName); if (matcher.find()) { typeName = matcher.group(1);/* www .j a v a 2s .c o m*/ } // stack: ... count newobj super.visitInsn(Opcodes.DUP_X1); // -> stack: ... newobj count newobj super.visitLdcInsn(typeName); // -> stack: ... newobj count newobj typename super.visitInsn(Opcodes.SWAP); // -> stack: ... newobj count typename newobj super.visitMethodInsn(Opcodes.INVOKESTATIC, recorderClass, recorderMethod, RECORDER_SIGNATURE, false); // -> stack: ... newobj }
From source file:com.github.megatronking.stringfog.plugin.StringFogClassVisitor.java
License:Apache License
@Override public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions); if (mv != null && !mIgnoreClass) { if ("<clinit>".equals(name)) { isClInitExists = true;/*ww w . j a va 2s .c om*/ // If clinit exists meaning the static fields (not final) would have be inited here. mv = new MethodVisitor(Opcodes.ASM5, mv) { private String lastStashCst; @Override public void visitCode() { super.visitCode(); // Here init static final fields. for (ClassStringField field : mStaticFinalFields) { if (!canEncrypted(field.value)) { continue; } String originValue = field.value; String encryptValue = mStringFogImpl.encrypt(originValue, mKey); mMappingPrinter.output(getJavaClassName(), originValue, encryptValue); super.visitLdcInsn(encryptValue); super.visitMethodInsn(Opcodes.INVOKESTATIC, mFogClassName, "decrypt", "(Ljava/lang/String;)Ljava/lang/String;", false); super.visitFieldInsn(Opcodes.PUTSTATIC, mClassName, field.name, ClassStringField.STRING_DESC); } } @Override public void visitLdcInsn(Object cst) { // Here init static or static final fields, but we must check field name int 'visitFieldInsn' if (cst != null && cst instanceof String && canEncrypted((String) cst)) { lastStashCst = (String) cst; String originValue = lastStashCst; String encryptValue = mStringFogImpl.encrypt(originValue, mKey); mMappingPrinter.output(getJavaClassName(), originValue, encryptValue); super.visitLdcInsn(encryptValue); super.visitMethodInsn(Opcodes.INVOKESTATIC, mFogClassName, "decrypt", "(Ljava/lang/String;)Ljava/lang/String;", false); } else { lastStashCst = null; super.visitLdcInsn(cst); } } @Override public void visitFieldInsn(int opcode, String owner, String name, String desc) { if (mClassName.equals(owner) && lastStashCst != null) { boolean isContain = false; for (ClassStringField field : mStaticFields) { if (field.name.equals(name)) { isContain = true; break; } } if (!isContain) { for (ClassStringField field : mStaticFinalFields) { if (field.name.equals(name) && field.value == null) { field.value = lastStashCst; break; } } } } lastStashCst = null; super.visitFieldInsn(opcode, owner, name, desc); } }; } else if ("<init>".equals(name)) { // Here init final(not static) and normal fields mv = new MethodVisitor(Opcodes.ASM5, mv) { @Override public void visitLdcInsn(Object cst) { // We don't care about whether the field is final or normal if (cst != null && cst instanceof String && canEncrypted((String) cst)) { String originValue = (String) cst; String encryptValue = mStringFogImpl.encrypt(originValue, mKey); mMappingPrinter.output(getJavaClassName(), originValue, encryptValue); super.visitLdcInsn(encryptValue); super.visitMethodInsn(Opcodes.INVOKESTATIC, mFogClassName, "decrypt", "(Ljava/lang/String;)Ljava/lang/String;", false); } else { super.visitLdcInsn(cst); } } }; } else { mv = new MethodVisitor(Opcodes.ASM5, mv) { @Override public void visitLdcInsn(Object cst) { if (cst != null && cst instanceof String && canEncrypted((String) cst)) { // If the value is a static final field for (ClassStringField field : mStaticFinalFields) { if (cst.equals(field.value)) { super.visitFieldInsn(Opcodes.GETSTATIC, mClassName, field.name, ClassStringField.STRING_DESC); return; } } // If the value is a final field (not static) for (ClassStringField field : mFinalFields) { // if the value of a final field is null, we ignore it if (cst.equals(field.value)) { super.visitVarInsn(Opcodes.ALOAD, 0); super.visitFieldInsn(Opcodes.GETFIELD, mClassName, field.name, "Ljava/lang/String;"); return; } } // local variables String originValue = (String) cst; String encryptValue = mStringFogImpl.encrypt(originValue, mKey); mMappingPrinter.output(getJavaClassName(), originValue, encryptValue); super.visitLdcInsn(encryptValue); super.visitMethodInsn(Opcodes.INVOKESTATIC, mFogClassName, "decrypt", "(Ljava/lang/String;)Ljava/lang/String;", false); return; } super.visitLdcInsn(cst); } }; } } return mv; }
From source file:com.github.megatronking.stringfog.plugin.StringFogClassVisitor.java
License:Apache License
@Override public void visitEnd() { if (!mIgnoreClass && !isClInitExists && !mStaticFinalFields.isEmpty()) { MethodVisitor mv = super.visitMethod(Opcodes.ACC_STATIC, "<clinit>", "()V", null, null); mv.visitCode();// w ww . ja v a 2 s . c o m // Here init static final fields. for (ClassStringField field : mStaticFinalFields) { if (!canEncrypted(field.value)) { continue; } String originValue = field.value; String encryptValue = mStringFogImpl.encrypt(originValue, mKey); mMappingPrinter.output(getJavaClassName(), originValue, encryptValue); mv.visitLdcInsn(encryptValue); mv.visitMethodInsn(Opcodes.INVOKESTATIC, mFogClassName, "decrypt", "(Ljava/lang/String;)Ljava/lang/String;", false); mv.visitFieldInsn(Opcodes.PUTSTATIC, mClassName, field.name, ClassStringField.STRING_DESC); } mv.visitInsn(Opcodes.RETURN); mv.visitMaxs(1, 0); mv.visitEnd(); } super.visitEnd(); }
From source file:com.github.rgcjonas.kuemmelgtr.core.Compiler.java
License:Open Source License
private static void compileCommon(TokenSource<RPNToken> source, MethodVisitor method, String variable) throws ParsingError { method.visitCode();//from www . jav a 2s . c o m // we now can compile our token stream int currentStackSize = 0; // we keep track of the current stack size to throw errors if we encounter an invalid instruction RPNToken t; while ((t = source.nextToken()) != null) { if (t instanceof RPNToken.Operand) { // we push it onto the stack method.visitLdcInsn(((RPNToken.Operand) t).getValue()); currentStackSize++; } else if (t instanceof RPNToken.Operator) { RPNToken.Operator op = (RPNToken.Operator) t; if (currentStackSize < op.getNumOperands()) throw new ParsingError(t.getSrcLine(), t.getSrcColumn(), "Missing operand(s)"); switch (op.getName()) { case "_add": method.visitInsn(Opcodes.DADD); currentStackSize--; break; case "_mult": method.visitInsn(Opcodes.DMUL); currentStackSize--; break; case "_sub": method.visitInsn(Opcodes.DSUB); currentStackSize--; break; case "_div": method.visitInsn(Opcodes.DDIV); currentStackSize--; break; case "_pow": method.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Math", "pow", "(DD)D"); currentStackSize--; break; default: //HACK: support every function in java/lang/Math. Will be way more performant than any lookup-and-evaluate //TODO: implement more functions inline if (currentStackSize < 1) throw new ParsingError(t.getSrcLine(), t.getSrcColumn(), "Missing operand"); try { Method meth = Math.class.getDeclaredMethod(op.getName(), double.class); // just check if it's available and hope it returns a double if (meth.getReturnType() != double.class) throw new NoSuchMethodException(); // we don't want to blow up at runtime, do we? method.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Math", op.getName(), "(D)D"); } catch (NoSuchMethodException e) { // we do not give up. The method may be available at runtime. method.visitVarInsn(Opcodes.ALOAD, 0); method.visitInsn(Opcodes.DUP_X2); // swap the this pointer and double method.visitInsn(Opcodes.POP); method.visitLdcInsn(op.getName()); method.visitLdcInsn((int) op.getSrcLine()); method.visitLdcInsn((int) op.getSrcColumn()); method.visitMethodInsn(Opcodes.INVOKEVIRTUAL, CompiledClassBase.class.getName().replace('.', '/'), "resolveAndEvaluateFunction", "(DLjava/lang/String;II)D"); } } } else if (t instanceof RPNToken.VariableRecall) { // maybe, maybe the variable is an argument we can load if (variable != null && ((RPNToken.VariableRecall) t).getName().equalsIgnoreCase(variable)) { method.visitVarInsn(Opcodes.DLOAD, 1); } else { // we let our parent class do the hard work method.visitVarInsn(Opcodes.ALOAD, 0); method.visitLdcInsn(((RPNToken.VariableRecall) t).getName()); method.visitLdcInsn(t.getSrcLine()); method.visitLdcInsn(t.getSrcColumn()); method.visitMethodInsn(Opcodes.INVOKEVIRTUAL, CompiledClassBase.class.getName().replace('.', '/'), "getVariable", "(Ljava/lang/String;II)D"); } currentStackSize++; } else if (t instanceof RPNToken.VariableAssignment) { // also defer to our parent class // we do not give up. The method may be available at runtime. method.visitVarInsn(Opcodes.ALOAD, 0); method.visitInsn(Opcodes.DUP_X2); // swap the this pointer and double method.visitInsn(Opcodes.POP); method.visitLdcInsn(((RPNToken.VariableAssignment) t).getVariableName()); method.visitLdcInsn(t.getSrcLine()); method.visitLdcInsn(t.getSrcColumn()); method.visitMethodInsn(Opcodes.INVOKEVIRTUAL, CompiledClassBase.class.getName().replace('.', '/'), "setVariable", "(DLjava/lang/String;II)D"); } else { throw new ParsingError(t.getSrcLine(), t.getSrcColumn(), "Unknown instruction: " + t); } } if (currentStackSize != 1) throw new ParsingError(0, 0, "Expected stack to be one value, found " + currentStackSize); method.visitInsn(Opcodes.DRETURN); method.visitMaxs(0, 0); method.visitEnd(); }
From source file:com.google.code.jconts.instrument.gen.AsyncMethodAdapter.java
License:Apache License
@Override public void visitMethodInsn(int opcode, String owner, String name, String desc) { checkProlog();//from ww w. ja v a 2 s. com if (opcode == Opcodes.INVOKESTATIC && ASYNC_NAME.equals(owner) && ARETURN_NAME.equals(name)) { if (ARETURN_VOID_DESC.equals(desc)) { mv.visitInsn(Opcodes.ACONST_NULL); } // state variable target.visitVarInsn(Opcodes.ALOAD, info.isStatic() ? 0 : 1); mv.visitFieldInsn(Opcodes.GETFIELD, info.stateClassName, CONTINUATION_FIELD, CONTINUATION_DESC); mv.visitInsn(Opcodes.SWAP); mv.visitMethodInsn(Opcodes.INVOKEINTERFACE, CONTINUATION_NAME, CONTINUATION_INVOKE_NAME, CONTINUATION_INVOKE_DESC); // Will be dropped while replacing ARETURN with RETURN. // FIXME: Should verify this value is NOT used. mv.visitInsn(Opcodes.ACONST_NULL); return; } if (opcode == Opcodes.INVOKESTATIC && ASYNC_NAME.equals(owner) && AWAIT_NAME.equals(name) && AWAIT_DESC.equals(desc)) { // Computation<T> is on stack // FIXME: ... // if (stack.size() != 1) { // throw new IllegalStateException( // "Stack preserving is not supported!"); // } int index = dispatchTable.size(); // Save state List<Type> l = new ArrayList<Type>(locals); if (!info.isStatic()) { l.remove(0); } // state.varX = locX String[] vars = info.tracker.stateFields(l.toArray(new Type[0])); for (int i = 0; i < vars.length; ++i) { // state variable target.visitVarInsn(Opcodes.ALOAD, info.isStatic() ? 0 : 1); mv.visitVarInsn(l.get(i).getOpcode(Opcodes.ILOAD), i + info.thisOffset); mv.visitFieldInsn(Opcodes.PUTFIELD, info.stateClassName, vars[i], l.get(i).getDescriptor()); } // Create instance of continuation // new Continuation([this, ]state, index); mv.visitTypeInsn(Opcodes.NEW, info.continuationClassName); mv.visitInsn(Opcodes.DUP); // "this' for new Continuation([this, ]state, index) if (!info.isStatic()) { mv.visitVarInsn(Opcodes.ALOAD, 0); } // state and index target.visitVarInsn(Opcodes.ALOAD, 0 + info.thisOffset); mv.visitIntInsn(Opcodes.BIPUSH, index); String ctorDesc; if (info.isStatic()) { ctorDesc = Type.getMethodDescriptor(Type.VOID_TYPE, new Type[] { info.stateType, Type.INT_TYPE }); } else { ctorDesc = Type.getMethodDescriptor(Type.VOID_TYPE, new Type[] { Type.getObjectType(info.owner), info.stateType, Type.INT_TYPE }); } mv.visitMethodInsn(Opcodes.INVOKESPECIAL, info.continuationClassName, CTOR_NAME, ctorDesc); mv.visitMethodInsn(Opcodes.INVOKEINTERFACE, COMPUTATION_NAME, COMPUTATION_EXECUTE_NAME, COMPUTATION_EXECUTE_DESC); super.visitInsn(Opcodes.RETURN); // Restore state // mv.visitFrame(Opcodes.F_SAME, 0, new Object[0], 0, new // Object[0]); Label label = new Label(); int invokeIndex = dispatchTable.size(); dispatchTable.add(label); // for invoke dispatchTable.add(label); // for setException mv.visitLabel(label); for (int i = 0; i < vars.length; ++i) { // state variable target.visitVarInsn(Opcodes.ALOAD, info.isStatic() ? 0 : 1); mv.visitFieldInsn(Opcodes.GETFIELD, info.stateClassName, vars[i], l.get(i).getDescriptor()); mv.visitVarInsn(l.get(i).getOpcode(Opcodes.ISTORE), i + info.thisOffset); } // if (index == invokeIndex) goto invokeLabel; Label invokeLabel = new Label(); target.visitVarInsn(Opcodes.ILOAD, 1 + info.thisOffset); mv.visitIntInsn(Opcodes.BIPUSH, invokeIndex); mv.visitJumpInsn(Opcodes.IF_ICMPEQ, invokeLabel); // Throw exception target.visitVarInsn(Opcodes.ALOAD, info.isStatic() ? 0 : 1); mv.visitFieldInsn(Opcodes.GETFIELD, info.stateClassName, "exception", THROWABLE_DESC); mv.visitInsn(Opcodes.ATHROW); // Push result value // invokeLabel: mv.visitLabel(invokeLabel); target.visitVarInsn(Opcodes.ALOAD, info.isStatic() ? 0 : 1); mv.visitFieldInsn(Opcodes.GETFIELD, info.stateClassName, "result", OBJECT_DESC); return; } super.visitMethodInsn(opcode, owner, name, desc); }
From source file:com.google.code.jconts.instrument.gen.ComputationClassGenerator.java
License:Apache License
private void generateExecute(ClassVisitor cv) { final String name = info.computationClassName; final Type outerType = Type.getObjectType(info.owner); // Generate execute(Continuation<T> cont); MethodVisitor mv = cv.visitMethod(Opcodes.ACC_FINAL | Opcodes.ACC_PUBLIC, COMPUTATION_EXECUTE_NAME, COMPUTATION_EXECUTE_DESC, executeSignature(), null); mv.visitCode();/*from ww w . j a va2s . c o m*/ Label start = new Label(); Label end = new Label(); mv.visitLabel(start); // Load outer this if (!info.isStatic()) { mv.visitVarInsn(Opcodes.ALOAD, 0); mv.visitFieldInsn(Opcodes.GETFIELD, name, "this$0", outerType.getDescriptor()); } // Load state field mv.visitVarInsn(Opcodes.ALOAD, 0); mv.visitFieldInsn(Opcodes.GETFIELD, name, "state", stateDesc); // state.continuation = continuation mv.visitVarInsn(Opcodes.ALOAD, 0); mv.visitFieldInsn(Opcodes.GETFIELD, name, "state", stateDesc); mv.visitVarInsn(Opcodes.ALOAD, 1); mv.visitFieldInsn(Opcodes.PUTFIELD, info.stateClassName, CONTINUATION_FIELD, CONTINUATION_DESC); // Initial state (0) mv.visitIntInsn(Opcodes.BIPUSH, 0); mv.visitMethodInsn(info.isStatic() ? Opcodes.INVOKESTATIC : Opcodes.INVOKEVIRTUAL, info.owner, info.name + "$async", Type.getMethodDescriptor(Type.VOID_TYPE, new Type[] { info.stateType, Type.INT_TYPE })); mv.visitInsn(Opcodes.RETURN); mv.visitLabel(end); mv.visitLocalVariable("this", 'L' + name + ';', signature, start, end, 0); if (!info.isStatic()) { mv.visitLocalVariable("this$0", outerType.getDescriptor(), null, start, end, 1); } SignatureWriter sign = new SignatureWriter(); contSignature(sign); mv.visitLocalVariable("continuation", CONTINUATION_DESC, sign.toString(), start, end, 1 + info.thisOffset); mv.visitMaxs(3 + info.thisOffset, 2 + info.thisOffset); mv.visitEnd(); }
From source file:com.google.code.jconts.instrument.gen.ContinuationClassGenerator.java
License:Apache License
private void generateExecute(ClassVisitor cv, boolean execute) { final String name = info.continuationClassName; final Type outerType = Type.getObjectType(info.owner); // Generate invoke(T result); String signature = null;/*from w w w .j av a2 s . c om*/ if (execute) { SignatureWriter sign = new SignatureWriter(); sign.visitParameterType().visitTypeVariable("T"); sign.visitReturnType().visitBaseType('V'); // void signature = sign.toString(); } MethodVisitor mv = cv.visitMethod(Opcodes.ACC_FINAL | Opcodes.ACC_PUBLIC, execute ? CONTINUATION_INVOKE_NAME : CONTINUATION_SET_EXCEPTION_NAME, execute ? CONTINUATION_INVOKE_DESC : CONTINUATION_SET_EXCEPTION_DESC, signature, null); mv.visitCode(); Label start = new Label(); Label end = new Label(); mv.visitLabel(start); // Load outer this if (!info.isStatic()) { mv.visitVarInsn(Opcodes.ALOAD, 0); mv.visitFieldInsn(Opcodes.GETFIELD, name, "this$0", outerType.getDescriptor()); } // state.result = result or state.exception = throwable mv.visitVarInsn(Opcodes.ALOAD, 0); mv.visitFieldInsn(Opcodes.GETFIELD, name, "state", stateDesc); mv.visitVarInsn(Opcodes.ALOAD, 1); mv.visitFieldInsn(Opcodes.PUTFIELD, info.stateClassName, execute ? "result" : "exception", execute ? OBJECT_DESC : THROWABLE_DESC); // Load state field mv.visitVarInsn(Opcodes.ALOAD, 0); mv.visitFieldInsn(Opcodes.GETFIELD, name, "state", stateDesc); // Continue from this index or index+1 (for exception) mv.visitVarInsn(Opcodes.ALOAD, 0); mv.visitFieldInsn(Opcodes.GETFIELD, name, "index", "I"); if (!execute) { mv.visitInsn(Opcodes.ICONST_1); mv.visitInsn(Opcodes.IADD); } mv.visitMethodInsn(info.isStatic() ? Opcodes.INVOKESTATIC : Opcodes.INVOKEVIRTUAL, info.owner, info.name + "$async", Type.getMethodDescriptor(Type.VOID_TYPE, new Type[] { info.stateType, Type.INT_TYPE })); mv.visitInsn(Opcodes.RETURN); mv.visitLabel(end); mv.visitLocalVariable("this", 'L' + name + ';', signature, start, end, 0); if (!info.isStatic()) { mv.visitLocalVariable("this$0", outerType.getDescriptor(), null, start, end, 1); } mv.visitLocalVariable("result", OBJECT_DESC, "TT;", start, end, 1 + info.thisOffset); mv.visitMaxs(3 + info.thisOffset + (execute ? 0 : 1), 2 + info.thisOffset); mv.visitEnd(); }
From source file:com.google.code.jconts.instrument.gen.CoroutineMethodAdapter.java
License:Apache License
@Override public void visitMethodInsn(int opcode, String owner, String name, String desc) { super.visitMethodInsn(opcode, owner, name, desc); if (opcode == Opcodes.INVOKESPECIAL) { return;//from w w w.j a v a 2 s. c o m } if (Type.getReturnType(desc) == Type.VOID_TYPE) { super.visitMethodInsn(Opcodes.INVOKESTATIC, COROUTINES_NAME, COROUTINES_YIELD_NAME, COROUTINES_YIELD_DESC); super.visitMethodInsn(Opcodes.INVOKESTATIC, Constants.ASYNC_NAME, AWAIT_NAME, AWAIT_DESC); super.visitInsn(Opcodes.POP); } }
From source file:com.google.devtools.build.android.desugar.BytecodeTypeInference.java
License:Open Source License
@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.createNonUninitializedType('L' + owner + ';'); replaceUninitializedTypeInStack(receiverType, realType); }/*from w w w . ja v a 2s. c o m*/ } 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); }
From source file:com.google.devtools.build.android.desugar.CoreLibrarySupport.java
License:Open Source License
/** * If the given invocation needs to go through a companion class of an emulated or renamed * core interface, this methods returns that interface. This is a helper method for * {@link CoreLibraryInvocationRewriter}. * * <p>This method can only return non-{@code null} if {@code owner} is a core library type. * It usually returns an emulated interface, unless the given invocation is a super-call to a * core class's implementation of an emulated method that's being moved (other implementations * of emulated methods in core classes are ignored). In that case the class is returned and the * caller can use {@link #getMoveTarget} to find out where to redirect the invokespecial to. *//*from w w w . ja v a2 s .c o m*/ // TODO(kmb): Rethink this API and consider combining it with getMoveTarget(). @Nullable public Class<?> getCoreInterfaceRewritingTarget(int opcode, String owner, String name, String desc, boolean itf) { if (looksGenerated(owner)) { // Regular desugaring handles generated classes, no emulation is needed return null; } if (!itf && opcode == Opcodes.INVOKESTATIC) { // Ignore static invocations on classes--they never need rewriting (unless moved but that's // handled separately). return null; } if ("<init>".equals(name)) { return null; // Constructors aren't rewritten } Class<?> clazz; if (isRenamedCoreLibrary(owner)) { // For renamed invocation targets we just need to do what InterfaceDesugaring does, that is, // only worry about invokestatic and invokespecial interface invocations; nothing to do for // classes and invokeinterface. InterfaceDesugaring ignores bootclasspath interfaces, // so we have to do its work here for renamed interfaces. if (itf && (opcode == Opcodes.INVOKESTATIC || opcode == Opcodes.INVOKESPECIAL)) { clazz = loadFromInternal(owner); } else { return null; } } else { // If not renamed, see if the owner needs emulation. clazz = getEmulatedCoreClassOrInterface(owner); if (clazz == null) { return null; } } checkArgument(itf == clazz.isInterface(), "%s expected to be interface: %s", owner, itf); if (opcode == Opcodes.INVOKESTATIC) { // Static interface invocation always goes to the given owner checkState(itf); // we should've bailed out above. return clazz; } // See if the invoked method is a default method, which will need rewriting. For invokespecial // we can only get here if its a default method, and invokestatic we handled above. Method callee = findInterfaceMethod(clazz, name, desc); if (callee != null && callee.isDefault()) { if (isExcluded(callee)) { return null; } if (!itf && opcode == Opcodes.INVOKESPECIAL) { // See if the invoked implementation is moved; note we ignore all other overrides in classes Class<?> impl = clazz; // we know clazz is not an interface because !itf while (impl != null) { String implName = impl.getName().replace('.', '/'); if (getMoveTarget(implName, name) != null) { return impl; } impl = impl.getSuperclass(); } } Class<?> result = callee.getDeclaringClass(); if (isRenamedCoreLibrary(result.getName().replace('.', '/')) || emulatedInterfaces.stream().anyMatch(emulated -> emulated.isAssignableFrom(result))) { return result; } // We get here if the declaring class is a supertype of an emulated interface. In that case // use the emulated interface instead (since we don't desugar the supertype). Fail in case // there are multiple possibilities. Iterator<Class<?>> roots = emulatedInterfaces.stream() .filter(emulated -> emulated.isAssignableFrom(clazz) && result.isAssignableFrom(emulated)) .iterator(); checkState(roots.hasNext()); // must exist Class<?> substitute = roots.next(); checkState(!roots.hasNext(), "Ambiguous emulation substitute: %s", callee); return substitute; } else { checkArgument(!itf || opcode != Opcodes.INVOKESPECIAL, "Couldn't resolve interface super call %s.super.%s : %s", owner, name, desc); } return null; }