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.
This commit is contained in:
Ivan Kylchik
2021-06-17 13:57:47 +03:00
committed by TeamCityServer
parent 1af1a3c84e
commit e5ca646de4
3 changed files with 21 additions and 22 deletions
@@ -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) {
@@ -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) }
@@ -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) }
}
}
}