Kotlin Compiler V2

Kotlin Compiler V2

Магия расширений компилятора Kotlin Или текущее положение вещей в мире плагинов компилятора и как нам с этим жить Andrei Shikov 1 fun main() { 0010100x . } 2 fun main() { ? PR0F1Tx . } 3 fun main() { ? PR0F1Tx . } gcc -Wall -O3 test.cc -o test 4 fun main() { 0010100x . } 5 Andrei does 6 Andrei loves 7 APT vs Plugins Структура компилятора Плагины на примерах 8 APT vs Plugins Структура компилятора Плагины на примерах 9 Java APT Kotlin plugins .java .kt 10 Java APT Kotlin plugins stubs .kt .java .java .kt processor compiler plugin 11 Java APT Kotlin plugins stubs .kt .java .java .kt processor compiler plugin 0010100x . 12 Java APT Kotlin plugins stubs .kt .java .java .kt processor compiler plugin 0010100x . 13 Java APT Kotlin plugins stubs .kt .java .java .kt processor compiler plugin / 0010100x . * стабильное api * документация * / ¯\_(ツ)_/¯ * 14 kapt = generate java stubs → java apt → compile plugin = compile 15 Преимущества плагинов Multiplatform Изменение кода Больше возможностей 16 APT vs Plugins Структура компилятора Плагины на примерах 17 fun main() { 0010100x . } 18 JVM fun main() { JSx } Native 19 Compiler Frontend Backend 20 Compiler Frontend Backend Process Validate Structure 21 Compiler Frontend Backend Process внутреннее Optimize представление Validate Generate Structure 22 class Test { fun example() { } } 23 PSI KtFile KtClass KtClassBody "Test" class Test { fun example() { } } KtFunction "example" KtBlockExpression 24 PSI KtFile KtClass KtClassBody "Test" class Test { fun example() { } } KtFunction "example" KtBlockExpression 25 PSI KtFile KtClass KtClassBody "Test" class Test { fun example() { } } KtFunction "example" KtBlockExpression 26 Descriptors KtFile KtClass KtClassBody "Test" KtFunction class Test { fun example() { "example" KtBlockExpression println("Hello") } KtCallExpression } println KtValueArgument "Hello" 27 Descriptors KtFile KtClass KtClassBody "Test" Module KtFunction PackageFragment "example" KtBlockExpression -Descriptor KtCallExpression Class Function println KtValueArgument "Hello" 28 Descriptors module Module com company PackageFragment package -Descriptor MyClass.kt Class Function Variable 29 KtFile KtClass KtClassBody "Test" KtFunction class Test { fun example() { "example" KtBlockExpression println("Hello") } KtCallExpression } println KtValueArgument "Hello" ResolvedCall FunctionDescriptor Parameters 30 BindingContext KtFunction KtCallExpression FunctionDescriptor ResolvedCall FunctionDescriptor Parameters 31 Compiler Frontend Backend Analyze Generate 32 Compiler Backend JVM JS Native 33 Compiler Backend JVM JS Native IR ASM Custom LLVM 1.3.72 34 Compiler Backend IR JVM JS Native ASM Custom LLVM 1.4 35 IR IrModuleFragment IrFile IrClass class Test { fun example() { } IrFunction } IrBody IrExpression 36 IrModuleFragment IR IrFile IrClass IrClassSymbol СlassDescriptor IrFunction IrFunctionSymbol FunctionDescriptor IrBody IrExpression 37 IR PSI IR lowering lowerloweringing } оптимизации Bytecode 38 IR PSI IR extension lowering lowerloweringing } оптимизации Bytecode 39 APT vs Plugins Структура компилятора Плагины на примерах 40 Экспериментальное API 41 compileKotlin { kotlinOptions { freeCompilerArgs += ["-Xplugin=your_plugin.jar"] } } 42 compileKotlin { kotlinOptions { freeCompilerArgs += ["-Xplugin=your_plugin.jar"] } } / OR dependencies { kotlinCompilerPluginClasspath 'your-plugin' kotlinNativeCompilerPluginClasspath 'your-plugin' } 43 @AutoService(ComponentRegistrar:class) class MyPlugin : ComponentRegistrar { override fun registerProjectComponents( project: MockProject, configuration: CompilerConfiguration ) { } } 44 @AutoService(CommandLineProcessor:class) class MyCLProcessor : CommandLineProcessor { override val pluginId: String = "me.test" override val pluginOptions = listOf(TEST_OPTION) companion object { val TEST_OPTION = CliOption( optionName = "testOption", valueDescription = "<path>", description = "My test option", required = true, allowMultipleOccurrences = false ) } } -P plugin:${pluginId}:${optionName}=<value> 45 @AutoService(CommandLineProcessor:class) class MyCLProcessor : CommandLineProcessor { . override fun processOption( option: AbstractCliOption, value: String, configuration: CompilerConfiguration ) { if (option = TEST_OPTION) { configuration.put(MY_KEY, File(option.value)) } } companion object { val MY_KEY = CompilerConfigurationKey.create<File>("myKey") } } 46 open class ProjectExtensionDescriptor<T> { fun registerExtension( project: Project, extension: T ) } interface SomeExtension { companion object : ProjectExtensionDescriptor<SomeExtension>() } 47 interface SomeExtension { companion object : ProjectExtensionDescriptor<SomeExtension>() } class MyPlugin : ComponentRegistrar { override fun registerProjectComponents( project: MockProject, configuration: CompilerConfiguration ) { SomeExtension.registerExtension( project, SomeExtensionImpl(сonfiguration[MY_KEY]) ) } } 48 Примеры kotlinx-serialization compose kapt in compiler 49 kotlinx-serialization compose kapt in compiler 50 @Serializable data class Data(val a: Int, val b: String = "42") 51 @Serializable data class Data(val a: Int, val b: String = "42") { companion object { fun serializer(): KSerializer<Data> = $serializer } @Deprecated(level = DeprecationLevel.HIDDEN) object $serializer : GeneratedSerializer<Data> { override fun childSerializers(): Array<KSerializer<> = arrayOf(IntSerializer, StringSerializer) override fun serialize() = . } } 52 Add serializer Validate it is correct Generate serializer code ExpressionCodegen SyntheticResolve DeclarationChecker IrGeneration JsSyntheticTranslate 53 Add serializer Validate it is correct Generate serializer code ExpressionCodegen SyntheticResolve DeclarationChecker IrGeneration JsSyntheticTranslate 54 SyntheticResolve Descriptor PSI Binary ResolvedCall Analyze Generate SyntheticResolveExtension 55 interface SyntheticResolveExtension { fun getSyntheticNestedClassNames(thisDescriptor: ClassDescriptor): List<Name> fun generateSyntheticClasses( thisDescriptor: ClassDescriptor, name: Name, . result: MutableSet<ClassDescriptor> ) { } fun getSyntheticFunctionNames(thisDescriptor: ClassDescriptor): List<Name> fun generateSyntheticMethods( thisDescriptor: ClassDescriptor, name: Name, . result: MutableSet<SimpleFunctionDescriptor> ) { } . } 56 @Serializable data class Data(val a: Int, val b: String = "42") { / generated companion object { fun serializer(): KSerializer<Data> = $serializer } private object $serializer : KSerializer<Data> { . } } 57 / companion object { / fun serializer(): KSerializer<Data> / } class SerializationResolveExtension : SyntheticResolveExtension { override fun getSyntheticFunctionNames(thisDescriptor: ClassDescriptor): List<Name> = if (thisDescriptor.isCompanionObject & thisDescriptor.isSerializableCompanion) { listOf(Name.identifier("serializer")) } else { emptyList() } } 58 / companion object { / fun serializer(): KSerializer<Data> / } class SerializationResolveExtension : SyntheticResolveExtension { override fun getSyntheticFunctionNames(thisDescriptor: ClassDescriptor): List<Name> = if (thisDescriptor.isCompanionObject & thisDescriptor.isSerializableCompanion) { listOf(Name.identifier("serializer")) } else { emptyList() } val ClassDescriptor.isSerializableCompanion get() = isCompanionObject & (containingDeclaration as ClassDescriptor).hasSerializableAnnotation val ClassDescriptor.hasSerializableAnnotation get() = hasAnnotation(FqName("kotlinx.serialization.Serializable")) } 59 / companion object { / fun serializer(): KSerializer<Data> / } class SerializationResolveExtension : SyntheticResolveExtension { override fun generateSyntheticMethods( thisDescriptor: ClassDescriptor, name: Name, bindingContext: BindingContext, fromSupertypes: List<SimpleFunctionDescriptor>, result: MutableCollection<SimpleFunctionDescriptor> ) { val classDescriptor = getSerializableForCompanion(thisDescriptor) ? return if (name.asString() = "serializer") { result.add(createSerializerGetterDescriptor(thisDescriptor, classDescriptor)) } } } 60 / companion object { / fun serializer(): KSerializer<Data> / } fun createSerializerGetterDescriptor( companionClass: ClassDescriptor, serializableClass: ClassDescriptor ): SimpleFunctionDescriptor { val f = SimpleFunctionDescriptorImpl.create( . ) val returnType = . f.initialize( . ) return f } 61 / companion object { / fun serializer(): KSerializer<Data> / } private fun createSerializerGetterDescriptor( companionClass: ClassDescriptor, serializableClass: ClassDescriptor ): SimpleFunctionDescriptor { val f = SimpleFunctionDescriptorImpl.create( companionClass, Annotations.EMPTY, Name.identifier("serializer"), CallableMemberDescriptor.Kind.SYNTHESIZED, companionClass.source ) val returnType = . f.initialize( . ) return f } 62 / fun serializer(): KSerializer<Data> private fun createSerializerGetterDescriptor( companionClass: ClassDescriptor, serializableClass: ClassDescriptor ): SimpleFunctionDescriptor { val f = SimpleFunctionDescriptorImpl.create(.) val returnType = KotlinTypeFactory.simpleNotNullType(.) / KSerializer<Data> f.initialize( / extensionReceiver * null, / dispatcherReceiver * companionClass.thisAsReceiverParameter, / typeArgs * emptyList(), / valueArgs * emptyList(), returnType, Modality.FINAL, Visibilities.PUBLIC ) return f } 63 Add serializer Validate it is correct Generate serializer code ExpressionCodegen SyntheticResolve DeclarationChecker IrGeneration JsSyntheticTranslate 64 Add serializer Validate it is correct Generate serializer code ExpressionCodegen SyntheticResolve DeclarationChecker IrGeneration JsSyntheticTranslate

View Full Text

Details

  • File Type
    pdf
  • Upload Time
    -
  • Content Languages
    English
  • Upload User
    Anonymous/Not logged-in
  • File Pages
    148 Page
  • File Size
    -

Download

Channel Download Status
Express Download Enable

Copyright

We respect the copyrights and intellectual property rights of all users. All uploaded documents are either original works of the uploader or authorized works of the rightful owners.

  • Not to be reproduced or distributed without explicit permission.
  • Not used for commercial purposes outside of approved use cases.
  • Not used to infringe on the rights of the original creators.
  • If you believe any content infringes your copyright, please contact us immediately.

Support

For help with questions, suggestions, or problems, please contact us