Optimize some methods of CallStack and Frame
This commit is contained in:
committed by
TeamCityServer
parent
e0438d1123
commit
877832ef8c
+13
-6
@@ -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<IdSignature, IrBody> = interpreter.bodyMap
|
||||
|
||||
override fun interceptProxy(irFunction: IrFunction, valueArguments: List<Variable>, 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
|
||||
|
||||
+25
-18
@@ -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!!)) }
|
||||
|
||||
+48
-43
@@ -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))
|
||||
|
||||
@@ -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
|
||||
|
||||
+21
-20
@@ -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<Any?>().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<Any?>(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<IrEnumEntry>().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.<init>" -> {
|
||||
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.<init>" -> {
|
||||
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<Instruction>(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<Any?>(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<Instruction> {
|
||||
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)
|
||||
|
||||
+1
-1
@@ -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 {
|
||||
|
||||
+1
-1
@@ -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() -> {
|
||||
|
||||
+40
-37
@@ -19,22 +19,22 @@ import org.jetbrains.kotlin.ir.util.fileOrNull
|
||||
|
||||
internal class CallStack {
|
||||
private val frames = mutableListOf<Frame>()
|
||||
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<Instruction>, 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<Instruction>) {
|
||||
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<Instruction>) {
|
||||
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) {
|
||||
|
||||
@@ -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<Variable> = innerStack.flatMap { it.getAll() }
|
||||
|
||||
@@ -102,46 +105,44 @@ internal class Frame(subFrame: SubFrame, val irFile: IrFile? = null) {
|
||||
}
|
||||
}
|
||||
|
||||
internal class SubFrame(private val instructions: MutableList<Instruction>, val owner: IrElement) {
|
||||
private val memory = mutableListOf<Variable>()
|
||||
internal class SubFrame(val owner: IrElement) {
|
||||
private val instructions = mutableListOf<Instruction>()
|
||||
private val dataStack = DataStack()
|
||||
private val memory = mutableListOf<Variable>()
|
||||
|
||||
// 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<Variable> = memory
|
||||
}
|
||||
|
||||
private class DataStack {
|
||||
private val stack = mutableListOf<State>()
|
||||
|
||||
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()
|
||||
}
|
||||
+3
-3
@@ -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<String>()
|
||||
@@ -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<String> {
|
||||
|
||||
+1
-1
@@ -19,7 +19,7 @@ internal class Primitive<T>(val value: T, val type: IrType) : State {
|
||||
override val fields: MutableList<Variable> = 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
|
||||
|
||||
@@ -19,7 +19,7 @@ internal interface State {
|
||||
val fields: MutableList<Variable>
|
||||
val irClass: IrClass
|
||||
|
||||
fun getState(symbol: IrSymbol): State? {
|
||||
fun getField(symbol: IrSymbol): State? {
|
||||
return fields.firstOrNull { it.symbol == symbol }?.state
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user