Modifying Classes with Transform API

Modifying Classes with Transform API

Transform API is a part of the Android Gradle Plugin and provides hooks to manipulate the compiled class during the build time before classes are given for Dexing.
It simplifies injecting custom class manipulation without having to deal with Gradle tasks and offers more flexibility on what is manipulated. Some of the projects using the Transform API are ProGuard, MultiDex and RetroLambda. People who are attending the talk will learn how the Android Gradle Plugin works and how they can use the Transform API to manipulate java class files.

5d3f2e1894f18e22c172d6db85a4fccc?s=128

FarmaanElahi

January 11, 2020
Tweet

Transcript

  1. Modifying Classes with Transform API Partner @ Triveous @FarmaanElahi

  2. Transform API?

  3. Is it same as Annotation Processor ?

  4. Is it same as Annotation Processor ? • Annotation Processor

    • Your code runs at compile time
  5. Is it same as Annotation Processor ? • Annotation Processor

    • Your code runs at compile time • Transform API • Your code runs after compilation but before dexing
  6. Is it same as Annotation Processor ? • Annotation Processor

    • Your code runs at compile time • Emits Java or Kotlin Source which is eventually compiled to bytecode • Transform API • Your code runs after compilation but before dexing
  7. Is it same as Annotation Processor ? • Annotation Processor

    • Your code runs at compile time • Emits Java or Kotlin Source which is eventually compiled to bytecode • Transform API • Your code runs after compilation but before dexing • Emits bytecode
  8. Examples • ProGuard • Retro Lambda • Multi Dex

  9. What can I build from it ? • Incredibly powerful

    API; you can modify any class internals • Helps achieves Aspect and Meta Oriented Programming Constructs
  10. When NOT to use this?

  11. When NOT to use this? • If your problem can

    be solved with an Annotation Processor • If you don’t understand bytecode and JVM internals
  12. Plugin Transformer Class Reader Class Visitor Class Writer Architecture

  13. Plugin Transformer Class Reader Class Visitor Class Writer • Gradle

    Plugin • Provides entry to build.gradle script • Allows configuration via Gradle Extension Architecture
  14. Plugin Transformer Class Reader Class Visitor Class Writer • Defines

    the scope of transformation • Project • Modules • External Libraries • Defines the input to this transformer (Can be classes or java resource) • Transformation Architecture
  15. Plugin Transformer Class Reader Class Visitor Class Writer • This

    is the beginning of the transforming a class • Helps to read the class file Architecture
  16. Plugin Transformer Class Reader Class Visitor Class Writer • Provides

    method to transform the class after reading the raw files • Provides various visit* method to transform different components • Requires a strict order in which this methods should be called to generate correct output. Architecture
  17. Plugin Transformer Class Reader Class Visitor Class Writer • Writes

    the byte codes Architecture
  18. • We’ll build a transformation which that traces method call

    Let’s build our own fun prime(n: Int){ println("--->prime(n=$n)") val startTime = System.currentTimeMillis() val result = primeNumberSequence.take(n).last() val timeToRun = System.currentTimeMillis() - startTime println("<--- prime[ran in $timeToRun] ms") return result } fun prime(n:Int) = primeSequence.take(n).last()
  19. Plugin Transformer Class Reader Class Visitor Class Writer

  20. plugin/build.gradle apply plugin: 'java-library' apply plugin: 'java-gradle-plugin' gradlePlugin { plugins

    { logger { id = 'com.logger.plugin' -/ apply plugin :"com.logger.plugin" implementationClass = 'com.logger.plugin.LoggerPlugin' } } } dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation "com.android.tools.build:gradle-api:3.5.0" implementation "com.android.tools.build:gradle:3.5.0" }
  21. gradle-plugin/build.gradle apply plugin: 'java-library' apply plugin: 'java-gradle-plugin' gradlePlugin { plugins

    { logger { id = 'com.logger.plugin' -/ apply plugin :"com.logger.plugin" implementationClass = 'com.logger.plugin.LoggerPlugin' } } } dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation "com.android.tools.build:gradle-api:3.5.0" implementation "com.android.tools.build:gradle:3.5.0" }
  22. class LoggerPlugin : Plugin<Project> { override fun apply(project: Project) {

    val androidExtension = project.extensions.findByName("android") as? AppExtension androidExtension-.registerTransform(DebugTransformer()) } } plugin/src/main/kotlin/com/logger/plugin/LoggerPlugin.kt
  23. class LoggerPlugin : Plugin<Project> { override fun apply(project: Project) {

    val androidExtension = project.extensions.findByName("android") as? AppExtension androidExtension-.registerTransform(DebugTransformer()) } } plugin/src/main/kotlin/com/logger/plugin/LoggerPlugin.kt
  24. Plugin Transformer Class Reader Class Visitor Class Writer

  25. class DebugTransformer : Transform() { override fun getName() = "DebugLogger"

    override fun getInputTypes() = setOf(DefaultContentType.CLASSES) override fun isIncremental() = false override fun getScopes() = mutableSetOf(QualifiedContent.Scope.PROJECT) override fun transform(transformInvocation: TransformInvocation?) } plugin/src/main/kotlin/com/logger/plugin/DebugTransformer.kt
  26. class DebugTransformer : Transform() { override fun getName() = "DebugLogger"

    override fun getInputTypes() = setOf(DefaultContentType.CLASSES) override fun isIncremental() = false override fun getScopes() = mutableSetOf(QualifiedContent.Scope.PROJECT) override fun transform(transformInvocation: TransformInvocation?) } plugin/src/main/kotlin/com/logger/plugin/DebugTransformer.kt
  27. class DebugTransformer : Transform() { override fun getName() = "DebugLogger"

    override fun getInputTypes() = setOf(DefaultContentType.CLASSES) override fun isIncremental() = false override fun getScopes() = mutableSetOf(QualifiedContent.Scope.PROJECT) override fun transform(transformInvocation: TransformInvocation?) } plugin/src/main/kotlin/com/logger/plugin/DebugTransformer.kt
  28. class DebugTransformer : Transform() { override fun getName() = "DebugLogger"

    override fun getInputTypes() = setOf(DefaultContentType.CLASSES) override fun isIncremental() = false override fun getScopes() = mutableSetOf(QualifiedContent.Scope.PROJECT) override fun transform(transformInvocation: TransformInvocation?) } plugin/src/main/kotlin/com/logger/plugin/DebugTransformer.kt
  29. class DebugTransformer : Transform() { override fun getName() = "DebugLogger"

    override fun getInputTypes() = setOf(DefaultContentType.CLASSES) override fun isIncremental() = false override fun getScopes() = mutableSetOf(QualifiedContent.Scope.PROJECT) override fun transform(transformInvocation: TransformInvocation?) } plugin/src/main/kotlin/com/logger/plugin/DebugTransformer.kt
  30. override fun transform(transformInvocation: TransformInvocation) { val outputProvider = transformInvocation.outputProvider inputs.flatMap

    { it.directoryInputs }.forEach { val destinationDirectory = outputProvider.getContentLocation( it.name, it.contentTypes, it.scopes, Format.DIRECTORY ) val allInputFiles = loadFileRecursively(it.file) } } plugin/src/main/kotlin/com/logger/plugin/DebugTransformer.kt
  31. override fun transform(transformInvocation: TransformInvocation) { val outputProvider = transformInvocation.outputProvider inputs.flatMap

    { it.directoryInputs }.forEach { val destinationDirectory = outputProvider.getContentLocation( it.name, it.contentTypes, it.scopes, Format.DIRECTORY ) val allInputFiles = loadFileRecursively(it.file) } } plugin/src/main/kotlin/com/logger/plugin/DebugTransformer.kt
  32. inputs.flatMap { it.directoryInputs }.forEach { --. val allInputFiles = loadFileRecursively(it.file)

    val inputDirPath = it.file.absolutePath val outputDirPath = destinationDirectory.absolutePath allInputFiles.forEach { inputFile -> val inputClassFilePath = inputFile.absolutePath val outputClassFile = File(inputClassFilePath.replace(inputDirPath, outputDirPath)) tranformClassFile(inputClassFile, outputClassFile) } } plugin/src/main/kotlin/com/logger/plugin/DebugTransformer.kt
  33. fun transformClass(inputFile: File, outputFile: File) { val classReader = ClassReader(inputFile.readBytes())

    val classWriter = ClassWriter(ASM5) val classVisitor = CustomClassVisitor(classWriter) classReader.accept(classVisitor, ClassReader.EXPAND_FRAMES) outputFile.writeBytes(classWriter.toByteArray()) } plugin/src/main/kotlin/com/logger/plugin/DebugTransformer.kt
  34. fun transformClass(inputFile: File, outputFile: File) { val classReader = ClassReader(inputFile.readBytes())

    val classWriter = ClassWriter(ASM5) val classVisitor = CustomClassVisitor(classWriter) classReader.accept(classVisitor, ClassReader.EXPAND_FRAMES) outputFile.writeBytes(classWriter.toByteArray()) } plugin/src/main/kotlin/com/logger/plugin/DebugTransformer.kt
  35. fun transformClass(inputFile: File, outputFile: File) { val classReader = ClassReader(inputFile.readBytes())

    val classWriter = ClassWriter(ASM5) val classVisitor = CustomClassVisitor(classWriter) classReader.accept(classVisitor, ClassReader.EXPAND_FRAMES) outputFile.writeBytes(classWriter.toByteArray()) } plugin/src/main/kotlin/com/logger/plugin/DebugTransformer.kt
  36. fun transformClass(inputFile: File, outputFile: File) { val classReader = ClassReader(inputFile.readBytes())

    val classWriter = ClassWriter(ASM5) val classVisitor = CustomClassVisitor(classWriter) classReader.accept(classVisitor, ClassReader.EXPAND_FRAMES) outputFile.writeBytes(classWriter.toByteArray()) } plugin/src/main/kotlin/com/logger/plugin/DebugTransformer.kt
  37. fun transformClass(inputFile: File, outputFile: File) { val classReader = ClassReader(inputFile.readBytes())

    val classWriter = ClassWriter(ASM5) val classVisitor = CustomClassVisitor(classWriter) classReader.accept(classVisitor, ClassReader.EXPAND_FRAMES) outputFile.writeBytes(classWriter.toByteArray()) } plugin/src/main/kotlin/com/logger/plugin/DebugTransformer.kt
  38. • You write bytecode • JVM is stack machine ◦

    One Stack for each thread on which method operates ◦ You can store and load variable from the Local Variable Array ◦ There is a constant pool which store references to class, method and constant values What now?
  39. What does bytecode look like? fun printSimpleSum() { val sum

    = v1() + v2() println("sum of values was $sum") } INVOKESTATIC myapp/MainActivity.v1 ()I INVOKESTATIC myapp/MainActivity.v2 ()I IADD ISTORE 1 GETSTATIC j/l/System.out : Lj/io/PrintStream; NEW j/l/StringBuilder DUP INVOKESPECIAL j/l/StringBuilder.<init> ()V LDC "sum of values was " INVOKEVIRTUAL j/l/StringBuilder.append (Lj/l/String;)Lj/l/StringBuilder; ILOAD 1 INVOKEVIRTUAL j/l/StringBuilder.append (I)Lj/l/StringBuilder; INVOKEVIRTUAL j/l/StringBuilder.toString ()Lj/l/String; INVOKEVIRTUAL j/io/PrintStream.println (Lj/l/String;)V
  40. fun printSimpleSum() { val sum = v1() + v2() println("sum

    of values was $sum") } INVOKESTATIC myapp/RunnerKt.v1 ()I INVOKESTATIC myapp/RunnerKt.v2 ()I IADD ISTORE 1 GETSTATIC j/l/System.out : Lj/io/PrintStream; NEW j/l/StringBuilder DUP INVOKESPECIAL j/l/StringBuilder.<init> ()V LDC "sum of values was " INVOKEVIRTUAL j/l/StringBuilder.append (Lj/l/String;)Lj/l/StringBuilder; ILOAD 1 INVOKEVIRTUAL j/l/StringBuilder.append (I)Lj/l/StringBuilder; INVOKEVIRTUAL j/l/StringBuilder.toString ()Lj/l/String; INVOKEVIRTUAL j/io/PrintStream.println (Lj/l/String;)V Return value of v1 What does bytecode look like?
  41. fun printSimpleSum() { val sum = v1() + v2() println("sum

    of values was $sum") } INVOKESTATIC myapp/RunnerKt.v1 ()I INVOKESTATIC myapp/RunnerKt.v2 ()I IADD ISTORE 1 GETSTATIC j/l/System.out : Lj/io/PrintStream; NEW j/l/StringBuilder DUP INVOKESPECIAL j/l/StringBuilder.<init> ()V LDC "sum of values was " INVOKEVIRTUAL j/l/StringBuilder.append (Lj/l/String;)Lj/l/StringBuilder; ILOAD 1 INVOKEVIRTUAL j/l/StringBuilder.append (I)Lj/l/StringBuilder; INVOKEVIRTUAL j/l/StringBuilder.toString ()Lj/l/String; INVOKEVIRTUAL j/io/PrintStream.println (Lj/l/String;)V Return value of v1 Return value of v2 What does bytecode look like?
  42. fun printSimpleSum() { val sum = v1() + v2() println("sum

    of values was $sum") } INVOKESTATIC myapp/RunnerKt.v1 ()I INVOKESTATIC myapp/RunnerKt.v2 ()I IADD ISTORE 1 GETSTATIC j/l/System.out : Lj/io/PrintStream; NEW j/l/StringBuilder DUP INVOKESPECIAL j/l/StringBuilder.<init> ()V LDC "sum of values was " INVOKEVIRTUAL j/l/StringBuilder.append (Lj/l/String;)Lj/l/StringBuilder; ILOAD 1 INVOKEVIRTUAL j/l/StringBuilder.append (I)Lj/l/StringBuilder; INVOKEVIRTUAL j/l/StringBuilder.toString ()Lj/l/String; INVOKEVIRTUAL j/io/PrintStream.println (Lj/l/String;)V Return value of v1 Return value of v2 What does bytecode look like?
  43. fun printSimpleSum() { val sum = v1() + v2() println("sum

    of values was $sum") } INVOKESTATIC myapp/RunnerKt.v1 ()I INVOKESTATIC myapp/RunnerKt.v2 ()I IADD ISTORE 1 GETSTATIC j/l/System.out : Lj/io/PrintStream; NEW j/l/StringBuilder DUP INVOKESPECIAL j/l/StringBuilder.<init> ()V LDC "sum of values was " INVOKEVIRTUAL j/l/StringBuilder.append (Lj/l/String;)Lj/l/StringBuilder; ILOAD 1 INVOKEVIRTUAL j/l/StringBuilder.append (I)Lj/l/StringBuilder; INVOKEVIRTUAL j/l/StringBuilder.toString ()Lj/l/String; INVOKEVIRTUAL j/io/PrintStream.println (Lj/l/String;)V v1() + v2() What does bytecode look like?
  44. fun printSimpleSum() { val sum = v1() + v2() println("sum

    of values was $sum") } INVOKESTATIC myapp/RunnerKt.v1 ()I INVOKESTATIC myapp/RunnerKt.v2 ()I IADD ISTORE 1 GETSTATIC j/l/System.out : Lj/io/PrintStream; NEW j/l/StringBuilder DUP INVOKESPECIAL j/l/StringBuilder.<init> ()V LDC "sum of values was " INVOKEVIRTUAL j/l/StringBuilder.append (Lj/l/String;)Lj/l/StringBuilder; ILOAD 1 INVOKEVIRTUAL j/l/StringBuilder.append (I)Lj/l/StringBuilder; INVOKEVIRTUAL j/l/StringBuilder.toString ()Lj/l/String; INVOKEVIRTUAL j/io/PrintStream.println (Lj/l/String;)V v1() + v2() What does bytecode look like?
  45. fun printSimpleSum() { val sum = v1() + v2() println("sum

    of values was $sum") } INVOKESTATIC myapp/RunnerKt.v1 ()I INVOKESTATIC myapp/RunnerKt.v2 ()I IADD ISTORE 1 GETSTATIC j/l/System.out : Lj/io/PrintStream; NEW j/l/StringBuilder DUP INVOKESPECIAL j/l/StringBuilder.<init> ()V LDC "sum of values was " INVOKEVIRTUAL j/l/StringBuilder.append (Lj/l/String;)Lj/l/StringBuilder; ILOAD 1 INVOKEVIRTUAL j/l/StringBuilder.append (I)Lj/l/StringBuilder; INVOKEVIRTUAL j/l/StringBuilder.toString ()Lj/l/String; INVOKEVIRTUAL j/io/PrintStream.println (Lj/l/String;)V Printstream Ref What does bytecode look like?
  46. fun printSimpleSum() { val sum = v1() + v2() println("sum

    of values was $sum") } INVOKESTATIC myapp/RunnerKt.v1 ()I INVOKESTATIC myapp/RunnerKt.v2 ()I IADD ISTORE 1 GETSTATIC j/l/System.out : Lj/io/PrintStream; NEW j/l/StringBuilder DUP INVOKESPECIAL j/l/StringBuilder.<init> ()V LDC "sum of values was " INVOKEVIRTUAL j/l/StringBuilder.append (Lj/l/String;)Lj/l/StringBuilder; ILOAD 1 INVOKEVIRTUAL j/l/StringBuilder.append (I)Lj/l/StringBuilder; INVOKEVIRTUAL j/l/StringBuilder.toString ()Lj/l/String; INVOKEVIRTUAL j/io/PrintStream.println (Lj/l/String;)V Printstream Ref StringBuilder What does bytecode look like?
  47. fun printSimpleSum() { val sum = v1() + v2() println("sum

    of values was $sum") } INVOKESTATIC myapp/RunnerKt.v1 ()I INVOKESTATIC myapp/RunnerKt.v2 ()I IADD ISTORE 1 GETSTATIC j/l/System.out : Lj/io/PrintStream; NEW j/l/StringBuilder DUP INVOKESPECIAL j/l/StringBuilder.<init> ()V LDC "sum of values was " INVOKEVIRTUAL j/l/StringBuilder.append (Lj/l/String;)Lj/l/StringBuilder; ILOAD 1 INVOKEVIRTUAL j/l/StringBuilder.append (I)Lj/l/StringBuilder; INVOKEVIRTUAL j/l/StringBuilder.toString ()Lj/l/String; INVOKEVIRTUAL j/io/PrintStream.println (Lj/l/String;)V Printstream Ref StringBuilder StringBuilder What does bytecode look like?
  48. fun printSimpleSum() { val sum = v1() + v2() println("sum

    of values was $sum") } INVOKESTATIC myapp/RunnerKt.v1 ()I INVOKESTATIC myapp/RunnerKt.v2 ()I IADD ISTORE 1 GETSTATIC j/l/System.out : Lj/io/PrintStream; NEW j/l/StringBuilder DUP INVOKESPECIAL j/l/StringBuilder.<init> ()V LDC "sum of values was " INVOKEVIRTUAL j/l/StringBuilder.append (Lj/l/String;)Lj/l/StringBuilder; ILOAD 1 INVOKEVIRTUAL j/l/StringBuilder.append (I)Lj/l/StringBuilder; INVOKEVIRTUAL j/l/StringBuilder.toString ()Lj/l/String; INVOKEVIRTUAL j/io/PrintStream.println (Lj/l/String;)V Printstream Ref StringBuilder StringBuilder What does bytecode look like?
  49. fun printSimpleSum() { val sum = v1() + v2() println("sum

    of values was $sum") } INVOKESTATIC myapp/RunnerKt.v1 ()I INVOKESTATIC myapp/RunnerKt.v2 ()I IADD ISTORE 1 GETSTATIC j/l/System.out : Lj/io/PrintStream; NEW j/l/StringBuilder DUP INVOKESPECIAL j/l/StringBuilder.<init> ()V LDC "sum of values was " INVOKEVIRTUAL j/l/StringBuilder.append (Lj/l/String;)Lj/l/StringBuilder; ILOAD 1 INVOKEVIRTUAL j/l/StringBuilder.append (I)Lj/l/StringBuilder; INVOKEVIRTUAL j/l/StringBuilder.toString ()Lj/l/String; INVOKEVIRTUAL j/io/PrintStream.println (Lj/l/String;)V Printstream Ref StringBuilder “Sum of values was” What does bytecode look like?
  50. fun printSimpleSum() { val sum = v1() + v2() println("sum

    of values was $sum") } INVOKESTATIC myapp/RunnerKt.v1 ()I INVOKESTATIC myapp/RunnerKt.v2 ()I IADD ISTORE 1 GETSTATIC j/l/System.out : Lj/io/PrintStream; NEW j/l/StringBuilder DUP INVOKESPECIAL j/l/StringBuilder.<init> ()V LDC "sum of values was " INVOKEVIRTUAL j/l/StringBuilder.append (Lj/l/String;)Lj/l/StringBuilder; ILOAD 1 INVOKEVIRTUAL j/l/StringBuilder.append (I)Lj/l/StringBuilder; INVOKEVIRTUAL j/l/StringBuilder.toString ()Lj/l/String; INVOKEVIRTUAL j/io/PrintStream.println (Lj/l/String;)V Printstream Ref StringBuilder “Sum of values was” What does bytecode look like?
  51. fun printSimpleSum() { val sum = v1() + v2() println("sum

    of values was $sum") } INVOKESTATIC myapp/RunnerKt.v1 ()I INVOKESTATIC myapp/RunnerKt.v2 ()I IADD ISTORE 1 GETSTATIC j/l/System.out : Lj/io/PrintStream; NEW j/l/StringBuilder DUP INVOKESPECIAL j/l/StringBuilder.<init> ()V LDC "sum of values was " INVOKEVIRTUAL j/l/StringBuilder.append (Lj/l/String;)Lj/l/StringBuilder; ILOAD 1 INVOKEVIRTUAL j/l/StringBuilder.append (I)Lj/l/StringBuilder; INVOKEVIRTUAL j/l/StringBuilder.toString ()Lj/l/String; INVOKEVIRTUAL j/io/PrintStream.println (Lj/l/String;)V Printstream Ref StringBuilder What does bytecode look like?
  52. fun printSimpleSum() { val sum = v1() + v2() println("sum

    of values was $sum") } INVOKESTATIC myapp/RunnerKt.v1 ()I INVOKESTATIC myapp/RunnerKt.v2 ()I IADD ISTORE 1 GETSTATIC j/l/System.out : Lj/io/PrintStream; NEW j/l/StringBuilder DUP INVOKESPECIAL j/l/StringBuilder.<init> ()V LDC "sum of values was " INVOKEVIRTUAL j/l/StringBuilder.append (Lj/l/String;)Lj/l/StringBuilder; ILOAD 1 INVOKEVIRTUAL j/l/StringBuilder.append (I)Lj/l/StringBuilder; INVOKEVIRTUAL j/l/StringBuilder.toString ()Lj/l/String; INVOKEVIRTUAL j/io/PrintStream.println (Lj/l/String;)V Printstream Ref StringBuilder Value in variable sum What does bytecode look like?
  53. fun printSimpleSum() { val sum = v1() + v2() println("sum

    of values was $sum") } INVOKESTATIC myapp/RunnerKt.v1 ()I INVOKESTATIC myapp/RunnerKt.v2 ()I IADD ISTORE 1 GETSTATIC j/l/System.out : Lj/io/PrintStream; NEW j/l/StringBuilder DUP INVOKESPECIAL j/l/StringBuilder.<init> ()V LDC "sum of values was " INVOKEVIRTUAL j/l/StringBuilder.append (Lj/l/String;)Lj/l/StringBuilder; ILOAD 1 INVOKEVIRTUAL j/l/StringBuilder.append (I)Lj/l/StringBuilder; INVOKEVIRTUAL j/l/StringBuilder.toString ()Lj/l/String; INVOKEVIRTUAL j/io/PrintStream.println (Lj/l/String;)V Printstream Ref StringBuilder Value in variable sum What does bytecode look like?
  54. fun printSimpleSum() { val sum = v1() + v2() println("sum

    of values was $sum") } INVOKESTATIC myapp/RunnerKt.v1 ()I INVOKESTATIC myapp/RunnerKt.v2 ()I IADD ISTORE 1 GETSTATIC j/l/System.out : Lj/io/PrintStream; NEW j/l/StringBuilder DUP INVOKESPECIAL j/l/StringBuilder.<init> ()V LDC "sum of values was " INVOKEVIRTUAL j/l/StringBuilder.append (Lj/l/String;)Lj/l/StringBuilder; ILOAD 1 INVOKEVIRTUAL j/l/StringBuilder.append (I)Lj/l/StringBuilder; INVOKEVIRTUAL j/l/StringBuilder.toString ()Lj/l/String; INVOKEVIRTUAL j/io/PrintStream.println (Lj/l/String;)V Printstream Ref StringBuilder What does bytecode look like?
  55. fun printSimpleSum() { val sum = v1() + v2() println("sum

    of values was $sum") } INVOKESTATIC myapp/RunnerKt.v1 ()I INVOKESTATIC myapp/RunnerKt.v2 ()I IADD ISTORE 1 GETSTATIC j/l/System.out : Lj/io/PrintStream; NEW j/l/StringBuilder DUP INVOKESPECIAL j/l/StringBuilder.<init> ()V LDC "sum of values was " INVOKEVIRTUAL j/l/StringBuilder.append (Lj/l/String;)Lj/l/StringBuilder; ILOAD 1 INVOKEVIRTUAL j/l/StringBuilder.append (I)Lj/l/StringBuilder; INVOKEVIRTUAL j/l/StringBuilder.toString ()Lj/l/String; INVOKEVIRTUAL j/io/PrintStream.println (Lj/l/String;)V Printstream Ref StringBuilder What does bytecode look like?
  56. What does bytecode look like? fun printSimpleSum() { val sum

    = v1() + v2() println("sum of values was $sum") } INVOKESTATIC myapp/RunnerKt.v1 ()I INVOKESTATIC myapp/RunnerKt.v2 ()I IADD ISTORE 1 GETSTATIC j/l/System.out : Lj/io/PrintStream; NEW j/l/StringBuilder DUP INVOKESPECIAL j/l/StringBuilder.<init> ()V LDC "sum of values was " INVOKEVIRTUAL j/l/StringBuilder.append (Lj/l/String;)Lj/l/StringBuilder; ILOAD 1 INVOKEVIRTUAL j/l/StringBuilder.append (I)Lj/l/StringBuilder; INVOKEVIRTUAL j/l/StringBuilder.toString ()Lj/l/String; INVOKEVIRTUAL j/io/PrintStream.println (Lj/l/String;)V Printstream Ref String
  57. What does bytecode look like? fun printSimpleSum() { val sum

    = v1() + v2() println("sum of values was $sum") } INVOKESTATIC myapp/RunnerKt.v1 ()I INVOKESTATIC myapp/RunnerKt.v2 ()I IADD ISTORE 1 GETSTATIC j/l/System.out : Lj/io/PrintStream; NEW j/l/StringBuilder DUP INVOKESPECIAL j/l/StringBuilder.<init> ()V LDC "sum of values was " INVOKEVIRTUAL j/l/StringBuilder.append (Lj/l/String;)Lj/l/StringBuilder; ILOAD 1 INVOKEVIRTUAL j/l/StringBuilder.append (I)Lj/l/StringBuilder; INVOKEVIRTUAL j/l/StringBuilder.toString ()Lj/l/String; INVOKEVIRTUAL j/io/PrintStream.println (Lj/l/String;)V Printstream Ref String
  58. Remember the goal fun prime(n: Int){ println("--->prime(n=$n)") val startTime =

    System.currentTimeMillis() val result = primeNumberSequence.take(n).last() val timeToRun = System.currentTimeMillis() - startTime println("<--- prime[ran in $timeToRun] ms") return result } fun prime(n:Int) = primeSequence.take(n).last()
  59. class CustomClassVisitor(private val classWriter: ClassWriter) : ClassVisitor(ASM5) { override fun

    visitMethod( access: Int, name: String?, desc: String?, signature: String?, exceptions: Array<out String>? ): MethodVisitor { super.visitMethod(access, name, desc, signature, exceptions) TODO("Implement custom method visitor") } } plugin/src/main/kotlin/com/logger/plugin/CustomClassVisitor.kt
  60. object : MethodVisitor(Opcodes.ASM5, mv) { override fun visitCode() { super.visitCode()

    InstructionAdapter(this).apply { TODO("on method entry") } } override fun visitInsn(opcode: Int) { when (opcode) { RETURN, ARETURN, IRETURN -> { InstructionAdapter(this).apply { TODO("on method exit") } } } super.visitInsn(opcode) } } plugin/src/main/kotlin/com/logger/plugin/CustomClassVisitor.kt
  61. object : MethodVisitor(Opcodes.ASM5, mv) { override fun visitCode() { super.visitCode()

    InstructionAdapter(this).apply { TODO("on method entry") } } override fun visitInsn(opcode: Int) { when (opcode) { RETURN, ARETURN, IRETURN -> { InstructionAdapter(this).apply { TODO("on method exit") } } } super.visitInsn(opcode) } } plugin/src/main/kotlin/com/logger/plugin/CustomClassVisitor.kt
  62. InstructionAdapter(this).apply { getstatic("j/l/System","out","Ljava/io/PrintStream;") } Printstream Ref plugin/src/main/kotlin/com/logger/plugin/CustomClassVisitor.kt

  63. InstructionAdapter(this).apply { getstatic("j/l/System","out","Ljava/io/PrintStream;") anew(Type.getObjectType("j/l/StringBuilder")) } Printstream Ref StringBuilder Ref plugin/src/main/kotlin/com/logger/plugin/CustomClassVisitor.kt

  64. InstructionAdapter(this).apply { getstatic("j/l/System","out","Ljava/io/PrintStream;") anew(Type.getObjectType("j/l/StringBuilder")) dup() } Printstream Ref StringBuilder Ref

    StringBuilder Ref plugin/src/main/kotlin/com/logger/plugin/CustomClassVisitor.kt
  65. InstructionAdapter(this).apply { getstatic("j/l/System","out","Ljava/io/PrintStream;") anew(Type.getObjectType("j/l/StringBuilder")) dup() invokespecial("j/l/StringBuilder","<init>","()V") } Printstream Ref plugin/src/main/kotlin/com/logger/plugin/CustomClassVisitor.kt

    StringBuilder Ref StringBuilder Ref
  66. InstructionAdapter(this).apply { getstatic("j/l/System","out","Ljava/io/PrintStream;") anew(Type.getObjectType("j/l/StringBuilder")) dup() invokespecial("j/l/StringBuilder","<init>","()V") visitLdcInsn("---> ${function.name}(") } Printstream

    Ref StringBuilder Ref “---> prime(” plugin/src/main/kotlin/com/logger/plugin/CustomClassVisitor.kt
  67. InstructionAdapter(this).apply { getstatic("j/l/System","out","Ljava/io/PrintStream;") anew(Type.getObjectType("j/l/StringBuilder")) dup() invokespecial("j/l/StringBuilder","<init>","()V") visitLdcInsn("---> $name(") invokevirtual("j/l/StringBuilder","append", "(Lj/l/Object;)Lj/l/StringBuilder;")

    } Printstream Ref plugin/src/main/kotlin/com/logger/plugin/CustomClassVisitor.kt StringBuilder Ref “---> prime(”
  68. InstructionAdapter(this).apply { getstatic("j/l/System","out","Ljava/io/PrintStream;") anew(Type.getObjectType("j/l/StringBuilder")) dup() invokespecial("j/l/StringBuilder","<init>","()V") visitLdcInsn("---> $name(") invokevirtual("j/l/StringBuilder","append", "(Lj/l/Object;)Lj/l/StringBuilder;")

    } Printstream Ref StringBuilder Ref plugin/src/main/kotlin/com/logger/plugin/CustomClassVisitor.kt
  69. InstructionAdapter(this).apply { getstatic("j/l/System","out","Ljava/io/PrintStream;") anew(Type.getObjectType("j/l/StringBuilder")) dup() invokespecial("j/l/StringBuilder","<init>","()V") visitLdcInsn("---> $name(") invokevirtual("j/l/StringBuilder","append", "(Lj/l/Object;)Lj/l/StringBuilder;")

    function.valueParamters.forEachIndexed { i, param -> visitLdcInsn(" ${param.name}=") invokevirtual("j/l/SB", "append", "(Lj/l/String;)L/j/SB;") visitVarInsn(ALOAD,i + 1) invokevirtual("j/l/SB", "append", "(Lj/l/String;)L/j/SB;") } } Printstream Ref StringBuilder Ref plugin/src/main/kotlin/com/logger/plugin/CustomClassVisitor.kt
  70. InstructionAdapter(this).apply { getstatic("j/l/System","out","Ljava/io/PrintStream;") anew(Type.getObjectType("j/l/StringBuilder")) dup() invokespecial("j/l/StringBuilder","<init>","()V") visitLdcInsn("---> $name(") invokevirtual("j/l/StringBuilder","append", "(Lj/l/Object;)Lj/l/StringBuilder;")

    function.valueParamters.forEachIndexed { i, param -> visitLdcInsn(" ${paran.name}=") invokevirtual("j/l/SB", "append", "(Lj/l/String;)L/j/SB;") visitVarInsn(ALOAD,i + 1) invokevirtual("j/l/SB", "append", "(Lj/l/String;)L/j/SB;") } } Printstream Ref StringBuilder Ref “ n=” plugin/src/main/kotlin/com/logger/plugin/CustomClassVisitor.kt
  71. InstructionAdapter(this).apply { getstatic("j/l/System","out","Ljava/io/PrintStream;") anew(Type.getObjectType("j/l/StringBuilder")) dup() invokespecial("j/l/StringBuilder","<init>","()V") visitLdcInsn("---> $name(") invokevirtual("j/l/StringBuilder","append", "(Lj/l/Object;)Lj/l/StringBuilder;")

    function.valueParamters.forEachIndexed { i, param -> visitLdcInsn(" ${paran.name}=") invokevirtual("j/l/SB", "append", "(Lj/l/String;)L/j/SB;") visitVarInsn(ALOAD,i + 1) invokevirtual("j/l/SB", "append", "(Lj/l/String;)L/j/SB;") } } Printstream Ref plugin/src/main/kotlin/com/logger/plugin/CustomClassVisitor.kt StringBuilder Ref “ n=”
  72. InstructionAdapter(this).apply { getstatic("j/l/System","out","Ljava/io/PrintStream;") anew(Type.getObjectType("j/l/StringBuilder")) dup() invokespecial("j/l/StringBuilder","<init>","()V") visitLdcInsn("---> $name(") invokevirtual("j/l/StringBuilder","append", "(Lj/l/Object;)Lj/l/StringBuilder;")

    function.valueParamters.forEachIndexed { i, param -> visitLdcInsn(" ${paran.name}=") invokevirtual("j/l/SB", "append", "(Lj/l/String;)L/j/SB;") visitVarInsn(ALOAD,i + 1) invokevirtual("j/l/SB", "append", "(Lj/l/String;)L/j/SB;") } } Printstream Ref StringBuilder Ref plugin/src/main/kotlin/com/logger/plugin/CustomClassVisitor.kt
  73. InstructionAdapter(this).apply { getstatic("j/l/System","out","Ljava/io/PrintStream;") anew(Type.getObjectType("j/l/StringBuilder")) dup() invokespecial("j/l/StringBuilder","<init>","()V") visitLdcInsn("---> $name(") invokevirtual("j/l/StringBuilder","append", "(Lj/l/Object;)Lj/l/StringBuilder;")

    function.valueParamters.forEachIndexed { i, param -> visitLdcInsn(" ${paran.name}=") invokevirtual("j/l/SB", "append", "(Lj/l/String;)L/j/SB;") visitVarInsn(ALOAD,i + 1) invokevirtual("j/l/SB", "append", "(Lj/l/String;)L/j/SB;") } } Printstream Ref StringBuilder Ref Value of n plugin/src/main/kotlin/com/logger/plugin/CustomClassVisitor.kt
  74. InstructionAdapter(this).apply { getstatic("j/l/System","out","Ljava/io/PrintStream;") anew(Type.getObjectType("j/l/StringBuilder")) dup() invokespecial("j/l/StringBuilder","<init>","()V") visitLdcInsn("---> $name(") invokevirtual("j/l/StringBuilder","append", "(Lj/l/Object;)Lj/l/StringBuilder;")

    function.valueParamters.forEachIndexed { i, param -> visitLdcInsn(" ${paran.name}=") invokevirtual("j/l/SB", "append", "(Lj/l/String;)L/j/SB;") visitVarInsn(ALOAD,i + 1) invokevirtual("j/l/SB", "append", "(Lj/l/String;)L/j/SB;") } } Printstream Ref plugin/src/main/kotlin/com/logger/plugin/CustomClassVisitor.kt StringBuilder Ref Value of n
  75. InstructionAdapter(this).apply { getstatic("j/l/System","out","Ljava/io/PrintStream;") anew(Type.getObjectType("j/l/StringBuilder")) dup() invokespecial("j/l/StringBuilder","<init>","()V") visitLdcInsn("---> $name(") invokevirtual("j/l/StringBuilder","append", "(Lj/l/Object;)Lj/l/StringBuilder;")

    function.valueParamters.forEachIndexed { i, param -> visitLdcInsn(" ${paran.name}=") invokevirtual("j/l/SB", "append", "(Lj/l/String;)L/j/SB;") visitVarInsn(ALOAD,i + 1) invokevirtual("j/l/SB", "append", "(Lj/l/String;)L/j/SB;") } } Printstream Ref StringBuilder Ref plugin/src/main/kotlin/com/logger/plugin/CustomClassVisitor.kt
  76. InstructionAdapter(this).apply { getstatic("j/l/System","out","Ljava/io/PrintStream;") anew(Type.getObjectType("j/l/StringBuilder")) dup() invokespecial("j/l/StringBuilder","<init>","()V") visitLdcInsn("---> $name(") invokevirtual("j/l/StringBuilder","append", "(Lj/l/Object;)Lj/l/StringBuilder;")

    function.valueParamters.forEachIndexed { i, param -> visitLdcInsn(" ${paran.name}=") invokevirtual("j/l/SB", "append", "(Lj/l/String;)L/j/SB;") visitVarInsn(ALOAD,i + 1) invokevirtual("j/l/SB", "append", "(Lj/l/String;)L/j/SB;") } invokevirtual("j/l/StringBuilder","toString","(L/j/l/String;)V") } Printstream Ref plugin/src/main/kotlin/com/logger/plugin/CustomClassVisitor.kt StringBuilder Ref
  77. InstructionAdapter(this).apply { getstatic("j/l/System","out","Ljava/io/PrintStream;") anew(Type.getObjectType("j/l/StringBuilder")) dup() invokespecial("j/l/StringBuilder","<init>","()V") visitLdcInsn("---> $name(") invokevirtual("j/l/StringBuilder","append", "(Lj/l/Object;)Lj/l/StringBuilder;")

    function.valueParamters.forEachIndexed { i, param -> visitLdcInsn(" ${paran.name}=") invokevirtual("j/l/SB", "append", "(Lj/l/String;)L/j/SB;") visitVarInsn(ALOAD,i + 1) invokevirtual("j/l/SB", "append", "(Lj/l/String;)L/j/SB;") } invokevirtual("j/l/StringBuilder","toString","(L/j/l/String;)V") } Printstream Ref String plugin/src/main/kotlin/com/logger/plugin/CustomClassVisitor.kt
  78. InstructionAdapter(this).apply { getstatic("j/l/System","out","Ljava/io/PrintStream;") anew(Type.getObjectType("j/l/StringBuilder")) dup() invokespecial("j/l/StringBuilder","<init>","()V") visitLdcInsn("---> $name(") invokevirtual("j/l/StringBuilder","append", "(Lj/l/Object;)Lj/l/StringBuilder;")

    function.valueParamters.forEachIndexed { i, param -> visitLdcInsn(" ${paran.name}=") invokevirtual("j/l/SB", "append", "(Lj/l/String;)L/j/SB;") visitVarInsn(ALOAD,i + 1) invokevirtual("j/l/SB", "append", "(Lj/l/String;)L/j/SB;") } invokevirtual("j/l/StringBuilder","toString","(L/j/l/String;)V") invokevirtual("j/io/PrintStream","println","(L/j/l/String;)V") } plugin/src/main/kotlin/com/logger/plugin/CustomClassVisitor.kt Printstream Ref String
  79. InstructionAdapter(this).apply { -/ method trace printing code invokestatic("j/l/System","currentTimeMillis","()J") store(2, LONG_TYPE)

    } Value of currentTimeMillis plugin/src/main/kotlin/com/logger/plugin/CustomClassVisitor.kt
  80. InstructionAdapter(this).apply { -/ method trace printing code invokestatic("j/l/System","currentTimeMillis","()J") store(2, LONG_TYPE)

    } plugin/src/main/kotlin/com/logger/plugin/CustomClassVisitor.kt Value of currentTimeMillis
  81. object : MethodVisitor(Opcodes.ASM5, mv) { override fun visitCode() { super.visitCode()

    InstructionAdapter(this).apply { TODO("on method entry") } } override fun visitInsn(opcode: Int) { when (opcode) { RETURN, ARETURN, IRETURN -> { InstructionAdapter(this).apply { TODO("on method exit") } } } super.visitInsn(opcode) } } plugin/src/main/kotlin/com/logger/plugin/CustomClassVisitor.kt
  82. InstructionAdapter(this).apply { getstatic("j/l/System","out","Ljava/io/PrintStream;") } Printstream Ref plugin/src/main/kotlin/com/logger/plugin/CustomClassVisitor.kt

  83. InstructionAdapter(this).apply { getstatic("j/l/System","out","Ljava/io/PrintStream;") anew(Type.getObjectType("j/l/StringBuilder")) } Printstream Ref StringBuilder Ref plugin/src/main/kotlin/com/logger/plugin/CustomClassVisitor.kt

  84. InstructionAdapter(this).apply { getstatic("j/l/System","out","Ljava/io/PrintStream;") anew(Type.getObjectType("j/l/StringBuilder")) dup() } Printstream Ref StringBuilder Ref

    StringBuilder Ref plugin/src/main/kotlin/com/logger/plugin/CustomClassVisitor.kt
  85. InstructionAdapter(this).apply { getstatic("j/l/System","out","Ljava/io/PrintStream;") anew(Type.getObjectType("j/l/StringBuilder")) dup() invokespecial("j/l/StringBuilder","<init>","()V") } Printstream Ref StringBuilder

    Ref plugin/src/main/kotlin/com/logger/plugin/CustomClassVisitor.kt StringBuilder Ref
  86. InstructionAdapter(this).apply { getstatic("j/l/System","out","Ljava/io/PrintStream;") anew(Type.getObjectType("j/l/StringBuilder")) dup() invokespecial("j/l/StringBuilder","<init>","()V") visitLdcInsn("--- ${function.name}(") } Printstream

    Ref StringBuilder Ref “--- prime [ran in” plugin/src/main/kotlin/com/logger/plugin/CustomClassVisitor.kt
  87. InstructionAdapter(this).apply { getstatic("j/l/System","out","Ljava/io/PrintStream;") anew(Type.getObjectType("j/l/StringBuilder")) dup() invokespecial("j/l/StringBuilder","<init>","()V") visitLdcInsn("---> $function.name(") invokevirtual("j/l/StringBuilder","append", "(Lj/l/Object;)Lj/l/StringBuilder;")

    } Printstream Ref plugin/src/main/kotlin/com/logger/plugin/CustomClassVisitor.kt StringBuilder Ref “--- prime [ran in”
  88. InstructionAdapter(this).apply { getstatic("j/l/System","out","Ljava/io/PrintStream;") anew(Type.getObjectType("j/l/StringBuilder")) dup() invokespecial("j/l/StringBuilder","<init>","()V") visitLdcInsn("---> $function.name(") invokevirtual("j/l/StringBuilder","append", "(Lj/l/Object;)Lj/l/StringBuilder;")

    } Printstream Ref StringBuilder Ref plugin/src/main/kotlin/com/logger/plugin/CustomClassVisitor.kt
  89. InstructionAdapter(this).apply{ getstatic("j/l/System", "out", "Lj/io/PrintStream;") anew("java/lang/StringBuilder") dup() invokespecial("j/l/StringBuilder", "<init>", "()V") visitLdcInsn("⇠

    ${function.name} [ran in ") invokevirtual("j/l/StringBuilder", "append", "(Lj/l/String;)Lj/l/StringBuilder;") invokestatic("j/l/System", "currentTimeMillis", "()J") } Printstream Ref StringBuilder Ref Value of currentTimeMillis plugin/src/main/kotlin/com/logger/plugin/CustomClassVisitor.kt
  90. InstructionAdapter(this).apply{ getstatic("j/l/System", "out", "Lj/io/PrintStream;") anew("java/lang/StringBuilder") dup() invokespecial("j/l/StringBuilder", "<init>", "()V") visitLdcInsn("⇠

    ${function.name} [ran in ") invokevirtual("j/l/StringBuilder", "append", "(Lj/l/String;)Lj/l/StringBuilder;") invokestatic("j/l/System", "currentTimeMillis", "()J") load(2, LONG_TYPE) } Printstream Ref StringBuilder Ref Value of currentTimeMillis Start Time plugin/src/main/kotlin/com/logger/plugin/CustomClassVisitor.kt
  91. InstructionAdapter(this).apply{ getstatic("j/l/System", "out", "Lj/io/PrintStream;") anew("java/lang/StringBuilder") dup() invokespecial("j/l/StringBuilder", "<init>", "()V") visitLdcInsn("⇠

    ${function.name} [ran in ") invokevirtual("j/l/StringBuilder", "append", "(Lj/l/String;)Lj/l/StringBuilder;") invokestatic("j/l/System", "currentTimeMillis", "()J") load(2, LONG_TYPE) sub(LONG_TYPE) } Printstream Ref StringBuilder Ref plugin/src/main/kotlin/com/logger/plugin/CustomClassVisitor.kt Value of currentTimeMillis Start Time
  92. InstructionAdapter(this).apply{ getstatic("j/l/System", "out", "Lj/io/PrintStream;") anew("java/lang/StringBuilder") dup() invokespecial("j/l/StringBuilder", "<init>", "()V") visitLdcInsn("⇠

    ${function.name} [ran in ") invokevirtual("j/l/StringBuilder", "append", "(Lj/l/String;)Lj/l/StringBuilder;") invokestatic("j/l/System", "currentTimeMillis", "()J") load(2, LONG_TYPE) sub(LONG_TYPE) } Printstream Ref StringBuilder Ref (Current - Start) time plugin/src/main/kotlin/com/logger/plugin/CustomClassVisitor.kt
  93. InstructionAdapter(this).apply{ getstatic("j/l/System", "out", "Lj/io/PrintStream;") anew("java/lang/StringBuilder") dup() invokespecial("j/l/StringBuilder", "<init>", "()V") visitLdcInsn("⇠

    ${function.name} [ran in ") invokevirtual("j/l/StringBuilder", "append", "(Lj/l/String;)Lj/l/StringBuilder;") invokestatic("j/l/System", "currentTimeMillis", "()J") load(2, LONG_TYPE) sub(LONG_TYPE) invokevirtual("j/l/StringBuilder", "append", "(J)Lj/l/SB;") } Printstream Ref plugin/src/main/kotlin/com/logger/plugin/CustomClassVisitor.kt StringBuilder Ref (Current - Start) time
  94. InstructionAdapter(this).apply{ getstatic("j/l/System", "out", "Lj/io/PrintStream;") anew("java/lang/StringBuilder") dup() invokespecial("j/l/StringBuilder", "<init>", "()V") visitLdcInsn("⇠

    ${function.name} [ran in ") invokevirtual("j/l/StringBuilder", "append", "(Lj/l/String;)Lj/l/StringBuilder;") invokestatic("j/l/System", "currentTimeMillis", "()J") load(2, LONG_TYPE) sub(LONG_TYPE) invokevirtual("j/l/StringBuilder", "append", "(J)Lj/l/SB;") } Printstream Ref StringBuilder Ref plugin/src/main/kotlin/com/logger/plugin/CustomClassVisitor.kt
  95. InstructionAdapter(this).apply{ getstatic("j/l/System", "out", "Lj/io/PrintStream;") anew("java/lang/StringBuilder") dup() invokespecial("j/l/StringBuilder", "<init>", "()V") visitLdcInsn("⇠

    ${function.name} [ran in ") invokevirtual("j/l/StringBuilder", "append", "(Lj/l/String;)Lj/l/StringBuilder;") invokestatic("j/l/System", "currentTimeMillis", "()J") load(2, LONG_TYPE) sub(LONG_TYPE) invokevirtual("j/l/StringBuilder", "append", "(J)Lj/l/SB;") visitLdcInsn(" ms]") } Printstream Ref StringBuilder Ref “ ms]” plugin/src/main/kotlin/com/logger/plugin/CustomClassVisitor.kt
  96. InstructionAdapter(this).apply{ getstatic("j/l/System", "out", "Lj/io/PrintStream;") anew("java/lang/StringBuilder") dup() invokespecial("j/l/StringBuilder", "<init>", "()V") visitLdcInsn("⇠

    ${function.name} [ran in ") invokevirtual("j/l/StringBuilder", "append", "(Lj/l/String;)Lj/l/StringBuilder;") invokestatic("j/l/System", "currentTimeMillis", "()J") load(2, LONG_TYPE) sub(LONG_TYPE) invokevirtual("j/l/StringBuilder", "append", "(J)Lj/l/SB;") visitLdcInsn(" ms]") invokevirtual("j/l/StringBuilder", "append", "(Lj/l/String;)Lj/l/SB;") } Printstream Ref plugin/src/main/kotlin/com/logger/plugin/CustomClassVisitor.kt StringBuilder Ref “ ms]”
  97. InstructionAdapter(this).apply{ getstatic("j/l/System", "out", "Lj/io/PrintStream;") anew("java/lang/StringBuilder") dup() invokespecial("j/l/StringBuilder", "<init>", "()V") visitLdcInsn("⇠

    ${function.name} [ran in ") invokevirtual("j/l/StringBuilder", "append", "(Lj/l/String;)Lj/l/StringBuilder;") invokestatic("j/l/System", "currentTimeMillis", "()J") load(2, LONG_TYPE) sub(LONG_TYPE) invokevirtual("j/l/StringBuilder", "append", "(J)Lj/l/SB;") visitLdcInsn(" ms]") invokevirtual("j/l/StringBuilder", "append", "(Lj/l/String;)Lj/l/SB;") } Printstream Ref StringBuilder Ref plugin/src/main/kotlin/com/logger/plugin/CustomClassVisitor.kt
  98. InstructionAdapter(this).apply{ getstatic("j/l/System", "out", "Lj/io/PrintStream;") anew("java/lang/StringBuilder") dup() invokespecial("j/l/StringBuilder", "<init>", "()V") visitLdcInsn("⇠

    ${function.name} [ran in ") invokevirtual("j/l/StringBuilder", "append", "(Lj/l/String;)Lj/l/StringBuilder;") invokestatic("j/l/System", "currentTimeMillis", "()J") load(2, LONG_TYPE) sub(LONG_TYPE) invokevirtual("j/l/StringBuilder", "append", "(J)Lj/l/SB;") visitLdcInsn(" ms]") invokevirtual("j/l/StringBuilder", "append", "(Lj/l/String;)Lj/l/SB;") invokevirtual("j/l/StringBuilder", "toString", "()Lj/l/String;") } Printstream Ref plugin/src/main/kotlin/com/logger/plugin/CustomClassVisitor.kt StringBuilder Ref
  99. InstructionAdapter(this).apply{ getstatic("j/l/System", "out", "Lj/io/PrintStream;") anew("java/lang/StringBuilder") dup() invokespecial("j/l/StringBuilder", "<init>", "()V") visitLdcInsn("⇠

    ${function.name} [ran in ") invokevirtual("j/l/StringBuilder", "append", "(Lj/l/String;)Lj/l/StringBuilder;") invokestatic("j/l/System", "currentTimeMillis", "()J") load(2, LONG_TYPE) sub(LONG_TYPE) invokevirtual("j/l/StringBuilder", "append", "(J)Lj/l/SB;") visitLdcInsn(" ms]") invokevirtual("j/l/StringBuilder", "append", "(Lj/l/String;)Lj/l/SB;") invokevirtual("j/l/StringBuilder", "toString", "()Lj/l/String;") } Printstream Ref String plugin/src/main/kotlin/com/logger/plugin/CustomClassVisitor.kt
  100. InstructionAdapter(this).apply{ getstatic("j/l/System", "out", "Lj/io/PrintStream;") anew("java/lang/StringBuilder") dup() invokespecial("j/l/StringBuilder", "<init>", "()V") visitLdcInsn("⇠

    ${function.name} [ran in ") invokevirtual("j/l/StringBuilder", "append", "(Lj/l/String;)Lj/l/StringBuilder;") invokestatic("j/l/System", "currentTimeMillis", "()J") load(2, LONG_TYPE) sub(LONG_TYPE) invokevirtual("j/l/StringBuilder", "append", "(J)Lj/l/SB;") visitLdcInsn(" ms]") invokevirtual("j/l/StringBuilder", "append", "(Lj/l/String;)Lj/l/SB;") invokevirtual("j/l/StringBuilder", "toString", "()Lj/l/String;") invokevirtual("j/io/PrintStream", "println", "(Lj/l/String;)V") } plugin/src/main/kotlin/com/logger/plugin/CustomClassVisitor.kt Printstream Ref String
  101. Resources • Transform API Documentation • Github • Hunter Samples

    • KotlinConf Talks - Writing you First Kotlin Compiler Plugin • https://www.baeldung.com/java-asm • https://dzone.com/articles/introduction-to-java-bytecode