Put all logic of working with expect/actual declarations inside Wrapper

For now decision of how to work with class or function is made by their
signatures.
This commit is contained in:
Ivan Kylchik
2021-05-19 16:15:34 +03:00
committed by TeamCityServer
parent 0cc866a2fb
commit 3b250132d0
2 changed files with 70 additions and 42 deletions
@@ -66,11 +66,11 @@ internal class DefaultCallInterceptor(override val interpreter: IrInterpreter) :
val isInlineOnly = irFunction.hasAnnotation(FqName("kotlin.internal.InlineOnly"))
when {
receiver is Wrapper && !isInlineOnly -> receiver.getMethod(irFunction).invokeMethod(irFunction, args)
irFunction.hasAnnotation(evaluateIntrinsicAnnotation) -> Wrapper.getStaticMethod(irFunction).invokeMethod(irFunction, args)
Wrapper.mustBeHandledWithWrapper(irFunction) -> Wrapper.getStaticMethod(irFunction).invokeMethod(irFunction, args)
handleIntrinsicMethods(irFunction) -> return
receiver is KFunctionState && call.symbol.owner.name.asString() == "invoke" -> handleInvoke(call, receiver, args)
receiver is ReflectionState -> Wrapper.getReflectionMethod(irFunction).invokeMethod(irFunction, args)
receiver is Primitive<*> -> calculateBuiltIns(irFunction, args) // check for js char, js long and get field for primitives
irFunction.body is IrSyntheticBody -> handleIntrinsicMethods(irFunction)
irFunction.body == null ->
irFunction.trySubstituteFunctionBody() ?: irFunction.tryCalculateLazyConst() ?: calculateBuiltIns(irFunction, args)
else -> defaultAction()
@@ -128,17 +128,17 @@ internal class DefaultCallInterceptor(override val interpreter: IrInterpreter) :
override fun interceptConstructor(
constructorCall: IrFunctionAccessExpression, receiver: State, args: List<State>, defaultAction: () -> Unit
) {
val constructor = constructorCall.symbol.owner
val irClass = constructor.parentAsClass
val irConstructor = constructorCall.symbol.owner
val irClass = irConstructor.parentAsClass
when {
irClass.hasAnnotation(evaluateIntrinsicAnnotation) || irClass.fqNameWhenAvailable!!.startsWith(Name.identifier("java")) -> {
Wrapper.getConstructorMethod(constructor).invokeMethod(constructor, args)
Wrapper.mustBeHandledWithWrapper(irClass) || irClass.fqNameWhenAvailable!!.startsWith(Name.identifier("java")) -> {
Wrapper.getConstructorMethod(irConstructor).invokeMethod(irConstructor, args)
if (constructorCall !is IrConstructorCall) (receiver as Common).superWrapperClass = callStack.popState() as Wrapper
}
irClass.defaultType.isArray() || irClass.defaultType.isPrimitiveArray() -> {
// array constructor doesn't have body so must be treated separately
callStack.addVariable(Variable(constructor.symbol, KTypeState(constructorCall.type, irBuiltIns.anyClass.owner)))
handleIntrinsicMethods(constructor)
callStack.addVariable(Variable(irConstructor.symbol, KTypeState(constructorCall.type, irBuiltIns.anyClass.owner)))
assert(handleIntrinsicMethods(irConstructor)) { "Unsupported intrinsic constructor: ${irConstructor.render()}" }
}
irClass.defaultType.isUnsignedType() -> {
val propertySymbol = irClass.declarations.single { it is IrProperty }.symbol
@@ -151,7 +151,7 @@ internal class DefaultCallInterceptor(override val interpreter: IrInterpreter) :
override fun interceptGetObjectValue(expression: IrGetObjectValue, defaultAction: () -> Unit) {
val objectClass = expression.symbol.owner
when {
objectClass.hasAnnotation(evaluateIntrinsicAnnotation) -> {
Wrapper.mustBeHandledWithWrapper(objectClass) -> {
val result = Wrapper.getCompanionObject(objectClass)
environment.mapOfObjects[expression.symbol] = result
callStack.pushState(result)
@@ -162,12 +162,11 @@ internal class DefaultCallInterceptor(override val interpreter: IrInterpreter) :
override fun interceptEnumEntry(enumEntry: IrEnumEntry, defaultAction: () -> Unit) {
val enumClass = enumEntry.symbol.owner.parentAsClass
when {
enumClass.hasAnnotation(evaluateIntrinsicAnnotation) -> {
Wrapper.mustBeHandledWithWrapper(enumClass) -> {
val enumEntryName = enumEntry.name.asString().toState(environment.irBuiltIns.stringType)
val valueOfFun = enumClass.declarations.single { it.nameForIrSerialization.asString() == "valueOf" } as IrFunction
Wrapper.getEnumEntry(enumClass)!!.invokeMethod(valueOfFun, listOf(enumEntryName))
Wrapper.getEnumEntry(enumClass).invokeMethod(valueOfFun, listOf(enumEntryName))
environment.mapOfEnums[enumEntry.symbol] = callStack.popState() as Complex
}
else -> defaultAction()
@@ -178,7 +177,7 @@ internal class DefaultCallInterceptor(override val interpreter: IrInterpreter) :
val field = expression.symbol.owner
assert(field.origin == IrDeclarationOrigin.IR_EXTERNAL_JAVA_DECLARATION_STUB && field.isStatic)
assert(field.initializer?.expression !is IrConst<*>)
callStack.pushState(Wrapper.getStaticGetter(field)!!.invokeWithArguments().toState(field.type))
callStack.pushState(Wrapper.getStaticGetter(field).invokeWithArguments().toState(field.type))
}
private fun MethodHandle?.invokeMethod(irFunction: IrFunction, args: List<State>) {
@@ -6,20 +6,13 @@
package org.jetbrains.kotlin.ir.interpreter.state
import org.jetbrains.kotlin.builtins.functions.BuiltInFunctionArity
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrField
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.interpreter.*
import org.jetbrains.kotlin.ir.interpreter.evaluateIntrinsicAnnotation
import org.jetbrains.kotlin.ir.interpreter.stack.Variable
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.defaultType
import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable
import org.jetbrains.kotlin.ir.util.isInterface
import org.jetbrains.kotlin.ir.util.parentAsClass
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.util.capitalizeDecapitalize.capitalizeAsciiOnly
import java.lang.invoke.MethodHandle
import java.lang.invoke.MethodHandles
@@ -54,7 +47,12 @@ internal class Wrapper(val value: Any, override val irClass: IrClass) : Complex
javaClassToIrClass += AbstractMap.SimpleImmutableEntry::class.java to irClass.declarations.filterIsInstance<IrClass>().single()
}
}
javaClassToIrClass += value::class.java to irClass
if (javaClassToIrClass[value::class.java].let { it == null || irClass.isSubclassOf(it) }) {
// second condition guarantees that implementation class will not be replaced with its interface
// for example: map will store ArrayList instead of just List
// this is needed for parallel calculations
javaClassToIrClass[value::class.java] = irClass
}
}
constructor(value: Any) : this(value, javaClassToIrClass[value::class.java]!!)
@@ -62,7 +60,6 @@ internal class Wrapper(val value: Any, override val irClass: IrClass) : Complex
override fun getIrFunctionByIrCall(expression: IrCall): IrFunction? = null
fun getMethod(irFunction: IrFunction): MethodHandle? {
if (irFunction.getEvaluateIntrinsicValue()?.isEmpty() == true) return null // this method will handle IntrinsicEvaluator
// if function is actually a getter, then use "get${property.name.capitalize()}" as method name
val propertyName = (irFunction as? IrSimpleFunction)?.correspondingPropertySymbol?.owner?.name?.asString()
val propertyCall = listOfNotNull(propertyName, "get${propertyName?.capitalizeAsciiOnly()}")
@@ -93,10 +90,47 @@ internal class Wrapper(val value: Any, override val irClass: IrClass) : Complex
private val companionObjectValue = mapOf<String, Any>("kotlin.text.Regex\$Companion" to Regex.Companion)
private val javaClassToIrClass = mutableMapOf<Class<*>, IrClass>()
// TODO remove later; used for tests only
private val intrinsicClasses = setOf(
"kotlin.text.StringBuilder", "kotlin.Pair", "kotlin.collections.HashMap",
"kotlin.text.RegexOption", "kotlin.text.Regex", "kotlin.text.Regex.Companion", "kotlin.text.MatchGroup",
)
private val intrinsicFunctionToHandler = mapOf(
"Array.kotlin.collections.asList()" to "kotlin.collections.ArraysKt",
"kotlin.collections.mutableListOf(Array)" to "kotlin.collections.CollectionsKt",
"kotlin.collections.arrayListOf(Array)" to "kotlin.collections.CollectionsKt",
"Char.kotlin.text.isWhitespace()" to "kotlin.text.CharsKt",
"Array.kotlin.collections.toMutableList()" to "kotlin.collections.ArraysKt",
)
fun associateJavaClassWithIrClass(javaClass: Class<*>, irClass: IrClass) {
javaClassToIrClass += javaClass to irClass
}
private fun IrDeclarationWithName.getSignature(): String? {
val fqName = this.fqNameWhenAvailable?.asString()
return when (this) {
is IrFunction -> {
val receiver = (dispatchReceiverParameter ?: extensionReceiverParameter)?.type?.getOnlyName()?.let { "$it." } ?: ""
this.valueParameters.joinToString(prefix = "$receiver$fqName(", postfix = ")") { it.type.getOnlyName() }
}
else -> fqName
}
}
private fun IrFunction.getJvmClassName(): String? {
return intrinsicFunctionToHandler[this.getSignature()]
}
fun mustBeHandledWithWrapper(declaration: IrDeclarationWithName): Boolean {
val fqName = declaration.fqNameWhenAvailable?.asString()
return when (declaration) {
is IrFunction -> declaration.getSignature() in intrinsicFunctionToHandler
else -> fqName in intrinsicClasses || fqName?.startsWith("java") == true
}
}
fun getReflectionMethod(irFunction: IrFunction): MethodHandle {
val receiverClass = irFunction.dispatchReceiverParameter!!.type.getClass(asObject = true)
val methodType = irFunction.getMethodType()
@@ -115,41 +149,40 @@ internal class Wrapper(val value: Any, override val irClass: IrClass) : Complex
}
fun getCompanionObject(irClass: IrClass): Wrapper {
val objectName = irClass.getEvaluateIntrinsicValue()!!
val objectName = irClass.internalName()
val objectValue = companionObjectValue[objectName] ?: throw InternalError("Companion object $objectName cannot be interpreted")
return Wrapper(objectValue, irClass)
}
fun getConstructorMethod(irConstructor: IrFunction): MethodHandle? {
val intrinsicValue = irConstructor.parentAsClass.getEvaluateIntrinsicValue()
if (intrinsicValue == "kotlin.Char" || intrinsicValue == "kotlin.Long") return null
val intrinsicValue = irConstructor.parentAsClass.internalName()
if (intrinsicValue == "kotlin.Char" || intrinsicValue == "kotlin.Long") return null // used in JS, must be handled as intrinsics
val methodType = irConstructor.getMethodType()
return MethodHandles.lookup().findConstructor(irConstructor.returnType.getClass(true), methodType)
}
fun getStaticMethod(irFunction: IrFunction): MethodHandle? {
val intrinsicName = irFunction.getEvaluateIntrinsicValue()
if (intrinsicName?.isEmpty() == true) return null
val jvmClassName = Class.forName(intrinsicName!!)
val intrinsicName = irFunction.getJvmClassName()
if (intrinsicName?.isEmpty() != false) return null
val jvmClass = Class.forName(intrinsicName)
val methodType = irFunction.getMethodType()
return MethodHandles.lookup().findStatic(jvmClassName, irFunction.name.asString(), methodType)
return MethodHandles.lookup().findStatic(jvmClass, irFunction.name.asString(), methodType)
}
fun getStaticGetter(field: IrField): MethodHandle? {
fun getStaticGetter(field: IrField): MethodHandle {
val jvmClass = field.parentAsClass.defaultType.getClass(true)
val returnType = field.type.let { it.getClass((it as IrSimpleType).hasQuestionMark) }
return MethodHandles.lookup().findStaticGetter(jvmClass, field.name.asString(), returnType)
}
fun getEnumEntry(enumClass: IrClass): MethodHandle? {
val intrinsicName = enumClass.getEvaluateIntrinsicValue()
if (intrinsicName?.isEmpty() == true) return null
val enumClassName = Class.forName(intrinsicName!!)
fun getEnumEntry(irEnumClass: IrClass): MethodHandle {
val intrinsicName = irEnumClass.internalName()
val jvmEnumClass = Class.forName(intrinsicName)
val methodType = MethodType.methodType(enumClassName, String::class.java)
return MethodHandles.lookup().findStatic(enumClassName, "valueOf", methodType)
val methodType = MethodType.methodType(jvmEnumClass, String::class.java)
return MethodHandles.lookup().findStatic(jvmEnumClass, "valueOf", methodType)
}
private fun IrFunction.getMethodType(): MethodType {
@@ -207,10 +240,6 @@ internal class Wrapper(val value: Any, override val irClass: IrClass) : Complex
fqName == "kotlin.collections.ListIterator" || fqName == "kotlin.collections.MutableListIterator" -> ListIterator::class.java
fqName == "kotlin.collections.Iterator" || fqName == "kotlin.collections.MutableIterator" -> Iterator::class.java
fqName == "kotlin.collections.Map.Entry" || fqName == "kotlin.collections.MutableMap.MutableEntry" -> Map.Entry::class.java
fqName == "kotlin.collections.ListIterator" || fqName == "kotlin.collections.MutableListIterator" -> ListIterator::class.java
fqName == "kotlin.collections.HashMap" -> HashMap::class.java
owner.hasAnnotation(evaluateIntrinsicAnnotation) -> Class.forName(owner!!.getEvaluateIntrinsicValue())
fqName == null -> Any::class.java // null if this.isTypeParameter()
else -> Class.forName(owner.internalName())
}