From e5ca646de4456333989cfecdd1f1cd0d7830767d Mon Sep 17 00:00:00 2001 From: Ivan Kylchik Date: Thu, 17 Jun 2021 13:57:47 +0300 Subject: [PATCH] Move object creation logic into constructor interpretation This newly created object is not used in arguments interpretation so there is no need to create it in InstructionsUnfolder. Moreover this object can interfere with other objects in memory, for example, when creating outer object from inner. --- .../ir/interpreter/InstructionsUnfolder.kt | 24 ++++--------------- .../kotlin/ir/interpreter/IrInterpreter.kt | 13 ++++++++-- .../kotlin/ir/interpreter/state/Complex.kt | 6 ++++- 3 files changed, 21 insertions(+), 22 deletions(-) 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 172aaf0ce52..801edeb039e 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 @@ -39,9 +39,9 @@ internal fun unfoldInstruction(element: IrElement?, environment: IrInterpreterEn is IrSimpleFunction -> unfoldFunction(element, environment) is IrConstructor -> unfoldConstructor(element, callStack) is IrCall -> unfoldCall(element, callStack) - is IrConstructorCall -> unfoldConstructorCall(element, environment) - is IrEnumConstructorCall -> unfoldEnumConstructorCall(element, callStack) - is IrDelegatingConstructorCall -> unfoldDelegatingConstructorCall(element, callStack) + is IrConstructorCall -> unfoldConstructorCall(element, callStack) + is IrEnumConstructorCall -> unfoldConstructorCall(element, callStack) + is IrDelegatingConstructorCall -> unfoldConstructorCall(element, callStack) is IrInstanceInitializerCall -> unfoldInstanceInitializerCall(element, callStack) is IrField -> unfoldField(element, callStack) is IrBody -> unfoldBody(element, callStack) @@ -113,23 +113,9 @@ private fun unfoldCall(call: IrCall, callStack: CallStack) { unfoldValueParameters(call, callStack) } -private fun unfoldConstructorCall(constructorCall: IrFunctionAccessExpression, environment: IrInterpreterEnvironment) { - val callStack = environment.callStack - val constructor = constructorCall.symbol.owner - val irClass = constructor.parentAsClass +// This function is responsible for IrConstructorCall, IrDelegatingConstructorCall and IrEnumConstructorCall +private fun unfoldConstructorCall(constructorCall: IrFunctionAccessExpression, callStack: CallStack) { unfoldValueParameters(constructorCall, callStack) - // this state is used to create object once - val state = if (irClass.isSubclassOfThrowable()) ExceptionState(irClass, callStack.getStackTrace()) else Common(irClass) - if (irClass.isObject) environment.mapOfObjects[irClass.symbol] = state // must set object's state here to avoid cyclic evaluation - callStack.addVariable(Variable(constructorCall.getThisReceiver(), state)) -} - -private fun unfoldEnumConstructorCall(enumConstructorCall: IrEnumConstructorCall, callStack: CallStack) { - unfoldValueParameters(enumConstructorCall, callStack) -} - -private fun unfoldDelegatingConstructorCall(delegatingConstructorCall: IrFunctionAccessExpression, callStack: CallStack) { - unfoldValueParameters(delegatingConstructorCall, callStack) } private fun unfoldValueParameters(expression: IrFunctionAccessExpression, 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 92cc3121541..5df049130d7 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 @@ -204,9 +204,9 @@ class IrInterpreter(internal val environment: IrInterpreterEnvironment, internal if (dispatchReceiver is Complex && irFunction.parentClassOrNull?.isInner == true) dispatchReceiver.loadOuterClassesInto(callStack) // 6. load up values onto stack - if (irFunction.isLocal) callStack.copyUpValuesFromPreviousFrame() if (dispatchReceiver is StateWithClosure) callStack.loadUpValues(dispatchReceiver) if (extensionReceiver is StateWithClosure) callStack.loadUpValues(extensionReceiver) + if (irFunction.isLocal) callStack.copyUpValuesFromPreviousFrame() callInterceptor.interceptCall(call, irFunction, args) { callStack.addInstruction(CompoundInstruction(irFunction)) @@ -243,7 +243,16 @@ class IrInterpreter(internal val environment: IrInterpreterEnvironment, internal val irClass = constructor.parentAsClass val receiverSymbol = constructor.dispatchReceiverParameter?.symbol - val objectState = callStack.getState(constructorCall.getThisReceiver()) + // this check is used to be sure that object will be created once + val objectState = when (constructorCall) { + !is IrConstructorCall -> callStack.getState(constructorCall.getThisReceiver()) + else -> (if (irClass.isSubclassOfThrowable()) ExceptionState(irClass, callStack.getStackTrace()) else Common(irClass)) + .apply { + // must set object's state here, before actual initialization, to avoid cyclic evaluation + if (irClass.isObject) environment.mapOfObjects[irClass.symbol] = this + } + } + if (irClass.isLocal) callStack.storeUpValues(objectState as StateWithClosure) val outerClass = receiverSymbol?.let { callStack.getState(it) } diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/Complex.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/Complex.kt index d374810d27e..7225e100960 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/Complex.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/Complex.kt @@ -49,6 +49,10 @@ internal interface Complex : State { } fun loadOuterClassesInto(callStack: CallStack) { - generateSequence(outerClass) { (it.state as? Complex)?.outerClass }.forEach { callStack.addVariable(it) } + generateSequence(outerClass) { (it.state as? Complex)?.outerClass } + .forEach { variable -> + callStack.addVariable(variable) + (variable.state as? StateWithClosure)?.let { callStack.loadUpValues(it) } + } } } \ No newline at end of file