diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/InstructionsUnfolder.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/InstructionsUnfolder.kt index 716436ee6b5..2594e35ad72 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/InstructionsUnfolder.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/InstructionsUnfolder.kt @@ -83,84 +83,67 @@ private fun unfoldConstructor(constructor: IrConstructor, callStack: CallStack) } private fun unfoldCall(call: IrCall, callStack: CallStack) { - val function = call.symbol.owner - // new sub frame is used to store value arguments, in case then they are used in default args evaluation - callStack.newSubFrame(call, listOf()) - callStack.addInstruction(SimpleInstruction(call)) unfoldValueParameters(call, callStack) - - // must save receivers in memory in case then they are used in default args evaluation - call.extensionReceiver?.let { - callStack.addInstruction(SimpleInstruction(function.extensionReceiverParameter!!)) - callStack.addInstruction(CompoundInstruction(it)) - } - call.dispatchReceiver?.let { - callStack.addInstruction(SimpleInstruction(function.dispatchReceiverParameter!!)) - callStack.addInstruction(CompoundInstruction(it)) - } } private fun unfoldConstructorCall(constructorCall: IrFunctionAccessExpression, callStack: CallStack) { val constructor = constructorCall.symbol.owner - callStack.newSubFrame(constructorCall, listOf()) // used to store value arguments, in case then they are use as default args + unfoldValueParameters(constructorCall, callStack) // this variable is used to create object once callStack.addVariable(Variable(constructorCall.getThisReceiver(), Common(constructor.parentAsClass))) - callStack.addInstruction(SimpleInstruction(constructorCall)) - unfoldValueParameters(constructorCall, callStack) - - constructorCall.dispatchReceiver?.let { - callStack.addInstruction(SimpleInstruction(constructor.dispatchReceiverParameter!!)) - callStack.addInstruction(CompoundInstruction(it)) - } } private fun unfoldEnumConstructorCall(enumConstructorCall: IrEnumConstructorCall, callStack: CallStack) { - callStack.newSubFrame(enumConstructorCall, listOf()) // used to store value arguments, in case then they are use as default args - callStack.addInstruction(SimpleInstruction(enumConstructorCall)) unfoldValueParameters(enumConstructorCall, callStack) } private fun unfoldDelegatingConstructorCall(delegatingConstructorCall: IrFunctionAccessExpression, callStack: CallStack) { - callStack.newSubFrame(delegatingConstructorCall, listOf()) // used to store value arguments, in case then they are use as default args - callStack.addInstruction(SimpleInstruction(delegatingConstructorCall)) unfoldValueParameters(delegatingConstructorCall, callStack) } private fun unfoldValueParameters(expression: IrFunctionAccessExpression, callStack: CallStack) { - fun IrValueParameter.getDefault(): IrExpressionBody? { - return defaultValue - ?: (this.parent as? IrSimpleFunction)?.overriddenSymbols - ?.map { it.owner.valueParameters[this.index].getDefault() } - ?.firstNotNullOfOrNull { it } - } + val irFunction = expression.symbol.owner + // new sub frame is used to store value arguments, in case then they are used in default args evaluation + callStack.newSubFrame(expression, listOf(SimpleInstruction(expression))) fun getDefaultForParameterAt(index: Int): IrExpression? { - return expression.symbol.owner.valueParameters[index].getDefault()?.expression - } - - val irFunction = expression.symbol.owner - val valueParametersSymbols = irFunction.valueParameters.map { it.symbol } - val valueArguments = (0 until expression.valueArgumentsCount).map { expression.getValueArgument(it) } - - for (i in valueParametersSymbols.indices.reversed()) { - callStack.addInstruction(SimpleInstruction(valueParametersSymbols[i].owner)) - val arg = valueArguments[i] ?: getDefaultForParameterAt(i) - when { - arg != null -> callStack.addInstruction(CompoundInstruction(arg)) - else -> - // case when value parameter is vararg and it is missing - expression.getVarargType(i)?.let { - callStack.addInstruction(SimpleInstruction(IrConstImpl.constNull(UNDEFINED_OFFSET, UNDEFINED_OFFSET, it))) - } + fun IrValueParameter.getDefault(): IrExpressionBody? { + return defaultValue + ?: (this.parent as? IrSimpleFunction)?.overriddenSymbols + ?.map { it.owner.valueParameters[this.index].getDefault() } + ?.firstNotNullOfOrNull { it } } + + return irFunction.valueParameters[index].getDefault()?.expression } - // hack for extension receiver in lambda - if (expression.valueArgumentsCount != irFunction.valueParameters.size) { - val extensionReceiver = irFunction.getExtensionReceiver() ?: return - callStack.addInstruction(SimpleInstruction(extensionReceiver.owner)) - valueArguments[0]?.let { callStack.addInstruction(CompoundInstruction(it)) } + val valueParametersSymbols = irFunction.valueParameters.map { it.symbol } + + // interpret defaults for null arguments (at the end) + (expression.valueArgumentsCount - 1 downTo 0).forEach { index -> + if (expression.getValueArgument(index) != null) return@forEach + callStack.addInstruction(SimpleInstruction(valueParametersSymbols[index].owner)) + + getDefaultForParameterAt(index) + ?.let { callStack.addInstruction(CompoundInstruction(it)) } + ?: expression.getVarargType(index)?.let { // case when value parameter is vararg and it is missing + callStack.addInstruction(SimpleInstruction(IrConstImpl.constNull(UNDEFINED_OFFSET, UNDEFINED_OFFSET, it))) + } } + + // interpret not null arguments (after evaluation of arguments) + expression.dispatchReceiver?.let { callStack.addInstruction(SimpleInstruction(irFunction.dispatchReceiverParameter!!)) } + expression.extensionReceiver?.let { callStack.addInstruction(SimpleInstruction(irFunction.extensionReceiverParameter!!)) } + (0 until expression.valueArgumentsCount).forEach { + if (expression.getValueArgument(it) != null) callStack.addInstruction(SimpleInstruction(irFunction.valueParameters[it])) + } + + // evaluate arguments + (expression.valueArgumentsCount - 1 downTo 0).forEach { + callStack.addInstruction(CompoundInstruction(expression.getValueArgument(it))) + } + expression.extensionReceiver?.let { callStack.addInstruction(CompoundInstruction(it)) } + expression.dispatchReceiver?.let { callStack.addInstruction(CompoundInstruction(it)) } } private fun unfoldInstanceInitializerCall(instanceInitializerCall: IrInstanceInitializerCall, callStack: CallStack) { @@ -360,7 +343,7 @@ private fun unfoldStringConcatenation(expression: IrStringConcatenation, environ toStringCall.dispatchReceiver = IrConstImpl.constNull(0, 0, receiver.type) // just stub receiver callStack.newSubFrame(toStringCall, listOf(SimpleInstruction(toStringCall))) - callStack.pushState(state) + callStack.addVariable(Variable(receiver.symbol, state)) } } } @@ -382,22 +365,21 @@ private fun unfoldComposite(element: IrComposite, callStack: CallStack) { private fun unfoldFunctionReference(reference: IrFunctionReference, callStack: CallStack) { val function = reference.symbol.owner - callStack.newSubFrame(reference, listOf()) - callStack.addInstruction(SimpleInstruction(reference)) + callStack.newSubFrame(reference, listOf(SimpleInstruction(reference))) - reference.extensionReceiver?.let { - callStack.addInstruction(SimpleInstruction(function.extensionReceiverParameter!!)) - callStack.addInstruction(CompoundInstruction(it)) - } - reference.dispatchReceiver?.let { - callStack.addInstruction(SimpleInstruction(function.dispatchReceiverParameter!!)) - callStack.addInstruction(CompoundInstruction(it)) - } + reference.dispatchReceiver?.let { callStack.addInstruction(SimpleInstruction(function.dispatchReceiverParameter!!)) } + reference.extensionReceiver?.let { callStack.addInstruction(SimpleInstruction(function.extensionReceiverParameter!!)) } + + reference.extensionReceiver?.let { callStack.addInstruction(CompoundInstruction(it)) } + reference.dispatchReceiver?.let { callStack.addInstruction(CompoundInstruction(it)) } } private fun unfoldPropertyReference(propertyReference: IrPropertyReference, callStack: CallStack) { callStack.addInstruction(SimpleInstruction(propertyReference)) - callStack.addInstruction(CompoundInstruction(propertyReference.dispatchReceiver)) + propertyReference.dispatchReceiver?.let { + callStack.addInstruction(SimpleInstruction(propertyReference.getter!!.owner.dispatchReceiverParameter!!)) + callStack.addInstruction(CompoundInstruction(it)) + } } private fun unfoldClassReference(classReference: IrClassReference, callStack: CallStack) { diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/IrInterpreter.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/IrInterpreter.kt index daee54f18f6..48349659811 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/IrInterpreter.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/IrInterpreter.kt @@ -163,14 +163,14 @@ class IrInterpreter private constructor( //must add value argument in current stack because it can be used later as default argument callStack.addVariable(Variable(valueParameter.symbol, state)) - callStack.pushState(state) } private fun interpretCall(call: IrCall) { + val owner = call.symbol.owner // 1. load evaluated arguments from stack - val valueArguments = call.symbol.owner.valueParameters.map { callStack.popState() }.reversed() - val extensionReceiver = call.extensionReceiver?.let { callStack.popState() } - var dispatchReceiver = call.dispatchReceiver?.let { callStack.popState() } + var dispatchReceiver = call.dispatchReceiver?.let { callStack.getVariable(owner.getDispatchReceiver()!!) }?.state + val extensionReceiver = call.extensionReceiver?.let { callStack.getVariable(owner.getExtensionReceiver()!!) }?.state + val valueArguments = owner.valueParameters.map { callStack.getVariable(it.symbol).state } // 2. get correct function for interpretation val irFunction = dispatchReceiver?.getIrFunctionByIrCall(call) ?: call.symbol.owner @@ -179,13 +179,13 @@ class IrInterpreter private constructor( else -> dispatchReceiver } - callStack.dropSubFrame() + callStack.dropSubFrame() // drop intermediate frame that contains variables for default arg evaluation callStack.newFrame(irFunction, listOf(SimpleInstruction(irFunction))) // TODO: if using KTypeState then it's class must be corresponding // `call.type` is used in check cast and emptyArray callStack.addVariable(Variable(irFunction.symbol, KTypeState(call.type, irBuiltIns.anyClass.owner))) - // 3. store arguments in memory + // 3. store arguments in memory (remap args on actual names) val args = mutableListOf() irFunction.getDispatchReceiver()?.let { dispatchReceiver?.let { receiver -> args.add(Variable(it, receiver)) } } irFunction.getExtensionReceiver()?.let { args.add(Variable(it, extensionReceiver ?: valueArguments.first())) } @@ -241,12 +241,12 @@ class IrInterpreter private constructor( } private fun interpretConstructorCall(constructorCall: IrFunctionAccessExpression) { - val valueArguments = constructorCall.symbol.owner.valueParameters.map { callStack.popState() }.reversed() + val valueArguments = constructorCall.symbol.owner.valueParameters.map { callStack.getVariable(it.symbol).state } val constructor = constructorCall.symbol.owner val irClass = constructor.parentAsClass val objectVar = callStack.getVariable(constructorCall.getThisReceiver()) if (irClass.isLocal) callStack.storeUpValues(objectVar.state as StateWithClosure) - val outerClass = if (irClass.isInner) callStack.popState() else null + val outerClass = if (irClass.isInner) callStack.getVariable(constructor.dispatchReceiverParameter!!.symbol).state else null callStack.dropSubFrame() callStack.newFrame(constructor, listOf(SimpleInstruction(constructor))) @@ -564,8 +564,8 @@ class IrInterpreter private constructor( val function = KFunctionState(reference) val irFunction = function.irFunction - val extensionReceiver = reference.extensionReceiver?.let { callStack.popState() } - val dispatchReceiver = reference.dispatchReceiver?.let { callStack.popState() } + val dispatchReceiver = reference.dispatchReceiver?.let { callStack.getVariable(irFunction.getDispatchReceiver()!!) }?.state + val extensionReceiver = reference.extensionReceiver?.let { callStack.getVariable(irFunction.getExtensionReceiver()!!) }?.state callStack.dropSubFrame() irFunction.getDispatchReceiver()?.let { dispatchReceiver?.let { receiver -> function.fields.add(Variable(it, receiver)) } } @@ -576,7 +576,8 @@ class IrInterpreter private constructor( } private fun interpretPropertyReference(propertyReference: IrPropertyReference) { - val dispatchReceiver = propertyReference.dispatchReceiver?.let { callStack.popState() } + val dispatchReceiverSymbol = propertyReference.getter?.owner?.getDispatchReceiver() + val dispatchReceiver = propertyReference.dispatchReceiver?.let { callStack.getVariable(dispatchReceiverSymbol!!) }?.state // it is impossible to get KProperty2 through ::, so extension receiver is always null val propertyState = KPropertyState(propertyReference, dispatchReceiver) callStack.pushState(propertyState) diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/Utils.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/Utils.kt index 5981888cdda..5ab6fbdf935 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/Utils.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/Utils.kt @@ -179,11 +179,6 @@ fun IrFunctionAccessExpression.getVarargType(index: Int): IrType? { } } -internal fun State?.extractNonLocalDeclarations(): List { - this ?: return listOf() - return this.fields.filter { it.symbol !is IrFieldSymbol } -} - internal fun IrFunction.getCapitalizedFileName() = this.file.name.replace(".kt", "Kt").capitalizeAsciiOnly() internal fun IrType.isUnsigned() = this.isUByte() || this.isUShort() || this.isUInt() || this.isULong() diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/stack/CallStack.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/stack/CallStack.kt index ab43a53232e..536fa632ae5 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/stack/CallStack.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/stack/CallStack.kt @@ -187,7 +187,7 @@ internal class CallStack { } fun copyUpValuesFromPreviousFrame() { - frames[frames.size - 2].getAll().forEach { addVariable(it) } + frames[frames.size - 2].getAll().forEach { if (!containsVariable(it.symbol)) addVariable(it) } } fun getStackTrace(): List {