From ef4e4881b7878cfffec380816750fb119e43e492 Mon Sep 17 00:00:00 2001 From: Ivan Kylchik Date: Tue, 7 Apr 2020 00:02:16 +0300 Subject: [PATCH] Implement spread operator interpretation --- .../common/interpreter/IrInterpreter.kt | 60 +++++++++---------- .../backend/common/interpreter/Utils.kt | 14 +++++ 2 files changed, 41 insertions(+), 33 deletions(-) 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 8b5cab7699a..28c0f8bd045 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 @@ -93,6 +93,7 @@ class IrInterpreter(irModule: IrModuleFragment) { is IrBreak -> interpretBreak(this, data) is IrContinue -> interpretContinue(this, data) is IrVararg -> interpretVararg(this, data) + is IrSpreadElement -> interpretSpreadElement(this, data) is IrTry -> interpretTry(this, data) is IrCatch -> interpretCatch(this, data) is IrThrow -> interpretThrow(this, data) @@ -441,7 +442,7 @@ class IrInterpreter(irModule: IrModuleFragment) { val sizeDescriptor = arrayConstructor.owner.valueParameters.single { it.name.asString() == "size" }.descriptor val size = (newFrame.getVariableState(sizeDescriptor) as Primitive<*>).value as Int - val arrayValue = Array(size) { 0 } + val arrayValue = MutableList(size) { 0 } if (owner.valueParameters.size == 2) { val initDescriptor = arrayConstructor.owner.valueParameters.single { it.name.asString() == "init" }.descriptor val initLambda = newFrame.getVariableState(initDescriptor) as Lambda @@ -452,20 +453,7 @@ class IrInterpreter(irModule: IrModuleFragment) { arrayValue[i] = lambdaFrame.popReturnValue().let { (it as? Wrapper)?.value ?: (it as? Primitive<*>)?.value ?: it } } } - - val array = when (parent.defaultType.getFqName()) { - "kotlin.ByteArray" -> Primitive(ByteArray(size) { i -> (arrayValue[i] as Number).toByte() }, parent.defaultType) - "kotlin.CharArray" -> Primitive(CharArray(size) { i -> (arrayValue[i] as Number).toChar() }, parent.defaultType) - "kotlin.ShortArray" -> Primitive(ShortArray(size) { i -> (arrayValue[i] as Number).toShort() }, parent.defaultType) - "kotlin.IntArray" -> Primitive(IntArray(size) { i -> (arrayValue[i] as Number).toInt() }, parent.defaultType) - "kotlin.LongArray" -> Primitive(LongArray(size) { i -> (arrayValue[i] as Number).toLong() }, parent.defaultType) - "kotlin.FloatArray" -> Primitive(FloatArray(size) { i -> (arrayValue[i] as Number).toFloat() }, parent.defaultType) - "kotlin.DoubleArray" -> Primitive(DoubleArray(size) { i -> (arrayValue[i] as Number).toDouble() }, parent.defaultType) - "kotlin.BooleanArray" -> Primitive(BooleanArray(size) { i -> arrayValue[i].toString().toBoolean() }, parent.defaultType) - else -> Primitive>(arrayValue, parent.defaultType) - } as Primitive<*> - - data.pushReturnValue(array) + data.pushReturnValue(arrayValue.toPrimitiveStateArray(parent.defaultType)) return Next } @@ -718,29 +706,35 @@ class IrInterpreter(irModule: IrModuleFragment) { } } - @Suppress("UNCHECKED_CAST") private suspend fun interpretVararg(expression: IrVararg, data: Frame): ExecutionResult { - val args = expression.elements.map { - it.interpret(data).apply { if (this.returnLabel != ReturnLabel.NEXT) return this } - data.popReturnValue() + val args = expression.elements.flatMap { + it.interpret(data).check { return it } + return@flatMap when (val result = data.popReturnValue()) { + is Wrapper -> listOf(result.value) + is Primitive<*> -> + when (val value = result.value) { + is ByteArray -> value.toList() + is CharArray -> value.toList() + is ShortArray -> value.toList() + is IntArray -> value.toList() + is LongArray -> value.toList() + is FloatArray -> value.toList() + is DoubleArray -> value.toList() + is BooleanArray -> value.toList() + is Array<*> -> value.toList() + else -> listOf(value) + } + else -> listOf(result) + } } - val type = expression.type - val array = when (type.getFqName()) { - "kotlin.ByteArray" -> Primitive(args.map { (it as Primitive).value }.toByteArray(), type) - "kotlin.CharArray" -> Primitive(args.map { (it as Primitive).value }.toCharArray(), type) - "kotlin.ShortArray" -> Primitive(args.map { (it as Primitive).value }.toShortArray(), type) - "kotlin.IntArray" -> Primitive(args.map { (it as Primitive).value }.toIntArray(), type) - "kotlin.LongArray" -> Primitive(args.map { (it as Primitive).value }.toLongArray(), type) - "kotlin.FloatArray" -> Primitive(args.map { (it as Primitive).value }.toFloatArray(), type) - "kotlin.DoubleArray" -> Primitive(args.map { (it as Primitive).value }.toDoubleArray(), type) - "kotlin.BooleanArray" -> Primitive(args.map { (it as Primitive).value }.toBooleanArray(), type) - else -> Primitive>(args.map { (it as? Wrapper)?.value ?: (it as? Primitive<*>)?.value ?: it }.toTypedArray(), type) - } - data.pushReturnValue(array) - + data.pushReturnValue(args.toPrimitiveStateArray(expression.type)) return Next } + private suspend fun interpretSpreadElement(spreadElement: IrSpreadElement, data: Frame): ExecutionResult { + return spreadElement.expression.interpret(data).check { return it } + } + private suspend fun interpretTry(expression: IrTry, data: Frame): ExecutionResult { var executionResult = expression.tryResult.interpret(data) if (executionResult.returnLabel == ReturnLabel.EXCEPTION) { diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/Utils.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/Utils.kt index 7c3a42ca063..d337816aa8d 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/Utils.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/interpreter/Utils.kt @@ -208,4 +208,18 @@ fun IrFunction.getLastOverridden(): IrFunction { function = function.overriddenSymbols.first().owner as IrFunctionImpl } return function +} + +fun List.toPrimitiveStateArray(type: IrType): Primitive<*> { + return when (type.getFqName()) { + "kotlin.ByteArray" -> Primitive(ByteArray(size) { i -> (this[i] as Number).toByte() }, type) + "kotlin.CharArray" -> Primitive(CharArray(size) { i -> this[i] as Char }, type) + "kotlin.ShortArray" -> Primitive(ShortArray(size) { i -> (this[i] as Number).toShort() }, type) + "kotlin.IntArray" -> Primitive(IntArray(size) { i -> (this[i] as Number).toInt() }, type) + "kotlin.LongArray" -> Primitive(LongArray(size) { i -> (this[i] as Number).toLong() }, type) + "kotlin.FloatArray" -> Primitive(FloatArray(size) { i -> (this[i] as Number).toFloat() }, type) + "kotlin.DoubleArray" -> Primitive(DoubleArray(size) { i -> (this[i] as Number).toDouble() }, type) + "kotlin.BooleanArray" -> Primitive(BooleanArray(size) { i -> this[i].toString().toBoolean() }, type) + else -> Primitive>(this.toTypedArray(), type) + } } \ No newline at end of file