JVM IR: build all needed stdlib symbols in JvmSymbols manually

This removes the mandatory dependency of all JVM IR tests on
kotlin-stdlib (ConfigurationKind.ALL in all IR test cases) and speeds up
tests which don't need kotiln-stdlib by about 20%. Another advantage of
this method is that all required dependencies are listed in one file,
are easy to grasp, and changes to the related code generation can be
done independently of the corresponding changes in the actual library,
which may help in bootstrapping the compiler
This commit is contained in:
Alexander Udalov
2019-03-26 18:19:16 +01:00
parent 6b7eba485b
commit b32241c967
17 changed files with 448 additions and 138 deletions
@@ -6,11 +6,16 @@
package org.jetbrains.kotlin.ir.builders.declarations
import org.jetbrains.kotlin.backend.common.descriptors.*
import org.jetbrains.kotlin.backend.common.ir.copyTo
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.*
import org.jetbrains.kotlin.ir.symbols.impl.*
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.util.defaultType
import org.jetbrains.kotlin.ir.util.parentAsClass
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.types.Variance
fun IrClassBuilder.buildClass(): IrClass {
val wrappedDescriptor = WrappedClassDescriptor()
@@ -47,6 +52,29 @@ inline fun buildField(b: IrFieldBuilder.() -> Unit) =
buildField()
}
fun IrPropertyBuilder.buildProperty(): IrProperty {
val wrappedDescriptor = WrappedPropertyDescriptor()
return IrPropertyImpl(
startOffset, endOffset, origin,
IrPropertySymbolImpl(wrappedDescriptor),
name, visibility, modality, isVar, isConst, isLateinit, isDelegated, isExternal
).also {
wrappedDescriptor.bind(it)
}
}
inline fun buildProperty(b: IrPropertyBuilder.() -> Unit) =
IrPropertyBuilder().run {
b()
buildProperty()
}
inline fun IrDeclarationContainer.addProperty(b: IrPropertyBuilder.() -> Unit): IrProperty =
buildProperty(b).also { property ->
declarations.add(property)
property.parent = this@addProperty
}
fun IrFunctionBuilder.buildFun(): IrSimpleFunction {
val wrappedDescriptor = WrappedSimpleFunctionDescriptor()
return IrFunctionImpl(
@@ -78,12 +106,43 @@ inline fun buildFun(b: IrFunctionBuilder.() -> Unit): IrSimpleFunction =
buildFun()
}
inline fun IrDeclarationContainer.addFunction(b: IrFunctionBuilder.() -> Unit): IrSimpleFunction =
buildFun(b).also { function ->
declarations.add(function)
function.parent = this@addFunction
}
fun IrDeclarationContainer.addFunction(
name: String,
returnType: IrType,
modality: Modality = Modality.FINAL,
isStatic: Boolean = false
): IrSimpleFunction =
addFunction {
this.name = Name.identifier(name)
this.returnType = returnType
this.modality = modality
}.apply {
if (!isStatic) {
dispatchReceiverParameter = parentAsClass.thisReceiver!!.copyTo(this)
}
}
inline fun buildConstructor(b: IrFunctionBuilder.() -> Unit): IrConstructor =
IrFunctionBuilder().run {
b()
buildConstructor()
}
inline fun IrClass.addConstructor(b: IrFunctionBuilder.() -> Unit = {}): IrConstructor =
buildConstructor {
b()
returnType = defaultType
}.also { constructor ->
declarations.add(constructor)
constructor.parent = this@addConstructor
}
fun IrValueParameterBuilder.build(): IrValueParameter {
val wrappedDescriptor = WrappedValueParameterDescriptor()
return IrValueParameterImpl(
@@ -113,9 +172,40 @@ inline fun IrFunction.addValueParameter(b: IrValueParameterBuilder.() -> Unit):
}
}
fun IrFunction.addValueParameter(name: String, type: IrType, origin: IrDeclarationOrigin): IrValueParameter =
fun IrFunction.addValueParameter(name: String, type: IrType, origin: IrDeclarationOrigin = IrDeclarationOrigin.DEFINED): IrValueParameter =
addValueParameter {
this.name = Name.identifier(name)
this.type = type
this.origin = origin
}
fun IrTypeParameterBuilder.build(): IrTypeParameter {
val wrappedDescriptor = WrappedTypeParameterDescriptor()
return IrTypeParameterImpl(
startOffset, endOffset, origin,
IrTypeParameterSymbolImpl(wrappedDescriptor),
name, index, isReified, variance
).also {
wrappedDescriptor.bind(it)
it.superTypes.addAll(superTypes)
}
}
inline fun IrTypeParametersContainer.addTypeParameter(b: IrTypeParameterBuilder.() -> Unit): IrTypeParameter =
IrTypeParameterBuilder().run {
b()
if (index == UNDEFINED_PARAMETER_INDEX) {
index = typeParameters.size
}
build().also { typeParameter ->
typeParameters.add(typeParameter)
typeParameter.parent = this@addTypeParameter
}
}
fun IrTypeParametersContainer.addTypeParameter(name: String, upperBound: IrType, variance: Variance = Variance.INVARIANT): IrTypeParameter =
addTypeParameter {
this.name = Name.identifier(name)
this.variance = variance
this.superTypes.add(upperBound)
}
@@ -20,7 +20,6 @@ import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.util.SymbolTable
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi2ir.PsiSourceManager
class JvmBackendContext(
@@ -41,20 +40,12 @@ class JvmBackendContext(
override val configuration get() = state.configuration
internal fun getJvmInternalClass(name: String): ClassDescriptor {
return getClass(FqName("kotlin.jvm.internal").child(Name.identifier(name)))
}
internal fun getClass(fqName: FqName): ClassDescriptor {
return state.module.getPackage(fqName.parent()).memberScope.getContributedClassifier(
fqName.shortName(), NoLookupLocation.FROM_BACKEND
) as ClassDescriptor? ?: error("Class is not found: $fqName")
}
fun getIrClass(fqName: FqName): IrClassSymbol {
return ir.symbols.externalSymbolTable.referenceClass(getClass(fqName))
}
override fun log(message: () -> String) {
/*TODO*/
if (inVerbosePhase) {
@@ -6,18 +6,37 @@
package org.jetbrains.kotlin.backend.jvm
import org.jetbrains.kotlin.backend.common.ir.Symbols
import org.jetbrains.kotlin.backend.common.ir.createImplicitParameterDeclarationWithWrappedDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.descriptors.impl.EmptyPackageFragmentDescriptor
import org.jetbrains.kotlin.ir.builders.declarations.*
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
import org.jetbrains.kotlin.ir.declarations.IrPackageFragment
import org.jetbrains.kotlin.ir.declarations.impl.IrExternalPackageFragmentImpl
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.impl.IrExternalPackageFragmentSymbolImpl
import org.jetbrains.kotlin.ir.types.defaultType
import org.jetbrains.kotlin.ir.types.typeWith
import org.jetbrains.kotlin.ir.util.ReferenceSymbolTable
import org.jetbrains.kotlin.ir.util.functions
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.storage.LockBasedStorageManager
import org.jetbrains.kotlin.types.Variance
class JvmSymbols(
context: JvmBackendContext,
private val symbolTable: ReferenceSymbolTable
) : Symbols<JvmBackendContext>(context, symbolTable) {
private val storageManager = LockBasedStorageManager(this::class.java.simpleName)
private val irBuiltIns = context.irBuiltIns
override val ThrowNullPointerException: IrSimpleFunctionSymbol
get() = error("Unused in JVM IR")
@@ -27,19 +46,40 @@ class JvmSymbols(
override val ThrowTypeCastException: IrSimpleFunctionSymbol
get() = error("Unused in JVM IR")
private fun createPackage(fqName: FqName): IrPackageFragment =
IrExternalPackageFragmentImpl(IrExternalPackageFragmentSymbolImpl(EmptyPackageFragmentDescriptor(context.state.module, fqName)))
private val kotlinJvmInternalPackage: IrPackageFragment = createPackage(FqName("kotlin.jvm.internal"))
private val kotlinJvmFunctionsPackage: IrPackageFragment = createPackage(FqName("kotlin.jvm.functions"))
private fun createClass(fqName: FqName, classKind: ClassKind = ClassKind.CLASS, block: (IrClass) -> Unit): IrClass =
buildClass {
name = fqName.shortName()
kind = classKind
}.apply {
parent = when (fqName.parent().asString()) {
"kotlin.jvm.internal" -> kotlinJvmInternalPackage
"kotlin.jvm.functions" -> kotlinJvmFunctionsPackage
else -> error("Other packages are not supported yet: $fqName")
}
createImplicitParameterDeclarationWithWrappedDescriptor()
block(this)
}
private val intrinsicsClass: IrClassSymbol = createClass(FqName("kotlin.jvm.internal.Intrinsics")) { klass ->
klass.addFunction("throwUninitializedPropertyAccessException", irBuiltIns.unitType, isStatic = true).apply {
addValueParameter("propertyName", irBuiltIns.stringType)
}
}.symbol
override val ThrowUninitializedPropertyAccessException: IrSimpleFunctionSymbol =
symbolTable.referenceSimpleFunction(
context.getJvmInternalClass("Intrinsics").staticScope.getContributedFunctions(
Name.identifier("throwUninitializedPropertyAccessException"),
NoLookupLocation.FROM_BACKEND
).single()
)
intrinsicsClass.functions.single { it.owner.name.asString() == "throwUninitializedPropertyAccessException" }
override val stringBuilder: IrClassSymbol
get() = symbolTable.referenceClass(context.getClass(FqName("java.lang.StringBuilder")))
override val defaultConstructorMarker: IrClassSymbol =
symbolTable.referenceClass(context.getJvmInternalClass("DefaultConstructorMarker"))
createClass(FqName("kotlin.jvm.internal.DefaultConstructorMarker")) { }.symbol
override val copyRangeTo: Map<ClassDescriptor, IrSimpleFunctionSymbol>
get() = error("Unused in JVM IR")
@@ -50,13 +90,165 @@ class JvmSymbols(
override val coroutineSuspendedGetter: IrSimpleFunctionSymbol
get() = TODO("not implemented")
val lambdaClass: IrClassSymbol =
symbolTable.referenceClass(context.getJvmInternalClass("Lambda"))
val javaLangClass: IrClassSymbol =
symbolTable.referenceClass(context.getClass(FqName("java.lang.Class")))
val functionReference: IrClassSymbol =
symbolTable.referenceClass(context.getJvmInternalClass("FunctionReference"))
val lambdaClass: IrClassSymbol = createClass(FqName("kotlin.jvm.internal.Lambda")) { klass ->
klass.addConstructor().apply {
addValueParameter("arity", irBuiltIns.intType)
}
}.symbol
private fun generateCallableReferenceMethods(klass: IrClass) {
klass.addFunction("getSignature", irBuiltIns.stringType, Modality.OPEN)
klass.addFunction("getName", irBuiltIns.stringType, Modality.OPEN)
klass.addFunction("getOwner", irBuiltIns.kDeclarationContainerClass.typeWith(), Modality.OPEN)
}
val functionReference: IrClassSymbol = createClass(FqName("kotlin.jvm.internal.FunctionReference")) { klass ->
klass.addConstructor().apply {
addValueParameter("arity", irBuiltIns.intType)
addValueParameter("receiver", irBuiltIns.anyNType)
}
generateCallableReferenceMethods(klass)
}.symbol
fun getFunction(parameterCount: Int): IrClassSymbol =
symbolTable.referenceClass(context.builtIns.getFunction(parameterCount))
}
symbolTable.referenceClass(builtIns.getFunction(parameterCount))
private val jvmFunctionClasses = storageManager.createMemoizedFunction { n: Int ->
createClass(FqName("kotlin.jvm.functions.Function$n"), ClassKind.INTERFACE) { klass ->
for (i in 1..n) {
klass.addTypeParameter("P$i", irBuiltIns.anyNType, Variance.IN_VARIANCE)
}
val returnType = klass.addTypeParameter("R", irBuiltIns.anyNType, Variance.OUT_VARIANCE)
klass.addFunction("invoke", returnType.defaultType, Modality.ABSTRACT).apply {
for (i in 1..n) {
addValueParameter("p$i", klass.typeParameters[i - 1].defaultType)
}
}
}.symbol
}
fun getJvmFunctionClass(parameterCount: Int): IrClassSymbol =
jvmFunctionClasses(parameterCount)
val functionN: IrClassSymbol = createClass(FqName("kotlin.jvm.functions.FunctionN"), ClassKind.INTERFACE) { klass ->
val returnType = klass.addTypeParameter("R", irBuiltIns.anyNType, Variance.OUT_VARIANCE)
klass.addFunction("invoke", returnType.defaultType, Modality.ABSTRACT).apply {
addValueParameter {
name = Name.identifier("args")
type = irBuiltIns.arrayClass.typeWith(irBuiltIns.anyNType)
origin = IrDeclarationOrigin.DEFINED
varargElementType = irBuiltIns.anyNType
}
}
}.symbol
private data class PropertyReferenceKey(
val mutable: Boolean,
val parameterCount: Int,
val impl: Boolean
)
private val propertyReferenceClasses = storageManager.createMemoizedFunction { key: PropertyReferenceKey ->
val (mutable, n, impl) = key
val className = buildString {
if (mutable) append("Mutable")
append("PropertyReference")
append(n)
if (impl) append("Impl")
}
createClass(FqName("kotlin.jvm.internal.$className")) { klass ->
if (impl) {
klass.addConstructor().apply {
addValueParameter("owner", irBuiltIns.kDeclarationContainerClass.typeWith())
addValueParameter("name", irBuiltIns.stringType)
addValueParameter("string", irBuiltIns.stringType)
}
} else {
klass.addConstructor()
klass.addConstructor().apply {
addValueParameter("receiver", irBuiltIns.anyNType)
}
}
val receiverFieldName = Name.identifier("receiver")
klass.addProperty {
name = receiverFieldName
}.apply {
backingField = buildField {
name = receiverFieldName
type = irBuiltIns.anyNType
visibility = Visibilities.PROTECTED
}.also { field ->
field.parent = klass
}
}
generateCallableReferenceMethods(klass)
// To avoid hassle with generic type parameters, we pretend that PropertyReferenceN.get takes and returns `Any?`
// (similarly with set). This should be enough for the JVM IR backend to generate correct calls and bridges.
klass.addFunction("get", irBuiltIns.anyNType, Modality.ABSTRACT).apply {
for (i in 0 until n) {
addValueParameter("receiver$i", irBuiltIns.anyNType)
}
}
if (mutable) {
klass.addFunction("set", irBuiltIns.unitType, Modality.ABSTRACT).apply {
for (i in 0 until n) {
addValueParameter("receiver$i", irBuiltIns.anyNType)
}
addValueParameter("value", irBuiltIns.anyNType)
}
}
}.symbol
}
fun getPropertyReferenceClass(mutable: Boolean, parameterCount: Int, impl: Boolean): IrClassSymbol =
propertyReferenceClasses(PropertyReferenceKey(mutable, parameterCount, impl))
val reflection: IrClassSymbol = createClass(FqName("kotlin.jvm.internal.Reflection")) { klass ->
// We use raw types for java.lang.Class and kotlin.reflect.KClass here for simplicity and because this is what's used
// at declaration site at kotlin.jvm.internal.Reflection.
val rawJavaLangClass = javaLangClass.typeWith()
val rawKClass = irBuiltIns.kClassClass.typeWith()
klass.addFunction("getOrCreateKotlinPackage", irBuiltIns.kDeclarationContainerClass.typeWith(), isStatic = true).apply {
addValueParameter("javaClass", rawJavaLangClass)
addValueParameter("moduleName", irBuiltIns.stringType)
}
klass.addFunction("getOrCreateKotlinClass", rawKClass, isStatic = true).apply {
addValueParameter("javaClass", rawJavaLangClass)
}
klass.addFunction("getOrCreateKotlinClasses", irBuiltIns.arrayClass.typeWith(rawKClass), isStatic = true).apply {
addValueParameter("javaClasses", irBuiltIns.arrayClass.typeWith(rawJavaLangClass))
}
for (mutable in listOf(false, true)) {
for (n in 0..2) {
val functionName = (if (mutable) "mutableProperty" else "property") + n
klass.addFunction(functionName, irBuiltIns.getKPropertyClass(mutable, n).typeWith(), isStatic = true).apply {
addValueParameter("p", getPropertyReferenceClass(mutable, n, impl = false).typeWith())
}
}
}
}.symbol
val getOrCreateKotlinPackage: IrSimpleFunctionSymbol =
reflection.functions.single { it.owner.name.asString() == "getOrCreateKotlinPackage" }
val getOrCreateKotlinClass: IrSimpleFunctionSymbol =
reflection.functions.single { it.owner.name.asString() == "getOrCreateKotlinClass" }
val getOrCreateKotlinClasses: IrSimpleFunctionSymbol =
reflection.functions.single { it.owner.name.asString() == "getOrCreateKotlinClasses" }
}
@@ -32,7 +32,6 @@ import org.jetbrains.kotlin.ir.util.isKClass
import org.jetbrains.kotlin.ir.util.isNonPrimitiveArray
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.types.Variance
internal val annotationPhase = makeIrFilePhase(
@@ -138,25 +137,16 @@ private class AnnotationLowering(private val context: JvmBackendContext) : FileL
val getField = irBuilder.irGet(field.type, receiver.dispatchReceiver!!, receiver.symbol)
if (!wrapIntoKClass)
return getField
val functionSymbol = if (wrapIntoArray) getOrCreateKClassesSymbol else getOrCreateKClassSymbol
return irBuilder.irCall(functionSymbol, functionSymbol.owner.returnType).apply {
return irBuilder.irCall(
if (wrapIntoArray) context.ir.symbols.getOrCreateKotlinClasses else context.ir.symbols.getOrCreateKotlinClass
).apply {
putValueArgument(0, getField)
}
}
private val javaLangClass = context.getIrClass(FqName("java.lang.Class"))
private val reflectionClass = context.getIrClass(FqName("kotlin.jvm.internal.Reflection"))
private val getOrCreateKClassSymbol by lazy {
reflectionClass.getFunctionByName("getOrCreateKotlinClass", 1)
}
private val getOrCreateKClassesSymbol by lazy {
reflectionClass.getFunctionByName("getOrCreateKotlinClasses", 1)
}
private fun javaClassType(typeArguments: List<IrTypeArgument>): IrType =
javaLangClass.createType(false, typeArguments)
context.ir.symbols.javaLangClass.createType(false, typeArguments)
private fun javaClassArrayType(variance: Variance, typeArguments: List<IrTypeArgument>): IrType {
val argument = makeTypeProjection(javaClassType(typeArguments), variance)
@@ -103,7 +103,7 @@ internal class CallableReferenceLowering(val context: JvmBackendContext) : FileL
context.irBuiltIns.anyClass.typeWith(),
(0 until argumentsCount).map { i -> expression.getValueArgument(i)!! }
)
val invokeFun = context.getIrClass(FqName("kotlin.jvm.functions.FunctionN")).owner.declarations.single {
val invokeFun = context.ir.symbols.functionN.owner.declarations.single {
it is IrSimpleFunction && it.name.asString() == "invoke"
} as IrSimpleFunction
@@ -154,10 +154,6 @@ internal class CallableReferenceLowering(val context: JvmBackendContext) : FileL
val functionReferenceConstructor: IrConstructor
)
private val continuationClass = context.getIrClass(FqName("kotlin.coroutines.experimental.Continuation")).owner
//private val getContinuationSymbol = context.ir.symbols.getContinuation
private inner class FunctionReferenceBuilder(
val referenceParent: IrDeclarationParent,
val irFunctionReference: IrFunctionReference
@@ -193,9 +189,9 @@ internal class CallableReferenceLowering(val context: JvmBackendContext) : FileL
useVararg = (numberOfParameters > MAX_ARGCOUNT_WITHOUT_VARARG)
val functionClassSymbol = if (useVararg)
context.getIrClass(FqName("kotlin.jvm.functions.FunctionN"))
context.ir.symbols.functionN
else
context.getIrClass(FqName("kotlin.jvm.functions.Function$numberOfParameters"))
context.ir.symbols.getJvmFunctionClass(numberOfParameters)
val functionClass = functionClassSymbol.owner
val functionParameterTypes = unboundCalleeParameters.map { it.type }
val functionClassTypeParameters = if (useVararg)
@@ -211,9 +207,12 @@ internal class CallableReferenceLowering(val context: JvmBackendContext) : FileL
var suspendFunctionClass: IrClass? = null
val lastParameterType = unboundCalleeParameters.lastOrNull()?.type
if ((lastParameterType as? IrSimpleType)?.classifier == continuationClass) {
if (lastParameterType is IrSimpleType &&
lastParameterType.classOrNull?.owner?.fqNameWhenAvailable?.asString() == "kotlin.coroutines.experimental.Continuation"
) {
// If the last parameter is Continuation<> inherit from SuspendFunction.
suspendFunctionClass = context.getIrClass(FqName("kotlin.coroutines.SuspendFunction${numberOfParameters - 1}")).owner
val suspendFunctionDescriptor = context.getClass(FqName("kotlin.coroutines.SuspendFunction${numberOfParameters - 1}"))
suspendFunctionClass = context.ir.symbols.externalSymbolTable.referenceClass(suspendFunctionDescriptor).owner
val suspendFunctionClassTypeParameters = functionParameterTypes.dropLast(1) +
(lastParameterType.arguments.single() as IrTypeProjection).type
functionReferenceClassSuperTypes += IrSimpleTypeImpl(
@@ -254,7 +253,7 @@ internal class CallableReferenceLowering(val context: JvmBackendContext) : FileL
val getSignatureMethod =
createGetSignatureMethod(functionReferenceOrLambda.owner.functions.find { it.name.asString() == "getSignature"}!!)
val getNameMethod =
createGetNameMethod(functionReferenceOrLambda.owner.properties.find { it.name.asString() == "name" }!!)
createGetNameMethod(functionReferenceOrLambda.owner.functions.find { it.name.asString() == "getName" }!!)
val getOwnerMethod =
createGetOwnerMethod(functionReferenceOrLambda.owner.functions.find { it.name.asString() == "getOwner" }!!)
@@ -474,19 +473,18 @@ internal class CallableReferenceLowering(val context: JvmBackendContext) : FileL
}
}
private fun createGetNameMethod(superNameProperty: IrProperty): IrSimpleFunction {
val superGetter = superNameProperty.getter!!
return buildFun {
private fun createGetNameMethod(superFunction: IrSimpleFunction): IrSimpleFunction =
buildFun {
setSourceRange(irFunctionReference)
origin = JvmLoweredDeclarationOrigin.FUNCTION_REFERENCE_IMPL
name = Name.identifier("getName")
returnType = superGetter.returnType
visibility = superGetter.visibility
modality = superGetter.modality
returnType = superFunction.returnType
visibility = superFunction.visibility
modality = superFunction.modality
}.apply {
val function = this
parent = functionReferenceClass
overriddenSymbols.add(superGetter.symbol)
overriddenSymbols.add(superFunction.symbol)
dispatchReceiverParameter = functionReferenceClass.thisReceiver?.copyTo(function)
val irBuilder = context.createIrBuilder(function.symbol, startOffset, endOffset)
@@ -496,7 +494,6 @@ internal class CallableReferenceLowering(val context: JvmBackendContext) : FileL
)
}
}
}
private fun createGetOwnerMethod(superFunction: IrSimpleFunction): IrSimpleFunction =
buildFun {
@@ -544,16 +541,15 @@ internal class CallableReferenceLowering(val context: JvmBackendContext) : FileL
else -> state.typeMapper.mapOwner(callee.descriptor)
}
val clazz = globalContext.getIrClass(FqName("java.lang.Class")).owner
val clazz = globalContext.ir.symbols.javaLangClass
val clazzRef = IrClassReferenceImpl(
UNDEFINED_OFFSET,
UNDEFINED_OFFSET,
clazz.defaultType,
clazz.symbol,
clazz.typeWith(),
clazz,
CrIrType(type)
)
val reflectionClass = globalContext.getIrClass(FqName("kotlin.jvm.internal.Reflection"))
return if (isContainerPackage) {
// Note that this name is not used in reflection. There should be the name of the referenced declaration's module instead,
// but there's no nice API to obtain that name here yet
@@ -562,15 +558,12 @@ internal class CallableReferenceLowering(val context: JvmBackendContext) : FileL
-1, -1, globalContext.irBuiltIns.stringType,
state.moduleName
)
val functionSymbol = reflectionClass.functions.find { it.owner.name.asString() == "getOrCreateKotlinPackage" }!!
irCall(functionSymbol, functionSymbol.owner.returnType).apply {
irCall(globalContext.ir.symbols.getOrCreateKotlinPackage).apply {
putValueArgument(0, clazzRef)
putValueArgument(1, module)
}
} else {
val functionSymbol = reflectionClass.functions.filter { it.owner.name.asString() == "getOrCreateKotlinClass" }
.single { it.owner.valueParameters.size == 1 }
irCall(functionSymbol, functionSymbol.owner.returnType).apply {
irCall(globalContext.ir.symbols.getOrCreateKotlinClass).apply {
putValueArgument(0, clazzRef)
}
}
@@ -18,14 +18,20 @@ import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.builders.declarations.*
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.types.impl.*
import org.jetbrains.kotlin.ir.expressions.impl.IrClassReferenceImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrInstanceInitializerCallImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrVarargImpl
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.IrFieldSymbol
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.ir.types.createType
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection
import org.jetbrains.kotlin.ir.types.typeWith
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.visitors.*
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.load.java.JvmAbi
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.types.Variance
@@ -60,18 +66,6 @@ internal class PropertyReferenceLowering(val context: JvmBackendContext) : Class
private val IrMemberAccessExpression.symbol: IrSymbol
get() = getter?.owner?.symbol ?: field!!.owner.symbol
private val plainJavaClass =
context.getIrClass(FqName("java.lang.Class")).owner
private val reflectionClass =
context.getIrClass(FqName("kotlin.jvm.internal.Reflection")).owner
private val getOrCreateKotlinClass =
reflectionClass.functions.single { it.name.asString() == "getOrCreateKotlinClass" && it.valueParameters.size == 1 }
private val getOrCreateKotlinPackage =
reflectionClass.functions.single { it.name.asString() == "getOrCreateKotlinPackage" && it.valueParameters.size == 2 }
private val arrayItemGetter =
context.ir.symbols.array.owner.functions.single { it.name.asString() == "get" }
@@ -101,8 +95,8 @@ internal class PropertyReferenceLowering(val context: JvmBackendContext) : Class
private val IrMemberAccessExpression.parentJavaClassReference
get() = IrClassReferenceImpl(
startOffset, endOffset,
plainJavaClass.defaultType,
plainJavaClass.symbol,
context.ir.symbols.javaLangClass.typeWith(),
context.ir.symbols.javaLangClass,
// TODO: when the parent is an interface, this should map to DefaultImpls. However, that requires
// moving this lowering below InterfaceLowering; see another TODO above.
CrIrType(context.state.typeMapper.mapImplementationOwner(propertyContainerChild!!.descriptor))
@@ -110,16 +104,17 @@ internal class PropertyReferenceLowering(val context: JvmBackendContext) : Class
private fun IrBuilderWithScope.buildReflectedContainerReference(expression: IrMemberAccessExpression): IrExpression {
val parent = expression.propertyContainerChild?.parent
val context = this@PropertyReferenceLowering.context
return when {
// FileClassLowering creates a class to which all package-level declarations are moved. However, it does not
// fix the declarations' parents (yet), which is why we check for both a file class and a package fragment.
parent is IrPackageFragment || (parent is IrClass && parent.origin == IrDeclarationOrigin.FILE_CLASS) ->
irCall(getOrCreateKotlinPackage).apply {
irCall(context.ir.symbols.getOrCreateKotlinPackage).apply {
putValueArgument(0, expression.parentJavaClassReference)
putValueArgument(1, irString(this@PropertyReferenceLowering.context.state.moduleName))
putValueArgument(1, irString(context.state.moduleName))
}
parent is IrClass ->
irCall(getOrCreateKotlinClass).apply {
irCall(context.ir.symbols.getOrCreateKotlinClass).apply {
putValueArgument(0, expression.parentJavaClassReference)
}
else -> throw AssertionError("referenced property not inside a class/package fragment")
@@ -133,9 +128,9 @@ internal class PropertyReferenceLowering(val context: JvmBackendContext) : Class
)
private fun propertyReferenceKind(mutable: Boolean, i: Int) = PropertyReferenceKind(
context.getIrClass(FqName("kotlin.jvm.internal.${if (mutable) "Mutable" else ""}PropertyReference$i")),
context.getIrClass(FqName("kotlin.jvm.internal.${if (mutable) "Mutable" else ""}PropertyReference${i}Impl")),
reflectionClass.functions.single { it.name.asString() == (if (mutable) "mutableProperty$i" else "property$i") }
context.ir.symbols.getPropertyReferenceClass(mutable, i, false),
context.ir.symbols.getPropertyReferenceClass(mutable, i, true),
context.ir.symbols.reflection.owner.functions.single { it.name.asString() == (if (mutable) "mutableProperty$i" else "property$i") }
)
private fun propertyReferenceKindFor(expression: IrMemberAccessExpression): PropertyReferenceKind =
@@ -295,7 +290,7 @@ internal class PropertyReferenceLowering(val context: JvmBackendContext) : Class
fun buildOverride(method: IrSimpleFunction, build: IrBlockBodyBuilder.(List<IrValueParameter>) -> IrExpression) =
buildFun {
setSourceRange(expression)
name = if (method.name.asString() == "<get-name>") Name.identifier("getName") else method.name
name = method.name
returnType = method.returnType
visibility = method.visibility
origin = referenceClass.origin
@@ -329,7 +324,7 @@ internal class PropertyReferenceLowering(val context: JvmBackendContext) : Class
}
}
buildOverride(superClass.properties.single { it.name.asString() == "name" }.getter!!) {
buildOverride(superClass.functions.single { it.name.asString() == "getName" }) {
irString(expression.descriptor.name.asString())
}
@@ -0,0 +1,18 @@
/*
* 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.ir.builders.declarations
import org.jetbrains.kotlin.descriptors.Modality
class IrPropertyBuilder : IrDeclarationBuilder() {
var modality: Modality = Modality.FINAL
var isVar: Boolean = false
var isConst: Boolean = false
var isLateinit: Boolean = false
var isDelegated: Boolean = false
var isExternal: Boolean = false
}
@@ -0,0 +1,17 @@
/*
* 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.ir.builders.declarations
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.utils.SmartList
class IrTypeParameterBuilder : IrDeclarationBuilder() {
var index: Int = UNDEFINED_PARAMETER_INDEX
var variance: Variance = Variance.INVARIANT
var isReified: Boolean = false
val superTypes: MutableList<IrType> = SmartList()
}
@@ -12,14 +12,12 @@ import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.TypeParameterDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.ir.declarations.impl.IrExternalPackageFragmentImpl
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.types.toIrType
import org.jetbrains.kotlin.ir.types.IrSimpleType
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
import org.jetbrains.kotlin.ir.types.toIrType
import org.jetbrains.kotlin.ir.types.withHasQuestionMark
import org.jetbrains.kotlin.ir.util.SymbolTable
import org.jetbrains.kotlin.ir.util.TypeTranslator
@@ -162,8 +160,24 @@ class IrBuiltIns(
val primitiveIrTypes by lazy { listOf(booleanType, charType, byteType, shortType, intType, floatType, longType, doubleType) }
val kCallableClass = builtIns.getBuiltInClassByFqName(KotlinBuiltIns.FQ_NAMES.kCallable.toSafe()).toIrSymbol()
val kPropertyClass = builtIns.getBuiltInClassByFqName(KotlinBuiltIns.FQ_NAMES.kPropertyFqName.toSafe()).toIrSymbol()
val kCallableClass = builtIns.kCallable.toIrSymbol()
val kPropertyClass = builtIns.kProperty.toIrSymbol()
val kDeclarationContainerClass = builtIns.kDeclarationContainer.toIrSymbol()
val kClassClass = builtIns.kClass.toIrSymbol()
private val kProperty0Class = builtIns.kProperty0.toIrSymbol()
private val kProperty1Class = builtIns.kProperty1.toIrSymbol()
private val kProperty2Class = builtIns.kProperty2.toIrSymbol()
private val kMutableProperty0Class = builtIns.kMutableProperty0.toIrSymbol()
private val kMutableProperty1Class = builtIns.kMutableProperty1.toIrSymbol()
private val kMutableProperty2Class = builtIns.kMutableProperty2.toIrSymbol()
fun getKPropertyClass(mutable: Boolean, n: Int): IrClassSymbol = when (n) {
0 -> if (mutable) kMutableProperty0Class else kProperty0Class
1 -> if (mutable) kMutableProperty1Class else kProperty1Class
2 -> if (mutable) kMutableProperty2Class else kProperty2Class
else -> error("No KProperty for n=$n mutable=$mutable")
}
// TODO switch to IrType
val primitiveTypes = listOf(bool, char, byte, short, int, long, float, double)
@@ -9,9 +9,7 @@ import org.jetbrains.kotlin.cli.jvm.config.addJvmClasspathRoot
import org.jetbrains.kotlin.codegen.AbstractBlackBoxAgainstJavaCodegenTest
import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.config.JVMConfigurationKeys
import org.jetbrains.kotlin.test.ConfigurationKind
import org.jetbrains.kotlin.test.TargetBackend
import java.io.File
abstract class AbstractIrBlackBoxAgainstJavaCodegenTest : AbstractBlackBoxAgainstJavaCodegenTest() {
@@ -20,9 +18,5 @@ abstract class AbstractIrBlackBoxAgainstJavaCodegenTest : AbstractBlackBoxAgains
configuration.put(JVMConfigurationKeys.IR, true)
}
override fun extractConfigurationKind(files: MutableList<TestFile>): ConfigurationKind {
return ConfigurationKind.ALL
}
override fun getBackend() = TargetBackend.JVM_IR
}
@@ -19,7 +19,6 @@ package org.jetbrains.kotlin.codegen.ir
import org.jetbrains.kotlin.codegen.AbstractBlackBoxCodegenTest
import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.config.JVMConfigurationKeys
import org.jetbrains.kotlin.test.ConfigurationKind
import org.jetbrains.kotlin.test.TargetBackend
abstract class AbstractIrBlackBoxCodegenTest : AbstractBlackBoxCodegenTest() {
@@ -27,15 +26,5 @@ abstract class AbstractIrBlackBoxCodegenTest : AbstractBlackBoxCodegenTest() {
configuration.put(JVMConfigurationKeys.IR, true)
}
//symbols are constructed with stdlib descriptors so stdlib should be presented
// TODO rewrite symbols building
override fun extractConfigurationKind(files: MutableList<TestFile>): ConfigurationKind {
val result = super.extractConfigurationKind(files)
return when (result) {
ConfigurationKind.JDK_NO_RUNTIME, ConfigurationKind.JDK_ONLY -> ConfigurationKind.NO_KOTLIN_REFLECT
else -> result
}
}
override fun getBackend() = TargetBackend.JVM_IR
}
@@ -19,10 +19,7 @@ package org.jetbrains.kotlin.codegen.ir
import org.jetbrains.kotlin.codegen.AbstractBlackBoxCodegenTest
import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.config.JVMConfigurationKeys
import org.jetbrains.kotlin.test.ConfigurationKind
abstract class AbstractIrBlackBoxInlineCodegenTest: AbstractBlackBoxCodegenTest() {
override fun updateConfiguration(configuration: CompilerConfiguration) = configuration.put(JVMConfigurationKeys.IR, true)
override fun extractConfigurationKind(files: MutableList<TestFile>): ConfigurationKind = ConfigurationKind.ALL
}
}
@@ -8,10 +8,7 @@ package org.jetbrains.kotlin.codegen.ir
import org.jetbrains.kotlin.codegen.AbstractBytecodeTextTest
import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.config.JVMConfigurationKeys
import org.jetbrains.kotlin.test.ConfigurationKind
abstract class AbstractIrBytecodeTextTest : AbstractBytecodeTextTest() {
override fun updateConfiguration(configuration: CompilerConfiguration) = configuration.put(JVMConfigurationKeys.IR, true)
override fun extractConfigurationKind(files: MutableList<TestFile>): ConfigurationKind = ConfigurationKind.ALL
}
@@ -9,7 +9,6 @@ import com.intellij.openapi.util.Comparing
import org.jetbrains.kotlin.codegen.AbstractCheckLocalVariablesTableTest
import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.config.JVMConfigurationKeys
import org.jetbrains.kotlin.test.ConfigurationKind
import org.junit.ComparisonFailure
import java.io.File
@@ -19,10 +18,6 @@ abstract class AbstractIrCheckLocalVariablesTableTest : AbstractCheckLocalVariab
configuration.put(JVMConfigurationKeys.IR, true)
}
override fun extractConfigurationKind(files: MutableList<TestFile>): ConfigurationKind {
return ConfigurationKind.ALL
}
override fun doCompare(
testFile: File,
text: String,
@@ -8,10 +8,7 @@ package org.jetbrains.kotlin.codegen.ir
import org.jetbrains.kotlin.codegen.AbstractCompileKotlinAgainstKotlinTest
import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.config.JVMConfigurationKeys
import org.jetbrains.kotlin.test.ConfigurationKind
abstract class AbstractIrCompileKotlinAgainstKotlinTest : AbstractCompileKotlinAgainstKotlinTest() {
override fun updateConfiguration(configuration: CompilerConfiguration) = configuration.put(JVMConfigurationKeys.IR, true)
override fun extractConfigurationKind(files: MutableList<TestFile>): ConfigurationKind = ConfigurationKind.ALL
}
}
@@ -9,7 +9,6 @@ import org.jetbrains.kotlin.codegen.AbstractLineNumberTest
import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.config.JVMConfigurationKeys
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.test.ConfigurationKind
import org.jetbrains.kotlin.test.testFramework.KtUsefulTestCase
import org.jetbrains.org.objectweb.asm.ClassReader
import org.jetbrains.org.objectweb.asm.Label
@@ -18,10 +17,6 @@ import org.jetbrains.org.objectweb.asm.Opcodes
import java.io.File
abstract class AbstractIrLineNumberTest : AbstractLineNumberTest() {
override fun extractConfigurationKind(files: MutableList<TestFile>): ConfigurationKind {
return ConfigurationKind.ALL
}
override fun updateConfiguration(configuration: CompilerConfiguration) {
super.updateConfiguration(configuration)
configuration.put(JVMConfigurationKeys.IR, true)
@@ -253,6 +253,7 @@ public abstract class KotlinBuiltIns {
public final FqNameUnsafe kPropertyFqName = reflect("KProperty");
public final FqNameUnsafe kMutablePropertyFqName = reflect("KMutableProperty");
public final ClassId kProperty = ClassId.topLevel(kPropertyFqName.toSafe());
public final FqNameUnsafe kDeclarationContainer = reflect("KDeclarationContainer");
public final FqName uByteFqName = fqName("UByte");
public final FqName uShortFqName = fqName("UShort");
@@ -492,6 +493,51 @@ public abstract class KotlinBuiltIns {
return getBuiltInClassByFqName(FQ_NAMES.kClass.toSafe());
}
@NotNull
public ClassDescriptor getKDeclarationContainer() {
return getBuiltInClassByFqName(FQ_NAMES.kDeclarationContainer.toSafe());
}
@NotNull
public ClassDescriptor getKCallable() {
return getBuiltInClassByFqName(FQ_NAMES.kCallable.toSafe());
}
@NotNull
public ClassDescriptor getKProperty() {
return getBuiltInClassByFqName(FQ_NAMES.kPropertyFqName.toSafe());
}
@NotNull
public ClassDescriptor getKProperty0() {
return getBuiltInClassByFqName(FQ_NAMES.kProperty0.toSafe());
}
@NotNull
public ClassDescriptor getKProperty1() {
return getBuiltInClassByFqName(FQ_NAMES.kProperty1.toSafe());
}
@NotNull
public ClassDescriptor getKProperty2() {
return getBuiltInClassByFqName(FQ_NAMES.kProperty2.toSafe());
}
@NotNull
public ClassDescriptor getKMutableProperty0() {
return getBuiltInClassByFqName(FQ_NAMES.kMutableProperty0.toSafe());
}
@NotNull
public ClassDescriptor getKMutableProperty1() {
return getBuiltInClassByFqName(FQ_NAMES.kMutableProperty1.toSafe());
}
@NotNull
public ClassDescriptor getKMutableProperty2() {
return getBuiltInClassByFqName(FQ_NAMES.kMutableProperty2.toSafe());
}
@NotNull
public ClassDescriptor getIterator() {
return getBuiltInClassByFqName(FQ_NAMES.iterator);