Simplify the interpretation logic of methods defined in super Wrapper
This commit is contained in:
committed by
TeamCityServer
parent
cf20e64c61
commit
23392b73a9
+7
-7
@@ -42,8 +42,8 @@ internal interface CallInterceptor {
|
||||
val interpreter: IrInterpreter
|
||||
|
||||
fun interceptProxy(irFunction: IrFunction, valueArguments: List<Variable>, expectedResultClass: Class<*> = Any::class.java): Any?
|
||||
fun interceptCall(call: IrCall, irFunction: IrFunction, receiver: State?, args: List<State>, defaultAction: () -> Unit)
|
||||
fun interceptConstructor(constructorCall: IrFunctionAccessExpression, receiver: State, args: List<State>, defaultAction: () -> Unit)
|
||||
fun interceptCall(call: IrCall, irFunction: IrFunction, args: List<State>, defaultAction: () -> Unit)
|
||||
fun interceptConstructor(constructorCall: IrFunctionAccessExpression, args: List<State>, defaultAction: () -> Unit)
|
||||
fun interceptGetObjectValue(expression: IrGetObjectValue, defaultAction: () -> Unit)
|
||||
fun interceptEnumEntry(enumEntry: IrEnumEntry, defaultAction: () -> Unit)
|
||||
fun interceptJavaStaticField(expression: IrGetField)
|
||||
@@ -65,8 +65,9 @@ internal class DefaultCallInterceptor(override val interpreter: IrInterpreter) :
|
||||
}.wrap(this@DefaultCallInterceptor, remainArraysAsIs = true, extendFrom = expectedResultClass)
|
||||
}
|
||||
|
||||
override fun interceptCall(call: IrCall, irFunction: IrFunction, receiver: State?, args: List<State>, defaultAction: () -> Unit) {
|
||||
override fun interceptCall(call: IrCall, irFunction: IrFunction, args: List<State>, defaultAction: () -> Unit) {
|
||||
val isInlineOnly = irFunction.hasAnnotation(FqName("kotlin.internal.InlineOnly"))
|
||||
val receiver = if (irFunction.dispatchReceiverParameter != null) args[0] else null
|
||||
when {
|
||||
receiver is Wrapper && !isInlineOnly -> receiver.getMethod(irFunction).invokeMethod(irFunction, args)
|
||||
Wrapper.mustBeHandledWithWrapper(irFunction) -> Wrapper.getStaticMethod(irFunction).invokeMethod(irFunction, args)
|
||||
@@ -123,14 +124,13 @@ internal class DefaultCallInterceptor(override val interpreter: IrInterpreter) :
|
||||
}
|
||||
|
||||
if (invokedFunction.symbol is IrConstructorSymbol) return
|
||||
this.interceptCall(call, function, dispatchReceiver, listOfNotNull(dispatchReceiver, extensionReceiver) + valueArguments) {
|
||||
this.interceptCall(call, function, listOfNotNull(dispatchReceiver, extensionReceiver) + valueArguments) {
|
||||
callStack.addInstruction(CompoundInstruction(function))
|
||||
}
|
||||
}
|
||||
|
||||
override fun interceptConstructor(
|
||||
constructorCall: IrFunctionAccessExpression, receiver: State, args: List<State>, defaultAction: () -> Unit
|
||||
) {
|
||||
override fun interceptConstructor(constructorCall: IrFunctionAccessExpression, args: List<State>, defaultAction: () -> Unit) {
|
||||
val receiver = callStack.getState(constructorCall.getThisReceiver())
|
||||
val irConstructor = constructorCall.symbol.owner
|
||||
val irClass = irConstructor.parentAsClass
|
||||
when {
|
||||
|
||||
+15
-15
@@ -170,18 +170,20 @@ class IrInterpreter private constructor(
|
||||
}
|
||||
|
||||
private fun interpretCall(call: IrCall) {
|
||||
fun IrFunction.mustBeHandledWithSuperOf(state: State?): State? {
|
||||
if (state is Common && this.parent == state.superWrapperClass?.irClass) return state.superWrapperClass
|
||||
return state
|
||||
}
|
||||
|
||||
val owner = call.symbol.owner
|
||||
// 1. load evaluated arguments from stack
|
||||
var dispatchReceiver = owner.getDispatchReceiver()?.let { callStack.getState(it) }
|
||||
val dispatchReceiver = owner.getDispatchReceiver()?.let { callStack.getState(it) }
|
||||
val extensionReceiver = owner.getExtensionReceiver()?.let { callStack.getState(it) }
|
||||
val valueArguments = owner.valueParameters.map { callStack.getState(it.symbol) }
|
||||
val valueArguments = owner.valueParameters.map { callStack.getState(it.symbol) }.toMutableList()
|
||||
|
||||
// 2. get correct function for interpretation
|
||||
val irFunction = dispatchReceiver?.getIrFunctionByIrCall(call) ?: call.symbol.owner
|
||||
dispatchReceiver = when (irFunction.parent) {
|
||||
(dispatchReceiver as? Complex)?.superWrapperClass?.irClass -> dispatchReceiver.superWrapperClass
|
||||
else -> dispatchReceiver
|
||||
}
|
||||
val args = listOfNotNull(irFunction.mustBeHandledWithSuperOf(dispatchReceiver), extensionReceiver) + valueArguments
|
||||
|
||||
callStack.dropSubFrame() // drop intermediate frame that contains variables for default arg evaluation
|
||||
callStack.newFrame(irFunction)
|
||||
@@ -191,13 +193,11 @@ class IrInterpreter private constructor(
|
||||
callStack.addVariable(Variable(irFunction.symbol, KTypeState(call.type, irBuiltIns.anyClass.owner)))
|
||||
|
||||
// 3. store arguments in memory (remap args on actual names)
|
||||
val args = mutableListOf<Variable>()
|
||||
irFunction.getDispatchReceiver()?.let { dispatchReceiver?.let { receiver -> args.add(Variable(it, receiver)) } }
|
||||
irFunction.getExtensionReceiver()?.let { args.add(Variable(it, extensionReceiver ?: valueArguments.first())) }
|
||||
// `shift` is used when extension receiver is actually a parameter in lambda
|
||||
val shift = if (irFunction.extensionReceiverParameter != null && extensionReceiver == null) 1 else 0
|
||||
irFunction.valueParameters.forEachIndexed { i, param -> args.add(Variable(param.symbol, valueArguments[i + shift])) }
|
||||
args.forEach { callStack.addVariable(it) }
|
||||
val variables = mutableListOf<Variable>()
|
||||
irFunction.getDispatchReceiver()?.let { dispatchReceiver?.let { receiver -> variables.add(Variable(it, receiver)) } }
|
||||
irFunction.getExtensionReceiver()?.let { variables.add(Variable(it, extensionReceiver ?: valueArguments.removeFirst())) }
|
||||
irFunction.valueParameters.forEach { variables.add(Variable(it.symbol, valueArguments.removeFirst())) }
|
||||
variables.forEach { callStack.addVariable(it) }
|
||||
|
||||
// 4. store reified type parameters
|
||||
irFunction.typeParameters.filter { it.isReified }
|
||||
@@ -213,7 +213,7 @@ class IrInterpreter private constructor(
|
||||
generateSequence(dispatchReceiver.outerClass) { (it.state as? Complex)?.outerClass }.forEach { callStack.addVariable(it) }
|
||||
}
|
||||
|
||||
callInterceptor.interceptCall(call, irFunction, dispatchReceiver, listOfNotNull(dispatchReceiver, extensionReceiver) + valueArguments) {
|
||||
callInterceptor.interceptCall(call, irFunction, args) {
|
||||
callStack.addInstruction(CompoundInstruction(irFunction))
|
||||
}
|
||||
}
|
||||
@@ -289,7 +289,7 @@ class IrInterpreter private constructor(
|
||||
}
|
||||
superReceiver?.let { callStack.addVariable(Variable(it, objectState)) }
|
||||
|
||||
callInterceptor.interceptConstructor(constructorCall, objectState, valueArguments) {
|
||||
callInterceptor.interceptConstructor(constructorCall, valueArguments) {
|
||||
callStack.pushState(objectState)
|
||||
callStack.addInstruction(CompoundInstruction(constructor))
|
||||
}
|
||||
|
||||
@@ -38,14 +38,6 @@ internal interface Complex: State {
|
||||
}
|
||||
}
|
||||
|
||||
private fun getThisOrSuperReceiver(superIrClass: IrClass?): IrClass? {
|
||||
return when {
|
||||
superIrClass == null -> this.irClass
|
||||
superIrClass.isInterface -> superIrClass
|
||||
else -> irClass.superTypes.map { it.classOrNull?.owner }.singleOrNull { it?.isInterface == false }
|
||||
}
|
||||
}
|
||||
|
||||
fun getOverridden(owner: IrSimpleFunction): IrSimpleFunction {
|
||||
if (owner.parent == superWrapperClass?.irClass) return owner
|
||||
if (!owner.isFakeOverride || owner.body != null || owner.parentAsClass.defaultType.isAny()) return owner
|
||||
@@ -55,7 +47,7 @@ internal interface Complex: State {
|
||||
}
|
||||
|
||||
override fun getIrFunctionByIrCall(expression: IrCall): IrFunction? {
|
||||
val receiver = getThisOrSuperReceiver(expression.superQualifierSymbol?.owner) ?: return null
|
||||
val receiver = expression.superQualifierSymbol?.owner ?: irClass
|
||||
val irFunction = getIrFunctionFromGivenClass(receiver, expression.symbol) ?: return null
|
||||
return getOverridden(irFunction as IrSimpleFunction)
|
||||
}
|
||||
|
||||
+13
-3
@@ -34,12 +34,12 @@ internal class Wrapper(val value: Any, override val irClass: IrClass) : Complex
|
||||
when {
|
||||
javaClass == HashMap::class.java -> {
|
||||
val nodeClass = javaClass.declaredClasses.single { it.name.contains("\$Node") }
|
||||
val mutableMap = irClass.superTypes.mapNotNull { it.classOrNull?.owner }.single { it.isInterface }
|
||||
val mutableMap = irClass.superTypes.mapNotNull { it.classOrNull?.owner }.single { it.name.asString() == "MutableMap" }
|
||||
javaClassToIrClass += nodeClass to mutableMap.declarations.filterIsInstance<IrClass>().single()
|
||||
}
|
||||
javaClass == LinkedHashMap::class.java -> {
|
||||
val entryClass = javaClass.declaredClasses.single { it.name.contains("\$Entry") }
|
||||
val mutableMap = irClass.superTypes.mapNotNull { it.classOrNull?.owner }.single { it.isInterface }
|
||||
val mutableMap = irClass.superTypes.mapNotNull { it.classOrNull?.owner }.single { it.name.asString() == "MutableMap" }
|
||||
javaClassToIrClass += entryClass to mutableMap.declarations.filterIsInstance<IrClass>().single()
|
||||
}
|
||||
javaClass.canonicalName == "java.util.Collections.SingletonMap" -> {
|
||||
@@ -92,7 +92,9 @@ internal class Wrapper(val value: Any, override val irClass: IrClass) : Complex
|
||||
|
||||
// TODO remove later; used for tests only
|
||||
private val intrinsicClasses = setOf(
|
||||
"kotlin.text.StringBuilder", "kotlin.Pair", "kotlin.collections.HashMap",
|
||||
"kotlin.text.StringBuilder", "kotlin.Pair", "kotlin.collections.ArrayList",
|
||||
"kotlin.collections.HashMap", "kotlin.collections.LinkedHashMap",
|
||||
"kotlin.collections.HashSet", "kotlin.collections.LinkedHashSet",
|
||||
"kotlin.text.RegexOption", "kotlin.text.Regex", "kotlin.text.Regex.Companion", "kotlin.text.MatchGroup",
|
||||
)
|
||||
|
||||
@@ -102,6 +104,7 @@ internal class Wrapper(val value: Any, override val irClass: IrClass) : Complex
|
||||
"kotlin.collections.arrayListOf(Array)" to "kotlin.collections.CollectionsKt",
|
||||
"Char.kotlin.text.isWhitespace()" to "kotlin.text.CharsKt",
|
||||
"Array.kotlin.collections.toMutableList()" to "kotlin.collections.ArraysKt",
|
||||
"Array.kotlin.collections.copyToArrayOfAny(Boolean)" to "kotlin.collections.CollectionsKt",
|
||||
)
|
||||
|
||||
fun associateJavaClassWithIrClass(javaClass: Class<*>, irClass: IrClass) {
|
||||
@@ -240,6 +243,13 @@ 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.ArrayList" -> ArrayList::class.java
|
||||
fqName == "kotlin.collections.HashMap" -> HashMap::class.java
|
||||
fqName == "kotlin.collections.HashSet" -> HashSet::class.java
|
||||
fqName == "kotlin.collections.LinkedHashMap" -> LinkedHashMap::class.java
|
||||
fqName == "kotlin.collections.LinkedHashSet" -> LinkedHashSet::class.java
|
||||
fqName == "kotlin.text.StringBuilder" -> StringBuilder::class.java
|
||||
fqName == "kotlin.text.Appendable" -> Appendable::class.java
|
||||
fqName == null -> Any::class.java // null if this.isTypeParameter()
|
||||
else -> Class.forName(owner.internalName())
|
||||
}
|
||||
|
||||
+14
-4
@@ -1,7 +1,7 @@
|
||||
import kotlin.collections.*
|
||||
|
||||
@CompileTimeCalculation
|
||||
class MyArrayList<E>: ArrayList<E>() {
|
||||
open class MyArrayList<E>: ArrayList<E>() {
|
||||
var addCounter = 0
|
||||
override fun add(element: E): Boolean {
|
||||
addCounter++
|
||||
@@ -10,12 +10,22 @@ class MyArrayList<E>: ArrayList<E>() {
|
||||
}
|
||||
|
||||
@CompileTimeCalculation
|
||||
fun test(): String {
|
||||
val list = MyArrayList<Int>()
|
||||
class MyOtherArrayList<E>: MyArrayList<E>() {
|
||||
override fun addAll(elements: Collection<E>): Boolean {
|
||||
return true // do nothing
|
||||
}
|
||||
}
|
||||
|
||||
@CompileTimeCalculation
|
||||
fun test(list: MyArrayList<Int>): String {
|
||||
list.add(1)
|
||||
list.add(2)
|
||||
list.add(3)
|
||||
|
||||
val otherList = arrayListOf(4, 5, 6)
|
||||
list.addAll(otherList)
|
||||
return "Counter " + list.addCounter + "; size " + list.size
|
||||
}
|
||||
|
||||
const val testResult = <!EVALUATED: `Counter 3; size 3`!>test()<!>
|
||||
const val testResult1 = <!EVALUATED: `Counter 3; size 6`!>test(MyArrayList<Int>())<!>
|
||||
const val testResult2 = <!EVALUATED: `Counter 3; size 3`!>test(MyOtherArrayList<Int>())<!>
|
||||
|
||||
Reference in New Issue
Block a user