Supported IrConstructorCall

(cherry picked from commit 315362b0fc3ddec049955b67f1df876d5569aa22)
This commit is contained in:
Igor Chevdar
2019-04-29 13:20:55 +03:00
committed by Vasily Levchenko
parent 6708e4df80
commit 2138b37dc9
19 changed files with 149 additions and 155 deletions
@@ -99,7 +99,7 @@ private fun KotlinToCCallBuilder.addArgument(
if (!variadic) cFunctionBuilder.addParameter(cArgument.type) if (!variadic) cFunctionBuilder.addParameter(cArgument.type)
} }
private fun KotlinToCCallBuilder.buildKotlinBridgeCall(transformCall: (IrCall) -> IrExpression = { it }): IrExpression = private fun KotlinToCCallBuilder.buildKotlinBridgeCall(transformCall: (IrMemberAccessExpression) -> IrExpression = { it }): IrExpression =
bridgeCallBuilder.build( bridgeCallBuilder.build(
bridgeBuilder.buildKotlinBridge().also { bridgeBuilder.buildKotlinBridge().also {
this.stubs.addKotlin(it) this.stubs.addKotlin(it)
@@ -16,6 +16,8 @@ import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl
import org.jetbrains.kotlin.ir.expressions.IrCall import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrMemberAccessExpression
import org.jetbrains.kotlin.ir.expressions.impl.IrConstructorCallImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrTryImpl import org.jetbrains.kotlin.ir.expressions.impl.IrTryImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl
@@ -128,8 +130,9 @@ private fun createKotlinBridge(
) )
bridgeDescriptor.bind(bridge) bridgeDescriptor.bind(bridge)
if (isExternal) { if (isExternal) {
val constructor = symbols.filterExceptions.owner.constructors.single()
bridge.annotations += bridge.annotations +=
irCall(startOffset, endOffset, symbols.filterExceptions.owner.constructors.single(), emptyList()) IrConstructorCallImpl.fromSymbolOwner(startOffset, endOffset, constructor.returnType, constructor.symbol)
} }
return bridge return bridge
} }
@@ -185,7 +188,7 @@ internal class KotlinCallBuilder(private val irBuilder: IrBuilderWithScope, priv
fun build( fun build(
function: IrFunction, function: IrFunction,
transformCall: (IrCall) -> IrExpression = { it } transformCall: (IrMemberAccessExpression) -> IrExpression = { it }
): IrExpression { ): IrExpression {
val arguments = this.arguments.toMutableList() val arguments = this.arguments.toMutableList()
@@ -8,7 +8,6 @@ package org.jetbrains.kotlin.backend.konan.descriptors
import org.jetbrains.kotlin.backend.common.ir.SharedVariablesManager import org.jetbrains.kotlin.backend.common.ir.SharedVariablesManager
import org.jetbrains.kotlin.backend.konan.KonanBackendContext import org.jetbrains.kotlin.backend.konan.KonanBackendContext
import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.descriptors.VariableDescriptor import org.jetbrains.kotlin.descriptors.VariableDescriptor
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor
@@ -21,9 +20,9 @@ import org.jetbrains.kotlin.ir.expressions.IrGetValue
import org.jetbrains.kotlin.ir.expressions.IrSetVariable import org.jetbrains.kotlin.ir.expressions.IrSetVariable
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrCompositeImpl import org.jetbrains.kotlin.ir.expressions.impl.IrCompositeImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrConstructorCallImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
import org.jetbrains.kotlin.ir.symbols.IrVariableSymbol import org.jetbrains.kotlin.ir.symbols.IrVariableSymbol
import org.jetbrains.kotlin.ir.types.toKotlinType
import org.jetbrains.kotlin.ir.types.typeWith import org.jetbrains.kotlin.ir.types.typeWith
import org.jetbrains.kotlin.ir.util.constructors import org.jetbrains.kotlin.ir.util.constructors
import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.*
@@ -36,14 +35,6 @@ internal class KonanSharedVariablesManager(val context: KonanBackendContext) : S
private val elementProperty = refClass.owner.declarations.filterIsInstance<IrProperty>().single() private val elementProperty = refClass.owner.declarations.filterIsInstance<IrProperty>().single()
private fun refConstructor(elementType: KotlinType): ClassConstructorDescriptor {
val typeParameter = refClassConstructor.descriptor.typeParameters[0]
return refClassConstructor.descriptor.substitute(TypeSubstitutor.create(
mapOf(typeParameter.typeConstructor to TypeProjectionImpl(Variance.INVARIANT, elementType))
))!!
}
private fun refType(elementType: KotlinType): KotlinType { private fun refType(elementType: KotlinType): KotlinType {
return refClass.descriptor.defaultType.replace(listOf(TypeProjectionImpl(elementType))) return refClass.descriptor.defaultType.replace(listOf(TypeProjectionImpl(elementType)))
} }
@@ -66,10 +57,10 @@ internal class KonanSharedVariablesManager(val context: KonanBackendContext) : S
val valueType = originalDeclaration.type val valueType = originalDeclaration.type
val refConstructorCall = IrCallImpl( val refConstructorCall = IrConstructorCallImpl.fromSymbolOwner(
originalDeclaration.startOffset, originalDeclaration.endOffset, originalDeclaration.startOffset, originalDeclaration.endOffset,
refClass.typeWith(valueType), refClass.typeWith(valueType),
refClassConstructor, refConstructor(valueType.toKotlinType()), 1 refClassConstructor
).apply { ).apply {
putTypeArgument(0, valueType) putTypeArgument(0, valueType)
} }
@@ -97,7 +97,7 @@ class IrFileImpl(entry: SourceManager.FileEntry) : IrFile {
override val metadata: MetadataSource.File? override val metadata: MetadataSource.File?
get() = TODO("not implemented") get() = TODO("not implemented")
override val annotations: MutableList<IrCall> override val annotations: MutableList<IrConstructorCall>
get() = TODO("not implemented") get() = TODO("not implemented")
override val fqName: FqName override val fqName: FqName
get() = TODO("not implemented") get() = TODO("not implemented")
@@ -92,13 +92,6 @@ val IrClass.isFinalClass: Boolean
fun IrClass.isSpecialClassWithNoSupertypes() = this.isAny() || this.isNothing() fun IrClass.isSpecialClassWithNoSupertypes() = this.isAny() || this.isNothing()
private val IrCall.annotationClass
get() = (this.symbol.owner as IrConstructor).constructedClass
fun List<IrCall>.findAnnotation(fqName: FqName): IrCall? = this.firstOrNull {
it.annotationClass.fqNameSafe == fqName
}
fun <T> IrDeclaration.getAnnotationArgumentValue(fqName: FqName, argumentName: String): T? { fun <T> IrDeclaration.getAnnotationArgumentValue(fqName: FqName, argumentName: String): T? {
val annotation = this.annotations.findAnnotation(fqName) val annotation = this.annotations.findAnnotation(fqName)
if (annotation == null) { if (annotation == null) {
@@ -8,7 +8,6 @@ import org.jetbrains.kotlin.backend.konan.llvm.objc.genObjCSelector
import org.jetbrains.kotlin.backend.konan.reportCompilationError import org.jetbrains.kotlin.backend.konan.reportCompilationError
import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrConstructor
import org.jetbrains.kotlin.ir.declarations.IrFunction import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.types.getClass import org.jetbrains.kotlin.ir.types.getClass
@@ -147,8 +146,8 @@ internal class IntrinsicGenerator(private val environment: IntrinsicGeneratorEnv
} }
IntrinsicType.OBJC_INIT_BY -> { IntrinsicType.OBJC_INIT_BY -> {
val receiver = environment.evaluateExpression(callSite.extensionReceiver!!) val receiver = environment.evaluateExpression(callSite.extensionReceiver!!)
val irConstructorCall = callSite.getValueArgument(0) as IrCall val irConstructorCall = callSite.getValueArgument(0) as IrConstructorCall
val constructorDescriptor = irConstructorCall.symbol.owner as IrConstructor val constructorDescriptor = irConstructorCall.symbol.owner
val constructorArgs = environment.evaluateExplicitArgs(irConstructorCall) val constructorArgs = environment.evaluateExplicitArgs(irConstructorCall)
val args = listOf(receiver) + constructorArgs val args = listOf(receiver) + constructorArgs
environment.evaluateCall(constructorDescriptor, args, Lifetime.IRRELEVANT) environment.evaluateCall(constructorDescriptor, args, Lifetime.IRRELEVANT)
@@ -159,7 +158,7 @@ internal class IntrinsicGenerator(private val environment: IntrinsicGeneratorEnv
environment.functionGenerationContext.genObjCSelector(selector) environment.functionGenerationContext.genObjCSelector(selector)
} }
IntrinsicType.INIT_INSTANCE -> { IntrinsicType.INIT_INSTANCE -> {
val initializer = callSite.getValueArgument(1) as IrCall val initializer = callSite.getValueArgument(1) as IrConstructorCall
val thiz = environment.evaluateExpression(callSite.getValueArgument(0)!!) val thiz = environment.evaluateExpression(callSite.getValueArgument(0)!!)
environment.evaluateCall( environment.evaluateCall(
initializer.symbol.owner, initializer.symbol.owner,
@@ -760,6 +760,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
is IrCall -> return evaluateCall (value) is IrCall -> return evaluateCall (value)
is IrDelegatingConstructorCall -> is IrDelegatingConstructorCall ->
return evaluateCall (value) return evaluateCall (value)
is IrConstructorCall -> return evaluateCall (value)
is IrInstanceInitializerCall -> is IrInstanceInitializerCall ->
return evaluateInstanceInitializerCall(value) return evaluateInstanceInitializerCall(value)
is IrGetValue -> return evaluateGetValue (value) is IrGetValue -> return evaluateGetValue (value)
@@ -1751,6 +1752,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
updateBuilderDebugLocation(value) updateBuilderDebugLocation(value)
return when (value) { return when (value) {
is IrDelegatingConstructorCall -> delegatingConstructorCall(value.symbol.owner, args) is IrDelegatingConstructorCall -> delegatingConstructorCall(value.symbol.owner, args)
is IrConstructorCall -> evaluateConstructorCall(value, args)
else -> evaluateFunctionCall(value as IrCall, args, resultLifetime(value)) else -> evaluateFunctionCall(value as IrCall, args, resultLifetime(value))
} }
} }
@@ -2016,7 +2018,6 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
return when { return when {
function.isTypedIntrinsic -> intrinsicGenerator.evaluateCall(callee, args) function.isTypedIntrinsic -> intrinsicGenerator.evaluateCall(callee, args)
function.symbol in context.irBuiltIns.irBuiltInsSymbols -> evaluateOperatorCall(callee, argsWithContinuationIfNeeded) function.symbol in context.irBuiltIns.irBuiltInsSymbols -> evaluateOperatorCall(callee, argsWithContinuationIfNeeded)
function is IrConstructor -> evaluateConstructorCall(callee, argsWithContinuationIfNeeded)
else -> evaluateSimpleFunctionCall(function, argsWithContinuationIfNeeded, resultLifetime, callee.superQualifierSymbol?.owner) else -> evaluateSimpleFunctionCall(function, argsWithContinuationIfNeeded, resultLifetime, callee.superQualifierSymbol?.owner)
} }
} }
@@ -2045,34 +2046,40 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
return lifetimes.getOrElse(callee) { /* TODO: make IRRELEVANT */ Lifetime.GLOBAL } return lifetimes.getOrElse(callee) { /* TODO: make IRRELEVANT */ Lifetime.GLOBAL }
} }
private fun evaluateConstructorCall(callee: IrCall, args: List<LLVMValueRef>): LLVMValueRef { private fun evaluateConstructorCall(callee: IrConstructorCall, args: List<LLVMValueRef>): LLVMValueRef {
context.log{"evaluateConstructorCall : ${ir2string(callee)}"} context.log{"evaluateConstructorCall : ${ir2string(callee)}"}
return memScoped { return memScoped {
val constructedClass = (callee.symbol as IrConstructorSymbol).owner.constructedClass val constructedClass = callee.symbol.owner.constructedClass
val thisValue = if (constructedClass.isArray) { val thisValue = when {
assert(args.isNotEmpty() && args[0].type == int32Type) constructedClass.isArray -> {
functionGenerationContext.allocArray(codegen.typeInfoValue(constructedClass), args[0], assert(args.isNotEmpty() && args[0].type == int32Type)
resultLifetime(callee), currentCodeContext.exceptionHandler) functionGenerationContext.allocArray(codegen.typeInfoValue(constructedClass), args[0],
} else if (constructedClass == context.ir.symbols.string.owner) { resultLifetime(callee), currentCodeContext.exceptionHandler)
// TODO: consider returning the empty string literal instead.
assert(args.isEmpty())
functionGenerationContext.allocArray(codegen.typeInfoValue(constructedClass), count = kImmZero,
lifetime = resultLifetime(callee), exceptionHandler = currentCodeContext.exceptionHandler)
} else if (constructedClass.isObjCClass()) {
assert(constructedClass.isKotlinObjCClass()) // Calls to other ObjC class constructors must be lowered.
val symbols = context.ir.symbols
val rawPtr = callDirect(
symbols.interopAllocObjCObject.owner,
listOf(genGetObjCClass(constructedClass)),
Lifetime.IRRELEVANT
)
callDirect(symbols.interopInterpretObjCPointer.owner, listOf(rawPtr), resultLifetime(callee)).also {
// Balance pointer retained by alloc:
callDirect(symbols.interopObjCRelease.owner, listOf(rawPtr), Lifetime.IRRELEVANT)
} }
} else {
functionGenerationContext.allocInstance(constructedClass, resultLifetime(callee)) constructedClass == context.ir.symbols.string.owner -> {
// TODO: consider returning the empty string literal instead.
assert(args.isEmpty())
functionGenerationContext.allocArray(codegen.typeInfoValue(constructedClass), count = kImmZero,
lifetime = resultLifetime(callee), exceptionHandler = currentCodeContext.exceptionHandler)
}
constructedClass.isObjCClass() -> {
assert(constructedClass.isKotlinObjCClass()) // Calls to other ObjC class constructors must be lowered.
val symbols = context.ir.symbols
val rawPtr = callDirect(
symbols.interopAllocObjCObject.owner,
listOf(genGetObjCClass(constructedClass)),
Lifetime.IRRELEVANT
)
callDirect(symbols.interopInterpretObjCPointer.owner, listOf(rawPtr), resultLifetime(callee)).also {
// Balance pointer retained by alloc:
callDirect(symbols.interopObjCRelease.owner, listOf(rawPtr), Lifetime.IRRELEVANT)
}
}
else -> functionGenerationContext.allocInstance(constructedClass, resultLifetime(callee))
} }
evaluateSimpleFunctionCall(callee.symbol.owner, evaluateSimpleFunctionCall(callee.symbol.owner,
listOf(thisValue) + args, Lifetime.IRRELEVANT /* constructor doesn't return anything */) listOf(thisValue) + args, Lifetime.IRRELEVANT /* constructor doesn't return anything */)
@@ -2223,8 +2230,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
//-------------------------------------------------------------------------// //-------------------------------------------------------------------------//
private fun delegatingConstructorCall( private fun delegatingConstructorCall(constructor: IrConstructor, args: List<LLVMValueRef>): LLVMValueRef {
constructor: IrConstructor, args: List<LLVMValueRef>): LLVMValueRef {
val constructedClass = functionGenerationContext.constructedClass!! val constructedClass = functionGenerationContext.constructedClass!!
val thisPtr = currentCodeContext.genGetValue(constructedClass.thisReceiver!!) val thisPtr = currentCodeContext.genGetValue(constructedClass.thisReceiver!!)
@@ -17,6 +17,7 @@ import org.jetbrains.kotlin.backend.konan.descriptors.target
import org.jetbrains.kotlin.backend.konan.ir.* import org.jetbrains.kotlin.backend.konan.ir.*
import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.builders.* import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
@@ -32,8 +33,7 @@ import org.jetbrains.kotlin.ir.symbols.impl.IrFieldSymbolImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid import org.jetbrains.kotlin.ir.visitors.*
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.utils.addIfNotNull import org.jetbrains.kotlin.utils.addIfNotNull
@@ -131,6 +131,7 @@ private class AutoboxingTransformer(val context: Context) : AbstractValueUsageTr
private val IrFunctionAccessExpression.target: IrFunction get() = when (this) { private val IrFunctionAccessExpression.target: IrFunction get() = when (this) {
is IrCall -> this.callTarget is IrCall -> this.callTarget
is IrDelegatingConstructorCall -> this.symbol.owner is IrDelegatingConstructorCall -> this.symbol.owner
is IrConstructorCall -> this.symbol.owner
else -> TODO(this.render()) else -> TODO(this.render())
} }
@@ -266,12 +267,12 @@ private class InlineClassTransformer(private val context: Context) : IrBuildingT
} }
} }
override fun visitCall(expression: IrCall): IrExpression { override fun visitConstructorCall(expression: IrConstructorCall): IrExpression {
super.visitCall(expression) super.visitConstructorCall(expression)
val function = expression.symbol.owner val constructor = expression.symbol.owner
return if (function is IrConstructor && function.constructedClass.isInlined()) { return if (constructor.constructedClass.isInlined()) {
builder.lowerConstructorCallToValue(expression, function) builder.lowerConstructorCallToValue(expression, constructor)
} else { } else {
expression expression
} }
@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.IrCall import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.expressions.IrConstructorCall
import org.jetbrains.kotlin.ir.symbols.* import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
@@ -171,7 +172,7 @@ internal class DeepCopyIrTreeWithSymbolsForInliner(val context: Context,
classifier = symbolRemapper.getReferencedClassifier(type.classifier), classifier = symbolRemapper.getReferencedClassifier(type.classifier),
hasQuestionMark = type.hasQuestionMark, hasQuestionMark = type.hasQuestionMark,
arguments = remapTypeArguments(type.arguments), arguments = remapTypeArguments(type.arguments),
annotations = type.annotations.map { it.transform(copier, null) as IrCall } annotations = type.annotations.map { it.transform(copier, null) as IrConstructorCall }
) )
} }
} }
@@ -220,14 +220,14 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
.map { .map {
val initializer = it.initializerExpression val initializer = it.initializerExpression
val entryConstructorCall = when { val entryConstructorCall = when {
initializer is IrCall -> initializer initializer is IrConstructorCall -> initializer
initializer is IrBlock && initializer.origin == ARGUMENTS_REORDERING_FOR_CALL -> initializer is IrBlock && initializer.origin == ARGUMENTS_REORDERING_FOR_CALL ->
initializer.statements.last() as IrCall initializer.statements.last() as IrConstructorCall
else -> error("Unexpected initializer: $initializer") else -> error("Unexpected initializer: $initializer")
} }
val entryClass = (entryConstructorCall.symbol.owner as IrConstructor).constructedClass val entryClass = entryConstructorCall.symbol.owner.constructedClass
irCall(startOffset, endOffset, irCall(startOffset, endOffset,
createUninitializedInstance, createUninitializedInstance,
@@ -265,7 +265,7 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
val startOffset = irClass.startOffset val startOffset = irClass.startOffset
val endOffset = irClass.endOffset val endOffset = irClass.endOffset
fun IrBlockBuilder.initInstanceCall(instance: IrCall, constructor: IrCall): IrCall = fun IrBlockBuilder.initInstanceCall(instance: IrCall, constructor: IrConstructorCall): IrCall =
irCall(initInstanceSymbol).apply { irCall(initInstanceSymbol).apply {
putValueArgument(0, instance) putValueArgument(0, instance)
putValueArgument(1, constructor) putValueArgument(1, constructor)
@@ -288,11 +288,11 @@ internal class EnumClassLowering(val context: Context) : ClassLoweringPass {
val initializer = it.value.initializerExpression!! val initializer = it.value.initializerExpression!!
initializer.patchDeclarationParents(constructor) initializer.patchDeclarationParents(constructor)
when { when {
initializer is IrCall -> +initInstanceCall(instance, initializer) initializer is IrConstructorCall -> +initInstanceCall(instance, initializer)
initializer is IrBlock && initializer.origin == ARGUMENTS_REORDERING_FOR_CALL -> { initializer is IrBlock && initializer.origin == ARGUMENTS_REORDERING_FOR_CALL -> {
val statements = initializer.statements val statements = initializer.statements
val constructorCall = statements.last() as IrCall val constructorCall = statements.last() as IrConstructorCall
statements[statements.lastIndex] = initInstanceCall(instance, constructorCall) statements[statements.lastIndex] = initInstanceCall(instance, constructorCall)
+initializer +initializer
} }
@@ -270,21 +270,13 @@ internal class EnumConstructorsLowering(val context: Context) : ClassLoweringPas
} }
private inner class InEnumEntryClassConstructor(enumEntry: IrEnumEntry) : InEnumEntry(enumEntry) { private inner class InEnumEntryClassConstructor(enumEntry: IrEnumEntry) : InEnumEntry(enumEntry) {
override fun createConstructorCall( override fun createConstructorCall(startOffset: Int, endOffset: Int, loweredConstructor: IrConstructorSymbol) =
startOffset: Int, IrDelegatingConstructorCallImpl(startOffset, endOffset, context.irBuiltIns.unitType, loweredConstructor)
endOffset: Int,
loweredConstructor: IrConstructorSymbol
) = IrDelegatingConstructorCallImpl(
startOffset,
endOffset,
context.irBuiltIns.unitType,
loweredConstructor
)
} }
private inner class InEnumEntryInitializer(enumEntry: IrEnumEntry) : InEnumEntry(enumEntry) { private inner class InEnumEntryInitializer(enumEntry: IrEnumEntry) : InEnumEntry(enumEntry) {
override fun createConstructorCall(startOffset: Int, endOffset: Int, loweredConstructor: IrConstructorSymbol) = override fun createConstructorCall(startOffset: Int, endOffset: Int, loweredConstructor: IrConstructorSymbol) =
IrCallImpl(startOffset, endOffset, loweredConstructor.owner.returnType, loweredConstructor) IrConstructorCallImpl.fromSymbolOwner(startOffset, endOffset, loweredConstructor.owner.returnType, loweredConstructor)
} }
private inner class EnumClassBodyTransformer : IrElementTransformerVoid() { private inner class EnumClassBodyTransformer : IrElementTransformerVoid() {
@@ -32,13 +32,7 @@ import org.jetbrains.kotlin.resolve.multiplatform.ExpectedActualResolver
internal class ExpectDeclarationsRemoving(val context: Context) : FileLoweringPass { internal class ExpectDeclarationsRemoving(val context: Context) : FileLoweringPass {
override fun lower(irFile: IrFile) { override fun lower(irFile: IrFile) {
// All declarations with `isExpect == true` are nested into a top-level declaration with `isExpect == true`. // All declarations with `isExpect == true` are nested into a top-level declaration with `isExpect == true`.
irFile.declarations.removeAll { irFile.declarations.removeAll { it.descriptor.isExpectMember }
if (it.descriptor.isExpectMember) {
true
} else {
false
}
}
} }
} }
@@ -36,19 +36,24 @@ internal class FunctionInlining(val context: Context) : IrElementTransformerVoid
fun inline(irModule: IrModuleFragment) = irModule.accept(this, data = null) fun inline(irModule: IrModuleFragment) = irModule.accept(this, data = null)
override fun visitCall(expression: IrCall): IrExpression { override fun visitFunctionAccess(expression: IrFunctionAccessExpression): IrExpression {
val callSite = super.visitCall(expression) as IrCall expression.transformChildrenVoid(this)
if (!callSite.symbol.owner.needsInlining) val callee = when (expression) {
return callSite is IrCall -> expression.symbol.owner
if (Symbols.isLateinitIsInitializedPropertyGetter(callSite.symbol)) is IrConstructorCall -> expression.symbol.owner
return callSite else -> return expression
}
if (!callee.needsInlining)
return expression
if (Symbols.isLateinitIsInitializedPropertyGetter(callee.symbol))
return expression
val callee = getFunctionDeclaration(callSite.symbol) val actualCallee = getFunctionDeclaration(callee.symbol)
callee.transformChildrenVoid(this) // Process recursive inline. actualCallee.transformChildrenVoid(this) // Process recursive inline.
val parent = allScopes.map { it.irElement }.filterIsInstance<IrDeclarationParent>().lastOrNull() val parent = allScopes.map { it.irElement }.filterIsInstance<IrDeclarationParent>().lastOrNull()
val inliner = Inliner(callSite, callee, currentScope!!, parent, context) val inliner = Inliner(expression, actualCallee, currentScope!!, parent, context)
return inliner.inline() return inliner.inline()
} }
@@ -76,7 +81,7 @@ internal class FunctionInlining(val context: Context) : IrElementTransformerVoid
private val IrFunction.needsInlining get() = isInlineConstructor || (this.isInline && !this.isExternal) private val IrFunction.needsInlining get() = isInlineConstructor || (this.isInline && !this.isExternal)
private inner class Inliner(val callSite: IrCall, private inner class Inliner(val callSite: IrFunctionAccessExpression,
val callee: IrFunction, val callee: IrFunction,
val currentScope: ScopeWithIr, val currentScope: ScopeWithIr,
val parent: IrDeclarationParent?, val parent: IrDeclarationParent?,
@@ -109,7 +114,7 @@ internal class FunctionInlining(val context: Context) : IrElementTransformerVoid
} }
} }
private fun inlineFunction(callSite: IrCall, callee: IrFunction): IrReturnableBlock { private fun inlineFunction(callSite: IrFunctionAccessExpression, callee: IrFunction): IrReturnableBlock {
val copiedCallee = copyIrElement.copy(callee) as IrFunction val copiedCallee = copyIrElement.copy(callee) as IrFunction
val evaluationStatements = evaluateArguments(callSite, copiedCallee) val evaluationStatements = evaluateArguments(callSite, copiedCallee)
@@ -126,12 +131,13 @@ internal class FunctionInlining(val context: Context) : IrElementTransformerVoid
val constructedClass = callee.parentAsClass val constructedClass = callee.parentAsClass
copiedCallee.parent = constructedClass copiedCallee.parent = constructedClass
val delegatingConstructorCall = statements[0] as IrDelegatingConstructorCall val delegatingConstructorCall = statements[0] as IrDelegatingConstructorCall
// TODO: Try use type parameters from callee.
irBuilder.run { irBuilder.run {
val constructorCall = IrCallImpl( val constructorCall = IrConstructorCallImpl(
startOffset, endOffset, startOffset, endOffset,
callSite.type, callSite.type,
delegatingConstructorCall.symbol, delegatingConstructorCall.descriptor, delegatingConstructorCall.symbol, delegatingConstructorCall.descriptor,
constructedClass.typeParameters.size, constructedClass.typeParameters.size, 0,
delegatingConstructorCall.symbol.owner.valueParameters.size delegatingConstructorCall.symbol.owner.valueParameters.size
).apply { ).apply {
delegatingConstructorCall.symbol.owner.valueParameters.forEach { delegatingConstructorCall.symbol.owner.valueParameters.forEach {
@@ -216,11 +222,12 @@ internal class FunctionInlining(val context: Context) : IrElementTransformerVoid
val unboundArgsSet = unboundFunctionParameters.toSet() val unboundArgsSet = unboundFunctionParameters.toSet()
val valueParameters = expression.getArguments().drop(1) // Skip dispatch receiver. val valueParameters = expression.getArguments().drop(1) // Skip dispatch receiver.
val immediateCall = IrCallImpl( val immediateCall = with(expression) {
expression.startOffset, expression.endOffset, if (function is IrConstructor)
expression.type, IrConstructorCallImpl.fromSymbolOwner(startOffset, endOffset, type, function.symbol)
functionArgument.symbol, functionArgument.descriptor else
).apply { IrCallImpl(startOffset, endOffset, type, functionArgument.symbol)
}.apply {
functionParameters.forEach { functionParameters.forEach {
val argument = val argument =
if (!unboundArgsSet.contains(it)) if (!unboundArgsSet.contains(it))
@@ -237,7 +244,7 @@ internal class FunctionInlining(val context: Context) : IrElementTransformerVoid
for (index in 0 until functionArgument.typeArgumentsCount) for (index in 0 until functionArgument.typeArgumentsCount)
putTypeArgument(index, functionArgument.getTypeArgument(index)) putTypeArgument(index, functionArgument.getTypeArgument(index))
} }
return this@FunctionInlining.visitCall(super.visitCall(immediateCall) as IrCall) return this@FunctionInlining.visitExpression(super.visitExpression(immediateCall))
} }
if (functionArgument !is IrBlock) if (functionArgument !is IrBlock)
return super.visitCall(expression) return super.visitCall(expression)
@@ -292,7 +299,7 @@ internal class FunctionInlining(val context: Context) : IrElementTransformerVoid
//-------------------------------------------------------------------------// //-------------------------------------------------------------------------//
private fun buildParameterToArgument(callSite: IrCall, callee: IrFunction): List<ParameterToArgument> { private fun buildParameterToArgument(callSite: IrFunctionAccessExpression, callee: IrFunction): List<ParameterToArgument> {
val parameterToArgument = mutableListOf<ParameterToArgument>() val parameterToArgument = mutableListOf<ParameterToArgument>()
@@ -367,7 +374,7 @@ internal class FunctionInlining(val context: Context) : IrElementTransformerVoid
//-------------------------------------------------------------------------// //-------------------------------------------------------------------------//
private fun evaluateArguments(callSite: IrCall, callee: IrFunction): List<IrStatement> { private fun evaluateArguments(callSite: IrFunctionAccessExpression, callee: IrFunction): List<IrStatement> {
val parameterToArgumentOld = buildParameterToArgument(callSite, callee) val parameterToArgumentOld = buildParameterToArgument(callSite, callee)
val evaluationStatements = mutableListOf<IrStatement>() val evaluationStatements = mutableListOf<IrStatement>()
@@ -649,28 +649,31 @@ internal class InteropLoweringPart1(val context: Context) : BaseInteropIrTransfo
) )
} }
override fun visitConstructorCall(expression: IrConstructorCall): IrExpression {
expression.transformChildrenVoid()
val descriptor = expression.descriptor.original
val callee = expression.symbol.owner
val initMethod = callee.getObjCInitMethod() ?: return expression
val arguments = descriptor.valueParameters.map { expression.getValueArgument(it) }
assert(expression.extensionReceiver == null)
assert(expression.dispatchReceiver == null)
val constructedClass = callee.constructedClass
val initMethodInfo = initMethod.getExternalObjCMethodInfo()!!
return builder.at(expression).run {
val classPtr = getObjCClass(constructedClass.symbol)
irForceNotNull(callAllocAndInit(classPtr, initMethodInfo, arguments, expression, initMethod))
}
}
override fun visitCall(expression: IrCall): IrExpression { override fun visitCall(expression: IrCall): IrExpression {
expression.transformChildrenVoid() expression.transformChildrenVoid()
val descriptor = expression.descriptor.original val descriptor = expression.descriptor.original
val callee = expression.symbol.owner val callee = expression.symbol.owner
if (callee is IrConstructor) {
val initMethod = callee.getObjCInitMethod()
if (initMethod != null) {
val arguments = descriptor.valueParameters.map { expression.getValueArgument(it) }
assert(expression.extensionReceiver == null)
assert(expression.dispatchReceiver == null)
val constructedClass = callee.constructedClass
val initMethodInfo = initMethod.getExternalObjCMethodInfo()!!
return builder.at(expression).run {
val classPtr = getObjCClass(constructedClass.symbol)
irForceNotNull(callAllocAndInit(classPtr, initMethodInfo, arguments, expression, initMethod))
}
}
}
descriptor.getObjCFactoryInitMethodInfo()?.let { initMethodInfo -> descriptor.getObjCFactoryInitMethodInfo()?.let { initMethodInfo ->
val arguments = (0 until expression.valueArgumentsCount) val arguments = (0 until expression.valueArgumentsCount)
@@ -858,6 +861,17 @@ private class InteropTransformer(val context: Context, override val irFile: IrFi
private fun generateCFunctionPointer(function: IrSimpleFunction, expression: IrExpression): IrExpression = private fun generateCFunctionPointer(function: IrSimpleFunction, expression: IrExpression): IrExpression =
generateWithStubs { generateCFunctionPointer(function, function, expression) } generateWithStubs { generateCFunctionPointer(function, function, expression) }
override fun visitConstructorCall(expression: IrConstructorCall): IrExpression {
expression.transformChildrenVoid(this)
val function = expression.symbol.owner
val inlinedClass = function.returnType.getInlinedClassNative()
if (inlinedClass?.descriptor == interop.cPointer || inlinedClass?.descriptor == interop.nativePointed) {
throw Error("Native interop types constructors must not be called directly")
}
return expression
}
override fun visitCall(expression: IrCall): IrExpression { override fun visitCall(expression: IrCall): IrExpression {
expression.transformChildrenVoid(this) expression.transformChildrenVoid(this)
@@ -865,13 +879,6 @@ private class InteropTransformer(val context: Context, override val irFile: IrFi
val descriptor = expression.descriptor.original val descriptor = expression.descriptor.original
val function = expression.symbol.owner val function = expression.symbol.owner
if (function is IrConstructor) {
val inlinedClass = function.returnType.getInlinedClassNative()
if (inlinedClass?.descriptor == interop.cPointer || inlinedClass?.descriptor == interop.nativePointed) {
throw Error("Native interop types constructors must not be called directly")
}
}
if (descriptor == interop.nativePointedRawPtrGetter || if (descriptor == interop.nativePointedRawPtrGetter ||
OverridingUtil.overrides(descriptor, interop.nativePointedRawPtrGetter)) { OverridingUtil.overrides(descriptor, interop.nativePointedRawPtrGetter)) {
@@ -1029,8 +1036,7 @@ private class InteropTransformer(val context: Context, override val irFile: IrFi
val intrinsic = interop.objCObjectInitBy.name val intrinsic = interop.objCObjectInitBy.name
val argument = expression.getValueArgument(0)!! val argument = expression.getValueArgument(0)!!
val constructedClass = val constructedClass = (argument as? IrConstructorCall)?.symbol?.owner?.constructedClass?.descriptor
((argument as? IrCall)?.descriptor as? ClassConstructorDescriptor)?.constructedClass
if (constructedClass == null) { if (constructedClass == null) {
context.reportCompilationError("Argument of '$intrinsic' must be a constructor call", context.reportCompilationError("Argument of '$intrinsic' must be a constructor call",
@@ -1068,7 +1068,7 @@ internal class SuspendFunctionsLowering(val context: Context): FileLoweringPass
} }
} }
fun IrBlockBodyBuilder.irSuccess(value: IrExpression): IrCall { fun IrBlockBodyBuilder.irSuccess(value: IrExpression): IrMemberAccessExpression {
val createResult = symbols.kotlinResult.owner.constructors.single { it.isPrimary } val createResult = symbols.kotlinResult.owner.constructors.single { it.isPrimary }
return irCall(createResult).apply { return irCall(createResult).apply {
putValueArgument(0, value) putValueArgument(0, value)
@@ -87,12 +87,7 @@ internal class VarargInjectionLowering constructor(val context: KonanBackendCont
expression.transformChildrenVoid(this) expression.transformChildrenVoid(this)
} }
override fun visitCall(expression: IrCall): IrExpression { override fun visitFunctionAccess(expression: IrFunctionAccessExpression): IrExpression {
replaceEmptyParameterWithEmptyArray(expression)
return expression
}
override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall): IrExpression {
replaceEmptyParameterWithEmptyArray(expression) replaceEmptyParameterWithEmptyArray(expression)
return expression return expression
} }
@@ -557,6 +557,17 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
else symbolTable.mapFunction(value.symbol.owner.constructors.single()) else symbolTable.mapFunction(value.symbol.owner.constructors.single())
) )
is IrConstructorCall -> {
val callee = value.symbol.owner
val arguments = value.getArguments().map { expressionToEdge(it.second) }
DataFlowIR.Node.NewObject(
symbolTable.mapFunction(callee),
arguments,
symbolTable.mapClassReferenceType(callee.constructedClass, false),
value
)
}
is IrCall -> when (value.symbol) { is IrCall -> when (value.symbol) {
getContinuationSymbol -> getContinuation() getContinuationSymbol -> getContinuation()
@@ -573,9 +584,9 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
initInstanceSymbol -> { initInstanceSymbol -> {
val thiz = expressionToEdge(value.getValueArgument(0)!!) val thiz = expressionToEdge(value.getValueArgument(0)!!)
val initializer = value.getValueArgument(1) as IrCall val initializer = value.getValueArgument(1) as IrConstructorCall
val arguments = listOf(thiz) + initializer.getArguments().map { expressionToEdge(it.second) } val arguments = listOf(thiz) + initializer.getArguments().map { expressionToEdge(it.second) }
val callee = initializer.symbol.owner as IrConstructor val callee = initializer.symbol.owner
DataFlowIR.Node.StaticCall( DataFlowIR.Node.StaticCall(
symbolTable.mapFunction(callee), symbolTable.mapFunction(callee),
arguments, arguments,
@@ -595,12 +606,7 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
it it
} }
if (callee is IrConstructor) { if (callee is IrConstructor) {
DataFlowIR.Node.NewObject( error("Constructor call should be done with IrConstructorCall")
symbolTable.mapFunction(callee),
arguments,
symbolTable.mapClassReferenceType(callee.constructedClass, false),
value
)
} else { } else {
callee as IrSimpleFunction callee as IrSimpleFunction
if (callee.isOverridable && value.superQualifier == null) { if (callee.isOverridable && value.superQualifier == null) {
@@ -20,6 +20,7 @@ import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.IrCall import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.expressions.IrConstructorCall
import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression
import org.jetbrains.kotlin.ir.expressions.IrGetField import org.jetbrains.kotlin.ir.expressions.IrGetField
import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.types.IrType
@@ -233,7 +234,8 @@ internal object DataFlowIR {
: Call(callee, arguments, irCallSite) : Call(callee, arguments, irCallSite)
// TODO: It can be replaced with a pair(AllocInstance, constructor Call), remove. // TODO: It can be replaced with a pair(AllocInstance, constructor Call), remove.
class NewObject(constructor: FunctionSymbol, arguments: List<Edge>, val constructedType: Type, override val irCallSite: IrCall?) class NewObject(constructor: FunctionSymbol, arguments: List<Edge>, val constructedType: Type,
override val irCallSite: IrConstructorCall?)
: Call(constructor, arguments, irCallSite) : Call(constructor, arguments, irCallSite)
open class VirtualCall(callee: FunctionSymbol, arguments: List<Edge>, open class VirtualCall(callee: FunctionSymbol, arguments: List<Edge>,
@@ -491,12 +491,10 @@ private fun IrFunction.substitutedReturnType(typeArguments: List<IrType>): IrTyp
// TODO: this function must be avoided since it takes symbol's owner implicitly. // TODO: this function must be avoided since it takes symbol's owner implicitly.
fun IrBuilderWithScope.irCall(symbol: IrFunctionSymbol, typeArguments: List<IrType> = emptyList()) = fun IrBuilderWithScope.irCall(symbol: IrFunctionSymbol, typeArguments: List<IrType> = emptyList()) =
irCall(symbol.owner, typeArguments) this.irCall(symbol, symbol.owner.substitutedReturnType(typeArguments), typeArguments)
fun IrBuilderWithScope.irCall( fun IrBuilderWithScope.irCall(irFunction: IrFunction, typeArguments: List<IrType> = emptyList()) =
irFunction: IrFunction, irCall(irFunction.symbol, typeArguments)
typeArguments: List<IrType> = emptyList()
): IrCall = irCall(this.startOffset, this.endOffset, irFunction, typeArguments)
internal fun irCall(startOffset: Int, endOffset: Int, irFunction: IrFunction, typeArguments: List<IrType>): IrCall = internal fun irCall(startOffset: Int, endOffset: Int, irFunction: IrFunction, typeArguments: List<IrType>): IrCall =
IrCallImpl( IrCallImpl(
@@ -512,7 +510,7 @@ fun IrBuilderWithScope.irCallOp(
callee: IrFunction, callee: IrFunction,
dispatchReceiver: IrExpression, dispatchReceiver: IrExpression,
argument: IrExpression argument: IrExpression
): IrCall = ) =
irCall(callee).apply { irCall(callee).apply {
this.dispatchReceiver = dispatchReceiver this.dispatchReceiver = dispatchReceiver
putValueArgument(0, argument) putValueArgument(0, argument)