Make possible to create arrays with their constructors
This commit is contained in:
+46
-12
@@ -20,6 +20,7 @@ import org.jetbrains.kotlin.ir.expressions.impl.IrConstructorCallImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrErrorExpressionImpl
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.types.classOrNull
|
||||
import org.jetbrains.kotlin.ir.types.isArray
|
||||
import org.jetbrains.kotlin.ir.types.isSubtypeOf
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import java.lang.invoke.MethodHandle
|
||||
@@ -323,6 +324,30 @@ class IrInterpreter(irModule: IrModuleFragment) {
|
||||
return Wrapper.getConstructorMethod(owner).invokeMethod(owner, newFrame).apply { data.pushReturnValue(newFrame) }
|
||||
}
|
||||
|
||||
if (parent.defaultType.isArray() || parent.defaultType.isPrimitiveArray()) {
|
||||
// array constructor doesn't have body so must be treated separately
|
||||
// here we must except only one possible constructor, with one value parameter size
|
||||
// the other one, with lambda, is transforming into ir returnable block
|
||||
val arrayConstructor = irBuiltIns.primitiveArrays.first().constructors.single { it.owner.valueParameters.size == 2 }
|
||||
val sizeDescriptor = arrayConstructor.owner.valueParameters.single { it.name.asString() == "size" }.descriptor
|
||||
val size = (newFrame.getVariableState(sizeDescriptor) as Primitive<Int>).value
|
||||
|
||||
val array = when (parent.defaultType.getFqName()) {
|
||||
"kotlin.ByteArray" -> Primitive(ByteArray(size), parent.defaultType)
|
||||
"kotlin.CharArray" -> Primitive(CharArray(size), parent.defaultType)
|
||||
"kotlin.ShortArray" -> Primitive(ShortArray(size), parent.defaultType)
|
||||
"kotlin.IntArray" -> Primitive(IntArray(size), parent.defaultType)
|
||||
"kotlin.LongArray" -> Primitive(LongArray(size), parent.defaultType)
|
||||
"kotlin.FloatArray" -> Primitive(FloatArray(size), parent.defaultType)
|
||||
"kotlin.DoubleArray" -> Primitive(DoubleArray(size), parent.defaultType)
|
||||
"kotlin.BooleanArray" -> Primitive(BooleanArray(size), parent.defaultType)
|
||||
else -> throw AssertionError("Unsupported array class ${parent.defaultType.getFqName()}")
|
||||
}
|
||||
|
||||
data.pushReturnValue(array)
|
||||
return Code.NEXT
|
||||
}
|
||||
|
||||
val state = Common(parent, mutableListOf())
|
||||
newFrame.addVar(Variable(constructorCall.getThisAsReceiver(), state)) //used to set up fields in body
|
||||
val code = constructorCall.getBody()?.interpret(newFrame) ?: Code.NEXT
|
||||
@@ -333,8 +358,8 @@ class IrInterpreter(irModule: IrModuleFragment) {
|
||||
|
||||
private suspend fun interpretConstructorCall(constructorCall: IrConstructorCall, data: Frame): Code {
|
||||
return interpretConstructor(constructorCall, data).apply {
|
||||
val instance = data.peekReturnValue() as Complex
|
||||
instance.setInstanceRecursive(instance)
|
||||
// constructor can return primitive object; fot example, when create array by constructor
|
||||
(data.peekReturnValue() as? Complex)?.let { it.setInstanceRecursive(it) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -372,17 +397,26 @@ class IrInterpreter(irModule: IrModuleFragment) {
|
||||
return Code.NEXT
|
||||
}
|
||||
|
||||
val inlineFunOwner = (block as? IrReturnableBlock)?.inlineFunctionSymbol?.owner
|
||||
if (inlineFunOwner?.hasAnnotation(evaluateIntrinsicAnnotation) == true) {
|
||||
val rawArgs = block.statements.filterIsInstance<IrVariable>().zip(inlineFunOwner.valueParameters)
|
||||
val args = mutableListOf<Variable>()
|
||||
for ((variable, valueParameter) in rawArgs) {
|
||||
val tempFrame = data.copy().apply { variable.initializer!!.interpret(this).also { if (it != Code.NEXT) return it } }
|
||||
// must set variable descriptor here because temp variables inside ir returnable block have different from methods args names
|
||||
args += Variable(valueParameter.descriptor, tempFrame.popReturnValue())
|
||||
val inlineFun = (block as? IrReturnableBlock)?.inlineFunctionSymbol?.owner
|
||||
if (inlineFun?.hasAnnotation(evaluateIntrinsicAnnotation) == true) {
|
||||
val newFrame = data.copy()
|
||||
block.statements.filterIsInstance<IrVariable>().forEach { variable ->
|
||||
variable.initializer!!.interpret(newFrame).also { if (it != Code.NEXT) return it }
|
||||
newFrame.addVar(Variable(variable.descriptor, newFrame.popReturnValue()))
|
||||
}
|
||||
val newFrame = data.copy().apply { addAll(args) }
|
||||
return Wrapper.getStaticMethod(inlineFunOwner).invokeMethod(inlineFunOwner, newFrame).apply { data.pushReturnValue(newFrame) }
|
||||
|
||||
val originalVarToInline = ParallelVisitorForInlineFun()
|
||||
.apply { this.visitElement(inlineFun.body!!.statements.first(), block.statements.last()) }
|
||||
.originalVarToInline
|
||||
|
||||
val frameForWrapper = InterpreterFrame()
|
||||
(listOfNotNull(inlineFun.extensionReceiverParameter, inlineFun.dispatchReceiverParameter) + inlineFun.valueParameters)
|
||||
.map { it.descriptor }
|
||||
.forEach { frameForWrapper.addVar(Variable(it, newFrame.getVariableState(originalVarToInline[it]!!))) }
|
||||
|
||||
return Wrapper.getStaticMethod(inlineFun)
|
||||
.invokeMethod(inlineFun, frameForWrapper)
|
||||
.apply { data.pushReturnValue(frameForWrapper) }
|
||||
}
|
||||
|
||||
return interpretStatements(block.statements, data)
|
||||
|
||||
+137
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.backend.common.interpreter
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.declarations.IrVariable
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.util.statements
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
||||
|
||||
/**
|
||||
* This class is used for parallel processing two ir elements and gathering information about ir temporary variables from inline block
|
||||
*/
|
||||
internal class ParallelVisitorForInlineFun : IrElementVisitor<Unit, IrElement> {
|
||||
val originalVarToInline = mutableMapOf<DeclarationDescriptor, DeclarationDescriptor>()
|
||||
|
||||
override fun visitElement(element: IrElement, data: IrElement) {
|
||||
element.accept(this, data)
|
||||
}
|
||||
|
||||
override fun visitGetValue(expression: IrGetValue, data: IrElement) {
|
||||
val original = expression.symbol.descriptor
|
||||
val inline = (data as IrGetValue).symbol.descriptor
|
||||
if (!original.equalTo(inline)) {
|
||||
originalVarToInline[original] = inline
|
||||
}
|
||||
}
|
||||
|
||||
override fun <T> visitConst(expression: IrConst<T>, data: IrElement) {}
|
||||
|
||||
override fun visitVariable(declaration: IrVariable, data: IrElement) {
|
||||
declaration.initializer?.accept(this, (data as IrVariable).initializer!!)
|
||||
}
|
||||
|
||||
override fun visitBody(body: IrBody, data: IrElement) {
|
||||
for ((index, statement) in body.statements.withIndex()) {
|
||||
statement.accept(this, (data as IrBody).statements[index])
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitBlock(expression: IrBlock, data: IrElement) {
|
||||
for ((index, statement) in expression.statements.withIndex()) {
|
||||
statement.accept(this, (data as IrBlock).statements[index])
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitStringConcatenation(expression: IrStringConcatenation, data: IrElement) {
|
||||
for ((index, argument) in expression.arguments.withIndex()) {
|
||||
argument.accept(this, (data as IrStringConcatenation).arguments[index])
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitSetVariable(expression: IrSetVariable, data: IrElement) {
|
||||
expression.value.accept(this, (data as IrSetVariable).value)
|
||||
}
|
||||
|
||||
override fun visitGetField(expression: IrGetField, data: IrElement) {
|
||||
expression.receiver?.accept(this, (data as IrGetField).receiver!!)
|
||||
}
|
||||
|
||||
override fun visitSetField(expression: IrSetField, data: IrElement) {
|
||||
expression.value.accept(this, (data as IrSetField).value)
|
||||
expression.receiver?.accept(this, data.receiver!!)
|
||||
}
|
||||
|
||||
override fun visitCall(expression: IrCall, data: IrElement) {
|
||||
expression.dispatchReceiver?.accept(this, (data as IrCall).dispatchReceiver!!)
|
||||
expression.extensionReceiver?.accept(this, (data as IrCall).extensionReceiver!!)
|
||||
for (i in 0 until expression.valueArgumentsCount) {
|
||||
expression.getValueArgument(i)?.accept(this, (data as IrCall).getValueArgument(i)!!)
|
||||
}
|
||||
expression.getBody()?.accept(this, (data as IrCall).getBody()!!)
|
||||
}
|
||||
|
||||
override fun visitConstructorCall(expression: IrConstructorCall, data: IrElement) {
|
||||
expression.dispatchReceiver?.accept(this, (data as IrConstructorCall).dispatchReceiver!!)
|
||||
expression.extensionReceiver?.accept(this, (data as IrConstructorCall).extensionReceiver!!)
|
||||
for (i in 0 until expression.valueArgumentsCount) {
|
||||
expression.getValueArgument(i)?.accept(this, (data as IrConstructorCall).getValueArgument(i)!!)
|
||||
}
|
||||
expression.getBody()?.accept(this, (data as IrConstructorCall).getBody()!!)
|
||||
}
|
||||
|
||||
override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall, data: IrElement) {
|
||||
expression.dispatchReceiver?.accept(this, (data as IrDelegatingConstructorCall).dispatchReceiver!!)
|
||||
expression.extensionReceiver?.accept(this, (data as IrDelegatingConstructorCall).extensionReceiver!!)
|
||||
for (i in 0 until expression.valueArgumentsCount) {
|
||||
expression.getValueArgument(i)?.accept(this, (data as IrDelegatingConstructorCall).getValueArgument(i)!!)
|
||||
}
|
||||
expression.getBody()?.accept(this, (data as IrDelegatingConstructorCall).getBody()!!)
|
||||
}
|
||||
|
||||
override fun visitWhen(expression: IrWhen, data: IrElement) {
|
||||
for ((index, branch) in expression.branches.withIndex()) {
|
||||
branch.accept(this, (data as IrWhen).branches[index])
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitBranch(branch: IrBranch, data: IrElement) {
|
||||
branch.condition.accept(this, (data as IrBranch).condition)
|
||||
branch.result.accept(this, data.result)
|
||||
}
|
||||
|
||||
override fun visitLoop(loop: IrLoop, data: IrElement) {
|
||||
loop.condition.accept(this, (data as IrLoop).condition)
|
||||
loop.body?.accept(this, data.body!!)
|
||||
}
|
||||
|
||||
override fun visitTry(aTry: IrTry, data: IrElement) {
|
||||
aTry.tryResult.accept(this, (data as IrTry).tryResult)
|
||||
for ((index, catch) in aTry.catches.withIndex()) {
|
||||
catch.accept(this, data.catches[index])
|
||||
}
|
||||
aTry.finallyExpression?.accept(this, data.finallyExpression!!)
|
||||
}
|
||||
|
||||
override fun visitCatch(aCatch: IrCatch, data: IrElement) {
|
||||
aCatch.catchParameter.accept(this, (data as IrCatch).catchParameter)
|
||||
aCatch.result.accept(this, data.result)
|
||||
}
|
||||
|
||||
override fun visitReturn(expression: IrReturn, data: IrElement) {
|
||||
expression.value.accept(this, (data as IrReturn).value)
|
||||
}
|
||||
|
||||
override fun visitThrow(expression: IrThrow, data: IrElement) {
|
||||
expression.value.accept(this, (data as IrThrow).value)
|
||||
}
|
||||
|
||||
override fun visitTypeOperator(expression: IrTypeOperatorCall, data: IrElement) {
|
||||
expression.argument.accept(this, (data as IrTypeOperatorCall).argument)
|
||||
}
|
||||
}
|
||||
+3
-1
@@ -9,4 +9,6 @@ package org.jetbrains.kotlin.backend.common.interpreter.intrinsic
|
||||
|
||||
public fun emptyArray(): Array<Any?> = kotlin.emptyArray()
|
||||
|
||||
public fun arrayOf(vararg elements: Any?): Array<Any?> = elements as Array<Any?>
|
||||
public fun arrayOf(vararg elements: Any?): Array<Any?> = elements as Array<Any?>
|
||||
|
||||
public fun arrayOfNulls(size: Int): Array<Any?> = arrayOfNulls<Any?>(size)
|
||||
Reference in New Issue
Block a user