Move out intrinsic evaluation from interpreter class
This commit is contained in:
+7
-104
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.backend.common.interpreter.builtins.*
|
|||||||
import org.jetbrains.kotlin.backend.common.interpreter.exceptions.InterpreterException
|
import org.jetbrains.kotlin.backend.common.interpreter.exceptions.InterpreterException
|
||||||
import org.jetbrains.kotlin.backend.common.interpreter.exceptions.InterpreterMethodNotFoundException
|
import org.jetbrains.kotlin.backend.common.interpreter.exceptions.InterpreterMethodNotFoundException
|
||||||
import org.jetbrains.kotlin.backend.common.interpreter.exceptions.InterpreterTimeOutException
|
import org.jetbrains.kotlin.backend.common.interpreter.exceptions.InterpreterTimeOutException
|
||||||
|
import org.jetbrains.kotlin.backend.common.interpreter.intrinsics.IntrinsicEvaluator
|
||||||
import org.jetbrains.kotlin.backend.common.interpreter.stack.*
|
import org.jetbrains.kotlin.backend.common.interpreter.stack.*
|
||||||
import org.jetbrains.kotlin.backend.common.interpreter.state.*
|
import org.jetbrains.kotlin.backend.common.interpreter.state.*
|
||||||
import org.jetbrains.kotlin.builtins.DefaultBuiltIns
|
import org.jetbrains.kotlin.builtins.DefaultBuiltIns
|
||||||
@@ -32,8 +33,6 @@ class IrInterpreter(irModule: IrModuleFragment) {
|
|||||||
private val irBuiltIns = irModule.irBuiltins
|
private val irBuiltIns = irModule.irBuiltins
|
||||||
private val irExceptions = irModule.files.flatMap { it.declarations }.filterIsInstance<IrClass>()
|
private val irExceptions = irModule.files.flatMap { it.declarations }.filterIsInstance<IrClass>()
|
||||||
.filter { it.isSubclassOf(irBuiltIns.throwableClass.owner) }
|
.filter { it.isSubclassOf(irBuiltIns.throwableClass.owner) }
|
||||||
private val classCastException = irExceptions.first { it.name.asString() == ClassCastException::class.java.simpleName }
|
|
||||||
private val illegalArgumentException = irExceptions.first { it.name.asString() == IllegalArgumentException::class.java.simpleName }
|
|
||||||
|
|
||||||
private val stack = StackImpl()
|
private val stack = StackImpl()
|
||||||
private var commandCount = 0
|
private var commandCount = 0
|
||||||
@@ -154,71 +153,7 @@ class IrInterpreter(irModule: IrModuleFragment) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun handleIntrinsicMethods(irFunction: IrFunction): ExecutionResult {
|
private suspend fun handleIntrinsicMethods(irFunction: IrFunction): ExecutionResult {
|
||||||
when (irFunction.name.asString()) {
|
return IntrinsicEvaluator().evaluate(irFunction, stack) { this.interpret() }
|
||||||
"emptyArray" -> {
|
|
||||||
val result = emptyArray<Any?>()
|
|
||||||
stack.pushReturnValue(result.toState(result.getType(irFunction.returnType)))
|
|
||||||
}
|
|
||||||
"arrayOf" -> {
|
|
||||||
val result = irFunction.getArgsForMethodInvocation(stack.getAll()).toTypedArray()
|
|
||||||
stack.pushReturnValue(result.toState(result.getType(irFunction.returnType)))
|
|
||||||
}
|
|
||||||
"arrayOfNulls" -> {
|
|
||||||
val size = stack.getVariableState(irFunction.valueParameters.first().descriptor).asInt()
|
|
||||||
val result = arrayOfNulls<Any?>(size)
|
|
||||||
stack.pushReturnValue(result.toState(result.getType(irFunction.returnType)))
|
|
||||||
}
|
|
||||||
"values", "enumValues" -> {
|
|
||||||
val enumClass =
|
|
||||||
(irFunction.parent as? IrClass) ?: stack.getVariableState(irFunction.typeParameters.first().descriptor).irClass
|
|
||||||
val enumEntries = enumClass.declarations
|
|
||||||
.filterIsInstance<IrEnumEntry>()
|
|
||||||
.map { entry ->
|
|
||||||
entry.interpret().check { return it }
|
|
||||||
stack.popReturnValue() as Common
|
|
||||||
}
|
|
||||||
stack.pushReturnValue(enumEntries.toTypedArray().toState(irBuiltIns.arrayClass.defaultType))
|
|
||||||
}
|
|
||||||
"valueOf", "enumValueOf" -> {
|
|
||||||
val enumClass =
|
|
||||||
(irFunction.parent as? IrClass) ?: stack.getVariableState(irFunction.typeParameters.first().descriptor).irClass
|
|
||||||
val enumEntryName = stack.getVariableState(irFunction.valueParameters.first().descriptor).asString()
|
|
||||||
val enumEntry = enumClass.declarations
|
|
||||||
.filterIsInstance<IrEnumEntry>()
|
|
||||||
.singleOrNull { it.name.asString() == enumEntryName }
|
|
||||||
if (enumEntry == null) {
|
|
||||||
val message = "No enum constant ${enumClass.fqNameForIrSerialization}.$enumEntryName"
|
|
||||||
stack.pushReturnValue(ExceptionState(IllegalArgumentException(message), illegalArgumentException, stack.getStackTrace()))
|
|
||||||
return Exception
|
|
||||||
} else {
|
|
||||||
enumEntry.interpret().check { return it }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"replace" -> {
|
|
||||||
val states = stack.getAll().map { it.state }
|
|
||||||
val regex = states.filterIsInstance<Wrapper>().single().value as Regex
|
|
||||||
val input = states.filterIsInstance<Primitive<*>>().single().asString()
|
|
||||||
val transform = states.filterIsInstance<Lambda>().single().irFunction
|
|
||||||
val matchResultParameter = transform.valueParameters.single()
|
|
||||||
val result = regex.replace(input) {
|
|
||||||
val itAsState = Variable(matchResultParameter.descriptor, Wrapper(it, matchResultParameter.type.classOrNull!!.owner))
|
|
||||||
runBlocking { stack.newFrame(initPool = listOf(itAsState)) { transform.interpret() } }//.check { return it }
|
|
||||||
stack.popReturnValue().asString()
|
|
||||||
//TODO("replace not implemented")
|
|
||||||
}
|
|
||||||
stack.pushReturnValue(result.toState(irBuiltIns.stringType))
|
|
||||||
}
|
|
||||||
"hashCode" -> {
|
|
||||||
if (irFunction.parentAsClass.isEnumClass) {
|
|
||||||
calculateBuiltIns(irFunction.getLastOverridden() as IrSimpleFunction)
|
|
||||||
} else {
|
|
||||||
throw InterpreterException("Hash code function intrinsic is supported only for enum class")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else -> throw InterpreterException("Unsupported intrinsic ${irFunction.name}")
|
|
||||||
}
|
|
||||||
|
|
||||||
return Next
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun calculateAbstract(irFunction: IrFunction): ExecutionResult {
|
private suspend fun calculateAbstract(irFunction: IrFunction): ExecutionResult {
|
||||||
@@ -419,42 +354,12 @@ class IrInterpreter(irModule: IrModuleFragment) {
|
|||||||
|
|
||||||
val parent = owner.parent as IrClass
|
val parent = owner.parent as IrClass
|
||||||
if (parent.hasAnnotation(evaluateIntrinsicAnnotation)) {
|
if (parent.hasAnnotation(evaluateIntrinsicAnnotation)) {
|
||||||
return when (owner.parentAsClass.getEvaluateIntrinsicValue()) {
|
return stack.newFrame(initPool = valueArguments) { Wrapper.getConstructorMethod(owner).invokeMethod(owner) }
|
||||||
"kotlin.Long" -> {
|
|
||||||
val low = valueArguments[0].state.asInt()
|
|
||||||
val high = valueArguments[1].state.asInt()
|
|
||||||
stack.pushReturnValue((high.toLong().shl(32) + low).toState(irBuiltIns.longType))
|
|
||||||
Next
|
|
||||||
}
|
|
||||||
"kotlin.Char" -> {
|
|
||||||
val value = valueArguments[0].state.asInt()
|
|
||||||
stack.pushReturnValue(value.toChar().toState(irBuiltIns.charType))
|
|
||||||
Next
|
|
||||||
}
|
|
||||||
else -> stack.newFrame(initPool = valueArguments) { Wrapper.getConstructorMethod(owner).invokeMethod(owner) }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parent.defaultType.isArray() || parent.defaultType.isPrimitiveArray()) {
|
if (parent.defaultType.isArray() || parent.defaultType.isPrimitiveArray()) {
|
||||||
// array constructor doesn't have body so must be treated separately
|
// array constructor doesn't have body so must be treated separately
|
||||||
val arrayConstructor = irBuiltIns.primitiveArrays.first().constructors.single { it.owner.valueParameters.size == 2 }
|
return stack.newFrame(initPool = valueArguments) { handleIntrinsicMethods(owner) }
|
||||||
val sizeDescriptor = arrayConstructor.owner.valueParameters.single { it.name.asString() == "size" }.descriptor
|
|
||||||
val size = valueArguments[0].state.asInt()
|
|
||||||
|
|
||||||
val arrayValue = MutableList<Any>(size) { 0 }
|
|
||||||
if (owner.valueParameters.size == 2) {
|
|
||||||
val initDescriptor = arrayConstructor.owner.valueParameters.single { it.name.asString() == "init" }.descriptor
|
|
||||||
val initLambda = valueArguments[1].state as Lambda
|
|
||||||
val indexDescriptor = initLambda.irFunction.valueParameters.single().descriptor
|
|
||||||
for (i in 0 until size) {
|
|
||||||
stack.newFrame(initPool = listOf(Variable(indexDescriptor, i.toState(irBuiltIns.intType)))) {
|
|
||||||
initLambda.irFunction.body!!.interpret()
|
|
||||||
}.check(ReturnLabel.RETURN) { return it } // TODO throw exception if label != RETURN
|
|
||||||
arrayValue[i] = stack.popReturnValue().let { (it as? Wrapper)?.value ?: (it as? Primitive<*>)?.value ?: it }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stack.pushReturnValue(arrayValue.toPrimitiveStateArray(parent.defaultType))
|
|
||||||
return Next
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val state = Common(parent)
|
val state = Common(parent)
|
||||||
@@ -665,11 +570,9 @@ class IrInterpreter(irModule: IrModuleFragment) {
|
|||||||
IrTypeOperator.IMPLICIT_COERCION_TO_UNIT -> stack.popReturnValue()
|
IrTypeOperator.IMPLICIT_COERCION_TO_UNIT -> stack.popReturnValue()
|
||||||
IrTypeOperator.CAST, IrTypeOperator.IMPLICIT_CAST -> {
|
IrTypeOperator.CAST, IrTypeOperator.IMPLICIT_CAST -> {
|
||||||
if (!stack.peekReturnValue().irClass.defaultType.isSubtypeOf(expression.type, irBuiltIns)) {
|
if (!stack.peekReturnValue().irClass.defaultType.isSubtypeOf(expression.type, irBuiltIns)) {
|
||||||
val convertibleClassName = stack.popReturnValue().irClass.fqNameForIrSerialization
|
val convertibleClassName = stack.popReturnValue().irClass.fqNameWhenAvailable
|
||||||
val castClassName = expression.type.classOrNull?.owner?.fqNameForIrSerialization
|
val castClassName = expression.type.classOrNull?.owner?.fqNameWhenAvailable
|
||||||
val message = "$convertibleClassName cannot be cast to $castClassName"
|
throw ClassCastException("$convertibleClassName cannot be cast to $castClassName")
|
||||||
stack.pushReturnValue(ExceptionState(ClassCastException(message), classCastException, stack.getStackTrace()))
|
|
||||||
return Exception
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
IrTypeOperator.SAFE_CAST -> {
|
IrTypeOperator.SAFE_CAST -> {
|
||||||
|
|||||||
+16
@@ -0,0 +1,16 @@
|
|||||||
|
/*
|
||||||
|
* 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.intrinsics
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.backend.common.interpreter.ExecutionResult
|
||||||
|
import org.jetbrains.kotlin.backend.common.interpreter.stack.Stack
|
||||||
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||||
|
|
||||||
|
interface Intrinsic {
|
||||||
|
fun equalTo(irFunction: IrFunction): Boolean
|
||||||
|
suspend fun evaluate(irFunction: IrFunction, stack: Stack, interpret: suspend IrElement.() -> ExecutionResult): ExecutionResult
|
||||||
|
}
|
||||||
+29
@@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* 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.intrinsics
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.backend.common.interpreter.ExecutionResult
|
||||||
|
import org.jetbrains.kotlin.backend.common.interpreter.exceptions.InterpreterMethodNotFoundException
|
||||||
|
import org.jetbrains.kotlin.backend.common.interpreter.stack.Stack
|
||||||
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||||
|
|
||||||
|
class IntrinsicEvaluator {
|
||||||
|
suspend fun evaluate(irFunction: IrFunction, stack: Stack, interpret: suspend IrElement.() -> ExecutionResult): ExecutionResult {
|
||||||
|
return when {
|
||||||
|
EmptyArray.equalTo(irFunction) -> EmptyArray.evaluate(irFunction, stack, interpret)
|
||||||
|
ArrayOf.equalTo(irFunction) -> ArrayOf.evaluate(irFunction, stack, interpret)
|
||||||
|
ArrayOfNulls.equalTo(irFunction) -> ArrayOfNulls.evaluate(irFunction, stack, interpret)
|
||||||
|
EnumValues.equalTo(irFunction) -> EnumValues.evaluate(irFunction, stack, interpret)
|
||||||
|
EnumValueOf.equalTo(irFunction) -> EnumValueOf.evaluate(irFunction, stack, interpret)
|
||||||
|
RegexReplace.equalTo(irFunction) -> RegexReplace.evaluate(irFunction, stack, interpret)
|
||||||
|
EnumHashCode.equalTo(irFunction) -> EnumHashCode.evaluate(irFunction, stack, interpret)
|
||||||
|
JsPrimitives.equalTo(irFunction) -> JsPrimitives.evaluate(irFunction, stack, interpret)
|
||||||
|
ArrayConstructor.equalTo(irFunction) -> ArrayConstructor.evaluate(irFunction, stack, interpret)
|
||||||
|
else -> throw InterpreterMethodNotFoundException("Method ${irFunction.name} hasn't implemented")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+201
@@ -0,0 +1,201 @@
|
|||||||
|
/*
|
||||||
|
* 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.intrinsics
|
||||||
|
|
||||||
|
import kotlinx.coroutines.runBlocking
|
||||||
|
import org.jetbrains.kotlin.backend.common.interpreter.*
|
||||||
|
import org.jetbrains.kotlin.backend.common.interpreter.stack.Stack
|
||||||
|
import org.jetbrains.kotlin.backend.common.interpreter.stack.Variable
|
||||||
|
import org.jetbrains.kotlin.backend.common.interpreter.state.*
|
||||||
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
|
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.types.classOrNull
|
||||||
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
|
|
||||||
|
sealed class IntrinsicBase : Intrinsic
|
||||||
|
|
||||||
|
object EmptyArray : IntrinsicBase() {
|
||||||
|
override fun equalTo(irFunction: IrFunction): Boolean {
|
||||||
|
val fqName = irFunction.fqNameWhenAvailable.toString()
|
||||||
|
return fqName == "kotlin.emptyArray"
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun evaluate(
|
||||||
|
irFunction: IrFunction, stack: Stack, interpret: suspend IrElement.() -> ExecutionResult
|
||||||
|
): ExecutionResult {
|
||||||
|
stack.pushReturnValue(emptyArray<Any?>().toState(irFunction.returnType))
|
||||||
|
return Next
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object ArrayOf : IntrinsicBase() {
|
||||||
|
override fun equalTo(irFunction: IrFunction): Boolean {
|
||||||
|
val fqName = irFunction.fqNameWhenAvailable.toString()
|
||||||
|
return fqName == "kotlin.arrayOf"
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun evaluate(
|
||||||
|
irFunction: IrFunction, stack: Stack, interpret: suspend IrElement.() -> ExecutionResult
|
||||||
|
): ExecutionResult {
|
||||||
|
val array = irFunction.getArgsForMethodInvocation(stack.getAll()).toTypedArray()
|
||||||
|
stack.pushReturnValue(array.toState(irFunction.returnType))
|
||||||
|
return Next
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object ArrayOfNulls : IntrinsicBase() {
|
||||||
|
override fun equalTo(irFunction: IrFunction): Boolean {
|
||||||
|
val fqName = irFunction.fqNameWhenAvailable.toString()
|
||||||
|
return fqName == "kotlin.arrayOfNulls"
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun evaluate(
|
||||||
|
irFunction: IrFunction, stack: Stack, interpret: suspend IrElement.() -> ExecutionResult
|
||||||
|
): ExecutionResult {
|
||||||
|
val size = stack.getVariableState(irFunction.valueParameters.first().descriptor).asInt()
|
||||||
|
val array = arrayOfNulls<Any?>(size)
|
||||||
|
stack.pushReturnValue(array.toState(irFunction.returnType))
|
||||||
|
return Next
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 suspend fun evaluate(
|
||||||
|
irFunction: IrFunction, stack: Stack, interpret: suspend IrElement.() -> ExecutionResult
|
||||||
|
): ExecutionResult {
|
||||||
|
val enumClass = when (irFunction.fqNameWhenAvailable.toString()) {
|
||||||
|
"kotlin.enumValues" -> stack.getVariableState(irFunction.typeParameters.first().descriptor).irClass
|
||||||
|
else -> irFunction.parent as IrClass
|
||||||
|
}
|
||||||
|
|
||||||
|
val enumEntries = enumClass.declarations.filterIsInstance<IrEnumEntry>()
|
||||||
|
.map { entry -> entry.interpret().check { return it }.let { stack.popReturnValue() as Common } }
|
||||||
|
stack.pushReturnValue(enumEntries.toTypedArray().toState(irFunction.returnType))
|
||||||
|
return Next
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 suspend fun evaluate(
|
||||||
|
irFunction: IrFunction, stack: Stack, interpret: suspend IrElement.() -> ExecutionResult
|
||||||
|
): ExecutionResult {
|
||||||
|
val enumClass = when (irFunction.fqNameWhenAvailable.toString()) {
|
||||||
|
"kotlin.enumValueOf" -> stack.getVariableState(irFunction.typeParameters.first().descriptor).irClass
|
||||||
|
else -> irFunction.parent as IrClass
|
||||||
|
}
|
||||||
|
val enumEntryName = stack.getVariableState(irFunction.valueParameters.first().descriptor).asString()
|
||||||
|
val enumEntry = enumClass.declarations.filterIsInstance<IrEnumEntry>().singleOrNull { it.name.asString() == enumEntryName }
|
||||||
|
enumEntry?.interpret()?.check { return it }
|
||||||
|
?: throw IllegalArgumentException("No enum constant ${enumClass.fqNameWhenAvailable}.$enumEntryName")
|
||||||
|
|
||||||
|
return Next
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object RegexReplace : IntrinsicBase() {
|
||||||
|
override fun equalTo(irFunction: IrFunction): Boolean {
|
||||||
|
val fqName = irFunction.fqNameWhenAvailable.toString()
|
||||||
|
return fqName == "kotlin.text.Regex.replace" && irFunction.valueParameters.size == 2
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun evaluate(
|
||||||
|
irFunction: IrFunction, stack: Stack, interpret: suspend IrElement.() -> ExecutionResult
|
||||||
|
): ExecutionResult {
|
||||||
|
val states = stack.getAll().map { it.state }
|
||||||
|
val regex = states.filterIsInstance<Wrapper>().single().value as Regex
|
||||||
|
val input = states.filterIsInstance<Primitive<*>>().single().asString()
|
||||||
|
val transform = states.filterIsInstance<Lambda>().single().irFunction
|
||||||
|
val matchResultParameter = transform.valueParameters.single()
|
||||||
|
val result = regex.replace(input) {
|
||||||
|
val itAsState = Variable(matchResultParameter.descriptor, Wrapper(it, matchResultParameter.type.classOrNull!!.owner))
|
||||||
|
runBlocking { stack.newFrame(initPool = listOf(itAsState)) { transform.interpret() } }//.check { return it }
|
||||||
|
stack.popReturnValue().asString()
|
||||||
|
}
|
||||||
|
stack.pushReturnValue(result.toState(irFunction.returnType))
|
||||||
|
return Next
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object EnumHashCode : IntrinsicBase() {
|
||||||
|
override fun equalTo(irFunction: IrFunction): Boolean {
|
||||||
|
val fqName = irFunction.fqNameWhenAvailable.toString()
|
||||||
|
return fqName.endsWith(".hashCode") && irFunction.parentAsClass.isEnumClass
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun evaluate(
|
||||||
|
irFunction: IrFunction, stack: Stack, interpret: suspend IrElement.() -> ExecutionResult
|
||||||
|
): ExecutionResult {
|
||||||
|
val hashCode = stack.getAll().single().state.hashCode()
|
||||||
|
stack.pushReturnValue(hashCode.toState(irFunction.returnType))
|
||||||
|
return Next
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object JsPrimitives : IntrinsicBase() {
|
||||||
|
override fun equalTo(irFunction: IrFunction): Boolean {
|
||||||
|
val fqName = irFunction.fqNameWhenAvailable.toString()
|
||||||
|
return fqName == "kotlin.Long.<init>" || fqName == "kotlin.Char.<init>"
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun evaluate(
|
||||||
|
irFunction: IrFunction, stack: Stack, interpret: suspend IrElement.() -> ExecutionResult
|
||||||
|
): ExecutionResult {
|
||||||
|
when (irFunction.fqNameWhenAvailable.toString()) {
|
||||||
|
"kotlin.Long.<init>" -> {
|
||||||
|
val low = stack.getVariableState(irFunction.valueParameters[0].descriptor).asInt()
|
||||||
|
val high = stack.getVariableState(irFunction.valueParameters[1].descriptor).asInt()
|
||||||
|
stack.pushReturnValue((high.toLong().shl(32) + low).toState(irFunction.returnType))
|
||||||
|
}
|
||||||
|
"kotlin.Char.<init>" -> {
|
||||||
|
val value = stack.getVariableState(irFunction.valueParameters[0].descriptor).asInt()
|
||||||
|
stack.pushReturnValue(value.toChar().toState(irFunction.returnType))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Next
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object ArrayConstructor : IntrinsicBase() {
|
||||||
|
override fun equalTo(irFunction: IrFunction): Boolean {
|
||||||
|
val fqName = irFunction.fqNameWhenAvailable.toString()
|
||||||
|
return fqName.matches("kotlin\\.(Byte|Char|Short|Int|Long|Float|Double|Boolean|)Array\\.<init>".toRegex())
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun evaluate(
|
||||||
|
irFunction: IrFunction, stack: Stack, interpret: suspend IrElement.() -> ExecutionResult
|
||||||
|
): ExecutionResult {
|
||||||
|
val sizeDescriptor = irFunction.valueParameters[0].descriptor
|
||||||
|
val size = stack.getVariableState(sizeDescriptor).asInt()
|
||||||
|
val arrayValue = MutableList<Any>(size) { 0 }
|
||||||
|
|
||||||
|
if (irFunction.valueParameters.size == 2) {
|
||||||
|
val initDescriptor = irFunction.valueParameters[1].descriptor
|
||||||
|
val initLambda = stack.getVariableState(initDescriptor) as Lambda
|
||||||
|
val index = initLambda.irFunction.valueParameters.single()
|
||||||
|
for (i in 0 until size) {
|
||||||
|
val indexVar = listOf(Variable(index.descriptor, i.toState(index.type)))
|
||||||
|
// TODO throw exception if label != RETURN
|
||||||
|
stack.newFrame(initPool = indexVar) { initLambda.irFunction.body!!.interpret() }.check(ReturnLabel.RETURN) { return it }
|
||||||
|
arrayValue[i] = stack.popReturnValue().let { (it as? Wrapper)?.value ?: (it as? Primitive<*>)?.value ?: it }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stack.pushReturnValue(arrayValue.toPrimitiveStateArray(irFunction.parentAsClass.defaultType))
|
||||||
|
return Next
|
||||||
|
}
|
||||||
|
}
|
||||||
+5
-2
@@ -20,6 +20,7 @@ import org.jetbrains.kotlin.ir.types.*
|
|||||||
import org.jetbrains.kotlin.ir.util.defaultType
|
import org.jetbrains.kotlin.ir.util.defaultType
|
||||||
import org.jetbrains.kotlin.ir.util.fqNameForIrSerialization
|
import org.jetbrains.kotlin.ir.util.fqNameForIrSerialization
|
||||||
import org.jetbrains.kotlin.ir.util.isTypeParameter
|
import org.jetbrains.kotlin.ir.util.isTypeParameter
|
||||||
|
import org.jetbrains.kotlin.ir.util.parentAsClass
|
||||||
import org.jetbrains.kotlin.name.FqNameUnsafe
|
import org.jetbrains.kotlin.name.FqNameUnsafe
|
||||||
import java.lang.invoke.MethodHandle
|
import java.lang.invoke.MethodHandle
|
||||||
import java.lang.invoke.MethodHandles
|
import java.lang.invoke.MethodHandles
|
||||||
@@ -63,9 +64,11 @@ class Wrapper private constructor(
|
|||||||
return Wrapper(objectValue, irClass)
|
return Wrapper(objectValue, irClass)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getConstructorMethod(irConstructor: IrFunction): MethodHandle {
|
fun getConstructorMethod(irConstructor: IrFunction): MethodHandle? {
|
||||||
val methodType = irConstructor.getMethodType()
|
val intrinsicValue = irConstructor.parentAsClass.getEvaluateIntrinsicValue()
|
||||||
|
if (intrinsicValue == "kotlin.Char" || intrinsicValue == "kotlin.Long") return null
|
||||||
|
|
||||||
|
val methodType = irConstructor.getMethodType()
|
||||||
return MethodHandles.lookup().findConstructor(irConstructor.returnType.getClass(true), methodType)
|
return MethodHandles.lookup().findConstructor(irConstructor.returnType.getClass(true), methodType)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user