backend: implement KonanSharedVariablesManager

This commit is contained in:
Svyatoslav Scherbina
2016-12-08 12:26:24 +07:00
committed by SvyatoslavScherbina
parent 7d5890e354
commit 8dce1884fd
7 changed files with 149 additions and 1 deletions
@@ -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<ParameterDescriptor>
get() {
@@ -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)
}
}
@@ -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<PropertyDescriptor>()
.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)
}
}
}
+5
View File
@@ -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"
+2
View File
@@ -100,6 +100,8 @@ KString Kotlin_String_subSequence(KString thiz, KInt startIndex, KInt endIndex);
KConstRef Kotlin_getCurrentStackTrace();
KRef Kotlin_internal_undefined();
#ifdef __cplusplus
}
#endif
@@ -0,0 +1,8 @@
package konan.internal
/**
* This class is used to allocate closure-captured variables in the heap.
*/
class Ref<T> {
var element: T = undefined()
}
@@ -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 <T> undefined(): T