diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt index ba7f0d0d70b..7580c4a137f 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt @@ -1588,13 +1588,19 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid // Note: the whole function code below is written in the assumption that // `invoke` method receiver is passed as first argument. - val functionImpl = args[0] + val functionImpl = args[0] // Instance of `konan.internal.FunctionImpl`. + // `functionImpl.unboundRef` is the pointer to (static) function of type + // `(FunctionImpl, Arg_1, ..., Arg_n): Ret`. See [CallableReferenceLowering] for details. + // LLVM type for such function is equal to type for `FunctionImpl.invoke(Arg_1, ..., Arg_n): Ret`. + // So we can use the latter for simplicity: val unboundRefType = codegen.getLlvmFunctionType(descriptor) + // Get `functionImpl.unboundRef`: val unboundRef = evaluateSimpleFunctionCall(codegen.newVar(), functionImplUnboundRefGetter, listOf(functionImpl)) + // Cast `functionImpl.unboundRef` to pointer to function: val entryPtr = codegen.bitcast(pointerType(unboundRefType), unboundRef, "entry") return call(descriptor, entryPtr, args, tmpVariableName) diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/CallableReferenceLowering.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/CallableReferenceLowering.kt index cee5aa189ba..39cfffc3da6 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/CallableReferenceLowering.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/CallableReferenceLowering.kt @@ -25,10 +25,13 @@ import org.jetbrains.kotlin.utils.addToStdlib.singletonList * This lowering pass lowers all [IrCallableReference]s to unbound ones. */ internal class CallableReferenceLowering(val context: KonanBackendContext) : DeclarationContainerLoweringPass { + + var callableReferenceCount = 0 + override fun lower(irDeclarationContainer: IrDeclarationContainer) { irDeclarationContainer.declarations.transformFlat { memberDeclaration -> if (memberDeclaration is IrFunction) - lowerCallableReferences(context, memberDeclaration) + lowerCallableReferences(this, memberDeclaration) else null } @@ -39,31 +42,43 @@ internal class CallableReferenceLowering(val context: KonanBackendContext) : Dec * Replaces all callable references in the function body to unbound ones. * Returns the list of this function and all created ones. */ -private fun lowerCallableReferences(context: KonanBackendContext, function: IrFunction): List { - val transformer = CallableReferencesUnbinder(context, function) +private fun lowerCallableReferences(lower: CallableReferenceLowering, function: IrFunction): List { + val transformer = CallableReferencesUnbinder(lower, function) function.transformChildrenVoid(transformer) return function.singletonList() + transformer.createdFunctions } +private object DECLARATION_ORIGIN_FUNCTION_FOR_CALLABLE_REFERENCE : + IrDeclarationOriginImpl("FUNCTION_FOR_CALLABLE_REFERENCE") + /** * Replaces all callable references in the function body to unbound ones. * Adds all created functions to [createdFunctions]. */ -private class CallableReferencesUnbinder(val context: KonanBackendContext, +private class CallableReferencesUnbinder(val lower: CallableReferenceLowering, val function: IrFunction) : IrElementTransformerVoid() { val createdFunctions = mutableListOf() + private val builtIns = lower.context.builtIns + override fun visitElement(element: IrElement): IrElement { return super.visitElement(element) } private val unboundCallableReferenceType by lazy { - context.builtIns.getKonanInternalClass("UnboundCallableReference").defaultType + builtIns.getKonanInternalClass("UnboundCallableReference").defaultType } private val simpleFunctionImplClass by lazy { - context.builtIns.getKonanInternalClass("SimpleFunctionImpl") + builtIns.getKonanInternalClass("SimpleFunctionImpl") + } + + private val simpleFunctionImplBoundArgsGetter by lazy { + simpleFunctionImplClass.defaultType.memberScope.getContributedDescriptors() + .filterIsInstance() + .single { it.name.asString() == "boundArgs" } + .getter!! } override fun visitCallableReference(expression: IrCallableReference): IrExpression { @@ -77,8 +92,8 @@ private class CallableReferencesUnbinder(val context: KonanBackendContext, val startOffset = expression.startOffset val endOffset = expression.endOffset - // The code below creates a call to `SimpleFunctionImpl` constructor which creates the value to be used - // as required callable reference. + // The code below creates a call to `SimpleFunctionImpl` constructor which creates the object implementing + // the function type. // Create the function to be used as `unboundRef` of `SimpleFunctionImpl`: val newFunction = createSimpleFunctionImplTarget(descriptor, unboundParams, boundParams, startOffset, endOffset) @@ -119,20 +134,13 @@ private class CallableReferencesUnbinder(val context: KonanBackendContext, // Create new function declaration: - val origin = object : IrDeclarationOriginImpl("FUNCTION_FOR_CALLABLE_REFERENCE") {} - - val simpleFunctionImplBoundArgsGetter = - simpleFunctionImplClass.defaultType.memberScope.getContributedDescriptors() - .filterIsInstance().filter { it.name.asString() == "boundArgs" } - .single().getter!! - val boundArgsArray = IrCallImpl(startOffset, endOffset, simpleFunctionImplBoundArgsGetter, null).apply { dispatchReceiver = IrGetValueImpl(startOffset, endOffset, newDescriptor.valueParameters[0]) } // TODO: do not call boundArgs getter for each bound argument. val arrayGet = boundArgsArray.type.memberScope.getContributedDescriptors() - .filterIsInstance().filter { it.name.asString() == "get" }.single() + .filterIsInstance().single { it.name.asString() == "get" } // TODO: some handling for type parameters is probably required here. @@ -150,14 +158,14 @@ private class CallableReferencesUnbinder(val context: KonanBackendContext, call.addArguments(boundParams.mapIndexed { index, param -> param to IrCallImpl(startOffset, endOffset, arrayGet).apply { dispatchReceiver = boundArgsArray - putValueArgument(0, IrConstImpl.int(startOffset, endOffset, context.builtIns.intType, index)) + putValueArgument(0, IrConstImpl.int(startOffset, endOffset, builtIns.intType, index)) } }) val ret = IrReturnImpl(startOffset, endOffset, newDescriptor, call) val newFunction = IrFunctionImpl( - startOffset, endOffset, origin, + startOffset, endOffset, DECLARATION_ORIGIN_FUNCTION_FOR_CALLABLE_REFERENCE, newDescriptor, IrBlockBodyImpl(startOffset, endOffset, listOf(ret)) ) @@ -171,7 +179,7 @@ private class CallableReferencesUnbinder(val context: KonanBackendContext, private fun createSimpleFunctionImplTargetDescriptor(descriptor: CallableDescriptor, unboundParams: List): FunctionDescriptor { - val newName = Name.identifier(descriptor.hashCode().toString()) // FIXME + val newName = Name.identifier("${descriptor.name}\$bound-${lower.callableReferenceCount++}") val newDescriptor = SimpleFunctionDescriptorImpl.create( function.descriptor.containingDeclaration, Annotations.EMPTY, @@ -179,19 +187,34 @@ private class CallableReferencesUnbinder(val context: KonanBackendContext, val simpleFunctionImplType = simpleFunctionImplClass.defaultType - // Maps each unbound param of original function to parameter of new function + // Map each unbound param of original function to parameter of new function. val newUnboundParams = unboundParams.mapIndexed { index, param -> - ValueParameterDescriptorImpl(newDescriptor, null, index + 1, - Annotations.EMPTY, param.name, param.type, - false, false, false, false, - (param as? ValueParameterDescriptor)?.varargElementType, - SourceElement.NO_SOURCE) + ValueParameterDescriptorImpl( + containingDeclaration = newDescriptor, + original = null, + index = index + 1, + annotations = Annotations.EMPTY, + name = param.name, + outType = param.type, + declaresDefaultValue = false, + isCrossinline = false, isNoinline = false, + isCoroutine = false, + varargElementType = (param as? ValueParameterDescriptor)?.varargElementType, + source = SourceElement.NO_SOURCE) } // `: SimpleFunctionImpl` - val functionParameter = ValueParameterDescriptorImpl(newDescriptor, null, 0, Annotations.EMPTY, - Name.special(""), - simpleFunctionImplType, false, false, false, false, null, SourceElement.NO_SOURCE) + val functionParameter = ValueParameterDescriptorImpl( + containingDeclaration = newDescriptor, + original = null, + index = 0, + annotations = Annotations.EMPTY, + name = Name.special(""), + outType = simpleFunctionImplType, + declaresDefaultValue = false, + isCrossinline = false, isNoinline = false, + isCoroutine = false, varargElementType = null, + source = SourceElement.NO_SOURCE) val newValueParameters = listOf(functionParameter) + newUnboundParams diff --git a/runtime/src/main/cpp/Natives.cpp b/runtime/src/main/cpp/Natives.cpp index efdb01bf27e..9604b0f111d 100644 --- a/runtime/src/main/cpp/Natives.cpp +++ b/runtime/src/main/cpp/Natives.cpp @@ -185,7 +185,7 @@ KConstRef Kotlin_getCurrentStackTrace() { } // TODO: consider handling it with compiler magic instead. -KRef Kotlin_internal_undefined() { +KRef Kotlin_konan_internal_undefined() { return nullptr; } diff --git a/runtime/src/main/cpp/Natives.h b/runtime/src/main/cpp/Natives.h index 170d5459e08..9a56e14d970 100644 --- a/runtime/src/main/cpp/Natives.h +++ b/runtime/src/main/cpp/Natives.h @@ -100,7 +100,7 @@ KString Kotlin_String_subSequence(KString thiz, KInt startIndex, KInt endIndex); KConstRef Kotlin_getCurrentStackTrace(); -KRef Kotlin_internal_undefined(); +KRef Kotlin_konan_internal_undefined(); #ifdef __cplusplus } diff --git a/runtime/src/main/kotlin/konan/internal/Undefined.kt b/runtime/src/main/kotlin/konan/internal/Undefined.kt index 20b1ed92456..660dbfa5e6c 100644 --- a/runtime/src/main/kotlin/konan/internal/Undefined.kt +++ b/runtime/src/main/kotlin/konan/internal/Undefined.kt @@ -4,5 +4,5 @@ package konan.internal * Returns undefined value of type `T`. * This method is unsafe and should be used with care. */ -@SymbolName("Kotlin_internal_undefined") +@SymbolName("Kotlin_konan_internal_undefined") internal external fun undefined(): T \ No newline at end of file