diff --git a/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2Native.kt b/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2Native.kt index 342d30290c2..c0204c3242d 100644 --- a/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2Native.kt +++ b/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2Native.kt @@ -123,6 +123,7 @@ class K2Native : CLICompiler() { put(OPTIMIZATION, arguments.optimization) put(PRINT_IR, arguments.printIr) + put(PRINT_IR_WITH_DESCRIPTORS, arguments.printIrWithDescriptors) put(PRINT_DESCRIPTORS, arguments.printDescriptors) put(PRINT_LOCATIONS, arguments.printLocations) put(PRINT_BITCODE, arguments.printBitCode) diff --git a/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2NativeCompilerArguments.java b/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2NativeCompilerArguments.java index 4b60934736d..df6f90a6805 100644 --- a/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2NativeCompilerArguments.java +++ b/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2NativeCompilerArguments.java @@ -73,6 +73,9 @@ public class K2NativeCompilerArguments extends CommonCompilerArguments { @Argument(value = "print_ir", prefix = "--", description = "Print IR") public boolean printIr; + @Argument(value = "print_ir_with_descriptors", prefix = "--", description = "Print IR with descriptors") + public boolean printIrWithDescriptors; + @Argument(value = "print_descriptors", prefix = "--", description = "Print descriptor tree") public boolean printDescriptors; diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Context.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Context.kt index 15df0745b89..dda241973f9 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Context.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Context.kt @@ -21,6 +21,7 @@ import llvm.LLVMModuleRef import org.jetbrains.kotlin.backend.common.validateIrModule import org.jetbrains.kotlin.backend.jvm.descriptors.initialize import org.jetbrains.kotlin.backend.konan.descriptors.* +import org.jetbrains.kotlin.backend.konan.ir.DumpIrTreeWithDescriptorsVisitor import org.jetbrains.kotlin.backend.konan.ir.Ir import org.jetbrains.kotlin.backend.konan.llvm.Llvm import org.jetbrains.kotlin.backend.konan.llvm.LlvmDeclarations @@ -300,6 +301,12 @@ internal class Context(config: KonanConfig) : KonanBackendContext(config) { irModule!!.accept(DumpIrTreeVisitor(out), "") } + fun printIrWithDescriptors() { + if (irModule == null) return + separator("IR after: ${phase?.description}") + irModule!!.accept(DumpIrTreeWithDescriptorsVisitor(out), "") + } + fun printLocations() { if (irModule == null) return separator("Locations after: ${phase?.description}") @@ -383,6 +390,10 @@ internal class Context(config: KonanConfig) : KonanBackendContext(config) { return config.configuration.getBoolean(KonanConfigKeys.PRINT_IR) } + fun shouldPrintIrWithDescriptors(): Boolean { + return config.configuration.getBoolean(KonanConfigKeys.PRINT_IR_WITH_DESCRIPTORS) + } + fun shouldPrintBitCode(): Boolean { return config.configuration.getBoolean(KonanConfigKeys.PRINT_BITCODE) } diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfigurationKeys.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfigurationKeys.kt index 2ab36273aca..1be35be19f6 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfigurationKeys.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfigurationKeys.kt @@ -66,7 +66,9 @@ class KonanConfigKeys { val PRINT_IR: CompilerConfigurationKey = CompilerConfigurationKey.create("print ir") - val PRINT_DESCRIPTORS: CompilerConfigurationKey + val PRINT_IR_WITH_DESCRIPTORS: CompilerConfigurationKey + = CompilerConfigurationKey.create("print ir with descriptors") + val PRINT_DESCRIPTORS: CompilerConfigurationKey = CompilerConfigurationKey.create("print descriptors") val PRINT_BITCODE: CompilerConfigurationKey = CompilerConfigurationKey.create("print bitcode") diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanPhases.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanPhases.kt index 399a1db1ea7..85667dea912 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanPhases.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanPhases.kt @@ -142,6 +142,9 @@ internal class PhaseManager(val context: Context) { if (shouldPrintIr()) { printIr() } + if (shouldPrintIrWithDescriptors()) { + printIrWithDescriptors() + } if (shouldPrintLocations()) { printLocations() } diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/DumpIrTreeWithDescriptorsVisitor.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/DumpIrTreeWithDescriptorsVisitor.kt new file mode 100644 index 00000000000..65367104254 --- /dev/null +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/DumpIrTreeWithDescriptorsVisitor.kt @@ -0,0 +1,365 @@ +package org.jetbrains.kotlin.backend.konan.ir + +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor +import org.jetbrains.kotlin.ir.IrElement +import org.jetbrains.kotlin.ir.declarations.* +import org.jetbrains.kotlin.ir.expressions.* +import org.jetbrains.kotlin.ir.visitors.IrElementVisitor +import org.jetbrains.kotlin.renderer.* +import org.jetbrains.kotlin.types.KotlinType +import org.jetbrains.kotlin.utils.Printer + +class RenderIrElementWithDescriptorsVisitor : IrElementVisitor { + override fun visitElement(element: IrElement, data: Nothing?): String = + "? ${element.javaClass.simpleName}" + + override fun visitDeclaration(declaration: IrDeclaration, data: Nothing?): String = + "? ${declaration.javaClass.simpleName} ${declaration.descriptor.ref()}" + + override fun visitModuleFragment(declaration: IrModuleFragment, data: Nothing?): String = + "MODULE_FRAGMENT ${declaration.descriptor}" + + override fun visitFile(declaration: IrFile, data: Nothing?): String = + "FILE ${declaration.name}" + + override fun visitFunction(declaration: IrFunction, data: Nothing?): String = + "FUN ${declaration.descriptor}" + + override fun visitConstructor(declaration: IrConstructor, data: Nothing?): String = + "CONSTRUCTOR ${declaration.descriptor}" + + override fun visitProperty(declaration: IrProperty, data: Nothing?): String = + "PROPERTY ${declaration.descriptor}" + + override fun visitField(declaration: IrField, data: Nothing?): String = + "FIELD ${declaration.descriptor}" + + override fun visitClass(declaration: IrClass, data: Nothing?): String = + "CLASS ${declaration.descriptor}" + + override fun visitTypeAlias(declaration: IrTypeAlias, data: Nothing?): String = + "TYPEALIAS ${declaration.descriptor} type=${declaration.descriptor.underlyingType.render()}" + + override fun visitVariable(declaration: IrVariable, data: Nothing?): String = + "VAR ${declaration.descriptor}" + + override fun visitEnumEntry(declaration: IrEnumEntry, data: Nothing?): String = + "ENUM_ENTRY ${declaration.descriptor}" + + override fun visitAnonymousInitializer(declaration: IrAnonymousInitializer, data: Nothing?): String = + "ANONYMOUS_INITIALIZER ${declaration.descriptor}" + + override fun visitLocalDelegatedProperty(declaration: IrLocalDelegatedProperty, data: Nothing?): String = + "LOCAL_DELEGATED_PROPERTY ${declaration.descriptor}" + + override fun visitExpressionBody(body: IrExpressionBody, data: Nothing?): String = + "EXPRESSION_BODY" + + override fun visitBlockBody(body: IrBlockBody, data: Nothing?): String = + "BLOCK_BODY" + + override fun visitSyntheticBody(body: IrSyntheticBody, data: Nothing?): String = + "SYNTHETIC_BODY kind=${body.kind}" + + override fun visitExpression(expression: IrExpression, data: Nothing?): String = + "? ${expression.javaClass.simpleName} type=${expression.type.render()}" + + override fun visitConst(expression: IrConst, data: Nothing?): String = + "CONST ${expression.kind} type=${expression.type.render()} value='${expression.value}'" + + override fun visitVararg(expression: IrVararg, data: Nothing?): String = + "VARARG type=${expression.type} varargElementType=${expression.varargElementType}" + + override fun visitSpreadElement(spread: IrSpreadElement, data: Nothing?): String = + "SPREAD_ELEMENT" + + override fun visitBlock(expression: IrBlock, data: Nothing?): String = + "BLOCK type=${expression.type.render()} origin=${expression.origin}" + + override fun visitComposite(expression: IrComposite, data: Nothing?): String = + "COMPOSITE type=${expression.type.render()} origin=${expression.origin}" + + override fun visitReturn(expression: IrReturn, data: Nothing?): String = + "RETURN type=${expression.type.render()} from='${expression.returnTarget}'" + + override fun visitCall(expression: IrCall, data: Nothing?): String = + "CALL '${expression.descriptor}' ${expression.renderSuperQualifier()}" + + "type=${expression.type.render()} origin=${expression.origin}" + + private fun IrCall.renderSuperQualifier(): String = + superQualifier?.let { "superQualifier=${it.name} " } ?: "" + + override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall, data: Nothing?): String = + "DELEGATING_CONSTRUCTOR_CALL '${expression.descriptor}'" + + override fun visitEnumConstructorCall(expression: IrEnumConstructorCall, data: Nothing?): String = + "ENUM_CONSTRUCTOR_CALL '${expression.descriptor}'" + + override fun visitInstanceInitializerCall(expression: IrInstanceInitializerCall, data: Nothing?): String = + "INSTANCE_INITIALIZER_CALL classDescriptor='${expression.classDescriptor}'" + + override fun visitGetValue(expression: IrGetValue, data: Nothing?): String = + "GET_VAR '${expression.descriptor}' type=${expression.type.render()} origin=${expression.origin}" + + override fun visitSetVariable(expression: IrSetVariable, data: Nothing?): String = + "SET_VAR '${expression.descriptor}' type=${expression.type.render()} origin=${expression.origin}" + + override fun visitGetField(expression: IrGetField, data: Nothing?): String = + "GET_FIELD '${expression.descriptor}' type=${expression.type.render()} origin=${expression.origin}" + + override fun visitSetField(expression: IrSetField, data: Nothing?): String = + "SET_FIELD '${expression.descriptor}' type=${expression.type.render()} origin=${expression.origin}" + + override fun visitGetObjectValue(expression: IrGetObjectValue, data: Nothing?): String = + "GET_OBJECT '${expression.descriptor}' type=${expression.type.render()}" + + override fun visitGetEnumValue(expression: IrGetEnumValue, data: Nothing?): String = + "GET_ENUM '${expression.descriptor}' type=${expression.type.render()}" + + override fun visitStringConcatenation(expression: IrStringConcatenation, data: Nothing?): String = + "STRING_CONCATENATION type=${expression.type.render()}" + + override fun visitTypeOperator(expression: IrTypeOperatorCall, data: Nothing?): String = + "TYPE_OP origin=${expression.operator} typeOperand=${expression.typeOperand.render()}" + + override fun visitWhen(expression: IrWhen, data: Nothing?): String = + "WHEN type=${expression.type.render()} origin=${expression.origin}" + + override fun visitBranch(branch: IrBranch, data: Nothing?): String = + "BRANCH" + + override fun visitWhileLoop(loop: IrWhileLoop, data: Nothing?): String = + "WHILE label=${loop.label} origin=${loop.origin}" + + override fun visitDoWhileLoop(loop: IrDoWhileLoop, data: Nothing?): String = + "DO_WHILE label=${loop.label} origin=${loop.origin}" + + override fun visitBreak(jump: IrBreak, data: Nothing?): String = + "BREAK label=${jump.label} loop.label=${jump.loop.label}" + + override fun visitContinue(jump: IrContinue, data: Nothing?): String = + "CONTINUE label=${jump.label} loop.label=${jump.loop.label}" + + override fun visitThrow(expression: IrThrow, data: Nothing?): String = + "THROW type=${expression.type.render()}" + + override fun visitCallableReference(expression: IrCallableReference, data: Nothing?): String = + "CALLABLE_REFERENCE '${expression.descriptor}' type=${expression.type.render()} origin=${expression.origin}" + + override fun visitClassReference(expression: IrClassReference, data: Nothing?): String = + "CLASS_REFERENCE '${expression.descriptor}' type=${expression.type.render()}" + + override fun visitGetClass(expression: IrGetClass, data: Nothing?): String = + "GET_CLASS type=${expression.type.render()}" + + override fun visitTry(aTry: IrTry, data: Nothing?): String = + "TRY type=${aTry.type.render()}" + + override fun visitCatch(aCatch: IrCatch, data: Nothing?): String = + "CATCH parameter=${aCatch.parameter.ref()}" + + override fun visitErrorDeclaration(declaration: IrErrorDeclaration, data: Nothing?): String = + "ERROR_DECL ${declaration.descriptor.javaClass.simpleName} ${declaration.descriptor.ref()}" + + override fun visitErrorExpression(expression: IrErrorExpression, data: Nothing?): String = + "ERROR_EXPR '${expression.description}' type=${expression.type.render()}" + + override fun visitErrorCallExpression(expression: IrErrorCallExpression, data: Nothing?): String = + "ERROR_CALL '${expression.description}' type=${expression.type.render()}" + + companion object { + val DECLARATION_RENDERER = DescriptorRenderer.withOptions { + withDefinedIn = false + overrideRenderingPolicy = OverrideRenderingPolicy.RENDER_OPEN_OVERRIDE + includePropertyConstant = true + classifierNamePolicy = ClassifierNamePolicy.FULLY_QUALIFIED + verbose = false + modifiers = DescriptorRendererModifier.ALL + } + + val REFERENCE_RENDERER = DescriptorRenderer.ONLY_NAMES_WITH_SHORT_TYPES + + internal fun IrDeclaration.name(): String = + descriptor.let { it.name.toString() } + + internal fun IrDeclaration.renderDeclared(): String = + DECLARATION_RENDERER.render(this.descriptor) + + internal fun DeclarationDescriptor.ref(): String = + if (this is ReceiverParameterDescriptor) + "" + else + REFERENCE_RENDERER.render(this) + + internal fun KotlinType.render(): String = + DECLARATION_RENDERER.renderType(this) + + internal fun IrDeclaration.renderOrigin(): String = + if (origin != IrDeclarationOrigin.DEFINED) origin.toString() + " " else "" + } +} + +class DumpIrTreeWithDescriptorsVisitor(out: Appendable): IrElementVisitor { + val printer = Printer(out, " ") + val elementRenderer = RenderIrElementWithDescriptorsVisitor() + + companion object { + val ANNOTATIONS_RENDERER = DescriptorRenderer.withOptions { + verbose = true + annotationArgumentsRenderingPolicy = AnnotationArgumentsRenderingPolicy.UNLESS_EMPTY + } + } + + override fun visitElement(element: IrElement, data: String) { + element.dumpLabeledSubTree(data) + } + + override fun visitFile(declaration: IrFile, data: String) { + declaration.dumpLabeledElementWith(data) { + if (declaration.fileAnnotations.isNotEmpty()) { + printer.println("fileAnnotations:") + indented { + declaration.fileAnnotations.forEach { + printer.println(ANNOTATIONS_RENDERER.renderAnnotation(it)) + } + } + } + declaration.declarations.forEach { it.accept(this, "") } + } + } + + override fun visitBlock(expression: IrBlock, data: String) { + if (expression is IrInlineFunctionBody) { + printer.println("INLINE FUNCTION BODY " + expression.descriptor) + indented { super.visitBlock(expression, data) } + return + } + super.visitBlock(expression, data) + } + + override fun visitFunction(declaration: IrFunction, data: String) { + visitFunctionWithParameters(declaration, data) + } + + override fun visitConstructor(declaration: IrConstructor, data: String) { + visitFunctionWithParameters(declaration, data) + } + + override fun visitErrorCallExpression(expression: IrErrorCallExpression, data: String) { + expression.dumpLabeledElementWith(data) { + expression.explicitReceiver?.accept(this, "receiver") + expression.arguments.forEach { it.accept(this, "") } + } + } + + private fun visitFunctionWithParameters(declaration: IrFunction, data: String) { + declaration.dumpLabeledElementWith(data) { + declaration.descriptor.valueParameters.forEach { valueParameter -> + declaration.getDefault(valueParameter)?.accept(this, valueParameter.name.asString()) + } + declaration.body?.accept(this, "") + } + } + + override fun visitEnumEntry(declaration: IrEnumEntry, data: String) { + declaration.dumpLabeledElementWith(data) { + declaration.initializerExpression.accept(this, "init") + declaration.correspondingClass?.accept(this, "class") + } + } + + override fun visitMemberAccess(expression: IrMemberAccessExpression, data: String) { + expression.dumpLabeledElementWith(data) { + dumpTypeArguments(expression) + + expression.dispatchReceiver?.accept(this, "\$this") + expression.extensionReceiver?.accept(this, "\$receiver") + for (valueParameter in expression.descriptor.valueParameters) { + expression.getValueArgument(valueParameter.index)?.accept(this, valueParameter.name.asString()) + } + } + } + + private fun dumpTypeArguments(expression: IrMemberAccessExpression) { + for (typeParameter in expression.descriptor.original.typeParameters) { + val typeArgument = expression.getTypeArgument(typeParameter) ?: continue + val renderedParameter = DescriptorRenderer.ONLY_NAMES_WITH_SHORT_TYPES.render(typeParameter) + val renderedType = DescriptorRenderer.ONLY_NAMES_WITH_SHORT_TYPES.renderType(typeArgument) + printer.println("$renderedParameter: $renderedType") + } + } + + override fun visitGetField(expression: IrGetField, data: String) { + expression.dumpLabeledElementWith(data) { + expression.receiver?.accept(this, "receiver") + } + } + + override fun visitSetField(expression: IrSetField, data: String) { + expression.dumpLabeledElementWith(data) { + expression.receiver?.accept(this, "receiver") + expression.value.accept(this, "value") + } + } + + override fun visitWhen(expression: IrWhen, data: String) { + expression.dumpLabeledElementWith(data) { + expression.branches.forEach { + it.accept(this, "") + } + } + } + + override fun visitBranch(branch: IrBranch, data: String) { + branch.dumpLabeledElementWith(data) { + branch.condition.accept(this, "if") + branch.result.accept(this, "then") + } + } + + override fun visitWhileLoop(loop: IrWhileLoop, data: String) { + loop.dumpLabeledElementWith(data) { + loop.condition.accept(this, "condition") + loop.body?.accept(this, "body") + } + } + + override fun visitDoWhileLoop(loop: IrDoWhileLoop, data: String) { + loop.dumpLabeledElementWith(data) { + loop.body?.accept(this, "body") + loop.condition.accept(this, "condition") + } + } + + override fun visitTry(aTry: IrTry, data: String) { + aTry.dumpLabeledElementWith(data) { + aTry.tryResult.accept(this, "try") + for (aCatch in aTry.catches) { + aCatch.accept(this, "") + } + aTry.finallyExpression?.accept(this, "finally") + } + } + + private inline fun IrElement.dumpLabeledElementWith(label: String, body: () -> Unit) { + printer.println(accept(elementRenderer, null).withLabel(label)) + indented(body) + } + + private fun IrElement.dumpLabeledSubTree(label: String) { + printer.println(accept(elementRenderer, null).withLabel(label)) + indented { + acceptChildren(this@DumpIrTreeWithDescriptorsVisitor, "") + } + } + + private inline fun indented(body: () -> Unit) { + printer.pushIndent() + body() + printer.popIndent() + } + + private fun String.withLabel(label: String) = + if (label.isEmpty()) this else "$label: $this" +} \ No newline at end of file diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/IrUtils.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/IrUtils.kt index 8e074973ed9..5106b0c6565 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/IrUtils.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/IrUtils.kt @@ -17,16 +17,19 @@ package org.jetbrains.kotlin.backend.konan.ir import org.jetbrains.kotlin.backend.konan.Context -import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor +import org.jetbrains.kotlin.descriptors.ClassDescriptor +import org.jetbrains.kotlin.descriptors.SourceElement import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.impl.ClassConstructorDescriptorImpl import org.jetbrains.kotlin.incremental.components.NoLookupLocation -import org.jetbrains.kotlin.ir.* -import org.jetbrains.kotlin.ir.util.DumpIrTreeVisitor -import org.jetbrains.kotlin.ir.declarations.* +import org.jetbrains.kotlin.ir.IrElement +import org.jetbrains.kotlin.ir.declarations.IrConstructor +import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin import org.jetbrains.kotlin.ir.declarations.impl.IrConstructorImpl -import org.jetbrains.kotlin.ir.expressions.* +import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.expressions.impl.* +import org.jetbrains.kotlin.ir.util.DumpIrTreeVisitor import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.types.KotlinType @@ -37,11 +40,14 @@ import java.io.StringWriter fun ir2string(ir: IrElement?): String = ir2stringWhole(ir).takeWhile { it != '\n' } -fun ir2stringWhole(ir: IrElement?): String { - val strWriter = StringWriter() +fun ir2stringWhole(ir: IrElement?, withDescriptors: Boolean = false): String { + val strWriter = StringWriter() - ir?.accept(DumpIrTreeVisitor(strWriter), "") - return strWriter.toString() + if (withDescriptors) + ir?.accept(DumpIrTreeWithDescriptorsVisitor(strWriter), "") + else + ir?.accept(DumpIrTreeVisitor(strWriter), "") + return strWriter.toString() } internal fun ClassDescriptor.createSimpleDelegatingConstructorDescriptor(superConstructorDescriptor: ClassConstructorDescriptor, isPrimary: Boolean = false)