[K/N] Supported outer this references from cached inline bodies

This commit is contained in:
Igor Chevdar
2021-09-16 10:37:59 +05:00
parent da02d25278
commit cb71240938
16 changed files with 268 additions and 89 deletions
@@ -40,6 +40,7 @@ import kotlin.LazyThreadSafetyMode.PUBLICATION
import kotlin.reflect.KProperty
import org.jetbrains.kotlin.backend.common.ir.copyTo
import org.jetbrains.kotlin.backend.common.ir.copyToWithoutSuperTypes
import org.jetbrains.kotlin.backend.konan.ir.getSuperClassNotAny
import org.jetbrains.kotlin.backend.konan.objcexport.ObjCExport
import org.jetbrains.kotlin.backend.konan.llvm.coverage.CoverageManager
import org.jetbrains.kotlin.backend.konan.serialization.KonanIrLinker
@@ -77,9 +78,9 @@ internal class SpecialDeclarationsFactory(val context: Context) {
object DECLARATION_ORIGIN_FIELD_FOR_OUTER_THIS :
IrDeclarationOriginImpl("FIELD_FOR_OUTER_THIS")
fun getOuterThisField(innerClass: IrClass): IrField =
if (!innerClass.isInner) throw AssertionError("Class is not inner: ${innerClass.descriptor}")
else outerThisFields.getOrPut(innerClass) {
fun getOuterThisField(innerClass: IrClass): IrField {
assert(innerClass.isInner) { "Class is not inner: ${innerClass.render()}" }
return outerThisFields.getOrPut(innerClass) {
val outerClass = innerClass.parent as? IrClass
?: throw AssertionError("No containing class for inner class ${innerClass.descriptor}")
@@ -112,6 +113,7 @@ internal class SpecialDeclarationsFactory(val context: Context) {
parent = innerClass
}
}
}
fun getLoweredEnumOrNull(enumClass: IrClass): LoweredEnumAccess? {
assert(enumClass.kind == ClassKind.ENUM_CLASS) { "Expected enum class but was: ${enumClass.descriptor}" }
@@ -291,12 +293,12 @@ internal class Context(config: KonanConfig) : KonanBackendContext(config) {
fun getLayoutBuilder(irClass: IrClass): ClassLayoutBuilder {
if (irClass is IrLazyClass)
return layoutBuilders.getOrPut(irClass) {
ClassLayoutBuilder(irClass, this, isLowered = shouldLower(this, irClass))
ClassLayoutBuilder(irClass, this)
}
val metadata = irClass.metadata as? CodegenClassMetadata
?: CodegenClassMetadata(irClass).also { irClass.metadata = it }
metadata.layoutBuilder?.let { return it }
val layoutBuilder = ClassLayoutBuilder(irClass, this, isLowered = shouldLower(this, irClass))
val layoutBuilder = ClassLayoutBuilder(irClass, this)
metadata.layoutBuilder = layoutBuilder
return layoutBuilder
}
@@ -77,6 +77,9 @@ internal class InternalAbi(private val context: Context) {
fun getEnumValuesAccessorName(enum: IrClass): Name =
getMangledNameFor("getValues", enum)
fun getInnerClassOuterThisAccessorName(innerClass: IrClass): Name =
getMangledNameFor("outerThis", innerClass)
/**
* Generate name for declaration that will be a part of internal ABI.
*/
@@ -15,15 +15,16 @@ import org.jetbrains.kotlin.backend.konan.objcexport.ObjCExport
import org.jetbrains.kotlin.backend.konan.serialization.*
import org.jetbrains.kotlin.config.CommonConfigurationKeys
import org.jetbrains.kotlin.config.languageVersionSettings
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.builders.declarations.buildFun
import org.jetbrains.kotlin.ir.builders.irBlockBody
import org.jetbrains.kotlin.ir.builders.irGetObjectValue
import org.jetbrains.kotlin.ir.builders.irReturn
import org.jetbrains.kotlin.ir.builders.declarations.addValueParameter
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImpl
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrGetObjectValue
import org.jetbrains.kotlin.ir.expressions.IrGetField
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
@@ -32,6 +33,7 @@ import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
internal fun moduleValidationCallback(state: ActionState, module: IrModuleFragment, context: Context) {
if (!context.config.needVerifyIr) return
@@ -140,7 +142,8 @@ internal val buildAdditionalCacheInfoPhase = konanUnitPhase(
override fun visitClass(declaration: IrClass) {
declaration.acceptChildrenVoid(this)
if (declaration.isExported && declaration.origin != DECLARATION_ORIGIN_FUNCTION_CLASS)
if (!declaration.isInterface && declaration.visibility != DescriptorVisibilities.LOCAL
&& declaration.isExported && declaration.origin != DECLARATION_ORIGIN_FUNCTION_CLASS)
classFields.add(moduleDeserializer.buildClassFields(declaration, getLayoutBuilder(declaration).getDeclaredFields()))
}
@@ -165,11 +168,6 @@ internal val buildAdditionalCacheInfoPhase = konanUnitPhase(
prerequisite = setOf(psiToIrPhase)
)
// Coupled with [psiToIrPhase] logic above.
internal fun shouldLower(context: Context, declaration: IrDeclaration): Boolean {
return context.llvmModuleSpecification.containsDeclaration(declaration)
}
internal val destroySymbolTablePhase = konanUnitPhase(
op = {
this.symbolTable = null // TODO: invalidate symbolTable itself.
@@ -393,6 +391,28 @@ internal val exportInternalAbiPhase = makeKonanModuleOpPhase(
context.internalAbi.declare(function, declaration.module)
}
if (declaration.isInner) {
val function = context.irFactory.buildFun {
name = InternalAbi.getInnerClassOuterThisAccessorName(declaration)
origin = InternalAbi.INTERNAL_ABI_ORIGIN
returnType = declaration.parentAsClass.defaultType
}
function.addValueParameter {
name = Name.identifier("innerClass")
origin = InternalAbi.INTERNAL_ABI_ORIGIN
type = declaration.defaultType
}
context.createIrBuilder(function.symbol).apply {
function.body = irBlockBody {
+irReturn(irGetField(
irGet(function.valueParameters[0]),
context.specialDeclarationsFactory.getOuterThisField(declaration))
)
}
}
context.internalAbi.declare(function, declaration.module)
}
}
}
module.acceptChildrenVoid(visitor)
@@ -404,7 +424,8 @@ internal val useInternalAbiPhase = makeKonanModuleOpPhase(
description = "Use internal ABI functions to access private entities",
prerequisite = emptySet(),
op = { context, module ->
val accessors = mutableMapOf<IrClass, IrSimpleFunction>()
val companionObjectAccessors = mutableMapOf<IrClass, IrSimpleFunction>()
val outerThisAccessors = mutableMapOf<IrClass, IrSimpleFunction>()
val transformer = object : IrElementTransformerVoid() {
override fun visitGetObjectValue(expression: IrGetObjectValue): IrExpression {
val irClass = expression.symbol.owner
@@ -416,7 +437,7 @@ internal val useInternalAbiPhase = makeKonanModuleOpPhase(
// Access to Obj-C metaclass is done via intrinsic.
return expression
}
val accessor = accessors.getOrPut(irClass) {
val accessor = companionObjectAccessors.getOrPut(irClass) {
context.irFactory.buildFun {
name = InternalAbi.getCompanionObjectAccessorName(irClass)
returnType = irClass.defaultType
@@ -428,6 +449,39 @@ internal val useInternalAbiPhase = makeKonanModuleOpPhase(
}
return IrCallImpl(expression.startOffset, expression.endOffset, expression.type, accessor.symbol, accessor.typeParameters.size, accessor.valueParameters.size)
}
override fun visitGetField(expression: IrGetField): IrExpression {
val field = expression.symbol.owner
val irClass = field.parentClassOrNull ?: return expression
if (!irClass.isInner || context.llvmModuleSpecification.containsDeclaration(irClass)
|| context.specialDeclarationsFactory.getOuterThisField(irClass) != field
) {
return expression
}
val accessor = outerThisAccessors.getOrPut(irClass) {
context.irFactory.buildFun {
name = InternalAbi.getInnerClassOuterThisAccessorName(irClass)
returnType = irClass.parentAsClass.defaultType
origin = InternalAbi.INTERNAL_ABI_ORIGIN
isExternal = true
}.also { function ->
context.internalAbi.reference(function, irClass.module)
function.addValueParameter {
name = Name.identifier("innerClass")
origin = InternalAbi.INTERNAL_ABI_ORIGIN
type = irClass.defaultType
}
}
}
return IrCallImpl(
expression.startOffset, expression.endOffset,
expression.type, accessor.symbol,
accessor.typeParameters.size, accessor.valueParameters.size
).apply {
putValueArgument(0, expression.receiver)
}
}
}
module.transformChildrenVoid(transformer)
}
@@ -260,7 +260,12 @@ internal class GlobalHierarchyAnalysis(val context: Context, val irModule: IrMod
}
}
internal class ClassLayoutBuilder(val irClass: IrClass, val context: Context, val isLowered: Boolean) {
internal fun IrField.toFieldInfo() =
ClassLayoutBuilder.FieldInfo(name.asString(), type,
correspondingPropertySymbol?.owner?.isConst ?: false,
initializer?.expression is IrConst<*>, this)
internal class ClassLayoutBuilder(val irClass: IrClass, val context: Context) {
val vtableEntries: List<OverriddenFunctionInfo> by lazy {
require(!irClass.isInterface)
@@ -458,15 +463,13 @@ internal class ClassLayoutBuilder(val irClass: IrClass, val context: Context, va
lateinit var hierarchyInfo: ClassGlobalHierarchyInfo
private fun IrField.toFieldInfo() =
FieldInfo(name.asString(), type,
correspondingPropertySymbol?.owner?.isConst ?: false,
initializer?.expression is IrConst<*>, this)
/**
* Fields declared in the class.
*/
fun getDeclaredFields(): List<FieldInfo> {
val outerThisField = if (irClass.isInner)
context.specialDeclarationsFactory.getOuterThisField(irClass)
else null
if (context.config.lazyIrForCaches && !context.llvmModuleSpecification.containsDeclaration(irClass)) {
val packageFragment = irClass.findPackage()
val moduleDescriptor = packageFragment.packageFragmentDescriptor.containingDeclaration
@@ -474,18 +477,13 @@ internal class ClassLayoutBuilder(val irClass: IrClass, val context: Context, va
return emptyList()
val moduleDeserializer = context.irLinker.cachedLibraryModuleDeserializers[moduleDescriptor]
?: error("No module deserializer for ${irClass.render()}")
val fields = moduleDeserializer.deserializeClassFields(irClass).toMutableList()
if (irClass.isInner)
fields.add(InnerClassLowering.addOuterThisField(mutableListOf(), irClass, context).toFieldInfo())
return fields
return moduleDeserializer.deserializeClassFields(irClass, outerThisField)
}
val declarations: List<IrDeclaration> = if (irClass.isInner && !isLowered) {
// Note: copying to avoid mutation of the original class.
irClass.declarations.toMutableList()
.also { InnerClassLowering.addOuterThisField(it, irClass, context) }
} else {
irClass.declarations
val declarations = irClass.declarations.toMutableList()
outerThisField?.let {
if (!declarations.contains(it))
declarations += it
}
return declarations.mapNotNull {
when (it) {
@@ -119,14 +119,6 @@ internal class InnerClassLowering(val context: Context) : ClassLoweringPass {
InnerClassTransformer(irClass).lowerInnerClass()
}
companion object {
fun addOuterThisField(declarations: MutableList<IrDeclaration>, irClass: IrClass, context: Context): IrField {
val outerThisField = context.specialDeclarationsFactory.getOuterThisField(irClass)
declarations += outerThisField
return outerThisField
}
}
private inner class InnerClassTransformer(val irClass: IrClass) {
lateinit var outerThisFieldSymbol: IrFieldSymbol
@@ -138,7 +130,8 @@ internal class InnerClassLowering(val context: Context) : ClassLoweringPass {
}
private fun createOuterThisField() {
val outerThisField = addOuterThisField(irClass.declarations, irClass, context)
val outerThisField = context.specialDeclarationsFactory.getOuterThisField(irClass)
irClass.declarations += outerThisField
outerThisFieldSymbol = outerThisField.symbol
}
@@ -29,6 +29,7 @@ import org.jetbrains.kotlin.backend.konan.*
import org.jetbrains.kotlin.backend.konan.descriptors.ClassLayoutBuilder
import org.jetbrains.kotlin.backend.konan.descriptors.findPackage
import org.jetbrains.kotlin.backend.konan.descriptors.isInteropLibrary
import org.jetbrains.kotlin.backend.konan.descriptors.toFieldInfo
import org.jetbrains.kotlin.backend.konan.ir.interop.IrProviderForCEnumAndCStructStubs
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.konan.DeserializedKlibModuleOrigin
@@ -92,14 +93,14 @@ internal class ByteArrayStream(val buf: ByteArray) {
class SerializedInlineFunctionReference(val file: Int, val functionSignature: Int, val body: Int,
val startOffset: Int, val endOffset: Int,
val extensionReceiverSig: Int, val dispatchReceiverSig: Int,
val extensionReceiverSig: Int, val dispatchReceiverSig: Int, val outerReceiverSigs: IntArray,
val valueParameterSigs: IntArray, val typeParameterSigs: IntArray,
val defaultValues: IntArray)
internal object InlineFunctionBodyReferenceSerializer {
fun serialize(bodies: List<SerializedInlineFunctionReference>): ByteArray {
val size = bodies.sumOf {
Int.SIZE_BYTES * (10 + it.valueParameterSigs.size + it.typeParameterSigs.size + it.defaultValues.size)
Int.SIZE_BYTES * (11 + it.outerReceiverSigs.size + it.valueParameterSigs.size + it.typeParameterSigs.size + it.defaultValues.size)
}
val stream = ByteArrayStream(ByteArray(size))
bodies.forEach {
@@ -110,6 +111,8 @@ internal object InlineFunctionBodyReferenceSerializer {
stream.writeInt(it.endOffset)
stream.writeInt(it.extensionReceiverSig)
stream.writeInt(it.dispatchReceiverSig)
stream.writeInt(it.outerReceiverSigs.size)
it.outerReceiverSigs.forEach { sig -> stream.writeInt(sig) }
stream.writeInt(it.valueParameterSigs.size)
it.valueParameterSigs.forEach { sig -> stream.writeInt(sig) }
stream.writeInt(it.typeParameterSigs.size)
@@ -131,6 +134,8 @@ internal object InlineFunctionBodyReferenceSerializer {
val endOffset = stream.readInt()
val extensionReceiverSig = stream.readInt()
val dispatchReceiverSig = stream.readInt()
val outerReceiverSigsCount = stream.readInt()
val outerReceiverSigs = IntArray(outerReceiverSigsCount) { stream.readInt() }
val valueParameterSigsCount = stream.readInt()
val valueParameterSigs = IntArray(valueParameterSigsCount) { stream.readInt() }
val typeParameterSigsCount = stream.readInt()
@@ -138,7 +143,7 @@ internal object InlineFunctionBodyReferenceSerializer {
val defaultValuesCount = stream.readInt()
val defaultValues = IntArray(defaultValuesCount) { stream.readInt() }
result.add(SerializedInlineFunctionReference(file, functionSignature, body, startOffset, endOffset,
extensionReceiverSig, dispatchReceiverSig, valueParameterSigs, typeParameterSigs, defaultValues))
extensionReceiverSig, dispatchReceiverSig, outerReceiverSigs, valueParameterSigs, typeParameterSigs, defaultValues))
}
return result
}
@@ -153,18 +158,19 @@ class SerializedClassFieldInfo(val name: Int, val binaryType: Int, val type: Int
}
}
class SerializedClassFields(val file: Int, val classSignature: Int,
val typeParameterSigs: IntArray, val fields: Array<SerializedClassFieldInfo>)
class SerializedClassFields(val file: Int, val classSignature: Int, val typeParameterSigs: IntArray,
val outerThisIndex: Int, val fields: Array<SerializedClassFieldInfo>)
internal object ClassFieldsSerializer {
fun serialize(classFields: List<SerializedClassFields>): ByteArray {
val size = classFields.sumOf { Int.SIZE_BYTES * (4 + it.typeParameterSigs.size + it.fields.size * 4) }
val size = classFields.sumOf { Int.SIZE_BYTES * (5 + it.typeParameterSigs.size + it.fields.size * 4) }
val stream = ByteArrayStream(ByteArray(size))
classFields.forEach {
stream.writeInt(it.file)
stream.writeInt(it.classSignature)
stream.writeInt(it.typeParameterSigs.size)
it.typeParameterSigs.forEach { stream.writeInt(it) }
stream.writeInt(it.outerThisIndex)
stream.writeInt(it.fields.size)
it.fields.forEach { field ->
stream.writeInt(field.name)
@@ -184,6 +190,7 @@ internal object ClassFieldsSerializer {
val classSignature = stream.readInt()
val typeParameterSigsCount = stream.readInt()
val typeParameterSigs = IntArray(typeParameterSigsCount) { stream.readInt() }
val outerThisIndex = stream.readInt()
val fieldsCount = stream.readInt()
val fields = Array(fieldsCount) {
val name = stream.readInt()
@@ -192,7 +199,7 @@ internal object ClassFieldsSerializer {
val flags = stream.readInt()
SerializedClassFieldInfo(name, binaryType, type, flags)
}
result.add(SerializedClassFields(file, classSignature, typeParameterSigs, fields))
result.add(SerializedClassFields(file, classSignature, typeParameterSigs, outerThisIndex, fields))
}
return result
}
@@ -412,6 +419,7 @@ internal class KonanIrLinker(
}
val typeParameterSigs = mutableListOf<Int>()
val outerReceiverSigs = mutableListOf<Int>()
val protoFunction = if (outerClasses.isEmpty()) {
val irProperty = (irFunction as? IrSimpleFunction)?.correspondingPropertySymbol?.owner
if (irProperty == null)
@@ -426,8 +434,11 @@ internal class KonanIrLinker(
BinarySymbolData.decode(protoClass.getTypeParameter(it).base.symbol).signatureId
}
}
if (classIndex < outerClasses.size - 1)
if (classIndex < outerClasses.size - 1) {
if (classIndex >= firstNotInnerClassIndex)
outerReceiverSigs.add(BinarySymbolData.decode(protoClass.thisReceiver.base.symbol).signatureId)
protoClass = protoClass.findClass(outerClasses[classIndex + 1], fileReader, symbolDeserializer)
}
}
protoClass.findInlineFunction(irFunction, fileReader, symbolDeserializer)
}
@@ -450,7 +461,7 @@ internal class KonanIrLinker(
} ?: InvalidIndex
return SerializedInlineFunctionReference(fileDeserializationState.fileIndex, functionSignature, protoFunction.base.body,
irFunction.startOffset, irFunction.endOffset, extensionReceiverSig, dispatchReceiverSig,
irFunction.startOffset, irFunction.endOffset, extensionReceiverSig, dispatchReceiverSig, outerReceiverSigs.toIntArray(),
valueParameterSigs.toIntArray(), typeParameterSigs.toIntArray(), defaultValues.toIntArray())
}
@@ -472,6 +483,7 @@ internal class KonanIrLinker(
val typeParameterSigs = mutableListOf<Int>()
var protoClass = protoDeclaration.irClass
val protoClasses = mutableListOf(protoClass)
val firstNotInnerClassIndex = outerClasses.indexOfLast { !it.isInner }
for (classIndex in outerClasses.indices) {
if (classIndex >= firstNotInnerClassIndex /* owner's type parameters are always accessible */) {
@@ -479,8 +491,10 @@ internal class KonanIrLinker(
BinarySymbolData.decode(protoClass.getTypeParameter(it).base.symbol).signatureId
}
}
if (classIndex < outerClasses.size - 1)
if (classIndex < outerClasses.size - 1) {
protoClass = protoClass.findClass(outerClasses[classIndex + 1], fileReader, symbolDeserializer)
protoClasses += protoClass
}
}
val protoFields = mutableListOf<ProtoField>()
@@ -504,31 +518,43 @@ internal class KonanIrLinker(
protoFieldsMap[name] = it
}
val outerThisIndex = fields.indexOfFirst { it.irField?.origin == SpecialDeclarationsFactory.DECLARATION_ORIGIN_FIELD_FOR_OUTER_THIS }
val compatibleMode = CompatibilityMode(libraryAbiVersion).oldSignatures
return SerializedClassFields(
fileDeserializationState.fileIndex,
BinarySymbolData.decode(protoClass.base.symbol).signatureId,
typeParameterSigs.toIntArray(),
outerThisIndex,
Array(fields.size) {
val field = fields[it]
val irField = field.irField ?: error("No IR for field ${field.name} of ${irClass.render()}")
val protoField = protoFieldsMap[field.name] ?: error("No proto for ${irField.render()}")
val nameAndType = BinaryNameAndType.decode(protoField.nameType)
var flags = 0
if (field.isConst)
flags = flags or SerializedClassFieldInfo.FLAG_IS_CONST
if (field.hasConstInitializer)
flags = flags or SerializedClassFieldInfo.FLAG_CONST_INITIALIZER
val classifier = irField.type.classifierOrNull ?: error("Fields of type ${irField.type.render()} are not supported")
val primitiveBinaryType = irField.type.computePrimitiveBinaryTypeOrNull()
if (it == outerThisIndex) {
require(irClass.isInner) { "Expected an inner class: ${irClass.render()}" }
require(protoClasses.size > 1) { "An inner class must have at least one outer class" }
val outerProtoClass = protoClasses[protoClasses.size - 2]
val nameAndType = BinaryNameAndType.decode(outerProtoClass.thisReceiver.nameType)
SerializedClassFieldInfo(
nameAndType.nameIndex,
primitiveBinaryType?.ordinal ?: InvalidIndex,
if (with(KonanManglerIr) { (classifier as? IrClassSymbol)?.owner?.isExported(compatibleMode) } == false)
InvalidIndex
else nameAndType.typeIndex,
flags)
SerializedClassFieldInfo(name = InvalidIndex, binaryType = InvalidIndex, nameAndType.typeIndex, flags = 0)
} else {
val protoField = protoFieldsMap[field.name] ?: error("No proto for ${irField.render()}")
val nameAndType = BinaryNameAndType.decode(protoField.nameType)
var flags = 0
if (field.isConst)
flags = flags or SerializedClassFieldInfo.FLAG_IS_CONST
if (field.hasConstInitializer)
flags = flags or SerializedClassFieldInfo.FLAG_CONST_INITIALIZER
val classifier = irField.type.classifierOrNull
?: error("Fields of type ${irField.type.render()} are not supported")
val primitiveBinaryType = irField.type.computePrimitiveBinaryTypeOrNull()
SerializedClassFieldInfo(
nameAndType.nameIndex,
primitiveBinaryType?.ordinal ?: InvalidIndex,
if (with(KonanManglerIr) { (classifier as? IrClassSymbol)?.owner?.isExported(compatibleMode) } == false)
InvalidIndex
else nameAndType.typeIndex,
flags)
}
})
}
}
@@ -732,6 +758,10 @@ internal class KonanIrLinker(
require(sigIndex != InvalidIndex) { "Expected a valid sig reference to the dispatch receiver for ${function.render()}" }
symbolDeserializer.referenceLocalIrSymbol(parameter.symbol, symbolDeserializer.deserializeIdSignature(sigIndex))
}
for (index in 0 until outerClasses.size - 1) {
val sigIndex = inlineFunctionReference.outerReceiverSigs[index]
symbolDeserializer.referenceLocalIrSymbol(outerClasses[index].thisReceiver!!.symbol, symbolDeserializer.deserializeIdSignature(sigIndex))
}
function.body = declarationDeserializer.deserializeStatementBody(inlineFunctionReference.body) as IrBody
@@ -759,7 +789,7 @@ internal class KonanIrLinker(
}
}
fun deserializeClassFields(irClass: IrClass): List<ClassLayoutBuilder.FieldInfo> {
fun deserializeClassFields(irClass: IrClass, outerThisField: IrField?): List<ClassLayoutBuilder.FieldInfo> {
val signature = irClass.symbol.signature
?: error("No signature for ${irClass.render()}")
val serializedClassFields = classesFields[signature]
@@ -786,29 +816,35 @@ internal class KonanIrLinker(
return symbolDeserializer.deserializePublicSymbol(classIdSig, BinarySymbolData.SymbolKind.CLASS_SYMBOL) as IrClassSymbol
}
return serializedClassFields.fields.map {
val name = fileDeserializationInfo.fileReader.string(it.name)
val type = when {
it.type != InvalidIndex -> declarationDeserializer.deserializeIrType(it.type)
it.binaryType == InvalidIndex -> builtIns.anyNType
else -> when (PrimitiveBinaryType.values().getOrNull(it.binaryType)) {
PrimitiveBinaryType.BOOLEAN -> builtIns.booleanType
PrimitiveBinaryType.BYTE -> builtIns.byteType
PrimitiveBinaryType.SHORT -> builtIns.shortType
PrimitiveBinaryType.INT -> builtIns.intType
PrimitiveBinaryType.LONG -> builtIns.longType
PrimitiveBinaryType.FLOAT -> builtIns.floatType
PrimitiveBinaryType.DOUBLE -> builtIns.doubleType
PrimitiveBinaryType.POINTER -> getByClassId(KonanPrimitiveType.NON_NULL_NATIVE_PTR.classId).defaultType
PrimitiveBinaryType.VECTOR128 -> getByClassId(KonanPrimitiveType.VECTOR128.classId).defaultType
else -> error("Bad binary type of field $name of ${irClass.render()}")
return serializedClassFields.fields.mapIndexed { index, field ->
if (index == serializedClassFields.outerThisIndex) {
require(irClass.isInner) { "Expected an inner class: ${irClass.render()}" }
require(outerThisField != null) { "For an inner class ${irClass.render()} there should be <outer this> field" }
outerThisField.toFieldInfo()
} else {
val name = fileDeserializationInfo.fileReader.string(field.name)
val type = when {
field.type != InvalidIndex -> declarationDeserializer.deserializeIrType(field.type)
field.binaryType == InvalidIndex -> builtIns.anyNType
else -> when (PrimitiveBinaryType.values().getOrNull(field.binaryType)) {
PrimitiveBinaryType.BOOLEAN -> builtIns.booleanType
PrimitiveBinaryType.BYTE -> builtIns.byteType
PrimitiveBinaryType.SHORT -> builtIns.shortType
PrimitiveBinaryType.INT -> builtIns.intType
PrimitiveBinaryType.LONG -> builtIns.longType
PrimitiveBinaryType.FLOAT -> builtIns.floatType
PrimitiveBinaryType.DOUBLE -> builtIns.doubleType
PrimitiveBinaryType.POINTER -> getByClassId(KonanPrimitiveType.NON_NULL_NATIVE_PTR.classId).defaultType
PrimitiveBinaryType.VECTOR128 -> getByClassId(KonanPrimitiveType.VECTOR128.classId).defaultType
else -> error("Bad binary type of field $name of ${irClass.render()}")
}
}
ClassLayoutBuilder.FieldInfo(
name, type,
isConst = (field.flags and SerializedClassFieldInfo.FLAG_IS_CONST) != 0,
hasConstInitializer = (field.flags and SerializedClassFieldInfo.FLAG_CONST_INITIALIZER) != 0,
irField = null)
}
ClassLayoutBuilder.FieldInfo(
name, type,
isConst = (it.flags and SerializedClassFieldInfo.FLAG_IS_CONST) != 0,
hasConstInitializer = (it.flags and SerializedClassFieldInfo.FLAG_CONST_INITIALIZER) != 0,
irField = null)
}
}
}
@@ -1416,6 +1416,24 @@ linkTest("innerClass_linkTest") {
lib = "codegen/innerClass/linkTest_lib.kt"
}
linkTest("innerClass_inheritance_linkTest") {
useGoldenData = true
source = "codegen/innerClass/inheritance_linkTest_main.kt"
lib = "codegen/innerClass/inheritance_linkTest_lib.kt"
}
linkTest("innerClass_inheritance2_linkTest") {
useGoldenData = true
source = "codegen/innerClass/inheritance2_linkTest_main.kt"
lib = "codegen/innerClass/inheritance2_linkTest_lib.kt"
}
linkTest("innerClass_inheritance3_linkTest") {
useGoldenData = true
source = "codegen/innerClass/inheritance3_linkTest_main.kt"
lib = "codegen/innerClass/inheritance3_linkTest_lib.kt"
}
task localClass_localHierarchy(type: KonanLocalTest) {
useGoldenData = true
source = "codegen/localClass/localHierarchy.kt"
@@ -0,0 +1,13 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
open class Outer(val x: Int) {
open inner class Inner1
inner class Middle(x: Int) : Outer(x) {
inner class Inner2 : Inner1() {
fun foo() = this@Outer.x + this@Middle.x
}
}
}
@@ -0,0 +1,9 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
fun main() {
val o = Outer(42).Middle(117).Inner2()
println(o.foo())
}
@@ -0,0 +1,14 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
open class Outer {
open inner class Inner1
inner class Middle {
inner class Inner2 : Inner1() {
fun getOuter() = this@Outer
fun getMiddle() = this@Middle
}
}
}
@@ -0,0 +1,10 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
fun main() {
val o = Outer().Middle().Inner2()
println(o.getOuter() != Outer())
println(o.getMiddle() != Outer().Middle())
}
@@ -0,0 +1,10 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
open class Foo(val z: Int) {
open inner class FooInner {
fun foo() = z
}
}
@@ -0,0 +1,14 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
class Bar : Foo(42) {
inner class BarInner(val x: Int) : FooInner()
}
fun main() {
val o = Bar().BarInner(117)
println(o.x)
println(o.foo())
}