diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/DescriptorUtils.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/DescriptorUtils.kt index 37497d52437..ce9fb3faaa5 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/DescriptorUtils.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/DescriptorUtils.kt @@ -1,6 +1,10 @@ package org.jetbrains.kotlin.backend.konan +import org.jetbrains.kotlin.backend.konan.llvm.KonanBuiltIns import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.incremental.components.NoLookupLocation +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.OverridingUtil import org.jetbrains.kotlin.resolve.descriptorUtil.* @@ -66,6 +70,18 @@ internal val ClassDescriptor.isArray: Boolean internal val ClassDescriptor.isInterface: Boolean get() = (this.kind == ClassKind.INTERFACE) +private val konanInternal = FqName.fromSegments(listOf("konan", "internal")) + +/** + * @return built-in class `konan.internal.$name` + */ +internal fun KonanBuiltIns.getKonanInternalClass(name: String): ClassDescriptor { + val classifier = this.builtInsModule + .getPackage(konanInternal).memberScope + .getContributedClassifier(Name.identifier(name), NoLookupLocation.FROM_BACKEND) + + return classifier as ClassDescriptor +} internal val CallableDescriptor.allValueParameters: List get() { diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanBackendContext.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanBackendContext.kt index 122add605c2..85bd442c48e 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanBackendContext.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanBackendContext.kt @@ -1,12 +1,15 @@ package org.jetbrains.kotlin.backend.konan import org.jetbrains.kotlin.backend.common.BackendContext +import org.jetbrains.kotlin.backend.konan.descriptors.KonanSharedVariablesManager import org.jetbrains.kotlin.backend.konan.llvm.KonanPlatform open internal class KonanBackendContext : BackendContext { override val builtIns = KonanPlatform.builtIns override val sharedVariablesManager by lazy { - TODO() + // Creating lazily because builtIns module seems to be incomplete during `link` test; + // TODO: investigate this. + KonanSharedVariablesManager(builtIns) } } \ No newline at end of file diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/descriptors/KonanSharedVariablesManager.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/descriptors/KonanSharedVariablesManager.kt new file mode 100644 index 00000000000..d7a165a9712 --- /dev/null +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/descriptors/KonanSharedVariablesManager.kt @@ -0,0 +1,106 @@ +package org.jetbrains.kotlin.backend.konan.descriptors + + +import org.jetbrains.kotlin.backend.common.descriptors.SharedVariablesManager +import org.jetbrains.kotlin.backend.konan.getKonanInternalClass +import org.jetbrains.kotlin.backend.konan.llvm.KonanBuiltIns +import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor +import org.jetbrains.kotlin.descriptors.PropertyDescriptor +import org.jetbrains.kotlin.descriptors.VariableDescriptor +import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor +import org.jetbrains.kotlin.ir.IrStatement +import org.jetbrains.kotlin.ir.declarations.IrVariable +import org.jetbrains.kotlin.ir.declarations.impl.IrVariableImpl +import org.jetbrains.kotlin.ir.expressions.IrExpression +import org.jetbrains.kotlin.ir.expressions.IrGetValue +import org.jetbrains.kotlin.ir.expressions.IrSetVariable +import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl +import org.jetbrains.kotlin.ir.expressions.impl.IrCompositeImpl +import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl +import org.jetbrains.kotlin.types.* + +internal class KonanSharedVariablesManager(val builtIns: KonanBuiltIns) : SharedVariablesManager { + + private val refClass = builtIns.getKonanInternalClass("Ref") + + private val refClassConstructor = refClass.unsubstitutedPrimaryConstructor!! + + private fun refConstructor(elementType: KotlinType): ClassConstructorDescriptor { + val typeParameter = refClassConstructor.typeParameters[0] + + return refClassConstructor.substitute(TypeSubstitutor.create( + mapOf(typeParameter.typeConstructor to TypeProjectionImpl(Variance.INVARIANT, elementType)) + ))!! + } + + private fun refType(elementType: KotlinType): KotlinType { + return refClass.defaultType.replace(listOf(TypeProjectionImpl(elementType))) + } + + override fun createSharedVariableDescriptor(variableDescriptor: VariableDescriptor): VariableDescriptor { + return LocalVariableDescriptor( + variableDescriptor.containingDeclaration, variableDescriptor.annotations, variableDescriptor.name, + refType(variableDescriptor.type), + false, false, variableDescriptor.source + ) + } + + private fun getElementProperty(sharedVariableDescriptor: VariableDescriptor): PropertyDescriptor { + return sharedVariableDescriptor.type.memberScope.getContributedDescriptors() + .filterIsInstance() + .single { + it.name.asString() == "element" + } + } + + override fun defineSharedValue(sharedVariableDescriptor: VariableDescriptor, + originalDeclaration: IrVariable): IrStatement { + + val valueType = originalDeclaration.descriptor.type + + val refConstructorTypeArguments = mapOf(refClassConstructor.typeParameters[0] to valueType) + + val refConstructorCall = IrCallImpl( + originalDeclaration.startOffset, originalDeclaration.endOffset, + refConstructor(valueType), refConstructorTypeArguments + ) + val sharedVariableDeclaration = IrVariableImpl( + originalDeclaration.startOffset, originalDeclaration.endOffset, originalDeclaration.origin, + sharedVariableDescriptor, refConstructorCall + ) + + val initializer = originalDeclaration.initializer ?: + return sharedVariableDeclaration + + val elementProperty = getElementProperty(sharedVariableDescriptor) + + val sharedVariableInitialization = + IrCallImpl(initializer.startOffset, initializer.endOffset, elementProperty.setter!!) + + sharedVariableInitialization.dispatchReceiver = + IrGetValueImpl(initializer.startOffset, initializer.endOffset, sharedVariableDescriptor) + + sharedVariableInitialization.putValueArgument(0, initializer) + + return IrCompositeImpl( + originalDeclaration.startOffset, originalDeclaration.endOffset, builtIns.unitType, null, + listOf(sharedVariableDeclaration, sharedVariableInitialization) + ) + } + + override fun getSharedValue(sharedVariableDescriptor: VariableDescriptor, originalGet: IrGetValue): IrExpression { + val elementProperty = getElementProperty(sharedVariableDescriptor) + return IrCallImpl(originalGet.startOffset, originalGet.endOffset, elementProperty.getter!!).apply { + dispatchReceiver = IrGetValueImpl(originalGet.startOffset, originalGet.endOffset, sharedVariableDescriptor) + } + } + + override fun setSharedValue(sharedVariableDescriptor: VariableDescriptor, originalSet: IrSetVariable): IrExpression { + val elementProperty = getElementProperty(sharedVariableDescriptor) + return IrCallImpl(originalSet.startOffset, originalSet.endOffset, elementProperty.setter!!).apply { + dispatchReceiver = IrGetValueImpl(originalSet.startOffset, originalSet.endOffset, sharedVariableDescriptor) + putValueArgument(0, originalSet.value) + } + } + +} \ No newline at end of file diff --git a/runtime/src/main/cpp/Natives.cpp b/runtime/src/main/cpp/Natives.cpp index ea26805972f..efdb01bf27e 100644 --- a/runtime/src/main/cpp/Natives.cpp +++ b/runtime/src/main/cpp/Natives.cpp @@ -184,4 +184,9 @@ KConstRef Kotlin_getCurrentStackTrace() { return GetCurrentStackTrace(); } +// TODO: consider handling it with compiler magic instead. +KRef Kotlin_internal_undefined() { + return nullptr; +} + } // extern "C" diff --git a/runtime/src/main/cpp/Natives.h b/runtime/src/main/cpp/Natives.h index 9bf54b49988..170d5459e08 100644 --- a/runtime/src/main/cpp/Natives.h +++ b/runtime/src/main/cpp/Natives.h @@ -100,6 +100,8 @@ KString Kotlin_String_subSequence(KString thiz, KInt startIndex, KInt endIndex); KConstRef Kotlin_getCurrentStackTrace(); +KRef Kotlin_internal_undefined(); + #ifdef __cplusplus } #endif diff --git a/runtime/src/main/kotlin/konan/internal/Ref.kt b/runtime/src/main/kotlin/konan/internal/Ref.kt new file mode 100644 index 00000000000..a9e2b70bcae --- /dev/null +++ b/runtime/src/main/kotlin/konan/internal/Ref.kt @@ -0,0 +1,8 @@ +package konan.internal + +/** + * This class is used to allocate closure-captured variables in the heap. + */ +class Ref { + var element: T = undefined() +} \ No newline at end of file diff --git a/runtime/src/main/kotlin/konan/internal/Undefined.kt b/runtime/src/main/kotlin/konan/internal/Undefined.kt new file mode 100644 index 00000000000..20b1ed92456 --- /dev/null +++ b/runtime/src/main/kotlin/konan/internal/Undefined.kt @@ -0,0 +1,8 @@ +package konan.internal + +/** + * Returns undefined value of type `T`. + * This method is unsafe and should be used with care. + */ +@SymbolName("Kotlin_internal_undefined") +internal external fun undefined(): T \ No newline at end of file