Support passing property as argument to array constructor in interpreter

This commit is contained in:
Ivan Kylchik
2021-06-02 16:13:13 +03:00
committed by TeamCityServer
parent 59fefb6214
commit 3326cbd9c0
4 changed files with 28 additions and 20 deletions
@@ -36,6 +36,7 @@ import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.util.hasAnnotation
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.util.OperatorNameConventions
import java.lang.invoke.MethodHandle
internal interface CallInterceptor {
@@ -74,7 +75,7 @@ internal class DefaultCallInterceptor(override val interpreter: IrInterpreter) :
receiver is Wrapper && !isInlineOnly -> receiver.getMethod(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 KFunctionState && call.symbol.owner.name == OperatorNameConventions.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 == null ->
@@ -171,9 +171,11 @@ 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
fun State?.getThisOrSuperReceiver(irFunction: IrFunction): State? {
// check if this function must be handled by super wrapper object
if (this !is Common || this.superWrapperClass == null || irFunction.parent !is IrClass) return this
if (superWrapperClass!!.irClass.isSubclassOf(irFunction.parentAsClass)) return superWrapperClass
return this
}
val owner = call.symbol.owner
@@ -184,7 +186,7 @@ class IrInterpreter private constructor(
// 2. get correct function for interpretation
val irFunction = dispatchReceiver?.getIrFunctionByIrCall(call) ?: call.symbol.owner
val args = listOfNotNull(irFunction.mustBeHandledWithSuperOf(dispatchReceiver), extensionReceiver) + valueArguments
val args = listOfNotNull(dispatchReceiver.getThisOrSuperReceiver(irFunction), extensionReceiver) + valueArguments
callStack.dropSubFrame() // drop intermediate frame that contains variables for default arg evaluation
callStack.newFrame(irFunction)
@@ -194,11 +196,9 @@ 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 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) }
irFunction.getDispatchReceiver()?.let { dispatchReceiver?.let { receiver -> callStack.addVariable(Variable(it, receiver)) } }
irFunction.getExtensionReceiver()?.let { callStack.addVariable(Variable(it, extensionReceiver ?: valueArguments.removeFirst())) }
irFunction.valueParameters.forEach { callStack.addVariable(Variable(it.symbol, valueArguments.removeFirst())) }
// 4. store reified type parameters
irFunction.typeParameters.filter { it.isReified }
@@ -592,8 +592,10 @@ class IrInterpreter private constructor(
val extensionReceiver = reference.extensionReceiver?.let { callStack.getState(irFunction.getExtensionReceiver()!!) }
callStack.dropSubFrame()
irFunction.getDispatchReceiver()?.let { dispatchReceiver?.let { receiver -> function.fields += Variable(it, receiver) } }
irFunction.getExtensionReceiver()?.let { extensionReceiver?.let { receiver -> function.fields += Variable(it, receiver) } }
// receivers in fields are used in comparison of two functions in KFunctionProxy
dispatchReceiver?.let { function.fields += Variable(irFunction.getDispatchReceiver()!!, it) }
extensionReceiver?.let { function.fields += Variable(irFunction.getExtensionReceiver()!!, it) }
function.upValues += function.fields
if (irFunction.isLocal) callStack.storeUpValues(function)
callStack.pushState(function)
@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.ir.interpreter.*
import org.jetbrains.kotlin.ir.interpreter.exceptions.handleUserException
import org.jetbrains.kotlin.ir.interpreter.state.*
import org.jetbrains.kotlin.ir.interpreter.state.reflection.KFunctionState
import org.jetbrains.kotlin.ir.interpreter.state.reflection.KPropertyState
import org.jetbrains.kotlin.ir.interpreter.state.reflection.KTypeState
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.types.impl.buildSimpleType
@@ -217,19 +218,23 @@ internal object ArrayConstructor : IntrinsicBase() {
override fun unwind(irFunction: IrFunction, environment: IrInterpreterEnvironment): List<Instruction> {
if (irFunction.valueParameters.size == 1) return listOf(customEvaluateInstruction(irFunction, environment))
val callStack = environment.callStack
val instructions = mutableListOf<Instruction>(customEvaluateInstruction(irFunction, environment))
val sizeDescriptor = irFunction.valueParameters[0].symbol
val size = environment.callStack.getState(sizeDescriptor).asInt()
val sizeSymbol = irFunction.valueParameters[0].symbol
val size = callStack.getState(sizeSymbol).asInt()
val initSymbol = irFunction.valueParameters[1].symbol
val function = when (val state = callStack.getState(initSymbol)) {
is KFunctionState -> state.irFunction.apply { callStack.loadUpValues(state) }
is KPropertyState -> state.property.getter
else -> TODO("Unsupported `init` in array constructor: $state")
} as IrSimpleFunction
val initDescriptor = irFunction.valueParameters[1].symbol
val initLambda = environment.callStack.getState(initDescriptor) as KFunctionState
environment.callStack.loadUpValues(initLambda)
val function = initLambda.irFunction as IrSimpleFunction
val index = initLambda.irFunction.valueParameters.single()
for (i in size - 1 downTo 0) {
val call = IrCallImpl.fromSymbolOwner(UNDEFINED_OFFSET, UNDEFINED_OFFSET, function.returnType, function.symbol)
call.putValueArgument(0, IrConstImpl.int(UNDEFINED_OFFSET, UNDEFINED_OFFSET, index.type, i))
val arg = IrConstImpl.int(UNDEFINED_OFFSET, UNDEFINED_OFFSET, environment.irBuiltIns.intType, i)
if (function.correspondingPropertySymbol == null) call.putValueArgument(0, arg) else call.extensionReceiver = arg
instructions += CompoundInstruction(call)
}
Binary file not shown.