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.expressions.impl.IrErrorExpressionImpl
|
||||||
import org.jetbrains.kotlin.ir.types.IrType
|
import org.jetbrains.kotlin.ir.types.IrType
|
||||||
import org.jetbrains.kotlin.ir.types.classOrNull
|
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.types.isSubtypeOf
|
||||||
import org.jetbrains.kotlin.ir.util.*
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
import java.lang.invoke.MethodHandle
|
import java.lang.invoke.MethodHandle
|
||||||
@@ -323,6 +324,30 @@ class IrInterpreter(irModule: IrModuleFragment) {
|
|||||||
return Wrapper.getConstructorMethod(owner).invokeMethod(owner, newFrame).apply { data.pushReturnValue(newFrame) }
|
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())
|
val state = Common(parent, mutableListOf())
|
||||||
newFrame.addVar(Variable(constructorCall.getThisAsReceiver(), state)) //used to set up fields in body
|
newFrame.addVar(Variable(constructorCall.getThisAsReceiver(), state)) //used to set up fields in body
|
||||||
val code = constructorCall.getBody()?.interpret(newFrame) ?: Code.NEXT
|
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 {
|
private suspend fun interpretConstructorCall(constructorCall: IrConstructorCall, data: Frame): Code {
|
||||||
return interpretConstructor(constructorCall, data).apply {
|
return interpretConstructor(constructorCall, data).apply {
|
||||||
val instance = data.peekReturnValue() as Complex
|
// constructor can return primitive object; fot example, when create array by constructor
|
||||||
instance.setInstanceRecursive(instance)
|
(data.peekReturnValue() as? Complex)?.let { it.setInstanceRecursive(it) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -372,17 +397,26 @@ class IrInterpreter(irModule: IrModuleFragment) {
|
|||||||
return Code.NEXT
|
return Code.NEXT
|
||||||
}
|
}
|
||||||
|
|
||||||
val inlineFunOwner = (block as? IrReturnableBlock)?.inlineFunctionSymbol?.owner
|
val inlineFun = (block as? IrReturnableBlock)?.inlineFunctionSymbol?.owner
|
||||||
if (inlineFunOwner?.hasAnnotation(evaluateIntrinsicAnnotation) == true) {
|
if (inlineFun?.hasAnnotation(evaluateIntrinsicAnnotation) == true) {
|
||||||
val rawArgs = block.statements.filterIsInstance<IrVariable>().zip(inlineFunOwner.valueParameters)
|
val newFrame = data.copy()
|
||||||
val args = mutableListOf<Variable>()
|
block.statements.filterIsInstance<IrVariable>().forEach { variable ->
|
||||||
for ((variable, valueParameter) in rawArgs) {
|
variable.initializer!!.interpret(newFrame).also { if (it != Code.NEXT) return it }
|
||||||
val tempFrame = data.copy().apply { variable.initializer!!.interpret(this).also { if (it != Code.NEXT) return it } }
|
newFrame.addVar(Variable(variable.descriptor, newFrame.popReturnValue()))
|
||||||
// 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 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)
|
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 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