[K/N] Supported outer this references from cached inline bodies
This commit is contained in:
+7
-5
@@ -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
|
||||
}
|
||||
|
||||
+3
@@ -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.
|
||||
*/
|
||||
|
||||
+65
-11
@@ -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)
|
||||
}
|
||||
|
||||
+14
-16
@@ -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) {
|
||||
|
||||
+2
-9
@@ -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
|
||||
}
|
||||
|
||||
|
||||
+84
-48
@@ -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 @@
|
||||
159
|
||||
@@ -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,2 @@
|
||||
true
|
||||
true
|
||||
@@ -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())
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
117
|
||||
42
|
||||
Reference in New Issue
Block a user