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 IrSimpleFunction -> unfoldFunction(element, environment)
is IrConstructor -> unfoldConstructor(element, callStack) is IrConstructor -> unfoldConstructor(element, callStack)
is IrCall -> unfoldCall(element, callStack) is IrCall -> unfoldCall(element, callStack)
is IrConstructorCall -> unfoldConstructorCall(element, environment) is IrConstructorCall -> unfoldConstructorCall(element, callStack)
is IrEnumConstructorCall -> unfoldEnumConstructorCall(element, callStack) is IrEnumConstructorCall -> unfoldConstructorCall(element, callStack)
is IrDelegatingConstructorCall -> unfoldDelegatingConstructorCall(element, callStack) is IrDelegatingConstructorCall -> unfoldConstructorCall(element, callStack)
is IrInstanceInitializerCall -> unfoldInstanceInitializerCall(element, callStack) is IrInstanceInitializerCall -> unfoldInstanceInitializerCall(element, callStack)
is IrField -> unfoldField(element, callStack) is IrField -> unfoldField(element, callStack)
is IrBody -> unfoldBody(element, callStack) is IrBody -> unfoldBody(element, callStack)
@@ -113,23 +113,9 @@ private fun unfoldCall(call: IrCall, callStack: CallStack) {
unfoldValueParameters(call, callStack) unfoldValueParameters(call, callStack)
} }
private fun unfoldConstructorCall(constructorCall: IrFunctionAccessExpression, environment: IrInterpreterEnvironment) { // This function is responsible for IrConstructorCall, IrDelegatingConstructorCall and IrEnumConstructorCall
val callStack = environment.callStack private fun unfoldConstructorCall(constructorCall: IrFunctionAccessExpression, callStack: CallStack) {
val constructor = constructorCall.symbol.owner
val irClass = constructor.parentAsClass
unfoldValueParameters(constructorCall, 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) { 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) if (dispatchReceiver is Complex && irFunction.parentClassOrNull?.isInner == true) dispatchReceiver.loadOuterClassesInto(callStack)
// 6. load up values onto stack // 6. load up values onto stack
if (irFunction.isLocal) callStack.copyUpValuesFromPreviousFrame()
if (dispatchReceiver is StateWithClosure) callStack.loadUpValues(dispatchReceiver) if (dispatchReceiver is StateWithClosure) callStack.loadUpValues(dispatchReceiver)
if (extensionReceiver is StateWithClosure) callStack.loadUpValues(extensionReceiver) if (extensionReceiver is StateWithClosure) callStack.loadUpValues(extensionReceiver)
if (irFunction.isLocal) callStack.copyUpValuesFromPreviousFrame()
callInterceptor.interceptCall(call, irFunction, args) { callInterceptor.interceptCall(call, irFunction, args) {
callStack.addInstruction(CompoundInstruction(irFunction)) callStack.addInstruction(CompoundInstruction(irFunction))
@@ -243,7 +243,16 @@ class IrInterpreter(internal val environment: IrInterpreterEnvironment, internal
val irClass = constructor.parentAsClass val irClass = constructor.parentAsClass
val receiverSymbol = constructor.dispatchReceiverParameter?.symbol 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) if (irClass.isLocal) callStack.storeUpValues(objectState as StateWithClosure)
val outerClass = receiverSymbol?.let { callStack.getState(it) } val outerClass = receiverSymbol?.let { callStack.getState(it) }
@@ -49,6 +49,10 @@ internal interface Complex : State {
} }
fun loadOuterClassesInto(callStack: CallStack) { 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) }
}
} }
} }