Skip to content

Instantly share code, notes, and snippets.

@h0tk3y
Last active February 16, 2023 12:23
Show Gist options
  • Save h0tk3y/0a905b638bb0459b33578ec511d7c242 to your computer and use it in GitHub Desktop.
Save h0tk3y/0a905b638bb0459b33578ec511d7c242 to your computer and use it in GitHub Desktop.
Call interception generated sources example

The two files below are example outputs of the code generator for call interception in gradle/gradle

package org.gradle.internal.classpath;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FilenameFilter;
import java.lang.Object;
import java.lang.Override;
import java.lang.String;
import java.lang.Throwable;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.List;
import kotlin.io.FilesKt;
import org.gradle.internal.classpath.declarations.FileInputStreamInterceptorsDeclaration;
import org.gradle.internal.classpath.declarations.FileInterceptorsDeclaration;
import org.gradle.internal.classpath.declarations.KotlinFileExtensionsInterceptorsDeclaration;
import org.gradle.internal.classpath.intercept.CallInterceptor;
import org.gradle.internal.classpath.intercept.InterceptScope;
import org.gradle.internal.classpath.intercept.Invocation;
class InterceptorDeclaration_GroovyInterceptorsImpl {
public static List<CallInterceptor> getCallInterceptors() {
return Arrays.asList(
new ReadTextCallInterceptor(),
new ListFilesCallInterceptor(),
new ExistsCallInterceptor(),
new IsFileCallInterceptor(),
new IsDirectoryCallInterceptor(),
new FileInputStreamConstructorCallInterceptor()
);
}
private static class ReadTextCallInterceptor extends CallInterceptor {
public ReadTextCallInterceptor() {
super(InterceptScope.methodsNamed("readText"));
}
@Override
protected Object doIntercept(Invocation invocation, String consumer) throws Throwable {
Object receiver = invocation.getReceiver();
if (receiver.equals(FilesKt.class)) {
Object arg0 = invocation.getArgument(0);
if (arg0 instanceof File) {
File arg0Typed = (File) arg0;
Object arg1 = invocation.getArgument(1);
if (arg1 instanceof Charset) {
Charset arg1Typed = (Charset) arg1;
if (invocation.getArgsCount() == 2) {
return KotlinFileExtensionsInterceptorsDeclaration.intercept_readText(arg0Typed, arg1Typed, 0, consumer);
}
}
}
}
return invocation.callOriginal();
}
}
private static class ListFilesCallInterceptor extends CallInterceptor {
public ListFilesCallInterceptor() {
super(InterceptScope.methodsNamed("listFiles"));
}
@Override
protected Object doIntercept(Invocation invocation, String consumer) throws Throwable {
Object receiver = invocation.getReceiver();
if (receiver instanceof File) {
File receiverTyped = (File) receiver;
if (invocation.getArgsCount() == 0) {
return FileInterceptorsDeclaration.intercept_listFiles(receiverTyped, consumer);
}
Object arg0 = invocation.getArgument(0);
if (arg0 instanceof FileFilter) {
FileFilter arg0Typed = (FileFilter) arg0;
if (invocation.getArgsCount() == 1) {
return FileInterceptorsDeclaration.intercept_listFiles(receiverTyped, arg0Typed, consumer);
}
}
if (arg0 instanceof FilenameFilter) {
FilenameFilter arg0Typed = (FilenameFilter) arg0;
if (invocation.getArgsCount() == 1) {
return FileInterceptorsDeclaration.intercept_listFiles(receiverTyped, arg0Typed, consumer);
}
}
}
return invocation.callOriginal();
}
}
private static class ExistsCallInterceptor extends CallInterceptor {
public ExistsCallInterceptor() {
super(InterceptScope.methodsNamed("exists"));
}
@Override
protected Object doIntercept(Invocation invocation, String consumer) throws Throwable {
Object receiver = invocation.getReceiver();
if (receiver instanceof File) {
File receiverTyped = (File) receiver;
if (invocation.getArgsCount() == 0) {
return FileInterceptorsDeclaration.intercept_exists(receiverTyped, consumer);
}
}
return invocation.callOriginal();
}
}
private static class IsFileCallInterceptor extends CallInterceptor {
public IsFileCallInterceptor() {
super(InterceptScope.methodsNamed("isFile"));
}
@Override
protected Object doIntercept(Invocation invocation, String consumer) throws Throwable {
Object receiver = invocation.getReceiver();
if (receiver instanceof File) {
File receiverTyped = (File) receiver;
if (invocation.getArgsCount() == 0) {
return FileInterceptorsDeclaration.intercept_isFile(receiverTyped, consumer);
}
}
return invocation.callOriginal();
}
}
private static class IsDirectoryCallInterceptor extends CallInterceptor {
public IsDirectoryCallInterceptor() {
super(InterceptScope.methodsNamed("isDirectory"));
}
@Override
protected Object doIntercept(Invocation invocation, String consumer) throws Throwable {
Object receiver = invocation.getReceiver();
if (receiver instanceof File) {
File receiverTyped = (File) receiver;
if (invocation.getArgsCount() == 0) {
return FileInterceptorsDeclaration.intercept_isDirectory(receiverTyped, consumer);
}
}
return invocation.callOriginal();
}
}
private static class FileInputStreamConstructorCallInterceptor extends CallInterceptor {
public FileInputStreamConstructorCallInterceptor() {
super(InterceptScope.constructorsOf(FileInputStream.class));
}
@Override
protected Object doIntercept(Invocation invocation, String consumer) throws Throwable {
Object receiver = invocation.getReceiver();
if (receiver.equals(FileInputStream.class)) {
Object arg0 = invocation.getArgument(0);
if (arg0 instanceof File) {
File arg0Typed = (File) arg0;
if (invocation.getArgsCount() == 1) {
FileInputStream result = new FileInputStream(arg0Typed);
FileInputStreamInterceptorsDeclaration.interceptFileInputStreamConstructor(result, arg0Typed, consumer);
return result;
}
}
if (arg0 instanceof String) {
String arg0Typed = (String) arg0;
if (invocation.getArgsCount() == 1) {
FileInputStream result = new FileInputStream(arg0Typed);
FileInputStreamInterceptorsDeclaration.interceptFileInputStreamConstructor(result, arg0Typed, consumer);
return result;
}
}
}
return invocation.callOriginal();
}
}
}
package org.gradle.internal.classpath;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FilenameFilter;
import java.lang.Override;
import java.lang.String;
import java.nio.charset.Charset;
import kotlin.io.FilesKt;
import org.gradle.internal.classpath.declarations.FileInputStreamInterceptorsDeclaration;
import org.gradle.internal.classpath.declarations.FileInterceptorsDeclaration;
import org.gradle.internal.classpath.declarations.KotlinFileExtensionsInterceptorsDeclaration;
import org.gradle.internal.instrumentation.api.jvmbytecode.JvmBytecodeCallInterceptor;
import org.gradle.internal.instrumentation.utils.LocalVariablesSorterWithDroppedVariables;
import org.gradle.model.internal.asm.MethodVisitorScope;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
class InterceptorDeclaration_JvmBytecodeImpl extends MethodVisitorScope implements JvmBytecodeCallInterceptor {
private static final Type FILE_INPUT_STREAM_INTERCEPTORS_DECLARATION_TYPE = Type.getType(FileInputStreamInterceptorsDeclaration.class);
private static final Type KOTLIN_FILE_EXTENSIONS_INTERCEPTORS_DECLARATION_TYPE = Type.getType(KotlinFileExtensionsInterceptorsDeclaration.class);
private static final Type FILE_INTERCEPTORS_DECLARATION_TYPE = Type.getType(FileInterceptorsDeclaration.class);
private final LocalVariablesSorterWithDroppedVariables localVariablesSorter;
/**
* This is the method visitor that does not map the local variables with the {@link localVariablesSorter} and can thus use the newly introduced variables.
*/
private final MethodVisitor unmappedMethodVisitor;
public InterceptorDeclaration_JvmBytecodeImpl(MethodVisitor unmappedMethodVisitor,
LocalVariablesSorterWithDroppedVariables localVariablesSorter) {
super(localVariablesSorter);
this.localVariablesSorter = localVariablesSorter;
this.unmappedMethodVisitor = unmappedMethodVisitor;
}
private static String binaryClassNameOf(String className) {
return Type.getObjectType(className).getClassName();
}
private void loadOwnerBinaryClassName(String className) {
_LDC(binaryClassNameOf(className));
}
@Override
public boolean visitMethodInsn(String className, int opcode, String owner, String name,
String descriptor, boolean isInterface) {
if (owner.equals("java/io/FileInputStream")) {
/**
* Intercepting constructor (getting notified after it): {@link FileInputStream#FileInputStream(File)}
* Intercepted by {@link FileInputStreamInterceptorsDeclaration#interceptFileInputStreamConstructor(FileInputStream, File, String)}
*/
if (name.equals("<init>") && descriptor.equals("(Ljava/io/File;)V") && opcode == Opcodes.INVOKESPECIAL) {
Type type0 = Type.getType(File.class);
int var0 = localVariablesSorter.newLocal(type0);
unmappedMethodVisitor.visitVarInsn(type0.getOpcode(Opcodes.ISTORE), var0);
_DUP();
unmappedMethodVisitor.visitVarInsn(type0.getOpcode(Opcodes.ILOAD), var0);
_INVOKESPECIAL(owner, name, descriptor);
unmappedMethodVisitor.visitVarInsn(type0.getOpcode(Opcodes.ILOAD), var0);
localVariablesSorter.dropLocal(var0);
loadOwnerBinaryClassName(className);
_INVOKESTATIC(FILE_INPUT_STREAM_INTERCEPTORS_DECLARATION_TYPE, "interceptFileInputStreamConstructor", "(Ljava/io/FileInputStream;Ljava/io/File;Ljava/lang/String;)V");
return true;
}
/**
* Intercepting constructor (getting notified after it): {@link FileInputStream#FileInputStream(String)}
* Intercepted by {@link FileInputStreamInterceptorsDeclaration#interceptFileInputStreamConstructor(FileInputStream, String, String)}
*/
if (name.equals("<init>") && descriptor.equals("(Ljava/lang/String;)V") && opcode == Opcodes.INVOKESPECIAL) {
Type type0 = Type.getType(String.class);
int var0 = localVariablesSorter.newLocal(type0);
unmappedMethodVisitor.visitVarInsn(type0.getOpcode(Opcodes.ISTORE), var0);
_DUP();
unmappedMethodVisitor.visitVarInsn(type0.getOpcode(Opcodes.ILOAD), var0);
_INVOKESPECIAL(owner, name, descriptor);
unmappedMethodVisitor.visitVarInsn(type0.getOpcode(Opcodes.ILOAD), var0);
localVariablesSorter.dropLocal(var0);
loadOwnerBinaryClassName(className);
_INVOKESTATIC(FILE_INPUT_STREAM_INTERCEPTORS_DECLARATION_TYPE, "interceptFileInputStreamConstructor", "(Ljava/io/FileInputStream;Ljava/lang/String;Ljava/lang/String;)V");
return true;
}
}
if (owner.equals("kotlin/io/FilesKt")) {
/**
* Intercepting static method: {@link FilesKt#readText(File, Charset)}
* Intercepted by {@link KotlinFileExtensionsInterceptorsDeclaration#intercept_readText(File, Charset, int, String)}
*/
if (name.equals("readText") && descriptor.equals("(Ljava/io/File;Ljava/nio/charset/Charset;)Ljava/lang/String;") && opcode == Opcodes.INVOKESTATIC) {
// The interceptor expects a Kotlin default mask, add a zero argument:
_ICONST_0();
_LDC(binaryClassNameOf(className));
_INVOKESTATIC(KOTLIN_FILE_EXTENSIONS_INTERCEPTORS_DECLARATION_TYPE, "intercept_readText", "(Ljava/io/File;Ljava/nio/charset/Charset;ILjava/lang/String;)Ljava/lang/String;");
return true;
}
// Additionally intercept the signature with the Kotlin default mask and marker:
if (name.equals("readText$default") && descriptor.equals("(Ljava/io/File;Ljava/nio/charset/Charset;ILjava/lang/Object;)Ljava/lang/String;") && opcode == Opcodes.INVOKESTATIC) {
_POP();
_LDC(binaryClassNameOf(className));
_INVOKESTATIC(KOTLIN_FILE_EXTENSIONS_INTERCEPTORS_DECLARATION_TYPE, "intercept_readText", "(Ljava/io/File;Ljava/nio/charset/Charset;ILjava/lang/String;)Ljava/lang/String;");
return true;
}
}
if (owner.equals("java/io/File")) {
/**
* Intercepting instance method: {@link File#listFiles()}
* Intercepted by {@link FileInterceptorsDeclaration#intercept_listFiles(File, String)}
*/
if (name.equals("listFiles") && descriptor.equals("()Ljava/io/File;]") && opcode == Opcodes.INVOKEVIRTUAL) {
_LDC(binaryClassNameOf(className));
_INVOKESTATIC(FILE_INTERCEPTORS_DECLARATION_TYPE, "intercept_listFiles", "(Ljava/io/File;Ljava/lang/String;)Ljava/io/File;]");
return true;
}
/**
* Intercepting instance method: {@link File#listFiles(FileFilter)}
* Intercepted by {@link FileInterceptorsDeclaration#intercept_listFiles(File, FileFilter, String)}
*/
if (name.equals("listFiles") && descriptor.equals("(Ljava/io/FileFilter;)Ljava/io/File;]") && opcode == Opcodes.INVOKEVIRTUAL) {
_LDC(binaryClassNameOf(className));
_INVOKESTATIC(FILE_INTERCEPTORS_DECLARATION_TYPE, "intercept_listFiles", "(Ljava/io/File;Ljava/io/FileFilter;Ljava/lang/String;)Ljava/io/File;]");
return true;
}
/**
* Intercepting instance method: {@link File#listFiles(FilenameFilter)}
* Intercepted by {@link FileInterceptorsDeclaration#intercept_listFiles(File, FilenameFilter, String)}
*/
if (name.equals("listFiles") && descriptor.equals("(Ljava/io/FilenameFilter;)Ljava/io/File;]") && opcode == Opcodes.INVOKEVIRTUAL) {
_LDC(binaryClassNameOf(className));
_INVOKESTATIC(FILE_INTERCEPTORS_DECLARATION_TYPE, "intercept_listFiles", "(Ljava/io/File;Ljava/io/FilenameFilter;Ljava/lang/String;)Ljava/io/File;]");
return true;
}
/**
* Intercepting instance method: {@link File#exists()}
* Intercepted by {@link FileInterceptorsDeclaration#intercept_exists(File, String)}
*/
if (name.equals("exists") && descriptor.equals("()Z") && opcode == Opcodes.INVOKEVIRTUAL) {
_LDC(binaryClassNameOf(className));
_INVOKESTATIC(FILE_INTERCEPTORS_DECLARATION_TYPE, "intercept_exists", "(Ljava/io/File;Ljava/lang/String;)Z");
return true;
}
/**
* Intercepting instance method: {@link File#isFile()}
* Intercepted by {@link FileInterceptorsDeclaration#intercept_isFile(File, String)}
*/
if (name.equals("isFile") && descriptor.equals("()Z") && opcode == Opcodes.INVOKEVIRTUAL) {
_LDC(binaryClassNameOf(className));
_INVOKESTATIC(FILE_INTERCEPTORS_DECLARATION_TYPE, "intercept_isFile", "(Ljava/io/File;Ljava/lang/String;)Z");
return true;
}
/**
* Intercepting instance method: {@link File#isDirectory()}
* Intercepted by {@link FileInterceptorsDeclaration#intercept_isDirectory(File, String)}
*/
if (name.equals("isDirectory") && descriptor.equals("()Z") && opcode == Opcodes.INVOKEVIRTUAL) {
_LDC(binaryClassNameOf(className));
_INVOKESTATIC(FILE_INTERCEPTORS_DECLARATION_TYPE, "intercept_isDirectory", "(Ljava/io/File;Ljava/lang/String;)Z");
return true;
}
}
return false;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment