IR: mostly remove descriptors from codegen

This commit is contained in:
Georgy Bronnikov
2019-04-15 01:29:55 +03:00
parent 9923d956aa
commit bfe148efd5
36 changed files with 1224 additions and 375 deletions
@@ -7,7 +7,7 @@ package org.jetbrains.kotlin.codegen
import org.jetbrains.org.objectweb.asm.MethodVisitor import org.jetbrains.org.objectweb.asm.MethodVisitor
internal fun visitAnnotableParameterCount(mv: MethodVisitor, paramCount: Int) { fun visitAnnotableParameterCount(mv: MethodVisitor, paramCount: Int) {
mv.visitAnnotableParameterCount(paramCount, true) mv.visitAnnotableParameterCount(paramCount, true)
mv.visitAnnotableParameterCount(paramCount, false) mv.visitAnnotableParameterCount(paramCount, false)
} }
@@ -7,4 +7,4 @@ package org.jetbrains.kotlin.codegen
import org.jetbrains.org.objectweb.asm.MethodVisitor import org.jetbrains.org.objectweb.asm.MethodVisitor
internal fun visitAnnotableParameterCount(mv: MethodVisitor, paramCount: Int) {} fun visitAnnotableParameterCount(mv: MethodVisitor, paramCount: Int) {}
@@ -11,7 +11,6 @@ import org.jetbrains.kotlin.backend.common.ir.*
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.builders.* import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
@@ -160,7 +159,7 @@ open class DefaultArgumentStubGenerator(
newIrFunction: IrFunction, newIrFunction: IrFunction,
params: MutableList<IrVariable> params: MutableList<IrVariable>
): IrExpression { ): IrExpression {
val dispatchCall = irCall(irFunction).apply { val dispatchCall = irCall(irFunction.symbol).apply {
passTypeArgumentsFrom(newIrFunction) passTypeArgumentsFrom(newIrFunction)
dispatchReceiver = newIrFunction.dispatchReceiverParameter?.let { irGet(it) } dispatchReceiver = newIrFunction.dispatchReceiverParameter?.let { irGet(it) }
extensionReceiver = newIrFunction.extensionReceiverParameter?.let { irGet(it) } extensionReceiver = newIrFunction.extensionReceiverParameter?.let { irGet(it) }
@@ -11,9 +11,12 @@ import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrDeclaration import org.jetbrains.kotlin.ir.declarations.IrDeclaration
import org.jetbrains.kotlin.ir.declarations.IrPackageFragment import org.jetbrains.kotlin.ir.declarations.IrPackageFragment
import org.jetbrains.kotlin.ir.declarations.IrTypeParameter
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.utils.DFS import org.jetbrains.kotlin.utils.DFS
@@ -89,3 +92,30 @@ fun IrType.getPrimitiveArrayElementType() = (this as? IrSimpleType)?.let {
fun IrType.isNonPrimitiveArray() = fun IrType.isNonPrimitiveArray() =
(this.isArray() || this.isNullableArray()) && !this.isPrimitiveArray() (this.isArray() || this.isNullableArray()) && !this.isPrimitiveArray()
fun IrType.substitute(params: List<IrTypeParameter>, arguments: List<IrType>): IrType =
substitute(params.map { it.symbol }.zip(arguments).toMap())
fun IrType.substitute(substitutionMap: Map<IrTypeParameterSymbol, IrType>): IrType {
if (this !is IrSimpleType) return this
substitutionMap[classifier]?.let { return it }
val newArguments = arguments.map {
if (it is IrTypeProjection) {
makeTypeProjection(it.type.substitute(substitutionMap), it.variance)
} else {
it
}
}
val newAnnotations = annotations.map { it.deepCopyWithSymbols() }
return IrSimpleTypeImpl(
classifier,
hasQuestionMark,
newArguments,
newAnnotations
)
}
@@ -6,27 +6,23 @@
package org.jetbrains.kotlin.backend.jvm package org.jetbrains.kotlin.backend.jvm
import org.jetbrains.kotlin.backend.common.ir.Symbols import org.jetbrains.kotlin.backend.common.ir.Symbols
import org.jetbrains.kotlin.backend.common.ir.addChild
import org.jetbrains.kotlin.backend.common.ir.createImplicitParameterDeclarationWithWrappedDescriptor import org.jetbrains.kotlin.backend.common.ir.createImplicitParameterDeclarationWithWrappedDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.descriptors.impl.EmptyPackageFragmentDescriptor import org.jetbrains.kotlin.descriptors.impl.EmptyPackageFragmentDescriptor
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.ir.builders.declarations.* import org.jetbrains.kotlin.ir.builders.declarations.*
import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
import org.jetbrains.kotlin.ir.declarations.IrPackageFragment import org.jetbrains.kotlin.ir.declarations.IrPackageFragment
import org.jetbrains.kotlin.ir.declarations.impl.IrExternalPackageFragmentImpl import org.jetbrains.kotlin.ir.declarations.impl.IrExternalPackageFragmentImpl
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.IrPropertySymbol
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.impl.IrExternalPackageFragmentSymbolImpl import org.jetbrains.kotlin.ir.symbols.impl.IrExternalPackageFragmentSymbolImpl
import org.jetbrains.kotlin.ir.types.defaultType import org.jetbrains.kotlin.ir.types.defaultType
import org.jetbrains.kotlin.ir.types.typeWith import org.jetbrains.kotlin.ir.types.typeWith
import org.jetbrains.kotlin.ir.util.ReferenceSymbolTable import org.jetbrains.kotlin.ir.util.ReferenceSymbolTable
import org.jetbrains.kotlin.ir.util.defaultType
import org.jetbrains.kotlin.ir.util.functions import org.jetbrains.kotlin.ir.util.functions
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
@@ -53,10 +49,7 @@ class JvmSymbols(
private fun createPackage(fqName: FqName): IrPackageFragment = private fun createPackage(fqName: FqName): IrPackageFragment =
IrExternalPackageFragmentImpl(IrExternalPackageFragmentSymbolImpl(EmptyPackageFragmentDescriptor(context.state.module, fqName))) IrExternalPackageFragmentImpl(IrExternalPackageFragmentSymbolImpl(EmptyPackageFragmentDescriptor(context.state.module, fqName)))
private val kotlinPackage: IrPackageFragment = createPackage(FqName("kotlin"))
private val kotlinJvmPackage: IrPackageFragment = createPackage(FqName("kotlin.jvm"))
private val kotlinJvmInternalPackage: IrPackageFragment = createPackage(FqName("kotlin.jvm.internal")) private val kotlinJvmInternalPackage: IrPackageFragment = createPackage(FqName("kotlin.jvm.internal"))
private val kotlinJvmInternalUnsafePackage: IrPackageFragment = createPackage(FqName("kotlin.jvm.internal.unsafe"))
private val kotlinJvmFunctionsPackage: IrPackageFragment = createPackage(FqName("kotlin.jvm.functions")) private val kotlinJvmFunctionsPackage: IrPackageFragment = createPackage(FqName("kotlin.jvm.functions"))
private fun createClass(fqName: FqName, classKind: ClassKind = ClassKind.CLASS, block: (IrClass) -> Unit): IrClass = private fun createClass(fqName: FqName, classKind: ClassKind = ClassKind.CLASS, block: (IrClass) -> Unit): IrClass =
@@ -261,47 +254,4 @@ class JvmSymbols(
val getOrCreateKotlinClasses: IrSimpleFunctionSymbol = val getOrCreateKotlinClasses: IrSimpleFunctionSymbol =
reflection.functions.single { it.owner.name.asString() == "getOrCreateKotlinClasses" } reflection.functions.single { it.owner.name.asString() == "getOrCreateKotlinClasses" }
val javaClassProperty: IrPropertySymbol = kotlinJvmPackage.addProperty {
name = Name.identifier("javaClass")
}.apply {
addGetter().apply {
val typeParameter = addTypeParameter {
name = Name.identifier("T")
}.apply {
superTypes.add(irBuiltIns.anyType)
}
addExtensionReceiver(typeParameter.defaultType)
returnType = javaLangClass.typeWith(typeParameter.defaultType)
}
}.symbol
val kClassJavaProperty: IrPropertySymbol = kotlinJvmPackage.addProperty {
name = Name.identifier("java")
}.apply {
addGetter().apply {
val extensionReceiverType = irBuiltIns.kClassClass.typeWith()
addExtensionReceiver(extensionReceiverType)
returnType = javaLangClass.typeWith(extensionReceiverType)
}
}.symbol
val monitorEnter = kotlinJvmInternalUnsafePackage.addFunction("monitorEnter", irBuiltIns.unitType, isStatic = true).apply {
addValueParameter("monitor", irBuiltIns.anyType)
}.symbol
val monitorExit = kotlinJvmInternalUnsafePackage.addFunction("monitorExit", irBuiltIns.unitType, isStatic = true).apply {
addValueParameter("monitor", irBuiltIns.anyType)
}.symbol
val isArrayOf = kotlinJvmPackage.addFunction("isArrayOf", irBuiltIns.booleanType, isStatic = true).apply {
addExtensionReceiver(irBuiltIns.arrayClass.owner.defaultType)
addTypeParameter("T", irBuiltIns.anyNType)
}.symbol
// We cannot create Cloneable reference out of thin air, since we have to preserve the information that it is a Java interface and
// it has no DefaultImpls counterpart.
val cloneable = symbolTable.referenceClass(
builtInsPackage("kotlin").getContributedClassifier(Name.identifier("Cloneable"), NoLookupLocation.FROM_BACKEND) as ClassDescriptor
)
} }
@@ -107,7 +107,7 @@ class AnnotationCodegen(
if (declaration is IrValueParameter && isInvisibleFromTheOutside(declaration.parent as? IrDeclaration)) return if (declaration is IrValueParameter && isInvisibleFromTheOutside(declaration.parent as? IrDeclaration)) return
// No need to annotate annotation methods since they're always non-null // No need to annotate annotation methods since they're always non-null
if (declaration is IrSimpleFunction && declaration.correspondingProperty != null && if (declaration is IrSimpleFunction && declaration.correspondingPropertySymbol != null &&
declaration.parentAsClass.isAnnotationClass declaration.parentAsClass.isAnnotationClass
) { ) {
return return
@@ -276,7 +276,7 @@ class AnnotationCodegen(
} }
interface InnerClassConsumer { interface InnerClassConsumer {
fun addInnerClassInfoFromAnnotation(irClass: IrClass) fun addInnerClassInfoFromAnnotation(innerClass: IrClass)
} }
private fun isBareTypeParameterWithNullableUpperBound(type: IrType): Boolean { private fun isBareTypeParameterWithNullableUpperBound(type: IrType): Boolean {
@@ -20,28 +20,27 @@ import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
import org.jetbrains.kotlin.backend.jvm.lower.constantValue import org.jetbrains.kotlin.backend.jvm.lower.constantValue
import org.jetbrains.kotlin.codegen.* import org.jetbrains.kotlin.codegen.*
import org.jetbrains.kotlin.codegen.binding.CodegenBinding import org.jetbrains.kotlin.codegen.binding.CodegenBinding.ASM_TYPE
import org.jetbrains.kotlin.codegen.inline.DefaultSourceMapper import org.jetbrains.kotlin.codegen.inline.DefaultSourceMapper
import org.jetbrains.kotlin.codegen.inline.SourceMapper import org.jetbrains.kotlin.codegen.inline.SourceMapper
import org.jetbrains.kotlin.codegen.serialization.JvmSerializationBindings import org.jetbrains.kotlin.codegen.serialization.JvmSerializationBindings
import org.jetbrains.kotlin.codegen.serialization.JvmSerializerExtension import org.jetbrains.kotlin.codegen.serialization.JvmSerializerExtension
import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.IrConst import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.types.IrSimpleType
import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.load.java.JvmAbi import org.jetbrains.kotlin.load.java.JvmAbi
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader
import org.jetbrains.kotlin.name.SpecialNames import org.jetbrains.kotlin.name.SpecialNames
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.DescriptorUtils.isTopLevelDeclaration
import org.jetbrains.kotlin.resolve.jvm.AsmTypes import org.jetbrains.kotlin.resolve.jvm.AsmTypes
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
import org.jetbrains.kotlin.resolve.jvm.diagnostics.OtherOrigin import org.jetbrains.kotlin.resolve.jvm.diagnostics.OtherOrigin
import org.jetbrains.kotlin.resolve.source.getPsi
import org.jetbrains.kotlin.serialization.DescriptorSerializer import org.jetbrains.kotlin.serialization.DescriptorSerializer
import org.jetbrains.kotlin.types.ErrorUtils import org.jetbrains.kotlin.utils.addToStdlib.safeAs
import org.jetbrains.org.objectweb.asm.Opcodes import org.jetbrains.org.objectweb.asm.Opcodes
import org.jetbrains.org.objectweb.asm.Type import org.jetbrains.org.objectweb.asm.Type
import java.io.File import java.io.File
@@ -52,20 +51,19 @@ open class ClassCodegen protected constructor(
private val parentClassCodegen: ClassCodegen? = null private val parentClassCodegen: ClassCodegen? = null
) : InnerClassConsumer { ) : InnerClassConsumer {
private val innerClasses = mutableListOf<ClassDescriptor>() private val innerClasses = mutableListOf<IrClass>()
val state = context.state val state = context.state
val typeMapper = context.state.typeMapper val typeMapper = IrTypeMapper(context.state.typeMapper)
val descriptor = irClass.descriptor val descriptor = irClass.descriptor
private val isAnonymous = DescriptorUtils.isAnonymousObject(irClass.descriptor) private val isAnonymous = irClass.isAnonymousObject
val type: Type = if (isAnonymous) CodegenBinding.asmTypeForAnonymousClass( val type: Type = if (isAnonymous)
state.bindingContext, state.bindingContext.get(ASM_TYPE, descriptor)!!
descriptor.source.getPsi() as KtElement else typeMapper.mapType(irClass)
) else typeMapper.mapType(descriptor)
private val sourceManager = context.psiSourceManager private val sourceManager = context.psiSourceManager
@@ -78,7 +76,7 @@ open class ClassCodegen protected constructor(
open fun createClassBuilder() = state.factory.newVisitor( open fun createClassBuilder() = state.factory.newVisitor(
OtherOrigin(psiElement, descriptor), OtherOrigin(psiElement, descriptor),
type, type,
psiElement?.containingFile?.let { setOf(it) } ?: emptySet() listOf(File(fileEntry.name))
) )
private var sourceMapper: DefaultSourceMapper? = null private var sourceMapper: DefaultSourceMapper? = null
@@ -92,8 +90,8 @@ open class ClassCodegen protected constructor(
} }
fun generate() { fun generate() {
val superClassInfo = SuperClassInfo.getSuperClassInfo(descriptor, typeMapper) val superClassInfo = irClass.getSuperClassInfo(typeMapper)
val signature = ImplementationBodyCodegen.signature(descriptor, type, superClassInfo, typeMapper) val signature = getSignature(irClass, type, superClassInfo, typeMapper)
visitor.defineClass( visitor.defineClass(
psiElement, psiElement,
@@ -170,22 +168,16 @@ open class ClassCodegen protected constructor(
companion object { companion object {
fun generate(irClass: IrClass, context: JvmBackendContext) { fun generate(irClass: IrClass, context: JvmBackendContext) {
val descriptor = irClass.descriptor
val state = context.state val state = context.state
if (ErrorUtils.isError(descriptor)) {
badDescriptor(irClass, state.classBuilderMode)
return
}
if (irClass.name == SpecialNames.NO_NAME_PROVIDED) { if (irClass.name == SpecialNames.NO_NAME_PROVIDED) {
badDescriptor(irClass, state.classBuilderMode) badClass(irClass, state.classBuilderMode)
} }
ClassCodegen(irClass, context).generate() ClassCodegen(irClass, context).generate()
} }
private fun badDescriptor(irClass: IrClass, mode: ClassBuilderMode) { private fun badClass(irClass: IrClass, mode: ClassBuilderMode) {
if (mode.generateBodies) { if (mode.generateBodies) {
throw IllegalStateException("Generating bad class in ClassBuilderMode = $mode: ${irClass.dump()}") throw IllegalStateException("Generating bad class in ClassBuilderMode = $mode: ${irClass.dump()}")
} }
@@ -216,9 +208,9 @@ open class ClassCodegen protected constructor(
private fun generateField(field: IrField, companionObjectCodegen: ClassCodegen?) { private fun generateField(field: IrField, companionObjectCodegen: ClassCodegen?) {
if (field.origin == IrDeclarationOrigin.FAKE_OVERRIDE) return if (field.origin == IrDeclarationOrigin.FAKE_OVERRIDE) return
val fieldType = typeMapper.mapType(field.descriptor) val fieldType = typeMapper.mapType(field)
val fieldSignature = typeMapper.mapFieldSignature(field.descriptor.type, field.descriptor) val fieldSignature = typeMapper.mapFieldSignature(field.type, field)
val fieldName = field.descriptor.name.asString() val fieldName = field.name.asString()
// The ConstantValue attribute makes the initializer part of the ABI, which is why since 1.4 // The ConstantValue attribute makes the initializer part of the ABI, which is why since 1.4
// it is no longer set unless the property is explicitly `const`. // it is no longer set unless the property is explicitly `const`.
val implicitConst = !state.languageVersionSettings.supportsFeature(LanguageFeature.NoConstantValueAttributeForNonConstVals) && val implicitConst = !state.languageVersionSettings.supportsFeature(LanguageFeature.NoConstantValueAttributeForNonConstVals) &&
@@ -274,13 +266,13 @@ open class ClassCodegen protected constructor(
private fun writeInnerClasses() { private fun writeInnerClasses() {
// JVMS7 (4.7.6): a nested class or interface member will have InnerClasses information // JVMS7 (4.7.6): a nested class or interface member will have InnerClasses information
// for each enclosing class and for each immediate member // for each enclosing class and for each immediate member
val classDescriptor = classForInnerClassRecord() val classForInnerClassRecord = getClassForInnerClassRecord()
if (classDescriptor != null) { if (classForInnerClassRecord != null) {
parentClassCodegen?.innerClasses?.add(classDescriptor) parentClassCodegen?.innerClasses?.add(classForInnerClassRecord)
var codegen: ClassCodegen? = this var codegen: ClassCodegen? = this
while (codegen != null) { while (codegen != null) {
val outerClass = codegen.classForInnerClassRecord() val outerClass = codegen.getClassForInnerClassRecord()
if (outerClass != null) { if (outerClass != null) {
innerClasses.add(outerClass) innerClasses.add(outerClass)
} }
@@ -289,23 +281,23 @@ open class ClassCodegen protected constructor(
} }
for (innerClass in innerClasses) { for (innerClass in innerClasses) {
MemberCodegen.writeInnerClass(innerClass, typeMapper, visitor) writeInnerClass(innerClass, typeMapper, context, visitor)
} }
} }
private fun classForInnerClassRecord(): ClassDescriptor? { private fun getClassForInnerClassRecord(): IrClass? {
return if (parentClassCodegen != null) descriptor else null return if (parentClassCodegen != null) irClass else null
} }
// It's necessary for proper recovering of classId by plain string JVM descriptor when loading annotations // It's necessary for proper recovering of classId by plain string JVM descriptor when loading annotations
// See FileBasedKotlinClass.convertAnnotationVisitor // See FileBasedKotlinClass.convertAnnotationVisitor
override fun addInnerClassInfoFromAnnotation(irClass: IrClass) { override fun addInnerClassInfoFromAnnotation(innerClass: IrClass) {
var current: DeclarationDescriptor? = irClass.descriptor var current: IrDeclaration? = innerClass
while (current != null && !isTopLevelDeclaration(current)) { while (current != null) {
if (current is ClassDescriptor) { if (current is IrClass) {
innerClasses.add(current) innerClasses.add(current)
} }
current = current.containingDeclaration current = current.parent as? IrDeclaration
} }
} }
@@ -323,7 +315,7 @@ open class ClassCodegen protected constructor(
// in the source. // in the source.
val containingDeclaration = irClass.symbol.owner.parent val containingDeclaration = irClass.symbol.owner.parent
if (containingDeclaration is IrFunction) { if (containingDeclaration is IrFunction) {
val method = typeMapper.mapAsmMethod(containingDeclaration.descriptor) val method = typeMapper.mapAsmMethod(containingDeclaration)
visitor.visitOuterClass(outerClassName, method.name, method.descriptor) visitor.visitOuterClass(outerClassName, method.name, method.descriptor)
} else { } else {
visitor.visitOuterClass(outerClassName, null, null) visitor.visitOuterClass(outerClassName, null, null)
@@ -340,7 +332,7 @@ open class ClassCodegen protected constructor(
} }
private val IrClass.flags: Int private val IrClass.flags: Int
get() = origin.flags or AsmUtil.getVisibilityAccessFlagForClass(descriptor) or when { get() = origin.flags or getVisibilityAccessFlagForClass() or when {
isAnnotationClass -> Opcodes.ACC_ANNOTATION or Opcodes.ACC_INTERFACE or Opcodes.ACC_ABSTRACT isAnnotationClass -> Opcodes.ACC_ANNOTATION or Opcodes.ACC_INTERFACE or Opcodes.ACC_ABSTRACT
isInterface -> Opcodes.ACC_INTERFACE or Opcodes.ACC_ABSTRACT isInterface -> Opcodes.ACC_INTERFACE or Opcodes.ACC_ABSTRACT
isEnumClass -> Opcodes.ACC_ENUM or Opcodes.ACC_SUPER or modality.flags isEnumClass -> Opcodes.ACC_ENUM or Opcodes.ACC_SUPER or modality.flags
@@ -372,3 +364,18 @@ private val IrField.OtherOrigin: JvmDeclarationOrigin
internal val IrFunction.OtherOrigin: JvmDeclarationOrigin internal val IrFunction.OtherOrigin: JvmDeclarationOrigin
get() = OtherOrigin(descriptor.psiElement, this.descriptor) get() = OtherOrigin(descriptor.psiElement, this.descriptor)
private fun IrClass.getSuperClassInfo(typeMapper: IrTypeMapper): IrSuperClassInfo {
if (isInterface) {
return IrSuperClassInfo(AsmTypes.OBJECT_TYPE, null)
}
for (superType in superTypes) {
val superClass = superType.safeAs<IrSimpleType>()?.classifier?.safeAs<IrClassSymbol>()?.owner
if (superClass != null && !superClass.isJvmInterface) {
return IrSuperClassInfo(typeMapper.mapClass(superClass), superType)
}
}
return IrSuperClassInfo(AsmTypes.OBJECT_TYPE, null)
}
@@ -5,17 +5,14 @@
package org.jetbrains.kotlin.backend.jvm.codegen package org.jetbrains.kotlin.backend.jvm.codegen
import org.jetbrains.kotlin.backend.common.descriptors.propertyIfAccessor
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
import org.jetbrains.kotlin.backend.jvm.intrinsics.IntrinsicMethods import org.jetbrains.kotlin.backend.jvm.intrinsics.IrIntrinsicMethods
import org.jetbrains.kotlin.backend.jvm.intrinsics.JavaClassProperty import org.jetbrains.kotlin.backend.jvm.intrinsics.JavaClassProperty
import org.jetbrains.kotlin.backend.jvm.intrinsics.Not import org.jetbrains.kotlin.backend.jvm.intrinsics.Not
import org.jetbrains.kotlin.backend.jvm.lower.CrIrType import org.jetbrains.kotlin.backend.jvm.lower.CrIrType
import org.jetbrains.kotlin.backend.jvm.lower.constantValue import org.jetbrains.kotlin.backend.jvm.lower.constantValue
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.codegen.* import org.jetbrains.kotlin.codegen.*
import org.jetbrains.kotlin.codegen.AsmUtil.* import org.jetbrains.kotlin.codegen.AsmUtil.*
import org.jetbrains.kotlin.codegen.ExpressionCodegen.putReifiedOperationMarkerIfTypeIsReifiedParameter
import org.jetbrains.kotlin.codegen.inline.* import org.jetbrains.kotlin.codegen.inline.*
import org.jetbrains.kotlin.codegen.inline.ReifiedTypeInliner.OperationKind.AS import org.jetbrains.kotlin.codegen.inline.ReifiedTypeInliner.OperationKind.AS
import org.jetbrains.kotlin.codegen.inline.ReifiedTypeInliner.OperationKind.SAFE_AS import org.jetbrains.kotlin.codegen.inline.ReifiedTypeInliner.OperationKind.SAFE_AS
@@ -25,27 +22,22 @@ import org.jetbrains.kotlin.codegen.signature.BothSignatureWriter
import org.jetbrains.kotlin.codegen.state.GenerationState import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.config.isReleaseCoroutines import org.jetbrains.kotlin.config.isReleaseCoroutines
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor
import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.IrSymbol import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.util.dump
import org.jetbrains.kotlin.ir.util.parentAsClass
import org.jetbrains.kotlin.ir.util.render
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.DescriptorUtils.isEnumClass
import org.jetbrains.kotlin.resolve.calls.components.hasDefaultValue
import org.jetbrains.kotlin.resolve.inline.InlineUtil
import org.jetbrains.kotlin.resolve.jvm.AsmTypes import org.jetbrains.kotlin.resolve.jvm.AsmTypes
import org.jetbrains.kotlin.resolve.jvm.AsmTypes.OBJECT_TYPE import org.jetbrains.kotlin.resolve.jvm.AsmTypes.OBJECT_TYPE
import org.jetbrains.kotlin.synthetic.SyntheticJavaPropertyDescriptor
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.typeUtil.isNothing
import org.jetbrains.kotlin.types.typesApproximation.approximateCapturedTypes
import org.jetbrains.kotlin.types.upperIfFlexible
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
import org.jetbrains.kotlin.utils.keysToMap import org.jetbrains.kotlin.utils.keysToMap
import org.jetbrains.org.objectweb.asm.Label import org.jetbrains.org.objectweb.asm.Label
import org.jetbrains.org.objectweb.asm.Type import org.jetbrains.org.objectweb.asm.Type
@@ -125,18 +117,15 @@ class ExpressionCodegen(
override var lastLineNumber: Int = -1 override var lastLineNumber: Int = -1
private val KotlinType.asmType: Type
get() = typeMapper.mapType(this)
private val IrType.asmType: Type private val IrType.asmType: Type
get() = toKotlinType().asmType
private val CallableDescriptor.asmType: Type
get() = typeMapper.mapType(this) get() = typeMapper.mapType(this)
val IrExpression.asmType: Type val IrExpression.asmType: Type
get() = type.asmType get() = type.asmType
val IrVariable.asmType: Type
get() = type.asmType
// Assume this expression's result has already been materialized on the stack // Assume this expression's result has already been materialized on the stack
// with the correct type. // with the correct type.
val IrExpression.onStack: MaterialValue val IrExpression.onStack: MaterialValue
@@ -178,7 +167,7 @@ class ExpressionCodegen(
if (irFunction.origin != JvmLoweredDeclarationOrigin.CLASS_STATIC_INITIALIZER) { if (irFunction.origin != JvmLoweredDeclarationOrigin.CLASS_STATIC_INITIALIZER) {
irFunction.markLineNumber(startOffset = irFunction is IrConstructor && irFunction.isPrimary) irFunction.markLineNumber(startOffset = irFunction is IrConstructor && irFunction.isPrimary)
} }
val returnType = typeMapper.mapReturnType(irFunction.descriptor) val returnType = typeMapper.mapReturnType(irFunction)
result.coerce(returnType).materialize() result.coerce(returnType).materialize()
mv.areturn(returnType) mv.areturn(returnType)
} }
@@ -201,18 +190,15 @@ class ExpressionCodegen(
} }
private fun writeValueParameterInLocalVariableTable(param: IrValueParameter, startLabel: Label) { private fun writeValueParameterInLocalVariableTable(param: IrValueParameter, startLabel: Label) {
val descriptor = param.descriptor // TODO: old code has a special treatment for destructuring lambda parameters.
val nameForDestructuredParameter = if (descriptor is ValueParameterDescriptor) { // There is no (easy) way to reproduce it with IR structures.
getNameForDestructuredParameterOrNull(descriptor) // Does not show up in tests, but might come to bite us at some point.
} else { val name = param.name.asString()
null
}
val type = typeMapper.mapType(descriptor) val type = typeMapper.mapType(param)
// NOTE: we expect all value parameters to be present in the frame. // NOTE: we expect all value parameters to be present in the frame.
mv.visitLocalVariable( mv.visitLocalVariable(
nameForDestructuredParameter ?: param.name.asString(), name, type.descriptor, null, startLabel, markNewLabel(), findLocalIndex(param.symbol)
type.descriptor, null, startLabel, markNewLabel(), findLocalIndex(param.symbol)
) )
} }
@@ -268,10 +254,10 @@ class ExpressionCodegen(
override fun visitCall(expression: IrCall, data: BlockInfo): PromisedValue { override fun visitCall(expression: IrCall, data: BlockInfo): PromisedValue {
expression.markLineNumber(startOffset = true) expression.markLineNumber(startOffset = true)
if (expression.descriptor is ConstructorDescriptor) { if (expression.symbol.owner is IrConstructor) {
throw AssertionError("IrCall with ConstructorDescriptor: ${expression.javaClass.simpleName}") throw AssertionError("IrCall with ConstructorDescriptor: ${expression.javaClass.simpleName}")
} }
return generateCall(expression, expression.superQualifier, data) return generateCall(expression, expression.superQualifierSymbol, data)
} }
override fun visitConstructorCall(expression: IrConstructorCall, data: BlockInfo): PromisedValue { override fun visitConstructorCall(expression: IrConstructorCall, data: BlockInfo): PromisedValue {
@@ -287,35 +273,36 @@ class ExpressionCodegen(
return expression.onStack return expression.onStack
} }
fun generateNewArray(expression: IrConstructorCall, data: BlockInfo): PromisedValue { private fun generateNewArray(expression: IrConstructorCall, data: BlockInfo): PromisedValue {
val args = expression.descriptor.valueParameters val args = expression.symbol.owner.valueParameters
assert(args.size == 1 || args.size == 2) { "Unknown constructor called: " + args.size + " arguments" } assert(args.size == 1 || args.size == 2) { "Unknown constructor called: " + args.size + " arguments" }
if (args.size == 1) { if (args.size == 1) {
// TODO move to the intrinsic // TODO move to the intrinsic
expression.getValueArgument(0)!!.accept(this, data).coerce(Type.INT_TYPE).materialize() expression.getValueArgument(0)!!.accept(this, data).coerce(Type.INT_TYPE).materialize()
newArrayInstruction(expression.type.toKotlinType()) newArrayInstruction(expression.type)
return expression.onStack return expression.onStack
} }
return generateCall(expression, null, data) return generateCall(expression, null, data)
} }
private fun generateCall(expression: IrFunctionAccessExpression, superQualifier: ClassDescriptor?, data: BlockInfo): PromisedValue { private fun generateCall(expression: IrFunctionAccessExpression, superQualifierSymbol: IrClassSymbol?, data: BlockInfo): PromisedValue {
classCodegen.context.irIntrinsics.getIntrinsic(expression.symbol) classCodegen.context.irIntrinsics.getIntrinsic(expression.symbol)
?.invoke(expression, this, data)?.let { return it.coerce(expression.asmType) } ?.invoke(expression, this, data)?.let { return it.coerce(expression.asmType) }
val isSuperCall = superQualifier != null val isSuperCall = superQualifierSymbol != null
val callable = resolveToCallable(expression, isSuperCall) val callable = resolveToCallable(expression, isSuperCall)
return generateCall(expression, callable, data, isSuperCall) return generateCall(expression, callable, data, isSuperCall)
} }
fun generateCall( fun generateCall(
expression: IrMemberAccessExpression, expression: IrFunctionAccessExpression,
callable: Callable, callable: Callable,
data: BlockInfo, data: BlockInfo,
isSuperCall: Boolean = false isSuperCall: Boolean = false
): PromisedValue { ): PromisedValue {
val callGenerator = getOrCreateCallGenerator(expression, expression.descriptor, data) val callee = expression.symbol.owner
val callGenerator = getOrCreateCallGenerator(expression, data)
val receiver = expression.dispatchReceiver val receiver = expression.dispatchReceiver
receiver?.apply { receiver?.apply {
@@ -335,19 +322,24 @@ class ExpressionCodegen(
val defaultMask = DefaultCallArgs(callable.valueParameterTypes.size) val defaultMask = DefaultCallArgs(callable.valueParameterTypes.size)
val extraArgsShift = val extraArgsShift =
when { when {
expression.descriptor is ConstructorDescriptor && isEnumClass(expression.descriptor.containingDeclaration) -> 2 callee is IrConstructor && callee.parentAsClass.isEnumClass -> 2
expression.descriptor is ConstructorDescriptor && callee is IrConstructor && callee.parentAsClass.isInner -> 1 // skip the `$outer` parameter
(expression.descriptor.containingDeclaration as ClassDescriptor).isInner -> 1 // skip the `$outer` parameter
else -> 0 else -> 0
} }
expression.descriptor.valueParameters.forEachIndexed { i, parameterDescriptor -> val typeParameters = if (callee is IrConstructor)
callee.parentAsClass.typeParameters + callee.typeParameters
else
callee.typeParameters
val typeArguments = (0 until typeParameters.size).map { expression.getTypeArgument(it)!! }
val typeSubstitutionMap = typeParameters.map { it.symbol }.zip(typeArguments).toMap()
expression.symbol.owner.valueParameters.forEachIndexed { i, irParameter ->
val arg = expression.getValueArgument(i) val arg = expression.getValueArgument(i)
val parameterType = callable.valueParameterTypes[i] val parameterType = callable.valueParameterTypes[i]
when { when {
arg != null -> { arg != null -> {
callGenerator.genValueAndPut(parameterDescriptor, arg, parameterType, i, this@ExpressionCodegen, data) callGenerator.genValueAndPut(irParameter, arg, parameterType, i, this@ExpressionCodegen, data)
} }
parameterDescriptor.hasDefaultValue() -> { irParameter.hasDefaultValue() -> {
callGenerator.putValueIfNeeded( callGenerator.putValueIfNeeded(
parameterType, parameterType,
StackValue.createDefaultValue(parameterType), StackValue.createDefaultValue(parameterType),
@@ -358,12 +350,10 @@ class ExpressionCodegen(
defaultMask.mark(i - extraArgsShift/*TODO switch to separate lower*/) defaultMask.mark(i - extraArgsShift/*TODO switch to separate lower*/)
} }
else -> { else -> {
assert(parameterDescriptor.varargElementType != null) assert(irParameter.varargElementType != null)
//empty vararg val type = typeMapper.mapType(
irParameter.type.substitute(typeSubstitutionMap)
// Upper bound for type of vararg parameter should always have a form of 'Array<out T>', )
// while its lower bound may be Nothing-typed after approximation
val type = typeMapper.mapType(parameterDescriptor.type.upperIfFlexible())
callGenerator.putValueIfNeeded( callGenerator.putValueIfNeeded(
parameterType, parameterType,
StackValue.operation(type) { StackValue.operation(type) {
@@ -378,17 +368,17 @@ class ExpressionCodegen(
callGenerator.genCall( callGenerator.genCall(
callable, callable,
defaultMask.generateOnStackIfNeeded(callGenerator, expression.descriptor is ConstructorDescriptor, this), defaultMask.generateOnStackIfNeeded(callGenerator, callee is IrConstructor, this),
this, this,
expression expression
) )
val returnType = expression.descriptor.returnType val returnType = callee.returnType.substitute(typeSubstitutionMap)
if (returnType != null && returnType.isNothing()) { if (returnType.isNothing()) {
mv.aconst(null) mv.aconst(null)
mv.athrow() mv.athrow()
return voidValue return voidValue
} else if (expression.descriptor is ConstructorDescriptor) { } else if (callee is IrConstructor) {
return voidValue return voidValue
} else if (expression.type.isUnit()) { } else if (expression.type.isUnit()) {
// NewInference allows casting `() -> T` to `() -> Unit`. A CHECKCAST here will fail. // NewInference allows casting `() -> T` to `() -> Unit`. A CHECKCAST here will fail.
@@ -398,7 +388,7 @@ class ExpressionCodegen(
} }
override fun visitVariable(declaration: IrVariable, data: BlockInfo): PromisedValue { override fun visitVariable(declaration: IrVariable, data: BlockInfo): PromisedValue {
val varType = typeMapper.mapType(declaration.descriptor) val varType = typeMapper.mapType(declaration)
val index = frameMap.enter(declaration.symbol, varType) val index = frameMap.enter(declaration.symbol, varType)
declaration.markLineNumber(startOffset = true) declaration.markLineNumber(startOffset = true)
@@ -431,10 +421,10 @@ class ExpressionCodegen(
return voidValue.coerce(expression.asmType) return voidValue.coerce(expression.asmType)
} }
val realDescriptor = DescriptorUtils.unwrapFakeOverride(expression.descriptor) val realField = expression.symbol.owner.resolveFakeOverride()!!
val fieldType = typeMapper.mapType(realDescriptor.original.type) val fieldType = typeMapper.mapType(realField.type)
val ownerType = typeMapper.mapImplementationOwner(expression.descriptor).internalName val ownerType = typeMapper.mapImplementationOwner(expression.symbol.owner).internalName
val fieldName = expression.descriptor.name.asString() val fieldName = realField.name.asString()
val isStatic = expression.receiver == null val isStatic = expression.receiver == null
expression.markLineNumber(startOffset = true) expression.markLineNumber(startOffset = true)
expression.receiver?.accept(this, data)?.materialize() expression.receiver?.accept(this, data)?.materialize()
@@ -497,8 +487,8 @@ class ExpressionCodegen(
override fun visitSetVariable(expression: IrSetVariable, data: BlockInfo): PromisedValue { override fun visitSetVariable(expression: IrSetVariable, data: BlockInfo): PromisedValue {
expression.markLineNumber(startOffset = true) expression.markLineNumber(startOffset = true)
expression.value.markLineNumber(startOffset = true) expression.value.markLineNumber(startOffset = true)
expression.value.accept(this, data).coerce(expression.descriptor.asmType).materialize() expression.value.accept(this, data).coerce(expression.symbol.owner.asmType).materialize()
mv.store(findLocalIndex(expression.symbol), expression.descriptor.asmType) mv.store(findLocalIndex(expression.symbol), expression.symbol.owner.asmType)
return voidValue.coerce(expression.asmType) return voidValue.coerce(expression.asmType)
} }
@@ -547,7 +537,7 @@ class ExpressionCodegen(
val hasSpread = arguments.firstIsInstanceOrNull<IrSpreadElement>() != null val hasSpread = arguments.firstIsInstanceOrNull<IrSpreadElement>() != null
if (hasSpread) { if (hasSpread) {
val arrayOfReferences = KotlinBuiltIns.isArray(outType.toKotlinType()) val arrayOfReferences = outType.makeNotNull().isArray()
if (size == 1) { if (size == 1) {
// Arrays.copyOf(receiverValue, newLength) // Arrays.copyOf(receiverValue, newLength)
val argument = (arguments[0] as IrSpreadElement).expression val argument = (arguments[0] as IrSpreadElement).expression
@@ -595,7 +585,7 @@ class ExpressionCodegen(
if (arrayOfReferences) { if (arrayOfReferences) {
mv.dup() mv.dup()
mv.invokevirtual(owner, "size", "()I", false) mv.invokevirtual(owner, "size", "()I", false)
newArrayInstruction(outType.toKotlinType()) newArrayInstruction(outType)
mv.invokevirtual(owner, "toArray", toArrayDescriptor, false) mv.invokevirtual(owner, "toArray", toArrayDescriptor, false)
mv.checkcast(type) mv.checkcast(type)
} else { } else {
@@ -604,7 +594,7 @@ class ExpressionCodegen(
} }
} else { } else {
mv.iconst(size) mv.iconst(size)
newArrayInstruction(expression.type.toKotlinType()) newArrayInstruction(expression.type)
for ((i, element) in expression.elements.withIndex()) { for ((i, element) in expression.elements.withIndex()) {
mv.dup() mv.dup()
mv.iconst(i) mv.iconst(i)
@@ -615,16 +605,16 @@ class ExpressionCodegen(
return expression.onStack return expression.onStack
} }
fun newArrayInstruction(arrayType: KotlinType) { fun newArrayInstruction(arrayType: IrType) {
if (KotlinBuiltIns.isArray(arrayType)) { if (arrayType.isArray()) {
val elementKotlinType = arrayType.arguments[0].type val elementIrType = arrayType.safeAs<IrSimpleType>()!!.arguments[0].safeAs<IrTypeProjection>()!!.type
putReifiedOperationMarkerIfTypeIsReifiedParameter( putReifiedOperationMarkerIfTypeIsReifiedParameter(
elementKotlinType, elementIrType,
ReifiedTypeInliner.OperationKind.NEW_ARRAY, ReifiedTypeInliner.OperationKind.NEW_ARRAY,
mv, mv,
this this
) )
mv.newarray(boxType(elementKotlinType.asmType)) mv.newarray(boxType(elementIrType.asmType))
} else { } else {
val type = typeMapper.mapType(arrayType) val type = typeMapper.mapType(arrayType)
mv.newarray(correctElementType(type)) mv.newarray(correctElementType(type))
@@ -634,10 +624,8 @@ class ExpressionCodegen(
override fun visitReturn(expression: IrReturn, data: BlockInfo): PromisedValue { override fun visitReturn(expression: IrReturn, data: BlockInfo): PromisedValue {
val owner = expression.returnTargetSymbol.owner val owner = expression.returnTargetSymbol.owner
//TODO: should be owner != irFunction //TODO: should be owner != irFunction
val isNonLocalReturn = state.typeMapper.mapFunctionName( val isNonLocalReturn =
owner.descriptor, typeMapper.mapFunctionName(owner, OwnerKind.IMPLEMENTATION) != typeMapper.mapFunctionName(irFunction, OwnerKind.IMPLEMENTATION)
OwnerKind.IMPLEMENTATION
) != state.typeMapper.mapFunctionName(irFunction.descriptor, OwnerKind.IMPLEMENTATION)
if (isNonLocalReturn && state.isInlineDisabled) { if (isNonLocalReturn && state.isInlineDisabled) {
//TODO: state.diagnostics.report(Errors.NON_LOCAL_RETURN_IN_DISABLED_INLINE.on(expression)) //TODO: state.diagnostics.report(Errors.NON_LOCAL_RETURN_IN_DISABLED_INLINE.on(expression))
genThrow( genThrow(
@@ -647,7 +635,7 @@ class ExpressionCodegen(
return voidValue return voidValue
} }
val returnType = typeMapper.mapReturnType(owner.descriptor) val returnType = typeMapper.mapReturnType(owner)
val afterReturnLabel = Label() val afterReturnLabel = Label()
expression.value.accept(this, data).coerce(returnType).materialize() expression.value.accept(this, data).coerce(returnType).materialize()
generateFinallyBlocksIfNeeded(returnType, afterReturnLabel, data) generateFinallyBlocksIfNeeded(returnType, afterReturnLabel, data)
@@ -697,8 +685,9 @@ class ExpressionCodegen(
} }
override fun visitTypeOperator(expression: IrTypeOperatorCall, data: BlockInfo): PromisedValue { override fun visitTypeOperator(expression: IrTypeOperatorCall, data: BlockInfo): PromisedValue {
val kotlinType = expression.typeOperand.toKotlinType() val typeOperand = expression.typeOperand
val asmType = kotlinType.asmType val asmType = typeOperand.asmType
val kotlinType = typeOperand.toKotlinType()
return when (expression.operator) { return when (expression.operator) {
IrTypeOperator.IMPLICIT_COERCION_TO_UNIT -> { IrTypeOperator.IMPLICIT_COERCION_TO_UNIT -> {
expression.argument.accept(this, data).discard() expression.argument.accept(this, data).discard()
@@ -714,9 +703,9 @@ class ExpressionCodegen(
expression.argument.accept(this, data).coerce(AsmTypes.OBJECT_TYPE).materialize() expression.argument.accept(this, data).coerce(AsmTypes.OBJECT_TYPE).materialize()
val boxedType = boxType(asmType) val boxedType = boxType(asmType)
if (TypeUtils.isReifiedTypeParameter(kotlinType)) { if (typeOperand.isReifiedTypeParameter) {
putReifiedOperationMarkerIfTypeIsReifiedParameter( putReifiedOperationMarkerIfTypeIsReifiedParameter(
kotlinType, if (IrTypeOperator.SAFE_CAST == expression.operator) SAFE_AS else AS, mv, this typeOperand, if (IrTypeOperator.SAFE_CAST == expression.operator) SAFE_AS else AS, mv, this
) )
v.checkcast(boxedType) v.checkcast(boxedType)
} else { } else {
@@ -731,8 +720,8 @@ class ExpressionCodegen(
IrTypeOperator.INSTANCEOF, IrTypeOperator.NOT_INSTANCEOF -> { IrTypeOperator.INSTANCEOF, IrTypeOperator.NOT_INSTANCEOF -> {
expression.argument.accept(this, data).coerce(AsmTypes.OBJECT_TYPE).materialize() expression.argument.accept(this, data).coerce(AsmTypes.OBJECT_TYPE).materialize()
val type = boxType(asmType) val type = boxType(asmType)
if (TypeUtils.isReifiedTypeParameter(kotlinType)) { if (typeOperand.isReifiedTypeParameter) {
putReifiedOperationMarkerIfTypeIsReifiedParameter(kotlinType, ReifiedTypeInliner.OperationKind.IS, mv, this) putReifiedOperationMarkerIfTypeIsReifiedParameter(typeOperand, ReifiedTypeInliner.OperationKind.IS, mv, this)
v.instanceOf(type) v.instanceOf(type)
} else { } else {
generateIsCheck(mv, kotlinType, type, state.languageVersionSettings.isReleaseCoroutines()) generateIsCheck(mv, kotlinType, type, state.languageVersionSettings.isReleaseCoroutines())
@@ -782,17 +771,17 @@ class ExpressionCodegen(
// Convert single arg to string. // Convert single arg to string.
val type = expression.arguments[0].accept(this, data).materialized.type val type = expression.arguments[0].accept(this, data).materialized.type
if (!expression.arguments[0].type.isString()) if (!expression.arguments[0].type.isString())
AsmUtil.genToString(StackValue.onStack(type), type, null, typeMapper).put(expression.asmType, mv) AsmUtil.genToString(StackValue.onStack(type), type, null, typeMapper.kotlinTypeMapper).put(expression.asmType, mv)
} }
arity == 2 && expression.arguments[0].type.isStringClassType() -> { arity == 2 && expression.arguments[0].type.isStringClassType() -> {
// Call the stringPlus intrinsic // Call the stringPlus intrinsic
expression.arguments.forEach { expression.arguments.forEach {
val type = it.accept(this, data).materialized.type val type = it.accept(this, data).materialized.type
if (type.sort != Type.OBJECT) if (type.sort != Type.OBJECT)
AsmUtil.genToString(StackValue.onStack(type), type, null, typeMapper).put(expression.asmType, mv) AsmUtil.genToString(StackValue.onStack(type), type, null, typeMapper.kotlinTypeMapper).put(expression.asmType, mv)
} }
mv.invokestatic( mv.invokestatic(
IntrinsicMethods.INTRINSICS_CLASS_NAME, IrIntrinsicMethods.INTRINSICS_CLASS_NAME,
"stringPlus", "stringPlus",
"(Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/String;", "(Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/String;",
false false
@@ -897,8 +886,8 @@ class ExpressionCodegen(
val catches = aTry.catches val catches = aTry.catches
for (clause in catches) { for (clause in catches) {
val clauseStart = markNewLabel() val clauseStart = markNewLabel()
val descriptor = clause.parameter val parameter = clause.catchParameter
val descriptorType = descriptor.asmType val descriptorType = parameter.asmType
val index = frameMap.enter(clause.catchParameter, descriptorType) val index = frameMap.enter(clause.catchParameter, descriptorType)
mv.store(index, descriptorType) mv.store(index, descriptorType)
@@ -917,7 +906,7 @@ class ExpressionCodegen(
val clauseEnd = markNewLabel() val clauseEnd = markNewLabel()
mv.visitLocalVariable( mv.visitLocalVariable(
descriptor.name.asString(), descriptorType.descriptor, null, clauseStart, clauseEnd, parameter.name.asString(), descriptorType.descriptor, null, clauseStart, clauseEnd,
index index
) )
@@ -1025,16 +1014,17 @@ class ExpressionCodegen(
} else if (classReference is IrClassReference) { } else if (classReference is IrClassReference) {
val classType = classReference.classType val classType = classReference.classType
if (classType is CrIrType) { if (classType is CrIrType) {
putJavaLangClassInstance(mv, classType.type, null, typeMapper) putJavaLangClassInstance(mv, classType.type, null, typeMapper.kotlinTypeMapper)
return classReference.onStack return classReference.onStack
} else { } else {
val kotlinType = classType.toKotlinType() val kotlinType = classType.toKotlinType()
if (TypeUtils.isTypeParameter(kotlinType)) { val classifier = classType.classifierOrNull
assert(TypeUtils.isReifiedTypeParameter(kotlinType)) { "Non-reified type parameter under ::class should be rejected by type checker: " + kotlinType } if (classifier is IrTypeParameterSymbol) {
putReifiedOperationMarkerIfTypeIsReifiedParameter(kotlinType, ReifiedTypeInliner.OperationKind.JAVA_CLASS, mv, this) assert(classifier.owner.isReified) { "Non-reified type parameter under ::class should be rejected by type checker: ${classifier.owner.dump()}" }
putReifiedOperationMarkerIfTypeIsReifiedParameter(classType, ReifiedTypeInliner.OperationKind.JAVA_CLASS, mv, this)
} }
putJavaLangClassInstance(mv, typeMapper.mapType(kotlinType), kotlinType, typeMapper) putJavaLangClassInstance(mv, typeMapper.mapType(classType), kotlinType, typeMapper.kotlinTypeMapper)
} }
} else { } else {
throw AssertionError("not an IrGetClass or IrClassReference: ${classReference.dump()}") throw AssertionError("not an IrGetClass or IrClassReference: ${classReference.dump()}")
@@ -1046,29 +1036,14 @@ class ExpressionCodegen(
return classReference.onStack return classReference.onStack
} }
private fun resolveToCallable(irCall: IrMemberAccessExpression, isSuper: Boolean): Callable { private fun resolveToCallable(irCall: IrFunctionAccessExpression, isSuper: Boolean): Callable {
var descriptor = irCall.descriptor return typeMapper.mapToCallableMethod(irCall.symbol.owner, isSuper)
if (descriptor is TypeAliasConstructorDescriptor) {
throw AssertionError("TypeAliasConstructorDescriptor should be unwrapped in psi2ir: $descriptor")
}
if (descriptor is PropertyDescriptor) {
descriptor = descriptor.getter!!
}
if (descriptor is CallableMemberDescriptor && JvmCodegenUtil.getDirectMember(descriptor) is SyntheticJavaPropertyDescriptor) {
val propertyDescriptor = JvmCodegenUtil.getDirectMember(descriptor) as SyntheticJavaPropertyDescriptor
descriptor = if (descriptor is PropertyGetterDescriptor) {
propertyDescriptor.getMethod
} else {
propertyDescriptor.setMethod!!
}
}
return typeMapper.mapToCallableMethod(descriptor as FunctionDescriptor, isSuper)
} }
private fun getOrCreateCallGenerator( private fun getOrCreateCallGenerator(
descriptor: CallableDescriptor, irFunction: IrFunction,
element: IrMemberAccessExpression?, element: IrMemberAccessExpression?,
typeParameterMappings: TypeParameterMappings?, typeParameterMappings: IrTypeParameterMappings?,
isDefaultCompilation: Boolean, isDefaultCompilation: Boolean,
data: BlockInfo data: BlockInfo
): IrCallGenerator { ): IrCallGenerator {
@@ -1076,56 +1051,56 @@ class ExpressionCodegen(
// We should inline callable containing reified type parameters even if inline is disabled // We should inline callable containing reified type parameters even if inline is disabled
// because they may contain something to reify and straight call will probably fail at runtime // because they may contain something to reify and straight call will probably fail at runtime
val isInline = descriptor.isInlineCall(state) val isInline = irFunction.isInlineCall(state)
if (!isInline) return IrCallGenerator.DefaultCallGenerator if (!isInline) return IrCallGenerator.DefaultCallGenerator
val original = unwrapInitialSignatureDescriptor(DescriptorUtils.unwrapFakeOverride(descriptor.original as FunctionDescriptor)) val original = (irFunction as? IrSimpleFunction)?.resolveFakeOverride() ?: irFunction
return if (isDefaultCompilation) { return if (isDefaultCompilation) {
TODO() TODO()
} else { } else {
IrInlineCodegen(this, state, original, typeParameterMappings!!, IrSourceCompilerForInline(state, element, this, data)) IrInlineCodegen(this, state, original.descriptor, typeParameterMappings!!, IrSourceCompilerForInline(state, element, this, data))
} }
} }
private fun getOrCreateCallGenerator( private fun getOrCreateCallGenerator(
memberAccessExpression: IrMemberAccessExpression, functionAccessExpression: IrFunctionAccessExpression,
descriptor: CallableDescriptor,
data: BlockInfo data: BlockInfo
): IrCallGenerator { ): IrCallGenerator {
val callee = functionAccessExpression.symbol.owner
val typeArgumentContainer = if (callee is IrConstructor) callee.parentAsClass else callee
val typeArguments = val typeArguments =
if (memberAccessExpression.typeArgumentsCount == 0) { if (functionAccessExpression.typeArgumentsCount == 0) {
//avoid ambiguity with type constructor type parameters //avoid ambiguity with type constructor type parameters
emptyMap() emptyMap()
} else (descriptor.propertyIfAccessor as? CallableDescriptor)?.original?.typeParameters?.keysToMap { } else typeArgumentContainer.typeParameters.keysToMap {
memberAccessExpression.getTypeArgumentOrDefault(it) functionAccessExpression.getTypeArgumentOrDefault(it)
} ?: emptyMap() }
val mappings = TypeParameterMappings() val mappings = IrTypeParameterMappings()
for (entry in typeArguments.entries) { for (entry in typeArguments.entries) {
val key = entry.key val key = entry.key
val type = entry.value val type = entry.value
val isReified = key.isReified || InlineUtil.isArrayConstructorWithLambda(descriptor) val isReified = key.isReified || callee.isArrayConstructorWithLambda()
val typeParameterAndReificationArgument = extractReificationArgument(type) val reificationArgument = extractReificationArgument(type)
if (typeParameterAndReificationArgument == null) { if (reificationArgument == null) {
val approximatedType = approximateCapturedTypes(entry.value).upper
// type is not generic // type is not generic
val signatureWriter = BothSignatureWriter(BothSignatureWriter.Mode.TYPE) val signatureWriter = BothSignatureWriter(BothSignatureWriter.Mode.TYPE)
val asmType = typeMapper.mapTypeParameter(approximatedType, signatureWriter) val asmType = typeMapper.mapTypeParameter(type, signatureWriter)
mappings.addParameterMappingToType( mappings.addParameterMappingToType(
key.name.identifier, approximatedType, asmType, signatureWriter.toString(), isReified key.name.identifier, type, asmType, signatureWriter.toString(), isReified
) )
} else { } else {
mappings.addParameterMappingForFurtherReification( mappings.addParameterMappingForFurtherReification(
key.name.identifier, type, typeParameterAndReificationArgument.second, isReified key.name.identifier, type, reificationArgument, isReified
) )
} }
} }
return getOrCreateCallGenerator(descriptor, memberAccessExpression, mappings, false, data) return getOrCreateCallGenerator(callee, functionAccessExpression, mappings, false, data)
} }
override fun consumeReifiedOperationMarker(typeParameterDescriptor: TypeParameterDescriptor) { override fun consumeReifiedOperationMarker(typeParameterDescriptor: TypeParameterDescriptor) {
@@ -1152,6 +1127,71 @@ class ExpressionCodegen(
fun isFinallyMarkerRequired(): Boolean { fun isFinallyMarkerRequired(): Boolean {
return irFunction.isInline || isInlineLambda return irFunction.isInline || isInlineLambda
} }
/* Borrowed and modified from compiler/backend/src/org/jetbrains/kotlin/codegen/codegenUtil.kt */
private fun extractReificationArgumentWithParameter(initialType: IrType): Pair<IrTypeParameter, IrReificationArgument>? {
var type = initialType
var arrayDepth = 0
val isNullable = type.isMarkedNullable()
while (type.isArray() || type.isNullableArray()) {
arrayDepth++
type = (type as IrSimpleType).arguments[0].safeAs<IrTypeProjection>()?.type ?: classCodegen.context.irBuiltIns.anyNType
}
val parameter = type.getTypeParameterOrNull() ?: return null
return Pair(parameter, IrReificationArgument(parameter.name.asString(), isNullable, arrayDepth))
}
private fun extractReificationArgument(initialType: IrType): IrReificationArgument? = extractReificationArgumentWithParameter(initialType)?.second
/* From ReifiedTypeInliner.kt */
inner class IrReificationArgument(
val parameterName: String, val nullable: Boolean, private val arrayDepth: Int
) {
fun asString() = "[".repeat(arrayDepth) + parameterName + (if (nullable) "?" else "")
fun combine(replacement: IrReificationArgument) =
IrReificationArgument(
replacement.parameterName,
this.nullable || (replacement.nullable && this.arrayDepth == 0),
this.arrayDepth + replacement.arrayDepth
)
fun reify(replacementAsmType: Type, irType: IrType) =
Pair(
Type.getType("[".repeat(arrayDepth) + replacementAsmType),
irType.arrayOf(arrayDepth).withHasQuestionMark(nullable)
)
private fun IrType.arrayOf(arrayDepth: Int): IrType {
val builtins = classCodegen.context.irBuiltIns
var currentType = this
repeat(arrayDepth) {
currentType = builtins.arrayClass.typeWith(currentType)
}
return currentType
}
fun toReificationArgument() = ReificationArgument(parameterName, nullable, arrayDepth)
}
/* From ExpressionCodegen.java */
private fun putReifiedOperationMarkerIfTypeIsReifiedParameter(
type: IrType, operationKind: ReifiedTypeInliner.OperationKind, v: InstructionAdapter,
codegen: BaseExpressionCodegen?
) {
val typeParameterAndReificationArgument = extractReificationArgumentWithParameter(type)
if (typeParameterAndReificationArgument != null && typeParameterAndReificationArgument.first.isReified) {
val irTypeParameter = typeParameterAndReificationArgument.first
codegen?.consumeReifiedOperationMarker(irTypeParameter.descriptor)
ReifiedTypeInliner.putReifiedOperationMarker(
operationKind, typeParameterAndReificationArgument.second.toReificationArgument(), v
)
}
}
} }
fun DefaultCallArgs.generateOnStackIfNeeded(callGenerator: IrCallGenerator, isConstructor: Boolean, codegen: ExpressionCodegen): Boolean { fun DefaultCallArgs.generateOnStackIfNeeded(callGenerator: IrCallGenerator, isConstructor: Boolean, codegen: ExpressionCodegen): Boolean {
@@ -1173,6 +1213,80 @@ fun DefaultCallArgs.generateOnStackIfNeeded(callGenerator: IrCallGenerator, isCo
return toInts.isNotEmpty() return toInts.isNotEmpty()
} }
internal fun CallableDescriptor.isInlineCall(state: GenerationState) = internal fun IrFunction.isInlineCall(state: GenerationState) =
(!state.isInlineDisabled || InlineUtil.containsReifiedTypeParameters(this)) && (!state.isInlineDisabled || containsReifiedTypeParameters()) &&
(InlineUtil.isInline(this) || InlineUtil.isArrayConstructorWithLambda(this)) (isInline || isArrayConstructorWithLambda())
val IrType.isReifiedTypeParameter: Boolean
get() = this.classifierOrNull?.safeAs<IrTypeParameterSymbol>()?.owner?.isReified == true
/* Copied and modified from InlineUtil.java */
fun isInline(declaration: IrDeclaration?): Boolean = declaration is IrSimpleFunction && declaration.isInline
fun IrFunction.containsReifiedTypeParameters(): Boolean =
typeParameters.any { it.isReified }
fun IrClass.isArrayOrPrimitiveArray() = this.defaultType.let { it.isArray() || it.isPrimitiveArray() }
/* From typeUtil.java */
fun IrType.getTypeParameterOrNull() = classifierOrNull?.owner?.safeAs<IrTypeParameter>()
/* From ReifiedTypeInliner.kt */
class IrTypeParameterMappings {
private val mappingsByName = hashMapOf<String, IrTypeParameterMapping>()
fun addParameterMappingToType(name: String, type: IrType, asmType: Type, signature: String, isReified: Boolean) {
mappingsByName[name] = IrTypeParameterMapping(
name, type, asmType, reificationArgument = null, signature = signature, isReified = isReified
)
}
fun addParameterMappingForFurtherReification(
name: String,
type: IrType,
reificationArgument: ExpressionCodegen.IrReificationArgument,
isReified: Boolean
) {
mappingsByName[name] = IrTypeParameterMapping(
name, type, asmType = null, reificationArgument = reificationArgument, signature = null, isReified = isReified
)
}
operator fun get(name: String): IrTypeParameterMapping? = mappingsByName[name]
fun hasReifiedParameters() = mappingsByName.values.any { it.isReified }
internal inline fun forEach(l: (IrTypeParameterMapping) -> Unit) {
mappingsByName.values.forEach(l)
}
fun toTypeParameterMappings() = TypeParameterMappings().also { result ->
mappingsByName.forEach { (_, value) ->
if (value.asmType == null) {
result.addParameterMappingForFurtherReification(
value.name,
value.type.toKotlinType(),
value.reificationArgument!!.toReificationArgument(),
value.isReified
)
} else {
result.addParameterMappingToType(
value.name,
value.type.toKotlinType(),
value.asmType,
value.signature!!,
value.isReified
)
}
}
}
}
class IrTypeParameterMapping(
val name: String,
val type: IrType,
val asmType: Type?,
val reificationArgument: ExpressionCodegen.IrReificationArgument?,
val signature: String?,
val isReified: Boolean
)
@@ -7,14 +7,14 @@ package org.jetbrains.kotlin.backend.jvm.codegen
import org.jetbrains.kotlin.builtins.KotlinBuiltIns.FQ_NAMES import org.jetbrains.kotlin.builtins.KotlinBuiltIns.FQ_NAMES
import org.jetbrains.kotlin.codegen.* import org.jetbrains.kotlin.codegen.*
import org.jetbrains.kotlin.codegen.FunctionCodegen
import org.jetbrains.kotlin.codegen.state.GenerationState import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.types.toKotlinType import org.jetbrains.kotlin.ir.util.dump
import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.util.getAnnotation
import org.jetbrains.kotlin.ir.util.hasAnnotation
import org.jetbrains.kotlin.ir.util.isAnnotationClass
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.jvm.AsmTypes import org.jetbrains.kotlin.resolve.jvm.AsmTypes
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodGenericSignature import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodGenericSignature
@@ -33,8 +33,6 @@ open class FunctionCodegen(
val state = classCodegen.state val state = classCodegen.state
val descriptor = irFunction.descriptor
fun generate(): JvmMethodGenericSignature = fun generate(): JvmMethodGenericSignature =
try { try {
doGenerate() doGenerate()
@@ -43,23 +41,26 @@ open class FunctionCodegen(
} }
private fun doGenerate(): JvmMethodGenericSignature { private fun doGenerate(): JvmMethodGenericSignature {
val signature = classCodegen.typeMapper.mapSignatureWithGeneric(descriptor, OwnerKind.IMPLEMENTATION) val signature = classCodegen.typeMapper.mapSignatureWithGeneric(irFunction, OwnerKind.IMPLEMENTATION)
val flags = calculateMethodFlags(irFunction.isStatic) val flags = calculateMethodFlags(irFunction.isStatic)
val methodVisitor = createMethod(flags, signature) val methodVisitor = createMethod(flags, signature)
generateParameterNames(descriptor, methodVisitor, signature, state, flags.and(Opcodes.ACC_SYNTHETIC) != 0) generateParameterNames(irFunction.descriptor, methodVisitor, signature, state, flags.and(Opcodes.ACC_SYNTHETIC) != 0)
if (irFunction.origin != IrDeclarationOrigin.FUNCTION_FOR_DEFAULT_PARAMETER) { if (irFunction.origin != IrDeclarationOrigin.FUNCTION_FOR_DEFAULT_PARAMETER) {
AnnotationCodegen(classCodegen, state, methodVisitor::visitAnnotation).genAnnotations(irFunction, signature.asmMethod.returnType) AnnotationCodegen(classCodegen, state, methodVisitor::visitAnnotation).genAnnotations(
FunctionCodegen.generateParameterAnnotations(descriptor, methodVisitor, signature, DummyOldInnerClassConsumer(), state) irFunction,
signature.asmMethod.returnType
)
generateParameterAnnotations(irFunction, methodVisitor, signature, classCodegen, state)
} }
if (!state.classBuilderMode.generateBodies || flags.and(Opcodes.ACC_ABSTRACT) != 0 || irFunction.isExternal) { if (!state.classBuilderMode.generateBodies || flags.and(Opcodes.ACC_ABSTRACT) != 0 || irFunction.isExternal) {
generateAnnotationDefaultValueIfNeeded(methodVisitor) generateAnnotationDefaultValueIfNeeded(methodVisitor)
methodVisitor.visitEnd() methodVisitor.visitEnd()
} else { } else {
val frameMap = createFrameMapWithReceivers(classCodegen.state, irFunction, signature) val frameMap = createFrameMapWithReceivers(signature)
ExpressionCodegen(irFunction, frameMap, InstructionAdapter(methodVisitor), classCodegen, isInlineLambda).generate() ExpressionCodegen(irFunction, frameMap, InstructionAdapter(methodVisitor), classCodegen, isInlineLambda).generate()
} }
@@ -102,7 +103,7 @@ open class FunctionCodegen(
// @Throws(vararg exceptionClasses: KClass<out Throwable>) // @Throws(vararg exceptionClasses: KClass<out Throwable>)
val exceptions = irFunction.getAnnotation(FqName("kotlin.jvm.Throws"))?.getValueArgument(0)?.let { val exceptions = irFunction.getAnnotation(FqName("kotlin.jvm.Throws"))?.getValueArgument(0)?.let {
(it as IrVararg).elements.map { exceptionClass -> (it as IrVararg).elements.map { exceptionClass ->
classCodegen.typeMapper.mapType((exceptionClass as IrClassReference).classType.toKotlinType()).internalName classCodegen.typeMapper.mapType((exceptionClass as IrClassReference).classType).internalName
}.toTypedArray() }.toTypedArray()
} }
@@ -127,7 +128,7 @@ open class FunctionCodegen(
// TODO: any simpler way to get to the value expression? // TODO: any simpler way to get to the value expression?
// Are there other valid IR structures that represent the default value? // Are there other valid IR structures that represent the default value?
return irFunction.safeAs<IrSimpleFunction>() return irFunction.safeAs<IrSimpleFunction>()
?.correspondingProperty ?.correspondingPropertySymbol?.owner
?.backingField ?.backingField
?.initializer.safeAs<IrExpressionBody>() ?.initializer.safeAs<IrExpressionBody>()
?.expression?.safeAs<IrGetValue>() ?.expression?.safeAs<IrGetValue>()
@@ -135,46 +136,95 @@ open class FunctionCodegen(
?.defaultValue?.safeAs<IrExpressionBody>() ?.defaultValue?.safeAs<IrExpressionBody>()
?.expression ?.expression
} }
}
private fun createFrameMapWithReceivers( private fun createFrameMapWithReceivers(signature: JvmMethodSignature): IrFrameMap {
state: GenerationState, val frameMap = IrFrameMap()
irFunction: IrFunction, if (irFunction is IrConstructor) {
signature: JvmMethodSignature frameMap.enter((irFunction.parent as IrClass).thisReceiver!!, AsmTypes.OBJECT_TYPE)
): IrFrameMap { } else if (irFunction.dispatchReceiverParameter != null) {
val frameMap = IrFrameMap() frameMap.enter(irFunction.dispatchReceiverParameter!!, AsmTypes.OBJECT_TYPE)
if (irFunction is IrConstructor) { }
frameMap.enter((irFunction.parent as IrClass).thisReceiver!!, AsmTypes.OBJECT_TYPE)
} else if (irFunction.dispatchReceiverParameter != null) {
frameMap.enter(irFunction.dispatchReceiverParameter!!, AsmTypes.OBJECT_TYPE)
}
for (parameter in signature.valueParameters) { for (parameter in signature.valueParameters) {
if (parameter.kind == JvmMethodParameterKind.RECEIVER) { if (parameter.kind == JvmMethodParameterKind.RECEIVER) {
val receiverParameter = irFunction.extensionReceiverParameter val receiverParameter = irFunction.extensionReceiverParameter
if (receiverParameter?.descriptor != null) { if (receiverParameter != null) {
frameMap.enter(receiverParameter, state.typeMapper.mapType(receiverParameter.descriptor)) frameMap.enter(receiverParameter, classCodegen.typeMapper.mapType(receiverParameter))
} else { } else {
frameMap.enterTemp(parameter.asmType)
}
} else if (parameter.kind != JvmMethodParameterKind.VALUE) {
frameMap.enterTemp(parameter.asmType) frameMap.enterTemp(parameter.asmType)
} }
} else if (parameter.kind != JvmMethodParameterKind.VALUE) {
frameMap.enterTemp(parameter.asmType)
} }
}
for (parameter in irFunction.valueParameters) { for (parameter in irFunction.valueParameters) {
frameMap.enter(parameter, state.typeMapper.mapType(parameter.type.toKotlinType())) frameMap.enter(parameter, classCodegen.typeMapper.mapType(parameter.type))
} }
return frameMap return frameMap
}
} }
/**/// TODO: temporary, to allow calling the old FunctionCodegen.generateParameterAnnotations // Borrowed from org.jetbrains.kotlin.codegen.FunctionCodegen.java
private class DummyOldInnerClassConsumer() fun generateParameterAnnotations(
: org.jetbrains.kotlin.codegen.InnerClassConsumer { irFunction: IrFunction,
mv: MethodVisitor,
override fun addInnerClassInfoFromAnnotation(classDescriptor: ClassDescriptor) { jvmSignature: JvmMethodSignature,
innerClassConsumer: InnerClassConsumer,
state: GenerationState
) {
val iterator = irFunction.valueParameters.iterator()
val kotlinParameterTypes = jvmSignature.valueParameters
var syntheticParameterCount = 0
kotlinParameterTypes.forEachIndexed { i, parameterSignature ->
val kind = parameterSignature.kind
if (kind.isSkippedInGenericSignature) {
if (AsmUtil.IS_BUILT_WITH_ASM6) {
markEnumOrInnerConstructorParameterAsSynthetic(mv, i, state.classBuilderMode)
} else {
syntheticParameterCount++
}
}
}
if (!AsmUtil.IS_BUILT_WITH_ASM6) {
visitAnnotableParameterCount(mv, kotlinParameterTypes.size - syntheticParameterCount)
} }
} kotlinParameterTypes.forEachIndexed { i, parameterSignature ->
val kind = parameterSignature.kind
if (kind.isSkippedInGenericSignature) return@forEachIndexed
val annotated = when (kind) {
JvmMethodParameterKind.VALUE -> iterator.next()
JvmMethodParameterKind.RECEIVER -> irFunction.extensionReceiverParameter
else -> null
}
if (annotated != null) {
AnnotationCodegen(
innerClassConsumer,
state
) { descriptor, visible ->
mv.visitParameterAnnotation(
if (AsmUtil.IS_BUILT_WITH_ASM6) i else i - syntheticParameterCount,
descriptor,
visible
)
}
.genAnnotations(annotated, parameterSignature.asmType)
}
}
}
private fun markEnumOrInnerConstructorParameterAsSynthetic(mv: MethodVisitor, i: Int, mode: ClassBuilderMode) {
// IDEA's ClsPsi builder fails to annotate synthetic parameters
if (mode === ClassBuilderMode.LIGHT_CLASSES) return
// This is needed to avoid RuntimeInvisibleParameterAnnotations error in javac:
// see MethodWriter.visitParameterAnnotation()
val av = mv.visitParameterAnnotation(i, "Ljava/lang/Synthetic;", true)
av?.visitEnd()
}
@@ -20,14 +20,14 @@ import org.jetbrains.kotlin.codegen.Callable
import org.jetbrains.kotlin.codegen.CallableMethod import org.jetbrains.kotlin.codegen.CallableMethod
import org.jetbrains.kotlin.codegen.StackValue import org.jetbrains.kotlin.codegen.StackValue
import org.jetbrains.kotlin.codegen.ValueKind import org.jetbrains.kotlin.codegen.ValueKind
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor import org.jetbrains.kotlin.ir.declarations.IrValueParameter
import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrMemberAccessExpression import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression
import org.jetbrains.org.objectweb.asm.Type import org.jetbrains.org.objectweb.asm.Type
interface IrCallGenerator { interface IrCallGenerator {
fun genCall(callableMethod: Callable, callDefault: Boolean, codegen: ExpressionCodegen, expression: IrMemberAccessExpression) { fun genCall(callableMethod: Callable, callDefault: Boolean, codegen: ExpressionCodegen, expression: IrFunctionAccessExpression) {
if (!callDefault) { if (!callDefault) {
callableMethod.genInvokeInstruction(codegen.mv) callableMethod.genInvokeInstruction(codegen.mv)
} else { } else {
@@ -40,7 +40,7 @@ interface IrCallGenerator {
} }
fun genValueAndPut( fun genValueAndPut(
valueParameterDescriptor: ValueParameterDescriptor?, irValueParameter: IrValueParameter?,
argumentExpression: IrExpression, argumentExpression: IrExpression,
parameterType: Type, parameterType: Type,
parameterIndex: Int, parameterIndex: Int,
@@ -6,19 +6,15 @@
package org.jetbrains.kotlin.backend.jvm.codegen package org.jetbrains.kotlin.backend.jvm.codegen
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.builtins.isExtensionFunctionType
import org.jetbrains.kotlin.codegen.* import org.jetbrains.kotlin.codegen.*
import org.jetbrains.kotlin.codegen.inline.* import org.jetbrains.kotlin.codegen.inline.*
import org.jetbrains.kotlin.codegen.state.GenerationState import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.ir.declarations.IrConstructor
import org.jetbrains.kotlin.ir.declarations.IrFunction import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.declarations.IrValueParameter import org.jetbrains.kotlin.ir.declarations.IrValueParameter
import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.resolve.inline.InlineUtil.isInlineParameter
import org.jetbrains.kotlin.utils.keysToMap import org.jetbrains.kotlin.utils.keysToMap
import org.jetbrains.org.objectweb.asm.Type import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.commons.Method import org.jetbrains.org.objectweb.asm.commons.Method
@@ -27,9 +23,10 @@ class IrInlineCodegen(
codegen: ExpressionCodegen, codegen: ExpressionCodegen,
state: GenerationState, state: GenerationState,
function: FunctionDescriptor, function: FunctionDescriptor,
typeParameterMappings: TypeParameterMappings, typeParameterMappings: IrTypeParameterMappings,
sourceCompiler: SourceCompilerForInline sourceCompiler: SourceCompilerForInline
) : InlineCodegen<ExpressionCodegen>(codegen, state, function, typeParameterMappings, sourceCompiler), IrCallGenerator { ) : InlineCodegen<ExpressionCodegen>(codegen, state, function, typeParameterMappings.toTypeParameterMappings(), sourceCompiler),
IrCallGenerator {
override fun generateAssertFieldIfNeeded(info: RootInliningContext) { override fun generateAssertFieldIfNeeded(info: RootInliningContext) {
// TODO: JVM assertions are not implemented yet in IR backend // TODO: JVM assertions are not implemented yet in IR backend
} }
@@ -45,19 +42,19 @@ class IrInlineCodegen(
} }
override fun genValueAndPut( override fun genValueAndPut(
valueParameterDescriptor: ValueParameterDescriptor?, irValueParameter: IrValueParameter?,
argumentExpression: IrExpression, argumentExpression: IrExpression,
parameterType: Type, parameterType: Type,
parameterIndex: Int, parameterIndex: Int,
codegen: ExpressionCodegen, codegen: ExpressionCodegen,
blockInfo: BlockInfo blockInfo: BlockInfo
) { ) {
if (valueParameterDescriptor?.let { isInlineParameter(it) } == true && isInlineIrExpression(argumentExpression)) { if (irValueParameter?.isInlineParameter() == true && isInlineIrExpression(argumentExpression)) {
val irReference: IrFunctionReference = val irReference: IrFunctionReference =
(argumentExpression as IrBlock).statements.filterIsInstance<IrFunctionReference>().single() (argumentExpression as IrBlock).statements.filterIsInstance<IrFunctionReference>().single()
rememberClosure(irReference, parameterType, valueParameterDescriptor) as IrExpressionLambdaImpl rememberClosure(irReference, parameterType, irValueParameter) as IrExpressionLambdaImpl
} else { } else {
putValueOnStack(argumentExpression, parameterType, valueParameterDescriptor?.index ?: -1) putValueOnStack(argumentExpression, parameterType, irValueParameter?.index ?: -1)
} }
} }
@@ -89,12 +86,17 @@ class IrInlineCodegen(
invocationParamBuilder.markValueParametersStart() invocationParamBuilder.markValueParametersStart()
} }
override fun genCall(callableMethod: Callable, callDefault: Boolean, codegen: ExpressionCodegen, expression: IrMemberAccessExpression) { override fun genCall(
callableMethod: Callable,
callDefault: Boolean,
codegen: ExpressionCodegen,
expression: IrFunctionAccessExpression
) {
val typeArguments = expression.descriptor.typeParameters.keysToMap { expression.getTypeArgumentOrDefault(it) } val typeArguments = expression.descriptor.typeParameters.keysToMap { expression.getTypeArgumentOrDefault(it) }
performInline(typeArguments, callDefault, codegen) performInline(typeArguments, callDefault, codegen)
} }
private fun rememberClosure(irReference: IrFunctionReference, type: Type, parameter: ValueParameterDescriptor): LambdaInfo { private fun rememberClosure(irReference: IrFunctionReference, type: Type, parameter: IrValueParameter): LambdaInfo {
//assert(InlineUtil.isInlinableParameterExpression(ktLambda)) { "Couldn't find inline expression in ${expression.text}" } //assert(InlineUtil.isInlinableParameterExpression(ktLambda)) { "Couldn't find inline expression in ${expression.text}" }
val expression = irReference.symbol.owner val expression = irReference.symbol.owner
return IrExpressionLambdaImpl( return IrExpressionLambdaImpl(
@@ -160,13 +162,5 @@ fun IrFunction.isInlineFunctionCall(context: JvmBackendContext) =
(!context.state.isInlineDisabled || typeParameters.any { it.isReified }) && (!context.state.isInlineDisabled || typeParameters.any { it.isReified }) &&
(isInline || isArrayConstructorWithLambda()) (isInline || isArrayConstructorWithLambda())
private fun IrFunction.isArrayConstructorWithLambda() =
valueParameters.size == 2 &&
this is IrConstructor &&
parentAsClass.let {
it.getPackageFragment()?.fqName?.asString() == "kotlin" &&
it.name.asString().endsWith("Array")
}
fun IrValueParameter.isInlineParameter() = fun IrValueParameter.isInlineParameter() =
!isNoinline && !type.isNullable() && type.isFunctionOrKFunction() !isNoinline && !type.isNullable() && type.isFunctionOrKFunction()
@@ -0,0 +1,65 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.backend.jvm.codegen
import org.jetbrains.kotlin.codegen.OwnerKind
import org.jetbrains.kotlin.codegen.signature.JvmSignatureWriter
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.toKotlinType
import org.jetbrains.kotlin.load.kotlin.TypeMappingMode
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
class IrTypeMapper(val kotlinTypeMapper: KotlinTypeMapper) {
val classBuilderMode get() = kotlinTypeMapper.classBuilderMode
fun classInternalName(irClass: IrClass) = kotlinTypeMapper.classInternalName(irClass.descriptor)
fun mapAsmMethod(irFunction: IrFunction) = kotlinTypeMapper.mapAsmMethod(irFunction.descriptor)
fun mapClass(irClass: IrClass) = kotlinTypeMapper.mapClass(irClass.descriptor)
fun mapFieldSignature(irType: IrType, irFrield: IrField) =
kotlinTypeMapper.mapFieldSignature(irType.toKotlinType(), irFrield.descriptor)
fun mapFunctionName(irReturnTarget: IrReturnTarget, ownerKind: OwnerKind) =
kotlinTypeMapper.mapFunctionName(irReturnTarget.descriptor, ownerKind)
fun mapImplementationOwner(irDeclaration: IrDeclaration) = kotlinTypeMapper.mapImplementationOwner(irDeclaration.descriptor)
fun mapReturnType(irReturnTarget: IrReturnTarget) = kotlinTypeMapper.mapReturnType(irReturnTarget.descriptor)
fun mapSignatureSkipGeneric(f: IrFunction, kind: OwnerKind = OwnerKind.IMPLEMENTATION) =
kotlinTypeMapper.mapSignatureSkipGeneric(f.descriptor, kind)
fun mapSignatureWithGeneric(f: IrFunction, kind: OwnerKind) = kotlinTypeMapper.mapSignatureWithGeneric(f.descriptor, kind)
fun mapSupertype(irType: IrType, sw: JvmSignatureWriter) = kotlinTypeMapper.mapSupertype(irType.toKotlinType(), sw)
fun mapToCallableMethod(f: IrFunction, superCall: Boolean, kind: OwnerKind? = null, resolvedCall: ResolvedCall<*>? = null) =
kotlinTypeMapper.mapToCallableMethod(f.descriptor, superCall, kind, resolvedCall)
fun mapType(irType: IrType) = kotlinTypeMapper.mapType(irType.toKotlinType())
fun mapType(irClass: IrClass) = kotlinTypeMapper.mapType(irClass.descriptor)
fun mapType(irField: IrField) = kotlinTypeMapper.mapType(irField.descriptor)
fun mapType(irValueParameter: IrValueParameter) = kotlinTypeMapper.mapType(irValueParameter.descriptor)
fun mapType(irVariable: IrVariable) = kotlinTypeMapper.mapType(irVariable.descriptor)
fun mapType(irType: IrType, sw: JvmSignatureWriter, mode: TypeMappingMode) =
kotlinTypeMapper.mapType(irType.toKotlinType(), sw, mode)
fun mapTypeParameter(irType: IrType, signatureWriter: JvmSignatureWriter) =
kotlinTypeMapper.mapTypeParameter(irType.toKotlinType(), signatureWriter)
fun writeFormalTypeParameters(irParameters: List<IrTypeParameter>, sw: JvmSignatureWriter) =
kotlinTypeMapper.writeFormalTypeParameters(irParameters.map { it.descriptor }, sw)
}
@@ -6,18 +6,42 @@
package org.jetbrains.kotlin.backend.jvm.codegen package org.jetbrains.kotlin.backend.jvm.codegen
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.backend.common.ir.ir2string
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.codegen.FrameMapBase import org.jetbrains.kotlin.backend.jvm.lower.allOverridden
import org.jetbrains.kotlin.codegen.SourceInfo import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap
import org.jetbrains.kotlin.codegen.*
import org.jetbrains.kotlin.codegen.AsmUtil.LABELED_THIS_PARAMETER
import org.jetbrains.kotlin.codegen.AsmUtil.RECEIVER_PARAMETER_NAME
import org.jetbrains.kotlin.codegen.inline.DefaultSourceMapper import org.jetbrains.kotlin.codegen.inline.DefaultSourceMapper
import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithSource import org.jetbrains.kotlin.codegen.signature.BothSignatureWriter
import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.IrSymbol import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.ir.util.isAnnotationClass import org.jetbrains.kotlin.ir.types.IrSimpleType
import org.jetbrains.kotlin.ir.util.isInterface import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.load.java.JavaVisibilities
import org.jetbrains.kotlin.load.kotlin.TypeMappingMode
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.checkers.ExpectedActualDeclarationChecker
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmClassSignature
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterKind
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
import org.jetbrains.kotlin.resolve.source.PsiSourceElement import org.jetbrains.kotlin.resolve.source.PsiSourceElement
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
import org.jetbrains.org.objectweb.asm.MethodVisitor
import org.jetbrains.org.objectweb.asm.Opcodes
import org.jetbrains.org.objectweb.asm.Type import org.jetbrains.org.objectweb.asm.Type
import java.io.File import java.util.ArrayList
import java.util.LinkedHashSet
class IrFrameMap : FrameMapBase<IrSymbol>() class IrFrameMap : FrameMapBase<IrSymbol>()
@@ -61,3 +85,371 @@ fun JvmBackendContext.getSourceMapper(declaration: IrClass): DefaultSourceMapper
) )
) )
} }
val IrType.isExtensionFunctionType: Boolean
get() = isFunctionTypeOrSubtype() && hasAnnotation(KotlinBuiltIns.FQ_NAMES.extensionFunctionType)
/**
* @return true if the function is a constructor of one of 9 array classes (Array&lt;T&gt;, IntArray, FloatArray, ...)
* which takes the size and an initializer lambda as parameters. Such constructors are marked as 'inline' but they are not loaded
* as such because the 'inline' flag is not stored for constructors in the binary metadata. Therefore we pretend that they are inline
*/
fun IrFunction.isArrayConstructorWithLambda(): Boolean = this is IrConstructor &&
valueParameters.size == 2 &&
parentAsClass.isArrayOrPrimitiveArray()
/* Borrowed from MemberCodegen.java */
fun writeInnerClass(innerClass: IrClass, typeMapper: IrTypeMapper, context: JvmBackendContext, v: ClassBuilder) {
val outerClassInternalName = innerClass.parent.safeAs<IrClass>()?.let { typeMapper.classInternalName(it) }
/* TODO: So long as the type mapper works by descriptors, the internal name should be consistent with it. */
val outerClassInternalNameByDescriptor = innerClass.descriptor.containingDeclaration.safeAs<ClassDescriptor>()?.let {
typeMapper.kotlinTypeMapper.classInternalName(it)
}
val innerName = innerClass.name.takeUnless { it.isSpecial }?.asString()
val innerClassInternalName = typeMapper.classInternalName(innerClass)
v.visitInnerClass(innerClassInternalName, outerClassInternalNameByDescriptor, innerName, innerClass.calculateInnerClassAccessFlags(context))
}
/* Borrowed with modifications from AsmUtil.java */
private val NO_FLAG_LOCAL = 0
private val visibilityToAccessFlag = mapOf(
Visibilities.PRIVATE to Opcodes.ACC_PRIVATE,
Visibilities.PRIVATE_TO_THIS to Opcodes.ACC_PRIVATE,
Visibilities.PROTECTED to Opcodes.ACC_PROTECTED,
JavaVisibilities.PROTECTED_STATIC_VISIBILITY to Opcodes.ACC_PROTECTED,
JavaVisibilities.PROTECTED_AND_PACKAGE to Opcodes.ACC_PROTECTED,
Visibilities.PUBLIC to Opcodes.ACC_PUBLIC,
Visibilities.INTERNAL to Opcodes.ACC_PUBLIC,
Visibilities.LOCAL to NO_FLAG_LOCAL,
JavaVisibilities.PACKAGE_VISIBILITY to AsmUtil.NO_FLAG_PACKAGE_PRIVATE
)
private fun IrDeclaration.getVisibilityAccessFlagForAnonymous(): Int =
if (isInlineOrContainedInInline(parent as? IrDeclaration)) Opcodes.ACC_PUBLIC else AsmUtil.NO_FLAG_PACKAGE_PRIVATE
fun IrClass.calculateInnerClassAccessFlags(context: JvmBackendContext): Int {
val isLambda = superTypes.any { it.safeAs<IrSimpleType>()?.classifier === context.ir.symbols.lambdaClass }
val visibility = when {
isLambda -> getVisibilityAccessFlagForAnonymous()
visibility === Visibilities.LOCAL -> Opcodes.ACC_PUBLIC
else -> getVisibilityAccessFlag()
}
return visibility or
if (origin.isSynthetic) Opcodes.ACC_SYNTHETIC else 0 or
innerAccessFlagsForModalityAndKind() or
if (isInner) 0 else Opcodes.ACC_STATIC
}
private fun IrClass.innerAccessFlagsForModalityAndKind(): Int {
when (kind) {
ClassKind.INTERFACE -> return Opcodes.ACC_ABSTRACT or Opcodes.ACC_INTERFACE
ClassKind.ENUM_CLASS -> return Opcodes.ACC_FINAL or Opcodes.ACC_ENUM
ClassKind.ANNOTATION_CLASS -> return Opcodes.ACC_ABSTRACT or Opcodes.ACC_ANNOTATION or Opcodes.ACC_INTERFACE
else -> {
if (modality === Modality.FINAL) {
return Opcodes.ACC_FINAL
} else if (modality === Modality.ABSTRACT || modality === Modality.SEALED) {
return Opcodes.ACC_ABSTRACT
}
}
}
return 0
}
private fun IrDeclarationWithVisibility.getVisibilityAccessFlag(kind: OwnerKind? = null): Int =
specialCaseVisibility(kind)
?: visibilityToAccessFlag[visibility]
?: throw IllegalStateException("$visibility is not a valid visibility in backend for ${ir2string(this)}")
private fun IrDeclarationWithVisibility.specialCaseVisibility(kind: OwnerKind?): Int? {
// if (JvmCodegenUtil.isNonIntrinsicPrivateCompanionObjectInInterface(memberDescriptor)) {
// return ACC_PUBLIC
// }
if (this is IrClass && Visibilities.isPrivate(visibility) &&
parent.safeAs<IrClass>()?.isInterface ?: false) { // TODO: non-intrinsic
return Opcodes.ACC_PUBLIC
}
// if (memberDescriptor is FunctionDescriptor && isInlineClassWrapperConstructor(memberDescriptor, kind))
if (this is IrConstructor && parentAsClass.isInline && kind === OwnerKind.IMPLEMENTATION) {
return Opcodes.ACC_PRIVATE
}
// if (kind !== OwnerKind.ERASED_INLINE_CLASS &&
// memberDescriptor is ConstructorDescriptor &&
// memberDescriptor !is AccessorForConstructorDescriptor &&
// shouldHideConstructorDueToInlineClassTypeValueParameters(memberDescriptor)
// ) {
if (kind !== OwnerKind.ERASED_INLINE_CLASS &&
this is IrConstructor &&
shouldHideDueToInlineClassTypeValueParameters()
) {
return Opcodes.ACC_PRIVATE
}
// if (memberDescriptor.isEffectivelyInlineOnly()) {
if (isEffectivelyInlineOnly()) {
return Opcodes.ACC_PRIVATE
}
// if (memberVisibility === Visibilities.LOCAL && memberDescriptor is CallableMemberDescriptor) {
if (visibility === Visibilities.LOCAL && this is IrFunction) {
return Opcodes.ACC_PUBLIC
}
// if (isEnumEntry(memberDescriptor)) {
if (this is IrClass && this.kind === ClassKind.ENUM_ENTRY) {
return AsmUtil.NO_FLAG_PACKAGE_PRIVATE
}
// These ones should be public anyway after ToArrayLowering.
// if (memberDescriptor.isToArrayFromCollection()) {
// return ACC_PUBLIC
// }
// if (memberDescriptor is ConstructorDescriptor && isAnonymousObject(memberDescriptor.containingDeclaration)) {
// return getVisibilityAccessFlagForAnonymous(memberDescriptor.containingDeclaration as ClassDescriptor)
// }
if (this is IrConstructor && parentAsClass.isAnonymousObject) {
return parentAsClass.getVisibilityAccessFlagForAnonymous()
}
// TODO: when is this applicable?
// if (memberDescriptor is SyntheticJavaPropertyDescriptor) {
// return getVisibilityAccessFlag((memberDescriptor as SyntheticJavaPropertyDescriptor).getMethod)
// }
// if (memberDescriptor is PropertyAccessorDescriptor) {
// val property = memberDescriptor.correspondingProperty
// if (property is SyntheticJavaPropertyDescriptor) {
// val method = (if (memberDescriptor === property.getGetter())
// (property as SyntheticJavaPropertyDescriptor).getMethod
// else
// (property as SyntheticJavaPropertyDescriptor).setMethod)
// ?: error("No get/set method in SyntheticJavaPropertyDescriptor: $property")
// return getVisibilityAccessFlag(method)
// }
// }
if (this is IrField && correspondingPropertySymbol?.owner?.isExternal == true) {
val method = correspondingPropertySymbol?.owner?.getter ?: correspondingPropertySymbol?.owner?.setter
?: error("No get/set method in SyntheticJavaPropertyDescriptor: ${ir2string(correspondingPropertySymbol?.owner)}")
return method.getVisibilityAccessFlag()
}
// if (memberDescriptor is CallableDescriptor && memberVisibility === Visibilities.PROTECTED) {
// for (overridden in DescriptorUtils.getAllOverriddenDescriptors(memberDescriptor as CallableDescriptor)) {
// if (isJvmInterface(overridden.containingDeclaration)) {
// return ACC_PUBLIC
// }
// }
// }
if (this is IrSimpleFunction && visibility === Visibilities.PROTECTED &&
allOverridden().any { it.parentAsClass.isJvmInterface }
) {
return Opcodes.ACC_PUBLIC
}
if (!Visibilities.isPrivate(visibility)) {
return null
}
if (this is IrSimpleFunction && isSuspend) {
return AsmUtil.NO_FLAG_PACKAGE_PRIVATE
}
// Should be taken care of in IR
// if (memberDescriptor is AccessorForCompanionObjectInstanceFieldDescriptor) {
// return NO_FLAG_PACKAGE_PRIVATE
// }
// return if (memberDescriptor is ConstructorDescriptor && isEnumEntry(containingDeclaration)) {
// NO_FLAG_PACKAGE_PRIVATE
// } else null
if (this is IrConstructor && parentAsClass.kind === ClassKind.ENUM_ENTRY) {
return AsmUtil.NO_FLAG_PACKAGE_PRIVATE
}
return null
}
/* From inlineClassManglingRules.kt */
fun IrConstructor.shouldHideDueToInlineClassTypeValueParameters() =
!Visibilities.isPrivate(visibility) &&
!parentAsClass.isInline &&
parentAsClass.modality !== Modality.SEALED &&
valueParameters.any { it.type.requiresFunctionNameMangling() }
fun IrType.requiresFunctionNameMangling(): Boolean =
isInlineClassThatRequiresMangling() || isTypeParameterWithUpperBoundThatRequiresMangling()
fun IrType.isInlineClassThatRequiresMangling() =
safeAs<IrSimpleType>()?.classifier?.owner?.safeAs<IrClass>()?.let {
it.isInline && !it.isDontMangleClass()
} ?: false
fun IrClass.isDontMangleClass() =
fqNameWhenAvailable != DescriptorUtils.RESULT_FQ_NAME
fun IrType.isTypeParameterWithUpperBoundThatRequiresMangling() =
safeAs<IrSimpleType>()?.classifier?.owner.safeAs<IrTypeParameter>()?.let { param ->
param.superTypes.any { it.requiresFunctionNameMangling() }
} ?: false
/* Borrowed from InlineUtil. */
private tailrec fun isInlineOrContainedInInline(declaration: IrDeclaration?): Boolean = when {
declaration === null -> false
declaration is IrFunction && declaration.isInline -> true
else -> isInlineOrContainedInInline(declaration.parent as? IrDeclaration)
}
/* Borrowed from inlineOnly.kt */
private val INLINE_ONLY_ANNOTATION_FQ_NAME = FqName("kotlin.internal.InlineOnly")
fun IrDeclarationWithVisibility.isInlineOnlyOrReifiable(): Boolean =
this is IrFunction && (isReifiable() || isInlineOnly())
fun IrDeclarationWithVisibility.isEffectivelyInlineOnly(): Boolean =
isInlineOnlyOrReifiable() ||
(this is IrSimpleFunction && isSuspend && isInline &&
(valueParameters.any { it.isCrossinline } || visibility === Visibilities.PRIVATE))
private fun IrFunction.isInlineOnly() =
isInline && hasAnnotation(INLINE_ONLY_ANNOTATION_FQ_NAME)
private fun IrFunction.isReifiable() = typeParameters.any { it.isReified }
// Borrowed with modifications from ImplementationBodyCodegen.java
private val KOTLIN_MARKER_INTERFACES: Map<FqName, String> = run {
val kotlinMarkerInterfaces = mutableMapOf<FqName, String>()
for (platformMutabilityMapping in JavaToKotlinClassMap.mutabilityMappings) {
kotlinMarkerInterfaces[platformMutabilityMapping.kotlinReadOnly.asSingleFqName()] = "kotlin/jvm/internal/markers/KMappedMarker"
val mutableClassId = platformMutabilityMapping.kotlinMutable
kotlinMarkerInterfaces[mutableClassId.asSingleFqName()] =
"kotlin/jvm/internal/markers/K" + mutableClassId.relativeClassName.asString()
.replace("MutableEntry", "Entry") // kotlin.jvm.internal.markers.KMutableMap.Entry for some reason
.replace(".", "$")
}
kotlinMarkerInterfaces
}
internal class IrSuperClassInfo(val type: Type, val irType: IrType?)
internal fun getSignature(
irClass: IrClass,
classAsmType: Type,
superClassInfo: IrSuperClassInfo,
typeMapper: IrTypeMapper
): JvmClassSignature {
val sw = BothSignatureWriter(BothSignatureWriter.Mode.CLASS)
typeMapper.writeFormalTypeParameters(irClass.typeParameters, sw)
sw.writeSuperclass()
val irType = superClassInfo.irType
if (irType == null) {
sw.writeClassBegin(superClassInfo.type)
sw.writeClassEnd()
} else {
typeMapper.mapSupertype(irType, sw)
}
sw.writeSuperclassEnd()
val superInterfaces = LinkedHashSet<String>()
val kotlinMarkerInterfaces = LinkedHashSet<String>()
for (superType in irClass.superTypes) {
val superClass = superType.safeAs<IrSimpleType>()?.classifier?.safeAs<IrClassSymbol>()?.owner ?: continue
if (superClass.isJvmInterface) {
val kotlinInterfaceName = superClass.fqNameWhenAvailable!!
sw.writeInterface()
val jvmInterfaceType = typeMapper.mapSupertype(superType, sw)
sw.writeInterfaceEnd()
val jvmInterfaceInternalName = jvmInterfaceType.internalName
superInterfaces.add(jvmInterfaceInternalName)
val kotlinMarkerInterfaceInternalName = KOTLIN_MARKER_INTERFACES.get(kotlinInterfaceName)
if (kotlinMarkerInterfaceInternalName != null) {
if (typeMapper.classBuilderMode === ClassBuilderMode.LIGHT_CLASSES) {
sw.writeInterface()
val kotlinCollectionType =
typeMapper.mapType(superClass.defaultType, sw, TypeMappingMode.SUPER_TYPE_KOTLIN_COLLECTIONS_AS_IS)
sw.writeInterfaceEnd()
superInterfaces.add(kotlinCollectionType.internalName)
}
kotlinMarkerInterfaces.add(kotlinMarkerInterfaceInternalName)
}
}
}
for (kotlinMarkerInterface in kotlinMarkerInterfaces) {
sw.writeInterface()
sw.writeAsmType(Type.getObjectType(kotlinMarkerInterface))
sw.writeInterfaceEnd()
}
superInterfaces.addAll(kotlinMarkerInterfaces)
return JvmClassSignature(
classAsmType.internalName, superClassInfo.type.internalName,
ArrayList(superInterfaces), sw.makeJavaGenericSignature()
)
}
/* Copied with modifications from AsmUtil.getVisibilityAccessFlagForClass */
/*
Use this method to get visibility flag for class to define it in byte code (v.defineClass method).
For other cases use getVisibilityAccessFlag(MemberDescriptor descriptor)
Classes in byte code should be public or package private
*/
fun IrClass.getVisibilityAccessFlagForClass(): Int {
/* Original had a check for SyntheticClassDescriptorForJava, never invoked in th IR backend. */
if (isOptionalAnnotationClass()) {
return AsmUtil.NO_FLAG_PACKAGE_PRIVATE
}
if (kind == ClassKind.ENUM_ENTRY) {
return AsmUtil.NO_FLAG_PACKAGE_PRIVATE
}
return if (visibility === Visibilities.PUBLIC ||
visibility === Visibilities.PROTECTED ||
// TODO: should be package private, but for now Kotlin's reflection can't access members of such classes
visibility === Visibilities.LOCAL ||
visibility === Visibilities.INTERNAL
) {
Opcodes.ACC_PUBLIC
} else AsmUtil.NO_FLAG_PACKAGE_PRIVATE
}
/* Borrowed and translated from ExpectedActualDeclarationChecker */
// TODO: Descriptor-based code also checks for `descriptor.isExpect`; we don't represent expect/actual distinction in IR thus far.
fun IrClass.isOptionalAnnotationClass(): Boolean =
isAnnotationClass &&
hasAnnotation(ExpectedActualDeclarationChecker.OPTIONAL_EXPECTATION_FQ_NAME)
//@JvmOverloads
//fun OtherOriginForIr(element: PsiElement?, descriptor: DeclarationDescriptor? = null) =
// if (element == null && descriptor == null)
// JvmDeclarationOrigin.NO_ORIGIN
// else
// object : JvmDeclarationOrigin(JvmDeclarationOriginKind.OTHER, element, descriptor) {
// override val element get() =
// error("Access to PsiElement")
// override val descriptor get() =
// error("Access to descriptor")
// }
// JvmDeclarationOrigin(OTHER, element, descriptor)
@@ -18,21 +18,23 @@ package org.jetbrains.kotlin.backend.jvm.intrinsics
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.codegen.AsmUtil import org.jetbrains.kotlin.codegen.AsmUtil
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression
import org.jetbrains.kotlin.ir.expressions.IrMemberAccessExpression
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
object ArrayIterator : IntrinsicMethod() { object ArrayIterator : IntrinsicMethod() {
override fun toCallable(expression: IrFunctionAccessExpression, signature: JvmMethodSignature, context: JvmBackendContext): IrIntrinsicFunction { override fun toCallable(
val method = context.state.typeMapper.mapToCallableMethod(expression.descriptor as FunctionDescriptor, false) expression: IrFunctionAccessExpression,
signature: JvmMethodSignature,
context: JvmBackendContext
): IrIntrinsicFunction {
val method = context.state.typeMapper.mapToCallableMethod(expression.descriptor, false)
return IrIntrinsicFunction.create(expression, signature, context, method.owner) { return IrIntrinsicFunction.create(expression, signature, context, method.owner) {
val methodSignature = "(${method.owner.descriptor})${method.returnType.descriptor}" val methodSignature = "(${method.owner.descriptor})${method.returnType.descriptor}"
val intrinsicOwner = val intrinsicOwner =
if (AsmUtil.isPrimitive(method.owner.elementType)) if (AsmUtil.isPrimitive(method.owner.elementType))
"kotlin/jvm/internal/ArrayIteratorsKt" "kotlin/jvm/internal/ArrayIteratorsKt"
else else
"kotlin/jvm/internal/ArrayIteratorKt" "kotlin/jvm/internal/ArrayIteratorKt"
it.invokestatic(intrinsicOwner, "iterator", methodSignature, false) it.invokestatic(intrinsicOwner, "iterator", methodSignature, false)
} }
} }
@@ -88,7 +88,7 @@ class PrimitiveComparison(
private val operatorToken: KtSingleValueToken private val operatorToken: KtSingleValueToken
) : IntrinsicMethod() { ) : IntrinsicMethod() {
override fun invoke(expression: IrFunctionAccessExpression, codegen: ExpressionCodegen, data: BlockInfo): PromisedValue? { override fun invoke(expression: IrFunctionAccessExpression, codegen: ExpressionCodegen, data: BlockInfo): PromisedValue? {
val parameterType = codegen.typeMapper.mapType(primitiveNumberType) val parameterType = codegen.typeMapper.kotlinTypeMapper.mapType(primitiveNumberType)
val (left, right) = expression.receiverAndArgs() val (left, right) = expression.receiverAndArgs()
val a = left.accept(codegen, data).coerce(parameterType).materialized val a = left.accept(codegen, data).coerce(parameterType).materialized
val b = right.accept(codegen, data).coerce(parameterType).materialized val b = right.accept(codegen, data).coerce(parameterType).materialized
@@ -26,7 +26,7 @@ abstract class IntrinsicMethod {
open fun invoke(expression: IrFunctionAccessExpression, codegen: ExpressionCodegen, data: BlockInfo): PromisedValue? = open fun invoke(expression: IrFunctionAccessExpression, codegen: ExpressionCodegen, data: BlockInfo): PromisedValue? =
with(codegen) { with(codegen) {
val descriptor = typeMapper.mapSignatureSkipGeneric(expression.descriptor) val descriptor = typeMapper.mapSignatureSkipGeneric(expression.symbol.owner)
val stackValue = toCallable(expression, descriptor, context).invoke(mv, codegen, data) val stackValue = toCallable(expression, descriptor, context).invoke(mv, codegen, data)
return object : PromisedValue(mv, stackValue.type) { return object : PromisedValue(mv, stackValue.type) {
override fun materialize() = stackValue.put(mv) override fun materialize() = stackValue.put(mv)
@@ -21,24 +21,26 @@ import org.jetbrains.kotlin.backend.jvm.codegen.BlockInfo
import org.jetbrains.kotlin.backend.jvm.codegen.ExpressionCodegen import org.jetbrains.kotlin.backend.jvm.codegen.ExpressionCodegen
import org.jetbrains.kotlin.codegen.OwnerKind import org.jetbrains.kotlin.codegen.OwnerKind
import org.jetbrains.kotlin.codegen.StackValue import org.jetbrains.kotlin.codegen.StackValue
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression
import org.jetbrains.kotlin.ir.expressions.IrMemberAccessExpression
import org.jetbrains.kotlin.resolve.jvm.AsmTypes import org.jetbrains.kotlin.resolve.jvm.AsmTypes
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
object IrEnumValueOf : IntrinsicMethod() { object IrEnumValueOf : IntrinsicMethod() {
override fun toCallable(expression: IrFunctionAccessExpression, signature: JvmMethodSignature, context: JvmBackendContext): IrIntrinsicFunction { override fun toCallable(
expression: IrFunctionAccessExpression,
signature: JvmMethodSignature,
context: JvmBackendContext
): IrIntrinsicFunction {
val enumType = context.state.typeMapper.mapType(expression.descriptor.returnType!!) val enumType = context.state.typeMapper.mapType(expression.descriptor.returnType!!)
val newSignature = context.state.typeMapper.mapSignatureSkipGeneric(expression.descriptor as FunctionDescriptor, OwnerKind.IMPLEMENTATION) val newSignature = context.state.typeMapper.mapSignatureSkipGeneric(expression.descriptor, OwnerKind.IMPLEMENTATION)
val stringType = AsmTypes.JAVA_STRING_TYPE; val stringType = AsmTypes.JAVA_STRING_TYPE
return object : IrIntrinsicFunction(expression, newSignature, context, listOf(stringType)) { return object : IrIntrinsicFunction(expression, newSignature, context, listOf(stringType)) {
override fun invoke(v: InstructionAdapter, codegen: ExpressionCodegen, data: BlockInfo): StackValue { override fun invoke(v: InstructionAdapter, codegen: ExpressionCodegen, data: BlockInfo): StackValue {
v.tconst(enumType) v.tconst(enumType)
codegen.gen(expression.getValueArgument(0)!!, stringType, data) codegen.gen(expression.getValueArgument(0)!!, stringType, data)
v.invokestatic("java/lang/Enum", "valueOf", "(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;", false); v.invokestatic("java/lang/Enum", "valueOf", "(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;", false)
v.checkcast(enumType) v.checkcast(enumType)
return StackValue.onStack(enumType) return StackValue.onStack(enumType)
} }
@@ -11,9 +11,8 @@ import org.jetbrains.kotlin.backend.jvm.codegen.ExpressionCodegen
import org.jetbrains.kotlin.codegen.AsmUtil import org.jetbrains.kotlin.codegen.AsmUtil
import org.jetbrains.kotlin.codegen.Callable import org.jetbrains.kotlin.codegen.Callable
import org.jetbrains.kotlin.codegen.StackValue import org.jetbrains.kotlin.codegen.StackValue
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrMemberAccessExpression import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression
import org.jetbrains.kotlin.ir.types.toKotlinType import org.jetbrains.kotlin.ir.types.toKotlinType
import org.jetbrains.kotlin.resolve.calls.components.isVararg import org.jetbrains.kotlin.resolve.calls.components.isVararg
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
@@ -23,7 +22,7 @@ import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
import java.util.* import java.util.*
open class IrIntrinsicFunction( open class IrIntrinsicFunction(
val expression: IrMemberAccessExpression, val expression: IrFunctionAccessExpression,
val signature: JvmMethodSignature, val signature: JvmMethodSignature,
val context: JvmBackendContext, val context: JvmBackendContext,
val argsTypes: List<Type> = expression.argTypes(context) val argsTypes: List<Type> = expression.argTypes(context)
@@ -80,7 +79,7 @@ open class IrIntrinsicFunction(
argument != null -> argument != null ->
genArg(argument, codegen, i + offset, data) genArg(argument, codegen, i + offset, data)
descriptor.isVararg -> { descriptor.isVararg -> {
val parameterType = codegen.typeMapper.mapType(descriptor.type) val parameterType = codegen.typeMapper.kotlinTypeMapper.mapType(descriptor.type)
StackValue.operation(parameterType) { StackValue.operation(parameterType) {
it.aconst(0) it.aconst(0)
it.newarray(AsmUtil.correctElementType(parameterType)) it.newarray(AsmUtil.correctElementType(parameterType))
@@ -98,7 +97,7 @@ open class IrIntrinsicFunction(
companion object { companion object {
fun create( fun create(
expression: IrMemberAccessExpression, expression: IrFunctionAccessExpression,
signature: JvmMethodSignature, signature: JvmMethodSignature,
context: JvmBackendContext, context: JvmBackendContext,
argsTypes: List<Type> = expression.argTypes(context), argsTypes: List<Type> = expression.argTypes(context),
@@ -111,7 +110,7 @@ open class IrIntrinsicFunction(
} }
fun createWithResult( fun createWithResult(
expression: IrMemberAccessExpression, signature: JvmMethodSignature, expression: IrFunctionAccessExpression, signature: JvmMethodSignature,
context: JvmBackendContext, context: JvmBackendContext,
argsTypes: List<Type> = expression.argTypes(context), argsTypes: List<Type> = expression.argTypes(context),
invokeInstruction: IrIntrinsicFunction.(InstructionAdapter) -> Type invokeInstruction: IrIntrinsicFunction.(InstructionAdapter) -> Type
@@ -123,7 +122,7 @@ open class IrIntrinsicFunction(
} }
fun create( fun create(
expression: IrMemberAccessExpression, expression: IrFunctionAccessExpression,
signature: JvmMethodSignature, signature: JvmMethodSignature,
context: JvmBackendContext, context: JvmBackendContext,
type: Type, type: Type,
@@ -134,17 +133,17 @@ open class IrIntrinsicFunction(
} }
} }
fun IrMemberAccessExpression.argTypes(context: JvmBackendContext): ArrayList<Type> { fun IrFunctionAccessExpression.argTypes(context: JvmBackendContext): ArrayList<Type> {
val callableMethod = context.state.typeMapper.mapToCallableMethod(descriptor as FunctionDescriptor, false) val callableMethod = context.state.typeMapper.mapToCallableMethod(descriptor, false)
return arrayListOf<Type>().apply { return arrayListOf<Type>().apply {
callableMethod.dispatchReceiverType?.let { add(it) } callableMethod.dispatchReceiverType?.let { add(it) }
addAll(callableMethod.getAsmMethod().argumentTypes) addAll(callableMethod.getAsmMethod().argumentTypes)
} }
} }
fun IrMemberAccessExpression.receiverAndArgs(): List<IrExpression> { fun IrFunctionAccessExpression.receiverAndArgs(): List<IrExpression> {
return (arrayListOf(this.dispatchReceiver, this.extensionReceiver) + return (arrayListOf(this.dispatchReceiver, this.extensionReceiver) +
descriptor.valueParameters.mapIndexed { i, _ -> getValueArgument(i) }).filterNotNull() symbol.owner.valueParameters.mapIndexed { i, _ -> getValueArgument(i) }).filterNotNull()
} }
fun List<IrExpression>.asmTypes(context: JvmBackendContext): List<Type> { fun List<IrExpression>.asmTypes(context: JvmBackendContext): List<Type> {
@@ -17,6 +17,7 @@
package org.jetbrains.kotlin.backend.jvm.intrinsics package org.jetbrains.kotlin.backend.jvm.intrinsics
import org.jetbrains.kotlin.backend.jvm.JvmSymbols import org.jetbrains.kotlin.backend.jvm.JvmSymbols
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.builtins.PrimitiveType import org.jetbrains.kotlin.builtins.PrimitiveType
import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrPackageFragment import org.jetbrains.kotlin.ir.declarations.IrPackageFragment
@@ -26,8 +27,8 @@ import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.ir.types.IrSimpleType
import org.jetbrains.kotlin.ir.types.classOrNull import org.jetbrains.kotlin.ir.types.classOrNull
import org.jetbrains.kotlin.ir.types.classifierOrNull
import org.jetbrains.kotlin.ir.util.constructors import org.jetbrains.kotlin.ir.util.constructors
import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable
import org.jetbrains.kotlin.ir.util.functions import org.jetbrains.kotlin.ir.util.functions
@@ -43,18 +44,64 @@ import org.jetbrains.org.objectweb.asm.Type
class IrIntrinsicMethods(val irBuiltIns: IrBuiltIns, val symbols: JvmSymbols) { class IrIntrinsicMethods(val irBuiltIns: IrBuiltIns, val symbols: JvmSymbols) {
private val KOTLIN_INTERNAL_IR = FqName("kotlin.internal.ir")
private val KOTLIN_JVM = FqName("kotlin.jvm")
private val KOTLIN_JVM_INTERNAL_UNSAFE = FqName("kotlin.jvm.internal.unsafe")
val andandSymbol = irBuiltIns.run { defineOperator(OperatorNames.ANDAND, bool, listOf(bool, bool)) } val andandSymbol = irBuiltIns.run { defineOperator(OperatorNames.ANDAND, bool, listOf(bool, bool)) }
private val intrinsicsMap = ( private val intrinsicsMap = (
listOf( listOf(
symbols.javaClassProperty.owner.getter!!.symbol.toKey() to JavaClassProperty, Key(KOTLIN_JVM, FqName("T"),"<get-javaClass>", emptyList()) to JavaClassProperty,
symbols.kClassJavaProperty.owner.getter!!.symbol.toKey() to KClassJavaProperty, Key(
symbols.monitorEnter.toKey() to MonitorInstruction.MONITOR_ENTER, KOTLIN_JVM,
symbols.monitorExit.toKey() to MonitorInstruction.MONITOR_EXIT, KotlinBuiltIns.FQ_NAMES.kClass.toSafe(),
symbols.isArrayOf.toKey() to IsArrayOf, "<get-java>",
emptyList()
) to KClassJavaProperty,
Key(
KOTLIN_JVM_INTERNAL_UNSAFE,
null,
"monitorEnter",
listOf(KotlinBuiltIns.FQ_NAMES.any.toSafe())
) to MonitorInstruction.MONITOR_ENTER,
Key(
KOTLIN_JVM_INTERNAL_UNSAFE,
null,
"monitorExit",
listOf(KotlinBuiltIns.FQ_NAMES.any.toSafe())
) to MonitorInstruction.MONITOR_EXIT,
Key(
KOTLIN_JVM,
KotlinBuiltIns.FQ_NAMES.array.toSafe(),
"isArrayOf",
emptyList()
) to IsArrayOf,
symbols.arrayOf.toKey() to ArrayOf, symbols.arrayOf.toKey() to ArrayOf,
symbols.extensionToString.toKey() to ToString, Key(
symbols.arrayOfNulls.toKey() to NewArray, KotlinBuiltIns.BUILT_INS_PACKAGE_FQ_NAME,
KotlinBuiltIns.FQ_NAMES.any.toSafe(),
"toString",
emptyList()
) to ToString,
Key(
KotlinBuiltIns.BUILT_INS_PACKAGE_FQ_NAME,
null,
"arrayOfNulls",
listOf(KotlinBuiltIns.FQ_NAMES._int.toSafe())
) to NewArray,
Key(
KotlinBuiltIns.FQ_NAMES.cloneable.toSafe(),
null,
"clone",
emptyList()
) to Clone,
Key(
KOTLIN_INTERNAL_IR,
null,
OperatorNames.ANDAND,
listOf(KotlinBuiltIns.FQ_NAMES._boolean.toSafe(), KotlinBuiltIns.FQ_NAMES._boolean.toSafe())
) to AndAnd,
irBuiltIns.eqeqSymbol.toKey()!! to Equals(KtTokens.EQEQ), irBuiltIns.eqeqSymbol.toKey()!! to Equals(KtTokens.EQEQ),
irBuiltIns.eqeqeqSymbol.toKey()!! to Equals(KtTokens.EQEQEQ), irBuiltIns.eqeqeqSymbol.toKey()!! to Equals(KtTokens.EQEQEQ),
irBuiltIns.ieee754equalsFunByOperandType[irBuiltIns.float]!!.toKey()!! to Ieee754Equals(Type.FLOAT_TYPE), irBuiltIns.ieee754equalsFunByOperandType[irBuiltIns.float]!!.toKey()!! to Ieee754Equals(Type.FLOAT_TYPE),
@@ -63,8 +110,7 @@ class IrIntrinsicMethods(val irBuiltIns: IrBuiltIns, val symbols: JvmSymbols) {
irBuiltIns.enumValueOfSymbol.toKey()!! to IrEnumValueOf, irBuiltIns.enumValueOfSymbol.toKey()!! to IrEnumValueOf,
irBuiltIns.noWhenBranchMatchedExceptionSymbol.toKey()!! to IrNoWhenBranchMatchedException, irBuiltIns.noWhenBranchMatchedExceptionSymbol.toKey()!! to IrNoWhenBranchMatchedException,
irBuiltIns.illegalArgumentExceptionSymbol.toKey()!! to IrIllegalArgumentException, irBuiltIns.illegalArgumentExceptionSymbol.toKey()!! to IrIllegalArgumentException,
irBuiltIns.throwNpeSymbol.toKey()!! to ThrowNPE, irBuiltIns.throwNpeSymbol.toKey()!! to ThrowNPE
andandSymbol.toKey() to AndAnd
) + ) +
numberConversionMethods() + numberConversionMethods() +
unaryFunForPrimitives("plus", UnaryPlus) + unaryFunForPrimitives("plus", UnaryPlus) +
@@ -94,7 +140,6 @@ class IrIntrinsicMethods(val irBuiltIns: IrBuiltIns, val symbols: JvmSymbols) {
binaryFunForPrimitives("compareTo", CompareTo) + binaryFunForPrimitives("compareTo", CompareTo) +
methodWithArity(irBuiltIns.booleanClass, "not", 0, Not) + methodWithArity(irBuiltIns.booleanClass, "not", 0, Not) +
methodWithArity(irBuiltIns.stringClass, "get", 1, StringGetChar) + methodWithArity(irBuiltIns.stringClass, "get", 1, StringGetChar) +
methodWithArity(symbols.cloneable, "clone", 0, Clone) +
symbols.primitiveIteratorsByType.values.flatMap { iteratorClass -> symbols.primitiveIteratorsByType.values.flatMap { iteratorClass ->
methodWithArity(iteratorClass, "next", 0, IteratorNext) methodWithArity(iteratorClass, "next", 0, IteratorNext)
} + } +
@@ -147,7 +192,7 @@ class IrIntrinsicMethods(val irBuiltIns: IrBuiltIns, val symbols: JvmSymbols) {
} }
private fun getParameterFqName(parameter: IrValueParameter?): FqName? = private fun getParameterFqName(parameter: IrValueParameter?): FqName? =
parameter?.type?.safeAs<IrSimpleType>()?.classifier?.owner?.let { parameter?.type?.classifierOrNull?.owner?.let {
when (it) { when (it) {
is IrClass -> it.fqNameWhenAvailable is IrClass -> it.fqNameWhenAvailable
is IrTypeParameter -> FqName(it.name.asString()) is IrTypeParameter -> FqName(it.name.asString())
@@ -10,7 +10,6 @@ import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.backend.jvm.codegen.ExpressionCodegen import org.jetbrains.kotlin.backend.jvm.codegen.ExpressionCodegen
import org.jetbrains.kotlin.codegen.StackValue import org.jetbrains.kotlin.codegen.StackValue
import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression
import org.jetbrains.kotlin.ir.types.toKotlinType
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
@@ -21,11 +20,11 @@ object NewArray : IntrinsicMethod() {
signature: JvmMethodSignature, signature: JvmMethodSignature,
context: JvmBackendContext context: JvmBackendContext
): IrIntrinsicFunction { ): IrIntrinsicFunction {
val ktType = expression.type val irType = expression.type
return object : IrIntrinsicFunction(expression, signature, context) { return object : IrIntrinsicFunction(expression, signature, context) {
override fun invoke(v: InstructionAdapter, codegen: ExpressionCodegen, data: BlockInfo): StackValue { override fun invoke(v: InstructionAdapter, codegen: ExpressionCodegen, data: BlockInfo): StackValue {
super.invoke(v, codegen, data) super.invoke(v, codegen, data)
codegen.newArrayInstruction(ktType.toKotlinType()) codegen.newArrayInstruction(irType)
return StackValue.onStack(returnType) return StackValue.onStack(returnType)
} }
@@ -44,7 +44,6 @@ import org.jetbrains.kotlin.ir.builders.declarations.buildFun
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.* import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
import org.jetbrains.kotlin.ir.symbols.IrValueParameterSymbol import org.jetbrains.kotlin.ir.symbols.IrValueParameterSymbol
import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
@@ -109,7 +108,7 @@ internal class CallableReferenceLowering(val context: JvmBackendContext) : FileL
val vararg = IrVarargImpl( val vararg = IrVarargImpl(
UNDEFINED_OFFSET, UNDEFINED_OFFSET, UNDEFINED_OFFSET, UNDEFINED_OFFSET,
context.ir.symbols.array.typeWith(context.irBuiltIns.anyNType), context.ir.symbols.array.typeWith(context.irBuiltIns.anyNType),
context.irBuiltIns.anyClass.typeWith(), context.irBuiltIns.anyNType,
(0 until argumentsCount).map { i -> expression.getValueArgument(i)!! } (0 until argumentsCount).map { i -> expression.getValueArgument(i)!! }
) )
val invokeFun = context.ir.symbols.functionN.owner.declarations.single { val invokeFun = context.ir.symbols.functionN.owner.declarations.single {
@@ -596,26 +595,3 @@ internal class CallableReferenceLowering(val context: JvmBackendContext) : FileL
const val MAX_ARGCOUNT_WITHOUT_VARARG = 22 const val MAX_ARGCOUNT_WITHOUT_VARARG = 22
} }
} }
// TODO: Move to IrUtils
private fun IrType.substitute(substitutionMap: Map<IrTypeParameterSymbol, IrType>): IrType {
if (this !is IrSimpleType) return this
substitutionMap[classifier]?.let { return it }
val newArguments = arguments.map {
if (it is IrTypeProjection) {
makeTypeProjection(it.type.substitute(substitutionMap), it.variance)
} else {
it
}
}
val newAnnotations = annotations.map { it.deepCopyWithSymbols() }
return IrSimpleTypeImpl(
classifier,
hasQuestionMark,
newArguments,
newAnnotations
)
}
@@ -28,6 +28,7 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.resolve.source.PsiSourceElement import org.jetbrains.kotlin.resolve.source.PsiSourceElement
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
import org.jetbrains.kotlin.utils.DFS
/** /**
* Binds the arguments explicitly represented in the IR to the parameters of the accessed function. * Binds the arguments explicitly represented in the IR to the parameters of the accessed function.
@@ -281,6 +282,7 @@ val IrClass.isEnumEntry get() = kind == ClassKind.ENUM_ENTRY
val IrClass.isInterface get() = kind == ClassKind.INTERFACE val IrClass.isInterface get() = kind == ClassKind.INTERFACE
val IrClass.isClass get() = kind == ClassKind.CLASS val IrClass.isClass get() = kind == ClassKind.CLASS
val IrClass.isObject get() = kind == ClassKind.OBJECT val IrClass.isObject get() = kind == ClassKind.OBJECT
val IrClass.isAnonymousObject get() = isClass && name == SpecialNames.NO_NAME_PROVIDED
val IrDeclarationWithName.fqNameWhenAvailable: FqName? val IrDeclarationWithName.fqNameWhenAvailable: FqName?
get() = when (val parent = parent) { get() = when (val parent = parent) {
is IrDeclarationWithName -> parent.fqNameWhenAvailable?.child(name) is IrDeclarationWithName -> parent.fqNameWhenAvailable?.child(name)
@@ -352,6 +354,12 @@ inline fun <reified T : IrDeclaration> IrDeclarationContainer.findDeclaration(pr
inline fun <reified T : IrDeclaration> IrDeclarationContainer.filterDeclarations(predicate: (T) -> Boolean): List<T> = inline fun <reified T : IrDeclaration> IrDeclarationContainer.filterDeclarations(predicate: (T) -> Boolean): List<T> =
declarations.filter { it is T && predicate(it) } as List<T> declarations.filter { it is T && predicate(it) } as List<T>
fun IrValueParameter.hasDefaultValue(): Boolean = DFS.ifAny(
listOf(this),
{ current -> (current.parent as? IrSimpleFunction)?.overriddenSymbols?.map { it.owner.valueParameters[current.index] } ?: listOf() },
{ current -> current.defaultValue != null }
)
fun IrValueParameter.copy(newDescriptor: ParameterDescriptor): IrValueParameter { fun IrValueParameter.copy(newDescriptor: ParameterDescriptor): IrValueParameter {
assert(this.descriptor.type == newDescriptor.type) assert(this.descriptor.type == newDescriptor.type)
@@ -1,3 +1,5 @@
// IGNORE_BACKEND: JVM_IR
// For JVM_IR, NewInference is needed because of KT-26531. See functionExpressionWithThisReferenceNI.kt
fun Int.thisRef1() = fun () = this fun Int.thisRef1() = fun () = this
fun Int.thisRef2() = fun (): Int {return this} fun Int.thisRef2() = fun (): Int {return this}
@@ -0,0 +1,36 @@
// !LANGUAGE: +NewInference
// NewInference needed because of KT-26531
fun Int.thisRef1() = fun () = this
fun Int.thisRef2() = fun (): Int {return this}
fun <T> T.genericThisRef1() = fun () = this
fun <T> T.genericThisRef2() = fun (): T {return this}
val Int.valThisRef1: () -> Int get() = fun () = this
val Int.valThisRef2: () -> Int get() = fun (): Int {return this}
val <T> T.valGenericThisRef1: ()->T get() = fun () = this
val <T> T.valGenericThisRef2: ()->T get() = fun (): T {return this}
val <T> T.withLabel1: ()->T get() = fun () = this@withLabel1
val <T> T.withLabel2: ()->T get() = fun (): T {return this@withLabel2}
fun box(): String {
if (1.thisRef1()() != 1) return "Test 1 failed"
if (2.thisRef2()() != 2) return "Test 2 failed"
if (3.genericThisRef1()() != 3) return "Test 3 failed"
if (4.genericThisRef2()() != 4) return "Test 4 failed"
if (5.valThisRef1() != 5) return "Test 5 failed"
if (6.valThisRef2() != 6) return "Test 6 failed"
if (7.valGenericThisRef1() != 7) return "Test 7 failed"
if (8.valGenericThisRef2() != 8) return "Test 8 failed"
if ("bar".withLabel1() != "bar") return "Test 9 failed"
if ("bar".withLabel2() != "bar") return "Test 10 failed"
return "OK"
}
+1 -1
View File
@@ -1,5 +1,5 @@
// !USE_EXPERIMENTAL: kotlin.ExperimentalStdlibApi // !USE_EXPERIMENTAL: kotlin.ExperimentalStdlibApi
// IGNORE_BACKEND: JS, JS_IR, NATIVE // IGNORE_BACKEND: JS, JS_IR, NATIVE, JVM_IR
// WITH_REFLECT // WITH_REFLECT
package test package test
@@ -0,0 +1,41 @@
// !USE_EXPERIMENTAL: kotlin.ExperimentalStdlibApi
// TARGET_BACKEND: JVM_IR
// WITH_REFLECT
package test
import kotlin.reflect.KType
import kotlin.reflect.typeOf
import kotlin.test.assertEquals
class C
fun check(expected: String, actual: KType) {
assertEquals(expected, actual.toString())
}
fun box(): String {
check("kotlin.Any", typeOf<Any>())
check("kotlin.String", typeOf<String>())
check("kotlin.String?", typeOf<String?>())
check("kotlin.Unit", typeOf<Unit>())
check("test.C", typeOf<C>())
check("test.C?", typeOf<C?>())
check("kotlin.collections.List<kotlin.String>", typeOf<List<String>>())
check("kotlin.collections.Map<in kotlin.Number, *>?", typeOf<Map<in Number, *>?>())
check("kotlin.Enum<*>", typeOf<Enum<*>>())
check("kotlin.Enum<kotlin.annotation.AnnotationRetention>", typeOf<Enum<AnnotationRetention>>())
check("kotlin.Array<kotlin.Any>", typeOf<Array<Any>>())
check("kotlin.Array<*>", typeOf<Array<*>>())
check("kotlin.Array<kotlin.IntArray>", typeOf<Array<IntArray>>())
check("kotlin.Array<in kotlin.Array<test.C>?>", typeOf<Array<in Array<C>?>>())
check("kotlin.Int", typeOf<Int>())
check("kotlin.Int?", typeOf<Int?>())
check("kotlin.Boolean", typeOf<Boolean>())
return "OK"
}
@@ -1,5 +1,6 @@
// !USE_EXPERIMENTAL: kotlin.ExperimentalStdlibApi // !USE_EXPERIMENTAL: kotlin.ExperimentalStdlibApi
// TARGET_BACKEND: JVM // TARGET_BACKEND: JVM
// IGNORE_BACKEND: JVM_IR
// WITH_RUNTIME // WITH_RUNTIME
package test package test
@@ -0,0 +1,42 @@
// !USE_EXPERIMENTAL: kotlin.ExperimentalStdlibApi
// TARGET_BACKEND: JVM_IR
// WITH_RUNTIME
// Separate test is needed for IR because type arguments of typeOf are computed differently.
package test
import kotlin.reflect.KType
import kotlin.reflect.typeOf
import kotlin.test.assertEquals
class C
fun check(expected: String, actual: KType) {
assertEquals(expected + " (Kotlin reflection is not available)", actual.toString())
}
fun box(): String {
check("java.lang.Object", typeOf<Any>())
check("java.lang.String", typeOf<String>())
check("java.lang.String?", typeOf<String?>())
check("kotlin.Unit", typeOf<Unit>())
check("test.C", typeOf<C>())
check("test.C?", typeOf<C?>())
check("java.util.List<java.lang.String>", typeOf<List<String>>())
check("java.util.Map<in java.lang.Number, *>?", typeOf<Map<in Number, *>?>())
check("java.lang.Enum<*>", typeOf<Enum<*>>())
check("java.lang.Enum<kotlin.annotation.AnnotationRetention>", typeOf<Enum<AnnotationRetention>>())
check("kotlin.Array<java.lang.Object>", typeOf<Array<Any>>())
check("kotlin.Array<*>", typeOf<Array<*>>())
check("kotlin.Array<kotlin.IntArray>", typeOf<Array<IntArray>>())
check("kotlin.Array<in kotlin.Array<test.C>?>", typeOf<Array<in Array<C>?>>())
check("int", typeOf<Int>())
check("java.lang.Integer?", typeOf<Int?>())
check("boolean", typeOf<Boolean>())
return "OK"
}
@@ -1,5 +1,6 @@
// !USE_EXPERIMENTAL: kotlin.ExperimentalStdlibApi // !USE_EXPERIMENTAL: kotlin.ExperimentalStdlibApi
// TARGET_BACKEND: JVM // TARGET_BACKEND: JVM
// IGNORE_BACKEND: JVM_IR
// WITH_RUNTIME // WITH_RUNTIME
package test package test
@@ -0,0 +1,55 @@
// !USE_EXPERIMENTAL: kotlin.ExperimentalStdlibApi
// TARGET_BACKEND: JVM_IR
// WITH_RUNTIME
// Separate test is needed for IR because of different ways type arguments of typeOf are calculated.
package test
import kotlin.reflect.KType
import kotlin.reflect.typeOf
class C
fun assertEqual(a: KType, b: KType) {
if (a != b || b != a) throw AssertionError("Fail equals: $a != $b")
if (a.hashCode() != b.hashCode()) throw AssertionError("Fail hashCode: $a != $b")
}
fun assertNotEqual(a: KType, b: KType) {
if (a == b || b == a) throw AssertionError("Fail equals: $a == $b")
}
inline fun <reified A, reified B> equal() {
assertEqual(typeOf<A>(), typeOf<B>())
}
inline fun <reified A, reified B> notEqual() {
assertNotEqual(typeOf<A>(), typeOf<B>())
}
fun box(): String {
equal<Any, Any>()
equal<Any?, Any?>()
equal<String, String>()
equal<C, C>()
equal<C?, C?>()
equal<List<String>, List<String>>()
equal<Enum<AnnotationRetention>, Enum<AnnotationRetention>>()
equal<Array<Any>, Array<Any>>()
equal<Array<IntArray>, Array<IntArray>>()
equal<Array<*>, Array<*>>()
equal<Int, Int>()
equal<Int?, Int?>()
notEqual<Any, Any?>()
notEqual<Any, String>()
notEqual<List<Any>, List<Any?>>()
notEqual<Map<in Number, BooleanArray>, Map<out Number, BooleanArray>>()
notEqual<Array<IntArray>, Array<Array<Int>>>()
return "OK"
}
@@ -1,5 +1,4 @@
// !LANGUAGE: +NewInference // !LANGUAGE: +NewInference
// IGNORE_BACKEND: JVM_IR
class Recursive<T : Recursive<T>> : Generic<PlaceHolder<T>>, MainSupertype class Recursive<T : Recursive<T>> : Generic<PlaceHolder<T>>, MainSupertype
open class Simple<T> : Generic<T>, MainSupertype open class Simple<T> : Generic<T>, MainSupertype
@@ -11261,6 +11261,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
runTest("compiler/testData/codegen/box/functions/functionExpression/functionExpressionWithThisReference.kt"); runTest("compiler/testData/codegen/box/functions/functionExpression/functionExpressionWithThisReference.kt");
} }
@TestMetadata("functionExpressionWithThisReferenceNI.kt")
public void testFunctionExpressionWithThisReferenceNI() throws Exception {
runTest("compiler/testData/codegen/box/functions/functionExpression/functionExpressionWithThisReferenceNI.kt");
}
@TestMetadata("functionLiteralExpression.kt") @TestMetadata("functionLiteralExpression.kt")
public void testFunctionLiteralExpression() throws Exception { public void testFunctionLiteralExpression() throws Exception {
runTest("compiler/testData/codegen/box/functions/functionExpression/functionLiteralExpression.kt"); runTest("compiler/testData/codegen/box/functions/functionExpression/functionLiteralExpression.kt");
@@ -11261,6 +11261,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
runTest("compiler/testData/codegen/box/functions/functionExpression/functionExpressionWithThisReference.kt"); runTest("compiler/testData/codegen/box/functions/functionExpression/functionExpressionWithThisReference.kt");
} }
@TestMetadata("functionExpressionWithThisReferenceNI.kt")
public void testFunctionExpressionWithThisReferenceNI() throws Exception {
runTest("compiler/testData/codegen/box/functions/functionExpression/functionExpressionWithThisReferenceNI.kt");
}
@TestMetadata("functionLiteralExpression.kt") @TestMetadata("functionLiteralExpression.kt")
public void testFunctionLiteralExpression() throws Exception { public void testFunctionLiteralExpression() throws Exception {
runTest("compiler/testData/codegen/box/functions/functionExpression/functionLiteralExpression.kt"); runTest("compiler/testData/codegen/box/functions/functionExpression/functionLiteralExpression.kt");
@@ -11266,6 +11266,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTest("compiler/testData/codegen/box/functions/functionExpression/functionExpressionWithThisReference.kt"); runTest("compiler/testData/codegen/box/functions/functionExpression/functionExpressionWithThisReference.kt");
} }
@TestMetadata("functionExpressionWithThisReferenceNI.kt")
public void testFunctionExpressionWithThisReferenceNI() throws Exception {
runTest("compiler/testData/codegen/box/functions/functionExpression/functionExpressionWithThisReferenceNI.kt");
}
@TestMetadata("functionLiteralExpression.kt") @TestMetadata("functionLiteralExpression.kt")
public void testFunctionLiteralExpression() throws Exception { public void testFunctionLiteralExpression() throws Exception {
runTest("compiler/testData/codegen/box/functions/functionExpression/functionLiteralExpression.kt"); runTest("compiler/testData/codegen/box/functions/functionExpression/functionLiteralExpression.kt");
@@ -21724,6 +21729,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTest("compiler/testData/codegen/box/reflection/typeOf/classes.kt"); runTest("compiler/testData/codegen/box/reflection/typeOf/classes.kt");
} }
@TestMetadata("classesIR.kt")
public void testClassesIR() throws Exception {
runTest("compiler/testData/codegen/box/reflection/typeOf/classesIR.kt");
}
@TestMetadata("inlineClasses.kt") @TestMetadata("inlineClasses.kt")
public void testInlineClasses() throws Exception { public void testInlineClasses() throws Exception {
runTest("compiler/testData/codegen/box/reflection/typeOf/inlineClasses.kt"); runTest("compiler/testData/codegen/box/reflection/typeOf/inlineClasses.kt");
@@ -21756,6 +21766,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTest("compiler/testData/codegen/box/reflection/typeOf/noReflect/classes.kt"); runTest("compiler/testData/codegen/box/reflection/typeOf/noReflect/classes.kt");
} }
@TestMetadata("classesIR.kt")
public void testClassesIR() throws Exception {
runTest("compiler/testData/codegen/box/reflection/typeOf/noReflect/classesIR.kt");
}
@TestMetadata("inlineClasses.kt") @TestMetadata("inlineClasses.kt")
public void testInlineClasses() throws Exception { public void testInlineClasses() throws Exception {
runTest("compiler/testData/codegen/box/reflection/typeOf/noReflect/inlineClasses.kt"); runTest("compiler/testData/codegen/box/reflection/typeOf/noReflect/inlineClasses.kt");
@@ -21765,6 +21780,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
public void testTypeReferenceEqualsHashCode() throws Exception { public void testTypeReferenceEqualsHashCode() throws Exception {
runTest("compiler/testData/codegen/box/reflection/typeOf/noReflect/typeReferenceEqualsHashCode.kt"); runTest("compiler/testData/codegen/box/reflection/typeOf/noReflect/typeReferenceEqualsHashCode.kt");
} }
@TestMetadata("typeReferenceEqualsHashCodeIR.kt")
public void testTypeReferenceEqualsHashCodeIR() throws Exception {
runTest("compiler/testData/codegen/box/reflection/typeOf/noReflect/typeReferenceEqualsHashCodeIR.kt");
}
} }
} }
@@ -8816,6 +8816,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/functions/functionExpression/functionExpressionWithThisReference.kt"); runTest("compiler/testData/codegen/box/functions/functionExpression/functionExpressionWithThisReference.kt");
} }
@TestMetadata("functionExpressionWithThisReferenceNI.kt")
public void testFunctionExpressionWithThisReferenceNI() throws Exception {
runTest("compiler/testData/codegen/box/functions/functionExpression/functionExpressionWithThisReferenceNI.kt");
}
@TestMetadata("functionLiteralExpression.kt") @TestMetadata("functionLiteralExpression.kt")
public void testFunctionLiteralExpression() throws Exception { public void testFunctionLiteralExpression() throws Exception {
runTest("compiler/testData/codegen/box/functions/functionExpression/functionLiteralExpression.kt"); runTest("compiler/testData/codegen/box/functions/functionExpression/functionLiteralExpression.kt");
@@ -9891,6 +9891,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/functions/functionExpression/functionExpressionWithThisReference.kt"); runTest("compiler/testData/codegen/box/functions/functionExpression/functionExpressionWithThisReference.kt");
} }
@TestMetadata("functionExpressionWithThisReferenceNI.kt")
public void testFunctionExpressionWithThisReferenceNI() throws Exception {
runTest("compiler/testData/codegen/box/functions/functionExpression/functionExpressionWithThisReferenceNI.kt");
}
@TestMetadata("functionLiteralExpression.kt") @TestMetadata("functionLiteralExpression.kt")
public void testFunctionLiteralExpression() throws Exception { public void testFunctionLiteralExpression() throws Exception {
runTest("compiler/testData/codegen/box/functions/functionExpression/functionLiteralExpression.kt"); runTest("compiler/testData/codegen/box/functions/functionExpression/functionLiteralExpression.kt");