Support Enum class as intrinsic in ir interpreter
Methods of Enum class don't have bodies, so must be treated as intrinsics
This commit is contained in:
committed by
TeamCityServer
parent
e5617ede7e
commit
0cc866a2fb
+7
-14
@@ -27,7 +27,6 @@ import org.jetbrains.kotlin.ir.interpreter.state.reflection.ReflectionState
|
||||
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.types.impl.originalKotlinType
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.ir.util.hasAnnotation
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
@@ -183,7 +182,7 @@ internal class DefaultCallInterceptor(override val interpreter: IrInterpreter) :
|
||||
}
|
||||
|
||||
private fun MethodHandle?.invokeMethod(irFunction: IrFunction, args: List<State>) {
|
||||
this ?: return handleIntrinsicMethods(irFunction)
|
||||
this ?: return assert(handleIntrinsicMethods(irFunction)) { "Unsupported intrinsic function: ${irFunction.render()}" }
|
||||
val argsForMethodInvocation = irFunction.getArgsForMethodInvocation(this@DefaultCallInterceptor, this.type(), args)
|
||||
withExceptionHandler(environment) {
|
||||
val result = this.invokeWithArguments(argsForMethodInvocation) // TODO if null return Unit
|
||||
@@ -191,8 +190,10 @@ internal class DefaultCallInterceptor(override val interpreter: IrInterpreter) :
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleIntrinsicMethods(irFunction: IrFunction) {
|
||||
IntrinsicEvaluator.unwindInstructions(irFunction, environment).forEach { callStack.addInstruction(it) }
|
||||
private fun handleIntrinsicMethods(irFunction: IrFunction): Boolean {
|
||||
val instructions = IntrinsicEvaluator.unwindInstructions(irFunction, environment) ?: return false
|
||||
instructions.forEach { callStack.addInstruction(it) }
|
||||
return true
|
||||
}
|
||||
|
||||
private fun calculateBuiltIns(irFunction: IrFunction, args: List<State>) {
|
||||
@@ -201,18 +202,10 @@ internal class DefaultCallInterceptor(override val interpreter: IrInterpreter) :
|
||||
else -> property.owner.name.asString()
|
||||
}
|
||||
|
||||
val receiverType = irFunction.dispatchReceiverParameter?.type
|
||||
val receiverType = irFunction.dispatchReceiverParameter?.type ?: irFunction.extensionReceiverParameter?.type
|
||||
val argsType = listOfNotNull(receiverType) + irFunction.valueParameters.map { it.type }
|
||||
val argsValues = args.wrap(this, irFunction)
|
||||
|
||||
fun IrType.getOnlyName(): String {
|
||||
return when {
|
||||
this.originalKotlinType != null -> this.originalKotlinType.toString()
|
||||
this is IrSimpleType -> (this.classifierOrFail.owner as IrDeclarationWithName).name.asString() + (if (this.hasQuestionMark) "?" else "")
|
||||
else -> this.render()
|
||||
}
|
||||
}
|
||||
|
||||
// TODO replace unary, binary, ternary functions with vararg
|
||||
withExceptionHandler(environment) {
|
||||
val result = when (argsType.size) {
|
||||
@@ -227,7 +220,7 @@ internal class DefaultCallInterceptor(override val interpreter: IrInterpreter) :
|
||||
methodName, argsType[0].getOnlyName(), argsType[1].getOnlyName(), argsType[2].getOnlyName(),
|
||||
argsValues[0], argsValues[1], argsValues[2]
|
||||
)
|
||||
else -> throw InterpreterError("Unsupported number of arguments for invocation as builtin functions")
|
||||
else -> throw InterpreterError("Unsupported number of arguments for invocation as builtin function: $methodName")
|
||||
}
|
||||
// TODO check "result is Unit"
|
||||
callStack.pushState(result.toState(result.getType(irFunction.returnType)))
|
||||
|
||||
+22
-16
@@ -10,7 +10,6 @@ import org.jetbrains.kotlin.ir.IrStatement
|
||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrGetObjectValueImpl
|
||||
import org.jetbrains.kotlin.ir.interpreter.exceptions.InterpreterError
|
||||
@@ -26,7 +25,7 @@ internal fun unfoldInstruction(element: IrElement?, environment: IrInterpreterEn
|
||||
when (element) {
|
||||
null -> return
|
||||
is IrSimpleFunction -> unfoldFunction(element, environment)
|
||||
is IrConstructor -> unfoldConstructor(element, callStack)
|
||||
is IrConstructor -> unfoldConstructor(element, environment)
|
||||
is IrCall -> unfoldCall(element, callStack)
|
||||
is IrConstructorCall -> unfoldConstructorCall(element, callStack)
|
||||
is IrEnumConstructorCall -> unfoldEnumConstructorCall(element, callStack)
|
||||
@@ -76,10 +75,23 @@ private fun unfoldFunction(function: IrSimpleFunction, environment: IrInterprete
|
||||
?: throw InterpreterError("Ir function must be with body")
|
||||
}
|
||||
|
||||
private fun unfoldConstructor(constructor: IrConstructor, callStack: CallStack) {
|
||||
// SimpleInstruction with function is added in constructor call
|
||||
// It will serve as endpoint for all possible constructor calls, there we drop frame and return object
|
||||
callStack.addInstruction(CompoundInstruction(constructor.body!!))
|
||||
private fun unfoldConstructor(constructor: IrConstructor, environment: IrInterpreterEnvironment) {
|
||||
val callStack = environment.callStack
|
||||
when (constructor.fqNameWhenAvailable?.asString()) {
|
||||
"kotlin.Enum.<init>" -> {
|
||||
val irClass = constructor.parentAsClass
|
||||
val receiver = irClass.thisReceiver!!.symbol
|
||||
val receiverState = callStack.getState(receiver)
|
||||
irClass.declarations.filterIsInstance<IrProperty>().forEachIndexed { index, property ->
|
||||
receiverState.setField(Variable(property.symbol, callStack.getState(constructor.valueParameters[index].symbol)))
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
// SimpleInstruction with function is added in constructor call
|
||||
// It will serve as endpoint for all possible constructor calls, there we drop frame and return object
|
||||
callStack.addInstruction(CompoundInstruction(constructor.body!!))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun unfoldCall(call: IrCall, callStack: CallStack) {
|
||||
@@ -341,14 +353,10 @@ private fun unfoldStringConcatenation(expression: IrStringConcatenation, environ
|
||||
}
|
||||
return callStack.pushState(result.toState(environment.irBuiltIns.stringType))
|
||||
}
|
||||
val toStringFun = state.getToStringFunction()
|
||||
val receiver = toStringFun.dispatchReceiverParameter!!
|
||||
val toStringCall =
|
||||
IrCallImpl.fromSymbolOwner(UNDEFINED_OFFSET, UNDEFINED_OFFSET, environment.irBuiltIns.stringType, toStringFun.symbol)
|
||||
|
||||
val toStringCall = state.createToStringIrCall()
|
||||
callStack.newSubFrame(toStringCall)
|
||||
callStack.addInstruction(SimpleInstruction(toStringCall))
|
||||
callStack.addVariable(Variable(receiver.symbol, state))
|
||||
callStack.addVariable(Variable(toStringCall.symbol.owner.dispatchReceiverParameter!!.symbol, state))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -360,10 +368,8 @@ private fun unfoldStringConcatenation(expression: IrStringConcatenation, environ
|
||||
|
||||
private fun unfoldComposite(element: IrComposite, callStack: CallStack) {
|
||||
when (element.origin) {
|
||||
IrStatementOrigin.DESTRUCTURING_DECLARATION -> element.statements.reversed()
|
||||
.forEach { callStack.addInstruction(CompoundInstruction(it)) }
|
||||
null -> element.statements.reversed()
|
||||
.forEach { callStack.addInstruction(CompoundInstruction(it)) } // is null for body of do while loop
|
||||
IrStatementOrigin.DESTRUCTURING_DECLARATION, IrStatementOrigin.DO_WHILE_LOOP ->
|
||||
element.statements.reversed().forEach { callStack.addInstruction(CompoundInstruction(it)) }
|
||||
else -> TODO("${element.origin} not implemented")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -211,9 +211,6 @@ internal fun IrClass.internalName(): String {
|
||||
internal inline fun withExceptionHandler(environment: IrInterpreterEnvironment, block: () -> Unit) {
|
||||
try {
|
||||
block()
|
||||
// check if during proxy interpretation was an exception
|
||||
val possibleException = environment.callStack.peekState() as? ExceptionState
|
||||
if (possibleException != null) environment.callStack.dropFramesUntilTryCatch()
|
||||
} catch (e: Throwable) {
|
||||
e.handleUserException(environment)
|
||||
}
|
||||
@@ -265,3 +262,8 @@ internal fun IrFunction.getArgsForMethodInvocation(
|
||||
|
||||
return argsValues
|
||||
}
|
||||
|
||||
internal fun IrType.getOnlyName(): String {
|
||||
if (this !is IrSimpleType) return this.render()
|
||||
return (this.classifierOrFail.owner as IrDeclarationWithName).name.asString() + (if (this.hasQuestionMark) "?" else "")
|
||||
}
|
||||
+14
-13
@@ -8,22 +8,23 @@ package org.jetbrains.kotlin.ir.interpreter.intrinsics
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
import org.jetbrains.kotlin.ir.interpreter.Instruction
|
||||
import org.jetbrains.kotlin.ir.interpreter.IrInterpreterEnvironment
|
||||
import org.jetbrains.kotlin.ir.interpreter.exceptions.InterpreterMethodNotFoundError
|
||||
import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable
|
||||
|
||||
internal object IntrinsicEvaluator {
|
||||
fun unwindInstructions(irFunction: IrFunction, environment: IrInterpreterEnvironment): List<Instruction> {
|
||||
fun unwindInstructions(irFunction: IrFunction, environment: IrInterpreterEnvironment): List<Instruction>? {
|
||||
val fqName = irFunction.fqNameWhenAvailable.toString()
|
||||
return when {
|
||||
EmptyArray.equalTo(irFunction) -> EmptyArray.unwind(irFunction, environment)
|
||||
ArrayOf.equalTo(irFunction) -> ArrayOf.unwind(irFunction, environment)
|
||||
ArrayOfNulls.equalTo(irFunction) -> ArrayOfNulls.unwind(irFunction, environment)
|
||||
EnumValues.equalTo(irFunction) -> EnumValues.unwind(irFunction, environment)
|
||||
EnumValueOf.equalTo(irFunction) -> EnumValueOf.unwind(irFunction, environment)
|
||||
EnumHashCode.equalTo(irFunction) -> EnumHashCode.unwind(irFunction, environment)
|
||||
JsPrimitives.equalTo(irFunction) -> JsPrimitives.unwind(irFunction, environment)
|
||||
ArrayConstructor.equalTo(irFunction) -> ArrayConstructor.unwind(irFunction, environment)
|
||||
SourceLocation.equalTo(irFunction) -> SourceLocation.unwind(irFunction, environment)
|
||||
AssertIntrinsic.equalTo(irFunction) -> AssertIntrinsic.unwind(irFunction, environment)
|
||||
else -> throw InterpreterMethodNotFoundError("Method ${irFunction.name} hasn't implemented")
|
||||
EmptyArray.canHandleFunctionWithName(fqName, irFunction.origin) -> EmptyArray.unwind(irFunction, environment)
|
||||
ArrayOf.canHandleFunctionWithName(fqName, irFunction.origin) -> ArrayOf.unwind(irFunction, environment)
|
||||
ArrayOfNulls.canHandleFunctionWithName(fqName, irFunction.origin) -> ArrayOfNulls.unwind(irFunction, environment)
|
||||
EnumValues.canHandleFunctionWithName(fqName, irFunction.origin) -> EnumValues.unwind(irFunction, environment)
|
||||
EnumValueOf.canHandleFunctionWithName(fqName, irFunction.origin) -> EnumValueOf.unwind(irFunction, environment)
|
||||
EnumIntrinsics.canHandleFunctionWithName(fqName, irFunction.origin) -> EnumIntrinsics.unwind(irFunction, environment)
|
||||
JsPrimitives.canHandleFunctionWithName(fqName, irFunction.origin) -> JsPrimitives.unwind(irFunction, environment)
|
||||
ArrayConstructor.canHandleFunctionWithName(fqName, irFunction.origin) -> ArrayConstructor.unwind(irFunction, environment)
|
||||
SourceLocation.canHandleFunctionWithName(fqName, irFunction.origin) -> SourceLocation.unwind(irFunction, environment)
|
||||
AssertIntrinsic.canHandleFunctionWithName(fqName, irFunction.origin) -> AssertIntrinsic.unwind(irFunction, environment)
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
}
|
||||
+61
-58
@@ -6,10 +6,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
|
||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
|
||||
import org.jetbrains.kotlin.ir.interpreter.*
|
||||
@@ -23,12 +20,15 @@ import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection
|
||||
import org.jetbrains.kotlin.ir.types.isArray
|
||||
import org.jetbrains.kotlin.ir.types.isCharArray
|
||||
import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable
|
||||
import org.jetbrains.kotlin.ir.util.resolveFakeOverride
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
|
||||
internal sealed class IntrinsicBase {
|
||||
abstract fun equalTo(irFunction: IrFunction): Boolean
|
||||
abstract fun canHandleFunctionWithName(fqName: String, origin: IrDeclarationOrigin): Boolean
|
||||
abstract fun evaluate(irFunction: IrFunction, environment: IrInterpreterEnvironment)
|
||||
abstract fun unwind(irFunction: IrFunction, environment: IrInterpreterEnvironment): List<Instruction>
|
||||
open fun unwind(irFunction: IrFunction, environment: IrInterpreterEnvironment): List<Instruction> {
|
||||
return listOf(customEvaluateInstruction(irFunction, environment))
|
||||
}
|
||||
|
||||
fun customEvaluateInstruction(irFunction: IrFunction, environment: IrInterpreterEnvironment): CustomInstruction {
|
||||
return CustomInstruction {
|
||||
@@ -39,15 +39,10 @@ internal sealed class IntrinsicBase {
|
||||
}
|
||||
|
||||
internal object EmptyArray : IntrinsicBase() {
|
||||
override fun equalTo(irFunction: IrFunction): Boolean {
|
||||
val fqName = irFunction.fqNameWhenAvailable.toString()
|
||||
override fun canHandleFunctionWithName(fqName: String, origin: IrDeclarationOrigin): Boolean {
|
||||
return fqName in setOf("kotlin.emptyArray", "kotlin.ArrayIntrinsicsKt.emptyArray")
|
||||
}
|
||||
|
||||
override fun unwind(irFunction: IrFunction, environment: IrInterpreterEnvironment): List<Instruction> {
|
||||
return listOf(customEvaluateInstruction(irFunction, environment))
|
||||
}
|
||||
|
||||
override fun evaluate(irFunction: IrFunction, environment: IrInterpreterEnvironment) {
|
||||
val returnType = environment.callStack.getState(irFunction.symbol) as KTypeState
|
||||
environment.callStack.pushState(emptyArray<Any?>().toState(returnType.irType))
|
||||
@@ -55,13 +50,8 @@ internal object EmptyArray : IntrinsicBase() {
|
||||
}
|
||||
|
||||
internal object ArrayOf : IntrinsicBase() {
|
||||
override fun equalTo(irFunction: IrFunction): Boolean {
|
||||
val fqName = irFunction.fqNameWhenAvailable.toString()
|
||||
return fqName == "kotlin.arrayOf"
|
||||
}
|
||||
|
||||
override fun unwind(irFunction: IrFunction, environment: IrInterpreterEnvironment): List<Instruction> {
|
||||
return listOf(customEvaluateInstruction(irFunction, environment))
|
||||
override fun canHandleFunctionWithName(fqName: String, origin: IrDeclarationOrigin): Boolean {
|
||||
return fqName == "kotlin.arrayOf" || fqName.matches("kotlin\\.(byte|char|short|int|long|float|double|boolean|)ArrayOf".toRegex())
|
||||
}
|
||||
|
||||
override fun evaluate(irFunction: IrFunction, environment: IrInterpreterEnvironment) {
|
||||
@@ -72,15 +62,10 @@ internal object ArrayOf : IntrinsicBase() {
|
||||
}
|
||||
|
||||
internal object ArrayOfNulls : IntrinsicBase() {
|
||||
override fun equalTo(irFunction: IrFunction): Boolean {
|
||||
val fqName = irFunction.fqNameWhenAvailable.toString()
|
||||
override fun canHandleFunctionWithName(fqName: String, origin: IrDeclarationOrigin): Boolean {
|
||||
return fqName == "kotlin.arrayOfNulls"
|
||||
}
|
||||
|
||||
override fun unwind(irFunction: IrFunction, environment: IrInterpreterEnvironment): List<Instruction> {
|
||||
return listOf(customEvaluateInstruction(irFunction, environment))
|
||||
}
|
||||
|
||||
override fun evaluate(irFunction: IrFunction, environment: IrInterpreterEnvironment) {
|
||||
val size = environment.callStack.getState(irFunction.valueParameters.first().symbol).asInt()
|
||||
val array = arrayOfNulls<Any?>(size)
|
||||
@@ -94,9 +79,8 @@ internal object ArrayOfNulls : IntrinsicBase() {
|
||||
}
|
||||
|
||||
internal object EnumValues : IntrinsicBase() {
|
||||
override fun equalTo(irFunction: IrFunction): Boolean {
|
||||
val fqName = irFunction.fqNameWhenAvailable.toString()
|
||||
return (fqName == "kotlin.enumValues" || fqName.endsWith(".values")) && irFunction.valueParameters.isEmpty()
|
||||
override fun canHandleFunctionWithName(fqName: String, origin: IrDeclarationOrigin): Boolean {
|
||||
return fqName == "kotlin.enumValues"
|
||||
}
|
||||
|
||||
private fun getEnumClass(irFunction: IrFunction, environment: IrInterpreterEnvironment): IrClass {
|
||||
@@ -113,7 +97,7 @@ internal object EnumValues : IntrinsicBase() {
|
||||
val enumClass = getEnumClass(irFunction, environment)
|
||||
val enumEntries = enumClass.declarations.filterIsInstance<IrEnumEntry>()
|
||||
|
||||
return listOf(customEvaluateInstruction(irFunction, environment)) + enumEntries.reversed().map { SimpleInstruction(it) }
|
||||
return super.unwind(irFunction, environment) + enumEntries.reversed().map { SimpleInstruction(it) }
|
||||
}
|
||||
|
||||
override fun evaluate(irFunction: IrFunction, environment: IrInterpreterEnvironment) {
|
||||
@@ -125,9 +109,8 @@ internal object EnumValues : IntrinsicBase() {
|
||||
}
|
||||
|
||||
internal object EnumValueOf : IntrinsicBase() {
|
||||
override fun equalTo(irFunction: IrFunction): Boolean {
|
||||
val fqName = irFunction.fqNameWhenAvailable.toString()
|
||||
return (fqName == "kotlin.enumValueOf" || fqName.endsWith(".valueOf")) && irFunction.valueParameters.size == 1
|
||||
override fun canHandleFunctionWithName(fqName: String, origin: IrDeclarationOrigin): Boolean {
|
||||
return fqName == "kotlin.enumValueOf"
|
||||
}
|
||||
|
||||
private fun getEnumClass(irFunction: IrFunction, environment: IrInterpreterEnvironment): IrClass {
|
||||
@@ -161,32 +144,59 @@ internal object EnumValueOf : IntrinsicBase() {
|
||||
}
|
||||
}
|
||||
|
||||
internal object EnumHashCode : IntrinsicBase() {
|
||||
override fun equalTo(irFunction: IrFunction): Boolean {
|
||||
val fqName = irFunction.fqNameWhenAvailable.toString()
|
||||
return fqName == "kotlin.Enum.hashCode"
|
||||
internal object EnumIntrinsics : IntrinsicBase() {
|
||||
override fun canHandleFunctionWithName(fqName: String, origin: IrDeclarationOrigin): Boolean {
|
||||
if (origin == IrDeclarationOrigin.ENUM_CLASS_SPECIAL_MEMBER) return true
|
||||
return fqName.startsWith("kotlin.Enum.")
|
||||
}
|
||||
|
||||
override fun unwind(irFunction: IrFunction, environment: IrInterpreterEnvironment): List<Instruction> {
|
||||
return listOf(customEvaluateInstruction(irFunction, environment))
|
||||
return when (irFunction.name.asString()) {
|
||||
"values" -> EnumValues.unwind(irFunction, environment)
|
||||
"valueOf" -> EnumValueOf.unwind(irFunction, environment)
|
||||
else -> super.unwind(irFunction, environment)
|
||||
}
|
||||
}
|
||||
|
||||
override fun evaluate(irFunction: IrFunction, environment: IrInterpreterEnvironment) {
|
||||
val hashCode = environment.callStack.getState(irFunction.dispatchReceiverParameter!!.symbol).hashCode()
|
||||
environment.callStack.pushState(hashCode.toState(irFunction.returnType))
|
||||
val callStack = environment.callStack
|
||||
val enumEntry = callStack.getState(irFunction.dispatchReceiverParameter!!.symbol)
|
||||
when (irFunction.name.asString()) {
|
||||
"<get-name>", "<get-ordinal>" -> {
|
||||
val symbol = (irFunction as IrSimpleFunction).correspondingPropertySymbol!!
|
||||
callStack.pushState(enumEntry.getField(symbol)!!)
|
||||
}
|
||||
"compareTo" -> {
|
||||
val ordinal = enumEntry.irClass.declarations.filterIsInstance<IrProperty>()
|
||||
.first { it.name.asString() == "ordinal" }
|
||||
.resolveFakeOverride()!!
|
||||
val other = callStack.getState(irFunction.valueParameters.single().symbol)
|
||||
val compareTo = enumEntry.getField(ordinal.symbol)!!.asInt().compareTo(other.getField(ordinal.symbol)!!.asInt())
|
||||
callStack.pushState(compareTo.toState(irFunction.returnType))
|
||||
}
|
||||
// TODO "clone" -> throw exception
|
||||
"equals" -> {
|
||||
val other = callStack.getState(irFunction.valueParameters.single().symbol)
|
||||
callStack.pushState((enumEntry === other).toState(irFunction.returnType))
|
||||
}
|
||||
"hashCode" -> callStack.pushState(enumEntry.hashCode().toState(irFunction.returnType))
|
||||
"toString" -> {
|
||||
val name = enumEntry.irClass.declarations.filterIsInstance<IrProperty>()
|
||||
.first { it.name.asString() == "name" }
|
||||
.resolveFakeOverride()!!
|
||||
callStack.pushState(enumEntry.getField(name.symbol)!!)
|
||||
}
|
||||
"values" -> EnumValues.evaluate(irFunction, environment)
|
||||
"valueOf" -> EnumValueOf.evaluate(irFunction, environment)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal object JsPrimitives : IntrinsicBase() {
|
||||
override fun equalTo(irFunction: IrFunction): Boolean {
|
||||
val fqName = irFunction.fqNameWhenAvailable.toString()
|
||||
override fun canHandleFunctionWithName(fqName: String, origin: IrDeclarationOrigin): Boolean {
|
||||
return fqName == "kotlin.Long.<init>" || fqName == "kotlin.Char.<init>"
|
||||
}
|
||||
|
||||
override fun unwind(irFunction: IrFunction, environment: IrInterpreterEnvironment): List<Instruction> {
|
||||
return listOf(customEvaluateInstruction(irFunction, environment))
|
||||
}
|
||||
|
||||
override fun evaluate(irFunction: IrFunction, environment: IrInterpreterEnvironment) {
|
||||
when (irFunction.fqNameWhenAvailable.toString()) {
|
||||
"kotlin.Long.<init>" -> {
|
||||
@@ -203,8 +213,7 @@ internal object JsPrimitives : IntrinsicBase() {
|
||||
}
|
||||
|
||||
internal object ArrayConstructor : IntrinsicBase() {
|
||||
override fun equalTo(irFunction: IrFunction): Boolean {
|
||||
val fqName = irFunction.fqNameWhenAvailable.toString()
|
||||
override fun canHandleFunctionWithName(fqName: String, origin: IrDeclarationOrigin): Boolean {
|
||||
return fqName.matches("kotlin\\.(Byte|Char|Short|Int|Long|Float|Double|Boolean|)Array\\.<init>".toRegex())
|
||||
}
|
||||
|
||||
@@ -220,7 +229,7 @@ internal object ArrayConstructor : IntrinsicBase() {
|
||||
environment.callStack.loadUpValues(initLambda)
|
||||
val function = initLambda.irFunction as IrSimpleFunction
|
||||
val index = initLambda.irFunction.valueParameters.single()
|
||||
for (i in 0 until size) {
|
||||
for (i in size - 1 downTo 0) {
|
||||
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)
|
||||
@@ -235,9 +244,9 @@ internal object ArrayConstructor : IntrinsicBase() {
|
||||
val arrayValue = MutableList<Any?>(size) { if (irFunction.returnType.isCharArray()) 0.toChar() else 0 }
|
||||
|
||||
if (irFunction.valueParameters.size == 2) {
|
||||
for (i in 0 until size) {
|
||||
for (i in size - 1 downTo 0) {
|
||||
arrayValue[i] = environment.callStack.popState().let {
|
||||
// TODO wrap
|
||||
// TODO may be use wrap
|
||||
when (it) {
|
||||
is Wrapper -> it.value
|
||||
is Primitive<*> -> if (it.type.isArray() || it.type.isPrimitiveArray()) it else it.value
|
||||
@@ -253,23 +262,17 @@ internal object ArrayConstructor : IntrinsicBase() {
|
||||
}
|
||||
|
||||
internal object SourceLocation : IntrinsicBase() {
|
||||
override fun equalTo(irFunction: IrFunction): Boolean {
|
||||
val fqName = irFunction.fqNameWhenAvailable.toString()
|
||||
override fun canHandleFunctionWithName(fqName: String, origin: IrDeclarationOrigin): Boolean {
|
||||
return fqName == "kotlin.experimental.sourceLocation" || fqName == "kotlin.experimental.SourceLocationKt.sourceLocation"
|
||||
}
|
||||
|
||||
override fun unwind(irFunction: IrFunction, environment: IrInterpreterEnvironment): List<Instruction> {
|
||||
return listOf(customEvaluateInstruction(irFunction, environment))
|
||||
}
|
||||
|
||||
override fun evaluate(irFunction: IrFunction, environment: IrInterpreterEnvironment) {
|
||||
environment.callStack.pushState(environment.callStack.getFileAndPositionInfo().toState(irFunction.returnType))
|
||||
}
|
||||
}
|
||||
|
||||
internal object AssertIntrinsic : IntrinsicBase() {
|
||||
override fun equalTo(irFunction: IrFunction): Boolean {
|
||||
val fqName = irFunction.fqNameWhenAvailable.toString()
|
||||
override fun canHandleFunctionWithName(fqName: String, origin: IrDeclarationOrigin): Boolean {
|
||||
return fqName == "kotlin.PreconditionsKt.assert"
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -25,7 +25,8 @@ 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
|
||||
val callStack = callInterceptor.environment.callStack
|
||||
if (callStack.containsVariable(anyParameter) && callStack.getState(anyParameter) === state) return true
|
||||
return this == callInterceptor.environment.callStack.currentFrameOwner
|
||||
}
|
||||
|
||||
|
||||
@@ -5,12 +5,18 @@
|
||||
|
||||
package org.jetbrains.kotlin.ir.interpreter.state
|
||||
|
||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
import org.jetbrains.kotlin.ir.declarations.IrProperty
|
||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||
import org.jetbrains.kotlin.ir.expressions.IrCall
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
|
||||
import org.jetbrains.kotlin.ir.interpreter.stack.Variable
|
||||
import org.jetbrains.kotlin.ir.types.isNullableAny
|
||||
import org.jetbrains.kotlin.ir.util.fqNameForIrSerialization
|
||||
import org.jetbrains.kotlin.ir.util.nameForIrSerialization
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
internal class Common private constructor(override val irClass: IrClass, override val fields: MutableList<Variable>) : Complex, StateWithClosure {
|
||||
override val upValues: MutableList<Variable> = mutableListOf()
|
||||
@@ -19,11 +25,6 @@ internal class Common private constructor(override val irClass: IrClass, overrid
|
||||
|
||||
constructor(irClass: IrClass) : this(irClass, mutableListOf())
|
||||
|
||||
fun copyFieldsFrom(state: Complex) {
|
||||
this.fields.addAll(state.fields)
|
||||
superWrapperClass = state.superWrapperClass ?: state as? Wrapper
|
||||
}
|
||||
|
||||
// This method is used to get correct java method name
|
||||
private fun getKotlinName(declaringClassName: String, methodName: String): String {
|
||||
return when {
|
||||
@@ -44,6 +45,33 @@ internal class Common private constructor(override val irClass: IrClass, overrid
|
||||
}
|
||||
}
|
||||
|
||||
fun getEqualsFunction(): IrSimpleFunction {
|
||||
val equalsFun = irClass.declarations
|
||||
.filterIsInstance<IrSimpleFunction>()
|
||||
.single {
|
||||
it.name == Name.identifier("equals") && it.dispatchReceiverParameter != null
|
||||
&& it.valueParameters.size == 1 && it.valueParameters[0].type.isNullableAny()
|
||||
}
|
||||
return getOverridden(equalsFun)
|
||||
}
|
||||
|
||||
fun getHashCodeFunction(): IrSimpleFunction {
|
||||
return irClass.declarations.filterIsInstance<IrSimpleFunction>()
|
||||
.single { it.name.asString() == "hashCode" && it.valueParameters.isEmpty() }
|
||||
.let { getOverridden(it) }
|
||||
}
|
||||
|
||||
fun getToStringFunction(): IrSimpleFunction {
|
||||
return irClass.declarations.filterIsInstance<IrSimpleFunction>()
|
||||
.single { it.name.asString() == "toString" && it.valueParameters.isEmpty() }
|
||||
.let { getOverridden(it) }
|
||||
}
|
||||
|
||||
fun createToStringIrCall(): IrCall {
|
||||
val toStringFun = getToStringFunction()
|
||||
return IrCallImpl.fromSymbolOwner(UNDEFINED_OFFSET, UNDEFINED_OFFSET, toStringFun.returnType, toStringFun.symbol)
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "Common(obj='${irClass.fqNameForIrSerialization}', values=$fields)"
|
||||
}
|
||||
|
||||
+1
-25
@@ -48,7 +48,7 @@ internal interface Complex: State {
|
||||
}
|
||||
}
|
||||
|
||||
private fun getOverridden(owner: IrSimpleFunction): IrSimpleFunction {
|
||||
fun getOverridden(owner: IrSimpleFunction): IrSimpleFunction {
|
||||
if (owner.parent == superWrapperClass?.irClass) return owner
|
||||
if (!owner.isFakeOverride || owner.body != null || owner.parentAsClass.defaultType.isAny()) return owner
|
||||
|
||||
@@ -61,28 +61,4 @@ internal interface Complex: State {
|
||||
val irFunction = receiver.getIrFunction(expression.symbol) ?: return null
|
||||
return getOverridden(irFunction as IrSimpleFunction)
|
||||
}
|
||||
|
||||
fun getEqualsFunction(): IrSimpleFunction {
|
||||
val equalsFun = irClass.declarations
|
||||
.filterIsInstance<IrSimpleFunction>()
|
||||
.single {
|
||||
it.name == Name.identifier("equals") && it.dispatchReceiverParameter != null
|
||||
&& it.valueParameters.size == 1 && it.valueParameters[0].type.isNullableAny()
|
||||
}
|
||||
return getOverridden(equalsFun)
|
||||
}
|
||||
|
||||
fun getHashCodeFunction(): IrSimpleFunction {
|
||||
return irClass.declarations.filterIsInstance<IrSimpleFunction>()
|
||||
.filter { it.name.asString() == "hashCode" }
|
||||
.first { it.valueParameters.isEmpty() }
|
||||
.let { getOverridden(it) }
|
||||
}
|
||||
|
||||
fun getToStringFunction(): IrSimpleFunction {
|
||||
return irClass.declarations.filterIsInstance<IrSimpleFunction>()
|
||||
.filter { it.name.asString() == "toString" }
|
||||
.first { it.valueParameters.isEmpty() }
|
||||
.let { getOverridden(it) }
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user