Rename some methods in interpreter's stack to make their purpose clearer

This commit is contained in:
Ivan Kylchik
2021-08-10 15:27:15 +03:00
committed by TeamCityServer
parent 69fe7e66a5
commit 492b8acf93
9 changed files with 190 additions and 241 deletions
@@ -19,7 +19,6 @@ import org.jetbrains.kotlin.ir.interpreter.intrinsics.IntrinsicEvaluator
import org.jetbrains.kotlin.ir.interpreter.proxy.wrap import org.jetbrains.kotlin.ir.interpreter.proxy.wrap
import org.jetbrains.kotlin.ir.interpreter.stack.CallStack import org.jetbrains.kotlin.ir.interpreter.stack.CallStack
import org.jetbrains.kotlin.ir.interpreter.state.* import org.jetbrains.kotlin.ir.interpreter.state.*
import org.jetbrains.kotlin.ir.interpreter.state.reflection.KTypeState
import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.classOrNull import org.jetbrains.kotlin.ir.types.classOrNull
import org.jetbrains.kotlin.ir.types.isArray import org.jetbrains.kotlin.ir.types.isArray
@@ -51,7 +50,7 @@ internal class DefaultCallInterceptor(override val interpreter: IrInterpreter) :
override fun interceptProxy(irFunction: IrFunction, valueArguments: List<State>, expectedResultClass: Class<*>): Any? { override fun interceptProxy(irFunction: IrFunction, valueArguments: List<State>, expectedResultClass: Class<*>): Any? {
val irCall = irFunction.createCall() val irCall = irFunction.createCall()
return interpreter.withNewCallStack(irCall) { return interpreter.withNewCallStack(irCall) {
this@withNewCallStack.environment.callStack.addInstruction(SimpleInstruction(irCall)) this@withNewCallStack.environment.callStack.pushInstruction(SimpleInstruction(irCall))
valueArguments.forEach { this@withNewCallStack.environment.callStack.pushState(it) } valueArguments.forEach { this@withNewCallStack.environment.callStack.pushState(it) }
}.wrap(this@DefaultCallInterceptor, remainArraysAsIs = false, extendFrom = expectedResultClass) }.wrap(this@DefaultCallInterceptor, remainArraysAsIs = false, extendFrom = expectedResultClass)
} }
@@ -73,7 +72,7 @@ internal class DefaultCallInterceptor(override val interpreter: IrInterpreter) :
} }
override fun interceptConstructor(constructorCall: IrFunctionAccessExpression, args: List<State>, defaultAction: () -> Unit) { override fun interceptConstructor(constructorCall: IrFunctionAccessExpression, args: List<State>, defaultAction: () -> Unit) {
val receiver = callStack.getState(constructorCall.getThisReceiver()) val receiver = callStack.loadState(constructorCall.getThisReceiver())
val irConstructor = constructorCall.symbol.owner val irConstructor = constructorCall.symbol.owner
val irClass = irConstructor.parentAsClass val irClass = irConstructor.parentAsClass
when { when {
@@ -81,7 +80,7 @@ internal class DefaultCallInterceptor(override val interpreter: IrInterpreter) :
Wrapper.getConstructorMethod(irConstructor).invokeMethod(irConstructor, args) Wrapper.getConstructorMethod(irConstructor).invokeMethod(irConstructor, args)
when { when {
irClass.isSubclassOfThrowable() -> (receiver as ExceptionState).copyFieldsFrom(callStack.popState() as Wrapper) irClass.isSubclassOfThrowable() -> (receiver as ExceptionState).copyFieldsFrom(callStack.popState() as Wrapper)
constructorCall is IrConstructorCall -> callStack.setState(constructorCall.getThisReceiver(), callStack.popState()) constructorCall is IrConstructorCall -> callStack.rewriteState(constructorCall.getThisReceiver(), callStack.popState())
else -> (receiver as Complex).superWrapperClass = callStack.popState() as Wrapper else -> (receiver as Complex).superWrapperClass = callStack.popState() as Wrapper
} }
} }
@@ -140,7 +139,7 @@ internal class DefaultCallInterceptor(override val interpreter: IrInterpreter) :
private fun handleIntrinsicMethods(irFunction: IrFunction): Boolean { private fun handleIntrinsicMethods(irFunction: IrFunction): Boolean {
val instructions = IntrinsicEvaluator.unwindInstructions(irFunction, environment) ?: return false val instructions = IntrinsicEvaluator.unwindInstructions(irFunction, environment) ?: return false
instructions.forEach { callStack.addInstruction(it) } instructions.forEach { callStack.pushInstruction(it) }
return true return true
} }
@@ -185,7 +184,7 @@ internal class DefaultCallInterceptor(override val interpreter: IrInterpreter) :
constructorCall.putValueArgument(index, primitive.value.toIrConst(constructorValueParameters[index].owner.type)) constructorCall.putValueArgument(index, primitive.value.toIrConst(constructorValueParameters[index].owner.type))
} }
callStack.addInstruction(CompoundInstruction(constructorCall)) callStack.pushInstruction(CompoundInstruction(constructorCall))
} }
private fun Any?.getType(defaultType: IrType): IrType { private fun Any?.getType(defaultType: IrType): IrType {
@@ -207,7 +206,7 @@ internal class DefaultCallInterceptor(override val interpreter: IrInterpreter) :
private fun IrFunction.trySubstituteFunctionBody(): IrElement? { private fun IrFunction.trySubstituteFunctionBody(): IrElement? {
val signature = this.symbol.signature ?: return null val signature = this.symbol.signature ?: return null
this.body = bodyMap[signature] ?: return null this.body = bodyMap[signature] ?: return null
callStack.addInstruction(CompoundInstruction(this)) callStack.pushInstruction(CompoundInstruction(this))
return body return body
} }
@@ -215,6 +214,6 @@ internal class DefaultCallInterceptor(override val interpreter: IrInterpreter) :
private fun IrFunction.tryCalculateLazyConst(): IrExpression? { private fun IrFunction.tryCalculateLazyConst(): IrExpression? {
if (this !is IrSimpleFunction) return null if (this !is IrSimpleFunction) return null
val expression = this.correspondingPropertySymbol?.owner?.backingField?.initializer?.expression val expression = this.correspondingPropertySymbol?.owner?.backingField?.initializer?.expression
return expression?.apply { callStack.addInstruction(CompoundInstruction(this)) } return expression?.apply { callStack.pushInstruction(CompoundInstruction(this)) }
} }
} }
@@ -25,8 +25,8 @@ internal fun IrExpression.handleAndDropResult(callStack: CallStack, dropOnlyUnit
val dropResult = fun() { val dropResult = fun() {
if (!dropOnlyUnit && !this.type.isUnit() || callStack.peekState().isUnit()) callStack.popState() if (!dropOnlyUnit && !this.type.isUnit() || callStack.peekState().isUnit()) callStack.popState()
} }
callStack.addInstruction(CustomInstruction(dropResult)) callStack.pushInstruction(CustomInstruction(dropResult))
callStack.addInstruction(CompoundInstruction(this)) callStack.pushInstruction(CompoundInstruction(this))
} }
internal fun unfoldInstruction(element: IrElement?, environment: IrInterpreterEnvironment) { internal fun unfoldInstruction(element: IrElement?, environment: IrInterpreterEnvironment) {
@@ -45,11 +45,11 @@ internal fun unfoldInstruction(element: IrElement?, environment: IrInterpreterEn
is IrBlock -> unfoldBlock(element, callStack) is IrBlock -> unfoldBlock(element, callStack)
is IrReturn -> unfoldReturn(element, callStack) is IrReturn -> unfoldReturn(element, callStack)
is IrSetField -> unfoldSetField(element, callStack) is IrSetField -> unfoldSetField(element, callStack)
is IrGetField -> callStack.addInstruction(SimpleInstruction(element)) is IrGetField -> callStack.pushInstruction(SimpleInstruction(element))
is IrGetValue -> unfoldGetValue(element, environment) is IrGetValue -> unfoldGetValue(element, environment)
is IrGetObjectValue -> unfoldGetObjectValue(element, environment) is IrGetObjectValue -> unfoldGetObjectValue(element, environment)
is IrGetEnumValue -> unfoldGetEnumValue(element, environment) is IrGetEnumValue -> unfoldGetEnumValue(element, environment)
is IrConst<*> -> callStack.addInstruction(SimpleInstruction(element)) is IrConst<*> -> callStack.pushInstruction(SimpleInstruction(element))
is IrVariable -> unfoldVariable(element, callStack) is IrVariable -> unfoldVariable(element, callStack)
is IrSetValue -> unfoldSetValue(element, callStack) is IrSetValue -> unfoldSetValue(element, callStack)
is IrTypeOperatorCall -> unfoldTypeOperatorCall(element, callStack) is IrTypeOperatorCall -> unfoldTypeOperatorCall(element, callStack)
@@ -60,12 +60,12 @@ internal fun unfoldInstruction(element: IrElement?, environment: IrInterpreterEn
is IrBreak -> unfoldBreak(element, callStack) is IrBreak -> unfoldBreak(element, callStack)
is IrContinue -> unfoldContinue(element, callStack) is IrContinue -> unfoldContinue(element, callStack)
is IrVararg -> unfoldVararg(element, callStack) is IrVararg -> unfoldVararg(element, callStack)
is IrSpreadElement -> callStack.addInstruction(CompoundInstruction(element.expression)) is IrSpreadElement -> callStack.pushInstruction(CompoundInstruction(element.expression))
is IrTry -> unfoldTry(element, callStack) is IrTry -> unfoldTry(element, callStack)
is IrCatch -> unfoldCatch(element, callStack) is IrCatch -> unfoldCatch(element, callStack)
is IrThrow -> unfoldThrow(element, callStack) is IrThrow -> unfoldThrow(element, callStack)
is IrStringConcatenation -> unfoldStringConcatenation(element, environment) is IrStringConcatenation -> unfoldStringConcatenation(element, environment)
is IrFunctionExpression -> callStack.addInstruction(SimpleInstruction(element)) is IrFunctionExpression -> callStack.pushInstruction(SimpleInstruction(element))
is IrFunctionReference -> unfoldFunctionReference(element, callStack) is IrFunctionReference -> unfoldFunctionReference(element, callStack)
is IrPropertyReference -> unfoldPropertyReference(element, callStack) is IrPropertyReference -> unfoldPropertyReference(element, callStack)
is IrClassReference -> unfoldClassReference(element, callStack) is IrClassReference -> unfoldClassReference(element, callStack)
@@ -83,7 +83,7 @@ private fun unfoldFunction(function: IrSimpleFunction, environment: IrInterprete
} }
// SimpleInstruction with function is added in IrCall // SimpleInstruction with function is added in IrCall
// It will serve as endpoint for all possible calls, there we drop frame and copy result to new one // It will serve as endpoint for all possible calls, there we drop frame and copy result to new one
function.body?.let { environment.callStack.addInstruction(CompoundInstruction(it)) } function.body?.let { environment.callStack.pushInstruction(CompoundInstruction(it)) }
?: throw InterpreterError("Ir function must be with body") ?: throw InterpreterError("Ir function must be with body")
} }
@@ -92,18 +92,18 @@ private fun unfoldConstructor(constructor: IrConstructor, callStack: CallStack)
"kotlin.Enum.<init>", "kotlin.Throwable.<init>" -> { "kotlin.Enum.<init>", "kotlin.Throwable.<init>" -> {
val irClass = constructor.parentAsClass val irClass = constructor.parentAsClass
val receiverSymbol = irClass.thisReceiver!!.symbol val receiverSymbol = irClass.thisReceiver!!.symbol
val receiverState = callStack.getState(receiverSymbol) val receiverState = callStack.loadState(receiverSymbol)
irClass.declarations.filterIsInstance<IrProperty>().forEach { property -> irClass.declarations.filterIsInstance<IrProperty>().forEach { property ->
val parameter = constructor.valueParameters.singleOrNull { it.name == property.name } val parameter = constructor.valueParameters.singleOrNull { it.name == property.name }
val state = parameter?.let { callStack.getState(it.symbol) } ?: Primitive.nullStateOfType(property.getter!!.returnType) val state = parameter?.let { callStack.loadState(it.symbol) } ?: Primitive.nullStateOfType(property.getter!!.returnType)
receiverState.setField(property.symbol, state) receiverState.setField(property.symbol, state)
} }
} }
else -> { else -> {
// SimpleInstruction with function is added in constructor call // SimpleInstruction with function is added in constructor call
// It will serve as endpoint for all possible constructor calls, there we drop frame and return object // It will serve as endpoint for all possible constructor calls, there we drop frame and return object
callStack.addInstruction(CompoundInstruction(constructor.body!!)) callStack.pushInstruction(CompoundInstruction(constructor.body!!))
} }
} }
} }
@@ -114,7 +114,7 @@ private fun unfoldValueParameters(expression: IrFunctionAccessExpression, enviro
if (hasDefaults) { if (hasDefaults) {
environment.getCachedFunction(expression.symbol, fromDelegatingCall = expression is IrDelegatingConstructorCall)?.let { environment.getCachedFunction(expression.symbol, fromDelegatingCall = expression is IrDelegatingConstructorCall)?.let {
val callToDefault = it.owner.createCall().apply { environment.irBuiltIns.copyArgs(expression, this) } val callToDefault = it.owner.createCall().apply { environment.irBuiltIns.copyArgs(expression, this) }
callStack.addInstruction(CompoundInstruction(callToDefault)) callStack.pushInstruction(CompoundInstruction(callToDefault))
return return
} }
@@ -140,7 +140,7 @@ private fun unfoldValueParameters(expression: IrFunctionAccessExpression, enviro
actualParameters[index] = if (copiedParameter.defaultValue != null || copiedParameter.isVararg) { actualParameters[index] = if (copiedParameter.defaultValue != null || copiedParameter.isVararg) {
copiedParameter.type = copiedParameter.type.makeNullable() // make nullable type to keep consistency; parameter can be null if it is missing copiedParameter.type = copiedParameter.type.makeNullable() // make nullable type to keep consistency; parameter can be null if it is missing
val irGetParameter = copiedParameter.createGetValue() val irGetParameter = copiedParameter.createGetValue()
// if parameter is vararg and it is missing then create constructor call for empty array // if parameter is vararg and it is missing, then create constructor call for empty array
val defaultInitializer = originalParameter.getDefaultWithActualParameters(this@apply, actualParameters) val defaultInitializer = originalParameter.getDefaultWithActualParameters(this@apply, actualParameters)
?: environment.irBuiltIns.emptyArrayConstructor(expression.getVarargType(index)!!.getTypeIfReified(callStack)) ?: environment.irBuiltIns.emptyArrayConstructor(expression.getVarargType(index)!!.getTypeIfReified(callStack))
@@ -162,14 +162,14 @@ private fun unfoldValueParameters(expression: IrFunctionAccessExpression, enviro
val callToDefault = environment.setCachedFunction( val callToDefault = environment.setCachedFunction(
expression.symbol, fromDelegatingCall = expression is IrDelegatingConstructorCall, newFunction = defaultFun.symbol expression.symbol, fromDelegatingCall = expression is IrDelegatingConstructorCall, newFunction = defaultFun.symbol
).owner.createCall().apply { environment.irBuiltIns.copyArgs(expression, this) } ).owner.createCall().apply { environment.irBuiltIns.copyArgs(expression, this) }
callStack.addInstruction(CompoundInstruction(callToDefault)) callStack.pushInstruction(CompoundInstruction(callToDefault))
} else { } else {
val irFunction = expression.symbol.owner val irFunction = expression.symbol.owner
callStack.addInstruction(SimpleInstruction(expression)) callStack.pushInstruction(SimpleInstruction(expression))
fun IrValueParameter.schedule(arg: IrExpression?) { fun IrValueParameter.schedule(arg: IrExpression?) {
callStack.addInstruction(SimpleInstruction(this)) callStack.pushInstruction(SimpleInstruction(this))
callStack.addInstruction(CompoundInstruction(arg)) callStack.pushInstruction(CompoundInstruction(arg))
} }
(expression.valueArgumentsCount - 1 downTo 0).forEach { irFunction.valueParameters[it].schedule(expression.getValueArgument(it)) } (expression.valueArgumentsCount - 1 downTo 0).forEach { irFunction.valueParameters[it].schedule(expression.getValueArgument(it)) }
expression.extensionReceiver?.let { irFunction.extensionReceiverParameter!!.schedule(it) } expression.extensionReceiver?.let { irFunction.extensionReceiverParameter!!.schedule(it) }
@@ -183,25 +183,25 @@ private fun unfoldInstanceInitializerCall(instanceInitializerCall: IrInstanceIni
toInitialize.reversed().forEach { toInitialize.reversed().forEach {
when { when {
it is IrAnonymousInitializer -> callStack.addInstruction(CompoundInstruction(it.body)) it is IrAnonymousInitializer -> callStack.pushInstruction(CompoundInstruction(it.body))
it is IrProperty && it.backingField?.initializer?.expression != null -> callStack.addInstruction(CompoundInstruction(it.backingField)) it is IrProperty && it.backingField?.initializer?.expression != null -> callStack.pushInstruction(CompoundInstruction(it.backingField))
} }
} }
} }
private fun unfoldField(field: IrField, callStack: CallStack) { private fun unfoldField(field: IrField, callStack: CallStack) {
callStack.addInstruction(SimpleInstruction(field)) callStack.pushInstruction(SimpleInstruction(field))
callStack.addInstruction(CompoundInstruction(field.initializer?.expression)) callStack.pushInstruction(CompoundInstruction(field.initializer?.expression))
} }
private fun unfoldBody(body: IrBody, callStack: CallStack) { private fun unfoldBody(body: IrBody, callStack: CallStack) {
callStack.addInstruction(SimpleInstruction(body)) callStack.pushInstruction(SimpleInstruction(body))
unfoldStatements(body.statements, callStack) unfoldStatements(body.statements, callStack)
} }
private fun unfoldBlock(block: IrBlock, callStack: CallStack) { private fun unfoldBlock(block: IrBlock, callStack: CallStack) {
callStack.newSubFrame(block) callStack.newSubFrame(block)
callStack.addInstruction(SimpleInstruction(block)) callStack.pushInstruction(SimpleInstruction(block))
unfoldStatements(block.statements, callStack) unfoldStatements(block.statements, callStack)
} }
@@ -214,24 +214,24 @@ private fun unfoldStatements(statements: List<IrStatement>, callStack: CallStack
is IrFunction -> if (!statement.isLocal) TODO("Only local functions are supported") is IrFunction -> if (!statement.isLocal) TODO("Only local functions are supported")
is IrExpression -> is IrExpression ->
when { when {
i.isLastIndex() -> callStack.addInstruction(CompoundInstruction(statement)) i.isLastIndex() -> callStack.pushInstruction(CompoundInstruction(statement))
else -> statement.handleAndDropResult(callStack, dropOnlyUnit = true) else -> statement.handleAndDropResult(callStack, dropOnlyUnit = true)
} }
else -> callStack.addInstruction(CompoundInstruction(statement)) else -> callStack.pushInstruction(CompoundInstruction(statement))
} }
} }
} }
private fun unfoldReturn(expression: IrReturn, callStack: CallStack) { private fun unfoldReturn(expression: IrReturn, callStack: CallStack) {
callStack.addInstruction(SimpleInstruction(expression)) callStack.pushInstruction(SimpleInstruction(expression))
callStack.addInstruction(CompoundInstruction(expression.value)) callStack.pushInstruction(CompoundInstruction(expression.value))
} }
private fun unfoldSetField(expression: IrSetField, callStack: CallStack) { private fun unfoldSetField(expression: IrSetField, callStack: CallStack) {
verify(!expression.accessesTopLevelOrObjectField()) { "Cannot interpret set method on top level properties" } verify(!expression.accessesTopLevelOrObjectField()) { "Cannot interpret set method on top level properties" }
callStack.addInstruction(SimpleInstruction(expression)) callStack.pushInstruction(SimpleInstruction(expression))
callStack.addInstruction(CompoundInstruction(expression.value)) callStack.pushInstruction(CompoundInstruction(expression.value))
} }
private fun unfoldGetValue(expression: IrGetValue, environment: IrInterpreterEnvironment) { private fun unfoldGetValue(expression: IrGetValue, environment: IrInterpreterEnvironment) {
@@ -242,7 +242,7 @@ private fun unfoldGetValue(expression: IrGetValue, environment: IrInterpreterEnv
val irGetObject = expectedClass.createGetObject() val irGetObject = expectedClass.createGetObject()
return unfoldGetObjectValue(irGetObject, environment) return unfoldGetObjectValue(irGetObject, environment)
} }
environment.callStack.pushState(environment.callStack.getState(expression.symbol)) environment.callStack.pushState(environment.callStack.loadState(expression.symbol))
} }
private fun unfoldGetObjectValue(expression: IrGetObjectValue, environment: IrInterpreterEnvironment) { private fun unfoldGetObjectValue(expression: IrGetObjectValue, environment: IrInterpreterEnvironment) {
@@ -250,64 +250,64 @@ private fun unfoldGetObjectValue(expression: IrGetObjectValue, environment: IrIn
val objectClass = expression.symbol.owner val objectClass = expression.symbol.owner
environment.mapOfObjects[objectClass.symbol]?.let { return callStack.pushState(it) } environment.mapOfObjects[objectClass.symbol]?.let { return callStack.pushState(it) }
callStack.addInstruction(SimpleInstruction(expression)) callStack.pushInstruction(SimpleInstruction(expression))
} }
private fun unfoldGetEnumValue(expression: IrGetEnumValue, environment: IrInterpreterEnvironment) { private fun unfoldGetEnumValue(expression: IrGetEnumValue, environment: IrInterpreterEnvironment) {
val callStack = environment.callStack val callStack = environment.callStack
environment.mapOfEnums[expression.symbol]?.let { return callStack.pushState(it) } environment.mapOfEnums[expression.symbol]?.let { return callStack.pushState(it) }
callStack.addInstruction(SimpleInstruction(expression)) callStack.pushInstruction(SimpleInstruction(expression))
val enumEntry = expression.symbol.owner val enumEntry = expression.symbol.owner
val enumClass = enumEntry.symbol.owner.parentAsClass val enumClass = enumEntry.symbol.owner.parentAsClass
enumClass.declarations.filterIsInstance<IrEnumEntry>().forEach { enumClass.declarations.filterIsInstance<IrEnumEntry>().forEach {
callStack.addInstruction(SimpleInstruction(it)) callStack.pushInstruction(SimpleInstruction(it))
} }
} }
private fun unfoldVariable(variable: IrVariable, callStack: CallStack) { private fun unfoldVariable(variable: IrVariable, callStack: CallStack) {
when (variable.initializer) { when (variable.initializer) {
null -> callStack.addVariable(variable.symbol, null) null -> callStack.storeState(variable.symbol, null)
else -> { else -> {
callStack.addInstruction(SimpleInstruction(variable)) callStack.pushInstruction(SimpleInstruction(variable))
callStack.addInstruction(CompoundInstruction(variable.initializer!!)) callStack.pushInstruction(CompoundInstruction(variable.initializer!!))
} }
} }
} }
private fun unfoldSetValue(expression: IrSetValue, callStack: CallStack) { private fun unfoldSetValue(expression: IrSetValue, callStack: CallStack) {
callStack.addInstruction(SimpleInstruction(expression)) callStack.pushInstruction(SimpleInstruction(expression))
callStack.addInstruction(CompoundInstruction(expression.value)) callStack.pushInstruction(CompoundInstruction(expression.value))
} }
private fun unfoldTypeOperatorCall(element: IrTypeOperatorCall, callStack: CallStack) { private fun unfoldTypeOperatorCall(element: IrTypeOperatorCall, callStack: CallStack) {
callStack.addInstruction(SimpleInstruction(element)) callStack.pushInstruction(SimpleInstruction(element))
callStack.addInstruction(CompoundInstruction(element.argument)) callStack.pushInstruction(CompoundInstruction(element.argument))
} }
private fun unfoldBranch(branch: IrBranch, callStack: CallStack) { private fun unfoldBranch(branch: IrBranch, callStack: CallStack) {
callStack.addInstruction(SimpleInstruction(branch)) callStack.pushInstruction(SimpleInstruction(branch))
callStack.addInstruction(CompoundInstruction(branch.condition)) callStack.pushInstruction(CompoundInstruction(branch.condition))
} }
private fun unfoldWhileLoop(loop: IrWhileLoop, callStack: CallStack) { private fun unfoldWhileLoop(loop: IrWhileLoop, callStack: CallStack) {
callStack.newSubFrame(loop) callStack.newSubFrame(loop)
callStack.addInstruction(SimpleInstruction(loop)) callStack.pushInstruction(SimpleInstruction(loop))
callStack.addInstruction(CompoundInstruction(loop.condition)) callStack.pushInstruction(CompoundInstruction(loop.condition))
} }
private fun unfoldDoWhileLoop(loop: IrDoWhileLoop, callStack: CallStack) { private fun unfoldDoWhileLoop(loop: IrDoWhileLoop, callStack: CallStack) {
callStack.newSubFrame(loop) callStack.newSubFrame(loop)
callStack.addInstruction(SimpleInstruction(loop)) callStack.pushInstruction(SimpleInstruction(loop))
callStack.addInstruction(CompoundInstruction(loop.condition)) callStack.pushInstruction(CompoundInstruction(loop.condition))
callStack.addInstruction(CompoundInstruction(loop.body)) callStack.pushInstruction(CompoundInstruction(loop.body))
} }
private fun unfoldWhen(element: IrWhen, callStack: CallStack) { private fun unfoldWhen(element: IrWhen, callStack: CallStack) {
// new sub frame to drop it after // new sub frame to drop it after
callStack.newSubFrame(element) callStack.newSubFrame(element)
callStack.addInstruction(SimpleInstruction(element)) callStack.pushInstruction(SimpleInstruction(element))
element.branches.reversed().forEach { callStack.addInstruction(CompoundInstruction(it)) } element.branches.reversed().forEach { callStack.pushInstruction(CompoundInstruction(it)) }
} }
private fun unfoldContinue(element: IrContinue, callStack: CallStack) { private fun unfoldContinue(element: IrContinue, callStack: CallStack) {
@@ -319,14 +319,14 @@ private fun unfoldBreak(element: IrBreak, callStack: CallStack) {
} }
private fun unfoldVararg(element: IrVararg, callStack: CallStack) { private fun unfoldVararg(element: IrVararg, callStack: CallStack) {
callStack.addInstruction(SimpleInstruction(element)) callStack.pushInstruction(SimpleInstruction(element))
element.elements.reversed().forEach { callStack.addInstruction(CompoundInstruction(it)) } element.elements.reversed().forEach { callStack.pushInstruction(CompoundInstruction(it)) }
} }
private fun unfoldTry(element: IrTry, callStack: CallStack) { private fun unfoldTry(element: IrTry, callStack: CallStack) {
callStack.newSubFrame(element) callStack.newSubFrame(element)
callStack.addInstruction(SimpleInstruction(element)) callStack.pushInstruction(SimpleInstruction(element))
callStack.addInstruction(CompoundInstruction(element.tryResult)) callStack.pushInstruction(CompoundInstruction(element.tryResult))
} }
private fun unfoldCatch(element: IrCatch, callStack: CallStack) { private fun unfoldCatch(element: IrCatch, callStack: CallStack) {
@@ -336,20 +336,20 @@ private fun unfoldCatch(element: IrCatch, callStack: CallStack) {
val frameOwner = callStack.currentFrameOwner as IrTry val frameOwner = callStack.currentFrameOwner as IrTry
callStack.dropSubFrame() // drop other catch blocks callStack.dropSubFrame() // drop other catch blocks
callStack.newSubFrame(element) // 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(element.catchParameter.symbol, exceptionState) callStack.storeState(element.catchParameter.symbol, exceptionState)
callStack.addInstruction(SimpleInstruction(frameOwner)) callStack.pushInstruction(SimpleInstruction(frameOwner))
callStack.addInstruction(CompoundInstruction(element.result)) callStack.pushInstruction(CompoundInstruction(element.result))
} }
} }
private fun unfoldThrow(expression: IrThrow, callStack: CallStack) { private fun unfoldThrow(expression: IrThrow, callStack: CallStack) {
callStack.addInstruction(SimpleInstruction(expression)) callStack.pushInstruction(SimpleInstruction(expression))
callStack.addInstruction(CompoundInstruction(expression.value)) callStack.pushInstruction(CompoundInstruction(expression.value))
} }
private fun unfoldStringConcatenation(expression: IrStringConcatenation, environment: IrInterpreterEnvironment) { private fun unfoldStringConcatenation(expression: IrStringConcatenation, environment: IrInterpreterEnvironment) {
val callStack = environment.callStack val callStack = environment.callStack
callStack.addInstruction(SimpleInstruction(expression)) callStack.pushInstruction(SimpleInstruction(expression))
// this callback is used to check the need for an explicit toString call // this callback is used to check the need for an explicit toString call
val explicitToStringCheck = fun() { val explicitToStringCheck = fun() {
@@ -368,52 +368,52 @@ private fun unfoldStringConcatenation(expression: IrStringConcatenation, environ
return callStack.pushState(environment.convertToState(result, environment.irBuiltIns.stringType)) return callStack.pushState(environment.convertToState(result, environment.irBuiltIns.stringType))
} }
val toStringCall = state.createToStringIrCall() val toStringCall = state.createToStringIrCall()
callStack.addInstruction(SimpleInstruction(toStringCall)) callStack.pushInstruction(SimpleInstruction(toStringCall))
callStack.pushState(state) callStack.pushState(state)
} }
} }
} }
expression.arguments.reversed().forEach { expression.arguments.reversed().forEach {
callStack.addInstruction(CustomInstruction(explicitToStringCheck)) callStack.pushInstruction(CustomInstruction(explicitToStringCheck))
callStack.addInstruction(CompoundInstruction(it)) callStack.pushInstruction(CompoundInstruction(it))
} }
} }
private fun unfoldComposite(element: IrComposite, callStack: CallStack) { private fun unfoldComposite(element: IrComposite, callStack: CallStack) {
when (element.origin) { when (element.origin) {
IrStatementOrigin.DESTRUCTURING_DECLARATION, IrStatementOrigin.DO_WHILE_LOOP, null -> // is null for body of do while loop IrStatementOrigin.DESTRUCTURING_DECLARATION, IrStatementOrigin.DO_WHILE_LOOP, null -> // is null for body of do while loop
element.statements.reversed().forEach { callStack.addInstruction(CompoundInstruction(it)) } element.statements.reversed().forEach { callStack.pushInstruction(CompoundInstruction(it)) }
else -> TODO("${element.origin} not implemented") else -> TODO("${element.origin} not implemented")
} }
} }
private fun unfoldFunctionReference(reference: IrFunctionReference, callStack: CallStack) { private fun unfoldFunctionReference(reference: IrFunctionReference, callStack: CallStack) {
val function = reference.symbol.owner val function = reference.symbol.owner
callStack.addInstruction(SimpleInstruction(reference)) callStack.pushInstruction(SimpleInstruction(reference))
reference.dispatchReceiver?.let { callStack.addInstruction(SimpleInstruction(function.dispatchReceiverParameter!!)) } reference.dispatchReceiver?.let { callStack.pushInstruction(SimpleInstruction(function.dispatchReceiverParameter!!)) }
reference.extensionReceiver?.let { callStack.addInstruction(SimpleInstruction(function.extensionReceiverParameter!!)) } reference.extensionReceiver?.let { callStack.pushInstruction(SimpleInstruction(function.extensionReceiverParameter!!)) }
reference.extensionReceiver?.let { callStack.addInstruction(CompoundInstruction(it)) } reference.extensionReceiver?.let { callStack.pushInstruction(CompoundInstruction(it)) }
reference.dispatchReceiver?.let { callStack.addInstruction(CompoundInstruction(it)) } reference.dispatchReceiver?.let { callStack.pushInstruction(CompoundInstruction(it)) }
} }
private fun unfoldPropertyReference(propertyReference: IrPropertyReference, callStack: CallStack) { private fun unfoldPropertyReference(propertyReference: IrPropertyReference, callStack: CallStack) {
val getter = propertyReference.getter!!.owner val getter = propertyReference.getter!!.owner
callStack.addInstruction(SimpleInstruction(propertyReference)) callStack.pushInstruction(SimpleInstruction(propertyReference))
propertyReference.dispatchReceiver?.let { callStack.addInstruction(SimpleInstruction(getter.dispatchReceiverParameter!!)) } propertyReference.dispatchReceiver?.let { callStack.pushInstruction(SimpleInstruction(getter.dispatchReceiverParameter!!)) }
propertyReference.extensionReceiver?.let { callStack.addInstruction(SimpleInstruction(getter.extensionReceiverParameter!!)) } propertyReference.extensionReceiver?.let { callStack.pushInstruction(SimpleInstruction(getter.extensionReceiverParameter!!)) }
propertyReference.extensionReceiver?.let { callStack.addInstruction(CompoundInstruction(it)) } propertyReference.extensionReceiver?.let { callStack.pushInstruction(CompoundInstruction(it)) }
propertyReference.dispatchReceiver?.let { callStack.addInstruction(CompoundInstruction(it)) } propertyReference.dispatchReceiver?.let { callStack.pushInstruction(CompoundInstruction(it)) }
} }
private fun unfoldClassReference(classReference: IrClassReference, callStack: CallStack) { private fun unfoldClassReference(classReference: IrClassReference, callStack: CallStack) {
callStack.addInstruction(SimpleInstruction(classReference)) callStack.pushInstruction(SimpleInstruction(classReference))
} }
private fun unfoldGetClass(element: IrGetClass, callStack: CallStack) { private fun unfoldGetClass(element: IrGetClass, callStack: CallStack) {
callStack.addInstruction(SimpleInstruction(element)) callStack.pushInstruction(SimpleInstruction(element))
callStack.addInstruction(CompoundInstruction(element.argument)) callStack.pushInstruction(CompoundInstruction(element.argument))
} }
@@ -65,7 +65,7 @@ class IrInterpreter(internal val environment: IrInterpreterEnvironment, internal
fun interpret(expression: IrExpression, file: IrFile? = null): IrExpression { fun interpret(expression: IrExpression, file: IrFile? = null): IrExpression {
commandCount = 0 commandCount = 0
callStack.newFrame(expression, file) callStack.newFrame(expression, file)
callStack.addInstruction(CompoundInstruction(expression)) callStack.pushInstruction(CompoundInstruction(expression))
while (!callStack.hasNoInstructions()) { while (!callStack.hasNoInstructions()) {
callStack.popInstruction().handle() callStack.popInstruction().handle()
@@ -106,8 +106,8 @@ class IrInterpreter(internal val environment: IrInterpreterEnvironment, internal
is IrGetEnumValue -> interpretGetEnumValue(element) is IrGetEnumValue -> interpretGetEnumValue(element)
is IrEnumEntry -> interpretEnumEntry(element) is IrEnumEntry -> interpretEnumEntry(element)
is IrConst<*> -> interpretConst(element) is IrConst<*> -> interpretConst(element)
is IrVariable -> callStack.addVariable(element.symbol, callStack.popState()) is IrVariable -> callStack.storeState(element.symbol, callStack.popState())
is IrSetValue -> callStack.setState(element.symbol, callStack.popState()) is IrSetValue -> callStack.rewriteState(element.symbol, callStack.popState())
is IrTypeOperatorCall -> interpretTypeOperatorCall(element) is IrTypeOperatorCall -> interpretTypeOperatorCall(element)
is IrBranch -> interpretBranch(element) is IrBranch -> interpretBranch(element)
is IrWhileLoop -> interpretWhile(element) is IrWhileLoop -> interpretWhile(element)
@@ -174,7 +174,7 @@ class IrInterpreter(internal val environment: IrInterpreterEnvironment, internal
val reifiedTypeArguments = environment.loadReifiedTypeArguments(call) val reifiedTypeArguments = environment.loadReifiedTypeArguments(call)
callStack.newFrame(irFunction) callStack.newFrame(irFunction)
callStack.addInstruction(SimpleInstruction(irFunction)) callStack.pushInstruction(SimpleInstruction(irFunction))
// 4. load up values onto stack; do it at first to set low priority of these variables // 4. load up values onto stack; do it at first to set low priority of these variables
if (dispatchReceiver is StateWithClosure) callStack.loadUpValues(dispatchReceiver) if (dispatchReceiver is StateWithClosure) callStack.loadUpValues(dispatchReceiver)
@@ -182,27 +182,27 @@ class IrInterpreter(internal val environment: IrInterpreterEnvironment, internal
if (irFunction.isLocal) callStack.copyUpValuesFromPreviousFrame() if (irFunction.isLocal) callStack.copyUpValuesFromPreviousFrame()
// 5. store arguments in memory (remap args on actual names) // 5. store arguments in memory (remap args on actual names)
irFunction.getDispatchReceiver()?.let { callStack.addVariable(it, dispatchReceiver!!) } irFunction.getDispatchReceiver()?.let { callStack.storeState(it, dispatchReceiver!!) }
irFunction.getExtensionReceiver()?.let { callStack.addVariable(it, extensionReceiver ?: callStack.getState(it)) } irFunction.getExtensionReceiver()?.let { callStack.storeState(it, extensionReceiver ?: callStack.loadState(it)) }
irFunction.valueParameters.forEachIndexed { i, param -> callStack.addVariable(param.symbol, valueArguments[i]) } irFunction.valueParameters.forEachIndexed { i, param -> callStack.storeState(param.symbol, valueArguments[i]) }
// `call.type` is used in check cast and emptyArray // `call.type` is used in check cast and emptyArray
callStack.addVariable(irFunction.symbol, KTypeState(call.type, environment.kTypeClass.owner)) callStack.storeState(irFunction.symbol, KTypeState(call.type, environment.kTypeClass.owner))
// 6. store reified type parameters // 6. store reified type parameters
reifiedTypeArguments.forEach { callStack.addVariable(it.key, it.value) } reifiedTypeArguments.forEach { callStack.storeState(it.key, it.value) }
// 7. load outer class object // 7. load outer class object
if (dispatchReceiver is Complex && irFunction.parentClassOrNull?.isInner == true) dispatchReceiver.loadOuterClassesInto(callStack) if (dispatchReceiver is Complex && irFunction.parentClassOrNull?.isInner == true) dispatchReceiver.loadOuterClassesInto(callStack)
callInterceptor.interceptCall(call, irFunction, args) { callInterceptor.interceptCall(call, irFunction, args) {
callStack.addInstruction(CompoundInstruction(irFunction)) callStack.pushInstruction(CompoundInstruction(irFunction))
} }
} }
private fun interpretField(field: IrField) { private fun interpretField(field: IrField) {
val irClass = field.parentAsClass val irClass = field.parentAsClass
val receiver = irClass.thisReceiver!!.symbol val receiver = irClass.thisReceiver!!.symbol
val receiverState = callStack.getState(receiver) val receiverState = callStack.loadState(receiver)
receiverState.setField(field.correspondingPropertySymbol!!, callStack.popState()) receiverState.setField(field.correspondingPropertySymbol!!, callStack.popState())
} }
@@ -219,7 +219,7 @@ class IrInterpreter(internal val environment: IrInterpreterEnvironment, internal
@Suppress("UNUSED_PARAMETER") @Suppress("UNUSED_PARAMETER")
private fun interpretConstructor(constructor: IrConstructor) { private fun interpretConstructor(constructor: IrConstructor) {
callStack.pushState(callStack.getState(constructor.parentAsClass.thisReceiver!!.symbol)) callStack.pushState(callStack.loadState(constructor.parentAsClass.thisReceiver!!.symbol))
callStack.dropFrameAndCopyResult() callStack.dropFrameAndCopyResult()
} }
@@ -231,7 +231,7 @@ class IrInterpreter(internal val environment: IrInterpreterEnvironment, internal
// this check is used to be sure that object will be created once // this check is used to be sure that object will be created once
val objectState = when (constructorCall) { val objectState = when (constructorCall) {
!is IrConstructorCall -> callStack.getState(constructorCall.getThisReceiver()) !is IrConstructorCall -> callStack.loadState(constructorCall.getThisReceiver())
else -> (if (irClass.isSubclassOfThrowable()) ExceptionState(irClass, callStack.getStackTrace()) else Common(irClass)) else -> (if (irClass.isSubclassOfThrowable()) ExceptionState(irClass, callStack.getStackTrace()) else Common(irClass))
.apply { .apply {
// must set object's state here, before actual initialization, to avoid cyclic evaluation // must set object's state here, before actual initialization, to avoid cyclic evaluation
@@ -244,12 +244,12 @@ class IrInterpreter(internal val environment: IrInterpreterEnvironment, internal
val returnType = constructorCall.type.getTypeIfReified(callStack) val returnType = constructorCall.type.getTypeIfReified(callStack)
callStack.newFrame(constructor) callStack.newFrame(constructor)
callStack.addInstruction(SimpleInstruction(constructor)) callStack.pushInstruction(SimpleInstruction(constructor))
if (irClass.isLocal) callStack.loadUpValues(objectState as StateWithClosure) if (irClass.isLocal) callStack.loadUpValues(objectState as StateWithClosure)
callStack.addVariable(constructorCall.getThisReceiver(), objectState) callStack.storeState(constructorCall.getThisReceiver(), objectState)
constructor.valueParameters.forEachIndexed { i, param -> callStack.addVariable(param.symbol, valueArguments[i]) } constructor.valueParameters.forEachIndexed { i, param -> callStack.storeState(param.symbol, valueArguments[i]) }
callStack.addVariable(constructor.symbol, KTypeState(returnType, environment.kTypeClass.owner)) callStack.storeState(constructor.symbol, KTypeState(returnType, environment.kTypeClass.owner))
val superReceiver = when (val irStatement = constructor.body?.statements?.get(0)) { val superReceiver = when (val irStatement = constructor.body?.statements?.get(0)) {
null -> null // for jvm null -> null // for jvm
@@ -258,7 +258,7 @@ class IrInterpreter(internal val environment: IrInterpreterEnvironment, internal
is IrBlock -> (irStatement.statements.last() as IrFunctionAccessExpression).getThisReceiver() is IrBlock -> (irStatement.statements.last() as IrFunctionAccessExpression).getThisReceiver()
else -> TODO("${irStatement::class.java} is not supported as first statement in constructor call") else -> TODO("${irStatement::class.java} is not supported as first statement in constructor call")
} }
superReceiver?.let { callStack.addVariable(it, objectState) } superReceiver?.let { callStack.storeState(it, objectState) }
if (outerClass != null) { if (outerClass != null) {
val outerClassSymbolToState = irClass.parentAsClass.thisReceiver!!.symbol to outerClass val outerClassSymbolToState = irClass.parentAsClass.thisReceiver!!.symbol to outerClass
@@ -267,14 +267,14 @@ class IrInterpreter(internal val environment: IrInterpreterEnvironment, internal
// This check is needed to test that this inner class is not subclass of its outer. // This check is needed to test that this inner class is not subclass of its outer.
// If it is true and if we add the next symbol, it will interfere with super symbol in memory. // If it is true and if we add the next symbol, it will interfere with super symbol in memory.
// In other case, we need this variable when inner class has inner super class. // In other case, we need this variable when inner class has inner super class.
callStack.addVariable(receiverSymbol, outerClass) callStack.storeState(receiverSymbol, outerClass)
// used to get information from outer class // used to get information from outer class
objectState.loadOuterClassesInto(callStack, constructorCall.getThisReceiver()) objectState.loadOuterClassesInto(callStack, constructorCall.getThisReceiver())
} }
} }
callInterceptor.interceptConstructor(constructorCall, valueArguments) { callInterceptor.interceptConstructor(constructorCall, valueArguments) {
callStack.addInstruction(CompoundInstruction(constructor)) callStack.pushInstruction(CompoundInstruction(constructor))
} }
} }
@@ -303,7 +303,7 @@ class IrInterpreter(internal val environment: IrInterpreterEnvironment, internal
val constructorCall = IrConstructorCallImpl.fromSymbolOwner(constructor.returnType, constructor.symbol) val constructorCall = IrConstructorCallImpl.fromSymbolOwner(constructor.returnType, constructor.symbol)
constructorCall.putValueArgument(0, expression.value.toIrConst(signedType)) constructorCall.putValueArgument(0, expression.value.toIrConst(signedType))
return callStack.addInstruction(CompoundInstruction(constructorCall)) return callStack.pushInstruction(CompoundInstruction(constructorCall))
} }
callStack.pushState(expression.toPrimitive()) callStack.pushState(expression.toPrimitive())
} }
@@ -317,9 +317,9 @@ class IrInterpreter(internal val environment: IrInterpreterEnvironment, internal
callStack.dropSubFrame() callStack.dropSubFrame()
if (result) { if (result) {
callStack.newSubFrame(loop) callStack.newSubFrame(loop)
callStack.addInstruction(SimpleInstruction(loop)) callStack.pushInstruction(SimpleInstruction(loop))
callStack.addInstruction(CompoundInstruction(loop.condition)) callStack.pushInstruction(CompoundInstruction(loop.condition))
callStack.addInstruction(CompoundInstruction(loop.body)) callStack.pushInstruction(CompoundInstruction(loop.body))
} }
} }
@@ -328,9 +328,9 @@ class IrInterpreter(internal val environment: IrInterpreterEnvironment, internal
callStack.dropSubFrame() callStack.dropSubFrame()
if (result) { if (result) {
callStack.newSubFrame(loop) callStack.newSubFrame(loop)
callStack.addInstruction(SimpleInstruction(loop)) callStack.pushInstruction(SimpleInstruction(loop))
callStack.addInstruction(CompoundInstruction(loop.condition)) callStack.pushInstruction(CompoundInstruction(loop.condition))
callStack.addInstruction(CompoundInstruction(loop.body)) callStack.pushInstruction(CompoundInstruction(loop.body))
} }
} }
@@ -338,14 +338,14 @@ class IrInterpreter(internal val environment: IrInterpreterEnvironment, internal
val result = callStack.popState().asBoolean() val result = callStack.popState().asBoolean()
if (result) { if (result) {
callStack.dropSubFrame() callStack.dropSubFrame()
callStack.addInstruction(CompoundInstruction(branch.result)) callStack.pushInstruction(CompoundInstruction(branch.result))
} }
} }
private fun interpretSetField(expression: IrSetField) { private fun interpretSetField(expression: IrSetField) {
val receiver = (expression.receiver as IrDeclarationReference).symbol val receiver = (expression.receiver as IrDeclarationReference).symbol
val propertySymbol = expression.symbol.owner.correspondingPropertySymbol!! val propertySymbol = expression.symbol.owner.correspondingPropertySymbol!!
callStack.getState(receiver).apply { this.setField(propertySymbol, callStack.popState()) } callStack.loadState(receiver).apply { this.setField(propertySymbol, callStack.popState()) }
} }
private fun interpretGetField(expression: IrGetField) { private fun interpretGetField(expression: IrGetField) {
@@ -355,12 +355,12 @@ class IrInterpreter(internal val environment: IrInterpreterEnvironment, internal
field.origin == IrDeclarationOrigin.IR_EXTERNAL_JAVA_DECLARATION_STUB && field.isStatic -> { field.origin == IrDeclarationOrigin.IR_EXTERNAL_JAVA_DECLARATION_STUB && field.isStatic -> {
// for java static variables // for java static variables
when (val initializerExpression = field.initializer?.expression) { when (val initializerExpression = field.initializer?.expression) {
is IrConst<*> -> callStack.addInstruction(SimpleInstruction(initializerExpression)) is IrConst<*> -> callStack.pushInstruction(SimpleInstruction(initializerExpression))
else -> callInterceptor.interceptJavaStaticField(expression) else -> callInterceptor.interceptJavaStaticField(expression)
} }
} }
field.origin == IrDeclarationOrigin.PROPERTY_BACKING_FIELD && field.correspondingPropertySymbol?.owner?.isConst == true -> { field.origin == IrDeclarationOrigin.PROPERTY_BACKING_FIELD && field.correspondingPropertySymbol?.owner?.isConst == true -> {
callStack.addInstruction(CompoundInstruction(field.initializer?.expression)) callStack.pushInstruction(CompoundInstruction(field.initializer?.expression))
} }
expression.accessesTopLevelOrObjectField() -> { expression.accessesTopLevelOrObjectField() -> {
val propertyOwner = field.correspondingPropertySymbol?.owner val propertyOwner = field.correspondingPropertySymbol?.owner
@@ -368,10 +368,10 @@ class IrInterpreter(internal val environment: IrInterpreterEnvironment, internal
propertyOwner?.backingField?.initializer?.expression is IrConst<*> || propertyOwner?.backingField?.initializer?.expression is IrConst<*> ||
propertyOwner?.parentClassOrNull?.hasAnnotation(compileTimeAnnotation) == true // check if object is marked as compile time propertyOwner?.parentClassOrNull?.hasAnnotation(compileTimeAnnotation) == true // check if object is marked as compile time
verify(isConst) { "Cannot interpret get method on top level non const properties" } verify(isConst) { "Cannot interpret get method on top level non const properties" }
callStack.addInstruction(CompoundInstruction(field.initializer?.expression)) callStack.pushInstruction(CompoundInstruction(field.initializer?.expression))
} }
else -> { else -> {
val result = callStack.getState(receiver!!).getField(field.correspondingPropertySymbol!!) val result = callStack.loadState(receiver!!).getField(field.correspondingPropertySymbol!!)
callStack.pushState(result!!) callStack.pushState(result!!)
} }
} }
@@ -391,7 +391,7 @@ class IrInterpreter(internal val environment: IrInterpreterEnvironment, internal
val constructor = objectClass.constructors.first() val constructor = objectClass.constructors.first()
val constructorCall = IrConstructorCallImpl.fromSymbolOwner(constructor.returnType, constructor.symbol) val constructorCall = IrConstructorCallImpl.fromSymbolOwner(constructor.returnType, constructor.symbol)
callStack.addInstruction(CompoundInstruction(constructorCall)) callStack.pushInstruction(CompoundInstruction(constructorCall))
} }
} }
@@ -427,9 +427,9 @@ class IrInterpreter(internal val environment: IrInterpreterEnvironment, internal
environment.mapOfEnums[enumEntry.symbol] = enumClassObject environment.mapOfEnums[enumEntry.symbol] = enumClassObject
callStack.newSubFrame(enumEntry) callStack.newSubFrame(enumEntry)
callStack.addInstruction(CustomInstruction(cleanEnumSuperCall)) callStack.pushInstruction(CustomInstruction(cleanEnumSuperCall))
callStack.addInstruction(CompoundInstruction(enumInitializer)) callStack.pushInstruction(CompoundInstruction(enumInitializer))
callStack.addVariable(enumConstructorCall.getThisReceiver(), enumClassObject) callStack.storeState(enumConstructorCall.getThisReceiver(), enumClassObject)
} }
} }
@@ -563,7 +563,7 @@ class IrInterpreter(internal val environment: IrInterpreterEnvironment, internal
callStack.pushState(possibleException) callStack.pushState(possibleException)
callStack.dropFramesUntilTryCatch() callStack.dropFramesUntilTryCatch()
} }
callStack.addInstruction(CustomInstruction(checkUnhandledException)) callStack.pushInstruction(CustomInstruction(checkUnhandledException))
} }
element.finallyExpression?.handleAndDropResult(callStack) element.finallyExpression?.handleAndDropResult(callStack)
} }
@@ -628,7 +628,7 @@ class IrInterpreter(internal val environment: IrInterpreterEnvironment, internal
private fun interpretClassReference(classReference: IrClassReference) { private fun interpretClassReference(classReference: IrClassReference) {
when (classReference.symbol) { when (classReference.symbol) {
is IrTypeParameterSymbol -> { // reified is IrTypeParameterSymbol -> { // reified
val kTypeState = callStack.getState(classReference.symbol) as KTypeState val kTypeState = callStack.loadState(classReference.symbol) as KTypeState
callStack.pushState(KClassState(kTypeState.irType.classOrNull!!.owner, classReference.type.classOrNull!!.owner)) callStack.pushState(KClassState(kTypeState.irType.classOrNull!!.owner, classReference.type.classOrNull!!.owner))
} }
else -> callStack.pushState(KClassState(classReference)) else -> callStack.pushState(KClassState(classReference))
@@ -161,7 +161,7 @@ internal fun IrFunction?.checkCast(environment: IrInterpreterEnvironment): Boole
if (actualType.classifierOrNull !is IrTypeParameterSymbol) return true if (actualType.classifierOrNull !is IrTypeParameterSymbol) return true
// TODO expectedType can be missing for functions called as proxy // TODO expectedType can be missing for functions called as proxy
val expectedType = (environment.callStack.getState(this.symbol) as? KTypeState)?.irType ?: return true val expectedType = (environment.callStack.loadState(this.symbol) as? KTypeState)?.irType ?: return true
if (expectedType.classifierOrFail is IrTypeParameterSymbol) return true if (expectedType.classifierOrFail is IrTypeParameterSymbol) return true
val actualState = environment.callStack.peekState() ?: return true val actualState = environment.callStack.peekState() ?: return true
@@ -242,7 +242,7 @@ internal fun IrValueParameter.getDefaultWithActualParameters(
} }
internal fun IrType.getTypeIfReified(callStack: CallStack): IrType { internal fun IrType.getTypeIfReified(callStack: CallStack): IrType {
return this.getTypeIfReified { (callStack.getState(it) as KTypeState).irType } return this.getTypeIfReified { (callStack.loadState(it) as KTypeState).irType }
} }
internal fun IrType.getTypeIfReified(getType: (IrClassifierSymbol) -> IrType): IrType { internal fun IrType.getTypeIfReified(getType: (IrClassifierSymbol) -> IrType): IrType {
@@ -43,7 +43,7 @@ internal object EmptyArray : IntrinsicBase() {
} }
override fun evaluate(irFunction: IrFunction, environment: IrInterpreterEnvironment) { override fun evaluate(irFunction: IrFunction, environment: IrInterpreterEnvironment) {
val returnType = environment.callStack.getState(irFunction.symbol) as KTypeState val returnType = environment.callStack.loadState(irFunction.symbol) as KTypeState
environment.callStack.pushState(environment.convertToState(emptyArray<Any?>(), returnType.irType)) environment.callStack.pushState(environment.convertToState(emptyArray<Any?>(), returnType.irType))
} }
} }
@@ -58,7 +58,7 @@ internal object ArrayOf : IntrinsicBase() {
override fun evaluate(irFunction: IrFunction, environment: IrInterpreterEnvironment) { override fun evaluate(irFunction: IrFunction, environment: IrInterpreterEnvironment) {
val elementsSymbol = irFunction.valueParameters.single().symbol val elementsSymbol = irFunction.valueParameters.single().symbol
val varargVariable = environment.callStack.getState(elementsSymbol) val varargVariable = environment.callStack.loadState(elementsSymbol)
environment.callStack.pushState(varargVariable) environment.callStack.pushState(varargVariable)
} }
} }
@@ -69,9 +69,9 @@ internal object ArrayOfNulls : IntrinsicBase() {
} }
override fun evaluate(irFunction: IrFunction, environment: IrInterpreterEnvironment) { override fun evaluate(irFunction: IrFunction, environment: IrInterpreterEnvironment) {
val size = environment.callStack.getState(irFunction.valueParameters.first().symbol).asInt() val size = environment.callStack.loadState(irFunction.valueParameters.first().symbol).asInt()
val array = arrayOfNulls<Any?>(size) val array = arrayOfNulls<Any?>(size)
val typeArgument = irFunction.typeParameters.map { environment.callStack.getState(it.symbol) }.single() as KTypeState val typeArgument = irFunction.typeParameters.map { environment.callStack.loadState(it.symbol) }.single() as KTypeState
val returnType = (irFunction.returnType as IrSimpleType).buildSimpleType { val returnType = (irFunction.returnType as IrSimpleType).buildSimpleType {
arguments = listOf(makeTypeProjection(typeArgument.irType, Variance.INVARIANT)) arguments = listOf(makeTypeProjection(typeArgument.irType, Variance.INVARIANT))
} }
@@ -88,7 +88,7 @@ internal object EnumValues : IntrinsicBase() {
private fun getEnumClass(irFunction: IrFunction, environment: IrInterpreterEnvironment): IrClass { private fun getEnumClass(irFunction: IrFunction, environment: IrInterpreterEnvironment): IrClass {
return when (irFunction.fqName) { return when (irFunction.fqName) {
"kotlin.enumValues" -> { "kotlin.enumValues" -> {
val kType = environment.callStack.getState(irFunction.typeParameters.first().symbol) as KTypeState val kType = environment.callStack.loadState(irFunction.typeParameters.first().symbol) as KTypeState
kType.irType.classOrNull!!.owner kType.irType.classOrNull!!.owner
} }
else -> irFunction.parent as IrClass else -> irFunction.parent as IrClass
@@ -118,7 +118,7 @@ internal object EnumValueOf : IntrinsicBase() {
private fun getEnumClass(irFunction: IrFunction, environment: IrInterpreterEnvironment): IrClass { private fun getEnumClass(irFunction: IrFunction, environment: IrInterpreterEnvironment): IrClass {
return when (irFunction.fqName) { return when (irFunction.fqName) {
"kotlin.enumValueOf" -> { "kotlin.enumValueOf" -> {
val kType = environment.callStack.getState(irFunction.typeParameters.first().symbol) as KTypeState val kType = environment.callStack.loadState(irFunction.typeParameters.first().symbol) as KTypeState
kType.irType.classOrNull!!.owner kType.irType.classOrNull!!.owner
} }
else -> irFunction.parent as IrClass else -> irFunction.parent as IrClass
@@ -127,7 +127,7 @@ internal object EnumValueOf : IntrinsicBase() {
private fun getEnumEntryByName(irFunction: IrFunction, environment: IrInterpreterEnvironment): IrEnumEntry? { private fun getEnumEntryByName(irFunction: IrFunction, environment: IrInterpreterEnvironment): IrEnumEntry? {
val enumClass = getEnumClass(irFunction, environment) val enumClass = getEnumClass(irFunction, environment)
val enumEntryName = environment.callStack.getState(irFunction.valueParameters.first().symbol).asString() val enumEntryName = environment.callStack.loadState(irFunction.valueParameters.first().symbol).asString()
val enumEntry = enumClass.declarations.filterIsInstance<IrEnumEntry>().singleOrNull { it.name.asString() == enumEntryName } val enumEntry = enumClass.declarations.filterIsInstance<IrEnumEntry>().singleOrNull { it.name.asString() == enumEntryName }
if (enumEntry == null) { if (enumEntry == null) {
IllegalArgumentException("No enum constant ${enumClass.fqName}.$enumEntryName").handleUserException(environment) IllegalArgumentException("No enum constant ${enumClass.fqName}.$enumEntryName").handleUserException(environment)
@@ -168,7 +168,7 @@ internal object EnumIntrinsics : IntrinsicBase() {
override fun evaluate(irFunction: IrFunction, environment: IrInterpreterEnvironment) { override fun evaluate(irFunction: IrFunction, environment: IrInterpreterEnvironment) {
val callStack = environment.callStack val callStack = environment.callStack
val enumEntry = callStack.getState(irFunction.dispatchReceiverParameter!!.symbol) val enumEntry = callStack.loadState(irFunction.dispatchReceiverParameter!!.symbol)
when (irFunction.name.asString()) { when (irFunction.name.asString()) {
"<get-name>", "<get-ordinal>" -> { "<get-name>", "<get-ordinal>" -> {
val symbol = (irFunction as IrSimpleFunction).correspondingPropertySymbol!! val symbol = (irFunction as IrSimpleFunction).correspondingPropertySymbol!!
@@ -176,13 +176,13 @@ internal object EnumIntrinsics : IntrinsicBase() {
} }
"compareTo" -> { "compareTo" -> {
val ordinalSymbol = enumEntry.irClass.getOriginalPropertyByName("ordinal").symbol val ordinalSymbol = enumEntry.irClass.getOriginalPropertyByName("ordinal").symbol
val other = callStack.getState(irFunction.valueParameters.single().symbol) val other = callStack.loadState(irFunction.valueParameters.single().symbol)
val compareTo = enumEntry.getField(ordinalSymbol)!!.asInt().compareTo(other.getField(ordinalSymbol)!!.asInt()) val compareTo = enumEntry.getField(ordinalSymbol)!!.asInt().compareTo(other.getField(ordinalSymbol)!!.asInt())
callStack.pushState(environment.convertToState(compareTo, irFunction.returnType)) callStack.pushState(environment.convertToState(compareTo, irFunction.returnType))
} }
// TODO "clone" -> throw exception // TODO "clone" -> throw exception
"equals" -> { "equals" -> {
val other = callStack.getState(irFunction.valueParameters.single().symbol) val other = callStack.loadState(irFunction.valueParameters.single().symbol)
callStack.pushState(environment.convertToState((enumEntry === other), irFunction.returnType)) callStack.pushState(environment.convertToState((enumEntry === other), irFunction.returnType))
} }
"hashCode" -> callStack.pushState(environment.convertToState(enumEntry.hashCode(), irFunction.returnType)) "hashCode" -> callStack.pushState(environment.convertToState(enumEntry.hashCode(), irFunction.returnType))
@@ -204,12 +204,12 @@ internal object JsPrimitives : IntrinsicBase() {
override fun evaluate(irFunction: IrFunction, environment: IrInterpreterEnvironment) { override fun evaluate(irFunction: IrFunction, environment: IrInterpreterEnvironment) {
when (irFunction.fqName) { when (irFunction.fqName) {
"kotlin.Long.<init>" -> { "kotlin.Long.<init>" -> {
val low = environment.callStack.getState(irFunction.valueParameters[0].symbol).asInt() val low = environment.callStack.loadState(irFunction.valueParameters[0].symbol).asInt()
val high = environment.callStack.getState(irFunction.valueParameters[1].symbol).asInt() val high = environment.callStack.loadState(irFunction.valueParameters[1].symbol).asInt()
environment.callStack.pushState(environment.convertToState((high.toLong().shl(32) + low), irFunction.returnType)) environment.callStack.pushState(environment.convertToState((high.toLong().shl(32) + low), irFunction.returnType))
} }
"kotlin.Char.<init>" -> { "kotlin.Char.<init>" -> {
val value = environment.callStack.getState(irFunction.valueParameters[0].symbol).asInt() val value = environment.callStack.loadState(irFunction.valueParameters[0].symbol).asInt()
environment.callStack.pushState(environment.convertToState(value.toChar(), irFunction.returnType)) environment.callStack.pushState(environment.convertToState(value.toChar(), irFunction.returnType))
} }
} }
@@ -231,14 +231,14 @@ internal object ArrayConstructor : IntrinsicBase() {
val instructions = mutableListOf<Instruction>(customEvaluateInstruction(irFunction, environment)) val instructions = mutableListOf<Instruction>(customEvaluateInstruction(irFunction, environment))
val sizeSymbol = irFunction.valueParameters[0].symbol val sizeSymbol = irFunction.valueParameters[0].symbol
val size = callStack.getState(sizeSymbol).asInt() val size = callStack.loadState(sizeSymbol).asInt()
val initSymbol = irFunction.valueParameters[1].symbol val initSymbol = irFunction.valueParameters[1].symbol
val state = callStack.getState(initSymbol).let { val state = callStack.loadState(initSymbol).let {
(it as? KFunctionState) ?: (it as KPropertyState).convertGetterToKFunctionState(environment) (it as? KFunctionState) ?: (it as KPropertyState).convertGetterToKFunctionState(environment)
} }
// if property was converted, then we must replace symbol in memory to get correct receiver later // if property was converted, then we must replace symbol in memory to get correct receiver later
callStack.setState(initSymbol, state) callStack.rewriteState(initSymbol, state)
for (i in size - 1 downTo 0) { for (i in size - 1 downTo 0) {
val call = (state.invokeSymbol.owner as IrSimpleFunction).createCall() val call = (state.invokeSymbol.owner as IrSimpleFunction).createCall()
@@ -252,7 +252,7 @@ internal object ArrayConstructor : IntrinsicBase() {
override fun evaluate(irFunction: IrFunction, environment: IrInterpreterEnvironment) { override fun evaluate(irFunction: IrFunction, environment: IrInterpreterEnvironment) {
val sizeDescriptor = irFunction.valueParameters[0].symbol val sizeDescriptor = irFunction.valueParameters[0].symbol
val size = environment.callStack.getState(sizeDescriptor).asInt() val size = environment.callStack.loadState(sizeDescriptor).asInt()
val arrayValue = MutableList<Any?>(size) { val arrayValue = MutableList<Any?>(size) {
when { when {
irFunction.returnType.isCharArray() -> 0.toChar() irFunction.returnType.isCharArray() -> 0.toChar()
@@ -274,7 +274,7 @@ internal object ArrayConstructor : IntrinsicBase() {
} }
} }
val type = (environment.callStack.getState(irFunction.symbol) as KTypeState).irType val type = (environment.callStack.loadState(irFunction.symbol) as KTypeState).irType
environment.callStack.pushState(arrayValue.toPrimitiveStateArray(type)) environment.callStack.pushState(arrayValue.toPrimitiveStateArray(type))
} }
} }
@@ -298,7 +298,7 @@ internal object AssertIntrinsic : IntrinsicBase() {
if (irFunction.valueParameters.size == 1) return listOf(customEvaluateInstruction(irFunction, environment)) if (irFunction.valueParameters.size == 1) return listOf(customEvaluateInstruction(irFunction, environment))
val lambdaParameter = irFunction.valueParameters.last() val lambdaParameter = irFunction.valueParameters.last()
val lambdaState = environment.callStack.getState(lambdaParameter.symbol) as KFunctionState val lambdaState = environment.callStack.loadState(lambdaParameter.symbol) as KFunctionState
val call = (lambdaState.invokeSymbol.owner as IrSimpleFunction).createCall() val call = (lambdaState.invokeSymbol.owner as IrSimpleFunction).createCall()
call.dispatchReceiver = lambdaParameter.createGetValue() call.dispatchReceiver = lambdaParameter.createGetValue()
@@ -306,7 +306,7 @@ internal object AssertIntrinsic : IntrinsicBase() {
} }
override fun evaluate(irFunction: IrFunction, environment: IrInterpreterEnvironment) { override fun evaluate(irFunction: IrFunction, environment: IrInterpreterEnvironment) {
val value = environment.callStack.getState(irFunction.valueParameters.first().symbol).asBoolean() val value = environment.callStack.loadState(irFunction.valueParameters.first().symbol).asBoolean()
if (value) return if (value) return
when (irFunction.valueParameters.size) { when (irFunction.valueParameters.size) {
1 -> AssertionError("Assertion failed").handleUserException(environment) 1 -> AssertionError("Assertion failed").handleUserException(environment)
@@ -337,7 +337,7 @@ internal object DataClassArrayToString : IntrinsicBase() {
} }
override fun evaluate(irFunction: IrFunction, environment: IrInterpreterEnvironment) { override fun evaluate(irFunction: IrFunction, environment: IrInterpreterEnvironment) {
val array = environment.callStack.getState(irFunction.valueParameters.single().symbol) as Primitive<*> val array = environment.callStack.loadState(irFunction.valueParameters.single().symbol) as Primitive<*>
environment.callStack.pushState(environment.convertToState(arrayToString(array.value), irFunction.returnType)) environment.callStack.pushState(environment.convertToState(arrayToString(array.value), irFunction.returnType))
} }
} }
@@ -25,7 +25,7 @@ internal class CommonProxy private constructor(override val state: Common, overr
private fun IrFunction.wasAlreadyCalled(): Boolean { private fun IrFunction.wasAlreadyCalled(): Boolean {
val anyParameter = this.getLastOverridden().dispatchReceiverParameter!!.symbol val anyParameter = this.getLastOverridden().dispatchReceiverParameter!!.symbol
val callStack = callInterceptor.environment.callStack val callStack = callInterceptor.environment.callStack
if (callStack.containsVariable(anyParameter) && callStack.getState(anyParameter) === state) return true if (callStack.containsStateInMemory(anyParameter) && callStack.loadState(anyParameter) === state) return true
return this == callInterceptor.environment.callStack.currentFrameOwner return this == callInterceptor.environment.callStack.currentFrameOwner
} }
@@ -60,7 +60,7 @@ internal class CallStack {
is IrTry -> { is IrTry -> {
dropSubFrame() dropSubFrame()
pushState(result) pushState(result)
addInstruction(SimpleInstruction(irReturn)) pushInstruction(SimpleInstruction(irReturn))
frameOwner.finallyExpression?.handleAndDropResult(this) frameOwner.finallyExpression?.handleAndDropResult(this)
return return
} }
@@ -68,7 +68,7 @@ internal class CallStack {
val tryBlock = currentFrame.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() dropSubFrame()
pushState(result) pushState(result)
addInstruction(SimpleInstruction(irReturn)) pushInstruction(SimpleInstruction(irReturn))
tryBlock.finallyExpression?.handleAndDropResult(this) tryBlock.finallyExpression?.handleAndDropResult(this)
return return
} }
@@ -81,7 +81,7 @@ internal class CallStack {
} }
currentFrame.dropInstructions() currentFrame.dropInstructions()
addInstruction(SimpleInstruction(returnTarget)) pushInstruction(SimpleInstruction(returnTarget))
if (returnTarget !is IrConstructor) pushState(result) if (returnTarget !is IrConstructor) pushState(result)
} }
@@ -91,17 +91,17 @@ internal class CallStack {
when (frameOwner) { when (frameOwner) {
is IrTry -> { is IrTry -> {
currentFrame.removeSubFrameWithoutDataPropagation() currentFrame.removeSubFrameWithoutDataPropagation()
addInstruction(CompoundInstruction(breakOrContinue)) pushInstruction(CompoundInstruction(breakOrContinue))
newSubFrame(frameOwner) // will be deleted when interpret 'try' newSubFrame(frameOwner) // will be deleted when interpret 'try'
addInstruction(SimpleInstruction(frameOwner)) pushInstruction(SimpleInstruction(frameOwner))
return return
} }
is IrCatch -> { is IrCatch -> {
val tryInstruction = currentFrame.dropInstructions()!! // last instruction in `catch` block is `try` val tryInstruction = currentFrame.dropInstructions()!! // last instruction in `catch` block is `try`
currentFrame.removeSubFrameWithoutDataPropagation() currentFrame.removeSubFrameWithoutDataPropagation()
addInstruction(CompoundInstruction(breakOrContinue)) pushInstruction(CompoundInstruction(breakOrContinue))
newSubFrame(tryInstruction.element!!) // will be deleted when interpret 'try' newSubFrame(tryInstruction.element!!) // will be deleted when interpret 'try'
addInstruction(tryInstruction) pushInstruction(tryInstruction)
return return
} }
else -> { else -> {
@@ -114,10 +114,10 @@ internal class CallStack {
when (breakOrContinue) { when (breakOrContinue) {
is IrBreak -> currentFrame.removeSubFrameWithoutDataPropagation() // drop loop is IrBreak -> currentFrame.removeSubFrameWithoutDataPropagation() // drop loop
else -> if (breakOrContinue.loop is IrDoWhileLoop) { else -> if (breakOrContinue.loop is IrDoWhileLoop) {
addInstruction(SimpleInstruction(breakOrContinue.loop)) pushInstruction(SimpleInstruction(breakOrContinue.loop))
addInstruction(CompoundInstruction(breakOrContinue.loop.condition)) pushInstruction(CompoundInstruction(breakOrContinue.loop.condition))
} else { } else {
addInstruction(CompoundInstruction(breakOrContinue.loop)) pushInstruction(CompoundInstruction(breakOrContinue.loop))
} }
} }
} }
@@ -133,14 +133,14 @@ internal class CallStack {
is IrTry -> { is IrTry -> {
dropSubFrame() // drop all instructions that left dropSubFrame() // drop all instructions that left
newSubFrame(frameOwner) newSubFrame(frameOwner)
addInstruction(SimpleInstruction(frameOwner)) // to evaluate finally at the end pushInstruction(SimpleInstruction(frameOwner)) // to evaluate finally at the end
frameOwner.catches.reversed().forEach { addInstruction(CompoundInstruction(it)) } frameOwner.catches.reversed().forEach { pushInstruction(CompoundInstruction(it)) }
pushState(exception) pushState(exception)
return return
} }
is IrCatch -> { is IrCatch -> {
// in case of exception in catch, drop everything except of last `try` instruction // in case of exception in catch, drop everything except of last `try` instruction
addInstruction(frame.dropInstructions()!!) pushInstruction(frame.dropInstructions()!!)
pushState(exception) pushState(exception)
return return
} }
@@ -155,54 +155,25 @@ internal class CallStack {
} }
fun hasNoInstructions() = frames.isEmpty() || (frames.size == 1 && frames.first().hasNoInstructions()) fun hasNoInstructions() = frames.isEmpty() || (frames.size == 1 && frames.first().hasNoInstructions())
fun pushInstruction(instruction: Instruction) = currentFrame.pushInstruction(instruction)
fun popInstruction(): Instruction = currentFrame.popInstruction()
fun addInstruction(instruction: Instruction) { fun pushState(state: State) = currentFrame.pushState(state)
currentFrame.addInstruction(instruction)
}
fun popInstruction(): Instruction {
return currentFrame.popInstruction()
}
fun pushState(state: State) {
currentFrame.pushState(state)
}
fun popState(): State = currentFrame.popState() fun popState(): State = currentFrame.popState()
fun peekState(): State? = currentFrame.peekState() fun peekState(): State? = currentFrame.peekState()
fun addVariable(symbol: IrSymbol, state: State?) { fun storeState(symbol: IrSymbol, state: State?) = currentFrame.storeState(symbol, state)
currentFrame.addVariable(symbol, state) private fun storeState(symbol: IrSymbol, variable: Variable) = currentFrame.storeState(symbol, variable)
} fun containsStateInMemory(symbol: IrSymbol): Boolean = currentFrame.containsStateInMemory(symbol)
fun loadState(symbol: IrSymbol): State = currentFrame.loadState(symbol)
fun rewriteState(symbol: IrSymbol, newState: State) = currentFrame.rewriteState(symbol, newState)
private fun addVariable(symbol: IrSymbol, variable: Variable) { // TODO save only necessary declarations
currentFrame.addVariable(symbol, variable) fun storeUpValues(state: StateWithClosure) = currentFrame.copyMemoryInto(state)
} fun loadUpValues(state: StateWithClosure) = state.upValues.forEach { (symbol, variable) -> storeState(symbol, variable) }
fun copyUpValuesFromPreviousFrame() = frames[frames.size - 2].copyMemoryInto(currentFrame)
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
currentFrame.copyMemoryInto(state)
}
fun loadUpValues(state: StateWithClosure) {
state.upValues.forEach { (symbol, variable) -> addVariable(symbol, variable) }
}
fun copyUpValuesFromPreviousFrame() {
frames[frames.size - 2].copyMemoryInto(currentFrame)
}
fun getStackTrace(): List<String> {
return frames.map { it.toString() }.filter { it != Frame.NOT_DEFINED }
}
fun getFileAndPositionInfo(): String {
return frames[frames.size - 2].getFileAndPositionInfo()
}
fun getStackTrace(): List<String> = frames.map { it.toString() }.filter { it != Frame.NOT_DEFINED }
fun getFileAndPositionInfo(): String = frames[frames.size - 2].getFileAndPositionInfo()
fun getStackCount(): Int = frames.size fun getStackCount(): Int = frames.size
} }
@@ -43,31 +43,16 @@ internal class Frame(subFrameOwner: IrElement, val irFile: IrFile? = null) {
fun hasNoSubFrames() = innerStack.isEmpty() fun hasNoSubFrames() = innerStack.isEmpty()
fun hasNoInstructions() = hasNoSubFrames() || (innerStack.size == 1 && innerStack.first().isEmpty()) fun hasNoInstructions() = hasNoSubFrames() || (innerStack.size == 1 && innerStack.first().isEmpty())
fun pushInstruction(instruction: Instruction) = currentFrame.pushInstruction(instruction)
fun addInstruction(instruction: Instruction) { fun popInstruction(): Instruction = currentFrame.popInstruction().apply { currentInstruction = this }
currentFrame.pushInstruction(instruction)
}
fun popInstruction(): Instruction {
return currentFrame.popInstruction().apply { currentInstruction = this }
}
fun dropInstructions() = currentFrame.dropInstructions() fun dropInstructions() = currentFrame.dropInstructions()
fun pushState(state: State) { fun pushState(state: State) = currentFrame.pushState(state)
currentFrame.pushState(state)
}
fun popState(): State = currentFrame.popState() fun popState(): State = currentFrame.popState()
fun peekState(): State? = currentFrame.peekState() fun peekState(): State? = currentFrame.peekState()
fun addVariable(symbol: IrSymbol, state: State?) { fun storeState(symbol: IrSymbol, state: State?) = currentFrame.storeState(symbol, state)
currentFrame.addVariable(symbol, state) fun storeState(symbol: IrSymbol, variable: Variable) = currentFrame.storeState(symbol, variable)
}
fun addVariable(symbol: IrSymbol, variable: Variable) {
currentFrame.addVariable(symbol, variable)
}
private inline fun forEachSubFrame(block: (SubFrame) -> Unit) { private inline fun forEachSubFrame(block: (SubFrame) -> Unit) {
// TODO speed up reverse iteration or do it forward // TODO speed up reverse iteration or do it forward
@@ -76,28 +61,22 @@ internal class Frame(subFrameOwner: IrElement, val irFile: IrFile? = null) {
} }
} }
fun getState(symbol: IrSymbol): State { fun loadState(symbol: IrSymbol): State {
forEachSubFrame { forEachSubFrame { it.loadState(symbol)?.let { state -> return state } }
it.getState(symbol)?.let { state -> return state }
}
throw InterpreterError("$symbol not found") // TODO better message throw InterpreterError("$symbol not found") // TODO better message
} }
fun setState(symbol: IrSymbol, newState: State) { fun rewriteState(symbol: IrSymbol, newState: State) {
forEachSubFrame { forEachSubFrame { if (it.containsStateInMemory(symbol)) return it.rewriteState(symbol, newState) }
if (it.containsVariable(symbol)) return it.setState(symbol, newState)
}
} }
fun containsVariable(symbol: IrSymbol): Boolean { fun containsStateInMemory(symbol: IrSymbol): Boolean {
forEachSubFrame { forEachSubFrame { if (it.containsStateInMemory(symbol)) return true }
if (it.containsVariable(symbol)) return true
}
return false return false
} }
fun copyMemoryInto(newFrame: Frame) { fun copyMemoryInto(newFrame: Frame) {
this.getAll().forEach { (symbol, variable) -> if (!newFrame.containsVariable(symbol)) newFrame.addVariable(symbol, variable) } this.getAll().forEach { (symbol, variable) -> if (!newFrame.containsStateInMemory(symbol)) newFrame.storeState(symbol, variable) }
} }
fun copyMemoryInto(closure: StateWithClosure) { fun copyMemoryInto(closure: StateWithClosure) {
@@ -149,17 +128,17 @@ private class SubFrame(val owner: IrElement) {
fun peekState(): State? = dataStack.peek() fun peekState(): State? = dataStack.peek()
// Methods to work with memory // Methods to work with memory
fun addVariable(symbol: IrSymbol, variable: Variable) { fun storeState(symbol: IrSymbol, variable: Variable) {
memory[symbol] = variable memory[symbol] = variable
} }
fun addVariable(symbol: IrSymbol, state: State?) { fun storeState(symbol: IrSymbol, state: State?) {
memory[symbol] = Variable(state) memory[symbol] = Variable(state)
} }
fun containsVariable(symbol: IrSymbol): Boolean = memory[symbol] != null fun containsStateInMemory(symbol: IrSymbol): Boolean = memory[symbol] != null
fun getState(symbol: IrSymbol): State? = memory[symbol]?.state fun loadState(symbol: IrSymbol): State? = memory[symbol]?.state
fun setState(symbol: IrSymbol, newState: State) { fun rewriteState(symbol: IrSymbol, newState: State) {
memory[symbol]?.state = newState memory[symbol]?.state = newState
} }
@@ -60,7 +60,7 @@ internal interface Complex : State {
.toList() .toList()
.takeFromEndWhile { receiver == null || it.first != receiver } // only state's below receiver must be loaded on stack .takeFromEndWhile { receiver == null || it.first != receiver } // only state's below receiver must be loaded on stack
.forEach { (symbol, state) -> .forEach { (symbol, state) ->
callStack.addVariable(symbol, state) callStack.storeState(symbol, state)
(state as? StateWithClosure)?.let { callStack.loadUpValues(it) } (state as? StateWithClosure)?.let { callStack.loadUpValues(it) }
} }
} }