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
|
package org.jetbrains.kotlin.ir.interpreter
|
||||||
|
|
||||||
import org.jetbrains.kotlin.ir.IrElement
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
|
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
|
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
|
||||||
import org.jetbrains.kotlin.ir.expressions.*
|
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
|
private val bodyMap: Map<IdSignature, IrBody> = interpreter.bodyMap
|
||||||
|
|
||||||
override fun interceptProxy(irFunction: IrFunction, valueArguments: List<Variable>, expectedResultClass: Class<*>): Any? {
|
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) {
|
return interpreter.withNewCallStack(irCall) {
|
||||||
this@withNewCallStack.environment.callStack.addInstruction(SimpleInstruction(irCall))
|
this@withNewCallStack.environment.callStack.addInstruction(SimpleInstruction(irCall))
|
||||||
valueArguments.forEach { this@withNewCallStack.environment.callStack.addVariable(it) }
|
valueArguments.forEach { this@withNewCallStack.environment.callStack.addVariable(it) }
|
||||||
@@ -81,22 +84,26 @@ internal class DefaultCallInterceptor(override val interpreter: IrInterpreter) :
|
|||||||
val invokedFunction = functionState.irFunction
|
val invokedFunction = functionState.irFunction
|
||||||
|
|
||||||
var index = 1 // drop first arg that is reference to function
|
var index = 1 // drop first arg that is reference to function
|
||||||
val dispatchReceiver = invokedFunction.dispatchReceiverParameter?.let { functionState.getState(it.symbol) ?: args[index++] }
|
val dispatchReceiver = invokedFunction.dispatchReceiverParameter?.let { functionState.getField(it.symbol) ?: args[index++] }
|
||||||
val extensionReceiver = invokedFunction.extensionReceiverParameter?.let { functionState.getState(it.symbol) ?: args[index++] }
|
val extensionReceiver = invokedFunction.extensionReceiverParameter?.let { functionState.getField(it.symbol) ?: args[index++] }
|
||||||
val valueArguments = invokedFunction.valueParameters.map { args[index++] }
|
val valueArguments = invokedFunction.valueParameters.map { args[index++] }
|
||||||
|
|
||||||
val function = when (val symbol = invokedFunction.symbol) {
|
val function = when (val symbol = invokedFunction.symbol) {
|
||||||
is IrSimpleFunctionSymbol -> {
|
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
|
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)))
|
callStack.addVariable(Variable(actualFunction.symbol, KTypeState(call.type, irBuiltIns.anyClass.owner)))
|
||||||
|
|
||||||
actualFunction
|
actualFunction
|
||||||
}
|
}
|
||||||
is IrConstructorSymbol -> {
|
is IrConstructorSymbol -> {
|
||||||
val irConstructorCall = IrConstructorCallImpl.fromSymbolOwner(invokedFunction.returnType, symbol)
|
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)))
|
callStack.addVariable(Variable(invokedFunction.parentAsClass.thisReceiver!!.symbol, Common(invokedFunction.parentAsClass)))
|
||||||
|
|
||||||
invokedFunction
|
invokedFunction
|
||||||
|
|||||||
+25
-18
@@ -104,7 +104,8 @@ private fun unfoldDelegatingConstructorCall(delegatingConstructorCall: IrFunctio
|
|||||||
private fun unfoldValueParameters(expression: IrFunctionAccessExpression, callStack: CallStack) {
|
private fun unfoldValueParameters(expression: IrFunctionAccessExpression, callStack: CallStack) {
|
||||||
val irFunction = expression.symbol.owner
|
val irFunction = expression.symbol.owner
|
||||||
// new sub frame is used to store value arguments, in case then they are used in default args evaluation
|
// 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 getDefaultForParameterAt(index: Int): IrExpression? {
|
||||||
fun IrValueParameter.getDefault(): IrExpressionBody? {
|
fun IrValueParameter.getDefault(): IrExpressionBody? {
|
||||||
@@ -169,7 +170,7 @@ private fun unfoldBody(body: IrBody, callStack: CallStack) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun unfoldBlock(block: IrBlock, callStack: CallStack) {
|
private fun unfoldBlock(block: IrBlock, callStack: CallStack) {
|
||||||
callStack.newSubFrame(block, listOf())
|
callStack.newSubFrame(block)
|
||||||
callStack.addInstruction(SimpleInstruction(block))
|
callStack.addInstruction(SimpleInstruction(block))
|
||||||
unfoldStatements(block.statements, callStack)
|
unfoldStatements(block.statements, callStack)
|
||||||
}
|
}
|
||||||
@@ -211,9 +212,10 @@ private fun unfoldGetValue(expression: IrGetValue, environment: IrInterpreterEnv
|
|||||||
// used to evaluate constants inside object
|
// used to evaluate constants inside object
|
||||||
if (expectedClass != null && expectedClass.isObject && expression.symbol.owner.origin == IrDeclarationOrigin.INSTANCE_RECEIVER) {
|
if (expectedClass != null && expectedClass.isObject && expression.symbol.owner.origin == IrDeclarationOrigin.INSTANCE_RECEIVER) {
|
||||||
// TODO is this correct behaviour?
|
// 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) {
|
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) {
|
private fun unfoldBranch(branch: IrBranch, callStack: CallStack) {
|
||||||
callStack.addInstruction(SimpleInstruction(branch)) //2
|
callStack.addInstruction(SimpleInstruction(branch))
|
||||||
callStack.addInstruction(CompoundInstruction(branch.condition)) //1
|
callStack.addInstruction(CompoundInstruction(branch.condition))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun unfoldWhileLoop(loop: IrWhileLoop, callStack: CallStack) {
|
private fun unfoldWhileLoop(loop: IrWhileLoop, callStack: CallStack) {
|
||||||
callStack.newSubFrame(loop, listOf())
|
callStack.newSubFrame(loop)
|
||||||
callStack.addInstruction(SimpleInstruction(loop))
|
callStack.addInstruction(SimpleInstruction(loop))
|
||||||
callStack.addInstruction(CompoundInstruction(loop.condition))
|
callStack.addInstruction(CompoundInstruction(loop.condition))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun unfoldDoWhileLoop(loop: IrDoWhileLoop, callStack: CallStack) {
|
private fun unfoldDoWhileLoop(loop: IrDoWhileLoop, callStack: CallStack) {
|
||||||
callStack.newSubFrame(loop, listOf())
|
callStack.newSubFrame(loop)
|
||||||
callStack.addInstruction(SimpleInstruction(loop))
|
callStack.addInstruction(SimpleInstruction(loop))
|
||||||
callStack.addInstruction(CompoundInstruction(loop.condition))
|
callStack.addInstruction(CompoundInstruction(loop.condition))
|
||||||
callStack.addInstruction(CompoundInstruction(loop.body))
|
callStack.addInstruction(CompoundInstruction(loop.body))
|
||||||
@@ -276,7 +278,9 @@ private fun unfoldDoWhileLoop(loop: IrDoWhileLoop, callStack: CallStack) {
|
|||||||
|
|
||||||
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, 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) {
|
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) {
|
private fun unfoldTry(element: IrTry, callStack: CallStack) {
|
||||||
callStack.newSubFrame(element, listOf())
|
callStack.newSubFrame(element)
|
||||||
callStack.addInstruction(SimpleInstruction(element))
|
callStack.addInstruction(SimpleInstruction(element))
|
||||||
callStack.addInstruction(CompoundInstruction(element.tryResult))
|
callStack.addInstruction(CompoundInstruction(element.tryResult))
|
||||||
}
|
}
|
||||||
@@ -302,9 +306,9 @@ private fun unfoldCatch(element: IrCatch, callStack: CallStack) {
|
|||||||
val exceptionState = callStack.peekState() as? ExceptionState ?: return
|
val exceptionState = callStack.peekState() as? ExceptionState ?: return
|
||||||
if (exceptionState.isSubtypeOf(element.catchParameter.type)) {
|
if (exceptionState.isSubtypeOf(element.catchParameter.type)) {
|
||||||
callStack.popState()
|
callStack.popState()
|
||||||
val frameOwner = callStack.getCurrentFrameOwner() as IrTry
|
val frameOwner = callStack.currentFrameOwner as IrTry
|
||||||
callStack.dropSubFrame() // drop other catch blocks
|
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.addVariable(Variable(element.catchParameter.symbol, exceptionState))
|
||||||
callStack.addInstruction(SimpleInstruction(frameOwner))
|
callStack.addInstruction(SimpleInstruction(frameOwner))
|
||||||
callStack.addInstruction(CompoundInstruction(element.result))
|
callStack.addInstruction(CompoundInstruction(element.result))
|
||||||
@@ -318,7 +322,7 @@ private fun unfoldThrow(expression: IrThrow, callStack: CallStack) {
|
|||||||
|
|
||||||
private fun unfoldStringConcatenation(expression: IrStringConcatenation, environment: IrInterpreterEnvironment) {
|
private fun unfoldStringConcatenation(expression: IrStringConcatenation, environment: IrInterpreterEnvironment) {
|
||||||
val callStack = environment.callStack
|
val callStack = environment.callStack
|
||||||
callStack.newSubFrame(expression, listOf())
|
callStack.newSubFrame(expression)
|
||||||
callStack.addInstruction(SimpleInstruction(expression))
|
callStack.addInstruction(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
|
||||||
@@ -339,10 +343,11 @@ private fun unfoldStringConcatenation(expression: IrStringConcatenation, environ
|
|||||||
}
|
}
|
||||||
val toStringFun = state.getToStringFunction()
|
val toStringFun = state.getToStringFunction()
|
||||||
val receiver = toStringFun.dispatchReceiverParameter!!
|
val receiver = toStringFun.dispatchReceiverParameter!!
|
||||||
val toStringCall = IrCallImpl.fromSymbolOwner(0, 0, environment.irBuiltIns.stringType, toStringFun.symbol)
|
val toStringCall =
|
||||||
toStringCall.dispatchReceiver = IrConstImpl.constNull(0, 0, receiver.type) // just stub receiver
|
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))
|
callStack.addVariable(Variable(receiver.symbol, state))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -365,7 +370,8 @@ private fun unfoldComposite(element: IrComposite, callStack: CallStack) {
|
|||||||
|
|
||||||
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.newSubFrame(reference, listOf(SimpleInstruction(reference)))
|
callStack.newSubFrame(reference)
|
||||||
|
callStack.addInstruction(SimpleInstruction(reference))
|
||||||
|
|
||||||
reference.dispatchReceiver?.let { callStack.addInstruction(SimpleInstruction(function.dispatchReceiverParameter!!)) }
|
reference.dispatchReceiver?.let { callStack.addInstruction(SimpleInstruction(function.dispatchReceiverParameter!!)) }
|
||||||
reference.extensionReceiver?.let { callStack.addInstruction(SimpleInstruction(function.extensionReceiverParameter!!)) }
|
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) {
|
private fun unfoldPropertyReference(propertyReference: IrPropertyReference, callStack: CallStack) {
|
||||||
val getter = propertyReference.getter!!.owner
|
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.dispatchReceiver?.let { callStack.addInstruction(SimpleInstruction(getter.dispatchReceiverParameter!!)) }
|
||||||
propertyReference.extensionReceiver?.let { callStack.addInstruction(SimpleInstruction(getter.extensionReceiverParameter!!)) }
|
propertyReference.extensionReceiver?.let { callStack.addInstruction(SimpleInstruction(getter.extensionReceiverParameter!!)) }
|
||||||
|
|||||||
+48
-43
@@ -62,18 +62,18 @@ class IrInterpreter private constructor(
|
|||||||
private fun Instruction.handle() {
|
private fun Instruction.handle() {
|
||||||
when (this) {
|
when (this) {
|
||||||
is CompoundInstruction -> unfoldInstruction(this.element, environment)
|
is CompoundInstruction -> unfoldInstruction(this.element, environment)
|
||||||
is SimpleInstruction -> interpret(this.element)
|
is SimpleInstruction -> interpret(this.element).also { incrementAndCheckCommands() }
|
||||||
is CustomInstruction -> this.evaluate()
|
is CustomInstruction -> this.evaluate()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun interpret(expression: IrExpression, file: IrFile? = null): IrExpression {
|
fun interpret(expression: IrExpression, file: IrFile? = null): IrExpression {
|
||||||
commandCount = 0
|
commandCount = 0
|
||||||
callStack.newFrame(expression, listOf(CompoundInstruction(expression)), file)
|
callStack.newFrame(expression, file)
|
||||||
|
callStack.addInstruction(CompoundInstruction(expression))
|
||||||
|
|
||||||
while (!callStack.hasNoInstructions()) {
|
while (!callStack.hasNoInstructions()) {
|
||||||
callStack.popInstruction().handle()
|
callStack.popInstruction().handle()
|
||||||
incrementAndCheckCommands()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return callStack.popState().toIrExpression(expression).apply { callStack.dropFrame() }
|
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 {
|
internal fun withNewCallStack(call: IrCall, init: IrInterpreter.() -> Any?): State {
|
||||||
return with(IrInterpreter(environment.copyWithNewCallStack(), bodyMap)) {
|
return with(IrInterpreter(environment.copyWithNewCallStack(), bodyMap)) {
|
||||||
callStack.newFrame(call.symbol.owner, listOf())
|
callStack.newFrame(call.symbol.owner)
|
||||||
callStack.newSubFrame(call, listOf())
|
callStack.newSubFrame(call)
|
||||||
init()
|
init()
|
||||||
|
|
||||||
while (!callStack.hasNoInstructions()) {
|
while (!callStack.hasNoInstructions()) {
|
||||||
@@ -115,7 +115,7 @@ class IrInterpreter private constructor(
|
|||||||
is IrEnumEntry -> interpretEnumEntry(element)
|
is IrEnumEntry -> interpretEnumEntry(element)
|
||||||
is IrConst<*> -> interpretConst(element)
|
is IrConst<*> -> interpretConst(element)
|
||||||
is IrVariable -> callStack.addVariable(Variable(element.symbol, callStack.popState()))
|
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 IrTypeOperatorCall -> interpretTypeOperatorCall(element)
|
||||||
is IrBranch -> interpretBranch(element)
|
is IrBranch -> interpretBranch(element)
|
||||||
is IrWhileLoop -> interpretWhile(element)
|
is IrWhileLoop -> interpretWhile(element)
|
||||||
@@ -169,9 +169,9 @@ class IrInterpreter private constructor(
|
|||||||
private fun interpretCall(call: IrCall) {
|
private fun interpretCall(call: IrCall) {
|
||||||
val owner = call.symbol.owner
|
val owner = call.symbol.owner
|
||||||
// 1. load evaluated arguments from stack
|
// 1. load evaluated arguments from stack
|
||||||
var dispatchReceiver = owner.getDispatchReceiver()?.let { callStack.getVariable(it) }?.state
|
var dispatchReceiver = owner.getDispatchReceiver()?.let { callStack.getState(it) }
|
||||||
val extensionReceiver = owner.getExtensionReceiver()?.let { callStack.getVariable(it) }?.state
|
val extensionReceiver = owner.getExtensionReceiver()?.let { callStack.getState(it) }
|
||||||
val valueArguments = owner.valueParameters.map { callStack.getVariable(it.symbol).state }
|
val valueArguments = owner.valueParameters.map { callStack.getState(it.symbol) }
|
||||||
|
|
||||||
// 2. get correct function for interpretation
|
// 2. get correct function for interpretation
|
||||||
val irFunction = dispatchReceiver?.getIrFunctionByIrCall(call) ?: call.symbol.owner
|
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.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
|
// TODO: if using KTypeState then it's class must be corresponding
|
||||||
// `call.type` is used in check cast and emptyArray
|
// `call.type` is used in check cast and emptyArray
|
||||||
callStack.addVariable(Variable(irFunction.symbol, KTypeState(call.type, irBuiltIns.anyClass.owner)))
|
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
|
property.backingField?.initializer?.expression ?: return@forEach
|
||||||
val receiver = irClass.thisReceiver!!.symbol
|
val receiver = irClass.thisReceiver!!.symbol
|
||||||
if (property.backingField?.initializer != null) {
|
if (property.backingField?.initializer != null) {
|
||||||
val receiverState = callStack.getVariable(receiver).state
|
val receiverState = callStack.getState(receiver)
|
||||||
val propertyVar = Variable(property.symbol, callStack.popState())
|
val propertyVar = Variable(property.symbol, callStack.popState())
|
||||||
receiverState.setField(propertyVar)
|
receiverState.setField(propertyVar)
|
||||||
}
|
}
|
||||||
@@ -232,7 +233,7 @@ class IrInterpreter private constructor(
|
|||||||
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.getVariable(receiver).state
|
val receiverState = callStack.getState(receiver)
|
||||||
receiverState.setField(Variable(field.correspondingPropertySymbol!!, callStack.popState()))
|
receiverState.setField(Variable(field.correspondingPropertySymbol!!, callStack.popState()))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -243,21 +244,22 @@ class IrInterpreter private constructor(
|
|||||||
|
|
||||||
private fun interpretConstructorCall(constructorCall: IrFunctionAccessExpression) {
|
private fun interpretConstructorCall(constructorCall: IrFunctionAccessExpression) {
|
||||||
val constructor = constructorCall.symbol.owner
|
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 irClass = constructor.parentAsClass
|
||||||
val objectVar = callStack.getVariable(constructorCall.getThisReceiver())
|
val objectState = callStack.getState(constructorCall.getThisReceiver())
|
||||||
if (irClass.isLocal) callStack.storeUpValues(objectVar.state as StateWithClosure)
|
if (irClass.isLocal) callStack.storeUpValues(objectState as StateWithClosure)
|
||||||
val outerClass = if (irClass.isInner) callStack.getVariable(constructor.dispatchReceiverParameter!!.symbol).state else null
|
val outerClass = if (irClass.isInner) callStack.getState(constructor.dispatchReceiverParameter!!.symbol) else null
|
||||||
|
|
||||||
callStack.dropSubFrame()
|
callStack.dropSubFrame()
|
||||||
callStack.newFrame(constructor, listOf(SimpleInstruction(constructor)))
|
callStack.newFrame(constructor)
|
||||||
callStack.addVariable(objectVar)
|
callStack.addInstruction(SimpleInstruction(constructor))
|
||||||
|
callStack.addVariable(Variable(constructorCall.getThisReceiver(), objectState))
|
||||||
constructor.valueParameters.forEachIndexed { i, param -> callStack.addVariable(Variable(param.symbol, valueArguments[i])) }
|
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) {
|
if (outerClass != null) {
|
||||||
val outerClassVar = Variable(irClass.parentAsClass.thisReceiver!!.symbol, outerClass)
|
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
|
// used in case when inner class has inner super class
|
||||||
callStack.addVariable(Variable(constructor.dispatchReceiverParameter!!.symbol, outerClass))
|
callStack.addVariable(Variable(constructor.dispatchReceiverParameter!!.symbol, outerClass))
|
||||||
// used to get information from outer class
|
// used to get information from outer class
|
||||||
@@ -271,10 +273,10 @@ class IrInterpreter private constructor(
|
|||||||
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(Variable(it, objectVar.state)) }
|
superReceiver?.let { callStack.addVariable(Variable(it, objectState)) }
|
||||||
|
|
||||||
callInterceptor.interceptConstructor(constructorCall, objectVar.state, valueArguments) {
|
callInterceptor.interceptConstructor(constructorCall, objectState, valueArguments) {
|
||||||
callStack.pushState(objectVar.state)
|
callStack.pushState(objectState)
|
||||||
callStack.addInstruction(CompoundInstruction(constructor))
|
callStack.addInstruction(CompoundInstruction(constructor))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -321,10 +323,10 @@ class IrInterpreter private constructor(
|
|||||||
val result = callStack.popState().asBoolean()
|
val result = callStack.popState().asBoolean()
|
||||||
callStack.dropSubFrame()
|
callStack.dropSubFrame()
|
||||||
if (result) {
|
if (result) {
|
||||||
callStack.newSubFrame(
|
callStack.newSubFrame(loop)
|
||||||
loop,
|
callStack.addInstruction(SimpleInstruction(loop))
|
||||||
listOf(CompoundInstruction(loop.body), CompoundInstruction(loop.condition), 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()
|
val result = callStack.popState().asBoolean()
|
||||||
callStack.dropSubFrame()
|
callStack.dropSubFrame()
|
||||||
if (result) {
|
if (result) {
|
||||||
callStack.newSubFrame(
|
callStack.newSubFrame(loop)
|
||||||
loop,
|
callStack.addInstruction(SimpleInstruction(loop))
|
||||||
listOf(CompoundInstruction(loop.body), CompoundInstruction(loop.condition), 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) {
|
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.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) {
|
private fun interpretGetField(expression: IrGetField) {
|
||||||
@@ -375,7 +377,7 @@ class IrInterpreter private constructor(
|
|||||||
callStack.addInstruction(CompoundInstruction(expression.symbol.owner.initializer?.expression))
|
callStack.addInstruction(CompoundInstruction(expression.symbol.owner.initializer?.expression))
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
val result = callStack.getVariable(receiver!!).state.getState(field.correspondingPropertySymbol!!)
|
val result = callStack.getState(receiver!!).getField(field.correspondingPropertySymbol!!)
|
||||||
callStack.pushState(result!!)
|
callStack.pushState(result!!)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -390,7 +392,8 @@ class IrInterpreter private constructor(
|
|||||||
|
|
||||||
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.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))
|
val enumClassObject = Variable(enumConstructorCall.getThisReceiver(), Common(enumEntry.correspondingClass ?: enumClass))
|
||||||
environment.mapOfEnums[enumEntry.symbol] = enumClassObject.state as Complex
|
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)
|
callStack.addVariable(enumClassObject)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -431,7 +436,7 @@ class IrInterpreter private constructor(
|
|||||||
val typeClassifier = expression.typeOperand.classifierOrFail
|
val typeClassifier = expression.typeOperand.classifierOrFail
|
||||||
val isReified = (typeClassifier.owner as? IrTypeParameter)?.isReified == true
|
val isReified = (typeClassifier.owner as? IrTypeParameter)?.isReified == true
|
||||||
val isErased = typeClassifier.owner is IrTypeParameter && !isReified
|
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) {
|
when (expression.operator) {
|
||||||
IrTypeOperator.IMPLICIT_COERCION_TO_UNIT -> {
|
IrTypeOperator.IMPLICIT_COERCION_TO_UNIT -> {
|
||||||
@@ -531,7 +536,7 @@ class IrInterpreter private constructor(
|
|||||||
|
|
||||||
private fun interpretThrow(expression: IrThrow) {
|
private fun interpretThrow(expression: IrThrow) {
|
||||||
val exception = callStack.popState()
|
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) {
|
when (exception) {
|
||||||
is Common -> callStack.pushState(ExceptionState(exception, callStack.getStackTrace()))
|
is Common -> callStack.pushState(ExceptionState(exception, callStack.getStackTrace()))
|
||||||
is Wrapper -> 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 function = KFunctionState(reference)
|
||||||
val irFunction = function.irFunction
|
val irFunction = function.irFunction
|
||||||
|
|
||||||
val dispatchReceiver = reference.dispatchReceiver?.let { callStack.getVariable(irFunction.getDispatchReceiver()!!) }?.state
|
val dispatchReceiver = reference.dispatchReceiver?.let { callStack.getState(irFunction.getDispatchReceiver()!!) }
|
||||||
val extensionReceiver = reference.extensionReceiver?.let { callStack.getVariable(irFunction.getExtensionReceiver()!!) }?.state
|
val extensionReceiver = reference.extensionReceiver?.let { callStack.getState(irFunction.getExtensionReceiver()!!) }
|
||||||
|
|
||||||
callStack.dropSubFrame()
|
callStack.dropSubFrame()
|
||||||
irFunction.getDispatchReceiver()?.let { dispatchReceiver?.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.add(Variable(it, receiver)) } }
|
irFunction.getExtensionReceiver()?.let { extensionReceiver?.let { receiver -> function.fields += Variable(it, receiver) } }
|
||||||
|
|
||||||
if (irFunction.isLocal) callStack.storeUpValues(function)
|
if (irFunction.isLocal) callStack.storeUpValues(function)
|
||||||
callStack.pushState(function)
|
callStack.pushState(function)
|
||||||
@@ -580,7 +585,7 @@ class IrInterpreter private constructor(
|
|||||||
val receiverSymbol = propertyReference.getter?.owner?.let { it.getDispatchReceiver() ?: it.getExtensionReceiver() }
|
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)
|
// it is impossible to get KProperty2 through ::, so only one receiver can be not null (or both null)
|
||||||
val receiver = (propertyReference.dispatchReceiver ?: propertyReference.extensionReceiver)
|
val receiver = (propertyReference.dispatchReceiver ?: propertyReference.extensionReceiver)
|
||||||
?.let { callStack.getVariable(receiverSymbol!!) }?.state
|
?.let { callStack.getState(receiverSymbol!!) }
|
||||||
|
|
||||||
callStack.dropSubFrame()
|
callStack.dropSubFrame()
|
||||||
val propertyState = KPropertyState(propertyReference, receiver)
|
val propertyState = KPropertyState(propertyReference, receiver)
|
||||||
@@ -590,7 +595,7 @@ class IrInterpreter private constructor(
|
|||||||
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.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))
|
callStack.pushState(KClassState(kTypeState.irType.classOrNull!!.owner, classReference.type.classOrNull!!.owner))
|
||||||
}
|
}
|
||||||
else -> callStack.pushState(KClassState(classReference))
|
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.IrConstImpl
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.IrErrorExpressionImpl
|
import org.jetbrains.kotlin.ir.expressions.impl.IrErrorExpressionImpl
|
||||||
import org.jetbrains.kotlin.ir.interpreter.builtins.evaluateIntrinsicAnnotation
|
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.state.*
|
||||||
import org.jetbrains.kotlin.ir.interpreter.proxy.Proxy
|
import org.jetbrains.kotlin.ir.interpreter.proxy.Proxy
|
||||||
import org.jetbrains.kotlin.ir.interpreter.proxy.wrap
|
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
|
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.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
|
if (expectedType.classifierOrFail is IrTypeParameterSymbol) return true
|
||||||
|
|
||||||
val actualState = environment.callStack.peekState() ?: return true
|
val actualState = environment.callStack.peekState() ?: return true
|
||||||
|
|||||||
+21
-20
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.ir.interpreter.intrinsics
|
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.IrClass
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrEnumEntry
|
import org.jetbrains.kotlin.ir.declarations.IrEnumEntry
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||||
@@ -48,7 +49,7 @@ internal object EmptyArray : IntrinsicBase() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun evaluate(irFunction: IrFunction, environment: IrInterpreterEnvironment) {
|
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))
|
environment.callStack.pushState(emptyArray<Any?>().toState(returnType.irType))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -65,7 +66,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.getVariable(elementsSymbol).state
|
val varargVariable = environment.callStack.getState(elementsSymbol)
|
||||||
environment.callStack.pushState(varargVariable)
|
environment.callStack.pushState(varargVariable)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -81,9 +82,9 @@ internal object ArrayOfNulls : IntrinsicBase() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun evaluate(irFunction: IrFunction, environment: IrInterpreterEnvironment) {
|
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 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 {
|
val returnType = (irFunction.returnType as IrSimpleType).buildSimpleType {
|
||||||
arguments = listOf(makeTypeProjection(typeArgument.irType, Variance.INVARIANT))
|
arguments = listOf(makeTypeProjection(typeArgument.irType, Variance.INVARIANT))
|
||||||
}
|
}
|
||||||
@@ -101,7 +102,7 @@ internal object EnumValues : IntrinsicBase() {
|
|||||||
private fun getEnumClass(irFunction: IrFunction, environment: IrInterpreterEnvironment): IrClass {
|
private fun getEnumClass(irFunction: IrFunction, environment: IrInterpreterEnvironment): IrClass {
|
||||||
return when (irFunction.fqNameWhenAvailable.toString()) {
|
return when (irFunction.fqNameWhenAvailable.toString()) {
|
||||||
"kotlin.enumValues" -> {
|
"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
|
kType.irType.classOrNull!!.owner
|
||||||
}
|
}
|
||||||
else -> irFunction.parent as IrClass
|
else -> irFunction.parent as IrClass
|
||||||
@@ -132,7 +133,7 @@ internal object EnumValueOf : IntrinsicBase() {
|
|||||||
private fun getEnumClass(irFunction: IrFunction, environment: IrInterpreterEnvironment): IrClass {
|
private fun getEnumClass(irFunction: IrFunction, environment: IrInterpreterEnvironment): IrClass {
|
||||||
return when (irFunction.fqNameWhenAvailable.toString()) {
|
return when (irFunction.fqNameWhenAvailable.toString()) {
|
||||||
"kotlin.enumValueOf" -> {
|
"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
|
kType.irType.classOrNull!!.owner
|
||||||
}
|
}
|
||||||
else -> irFunction.parent as IrClass
|
else -> irFunction.parent as IrClass
|
||||||
@@ -141,7 +142,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.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 }
|
val enumEntry = enumClass.declarations.filterIsInstance<IrEnumEntry>().singleOrNull { it.name.asString() == enumEntryName }
|
||||||
if (enumEntry == null) {
|
if (enumEntry == null) {
|
||||||
IllegalArgumentException("No enum constant ${enumClass.fqNameWhenAvailable}.$enumEntryName").handleUserException(environment)
|
IllegalArgumentException("No enum constant ${enumClass.fqNameWhenAvailable}.$enumEntryName").handleUserException(environment)
|
||||||
@@ -171,7 +172,7 @@ internal object EnumHashCode : IntrinsicBase() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun evaluate(irFunction: IrFunction, environment: IrInterpreterEnvironment) {
|
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))
|
environment.callStack.pushState(hashCode.toState(irFunction.returnType))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -189,12 +190,12 @@ internal object JsPrimitives : IntrinsicBase() {
|
|||||||
override fun evaluate(irFunction: IrFunction, environment: IrInterpreterEnvironment) {
|
override fun evaluate(irFunction: IrFunction, environment: IrInterpreterEnvironment) {
|
||||||
when (irFunction.fqNameWhenAvailable.toString()) {
|
when (irFunction.fqNameWhenAvailable.toString()) {
|
||||||
"kotlin.Long.<init>" -> {
|
"kotlin.Long.<init>" -> {
|
||||||
val low = environment.callStack.getVariable(irFunction.valueParameters[0].symbol).state.asInt()
|
val low = environment.callStack.getState(irFunction.valueParameters[0].symbol).asInt()
|
||||||
val high = environment.callStack.getVariable(irFunction.valueParameters[1].symbol).state.asInt()
|
val high = environment.callStack.getState(irFunction.valueParameters[1].symbol).asInt()
|
||||||
environment.callStack.pushState((high.toLong().shl(32) + low).toState(irFunction.returnType))
|
environment.callStack.pushState((high.toLong().shl(32) + low).toState(irFunction.returnType))
|
||||||
}
|
}
|
||||||
"kotlin.Char.<init>" -> {
|
"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))
|
environment.callStack.pushState(value.toChar().toState(irFunction.returnType))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -212,16 +213,16 @@ internal object ArrayConstructor : IntrinsicBase() {
|
|||||||
val instructions = mutableListOf<Instruction>(customEvaluateInstruction(irFunction, environment))
|
val instructions = mutableListOf<Instruction>(customEvaluateInstruction(irFunction, environment))
|
||||||
|
|
||||||
val sizeDescriptor = irFunction.valueParameters[0].symbol
|
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 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)
|
environment.callStack.loadUpValues(initLambda)
|
||||||
val function = initLambda.irFunction as IrSimpleFunction
|
val function = initLambda.irFunction as IrSimpleFunction
|
||||||
val index = initLambda.irFunction.valueParameters.single()
|
val index = initLambda.irFunction.valueParameters.single()
|
||||||
for (i in 0 until size) {
|
for (i in 0 until size) {
|
||||||
val call = IrCallImpl.fromSymbolOwner(0, 0, function.returnType, function.symbol)
|
val call = IrCallImpl.fromSymbolOwner(UNDEFINED_OFFSET, UNDEFINED_OFFSET, function.returnType, function.symbol)
|
||||||
call.putValueArgument(0, IrConstImpl.int(0, 0, index.type, i))
|
call.putValueArgument(0, IrConstImpl.int(UNDEFINED_OFFSET, UNDEFINED_OFFSET, index.type, i))
|
||||||
instructions += CompoundInstruction(call)
|
instructions += CompoundInstruction(call)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -230,7 +231,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.getVariable(sizeDescriptor).state.asInt()
|
val size = environment.callStack.getState(sizeDescriptor).asInt()
|
||||||
val arrayValue = MutableList<Any?>(size) { if (irFunction.returnType.isCharArray()) 0.toChar() else 0 }
|
val arrayValue = MutableList<Any?>(size) { if (irFunction.returnType.isCharArray()) 0.toChar() else 0 }
|
||||||
|
|
||||||
if (irFunction.valueParameters.size == 2) {
|
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))
|
environment.callStack.pushState(arrayValue.toPrimitiveStateArray(type.irType))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -275,15 +276,15 @@ internal object AssertIntrinsic : IntrinsicBase() {
|
|||||||
override fun unwind(irFunction: IrFunction, environment: IrInterpreterEnvironment): List<Instruction> {
|
override fun unwind(irFunction: IrFunction, environment: IrInterpreterEnvironment): List<Instruction> {
|
||||||
if (irFunction.valueParameters.size == 1) return listOf(customEvaluateInstruction(irFunction, environment))
|
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 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))
|
return listOf(customEvaluateInstruction(irFunction, environment), CompoundInstruction(call))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun evaluate(irFunction: IrFunction, environment: IrInterpreterEnvironment) {
|
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
|
if (value) return
|
||||||
when (irFunction.valueParameters.size) {
|
when (irFunction.valueParameters.size) {
|
||||||
1 -> AssertionError("Assertion failed").handleUserException(environment)
|
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 {
|
private fun IrFunction.wasAlreadyCalled(): Boolean {
|
||||||
val anyParameter = this.getLastOverridden().dispatchReceiverParameter!!.symbol
|
val anyParameter = this.getLastOverridden().dispatchReceiverParameter!!.symbol
|
||||||
if (callInterceptor.environment.callStack.containsVariable(anyParameter)) return true
|
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 {
|
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
|
val receiver = state.receiver // null receiver <=> property is on top level
|
||||||
?: return callInterceptor.interceptProxy(getter, emptyList())
|
?: return callInterceptor.interceptProxy(getter, emptyList())
|
||||||
|
|
||||||
val value = receiver.getState(actualPropertySymbol)
|
val value = receiver.getField(actualPropertySymbol)
|
||||||
return when {
|
return when {
|
||||||
// null value <=> property is extension or Primitive; receiver.isNull() <=> nullable extension
|
// null value <=> property is extension or Primitive; receiver.isNull() <=> nullable extension
|
||||||
value == null || receiver.isNull() -> {
|
value == null || receiver.isNull() -> {
|
||||||
|
|||||||
+40
-37
@@ -19,22 +19,22 @@ import org.jetbrains.kotlin.ir.util.fileOrNull
|
|||||||
|
|
||||||
internal class CallStack {
|
internal class CallStack {
|
||||||
private val frames = mutableListOf<Frame>()
|
private val frames = mutableListOf<Frame>()
|
||||||
private fun getCurrentFrame() = frames.last()
|
private val currentFrame get() = frames.last()
|
||||||
internal fun getCurrentFrameOwner() = frames.last().currentSubFrameOwner
|
internal val currentFrameOwner get() = currentFrame.currentSubFrameOwner
|
||||||
|
|
||||||
fun newFrame(frameOwner: IrElement, instructions: List<Instruction>, irFile: IrFile? = null) {
|
fun newFrame(frameOwner: IrElement, irFile: IrFile? = null) {
|
||||||
val newFrame = SubFrame(instructions.toMutableList(), frameOwner)
|
val newFrame = SubFrame(frameOwner)
|
||||||
frames.add(Frame(newFrame, irFile))
|
frames.add(Frame(newFrame, irFile))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun newFrame(frameOwner: IrFunction, instructions: List<Instruction>) {
|
fun newFrame(frameOwner: IrFunction) {
|
||||||
val newFrame = SubFrame(instructions.toMutableList(), frameOwner)
|
val newFrame = SubFrame(frameOwner)
|
||||||
frames.add(Frame(newFrame, frameOwner.fileOrNull))
|
frames.add(Frame(newFrame, frameOwner.fileOrNull))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun newSubFrame(frameOwner: IrElement, instructions: List<Instruction>) {
|
fun newSubFrame(frameOwner: IrElement) {
|
||||||
val newFrame = SubFrame(instructions.toMutableList(), frameOwner)
|
val newFrame = SubFrame(frameOwner)
|
||||||
getCurrentFrame().addSubFrame(newFrame)
|
currentFrame.addSubFrame(newFrame)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun dropFrame() {
|
fun dropFrame() {
|
||||||
@@ -49,12 +49,12 @@ internal class CallStack {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun dropSubFrame() {
|
fun dropSubFrame() {
|
||||||
getCurrentFrame().removeSubFrame()
|
currentFrame.removeSubFrame()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun returnFromFrameWithResult(irReturn: IrReturn) {
|
fun returnFromFrameWithResult(irReturn: IrReturn) {
|
||||||
val result = popState()
|
val result = popState()
|
||||||
var frameOwner = getCurrentFrameOwner()
|
var frameOwner = currentFrameOwner
|
||||||
while (frameOwner != irReturn.returnTargetSymbol.owner) {
|
while (frameOwner != irReturn.returnTargetSymbol.owner) {
|
||||||
when (frameOwner) {
|
when (frameOwner) {
|
||||||
is IrTry -> {
|
is IrTry -> {
|
||||||
@@ -65,7 +65,7 @@ internal class CallStack {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
is IrCatch -> {
|
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()
|
dropSubFrame()
|
||||||
pushState(result)
|
pushState(result)
|
||||||
addInstruction(SimpleInstruction(irReturn))
|
addInstruction(SimpleInstruction(irReturn))
|
||||||
@@ -74,44 +74,46 @@ internal class CallStack {
|
|||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
dropSubFrame()
|
dropSubFrame()
|
||||||
if (getCurrentFrame().hasNoSubFrames() && frameOwner != irReturn.returnTargetSymbol.owner) dropFrame()
|
if (currentFrame.hasNoSubFrames() && frameOwner != irReturn.returnTargetSymbol.owner) dropFrame()
|
||||||
frameOwner = getCurrentFrameOwner()
|
frameOwner = currentFrameOwner
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dropFrame()
|
dropFrame()
|
||||||
// check that last frame is not a function itself; use case for proxyInterpret
|
// 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)
|
pushState(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun unrollInstructionsForBreakContinue(breakOrContinue: IrBreakContinue) {
|
fun unrollInstructionsForBreakContinue(breakOrContinue: IrBreakContinue) {
|
||||||
var frameOwner = getCurrentFrameOwner()
|
var frameOwner = currentFrameOwner
|
||||||
while (frameOwner != breakOrContinue.loop) {
|
while (frameOwner != breakOrContinue.loop) {
|
||||||
when (frameOwner) {
|
when (frameOwner) {
|
||||||
is IrTry -> {
|
is IrTry -> {
|
||||||
getCurrentFrame().removeSubFrameWithoutDataPropagation()
|
currentFrame.removeSubFrameWithoutDataPropagation()
|
||||||
addInstruction(CompoundInstruction(breakOrContinue))
|
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
|
return
|
||||||
}
|
}
|
||||||
is IrCatch -> {
|
is IrCatch -> {
|
||||||
val tryInstruction = getCurrentFrame().dropInstructions()!! // last instruction in `catch` block is `try`
|
val tryInstruction = currentFrame.dropInstructions()!! // last instruction in `catch` block is `try`
|
||||||
getCurrentFrame().removeSubFrameWithoutDataPropagation()
|
currentFrame.removeSubFrameWithoutDataPropagation()
|
||||||
addInstruction(CompoundInstruction(breakOrContinue))
|
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
|
return
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
getCurrentFrame().removeSubFrameWithoutDataPropagation()
|
currentFrame.removeSubFrameWithoutDataPropagation()
|
||||||
frameOwner = getCurrentFrameOwner()
|
frameOwner = currentFrameOwner
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
when (breakOrContinue) {
|
when (breakOrContinue) {
|
||||||
is IrBreak -> getCurrentFrame().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))
|
addInstruction(SimpleInstruction(breakOrContinue.loop))
|
||||||
addInstruction(CompoundInstruction(breakOrContinue.loop.condition))
|
addInstruction(CompoundInstruction(breakOrContinue.loop.condition))
|
||||||
@@ -123,15 +125,15 @@ internal class CallStack {
|
|||||||
|
|
||||||
fun dropFramesUntilTryCatch() {
|
fun dropFramesUntilTryCatch() {
|
||||||
val exception = popState()
|
val exception = popState()
|
||||||
var frameOwner = getCurrentFrameOwner()
|
var frameOwner = currentFrameOwner
|
||||||
while (frames.isNotEmpty()) {
|
while (frames.isNotEmpty()) {
|
||||||
val frame = getCurrentFrame()
|
val frame = currentFrame
|
||||||
while (!frame.hasNoSubFrames()) {
|
while (!frame.hasNoSubFrames()) {
|
||||||
frameOwner = frame.currentSubFrameOwner
|
frameOwner = frame.currentSubFrameOwner
|
||||||
when (frameOwner) {
|
when (frameOwner) {
|
||||||
is IrTry -> {
|
is IrTry -> {
|
||||||
dropSubFrame() // drop all instructions that left
|
dropSubFrame() // drop all instructions that left
|
||||||
newSubFrame(frameOwner, listOf())
|
newSubFrame(frameOwner)
|
||||||
addInstruction(SimpleInstruction(frameOwner)) // to evaluate finally at the end
|
addInstruction(SimpleInstruction(frameOwner)) // to evaluate finally at the end
|
||||||
frameOwner.catches.reversed().forEach { addInstruction(CompoundInstruction(it)) }
|
frameOwner.catches.reversed().forEach { addInstruction(CompoundInstruction(it)) }
|
||||||
pushState(exception)
|
pushState(exception)
|
||||||
@@ -149,37 +151,38 @@ internal class CallStack {
|
|||||||
dropFrame()
|
dropFrame()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (frames.size == 0) newFrame(frameOwner, emptyList()) // just stub frame
|
if (frames.size == 0) newFrame(frameOwner) // just stub frame
|
||||||
pushState(exception)
|
pushState(exception)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun hasNoInstructions() = frames.isEmpty() || (frames.size == 1 && frames.first().hasNoInstructions())
|
fun hasNoInstructions() = frames.isEmpty() || (frames.size == 1 && frames.first().hasNoInstructions())
|
||||||
|
|
||||||
fun addInstruction(instruction: Instruction) {
|
fun addInstruction(instruction: Instruction) {
|
||||||
getCurrentFrame().addInstruction(instruction)
|
currentFrame.addInstruction(instruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun popInstruction(): Instruction {
|
fun popInstruction(): Instruction {
|
||||||
return getCurrentFrame().popInstruction()
|
return currentFrame.popInstruction()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun pushState(state: State) {
|
fun pushState(state: State) {
|
||||||
getCurrentFrame().pushState(state)
|
currentFrame.pushState(state)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun popState(): State = getCurrentFrame().popState()
|
fun popState(): State = currentFrame.popState()
|
||||||
fun peekState(): State? = getCurrentFrame().peekState()
|
fun peekState(): State? = currentFrame.peekState()
|
||||||
|
|
||||||
fun addVariable(variable: Variable) {
|
fun addVariable(variable: Variable) {
|
||||||
getCurrentFrame().addVariable(variable)
|
currentFrame.addVariable(variable)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getVariable(symbol: IrSymbol): Variable = getCurrentFrame().getVariable(symbol)
|
fun getState(symbol: IrSymbol): State = currentFrame.getState(symbol)
|
||||||
fun containsVariable(symbol: IrSymbol): Boolean = getCurrentFrame().containsVariable(symbol)
|
fun setState(symbol: IrSymbol, newState: State) = currentFrame.setState(symbol, newState)
|
||||||
|
fun containsVariable(symbol: IrSymbol): Boolean = currentFrame.containsVariable(symbol)
|
||||||
|
|
||||||
fun storeUpValues(state: StateWithClosure) {
|
fun storeUpValues(state: StateWithClosure) {
|
||||||
// TODO save only necessary declarations
|
// TODO save only necessary declarations
|
||||||
state.upValues.addAll(getCurrentFrame().getAll().toMutableList())
|
state.upValues.addAll(currentFrame.getAll().toMutableList())
|
||||||
}
|
}
|
||||||
|
|
||||||
fun loadUpValues(state: StateWithClosure) {
|
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.symbols.IrSymbol
|
||||||
import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable
|
import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable
|
||||||
import org.jetbrains.kotlin.util.capitalizeDecapitalize.capitalizeAsciiOnly
|
import org.jetbrains.kotlin.util.capitalizeDecapitalize.capitalizeAsciiOnly
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
|
|
||||||
|
|
||||||
internal class Frame(subFrame: SubFrame, val irFile: IrFile? = null) {
|
internal class Frame(subFrame: SubFrame, val irFile: IrFile? = null) {
|
||||||
private val innerStack = mutableListOf(subFrame)
|
private val innerStack = mutableListOf(subFrame)
|
||||||
private var currentInstruction: Instruction? = null
|
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 {
|
companion object {
|
||||||
const val NOT_DEFINED = "Not defined"
|
const val NOT_DEFINED = "Not defined"
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getCurrentFrame() = innerStack.last()
|
|
||||||
|
|
||||||
fun addSubFrame(frame: SubFrame) {
|
fun addSubFrame(frame: SubFrame) {
|
||||||
innerStack.add(frame)
|
innerStack.add(frame)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun removeSubFrame() {
|
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()
|
removeSubFrameWithoutDataPropagation()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,34 +43,39 @@ internal class Frame(subFrame: SubFrame, val irFile: IrFile? = null) {
|
|||||||
fun hasNoInstructions() = hasNoSubFrames() || (innerStack.size == 1 && innerStack.first().isEmpty())
|
fun hasNoInstructions() = hasNoSubFrames() || (innerStack.size == 1 && innerStack.first().isEmpty())
|
||||||
|
|
||||||
fun addInstruction(instruction: Instruction) {
|
fun addInstruction(instruction: Instruction) {
|
||||||
getCurrentFrame().pushInstruction(instruction)
|
currentFrame.pushInstruction(instruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun popInstruction(): 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) {
|
fun pushState(state: State) {
|
||||||
getCurrentFrame().pushState(state)
|
currentFrame.pushState(state)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun popState(): State = getCurrentFrame().popState()
|
fun popState(): State = currentFrame.popState()
|
||||||
fun peekState(): State? = getCurrentFrame().peekState()
|
fun peekState(): State? = currentFrame.peekState()
|
||||||
|
|
||||||
fun addVariable(variable: Variable) {
|
fun addVariable(variable: Variable) {
|
||||||
getCurrentFrame().addVariable(variable)
|
currentFrame.addVariable(variable)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getVariable(symbol: IrSymbol): Variable {
|
fun getState(symbol: IrSymbol): State {
|
||||||
return tryToGetVariable(symbol)
|
return (innerStack.lastIndex downTo 0).firstNotNullOfOrNull { innerStack[it].getState(symbol) }
|
||||||
?: throw InterpreterError("$symbol not found") // TODO better message
|
?: 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() }
|
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) {
|
internal class SubFrame(val owner: IrElement) {
|
||||||
private val memory = mutableListOf<Variable>()
|
private val instructions = mutableListOf<Instruction>()
|
||||||
private val dataStack = DataStack()
|
private val dataStack = DataStack()
|
||||||
|
private val memory = mutableListOf<Variable>()
|
||||||
|
|
||||||
|
// Methods to work with instruction
|
||||||
fun isEmpty() = instructions.isEmpty()
|
fun isEmpty() = instructions.isEmpty()
|
||||||
|
fun pushInstruction(instruction: Instruction) = instructions.add(0, instruction)
|
||||||
fun pushInstruction(instruction: Instruction) {
|
fun popInstruction(): Instruction = instructions.removeFirst()
|
||||||
instructions.add(0, instruction)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun popInstruction(): Instruction {
|
|
||||||
return instructions.removeFirst()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun dropInstructions() = instructions.lastOrNull()?.apply { instructions.clear() }
|
fun dropInstructions() = instructions.lastOrNull()?.apply { instructions.clear() }
|
||||||
|
|
||||||
fun pushState(state: State) {
|
// Methods to work with data
|
||||||
dataStack.push(state)
|
fun pushState(state: State) = dataStack.push(state)
|
||||||
}
|
|
||||||
|
|
||||||
fun popState(): State = dataStack.pop()
|
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) {
|
fun addVariable(variable: Variable) {
|
||||||
memory += 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
|
fun getAll(): List<Variable> = memory
|
||||||
}
|
}
|
||||||
|
|
||||||
private class DataStack {
|
private class DataStack {
|
||||||
private val stack = mutableListOf<State>()
|
private val stack = mutableListOf<State>()
|
||||||
|
|
||||||
fun isEmpty() = stack.isEmpty()
|
|
||||||
|
|
||||||
fun push(state: State) {
|
fun push(state: State) {
|
||||||
stack.add(state)
|
stack.add(state)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun pop(): State = stack.removeLast()
|
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 var outerClass: Variable? = null
|
||||||
|
|
||||||
override val message: String?
|
override val message: String?
|
||||||
get() = getState(messageProperty.symbol)?.asStringOrNull()
|
get() = getField(messageProperty.symbol)?.asStringOrNull()
|
||||||
override val cause: Throwable?
|
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 lateinit var exceptionFqName: String
|
||||||
private val exceptionHierarchy = mutableListOf<String>()
|
private val exceptionHierarchy = mutableListOf<String>()
|
||||||
@@ -115,7 +115,7 @@ internal class ExceptionState private constructor(
|
|||||||
val causeVar = exception.cause?.let {
|
val causeVar = exception.cause?.let {
|
||||||
Variable(causeProperty.symbol, ExceptionState(it, irClass, stackTrace + it.stackTrace.reversed().map { "at $it" }))
|
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> {
|
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 fields: MutableList<Variable> = mutableListOf()
|
||||||
override val irClass: IrClass = type.classOrNull!!.owner
|
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 {
|
override fun getIrFunctionByIrCall(expression: IrCall): IrFunction {
|
||||||
val owner = expression.symbol.owner
|
val owner = expression.symbol.owner
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ internal interface State {
|
|||||||
val fields: MutableList<Variable>
|
val fields: MutableList<Variable>
|
||||||
val irClass: IrClass
|
val irClass: IrClass
|
||||||
|
|
||||||
fun getState(symbol: IrSymbol): State? {
|
fun getField(symbol: IrSymbol): State? {
|
||||||
return fields.firstOrNull { it.symbol == symbol }?.state
|
return fields.firstOrNull { it.symbol == symbol }?.state
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user