From 2a6450446dff3a22c652c96d5e738d23acea65f1 Mon Sep 17 00:00:00 2001 From: Vasily Levchenko Date: Fri, 3 Feb 2017 10:32:15 +0300 Subject: [PATCH] IR: enhancements in default parameter extension - simplify argument count - refactoring - inner class support --- .../kotlin/backend/konan/KonanLower.kt | 2 +- .../jetbrains/kotlin/backend/konan/ir/Ir.kt | 3 +- .../lower/DefaultArgumentStubGenerator.kt | 391 ++++++++++++++++++ .../lower/DefaultParameterStubGenerator.kt | 379 ----------------- 4 files changed, 393 insertions(+), 382 deletions(-) create mode 100644 backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/DefaultArgumentStubGenerator.kt delete mode 100644 backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/DefaultParameterStubGenerator.kt diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanLower.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanLower.kt index 55d5d6bc0c4..f1fdb17c8e7 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanLower.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanLower.kt @@ -31,7 +31,7 @@ internal class KonanLower(val context: Context) { VarargInjectionLowering(context).runOnFilePostfix(irFile) } phaser.phase(KonanPhase.LOWER_DEFAULT_PARAMETER_EXTENT) { - DefaultParameterStubGenerator(context).runOnFilePostfix(irFile) + DefaultArgumentStubGenerator(context).runOnFilePostfix(irFile) DefaultParameterInjector(context).runOnFilePostfix(irFile) } phaser.phase(KonanPhase.LOWER_BUILTIN_OPERATORS) { diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/Ir.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/Ir.kt index b1e6784fa56..9384b1f2de0 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/Ir.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/ir/Ir.kt @@ -1,7 +1,6 @@ package org.jetbrains.kotlin.backend.konan.ir import org.jetbrains.kotlin.backend.konan.Context -import org.jetbrains.kotlin.backend.konan.lower.DefaultParameterDescription import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.ir.declarations.IrModuleFragment import org.jetbrains.kotlin.descriptors.PropertyDescriptor @@ -10,7 +9,7 @@ import org.jetbrains.kotlin.descriptors.PropertyDescriptor internal class Ir(val context: Context, val irModule: IrModuleFragment) { val propertiesWithBackingFields = mutableSetOf() - val defaultParameterDescriptions = mutableMapOf() + val defaultParameterDescriptorsCache = mutableMapOf() val originalModuleIndex = ModuleIndex(irModule) diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/DefaultArgumentStubGenerator.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/DefaultArgumentStubGenerator.kt new file mode 100644 index 00000000000..48be11799a1 --- /dev/null +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/DefaultArgumentStubGenerator.kt @@ -0,0 +1,391 @@ +package org.jetbrains.kotlin.backend.konan.lower + +import org.jetbrains.kotlin.backend.common.BodyLoweringPass +import org.jetbrains.kotlin.backend.common.DeclarationContainerLoweringPass +import org.jetbrains.kotlin.backend.common.lower.createIrBuilder +import org.jetbrains.kotlin.backend.common.lower.irBlockBody +import org.jetbrains.kotlin.backend.konan.Context +import org.jetbrains.kotlin.backend.konan.KonanPlatform +import org.jetbrains.kotlin.backend.konan.ir.ir2string +import org.jetbrains.kotlin.builtins.KotlinBuiltIns +import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.descriptors.annotations.Annotations +import org.jetbrains.kotlin.descriptors.impl.ClassConstructorDescriptorImpl +import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl +import org.jetbrains.kotlin.descriptors.impl.TypeParameterDescriptorImpl +import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl +import org.jetbrains.kotlin.ir.IrElement +import org.jetbrains.kotlin.ir.builders.* +import org.jetbrains.kotlin.ir.declarations.IrDeclarationContainer +import org.jetbrains.kotlin.ir.declarations.IrDeclarationOriginImpl +import org.jetbrains.kotlin.ir.declarations.IrFunction +import org.jetbrains.kotlin.ir.declarations.impl.IrConstructorImpl +import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl +import org.jetbrains.kotlin.ir.expressions.* +import org.jetbrains.kotlin.ir.expressions.impl.* +import org.jetbrains.kotlin.ir.util.transformFlat +import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid +import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.resolve.DescriptorUtils +import org.jetbrains.kotlin.resolve.descriptorUtil.hasDefaultValue +import org.jetbrains.kotlin.types.KotlinType +import org.jetbrains.kotlin.utils.addToStdlib.singletonList + +class DefaultArgumentStubGenerator internal constructor(val context: Context): DeclarationContainerLoweringPass { + override fun lower(irDeclarationContainer: IrDeclarationContainer) { + irDeclarationContainer.declarations.transformFlat { memberDeclaration -> + if (memberDeclaration is IrFunction) + lower(memberDeclaration) + else + null + } + + } + + object DECLARATION_ORIGIN_FUNCTION_FOR_DEFAULT_PARAMETER : + IrDeclarationOriginImpl("DEFAULT_PARAMETER_EXTENT") + + private fun lower(irFunction: IrFunction): List { + val functionDescriptor = irFunction.descriptor + + if (hasNotDefaultParameters(functionDescriptor)) + return irFunction.singletonList() + + val bodies = functionDescriptor.valueParameters + .mapNotNull{irFunction.getDefault(it)} + + + log("detected ${functionDescriptor.name.asString()} has got #${bodies.size} default expressions") + functionDescriptor.overriddenDescriptors.forEach { context.log("DEFAULT-REPLACER: $it") } + if (bodies.isNotEmpty()) { + val descriptor = functionDescriptor.generateDefaultsDescription(context) + log("$functionDescriptor -> $descriptor") + val builder = context.createIrBuilder(descriptor) + val body = builder.irBlockBody(irFunction) { + val params = mutableListOf() + val variables = mutableMapOf() + + val newExtensionReceiver = + if (descriptor.extensionReceiverParameter == null) { + null + } else { + IrGetValueImpl( + startOffset = irFunction.startOffset, + endOffset = irFunction.endOffset, + descriptor = descriptor.extensionReceiverParameter!!, + origin = null + ) + } + + for (valueParameter in functionDescriptor.valueParameters) { + val parameterDescriptor = descriptor.valueParameters[valueParameter.index] + if (valueParameter.hasDefaultValue()) { + val variable = scope.createTemporaryVariable( + irExpression = nullConst(irFunction, valueParameter.type)!!, + isMutable = true) + val variableDescriptor = variable.descriptor + params.add(variableDescriptor) + +variable + val condition = irNotEquals(irCall(Helper.kIntAnd).apply { + dispatchReceiver = irGet(maskParameterDescriptor(descriptor)) + putValueArgument(0, irInt(1 shl valueParameter.index)) + }, irInt(0)) + val expressionBody = getDefaultParameterExpressionBody(irFunction, valueParameter) + /* Use previously calculated values in next expression. */ + expressionBody.expression.transformChildrenVoid(object:IrElementTransformerVoid() { + override fun visitGetValue(expression: IrGetValue): IrExpression { + if (expression.descriptor == functionDescriptor.extensionReceiverParameter) + return newExtensionReceiver!! + if (!variables.containsKey(expression.descriptor)) + return expression + return irGet(variables[expression.descriptor] as VariableDescriptor) + } + }) + /* Mapping calculated values with its origin variables. */ + variables.put(valueParameter, variableDescriptor) + +irIfThenElse( + type = KonanPlatform.builtIns.unitType, + condition = condition, + thenPart = irSetVar(variableDescriptor, expressionBody.expression), + elsePart = irSetVar(variableDescriptor, irGet(parameterDescriptor))) + } else { + params.add(parameterDescriptor) + } + } + if (functionDescriptor is ClassConstructorDescriptor) { + + irReturn(IrDelegatingConstructorCallImpl( + startOffset = irFunction.startOffset, + endOffset = irFunction.endOffset, + descriptor = functionDescriptor + ).apply { + params.forEachIndexed { i, variable -> + putValueArgument(i, irGet(variable)) + } + if (functionDescriptor.dispatchReceiverParameter != null) { + dispatchReceiver = irThis() + } + }) + } else { + +irReturn(irCall(functionDescriptor).apply { + if (functionDescriptor.dispatchReceiverParameter != null) { + dispatchReceiver = irThis() + } + if (functionDescriptor.extensionReceiverParameter != null) { + extensionReceiver = newExtensionReceiver + } + params.forEachIndexed { i, variable -> + putValueArgument(i, irGet(variable)) + } + }) + } + } + return if (functionDescriptor is ClassConstructorDescriptor) + listOf(irFunction, IrConstructorImpl( + startOffset = irFunction.startOffset, + endOffset = irFunction.endOffset, + descriptor = descriptor as ClassConstructorDescriptor, + origin = DECLARATION_ORIGIN_FUNCTION_FOR_DEFAULT_PARAMETER, + body = body)) + else + listOf(irFunction, IrFunctionImpl( + startOffset = irFunction.startOffset, + endOffset = irFunction.endOffset, + descriptor = descriptor, + origin = DECLARATION_ORIGIN_FUNCTION_FOR_DEFAULT_PARAMETER, + body = body)) + } + return irFunction.singletonList() + } + + + private fun log(msg:String) = context.log("DEFAULT-REPLACER: $msg") +} + +private fun getDefaultParameterExpressionBody(irFunction: IrFunction, valueParameter: ValueParameterDescriptor):IrExpressionBody { + return irFunction.getDefault(valueParameter) as? IrExpressionBody ?: TODO("FIXME!!!") +} + +private fun maskParameterDescriptor(descriptor: FunctionDescriptor) = descriptor.valueParameters.single { it.name == Helper.kParameterMaskName } + +private fun markerParameterDescriptor(descriptor: FunctionDescriptor) = descriptor.valueParameters.single {it.name == Helper.kConstructorMarkerName} + +private fun nullConst(expression: IrElement, type: KotlinType): IrExpression? { + when { + KotlinBuiltIns.isFloat(type) -> return IrConstImpl.float (expression.startOffset, expression.endOffset, type, 0.0F) + KotlinBuiltIns.isDouble(type) -> return IrConstImpl.double (expression.startOffset, expression.endOffset, type, 0.0) + KotlinBuiltIns.isBoolean(type) -> return IrConstImpl.boolean (expression.startOffset, expression.endOffset, type, false) + KotlinBuiltIns.isByte(type) -> return IrConstImpl.byte (expression.startOffset, expression.endOffset, type, 0) + KotlinBuiltIns.isChar(type) -> return IrConstImpl.char (expression.startOffset, expression.endOffset, type, 0.toChar()) + KotlinBuiltIns.isShort(type) -> return IrConstImpl.short (expression.startOffset, expression.endOffset, type, 0) + KotlinBuiltIns.isInt(type) -> return IrConstImpl.int (expression.startOffset, expression.endOffset, type, 0) + KotlinBuiltIns.isLong(type) -> return IrConstImpl.long (expression.startOffset, expression.endOffset, type, 0) + else -> return IrConstImpl.constNull (expression.startOffset, expression.endOffset, type) + } +} + +class DefaultParameterInjector internal constructor(val context: Context): BodyLoweringPass { + override fun lower(irBody: IrBody) { + + irBody.transformChildrenVoid(object : IrElementTransformerVoid() { + override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall): IrExpression { + super.visitDelegatingConstructorCall(expression) + val descriptor = expression.descriptor + if (hasNotDefaultParameters(descriptor)) + return expression + val argumentsCount = argumentCount(expression) + if (argumentsCount == descriptor.valueParameters.size) + return expression + val (desc, params) = parametersForCall(expression) + return IrDelegatingConstructorCallImpl( + startOffset = expression.startOffset, + endOffset = expression.endOffset, + descriptor = desc as ClassConstructorDescriptor) + .apply { + params.forEach { + log("call::params@${it.first.index}/${it.first.name.asString()}: ${ir2string(it.second)}") + putValueArgument(it.first.index, it.second) + } + } + + } + + override fun visitCall(expression: IrCall): IrExpression { + super.visitCall(expression) + val functionDescriptor = expression.descriptor as FunctionDescriptor + + if (hasNotDefaultParameters(functionDescriptor)) + return expression + + val argumentsCount = argumentCount(expression) + if (argumentsCount == functionDescriptor.valueParameters.size) + return expression + val (descriptor, params) = parametersForCall(expression) + descriptor.typeParameters.forEach { log("$descriptor [${it.index}]: $it") } + descriptor.original.typeParameters.forEach { log("${descriptor.original}[${it.index}] : $it") } + return IrCallImpl( + startOffset = expression.startOffset, + endOffset = expression.endOffset, + descriptor = descriptor, + typeArguments = expression.descriptor.typeParameters.map{it to (expression.getTypeArgument(it) ?: it.defaultType) }.toMap()) + .apply { + params.forEach { + log("call::params@${it.first.index}/${it.first.name.asString()}: ${ir2string(it.second)}") + putValueArgument(it.first.index, it.second) + } + expression.extensionReceiver?.apply{ + extensionReceiver = expression.extensionReceiver + } + expression.dispatchReceiver?.apply { + dispatchReceiver = expression.dispatchReceiver + } + log("call::extension@: ${ir2string(expression.extensionReceiver)}") + log("call::dispatch@: ${ir2string(expression.dispatchReceiver)}") + } + } + + private fun parametersForCall(expression: IrMemberAccessExpression): Pair>> { + val descriptor = expression.descriptor as FunctionDescriptor + val keyDescriptor = if (DescriptorUtils.isOverride(descriptor)) + DescriptorUtils.getAllOverriddenDescriptors(descriptor).first() + else + descriptor.original + val realDescriptor = keyDescriptor.generateDefaultsDescription(context) + + log("$descriptor -> $realDescriptor") + var maskValue = 0 + val params = mutableListOf>() + params.addAll(descriptor.valueParameters.mapIndexed { i, _ -> + val valueArgument = expression.getValueArgument(i) + if (valueArgument == null) maskValue = maskValue or (1 shl i) + val valueParameterDescriptor = realDescriptor.valueParameters[i] + val pair = valueParameterDescriptor to (valueArgument ?: nullConst(expression, valueParameterDescriptor.type)) + return@mapIndexed pair + }) + params += maskParameterDescriptor(realDescriptor) to IrConstImpl( + startOffset = irBody.startOffset, + endOffset = irBody.endOffset, + type = KonanPlatform.builtIns.intType, + kind = IrConstKind.Int, + value = maskValue) + if (expression.descriptor is ClassConstructorDescriptor) { + params += markerParameterDescriptor(realDescriptor) to IrGetObjectValueImpl( + irBody.startOffset, + irBody.endOffset, + Helper.kDefaultArgumentMarkerClassDescriptor.defaultType, + Helper.kDefaultArgumentMarkerClassDescriptor) + } + params.forEach { + log("descriptor::${realDescriptor.name.asString()}#${it.first.index}: ${it.first.name.asString()}") + } + return Pair(realDescriptor, params) + } + + private fun argumentCount(expression: IrMemberAccessExpression) = + expression.descriptor.valueParameters.count { expression.getValueArgument(it) != null } + }) + } + + private fun log(msg: String) = context.log("DEFAULT-INJECTOR: $msg") +} + +private fun hasNotDefaultParameters(descriptor: CallableDescriptor) = descriptor.valueParameters.none { it.hasDefaultValue() } + + +private fun FunctionDescriptor.generateDefaultsDescription(context: Context): FunctionDescriptor { + return context.ir.defaultParameterDescriptorsCache.getOrPut(this) { + val descriptor = when (this) { + is ClassConstructorDescriptor -> + ClassConstructorDescriptorImpl.create( + /* containingDeclaration = */ containingDeclaration, + /* annotations = */ annotations, + /* isPrimary = */ false, + /* source = */ SourceElement.NO_SOURCE) + is FunctionDescriptor -> { + val name = Name.identifier("$name\$default") + + SimpleFunctionDescriptorImpl.create( + /* containingDeclaration = */ if (DescriptorUtils.isOverride(this)) this.overriddenDescriptors.first().containingDeclaration as ClassDescriptor else containingDeclaration, + /* annotations = */ annotations, + /* name = */ name, + /* kind = */ CallableMemberDescriptor.Kind.SYNTHESIZED, + /* source = */ SourceElement.NO_SOURCE) + } + else -> TODO("FIXME: $this") + } + + val syntheticParameters = mutableListOf(valueParameter(descriptor, valueParameters.size, Helper.kParameterMaskName, KonanPlatform.builtIns.intType)) + if (this is ClassConstructorDescriptor) { + syntheticParameters += valueParameter(descriptor, syntheticParameters.last().index + 1, + Helper.kConstructorMarkerName, + Helper.kDefaultArgumentMarkerClassDescriptor.defaultType) + } + descriptor.initialize( + /* receiverParameterType = */ extensionReceiverParameter?.type, + /* dispatchReceiverParameter = */ dispatchReceiverParameter, + /* typeParameters = */ typeParameters.map { + TypeParameterDescriptorImpl.createForFurtherModification( + /* containingDeclaration = */ descriptor, + /* annotations = */ it.annotations, + /* reified = */ it.isReified, + /* variance = */ it.variance, + /* name = */ it.name, + /* index = */ it.index, + /* source = */ it.source, + /* reportCycleError = */ null, + /* supertypeLoopsChecker = */ SupertypeLoopChecker.EMPTY + ).apply { + it.upperBounds.forEach { addUpperBound(it) } + setInitialized() + } + }, + /* unsubstitutedValueParameters = */ valueParameters.map { + ValueParameterDescriptorImpl( + containingDeclaration = descriptor, + original = null, /* ValueParameterDescriptorImpl::copy do not save original. */ + index = it.index, + annotations = it.annotations, + name = it.name, + outType = it.type, + declaresDefaultValue = false, + isCrossinline = it.isCrossinline, + isNoinline = it.isNoinline, + varargElementType = it.varargElementType, + source = it.source) + } + syntheticParameters, + /* unsubstitutedReturnType = */ returnType, + /* modality = */ Modality.FINAL, + /* visibility = */ this.visibility) + context.log("adds to cache[$this] = $descriptor") + descriptor + } +} + +private fun valueParameter(descriptor: FunctionDescriptor, index: Int, name: Name, type: KotlinType):ValueParameterDescriptor { + return ValueParameterDescriptorImpl( + containingDeclaration = descriptor, + original = null, + index = index, + annotations = Annotations.EMPTY, + name = name, + outType = type, + declaresDefaultValue = false, + isCrossinline = false, + isNoinline = false, + varargElementType = null, + source = SourceElement.NO_SOURCE + ) +} + +internal object Helper { + val kIntDesctiptor = DescriptorUtils.getClassDescriptorForType(KonanPlatform.builtIns.intType) + val kIntAnd = DescriptorUtils.getFunctionByName(kIntDesctiptor.unsubstitutedMemberScope, Name.identifier("and")) + + val kKonanInternalPackageDescriptor = KonanPlatform.builtIns.builtInsModule.getPackage(FqName("konan.internal")) + val kDefaultArgumentMarkerName = Name.identifier("DefaultArgumentMarker") + val kParameterMaskName = Name.identifier("__\$mask\$__") + val kConstructorMarkerName = Name.identifier("__\$marker\$__") + val kDefaultArgumentMarkerClassDescriptor = DescriptorUtils.getAllDescriptors(kKonanInternalPackageDescriptor.memberScope) + .first{ it is ClassDescriptor && it.name == kDefaultArgumentMarkerName} as ClassDescriptor +} \ No newline at end of file diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/DefaultParameterStubGenerator.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/DefaultParameterStubGenerator.kt deleted file mode 100644 index 0510b1d4fdd..00000000000 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/DefaultParameterStubGenerator.kt +++ /dev/null @@ -1,379 +0,0 @@ -package org.jetbrains.kotlin.backend.konan.lower - -import org.jetbrains.kotlin.backend.common.BodyLoweringPass -import org.jetbrains.kotlin.backend.common.DeclarationContainerLoweringPass -import org.jetbrains.kotlin.backend.common.lower.createIrBuilder -import org.jetbrains.kotlin.backend.common.lower.irBlockBody -import org.jetbrains.kotlin.backend.konan.Context -import org.jetbrains.kotlin.backend.konan.KonanPlatform -import org.jetbrains.kotlin.backend.konan.ir.ir2string -import org.jetbrains.kotlin.builtins.KotlinBuiltIns -import org.jetbrains.kotlin.descriptors.* -import org.jetbrains.kotlin.descriptors.annotations.Annotations -import org.jetbrains.kotlin.descriptors.impl.ClassConstructorDescriptorImpl -import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl -import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl -import org.jetbrains.kotlin.ir.IrElement -import org.jetbrains.kotlin.ir.builders.* -import org.jetbrains.kotlin.ir.declarations.IrDeclarationContainer -import org.jetbrains.kotlin.ir.declarations.IrDeclarationOriginImpl -import org.jetbrains.kotlin.ir.declarations.IrFunction -import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl -import org.jetbrains.kotlin.ir.expressions.* -import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl -import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl -import org.jetbrains.kotlin.ir.expressions.impl.IrDelegatingConstructorCallImpl -import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl -import org.jetbrains.kotlin.ir.util.transformFlat -import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid -import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid -import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid -import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid -import org.jetbrains.kotlin.name.Name -import org.jetbrains.kotlin.resolve.DescriptorUtils -import org.jetbrains.kotlin.resolve.descriptorUtil.hasDefaultValue -import org.jetbrains.kotlin.types.KotlinType -import org.jetbrains.kotlin.utils.addToStdlib.singletonList - -class DefaultParameterStubGenerator internal constructor(val context: Context): DeclarationContainerLoweringPass { - override fun lower(irDeclarationContainer: IrDeclarationContainer) { - irDeclarationContainer.declarations.transformFlat { memberDeclaration -> - if (memberDeclaration is IrFunction) - lower(memberDeclaration) - else - null - } - - } - - object DECLARATION_ORIGIN_FUNCTION_FOR_DEFAULT_PARAMETER : - IrDeclarationOriginImpl("DEFAULT_PARAMETER_EXTENT") - - private fun lower(irFunction: IrFunction): List { - val bodies = mutableListOf() - val functionDescriptor = irFunction.descriptor - - if (hasNotDefaultParameters(functionDescriptor)) - return irFunction.singletonList() - - irFunction.acceptChildrenVoid(object:IrElementVisitorVoid{ - override fun visitExpressionBody(body: IrExpressionBody) { - bodies.add(body) - } - - override fun visitElement(element: IrElement) { - element.acceptChildrenVoid(this) - } - }) - - log("detected ${functionDescriptor.name.asString()} has got #${bodies.size} default expressions") - functionDescriptor.overriddenDescriptors.forEach { context.log("DEFAULT-REPLACER: $it") } - if (bodies.isNotEmpty()) { - val description = functionDescriptor.getOrCreateDefaultsDescription(context) - val builder = context.createIrBuilder(description.function) - val body = builder.irBlockBody(irFunction) { - val params = mutableListOf() - val variables = mutableMapOf() - - val newExtensionReceiver = - if (description.function.extensionReceiverParameter == null) { - null - } else { - IrGetValueImpl( - startOffset = irFunction.startOffset, - endOffset = irFunction.endOffset, - descriptor = description.function.extensionReceiverParameter!!, - origin = null - ) - } - - for (valueParameter in functionDescriptor.valueParameters) { - val parameterDescriptor = description.function.valueParameters[valueParameter.index] - if (valueParameter.hasDefaultValue()) { - val variable = scope.createTemporaryVariable( - irExpression = nullConst(valueParameter.type)!!, - isMutable = true) - val variableDescriptor = variable.descriptor - params.add(variableDescriptor) - +variable - val condition = irNotEquals(irCall(intAnd).apply { - dispatchReceiver = irGet(description.mask) - putValueArgument(0, irInt(1 shl valueParameter.index)) - }, irInt(0)) - val exprBody = getDefaultParameterExpressionBody(irFunction, valueParameter) - /* Use previously calculated values in next expression. */ - exprBody.expression.transformChildrenVoid(object:IrElementTransformerVoid() { - override fun visitGetValue(expression: IrGetValue): IrExpression { - if (expression.descriptor == functionDescriptor.extensionReceiverParameter) - return newExtensionReceiver!! - if (!variables.containsKey(expression.descriptor)) - return expression - return irGet(variables[expression.descriptor] as VariableDescriptor) - } - }) - /* Mapping calculated values with its origin variables. */ - variables.put(valueParameter, variableDescriptor) - +irIfThenElse( - type = KonanPlatform.builtIns.unitType, - condition = condition, - thenPart = irSetVar(variableDescriptor, exprBody.expression), - elsePart = irSetVar(variableDescriptor, irGet(parameterDescriptor))) - } else { - params.add(parameterDescriptor) - } - } - if (functionDescriptor !is ClassConstructorDescriptor) { - +irReturn(irCall(functionDescriptor).apply { - if (functionDescriptor.dispatchReceiverParameter != null) { - dispatchReceiver = irThis() - } - if (functionDescriptor.extensionReceiverParameter != null) { - extensionReceiver = newExtensionReceiver - } - params.forEachIndexed { i, variable -> - putValueArgument(i, irGet(variable)) - } - }) - } else { - + irReturn(IrDelegatingConstructorCallImpl( - startOffset = irFunction.startOffset, - endOffset = irFunction.endOffset, - descriptor = functionDescriptor - ).apply { - params.forEachIndexed { i, variable -> - putValueArgument(i, irGet(variable)) - } - }) - } - } - // TODO: replace irFunction with new one without expression bodies. - return listOf(irFunction, IrFunctionImpl( - irFunction.startOffset, - irFunction.endOffset, - DECLARATION_ORIGIN_FUNCTION_FOR_DEFAULT_PARAMETER, - description.function, body)) - } - return irFunction.singletonList() - } - - private fun log(msg:String) = context.log("DEFAULT-REPLACER: $msg") -} - -private fun getDefaultParameterExpressionBody(irFunction: IrFunction, valueParameter: ValueParameterDescriptor):IrExpressionBody { - return irFunction.getDefault(valueParameter) as? IrExpressionBody ?: TODO("FIXME!!!") -} - -private fun nullConst(type: KotlinType): IrExpression? { - when { - KotlinBuiltIns.isFloat(type) -> return IrConstImpl (0, 0, type, IrConstKind.Float, 0.0F) - KotlinBuiltIns.isDouble(type) -> return IrConstImpl (0, 0, type, IrConstKind.Double, 0.0) - KotlinBuiltIns.isBoolean(type) -> return IrConstImpl (0, 0, type, IrConstKind.Boolean, false) - KotlinBuiltIns.isByte(type) -> return IrConstImpl (0, 0, type, IrConstKind.Byte, 0) - KotlinBuiltIns.isShort(type) -> return IrConstImpl (0, 0, type, IrConstKind.Short, 0) - KotlinBuiltIns.isInt(type) -> return IrConstImpl (0, 0, type, IrConstKind.Int, 0) - KotlinBuiltIns.isLong(type) -> return IrConstImpl (0, 0, type, IrConstKind.Long, 0) - else -> return IrConstImpl(0, 0, type, IrConstKind.Null, null) - } -} - -class DefaultParameterInjector internal constructor(val context: Context): BodyLoweringPass { - override fun lower(irBody: IrBody) { - irBody.transformChildrenVoid(object : IrElementTransformerVoid() { - override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall): IrExpression { - super.visitDelegatingConstructorCall(expression) - val descriptor = expression.descriptor - if (hasNotDefaultParameters(descriptor)) - return expression - val argumentsCount = argumentCount(expression) - if (argumentsCount == descriptor.valueParameters.size) - return expression - val (desc, params) = parametersForCall(expression) - return IrDelegatingConstructorCallImpl( - startOffset = irBody.startOffset, - endOffset = irBody.endOffset, - descriptor = desc.function as ClassConstructorDescriptor) - .apply { - params.forEach { - log("call::params@${it.first.index}/${it.first.name.asString()}: ${ir2string(it.second)}") - putValueArgument(it.first.index, it.second) - } - } - } - - override fun visitCall(expression: IrCall): IrExpression { - super.visitCall(expression) - val functionDescriptor = expression.descriptor as FunctionDescriptor - - if (hasNotDefaultParameters(functionDescriptor)) - return expression - - val argumentsCount = argumentCount(expression) - if (argumentsCount == functionDescriptor.valueParameters.size) - return expression - val (desc, params) = parametersForCall(expression) - return IrCallImpl( - startOffset = irBody.startOffset, - endOffset = irBody.endOffset, - type = desc.function.returnType!!, - descriptor = desc.function, - typeArguments = null) - .apply { - params.forEach { - log("call::params@${it.first.index}/${it.first.name.asString()}: ${ir2string(it.second)}") - putValueArgument(it.first.index, it.second) - } - expression.extensionReceiver?.apply{ - extensionReceiver = expression.extensionReceiver - } - expression.dispatchReceiver?.apply { - dispatchReceiver = expression.dispatchReceiver - } - log("call::extension@: ${ir2string(expression.extensionReceiver)}") - log("call::dispatch@: ${ir2string(expression.dispatchReceiver)}") - } - } - - private fun parametersForCall(expression: IrMemberAccessExpression): Pair>> { - var maskValue = 0 - val rawDescriptor = expression.descriptor as FunctionDescriptor - val descriptor = rawDescriptor.overriddenDescriptors.firstOrNull()?:rawDescriptor - val desc = descriptor.getOrCreateDefaultsDescription(context) - descriptor.valueParameters.forEach { - log("descriptor::${descriptor.name.asString()}#${it.index}: ${it.name.asString()}") - } - val params = descriptor.valueParameters.mapIndexed { i, _ -> - val valueArgument = expression.getValueArgument(i) - if (valueArgument == null) maskValue = maskValue or (1 shl i) - val valueParameterDescriptor = desc.function.valueParameters[i] - val pair = valueParameterDescriptor to (valueArgument ?: nullConst(valueParameterDescriptor.type)) - return@mapIndexed pair - } + (desc.mask to IrConstImpl( - startOffset = irBody.startOffset, - endOffset = irBody.endOffset, - type = KonanPlatform.builtIns.intType, - kind = IrConstKind.Int, - value = maskValue)) - params.forEach { - log("descriptor::${desc.function.name.asString()}#${it.first.index}: ${it.first.name.asString()}") - } - return Pair(desc, params) - } - - private fun argumentCount(expression: IrMemberAccessExpression): Int { - var argumentsCount = 0 - expression.acceptChildrenVoid(object : IrElementVisitorVoid { - override fun visitElement(element: IrElement) { - argumentsCount++ - } - }) - val descriptor = expression.descriptor - if (descriptor !is ConstructorDescriptor && (descriptor.dispatchReceiverParameter != null || descriptor.extensionReceiverParameter != null)) - argumentsCount-- - return argumentsCount - } - }) - } - - private fun log(msg: String) = context.log("DEFAULT-INJECTOR: $msg") -} - -private fun hasNotDefaultParameters(descriptor: CallableDescriptor) = descriptor.valueParameters.none { it.hasDefaultValue() } - -val intDesctiptor = DescriptorUtils.getClassDescriptorForType(KonanPlatform.builtIns.intType) -val intAnd = DescriptorUtils.getFunctionByName(intDesctiptor.unsubstitutedMemberScope, Name.identifier("and")) - -data class DefaultParameterDescription(val function: FunctionDescriptor, val mask:ValueParameterDescriptor, - val hasExtensionReceiver:Boolean, val hasDispatchReceiver: Boolean) - -private fun FunctionDescriptor.getOrCreateDefaultsDescription(context: Context): DefaultParameterDescription { - return context.ir.defaultParameterDescriptions.getOrPut(this) { - this.generateDefaultsDescription(context) - } -} - -private fun FunctionDescriptor.generateDefaultsDescription(context: Context): DefaultParameterDescription { - val descriptor = when (this){ - is ConstructorDescriptor -> DefaultParameterClassConstructorDescriptor( - containingDeclaration = this.containingDeclaration as ClassDescriptor, - annotations = annotations, - original = null, - isPrimary = false, - source = SourceElement.NO_SOURCE, - kind = CallableMemberDescriptor.Kind.SYNTHESIZED) - - is FunctionDescriptor -> SimpleFunctionDescriptorImpl.create( - /* containingDeclaration = */ this.containingDeclaration, - /* annotations = */ Annotations.EMPTY, - /* name = */ name, - /* kind = */ CallableMemberDescriptor.Kind.SYNTHESIZED, - /* source = */ SourceElement.NO_SOURCE) - else -> TODO("FIXME!!!") - } - - val parameterList = mutableListOf() - - val maskVariable = valueParameter(descriptor, valueParameters.size , "__\$mask\$__", KonanPlatform.builtIns.intType) - - parameterList += valueParameters.map{ - ValueParameterDescriptorImpl( - containingDeclaration = it.containingDeclaration, - original = it.original, - index = it.index, - annotations = it.annotations, - name = it.name, - outType = it.type, - declaresDefaultValue = false, - isCrossinline = it.isCrossinline, - isNoinline = it.isNoinline, - varargElementType = it.varargElementType, - source = it.source) - } - - parameterList.add(maskVariable) - descriptor.initialize( - /* receiverParameterType = */ extensionReceiverParameter?.type, - /* dispatchReceiverParameter = */ dispatchReceiverParameter, - /* typeParameters = */ typeParameters, - /* unsubstitutedValueParameters = */ parameterList, - /* unsubstitutedReturnType = */ returnType, - /* modality = */ Modality.FINAL, - /* visibility = */ this.visibility) - return DefaultParameterDescription( - function = descriptor, - mask = maskVariable, - hasDispatchReceiver = (extensionReceiverParameter != null), - hasExtensionReceiver = (dispatchReceiverParameter != null)) -} - -private fun valueParameter(descriptor: FunctionDescriptor, index: Int, name: String, type: KotlinType):ValueParameterDescriptor { - return ValueParameterDescriptorImpl( - containingDeclaration = descriptor, - original = null, - index = index, - annotations = Annotations.EMPTY, - name = Name.identifier(name), - outType = type, - declaresDefaultValue = false, - isCrossinline = false, - isNoinline = false, - varargElementType = null, - source = SourceElement.NO_SOURCE - ) -} - -/** - * This descriptor overrides name property, for class constructor : instead of -> $defeult symbol. - */ -class DefaultParameterClassConstructorDescriptor( - containingDeclaration: ClassDescriptor, - original: ConstructorDescriptor?, - annotations: Annotations, - isPrimary: Boolean, - kind: CallableMemberDescriptor.Kind, - source: SourceElement -) : ClassConstructorDescriptorImpl(containingDeclaration, original, annotations, isPrimary, kind, source) { - - override fun getName(): Name { - return Name.identifier("${super.getName().asString()}\$default") - } -} \ No newline at end of file