From 877832ef8cfee76c55ba4c4f429b89b8a023fb67 Mon Sep 17 00:00:00 2001 From: Ivan Kylchik Date: Thu, 15 Apr 2021 16:45:10 +0300 Subject: [PATCH] Optimize some methods of CallStack and Frame --- .../kotlin/ir/interpreter/CallInterceptor.kt | 19 ++-- .../ir/interpreter/InstructionsUnfolder.kt | 43 +++++---- .../kotlin/ir/interpreter/IrInterpreter.kt | 91 ++++++++++--------- .../jetbrains/kotlin/ir/interpreter/Utils.kt | 3 +- .../intrinsics/IntrinsicImplementations.kt | 41 +++++---- .../ir/interpreter/proxy/CommonProxy.kt | 2 +- .../proxy/reflection/KProperty0Proxy.kt | 2 +- .../kotlin/ir/interpreter/stack/CallStack.kt | 77 ++++++++-------- .../kotlin/ir/interpreter/stack/Frame.kt | 75 +++++++-------- .../ir/interpreter/state/ExceptionState.kt | 6 +- .../kotlin/ir/interpreter/state/Primitive.kt | 2 +- .../kotlin/ir/interpreter/state/State.kt | 2 +- 12 files changed, 193 insertions(+), 170 deletions(-) diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/CallInterceptor.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/CallInterceptor.kt index f1134a61bcd..1f964dbf671 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/CallInterceptor.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/CallInterceptor.kt @@ -6,6 +6,7 @@ package org.jetbrains.kotlin.ir.interpreter import org.jetbrains.kotlin.ir.IrElement +import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns import org.jetbrains.kotlin.ir.expressions.* @@ -54,7 +55,9 @@ internal class DefaultCallInterceptor(override val interpreter: IrInterpreter) : private val bodyMap: Map = interpreter.bodyMap override fun interceptProxy(irFunction: IrFunction, valueArguments: List, expectedResultClass: Class<*>): Any? { - val irCall = IrCallImpl.fromSymbolOwner(0, 0, irFunction.returnType, irFunction.symbol as IrSimpleFunctionSymbol) + val irCall = IrCallImpl.fromSymbolOwner( + UNDEFINED_OFFSET, UNDEFINED_OFFSET, irFunction.returnType, irFunction.symbol as IrSimpleFunctionSymbol + ) return interpreter.withNewCallStack(irCall) { this@withNewCallStack.environment.callStack.addInstruction(SimpleInstruction(irCall)) valueArguments.forEach { this@withNewCallStack.environment.callStack.addVariable(it) } @@ -81,22 +84,26 @@ internal class DefaultCallInterceptor(override val interpreter: IrInterpreter) : val invokedFunction = functionState.irFunction var index = 1 // drop first arg that is reference to function - val dispatchReceiver = invokedFunction.dispatchReceiverParameter?.let { functionState.getState(it.symbol) ?: args[index++] } - val extensionReceiver = invokedFunction.extensionReceiverParameter?.let { functionState.getState(it.symbol) ?: args[index++] } + val dispatchReceiver = invokedFunction.dispatchReceiverParameter?.let { functionState.getField(it.symbol) ?: args[index++] } + val extensionReceiver = invokedFunction.extensionReceiverParameter?.let { functionState.getField(it.symbol) ?: args[index++] } val valueArguments = invokedFunction.valueParameters.map { args[index++] } val function = when (val symbol = invokedFunction.symbol) { is IrSimpleFunctionSymbol -> { - val irCall = IrCallImpl.fromSymbolOwner(0, 0, invokedFunction.returnType, invokedFunction.symbol as IrSimpleFunctionSymbol) + val irCall = IrCallImpl.fromSymbolOwner( + UNDEFINED_OFFSET, UNDEFINED_OFFSET, invokedFunction.returnType, invokedFunction.symbol as IrSimpleFunctionSymbol + ) val actualFunction = dispatchReceiver?.getIrFunctionByIrCall(irCall) ?: invokedFunction - callStack.newFrame(actualFunction, listOf(SimpleInstruction(actualFunction))) + callStack.newFrame(actualFunction) + callStack.addInstruction(SimpleInstruction(actualFunction)) callStack.addVariable(Variable(actualFunction.symbol, KTypeState(call.type, irBuiltIns.anyClass.owner))) actualFunction } is IrConstructorSymbol -> { val irConstructorCall = IrConstructorCallImpl.fromSymbolOwner(invokedFunction.returnType, symbol) - callStack.newSubFrame(irConstructorCall, listOf(SimpleInstruction(irConstructorCall))) + callStack.newSubFrame(irConstructorCall) + callStack.addInstruction(SimpleInstruction(irConstructorCall)) callStack.addVariable(Variable(invokedFunction.parentAsClass.thisReceiver!!.symbol, Common(invokedFunction.parentAsClass))) invokedFunction 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 9437d25d67a..5b736cd7bfd 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 @@ -104,7 +104,8 @@ private fun unfoldDelegatingConstructorCall(delegatingConstructorCall: IrFunctio private fun unfoldValueParameters(expression: IrFunctionAccessExpression, callStack: CallStack) { 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))) + callStack.newSubFrame(expression) + callStack.addInstruction(SimpleInstruction(expression)) fun getDefaultForParameterAt(index: Int): IrExpression? { fun IrValueParameter.getDefault(): IrExpressionBody? { @@ -169,7 +170,7 @@ private fun unfoldBody(body: IrBody, callStack: CallStack) { } private fun unfoldBlock(block: IrBlock, callStack: CallStack) { - callStack.newSubFrame(block, listOf()) + callStack.newSubFrame(block) callStack.addInstruction(SimpleInstruction(block)) unfoldStatements(block.statements, callStack) } @@ -211,9 +212,10 @@ private fun unfoldGetValue(expression: IrGetValue, environment: IrInterpreterEnv // used to evaluate constants inside object if (expectedClass != null && expectedClass.isObject && expression.symbol.owner.origin == IrDeclarationOrigin.INSTANCE_RECEIVER) { // TODO is this correct behaviour? - return unfoldGetObjectValue(IrGetObjectValueImpl(0, 0, expectedClass.defaultType, expectedClass.symbol), environment) + val irGetObject = IrGetObjectValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, expectedClass.defaultType, expectedClass.symbol) + return unfoldGetObjectValue(irGetObject, environment) } - environment.callStack.pushState(environment.callStack.getVariable(expression.symbol).state) + environment.callStack.pushState(environment.callStack.getState(expression.symbol)) } private fun unfoldGetObjectValue(expression: IrGetObjectValue, environment: IrInterpreterEnvironment) { @@ -257,18 +259,18 @@ private fun unfoldTypeOperatorCall(element: IrTypeOperatorCall, callStack: CallS } private fun unfoldBranch(branch: IrBranch, callStack: CallStack) { - callStack.addInstruction(SimpleInstruction(branch)) //2 - callStack.addInstruction(CompoundInstruction(branch.condition)) //1 + callStack.addInstruction(SimpleInstruction(branch)) + callStack.addInstruction(CompoundInstruction(branch.condition)) } private fun unfoldWhileLoop(loop: IrWhileLoop, callStack: CallStack) { - callStack.newSubFrame(loop, listOf()) + callStack.newSubFrame(loop) callStack.addInstruction(SimpleInstruction(loop)) callStack.addInstruction(CompoundInstruction(loop.condition)) } private fun unfoldDoWhileLoop(loop: IrDoWhileLoop, callStack: CallStack) { - callStack.newSubFrame(loop, listOf()) + callStack.newSubFrame(loop) callStack.addInstruction(SimpleInstruction(loop)) callStack.addInstruction(CompoundInstruction(loop.condition)) callStack.addInstruction(CompoundInstruction(loop.body)) @@ -276,7 +278,9 @@ private fun unfoldDoWhileLoop(loop: IrDoWhileLoop, callStack: CallStack) { private fun unfoldWhen(element: IrWhen, callStack: CallStack) { // new sub frame to drop it after - callStack.newSubFrame(element, element.branches.map { CompoundInstruction(it) } + listOf(SimpleInstruction(element))) + callStack.newSubFrame(element) + callStack.addInstruction(SimpleInstruction(element)) + element.branches.reversed().forEach { callStack.addInstruction(CompoundInstruction(it)) } } private fun unfoldContinue(element: IrContinue, callStack: CallStack) { @@ -293,7 +297,7 @@ private fun unfoldVararg(element: IrVararg, callStack: CallStack) { } private fun unfoldTry(element: IrTry, callStack: CallStack) { - callStack.newSubFrame(element, listOf()) + callStack.newSubFrame(element) callStack.addInstruction(SimpleInstruction(element)) callStack.addInstruction(CompoundInstruction(element.tryResult)) } @@ -302,9 +306,9 @@ private fun unfoldCatch(element: IrCatch, callStack: CallStack) { val exceptionState = callStack.peekState() as? ExceptionState ?: return if (exceptionState.isSubtypeOf(element.catchParameter.type)) { callStack.popState() - val frameOwner = callStack.getCurrentFrameOwner() as IrTry + val frameOwner = callStack.currentFrameOwner as IrTry callStack.dropSubFrame() // drop other catch blocks - callStack.newSubFrame(element, listOf()) // new frame with IrTry instruction to interpret finally block at the end + callStack.newSubFrame(element) // new frame with IrTry instruction to interpret finally block at the end callStack.addVariable(Variable(element.catchParameter.symbol, exceptionState)) callStack.addInstruction(SimpleInstruction(frameOwner)) callStack.addInstruction(CompoundInstruction(element.result)) @@ -318,7 +322,7 @@ private fun unfoldThrow(expression: IrThrow, callStack: CallStack) { private fun unfoldStringConcatenation(expression: IrStringConcatenation, environment: IrInterpreterEnvironment) { val callStack = environment.callStack - callStack.newSubFrame(expression, listOf()) + callStack.newSubFrame(expression) callStack.addInstruction(SimpleInstruction(expression)) // this callback is used to check the need for an explicit toString call @@ -339,10 +343,11 @@ private fun unfoldStringConcatenation(expression: IrStringConcatenation, environ } val toStringFun = state.getToStringFunction() val receiver = toStringFun.dispatchReceiverParameter!! - val toStringCall = IrCallImpl.fromSymbolOwner(0, 0, environment.irBuiltIns.stringType, toStringFun.symbol) - toStringCall.dispatchReceiver = IrConstImpl.constNull(0, 0, receiver.type) // just stub receiver + val toStringCall = + IrCallImpl.fromSymbolOwner(UNDEFINED_OFFSET, UNDEFINED_OFFSET, environment.irBuiltIns.stringType, toStringFun.symbol) - callStack.newSubFrame(toStringCall, listOf(SimpleInstruction(toStringCall))) + callStack.newSubFrame(toStringCall) + callStack.addInstruction(SimpleInstruction(toStringCall)) callStack.addVariable(Variable(receiver.symbol, state)) } } @@ -365,7 +370,8 @@ private fun unfoldComposite(element: IrComposite, callStack: CallStack) { private fun unfoldFunctionReference(reference: IrFunctionReference, callStack: CallStack) { val function = reference.symbol.owner - callStack.newSubFrame(reference, listOf(SimpleInstruction(reference))) + callStack.newSubFrame(reference) + callStack.addInstruction(SimpleInstruction(reference)) reference.dispatchReceiver?.let { callStack.addInstruction(SimpleInstruction(function.dispatchReceiverParameter!!)) } reference.extensionReceiver?.let { callStack.addInstruction(SimpleInstruction(function.extensionReceiverParameter!!)) } @@ -376,7 +382,8 @@ private fun unfoldFunctionReference(reference: IrFunctionReference, callStack: C private fun unfoldPropertyReference(propertyReference: IrPropertyReference, callStack: CallStack) { val getter = propertyReference.getter!!.owner - callStack.newSubFrame(propertyReference, listOf(SimpleInstruction(propertyReference))) + callStack.newSubFrame(propertyReference) + callStack.addInstruction(SimpleInstruction(propertyReference)) propertyReference.dispatchReceiver?.let { callStack.addInstruction(SimpleInstruction(getter.dispatchReceiverParameter!!)) } propertyReference.extensionReceiver?.let { callStack.addInstruction(SimpleInstruction(getter.extensionReceiverParameter!!)) } 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 4e39fe9f44f..8f3400cf7e4 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 @@ -62,18 +62,18 @@ class IrInterpreter private constructor( private fun Instruction.handle() { when (this) { is CompoundInstruction -> unfoldInstruction(this.element, environment) - is SimpleInstruction -> interpret(this.element) + is SimpleInstruction -> interpret(this.element).also { incrementAndCheckCommands() } is CustomInstruction -> this.evaluate() } } fun interpret(expression: IrExpression, file: IrFile? = null): IrExpression { commandCount = 0 - callStack.newFrame(expression, listOf(CompoundInstruction(expression)), file) + callStack.newFrame(expression, file) + callStack.addInstruction(CompoundInstruction(expression)) while (!callStack.hasNoInstructions()) { callStack.popInstruction().handle() - incrementAndCheckCommands() } return callStack.popState().toIrExpression(expression).apply { callStack.dropFrame() } @@ -81,8 +81,8 @@ class IrInterpreter private constructor( internal fun withNewCallStack(call: IrCall, init: IrInterpreter.() -> Any?): State { return with(IrInterpreter(environment.copyWithNewCallStack(), bodyMap)) { - callStack.newFrame(call.symbol.owner, listOf()) - callStack.newSubFrame(call, listOf()) + callStack.newFrame(call.symbol.owner) + callStack.newSubFrame(call) init() while (!callStack.hasNoInstructions()) { @@ -115,7 +115,7 @@ class IrInterpreter private constructor( is IrEnumEntry -> interpretEnumEntry(element) is IrConst<*> -> interpretConst(element) is IrVariable -> callStack.addVariable(Variable(element.symbol, callStack.popState())) - is IrSetValue -> callStack.getVariable(element.symbol).state = callStack.popState() + is IrSetValue -> callStack.setState(element.symbol, callStack.popState()) is IrTypeOperatorCall -> interpretTypeOperatorCall(element) is IrBranch -> interpretBranch(element) is IrWhileLoop -> interpretWhile(element) @@ -169,9 +169,9 @@ class IrInterpreter private constructor( private fun interpretCall(call: IrCall) { val owner = call.symbol.owner // 1. load evaluated arguments from stack - var dispatchReceiver = owner.getDispatchReceiver()?.let { callStack.getVariable(it) }?.state - val extensionReceiver = owner.getExtensionReceiver()?.let { callStack.getVariable(it) }?.state - val valueArguments = owner.valueParameters.map { callStack.getVariable(it.symbol).state } + var dispatchReceiver = owner.getDispatchReceiver()?.let { callStack.getState(it) } + val extensionReceiver = owner.getExtensionReceiver()?.let { callStack.getState(it) } + val valueArguments = owner.valueParameters.map { callStack.getState(it.symbol) } // 2. get correct function for interpretation val irFunction = dispatchReceiver?.getIrFunctionByIrCall(call) ?: call.symbol.owner @@ -181,7 +181,8 @@ class IrInterpreter private constructor( } callStack.dropSubFrame() // drop intermediate frame that contains variables for default arg evaluation - callStack.newFrame(irFunction, listOf(SimpleInstruction(irFunction))) + callStack.newFrame(irFunction) + callStack.addInstruction(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))) @@ -222,7 +223,7 @@ class IrInterpreter private constructor( property.backingField?.initializer?.expression ?: return@forEach val receiver = irClass.thisReceiver!!.symbol if (property.backingField?.initializer != null) { - val receiverState = callStack.getVariable(receiver).state + val receiverState = callStack.getState(receiver) val propertyVar = Variable(property.symbol, callStack.popState()) receiverState.setField(propertyVar) } @@ -232,7 +233,7 @@ class IrInterpreter private constructor( private fun interpretField(field: IrField) { val irClass = field.parentAsClass val receiver = irClass.thisReceiver!!.symbol - val receiverState = callStack.getVariable(receiver).state + val receiverState = callStack.getState(receiver) receiverState.setField(Variable(field.correspondingPropertySymbol!!, callStack.popState())) } @@ -243,21 +244,22 @@ class IrInterpreter private constructor( private fun interpretConstructorCall(constructorCall: IrFunctionAccessExpression) { val constructor = constructorCall.symbol.owner - val valueArguments = constructor.valueParameters.map { callStack.getVariable(it.symbol).state } + val valueArguments = constructor.valueParameters.map { callStack.getState(it.symbol) } 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.getVariable(constructor.dispatchReceiverParameter!!.symbol).state else null + val objectState = callStack.getState(constructorCall.getThisReceiver()) + if (irClass.isLocal) callStack.storeUpValues(objectState as StateWithClosure) + val outerClass = if (irClass.isInner) callStack.getState(constructor.dispatchReceiverParameter!!.symbol) else null callStack.dropSubFrame() - callStack.newFrame(constructor, listOf(SimpleInstruction(constructor))) - callStack.addVariable(objectVar) + callStack.newFrame(constructor) + callStack.addInstruction(SimpleInstruction(constructor)) + callStack.addVariable(Variable(constructorCall.getThisReceiver(), objectState)) constructor.valueParameters.forEachIndexed { i, param -> callStack.addVariable(Variable(param.symbol, valueArguments[i])) } - if (irClass.isLocal) callStack.loadUpValues(objectVar.state as StateWithClosure) + if (irClass.isLocal) callStack.loadUpValues(objectState as StateWithClosure) if (outerClass != null) { val outerClassVar = Variable(irClass.parentAsClass.thisReceiver!!.symbol, outerClass) - (objectVar.state as Complex).outerClass = outerClassVar + (objectState as Complex).outerClass = outerClassVar // used in case when inner class has inner super class callStack.addVariable(Variable(constructor.dispatchReceiverParameter!!.symbol, outerClass)) // used to get information from outer class @@ -271,10 +273,10 @@ class IrInterpreter private constructor( is IrBlock -> (irStatement.statements.last() as IrFunctionAccessExpression).getThisReceiver() else -> TODO("${irStatement::class.java} is not supported as first statement in constructor call") } - superReceiver?.let { callStack.addVariable(Variable(it, objectVar.state)) } + superReceiver?.let { callStack.addVariable(Variable(it, objectState)) } - callInterceptor.interceptConstructor(constructorCall, objectVar.state, valueArguments) { - callStack.pushState(objectVar.state) + callInterceptor.interceptConstructor(constructorCall, objectState, valueArguments) { + callStack.pushState(objectState) callStack.addInstruction(CompoundInstruction(constructor)) } } @@ -321,10 +323,10 @@ class IrInterpreter private constructor( val result = callStack.popState().asBoolean() callStack.dropSubFrame() if (result) { - callStack.newSubFrame( - loop, - listOf(CompoundInstruction(loop.body), CompoundInstruction(loop.condition), SimpleInstruction(loop)) - ) + callStack.newSubFrame(loop) + callStack.addInstruction(SimpleInstruction(loop)) + callStack.addInstruction(CompoundInstruction(loop.condition)) + callStack.addInstruction(CompoundInstruction(loop.body)) } } @@ -332,10 +334,10 @@ class IrInterpreter private constructor( val result = callStack.popState().asBoolean() callStack.dropSubFrame() if (result) { - callStack.newSubFrame( - loop, - listOf(CompoundInstruction(loop.body), CompoundInstruction(loop.condition), SimpleInstruction(loop)) - ) + callStack.newSubFrame(loop) + callStack.addInstruction(SimpleInstruction(loop)) + callStack.addInstruction(CompoundInstruction(loop.condition)) + callStack.addInstruction(CompoundInstruction(loop.body)) } } @@ -350,7 +352,7 @@ class IrInterpreter private constructor( private fun interpretSetField(expression: IrSetField) { val receiver = (expression.receiver as IrDeclarationReference).symbol val propertySymbol = expression.symbol.owner.correspondingPropertySymbol!! - callStack.getVariable(receiver).apply { this.state.setField(Variable(propertySymbol, callStack.popState())) } + callStack.getState(receiver).apply { this.setField(Variable(propertySymbol, callStack.popState())) } } private fun interpretGetField(expression: IrGetField) { @@ -375,7 +377,7 @@ class IrInterpreter private constructor( callStack.addInstruction(CompoundInstruction(expression.symbol.owner.initializer?.expression)) } else -> { - val result = callStack.getVariable(receiver!!).state.getState(field.correspondingPropertySymbol!!) + val result = callStack.getState(receiver!!).getField(field.correspondingPropertySymbol!!) callStack.pushState(result!!) } } @@ -390,7 +392,8 @@ class IrInterpreter private constructor( val constructor = objectClass.constructors.first() val constructorCall = IrConstructorCallImpl.fromSymbolOwner(constructor.returnType, constructor.symbol) - callStack.newSubFrame(constructorCall, listOf(SimpleInstruction(constructorCall))) + callStack.newSubFrame(constructorCall) + callStack.addInstruction(SimpleInstruction(constructorCall)) } } @@ -422,7 +425,9 @@ class IrInterpreter private constructor( val enumClassObject = Variable(enumConstructorCall.getThisReceiver(), Common(enumEntry.correspondingClass ?: enumClass)) environment.mapOfEnums[enumEntry.symbol] = enumClassObject.state as Complex - callStack.newSubFrame(enumEntry, listOf(CompoundInstruction(enumConstructorCall), CustomInstruction(cleanEnumSuperCall))) + callStack.newSubFrame(enumEntry) + callStack.addInstruction(CustomInstruction(cleanEnumSuperCall)) + callStack.addInstruction(CompoundInstruction(enumConstructorCall)) callStack.addVariable(enumClassObject) } } @@ -431,7 +436,7 @@ class IrInterpreter private constructor( val typeClassifier = expression.typeOperand.classifierOrFail val isReified = (typeClassifier.owner as? IrTypeParameter)?.isReified == true val isErased = typeClassifier.owner is IrTypeParameter && !isReified - val typeOperand = if (isReified) (callStack.getVariable(typeClassifier).state as KTypeState).irType else expression.typeOperand + val typeOperand = if (isReified) (callStack.getState(typeClassifier) as KTypeState).irType else expression.typeOperand when (expression.operator) { IrTypeOperator.IMPLICIT_COERCION_TO_UNIT -> { @@ -531,7 +536,7 @@ class IrInterpreter private constructor( private fun interpretThrow(expression: IrThrow) { val exception = callStack.popState() - callStack.newSubFrame(expression, listOf()) // temporary frame to get correct stack trace + callStack.newSubFrame(expression) // temporary frame to get correct stack trace when (exception) { is Common -> callStack.pushState(ExceptionState(exception, callStack.getStackTrace())) is Wrapper -> callStack.pushState(ExceptionState(exception, callStack.getStackTrace())) @@ -565,12 +570,12 @@ class IrInterpreter private constructor( val function = KFunctionState(reference) val irFunction = function.irFunction - val dispatchReceiver = reference.dispatchReceiver?.let { callStack.getVariable(irFunction.getDispatchReceiver()!!) }?.state - val extensionReceiver = reference.extensionReceiver?.let { callStack.getVariable(irFunction.getExtensionReceiver()!!) }?.state + val dispatchReceiver = reference.dispatchReceiver?.let { callStack.getState(irFunction.getDispatchReceiver()!!) } + val extensionReceiver = reference.extensionReceiver?.let { callStack.getState(irFunction.getExtensionReceiver()!!) } callStack.dropSubFrame() - irFunction.getDispatchReceiver()?.let { dispatchReceiver?.let { receiver -> function.fields.add(Variable(it, receiver)) } } - irFunction.getExtensionReceiver()?.let { extensionReceiver?.let { receiver -> function.fields.add(Variable(it, receiver)) } } + irFunction.getDispatchReceiver()?.let { dispatchReceiver?.let { receiver -> function.fields += Variable(it, receiver) } } + irFunction.getExtensionReceiver()?.let { extensionReceiver?.let { receiver -> function.fields += Variable(it, receiver) } } if (irFunction.isLocal) callStack.storeUpValues(function) callStack.pushState(function) @@ -580,7 +585,7 @@ class IrInterpreter private constructor( val receiverSymbol = propertyReference.getter?.owner?.let { it.getDispatchReceiver() ?: it.getExtensionReceiver() } // it is impossible to get KProperty2 through ::, so only one receiver can be not null (or both null) val receiver = (propertyReference.dispatchReceiver ?: propertyReference.extensionReceiver) - ?.let { callStack.getVariable(receiverSymbol!!) }?.state + ?.let { callStack.getState(receiverSymbol!!) } callStack.dropSubFrame() val propertyState = KPropertyState(propertyReference, receiver) @@ -590,7 +595,7 @@ class IrInterpreter private constructor( private fun interpretClassReference(classReference: IrClassReference) { when (classReference.symbol) { is IrTypeParameterSymbol -> { // reified - val kTypeState = callStack.getVariable(classReference.symbol).state as KTypeState + val kTypeState = callStack.getState(classReference.symbol) as KTypeState callStack.pushState(KClassState(kTypeState.irType.classOrNull!!.owner, classReference.type.classOrNull!!.owner)) } else -> callStack.pushState(KClassState(classReference)) 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 5ab6fbdf935..9d3ab9fade0 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 @@ -15,7 +15,6 @@ import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl import org.jetbrains.kotlin.ir.expressions.impl.IrErrorExpressionImpl import org.jetbrains.kotlin.ir.interpreter.builtins.evaluateIntrinsicAnnotation -import org.jetbrains.kotlin.ir.interpreter.stack.Variable import org.jetbrains.kotlin.ir.interpreter.state.* import org.jetbrains.kotlin.ir.interpreter.proxy.Proxy import org.jetbrains.kotlin.ir.interpreter.proxy.wrap @@ -260,7 +259,7 @@ internal fun IrFunction?.checkCast(environment: IrInterpreterEnvironment): Boole if (actualType.classifierOrNull !is IrTypeParameterSymbol) return true // TODO expectedType can be missing for functions called as proxy - val expectedType = (environment.callStack.getVariable(this.symbol).state as? KTypeState)?.irType ?: return true + val expectedType = (environment.callStack.getState(this.symbol) as? KTypeState)?.irType ?: return true if (expectedType.classifierOrFail is IrTypeParameterSymbol) return true val actualState = environment.callStack.peekState() ?: return true diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/intrinsics/IntrinsicImplementations.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/intrinsics/IntrinsicImplementations.kt index 820a92aca82..1bb194348b5 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/intrinsics/IntrinsicImplementations.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/intrinsics/IntrinsicImplementations.kt @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.ir.interpreter.intrinsics +import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.IrEnumEntry import org.jetbrains.kotlin.ir.declarations.IrFunction @@ -48,7 +49,7 @@ internal object EmptyArray : IntrinsicBase() { } override fun evaluate(irFunction: IrFunction, environment: IrInterpreterEnvironment) { - val returnType = environment.callStack.getVariable(irFunction.symbol).state as KTypeState + val returnType = environment.callStack.getState(irFunction.symbol) as KTypeState environment.callStack.pushState(emptyArray().toState(returnType.irType)) } } @@ -65,7 +66,7 @@ internal object ArrayOf : IntrinsicBase() { override fun evaluate(irFunction: IrFunction, environment: IrInterpreterEnvironment) { val elementsSymbol = irFunction.valueParameters.single().symbol - val varargVariable = environment.callStack.getVariable(elementsSymbol).state + val varargVariable = environment.callStack.getState(elementsSymbol) environment.callStack.pushState(varargVariable) } } @@ -81,9 +82,9 @@ internal object ArrayOfNulls : IntrinsicBase() { } override fun evaluate(irFunction: IrFunction, environment: IrInterpreterEnvironment) { - val size = environment.callStack.getVariable(irFunction.valueParameters.first().symbol).state.asInt() + val size = environment.callStack.getState(irFunction.valueParameters.first().symbol).asInt() val array = arrayOfNulls(size) - val typeArgument = irFunction.typeParameters.map { environment.callStack.getVariable(it.symbol) }.single().state as KTypeState + val typeArgument = irFunction.typeParameters.map { environment.callStack.getState(it.symbol) }.single() as KTypeState val returnType = (irFunction.returnType as IrSimpleType).buildSimpleType { arguments = listOf(makeTypeProjection(typeArgument.irType, Variance.INVARIANT)) } @@ -101,7 +102,7 @@ internal object EnumValues : IntrinsicBase() { private fun getEnumClass(irFunction: IrFunction, environment: IrInterpreterEnvironment): IrClass { return when (irFunction.fqNameWhenAvailable.toString()) { "kotlin.enumValues" -> { - val kType = environment.callStack.getVariable(irFunction.typeParameters.first().symbol).state as KTypeState + val kType = environment.callStack.getState(irFunction.typeParameters.first().symbol) as KTypeState kType.irType.classOrNull!!.owner } else -> irFunction.parent as IrClass @@ -132,7 +133,7 @@ internal object EnumValueOf : IntrinsicBase() { private fun getEnumClass(irFunction: IrFunction, environment: IrInterpreterEnvironment): IrClass { return when (irFunction.fqNameWhenAvailable.toString()) { "kotlin.enumValueOf" -> { - val kType = environment.callStack.getVariable(irFunction.typeParameters.first().symbol).state as KTypeState + val kType = environment.callStack.getState(irFunction.typeParameters.first().symbol) as KTypeState kType.irType.classOrNull!!.owner } else -> irFunction.parent as IrClass @@ -141,7 +142,7 @@ internal object EnumValueOf : IntrinsicBase() { private fun getEnumEntryByName(irFunction: IrFunction, environment: IrInterpreterEnvironment): IrEnumEntry? { val enumClass = getEnumClass(irFunction, environment) - val enumEntryName = environment.callStack.getVariable(irFunction.valueParameters.first().symbol).state.asString() + val enumEntryName = environment.callStack.getState(irFunction.valueParameters.first().symbol).asString() val enumEntry = enumClass.declarations.filterIsInstance().singleOrNull { it.name.asString() == enumEntryName } if (enumEntry == null) { IllegalArgumentException("No enum constant ${enumClass.fqNameWhenAvailable}.$enumEntryName").handleUserException(environment) @@ -171,7 +172,7 @@ internal object EnumHashCode : IntrinsicBase() { } override fun evaluate(irFunction: IrFunction, environment: IrInterpreterEnvironment) { - val hashCode = environment.callStack.getVariable(irFunction.dispatchReceiverParameter!!.symbol).state.hashCode() + val hashCode = environment.callStack.getState(irFunction.dispatchReceiverParameter!!.symbol).hashCode() environment.callStack.pushState(hashCode.toState(irFunction.returnType)) } } @@ -189,12 +190,12 @@ internal object JsPrimitives : IntrinsicBase() { override fun evaluate(irFunction: IrFunction, environment: IrInterpreterEnvironment) { when (irFunction.fqNameWhenAvailable.toString()) { "kotlin.Long." -> { - val low = environment.callStack.getVariable(irFunction.valueParameters[0].symbol).state.asInt() - val high = environment.callStack.getVariable(irFunction.valueParameters[1].symbol).state.asInt() + val low = environment.callStack.getState(irFunction.valueParameters[0].symbol).asInt() + val high = environment.callStack.getState(irFunction.valueParameters[1].symbol).asInt() environment.callStack.pushState((high.toLong().shl(32) + low).toState(irFunction.returnType)) } "kotlin.Char." -> { - val value = environment.callStack.getVariable(irFunction.valueParameters[0].symbol).state.asInt() + val value = environment.callStack.getState(irFunction.valueParameters[0].symbol).asInt() environment.callStack.pushState(value.toChar().toState(irFunction.returnType)) } } @@ -212,16 +213,16 @@ internal object ArrayConstructor : IntrinsicBase() { val instructions = mutableListOf(customEvaluateInstruction(irFunction, environment)) val sizeDescriptor = irFunction.valueParameters[0].symbol - val size = environment.callStack.getVariable(sizeDescriptor).state.asInt() + val size = environment.callStack.getState(sizeDescriptor).asInt() val initDescriptor = irFunction.valueParameters[1].symbol - val initLambda = environment.callStack.getVariable(initDescriptor).state as KFunctionState + 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 0 until size) { - val call = IrCallImpl.fromSymbolOwner(0, 0, function.returnType, function.symbol) - call.putValueArgument(0, IrConstImpl.int(0, 0, index.type, i)) + val call = IrCallImpl.fromSymbolOwner(UNDEFINED_OFFSET, UNDEFINED_OFFSET, function.returnType, function.symbol) + call.putValueArgument(0, IrConstImpl.int(UNDEFINED_OFFSET, UNDEFINED_OFFSET, index.type, i)) instructions += CompoundInstruction(call) } @@ -230,7 +231,7 @@ internal object ArrayConstructor : IntrinsicBase() { override fun evaluate(irFunction: IrFunction, environment: IrInterpreterEnvironment) { val sizeDescriptor = irFunction.valueParameters[0].symbol - val size = environment.callStack.getVariable(sizeDescriptor).state.asInt() + val size = environment.callStack.getState(sizeDescriptor).asInt() val arrayValue = MutableList(size) { if (irFunction.returnType.isCharArray()) 0.toChar() else 0 } if (irFunction.valueParameters.size == 2) { @@ -246,7 +247,7 @@ internal object ArrayConstructor : IntrinsicBase() { } } - val type = environment.callStack.getVariable(irFunction.symbol).state as KTypeState + val type = environment.callStack.getState(irFunction.symbol) as KTypeState environment.callStack.pushState(arrayValue.toPrimitiveStateArray(type.irType)) } } @@ -275,15 +276,15 @@ internal object AssertIntrinsic : IntrinsicBase() { override fun unwind(irFunction: IrFunction, environment: IrInterpreterEnvironment): List { if (irFunction.valueParameters.size == 1) return listOf(customEvaluateInstruction(irFunction, environment)) - val messageLambda = environment.callStack.getVariable(irFunction.valueParameters.last().symbol).state as KFunctionState + val messageLambda = environment.callStack.getState(irFunction.valueParameters.last().symbol) as KFunctionState val function = messageLambda.irFunction as IrSimpleFunction - val call = IrCallImpl.fromSymbolOwner(0, 0, function.returnType, function.symbol) + val call = IrCallImpl.fromSymbolOwner(UNDEFINED_OFFSET, UNDEFINED_OFFSET, function.returnType, function.symbol) return listOf(customEvaluateInstruction(irFunction, environment), CompoundInstruction(call)) } override fun evaluate(irFunction: IrFunction, environment: IrInterpreterEnvironment) { - val value = environment.callStack.getVariable(irFunction.valueParameters.first().symbol).state.asBoolean() + val value = environment.callStack.getState(irFunction.valueParameters.first().symbol).asBoolean() if (value) return when (irFunction.valueParameters.size) { 1 -> AssertionError("Assertion failed").handleUserException(environment) diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/proxy/CommonProxy.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/proxy/CommonProxy.kt index 96e7a6f4440..de66aa94280 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/proxy/CommonProxy.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/proxy/CommonProxy.kt @@ -26,7 +26,7 @@ internal class CommonProxy private constructor(override val state: Common, overr private fun IrFunction.wasAlreadyCalled(): Boolean { val anyParameter = this.getLastOverridden().dispatchReceiverParameter!!.symbol if (callInterceptor.environment.callStack.containsVariable(anyParameter)) return true - return this == callInterceptor.environment.callStack.getCurrentFrameOwner() + return this == callInterceptor.environment.callStack.currentFrameOwner } override fun equals(other: Any?): Boolean { diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/proxy/reflection/KProperty0Proxy.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/proxy/reflection/KProperty0Proxy.kt index 4558a3a8e8e..8886e8df61c 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/proxy/reflection/KProperty0Proxy.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/proxy/reflection/KProperty0Proxy.kt @@ -28,7 +28,7 @@ internal open class KProperty0Proxy( val receiver = state.receiver // null receiver <=> property is on top level ?: return callInterceptor.interceptProxy(getter, emptyList()) - val value = receiver.getState(actualPropertySymbol) + val value = receiver.getField(actualPropertySymbol) return when { // null value <=> property is extension or Primitive; receiver.isNull() <=> nullable extension value == null || receiver.isNull() -> { 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 536fa632ae5..66f197d785f 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 @@ -19,22 +19,22 @@ import org.jetbrains.kotlin.ir.util.fileOrNull internal class CallStack { private val frames = mutableListOf() - private fun getCurrentFrame() = frames.last() - internal fun getCurrentFrameOwner() = frames.last().currentSubFrameOwner + private val currentFrame get() = frames.last() + internal val currentFrameOwner get() = currentFrame.currentSubFrameOwner - fun newFrame(frameOwner: IrElement, instructions: List, irFile: IrFile? = null) { - val newFrame = SubFrame(instructions.toMutableList(), frameOwner) + fun newFrame(frameOwner: IrElement, irFile: IrFile? = null) { + val newFrame = SubFrame(frameOwner) frames.add(Frame(newFrame, irFile)) } - fun newFrame(frameOwner: IrFunction, instructions: List) { - val newFrame = SubFrame(instructions.toMutableList(), frameOwner) + fun newFrame(frameOwner: IrFunction) { + val newFrame = SubFrame(frameOwner) frames.add(Frame(newFrame, frameOwner.fileOrNull)) } - fun newSubFrame(frameOwner: IrElement, instructions: List) { - val newFrame = SubFrame(instructions.toMutableList(), frameOwner) - getCurrentFrame().addSubFrame(newFrame) + fun newSubFrame(frameOwner: IrElement) { + val newFrame = SubFrame(frameOwner) + currentFrame.addSubFrame(newFrame) } fun dropFrame() { @@ -49,12 +49,12 @@ internal class CallStack { } fun dropSubFrame() { - getCurrentFrame().removeSubFrame() + currentFrame.removeSubFrame() } fun returnFromFrameWithResult(irReturn: IrReturn) { val result = popState() - var frameOwner = getCurrentFrameOwner() + var frameOwner = currentFrameOwner while (frameOwner != irReturn.returnTargetSymbol.owner) { when (frameOwner) { is IrTry -> { @@ -65,7 +65,7 @@ internal class CallStack { return } is IrCatch -> { - val tryBlock = getCurrentFrame().dropInstructions()!!.element as IrTry// last instruction in `catch` block is `try` + val tryBlock = currentFrame.dropInstructions()!!.element as IrTry// last instruction in `catch` block is `try` dropSubFrame() pushState(result) addInstruction(SimpleInstruction(irReturn)) @@ -74,44 +74,46 @@ internal class CallStack { } else -> { dropSubFrame() - if (getCurrentFrame().hasNoSubFrames() && frameOwner != irReturn.returnTargetSymbol.owner) dropFrame() - frameOwner = getCurrentFrameOwner() + if (currentFrame.hasNoSubFrames() && frameOwner != irReturn.returnTargetSymbol.owner) dropFrame() + frameOwner = currentFrameOwner } } } dropFrame() // check that last frame is not a function itself; use case for proxyInterpret - if (frames.size == 0) newFrame(irReturn, emptyList()) // just stub frame + if (frames.size == 0) newFrame(irReturn) // just stub frame pushState(result) } fun unrollInstructionsForBreakContinue(breakOrContinue: IrBreakContinue) { - var frameOwner = getCurrentFrameOwner() + var frameOwner = currentFrameOwner while (frameOwner != breakOrContinue.loop) { when (frameOwner) { is IrTry -> { - getCurrentFrame().removeSubFrameWithoutDataPropagation() + currentFrame.removeSubFrameWithoutDataPropagation() addInstruction(CompoundInstruction(breakOrContinue)) - newSubFrame(frameOwner, listOf(SimpleInstruction(frameOwner))) // will be deleted when interpret 'try' + newSubFrame(frameOwner) // will be deleted when interpret 'try' + addInstruction(SimpleInstruction(frameOwner)) return } is IrCatch -> { - val tryInstruction = getCurrentFrame().dropInstructions()!! // last instruction in `catch` block is `try` - getCurrentFrame().removeSubFrameWithoutDataPropagation() + val tryInstruction = currentFrame.dropInstructions()!! // last instruction in `catch` block is `try` + currentFrame.removeSubFrameWithoutDataPropagation() addInstruction(CompoundInstruction(breakOrContinue)) - newSubFrame(tryInstruction.element!!, listOf(tryInstruction)) // will be deleted when interpret 'try' + newSubFrame(tryInstruction.element!!) // will be deleted when interpret 'try' + addInstruction(tryInstruction) return } else -> { - getCurrentFrame().removeSubFrameWithoutDataPropagation() - frameOwner = getCurrentFrameOwner() + currentFrame.removeSubFrameWithoutDataPropagation() + frameOwner = currentFrameOwner } } } when (breakOrContinue) { - is IrBreak -> getCurrentFrame().removeSubFrameWithoutDataPropagation() // drop loop + is IrBreak -> currentFrame.removeSubFrameWithoutDataPropagation() // drop loop else -> if (breakOrContinue.loop is IrDoWhileLoop) { addInstruction(SimpleInstruction(breakOrContinue.loop)) addInstruction(CompoundInstruction(breakOrContinue.loop.condition)) @@ -123,15 +125,15 @@ internal class CallStack { fun dropFramesUntilTryCatch() { val exception = popState() - var frameOwner = getCurrentFrameOwner() + var frameOwner = currentFrameOwner while (frames.isNotEmpty()) { - val frame = getCurrentFrame() + val frame = currentFrame while (!frame.hasNoSubFrames()) { frameOwner = frame.currentSubFrameOwner when (frameOwner) { is IrTry -> { dropSubFrame() // drop all instructions that left - newSubFrame(frameOwner, listOf()) + newSubFrame(frameOwner) addInstruction(SimpleInstruction(frameOwner)) // to evaluate finally at the end frameOwner.catches.reversed().forEach { addInstruction(CompoundInstruction(it)) } pushState(exception) @@ -149,37 +151,38 @@ internal class CallStack { dropFrame() } - if (frames.size == 0) newFrame(frameOwner, emptyList()) // just stub frame + if (frames.size == 0) newFrame(frameOwner) // just stub frame pushState(exception) } fun hasNoInstructions() = frames.isEmpty() || (frames.size == 1 && frames.first().hasNoInstructions()) fun addInstruction(instruction: Instruction) { - getCurrentFrame().addInstruction(instruction) + currentFrame.addInstruction(instruction) } fun popInstruction(): Instruction { - return getCurrentFrame().popInstruction() + return currentFrame.popInstruction() } fun pushState(state: State) { - getCurrentFrame().pushState(state) + currentFrame.pushState(state) } - fun popState(): State = getCurrentFrame().popState() - fun peekState(): State? = getCurrentFrame().peekState() + fun popState(): State = currentFrame.popState() + fun peekState(): State? = currentFrame.peekState() fun addVariable(variable: Variable) { - getCurrentFrame().addVariable(variable) + currentFrame.addVariable(variable) } - fun getVariable(symbol: IrSymbol): Variable = getCurrentFrame().getVariable(symbol) - fun containsVariable(symbol: IrSymbol): Boolean = getCurrentFrame().containsVariable(symbol) + fun getState(symbol: IrSymbol): State = currentFrame.getState(symbol) + fun setState(symbol: IrSymbol, newState: State) = currentFrame.setState(symbol, newState) + fun containsVariable(symbol: IrSymbol): Boolean = currentFrame.containsVariable(symbol) fun storeUpValues(state: StateWithClosure) { // TODO save only necessary declarations - state.upValues.addAll(getCurrentFrame().getAll().toMutableList()) + state.upValues.addAll(currentFrame.getAll().toMutableList()) } fun loadUpValues(state: StateWithClosure) { diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/stack/Frame.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/stack/Frame.kt index 946532b1375..11d9481f79b 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/stack/Frame.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/stack/Frame.kt @@ -14,26 +14,24 @@ import org.jetbrains.kotlin.ir.interpreter.state.State import org.jetbrains.kotlin.ir.symbols.IrSymbol import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable import org.jetbrains.kotlin.util.capitalizeDecapitalize.capitalizeAsciiOnly -import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult internal class Frame(subFrame: SubFrame, val irFile: IrFile? = null) { private val innerStack = mutableListOf(subFrame) private var currentInstruction: Instruction? = null - val currentSubFrameOwner: IrElement - get() = getCurrentFrame().owner + + private val currentFrame get() = innerStack.last() + val currentSubFrameOwner: IrElement get() = currentFrame.owner companion object { const val NOT_DEFINED = "Not defined" } - private fun getCurrentFrame() = innerStack.last() - fun addSubFrame(frame: SubFrame) { innerStack.add(frame) } fun removeSubFrame() { - getCurrentFrame().peekState()?.let { if (innerStack.size > 1) innerStack[innerStack.size - 2].pushState(it) } + currentFrame.peekState()?.let { if (innerStack.size > 1) innerStack[innerStack.size - 2].pushState(it) } removeSubFrameWithoutDataPropagation() } @@ -45,34 +43,39 @@ internal class Frame(subFrame: SubFrame, val irFile: IrFile? = null) { fun hasNoInstructions() = hasNoSubFrames() || (innerStack.size == 1 && innerStack.first().isEmpty()) fun addInstruction(instruction: Instruction) { - getCurrentFrame().pushInstruction(instruction) + currentFrame.pushInstruction(instruction) } fun popInstruction(): Instruction { - return getCurrentFrame().popInstruction().apply { currentInstruction = this } + return currentFrame.popInstruction().apply { currentInstruction = this } } - fun dropInstructions() = getCurrentFrame().dropInstructions() + fun dropInstructions() = currentFrame.dropInstructions() fun pushState(state: State) { - getCurrentFrame().pushState(state) + currentFrame.pushState(state) } - fun popState(): State = getCurrentFrame().popState() - fun peekState(): State? = getCurrentFrame().peekState() + fun popState(): State = currentFrame.popState() + fun peekState(): State? = currentFrame.peekState() fun addVariable(variable: Variable) { - getCurrentFrame().addVariable(variable) + currentFrame.addVariable(variable) } - fun getVariable(symbol: IrSymbol): Variable { - return tryToGetVariable(symbol) + fun getState(symbol: IrSymbol): State { + return (innerStack.lastIndex downTo 0).firstNotNullOfOrNull { innerStack[it].getState(symbol) } ?: throw InterpreterError("$symbol not found") // TODO better message } - fun containsVariable(symbol: IrSymbol): Boolean = tryToGetVariable(symbol) != null + fun setState(symbol: IrSymbol, newState: State) { + (innerStack.lastIndex downTo 0).forEach { + if (innerStack[it].containsVariable(symbol)) + return innerStack[it].setState(symbol, newState) + } + } - private fun tryToGetVariable(symbol: IrSymbol): Variable? = innerStack.reversed().firstNotNullResult { it.getVariable(symbol) } + fun containsVariable(symbol: IrSymbol): Boolean = (innerStack.lastIndex downTo 0).any { innerStack[it].containsVariable(symbol) } fun getAll(): List = innerStack.flatMap { it.getAll() } @@ -102,46 +105,44 @@ internal class Frame(subFrame: SubFrame, val irFile: IrFile? = null) { } } -internal class SubFrame(private val instructions: MutableList, val owner: IrElement) { - private val memory = mutableListOf() +internal class SubFrame(val owner: IrElement) { + private val instructions = mutableListOf() private val dataStack = DataStack() + private val memory = mutableListOf() + // Methods to work with instruction fun isEmpty() = instructions.isEmpty() - - fun pushInstruction(instruction: Instruction) { - instructions.add(0, instruction) - } - - fun popInstruction(): Instruction { - return instructions.removeFirst() - } - + fun pushInstruction(instruction: Instruction) = instructions.add(0, instruction) + fun popInstruction(): Instruction = instructions.removeFirst() fun dropInstructions() = instructions.lastOrNull()?.apply { instructions.clear() } - fun pushState(state: State) { - dataStack.push(state) - } - + // Methods to work with data + fun pushState(state: State) = dataStack.push(state) fun popState(): State = dataStack.pop() - fun peekState(): State? = if (!dataStack.isEmpty()) dataStack.peek() else null + fun peekState(): State? = dataStack.peek() + // Methods to work with memory fun addVariable(variable: Variable) { memory += variable } - fun getVariable(symbol: IrSymbol): Variable? = memory.firstOrNull { it.symbol == symbol } + private fun getVariable(symbol: IrSymbol): Variable? = memory.firstOrNull { it.symbol == symbol } + fun containsVariable(symbol: IrSymbol): Boolean = getVariable(symbol) != null + fun getState(symbol: IrSymbol): State? = getVariable(symbol)?.state + fun setState(symbol: IrSymbol, newState: State) { + getVariable(symbol)?.state = newState + } + fun getAll(): List = memory } private class DataStack { private val stack = mutableListOf() - fun isEmpty() = stack.isEmpty() - fun push(state: State) { stack.add(state) } fun pop(): State = stack.removeLast() - fun peek(): State = stack.last() + fun peek(): State? = stack.lastOrNull() } \ No newline at end of file diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/ExceptionState.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/ExceptionState.kt index fe2c16856f0..20bb81db8c0 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/ExceptionState.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/ExceptionState.kt @@ -23,9 +23,9 @@ internal class ExceptionState private constructor( override var outerClass: Variable? = null override val message: String? - get() = getState(messageProperty.symbol)?.asStringOrNull() + get() = getField(messageProperty.symbol)?.asStringOrNull() override val cause: Throwable? - get() = getState(causeProperty.symbol)?.let { if (it is ExceptionState) it else null } + get() = getField(causeProperty.symbol)?.let { if (it is ExceptionState) it else null } private lateinit var exceptionFqName: String private val exceptionHierarchy = mutableListOf() @@ -115,7 +115,7 @@ internal class ExceptionState private constructor( val causeVar = exception.cause?.let { Variable(causeProperty.symbol, ExceptionState(it, irClass, stackTrace + it.stackTrace.reversed().map { "at $it" })) } - return listOfNotNull(messageVar, causeVar).toMutableList() + return causeVar?.let { mutableListOf(messageVar, it) } ?: mutableListOf(messageVar) } private fun evaluateAdditionalStackTrace(e: Throwable): List { diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/Primitive.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/Primitive.kt index 9581bbff7b5..477952cdcee 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/Primitive.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/Primitive.kt @@ -19,7 +19,7 @@ internal class Primitive(val value: T, val type: IrType) : State { override val fields: MutableList = mutableListOf() override val irClass: IrClass = type.classOrNull!!.owner - override fun getState(symbol: IrSymbol): State? = null + override fun getField(symbol: IrSymbol): State? = null override fun getIrFunctionByIrCall(expression: IrCall): IrFunction { val owner = expression.symbol.owner diff --git a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/State.kt b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/State.kt index e1e64ee893c..f0315d50b43 100644 --- a/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/State.kt +++ b/compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/state/State.kt @@ -19,7 +19,7 @@ internal interface State { val fields: MutableList val irClass: IrClass - fun getState(symbol: IrSymbol): State? { + fun getField(symbol: IrSymbol): State? { return fields.firstOrNull { it.symbol == symbol }?.state }