diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/IrInterpreter.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/IrInterpreter.kt index b908ec253d0..b2a55843f4c 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/IrInterpreter.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/IrInterpreter.kt @@ -5,9 +5,7 @@ package org.jetbrains.kotlin.backend.common.interpreter -import kotlinx.coroutines.runBlocking -import kotlinx.coroutines.withContext -import kotlinx.coroutines.yield +import kotlinx.coroutines.* import org.jetbrains.kotlin.backend.common.interpreter.builtins.* import org.jetbrains.kotlin.backend.common.interpreter.stack.* import org.jetbrains.kotlin.builtins.DefaultBuiltIns @@ -245,6 +243,20 @@ class IrInterpreter(irModule: IrModuleFragment) { enumEntry.interpret(data).also { if (it != Code.NEXT) return it } } } + "replace" -> { + val states = data.getAll().map { it.state } + val regex = states.filterIsInstance().single().value as Regex + val input = states.filterIsInstance>().single().value.toString() + val transform = states.filterIsInstance().single().irFunction + val matchResultParameter = transform.valueParameters.single() + val result = regex.replace(input) { + val itAsState = Variable(matchResultParameter.descriptor, Wrapper(it, matchResultParameter.type.classOrNull!!.owner)) + val newFrame = InterpreterFrame(mutableListOf(itAsState)) + runBlocking { transform.interpret(newFrame) } + (newFrame.popReturnValue() as Primitive<*>).value.toString() + } + data.pushReturnValue(result.toState(irBuiltIns.stringType)) + } else -> throw AssertionError("Unsupported intrinsic ${irFunction.name}") } @@ -353,8 +365,9 @@ class IrInterpreter(irModule: IrModuleFragment) { } private suspend fun interpretValueParameters(parametersContainer: IrMemberAccessExpression, data: Frame): Code { + val defaultValues = (parametersContainer.symbol.owner as IrFunction).valueParameters.map { it.defaultValue } for (i in (parametersContainer.valueArgumentsCount - 1) downTo 0) { - val code = parametersContainer.getValueArgument(i)?.interpret(data) ?: Code.NEXT + val code = parametersContainer.getValueArgument(i)?.interpret(data) ?: defaultValues[i]!!.expression.interpret(data) if (code != Code.NEXT) return code } return Code.NEXT @@ -395,8 +408,9 @@ class IrInterpreter(irModule: IrModuleFragment) { } val isWrapper = dispatchReceiver is Wrapper && rawExtensionReceiver == null + val isInterfaceDefaultMethod = irFunction.body != null && (irFunction.parent as? IrClass)?.isInterface == true val code = when { - isWrapper -> (dispatchReceiver as Wrapper).getMethod(irFunction).invokeMethod(irFunction, newFrame) + isWrapper && !isInterfaceDefaultMethod -> (dispatchReceiver as Wrapper).getMethod(irFunction).invokeMethod(irFunction, newFrame) irFunction.hasAnnotation(evaluateIntrinsicAnnotation) -> Wrapper.getStaticMethod(irFunction).invokeMethod(irFunction, newFrame) irFunction.isAbstract() -> calculateAbstract(irFunction, newFrame) //abstract check must be before fake overridden check irFunction.isFakeOverridden() -> calculateOverridden(irFunction as IrFunctionImpl, newFrame) @@ -615,7 +629,12 @@ class IrInterpreter(irModule: IrModuleFragment) { } private suspend fun interpretGetObjectValue(expression: IrGetObjectValue, data: Frame): Code { - val objectState = Common(expression.symbol.owner, mutableListOf()).apply { this.instance = this } + val owner = expression.symbol.owner + if (owner.hasAnnotation(evaluateIntrinsicAnnotation)) { + data.pushReturnValue(Wrapper.getCompanionObject(owner)) + return Code.NEXT + } + val objectState = Common(owner, mutableListOf()).apply { this.instance = this } data.pushReturnValue(objectState) return Code.NEXT } diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/stack/State.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/stack/State.kt index 7a12dd8f3a2..73adf2cc2d5 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/stack/State.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/stack/State.kt @@ -153,16 +153,21 @@ class Wrapper(val value: Any, override val irClass: IrClass) : Complex(irClass, private val typeFqName = irClass.fqNameForIrSerialization.toUnsafe() private val receiverClass = irClass.defaultType.getClass(true) + init { + instance = this + } + fun getMethod(irFunction: IrFunction): MethodHandle? { - // if function is actually a getter, then use property name as method name - val property = (irFunction as? IrFunctionImpl)?.correspondingPropertySymbol?.owner + // if function is actually a getter, then use "get${property.name.capitalize()}" as method name + val propertyName = (irFunction as? IrFunctionImpl)?.correspondingPropertySymbol?.owner?.name?.asString() + val propertyExplicitCall = propertyName?.takeIf { receiverClass.methods.map { it.name }.contains(it) } + val propertyGetCall = "get${propertyName?.capitalize()}".takeIf { receiverClass.methods.map { it.name }.contains(it) } // intrinsicName is used to get correct java method // for example: - method 'get' in kotlin StringBuilder is actually 'charAt' in java StringBuilder - // - use getter for private fields such as detailMessage in java.lang.Throwable - val intrinsicName = property?.getEvaluateIntrinsicValue() ?: irFunction.getEvaluateIntrinsicValue() + val intrinsicName = irFunction.getEvaluateIntrinsicValue() if (intrinsicName?.isEmpty() == true) return null - val methodName = intrinsicName ?: (property ?: irFunction).name.toString() + val methodName = intrinsicName ?: propertyExplicitCall ?: propertyGetCall ?: irFunction.name.toString() val methodType = irFunction.getMethodType() return MethodHandles.lookup().findVirtual(receiverClass, methodName, methodType) @@ -173,6 +178,14 @@ class Wrapper(val value: Any, override val irClass: IrClass) : Complex(irClass, } companion object { + private val companionObjectValue = mapOf("kotlin.text.Regex\$Companion" to Regex.Companion) + + fun getCompanionObject(irClass: IrClass): Wrapper { + val objectName = irClass.getEvaluateIntrinsicValue()!! + val objectValue = companionObjectValue[objectName] ?: throw AssertionError("Companion object $objectName cannot be interpreted") + return Wrapper(objectValue, irClass) + } + fun getConstructorMethod(irConstructor: IrFunction): MethodHandle { val methodType = irConstructor.getMethodType()