From 8df6ff5215cdbaae62b5f9930e0fb25a66ede323 Mon Sep 17 00:00:00 2001 From: Igor Chevdar Date: Tue, 5 Dec 2017 17:21:16 +0300 Subject: [PATCH] Added bridges building for workers --- .../kotlin/backend/konan/KonanLower.kt | 1 + .../backend/konan/lower/BridgesBuilding.kt | 264 +++++++++++------- 2 files changed, 163 insertions(+), 102 deletions(-) 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 9d5e1cab998..9d678262155 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 @@ -132,6 +132,7 @@ internal class KonanLower(val context: Context) { } phaser.phase(KonanPhase.BRIDGES_BUILDING) { BridgesBuilding(context).runOnFilePostfix(irFile) + WorkersBridgesBuilding(context).lower(irFile) } phaser.phase(KonanPhase.AUTOBOX) { validateIrFile(context, irFile) diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/BridgesBuilding.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/BridgesBuilding.kt index 903c914d247..d81b1a941ed 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/BridgesBuilding.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/BridgesBuilding.kt @@ -17,6 +17,7 @@ package org.jetbrains.kotlin.backend.konan.lower import org.jetbrains.kotlin.backend.common.ClassLoweringPass +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.common.lower.irIfThen @@ -24,38 +25,95 @@ import org.jetbrains.kotlin.backend.konan.Context import org.jetbrains.kotlin.backend.konan.descriptors.* import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.descriptors.annotations.Annotations +import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl import org.jetbrains.kotlin.ir.IrStatement -import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.builders.* -import org.jetbrains.kotlin.ir.declarations.IrClass -import org.jetbrains.kotlin.ir.declarations.IrDeclarationOriginImpl -import org.jetbrains.kotlin.ir.declarations.IrFunction -import org.jetbrains.kotlin.ir.declarations.IrProperty +import org.jetbrains.kotlin.ir.declarations.* 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.symbols.IrClassSymbol import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol import org.jetbrains.kotlin.ir.util.createParameterDeclarations +import org.jetbrains.kotlin.ir.util.transformFlat import org.jetbrains.kotlin.ir.util.type import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.load.java.BuiltinMethodsWithSpecialGenericSignature import org.jetbrains.kotlin.types.KotlinType -internal class BridgesBuilding(val context: Context) : ClassLoweringPass { +internal class WorkersBridgesBuilding(val context: Context) : DeclarationContainerLoweringPass, IrElementTransformerVoid() { - private fun IrBuilderWithScope.returnIfBadType(value: IrExpression, - type: KotlinType, - returnValueOnFail: IrExpression) - = irIfThen(irNotIs(value, type), irReturn(returnValueOnFail)) + val interop = context.interopBuiltIns + val symbols = context.ir.symbols + val nullableAnyType = context.builtIns.nullableAnyType + var runtimeJobDescriptor: FunctionDescriptor? = null - private fun IrBuilderWithScope.irConst(value: Any?) = when (value) { - null -> irNull() - is Int -> irInt(value) - is Boolean -> if (value) irTrue() else irFalse() - else -> TODO() + override fun lower(irDeclarationContainer: IrDeclarationContainer) { + irDeclarationContainer.declarations.transformFlat { + listOf(it) + buildWorkerBridges(it) + } } + private fun buildWorkerBridges(declaration: IrDeclaration): List { + val bridges = mutableListOf() + declaration.transformChildrenVoid(object: IrElementTransformerVoid() { + + override fun visitCall(expression: IrCall): IrExpression { + expression.transformChildrenVoid(this) + + val descriptor = expression.descriptor.original + if (descriptor != interop.scheduleImplFunction) + return expression + + val job = expression.getValueArgument(3) as IrFunctionReference + val jobDescriptor = job.descriptor + val arg = jobDescriptor.valueParameters[0] + if (runtimeJobDescriptor == null) { + runtimeJobDescriptor = jobDescriptor.newCopyBuilder() + .setReturnType(nullableAnyType) + .setValueParameters(listOf(ValueParameterDescriptorImpl( + containingDeclaration = jobDescriptor, + original = null, + index = 0, + annotations = Annotations.EMPTY, + name = arg.name, + outType = nullableAnyType, + declaresDefaultValue = arg.declaresDefaultValue(), + isCrossinline = arg.isCrossinline, + isNoinline = arg.isNoinline, + varargElementType = arg.varargElementType, + source = arg.source + ))) + .build()!! + } + val overriddenJobDescriptor = OverriddenFunctionDescriptor(jobDescriptor, runtimeJobDescriptor!!) + if (!overriddenJobDescriptor.needBridge) return expression + + val bridge = context.buildBridge( + startOffset = job.startOffset, + endOffset = job.endOffset, + descriptor = overriddenJobDescriptor, + targetSymbol = job.symbol) + bridges += bridge + expression.putValueArgument(3, IrFunctionReferenceImpl( + startOffset = job.startOffset, + endOffset = job.endOffset, + type = job.type, + symbol = bridge.symbol, + descriptor = bridge.descriptor, + typeArguments = null) + ) + return expression + } + }) + return bridges + } +} + +internal class BridgesBuilding(val context: Context) : ClassLoweringPass { + override fun lower(irClass: IrClass) { val functions = mutableSetOf() irClass.declarations.forEach { @@ -74,108 +132,44 @@ internal class BridgesBuilding(val context: Context) : ClassLoweringPass { functions.filterNotNull() .filterNot { it.modality == Modality.ABSTRACT } .forEach { function -> - function.allOverriddenDescriptors - .map { OverriddenFunctionDescriptor(function, it) } - .filter { !it.bridgeDirections.allNotNeeded() } - .filter { it.canBeCalledVirtually } - .filter { !it.inheritsBridge } - .distinctBy { it.bridgeDirections } - .forEach { - buildBridge(it, irClass) - builtBridges += it.descriptor - } - } + function.allOverriddenDescriptors + .map { OverriddenFunctionDescriptor(function, it) } + .filter { !it.bridgeDirections.allNotNeeded() } + .filter { it.canBeCalledVirtually } + .filter { !it.inheritsBridge } + .distinctBy { it.bridgeDirections } + .forEach { + buildBridge(it, irClass) + builtBridges += it.descriptor + } + } irClass.transformChildrenVoid(object: IrElementTransformerVoid() { override fun visitFunction(declaration: IrFunction): IrStatement { declaration.transformChildrenVoid(this) - val descriptor = declaration.descriptor - val typeSafeBarrierDescription = BuiltinMethodsWithSpecialGenericSignature.getDefaultValueForOverriddenBuiltinFunction(descriptor) - if (typeSafeBarrierDescription == null || builtBridges.contains(descriptor)) - return declaration - val body = declaration.body as? IrBlockBody ?: return declaration + val typeSafeBarrierDescription = BuiltinMethodsWithSpecialGenericSignature.getDefaultValueForOverriddenBuiltinFunction(declaration.descriptor) + if (typeSafeBarrierDescription == null || builtBridges.contains(declaration.descriptor)) + return declaration + val irBuilder = context.createIrBuilder(declaration.symbol, declaration.startOffset, declaration.endOffset) declaration.body = irBuilder.irBlockBody(declaration) { - val valueParameters = declaration.valueParameters - for (i in valueParameters.indices) { - if (!typeSafeBarrierDescription.checkParameter(i)) - continue - val type = valueParameters[i].type - if (type != context.builtIns.nullableAnyType) { - +returnIfBadType(irGet(valueParameters[i].symbol), type, - if (typeSafeBarrierDescription == BuiltinMethodsWithSpecialGenericSignature.TypeSafeBarrierDescription.MAP_GET_OR_DEFAULT) - irGet(valueParameters[2].symbol) - else irConst(typeSafeBarrierDescription.defaultValue) - ) - } - body.statements.forEach { +it } - } + buildTypeSafeBarrier(declaration, typeSafeBarrierDescription) + body.statements.forEach { +it } } return declaration } }) } - private object DECLARATION_ORIGIN_BRIDGE_METHOD : - IrDeclarationOriginImpl("BRIDGE_METHOD") - private fun buildBridge(descriptor: OverriddenFunctionDescriptor, irClass: IrClass) { - val bridgeDescriptor = context.specialDeclarationsFactory.getBridgeDescriptor(descriptor) - val bridge = IrFunctionImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, DECLARATION_ORIGIN_BRIDGE_METHOD, - bridgeDescriptor).apply { createParameterDeclarations() } - - val target = descriptor.descriptor - - assert(target.containingDeclaration == irClass.descriptor) - val superQualifierSymbol = irClass.symbol - val targetSymbol = irClass.findMember(target) // TODO: optimize - - val statements = mutableListOf() - val irBuilder = context.createIrBuilder(bridge.symbol, irClass.startOffset, irClass.endOffset) - irBuilder.run { - val typeSafeBarrierDescription = BuiltinMethodsWithSpecialGenericSignature.getDefaultValueForOverriddenBuiltinFunction(descriptor.overriddenDescriptor) - if (typeSafeBarrierDescription != null) { - val valueParameters = bridge.valueParameters - for (i in valueParameters.indices) { - if (!typeSafeBarrierDescription.checkParameter(i)) - continue - val type = target.valueParameters[i].type - if (type != context.builtIns.nullableAnyType) { - statements += returnIfBadType(irGet(valueParameters[i].symbol), type, - if (typeSafeBarrierDescription == BuiltinMethodsWithSpecialGenericSignature.TypeSafeBarrierDescription.MAP_GET_OR_DEFAULT) - irGet(valueParameters[2].symbol) - else irConst(typeSafeBarrierDescription.defaultValue) - ) - } - } - } - } - - val delegatingCall = IrCallImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, targetSymbol, target, - superQualifierSymbol = superQualifierSymbol /* Call non-virtually */ - ).apply { - val dispatchReceiverParameter = bridge.dispatchReceiverParameter - if (dispatchReceiverParameter != null) - dispatchReceiver = IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, dispatchReceiverParameter.symbol) - val extensionReceiverParameter = bridge.extensionReceiverParameter - if (extensionReceiverParameter != null) - extensionReceiver = IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, extensionReceiverParameter.symbol) - bridge.valueParameters.forEachIndexed { index, parameter -> - this.putValueArgument(index, IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, parameter.symbol)) - } - } - - val bridgeBody = if (bridgeDescriptor.returnType.let { it != null && !KotlinBuiltIns.isUnitOrNullableUnit(it) }) - IrReturnImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, bridge.symbol, delegatingCall) - else - delegatingCall - statements += bridgeBody - irClass.declarations.add( - IrFunctionImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, DECLARATION_ORIGIN_BRIDGE_METHOD, - bridgeDescriptor, IrBlockBodyImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, statements) - ).apply { createParameterDeclarations() } + irClass.declarations.add(context.buildBridge( + startOffset = irClass.startOffset, + endOffset = irClass.endOffset, + descriptor = descriptor, + targetSymbol = irClass.findMember(descriptor.descriptor), // TODO: optimize. + superQualifierSymbol = irClass.symbol) ) } } @@ -188,3 +182,69 @@ private fun IrClass.findMember(descriptor: FunctionDescriptor): IrFunctionSymbol return (functions + propertyAccessors).single { it.descriptor == descriptor } } + +private object DECLARATION_ORIGIN_BRIDGE_METHOD : + IrDeclarationOriginImpl("BRIDGE_METHOD") + +private fun IrBuilderWithScope.returnIfBadType(value: IrExpression, + type: KotlinType, + returnValueOnFail: IrExpression) + = irIfThen(irNotIs(value, type), irReturn(returnValueOnFail)) + +private fun IrBuilderWithScope.irConst(value: Any?) = when (value) { + null -> irNull() + is Int -> irInt(value) + is Boolean -> if (value) irTrue() else irFalse() + else -> TODO() +} + +private fun IrBlockBodyBuilder.buildTypeSafeBarrier(function: IrFunction, + typeSafeBarrierDescription: BuiltinMethodsWithSpecialGenericSignature.TypeSafeBarrierDescription) { + val valueParameters = function.valueParameters + for (i in valueParameters.indices) { + if (!typeSafeBarrierDescription.checkParameter(i)) + continue + val type = valueParameters[i].type + if (type != context.builtIns.nullableAnyType) { + +returnIfBadType(irGet(valueParameters[i].symbol), type, + if (typeSafeBarrierDescription == BuiltinMethodsWithSpecialGenericSignature.TypeSafeBarrierDescription.MAP_GET_OR_DEFAULT) + irGet(valueParameters[2].symbol) + else irConst(typeSafeBarrierDescription.defaultValue) + ) + } + } +} + +private fun Context.buildBridge(startOffset: Int, endOffset: Int, + descriptor: OverriddenFunctionDescriptor, targetSymbol: IrFunctionSymbol, + superQualifierSymbol: IrClassSymbol? = null): IrFunctionImpl { + val bridgeDescriptor = specialDeclarationsFactory.getBridgeDescriptor(descriptor) + val bridge = IrFunctionImpl(startOffset, endOffset, DECLARATION_ORIGIN_BRIDGE_METHOD, + bridgeDescriptor).apply { createParameterDeclarations() } + + val irBuilder = createIrBuilder(bridge.symbol, startOffset, endOffset) + bridge.body = irBuilder.irBlockBody(bridge) { + val typeSafeBarrierDescription = BuiltinMethodsWithSpecialGenericSignature.getDefaultValueForOverriddenBuiltinFunction(descriptor.overriddenDescriptor) + typeSafeBarrierDescription?.let { buildTypeSafeBarrier(bridge, it) } + + val delegatingCall = IrCallImpl(startOffset, endOffset, targetSymbol, descriptor.descriptor, + superQualifierSymbol = superQualifierSymbol /* Call non-virtually */ + ).apply { + bridge.dispatchReceiverParameter?.let { + dispatchReceiver = irGet(it.symbol) + } + bridge.extensionReceiverParameter?.let { + extensionReceiver = irGet(it.symbol) + } + bridge.valueParameters.forEachIndexed { index, parameter -> + this.putValueArgument(index, irGet(parameter.symbol)) + } + } + + if (KotlinBuiltIns.isUnitOrNullableUnit(bridgeDescriptor.returnType!!)) + +delegatingCall + else + +irReturn(delegatingCall) + } + return bridge +} \ No newline at end of file