[IR] Refactor JvmSymbols to allow on-demand loading of (subsets of) symbols

This commit is contained in:
Kristoffer Andersen
2021-11-10 13:06:53 +01:00
committed by Alexander Udalov
parent 4b4ee78e5d
commit 7e633cf217
3 changed files with 171 additions and 111 deletions
@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.backend.common.FileLoweringPass
import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext
import org.jetbrains.kotlin.backend.common.phaser.makeIrModulePhase
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.backend.jvm.JvmReflectSymbols
import org.jetbrains.kotlin.backend.jvm.codegen.isJvmInterface
import org.jetbrains.kotlin.backend.jvm.ir.IrInlineScopeResolver
import org.jetbrains.kotlin.backend.jvm.ir.createJvmIrBuilder
@@ -83,7 +84,7 @@ internal class ReflectiveAccessLowering(
// reflective access . We record these _before_ transformation, in order to
// later predict the compilation strategy for fields. See the uses of
// `fieldLocationAndReceiver`.
val callsOnCompanionObjects: MutableMap<IrCall,IrClassSymbol> = mutableMapOf()
val callsOnCompanionObjects: MutableMap<IrCall, IrClassSymbol> = mutableMapOf()
private fun recordCompanionObjectAsDispatchReceiver(expression: IrCall) {
if ((expression.dispatchReceiver as? IrGetObjectValue)?.symbol?.owner?.isCompanion == true) {
@@ -169,6 +170,7 @@ internal class ReflectiveAccessLowering(
*/
private val symbols = context.ir.symbols
private val reflectSymbols = symbols.javaLangReflectSymbols
private fun IrBuilderWithScope.javaClassObject(klass: IrType): IrExpression =
irCall(symbols.kClassJava.owner.getter!!).apply {
@@ -182,26 +184,26 @@ internal class ReflectiveAccessLowering(
}
private fun IrBuilderWithScope.getDeclaredField(declaringClass: IrExpression, fieldName: String): IrExpression =
irCall(symbols.getDeclaredField).apply {
irCall(reflectSymbols.getDeclaredField).apply {
dispatchReceiver = declaringClass
putValueArgument(0, irString(fieldName))
}
private fun IrBuilderWithScope.fieldSetAccessible(field: IrExpression): IrExpression =
irCall(symbols.javaLangReflectFieldSetAccessible).apply {
irCall(reflectSymbols.javaLangReflectFieldSetAccessible).apply {
dispatchReceiver = field
putValueArgument(0, irTrue())
}
private fun IrBuilderWithScope.fieldSet(fieldObject: IrExpression, receiver: IrExpression, value: IrExpression): IrExpression =
irCall(symbols.javaLangReflectFieldSet).apply {
irCall(reflectSymbols.javaLangReflectFieldSet).apply {
dispatchReceiver = fieldObject
putValueArgument(0, receiver)
putValueArgument(1, value)
}
private fun IrBuilderWithScope.fieldGet(fieldObject: IrExpression, receiver: IrExpression): IrExpression =
irCall(symbols.javaLangReflectFieldGet).apply {
irCall(reflectSymbols.javaLangReflectFieldGet).apply {
dispatchReceiver = fieldObject
putValueArgument(0, receiver)
}
@@ -211,14 +213,14 @@ internal class ReflectiveAccessLowering(
methodName: String,
parameterTypes: List<IrType>
): IrExpression =
irCall(symbols.getDeclaredMethod).apply {
irCall(reflectSymbols.getDeclaredMethod).apply {
dispatchReceiver = declaringClass
putValueArgument(0, irString(methodName))
putValueArgument(1, irVararg(symbols.javaLangClass.defaultType, parameterTypes.map { javaClassObject(it) }))
}
private fun IrBuilderWithScope.methodSetAccessible(method: IrExpression): IrExpression =
irCall(symbols.javaLangReflectMethodSetAccessible).apply {
irCall(reflectSymbols.javaLangReflectMethodSetAccessible).apply {
dispatchReceiver = method
putValueArgument(0, irTrue())
}
@@ -228,7 +230,7 @@ internal class ReflectiveAccessLowering(
receiver: IrExpression,
arguments: List<IrExpression>
): IrExpression =
irCall(symbols.javaLangReflectMethodInvoke).apply {
irCall(reflectSymbols.javaLangReflectMethodInvoke).apply {
dispatchReceiver = method
putValueArgument(0, receiver)
putValueArgument(1, irVararg(context.irBuiltIns.anyNType, arguments))
@@ -238,20 +240,20 @@ internal class ReflectiveAccessLowering(
declaringClass: IrExpression,
parameterTypes: List<IrType>
): IrExpression =
irCall(symbols.getDeclaredConstructor).apply {
irCall(reflectSymbols.getDeclaredConstructor).apply {
dispatchReceiver = declaringClass
putValueArgument(0, irVararg(symbols.javaLangClass.defaultType, parameterTypes.map { javaClassObject(it) }))
}
private fun IrBuilderWithScope.constructorSetAccessible(constructor: IrExpression): IrExpression =
irCall(symbols.javaLangReflectConstructorSetAccessible).apply {
irCall(reflectSymbols.javaLangReflectConstructorSetAccessible).apply {
dispatchReceiver = constructor
putValueArgument(0, irTrue())
}
private fun IrBuilderWithScope.constructorNewInstance(constructor: IrExpression, arguments: List<IrExpression>): IrExpression =
irCall(symbols.javaLangReflectConstructorNewInstance).apply {
irCall(reflectSymbols.javaLangReflectConstructorNewInstance).apply {
dispatchReceiver = constructor
putValueArgument(0, irVararg(context.irBuiltIns.anyNType, arguments))
}
@@ -278,7 +280,7 @@ internal class ReflectiveAccessLowering(
parameterTypes
),
nameHint = "method",
irType = symbols.javaLangReflectMethod.defaultType
irType = reflectSymbols.javaLangReflectMethod.defaultType
)
+methodSetAccessible(irGet(methodVar))
+methodInvoke(irGet(methodVar), receiver ?: irNull(), arguments)
@@ -330,7 +332,7 @@ internal class ReflectiveAccessLowering(
call.valueParameterTypes()
),
nameHint = "constructor",
irType = symbols.javaLangReflectConstructor.defaultType
irType = reflectSymbols.javaLangReflectConstructor.defaultType
)
+constructorSetAccessible(irGet(constructorVar))
+constructorNewInstance(irGet(constructorVar), call.getValueArguments())
@@ -353,7 +355,7 @@ internal class ReflectiveAccessLowering(
val fieldVar = createTmpVariable(
getDeclaredField(irGet(classVar), fieldName),
nameHint = "field",
irType = symbols.javaLangReflectField.defaultType
irType = reflectSymbols.javaLangReflectField.defaultType
)
+fieldSetAccessible(irGet(fieldVar))
+fieldGet(irGet(fieldVar), instance ?: irGet(classVar))
@@ -385,7 +387,7 @@ internal class ReflectiveAccessLowering(
fieldName
),
nameHint = "field",
irType = symbols.javaLangReflectField.defaultType
irType = reflectSymbols.javaLangReflectField.defaultType
)
+fieldSetAccessible(irGet(fieldVar))
+fieldSet(irGet(fieldVar), instance ?: irNull(), value)
@@ -502,7 +504,7 @@ internal class ReflectiveAccessLowering(
val builder = context.createJvmIrBuilder(expression.symbol)
// invokeSpecial(owner: String, name: String, descriptor: String, isInterface: Boolean): T
return builder.irCall(context.irIntrinsics.symbols.jvmDebuggerInvokeSpecialIntrinsic).apply {
return builder.irCall(context.ir.symbols.jvmDebuggerInvokeSpecialIntrinsic).apply {
dispatchReceiver = expression.dispatchReceiver
this.type = expression.symbol.owner.returnType
putValueArgument(0, builder.irString("${owner.packageFqName}/${owner.name}"))
@@ -0,0 +1,147 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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
import org.jetbrains.kotlin.backend.common.ir.createImplicitParameterDeclarationWithWrappedDescriptor
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.ir.IrBuiltIns
import org.jetbrains.kotlin.ir.builders.declarations.addFunction
import org.jetbrains.kotlin.ir.builders.declarations.addValueParameter
import org.jetbrains.kotlin.ir.builders.declarations.buildClass
import org.jetbrains.kotlin.ir.declarations.IrClass
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.types.defaultType
import org.jetbrains.kotlin.ir.types.makeNullable
import org.jetbrains.kotlin.ir.types.typeWith
import org.jetbrains.kotlin.ir.util.defaultType
import org.jetbrains.kotlin.ir.util.functions
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
class JvmReflectSymbols(val context: JvmBackendContext) {
private val irBuiltIns: IrBuiltIns = context.irBuiltIns
private val javaLangReflect: FqName = FqName("java.lang.reflect")
private val javaLangReflectPackage: IrPackageFragment =
IrExternalPackageFragmentImpl.createEmptyExternalPackageFragment(context.state.module, javaLangReflect)
val javaLangReflectField: IrClassSymbol =
createJavaLangReflectClass(FqName("java.lang.reflect.Field")) { klass ->
klass.addFunction("setAccessible", irBuiltIns.unitType).apply {
addValueParameter("isAccessible", irBuiltIns.booleanType)
}
klass.addFunction("get", irBuiltIns.anyNType).apply {
addValueParameter("receiver", irBuiltIns.anyNType)
}
klass.addFunction("set", irBuiltIns.unitType).apply {
addValueParameter("receiver", irBuiltIns.anyNType)
addValueParameter("value", irBuiltIns.anyNType)
}
}
val javaLangReflectMethod: IrClassSymbol =
createJavaLangReflectClass(FqName("java.lang.reflect.Method")) { klass ->
klass.addFunction("setAccessible", irBuiltIns.unitType).apply {
addValueParameter("isAccessible", irBuiltIns.booleanType)
}
klass.addFunction("invoke", irBuiltIns.anyNType).apply {
addValueParameter("receiver", irBuiltIns.anyNType)
addValueParameter {
name = Name.identifier("args")
type = irBuiltIns.arrayClass.typeWith(irBuiltIns.anyNType)
varargElementType = irBuiltIns.anyNType
}
}
}
val javaLangReflectConstructor: IrClassSymbol =
createJavaLangReflectClass(FqName("java.lang.reflect.Constructor")) { klass ->
klass.addFunction("setAccessible", irBuiltIns.unitType).apply {
addValueParameter("isAccessible", irBuiltIns.booleanType)
}
klass.addFunction("newInstance", irBuiltIns.anyNType).apply {
addValueParameter {
name = Name.identifier("args")
type = irBuiltIns.arrayClass.typeWith(irBuiltIns.anyNType)
varargElementType = irBuiltIns.anyNType
}
}
}
init {
val klass = context.ir.symbols.javaLangClass.owner
klass.addFunction("getDeclaredMethod", javaLangReflectMethod.defaultType.makeNullable()).apply {
addValueParameter("methodName", irBuiltIns.stringType.makeNullable())
addValueParameter {
name = Name.identifier("args")
type = irBuiltIns.arrayClass.typeWith(klass.defaultType).makeNullable()
varargElementType = klass.defaultType
}
}
klass.addFunction("getDeclaredField", javaLangReflectField.defaultType).apply {
addValueParameter("fieldName", irBuiltIns.stringType)
}
klass.addFunction("getDeclaredConstructor", javaLangReflectConstructor.defaultType.makeNullable()).apply {
addValueParameter {
name = Name.identifier("args")
type = irBuiltIns.arrayClass.typeWith(klass.defaultType).makeNullable()
varargElementType = klass.defaultType
}
}
}
val javaLangReflectFieldSetAccessible: IrSimpleFunctionSymbol =
javaLangReflectField.functionByName("setAccessible")
val javaLangReflectMethodSetAccessible: IrSimpleFunctionSymbol =
javaLangReflectMethod.functionByName("setAccessible")
val javaLangReflectConstructorSetAccessible: IrSimpleFunctionSymbol =
javaLangReflectConstructor.functionByName("setAccessible")
val getDeclaredField: IrSimpleFunctionSymbol =
context.ir.symbols.javaLangClass.functionByName("getDeclaredField")
val getDeclaredMethod: IrSimpleFunctionSymbol =
context.ir.symbols.javaLangClass.functionByName("getDeclaredMethod")
val getDeclaredConstructor: IrSimpleFunctionSymbol =
context.ir.symbols.javaLangClass.functionByName("getDeclaredConstructor")
val javaLangReflectFieldGet: IrSimpleFunctionSymbol =
javaLangReflectField.functionByName("get")
val javaLangReflectFieldSet: IrSimpleFunctionSymbol =
javaLangReflectField.functionByName("set")
val javaLangReflectMethodInvoke: IrSimpleFunctionSymbol =
javaLangReflectMethod.functionByName("invoke")
val javaLangReflectConstructorNewInstance: IrSimpleFunctionSymbol =
javaLangReflectConstructor.functionByName("newInstance")
private fun createJavaLangReflectClass(
fqName: FqName,
classKind: ClassKind = ClassKind.CLASS,
classModality: Modality = Modality.FINAL,
classIsInline: Boolean = false,
block: (IrClass) -> Unit = {}
): IrClassSymbol =
context.irFactory.buildClass {
name = fqName.shortName()
kind = classKind
modality = classModality
isInline = classIsInline
}.apply {
parent = javaLangReflectPackage
createImplicitParameterDeclarationWithWrappedDescriptor()
block(this)
}.symbol
}
@@ -60,7 +60,6 @@ class JvmSymbols(
private val kotlinReflectPackage: IrPackageFragment = createPackage(FqName("kotlin.reflect"))
private val javaLangPackage: IrPackageFragment = createPackage(FqName("java.lang"))
private val javaLangInvokePackage: IrPackageFragment = createPackage(FqName("java.lang.invoke"))
private val javaLangReflectPackage: IrPackageFragment = createPackage(FqName("java.lang.reflect"))
private val javaUtilPackage: IrPackageFragment = createPackage(FqName("java.util"))
@@ -105,7 +104,6 @@ class JvmSymbols(
"kotlin.reflect" -> kotlinReflectPackage
"java.lang" -> javaLangPackage
"java.lang.invoke" -> javaLangInvokePackage
"java.lang.reflect" -> javaLangReflectPackage
"java.util" -> javaUtilPackage
"kotlin.internal" -> kotlinInternalPackage
else -> error("Other packages are not supported yet: $fqName")
@@ -232,103 +230,12 @@ class JvmSymbols(
private val kDeclarationContainer: IrClassSymbol =
createClass(StandardNames.FqNames.kDeclarationContainer.toSafe(), ClassKind.INTERFACE, Modality.ABSTRACT)
val javaLangReflectField: IrClassSymbol =
createClass(FqName("java.lang.reflect.Field")) { klass ->
klass.addFunction("setAccessible", irBuiltIns.unitType).apply {
addValueParameter("isAccessible", irBuiltIns.booleanType)
}
klass.addFunction("get", irBuiltIns.anyNType).apply {
addValueParameter("receiver", irBuiltIns.anyNType)
}
klass.addFunction("set", irBuiltIns.unitType).apply {
addValueParameter("receiver", irBuiltIns.anyNType)
addValueParameter("value", irBuiltIns.anyNType)
}
}
val javaLangReflectMethod: IrClassSymbol =
createClass(FqName("java.lang.reflect.Method")) { klass ->
klass.addFunction("setAccessible", irBuiltIns.unitType).apply {
addValueParameter("isAccessible", irBuiltIns.booleanType)
}
klass.addFunction("invoke", irBuiltIns.anyNType).apply {
addValueParameter("receiver", irBuiltIns.anyNType)
addValueParameter {
name = Name.identifier("args")
type = irBuiltIns.arrayClass.typeWith(irBuiltIns.anyNType)
varargElementType = irBuiltIns.anyNType
}
}
}
val javaLangReflectConstructor: IrClassSymbol =
createClass(FqName("java.lang.reflect.Constructor")) { klass ->
klass.addFunction("setAccessible", irBuiltIns.unitType).apply {
addValueParameter("isAccessible", irBuiltIns.booleanType)
}
klass.addFunction("newInstance", irBuiltIns.anyNType).apply {
addValueParameter {
name = Name.identifier("args")
type = irBuiltIns.arrayClass.typeWith(irBuiltIns.anyNType)
varargElementType = irBuiltIns.anyNType
}
}
}
val javaLangReflectFieldSetAccessible: IrSimpleFunctionSymbol =
javaLangReflectField.functionByName("setAccessible")
val javaLangReflectMethodSetAccessible: IrSimpleFunctionSymbol =
javaLangReflectMethod.functionByName("setAccessible")
val javaLangReflectConstructorSetAccessible: IrSimpleFunctionSymbol =
javaLangReflectConstructor.functionByName("setAccessible")
val javaLangClass: IrClassSymbol =
createClass(FqName("java.lang.Class")) { klass ->
klass.addTypeParameter("T", irBuiltIns.anyNType, Variance.INVARIANT)
klass.addFunction("desiredAssertionStatus", irBuiltIns.booleanType)
klass.addFunction("getDeclaredMethod", javaLangReflectMethod.defaultType.makeNullable()).apply {
addValueParameter("methodName", irBuiltIns.stringType.makeNullable())
addValueParameter {
name = Name.identifier("args")
type = irBuiltIns.arrayClass.typeWith(klass.defaultType).makeNullable()
varargElementType = klass.defaultType
}
}
klass.addFunction("getDeclaredField", javaLangReflectField.defaultType).apply {
addValueParameter("fieldName", irBuiltIns.stringType)
}
klass.addFunction("getDeclaredConstructor", javaLangReflectConstructor.defaultType.makeNullable()).apply {
addValueParameter {
name = Name.identifier("args")
type = irBuiltIns.arrayClass.typeWith(klass.defaultType).makeNullable()
varargElementType = klass.defaultType
}
}
}
val getDeclaredField: IrSimpleFunctionSymbol =
javaLangClass.functionByName("getDeclaredField")
val getDeclaredMethod: IrSimpleFunctionSymbol =
javaLangClass.functionByName("getDeclaredMethod")
val getDeclaredConstructor: IrSimpleFunctionSymbol =
javaLangClass.functionByName("getDeclaredConstructor")
val javaLangReflectFieldGet: IrSimpleFunctionSymbol =
javaLangReflectField.functionByName("get")
val javaLangReflectFieldSet: IrSimpleFunctionSymbol =
javaLangReflectField.functionByName("set")
val javaLangReflectMethodInvoke: IrSimpleFunctionSymbol =
javaLangReflectMethod.functionByName("invoke")
val javaLangReflectConstructorNewInstance: IrSimpleFunctionSymbol =
javaLangReflectConstructor.functionByName("newInstance")
private val javaLangDeprecatedWithDeprecatedFlag: IrClassSymbol =
createClass(FqName("java.lang.Deprecated"), classKind = ClassKind.ANNOTATION_CLASS) { klass ->
klass.addConstructor { isPrimary = true }
@@ -630,6 +537,10 @@ class JvmSymbols(
}
}
val javaLangReflectSymbols: JvmReflectSymbols by lazy {
JvmReflectSymbols(context)
}
override val functionAdapter: IrClassSymbol = createClass(FqName("kotlin.jvm.internal.FunctionAdapter"), ClassKind.INTERFACE) { klass ->
klass.addFunction("getFunctionDelegate", irBuiltIns.functionClass.starProjectedType, Modality.ABSTRACT)
}
@@ -1198,8 +1109,8 @@ class JvmSymbols(
}
}
private fun IrClassSymbol.functionByName(name: String): IrSimpleFunctionSymbol =
fun IrClassSymbol.functionByName(name: String): IrSimpleFunctionSymbol =
functions.single { it.owner.name.asString() == name }
private fun IrClassSymbol.fieldByName(name: String): IrFieldSymbol =
fun IrClassSymbol.fieldByName(name: String): IrFieldSymbol =
fields.single { it.owner.name.asString() == name }