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:
committed by
TeamCityServer
parent
0cc866a2fb
commit
3b250132d0
+12
-13
@@ -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>) {
|
||||
|
||||
+58
-29
@@ -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())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user