/* * Copyright 2010-2019 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.generators.interpreter import org.jetbrains.kotlin.builtins.DefaultBuiltIns import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.PrimitiveType import org.jetbrains.kotlin.config.ApiVersion import org.jetbrains.kotlin.config.LanguageVersion import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl import org.jetbrains.kotlin.generators.util.GeneratorsFileUtil import org.jetbrains.kotlin.ir.declarations.IrFunction import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImpl import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns import org.jetbrains.kotlin.ir.types.impl.originalKotlinType import org.jetbrains.kotlin.ir.util.IdSignature import org.jetbrains.kotlin.ir.util.IdSignatureComposer import org.jetbrains.kotlin.ir.util.SymbolTable import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi2ir.generators.TypeTranslatorImpl import org.jetbrains.kotlin.storage.LockBasedStorageManager import org.jetbrains.kotlin.utils.Printer import java.io.File val DESTINATION = File("compiler/ir/ir.interpreter/src/org/jetbrains/kotlin/ir/interpreter/builtins/IrBuiltInsMapGenerated.kt") fun main() { GeneratorsFileUtil.writeFileIfContentChanged(DESTINATION, generateMap()) } fun generateMap(): String { val sb = StringBuilder() val p = Printer(sb) p.println(File("license/COPYRIGHT.txt").readText()) p.println("package org.jetbrains.kotlin.ir.interpreter.builtins") p.println() p.println("import org.jetbrains.kotlin.ir.interpreter.internalName") p.println("import org.jetbrains.kotlin.ir.interpreter.state.*") p.println() p.println("/** This file is generated by org.jetbrains.kotlin.backend.common.interpreter.builtins.GenerateBuiltInsMap.generateMap(). DO NOT MODIFY MANUALLY */") p.println() val irBuiltIns = getIrBuiltIns() val unaryOperationsMap = getOperationMap(1) val binaryOperationsMap = getOperationMap(2) val ternaryOperationsMap = getOperationMap(3) val binaryIrOperationsMap = getBinaryIrOperationMap(irBuiltIns) p.println("@Suppress(\"DEPRECATION\")") p.println("val unaryFunctions = mapOf>(") p.println(generateUnaryBody(unaryOperationsMap, irBuiltIns)) p.println(")") p.println() p.println("val binaryFunctions = mapOf>(") p.println(generateBinaryBody(binaryOperationsMap, binaryIrOperationsMap)) p.println(")") p.println() p.println("val ternaryFunctions = mapOf>(") p.println(generateTernaryBody(ternaryOperationsMap)) p.println(")") p.println() p.println( """ private fun Any.defaultToString(): String { return when (this) { is Lambda -> this.toString() is State -> "${'$'}{this.irClass.internalName()}@" + System.identityHashCode(this).toString(16).padStart(8, '0') else -> this.toString().replaceAfter("@", System.identityHashCode(this).toString(16).padStart(8, '0')) } } """.trimIndent() ) p.println() return sb.toString() } private fun getOperationMap(argumentsCount: Int): MutableMap> { val builtIns = DefaultBuiltIns.Instance val operationMap = mutableMapOf>() val allPrimitiveTypes = PrimitiveType.values().map { builtIns.getBuiltInClassByFqName(it.typeFqName) } val arrays = PrimitiveType.values().map { builtIns.getPrimitiveArrayClassDescriptor(it) } + builtIns.array fun CallableDescriptor.isFakeOverride(classDescriptor: ClassDescriptor): Boolean { val isPrimitive = KotlinBuiltIns.isPrimitiveClass(classDescriptor) || KotlinBuiltIns.isString(classDescriptor.defaultType) val isFakeOverridden = (this as? FunctionDescriptor)?.kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE return when { isPrimitive -> false else -> isFakeOverridden } } for (classDescriptor in allPrimitiveTypes + builtIns.string + arrays + builtIns.any) { val classTypeParameters = classDescriptor.typeConstructor.parameters.map { it.name.asString() } val typeParametersReplacedToAny = if (classTypeParameters.isNotEmpty()) classTypeParameters.joinToString(prefix = "<", postfix = ">") { "Any?" } else "" val classType = classDescriptor.defaultType.constructor.toString() val compileTimeFunctions = classDescriptor.unsubstitutedMemberScope.getContributedDescriptors() .filterIsInstance() .filter { !it.isFakeOverride(classDescriptor) } for (function in compileTimeFunctions) { val operationArguments = (listOf(classType) + function.valueParameters.map { it.type }).joinToString { "\"" + it + "\"" } val typeParametersOfFun = listOf(classType + typeParametersReplacedToAny) + function.valueParameters.map { if (classTypeParameters.contains(it.type.toString())) "Any?" else it.type.toString() } if (function.valueParameters.size + 1 == argumentsCount) { // +1 for receiver operationMap[function] = typeParametersOfFun.joinToString(prefix = "<", postfix = ">") to operationArguments } } } return operationMap } private fun getBinaryIrOperationMap(irBuiltIns: IrBuiltIns): MutableMap> { val operationMap = mutableMapOf>() val irFunSymbols = (irBuiltIns.lessFunByOperandType.values + irBuiltIns.lessOrEqualFunByOperandType.values + irBuiltIns.greaterFunByOperandType.values + irBuiltIns.greaterOrEqualFunByOperandType.values + irBuiltIns.eqeqSymbol + irBuiltIns.eqeqeqSymbol + irBuiltIns.ieee754equalsFunByOperandType.values + irBuiltIns.andandSymbol + irBuiltIns.ororSymbol) .map { it.owner } for (function in irFunSymbols) { val parametersTypes = function.valueParameters.map { it.type.originalKotlinType!!.toString() } val operationArguments = parametersTypes.joinToString { "\"" + it + "\"" } val functionTypeParameters = parametersTypes.joinToString(prefix = "<", postfix = ">") check(parametersTypes.size == 2) { "Couldn't add following method from ir builtins to operations map: ${function.name}" } operationMap[function] = functionTypeParameters to operationArguments } return operationMap } private fun generateUnaryBody(unaryOperationsMap: Map>, irBuiltIns: IrBuiltIns): String { val irNullCheck = irBuiltIns.checkNotNullSymbol.owner return unaryOperationsMap.entries.joinToString(separator = ",\n", postfix = ",\n") { (function, parameters) -> val methodName = "${function.name}" val parentheses = if (function is FunctionDescriptor) "()" else "" val body = if (methodName == "toString" && parameters.first == "") "a.defaultToString()" else "a.$methodName$parentheses" " unaryOperation${parameters.first}(\"$methodName\", ${parameters.second}) { a -> $body }" } + " unaryOperation(\"${irNullCheck.name}\", \"${irNullCheck.valueParameters.first().type.originalKotlinType}\") { a -> a!! },\n" + " unaryOperation(\"message\", \"Throwable\") { a -> a.getMessage() },\n" + " unaryOperation(\"cause\", \"Throwable\") { a -> a.getCause() }" } private fun generateBinaryBody( binaryOperationsMap: Map>, binaryIrOperationsMap: Map> ): String { return binaryOperationsMap.entries.joinToString(separator = ",\n", postfix = ",\n") { (function, parameters) -> val methodName = "${function.name}" " binaryOperation${parameters.first}(\"$methodName\", ${parameters.second}) { a, b -> a.$methodName(b) }" } + binaryIrOperationsMap.entries.joinToString(separator = ",\n") { (function, parameters) -> val methodName = "${function.name}" val methodSymbol = getIrMethodSymbolByName(methodName) " binaryOperation${parameters.first}(\"$methodName\", ${parameters.second}) { a, b -> a $methodSymbol b }" } } private fun generateTernaryBody(ternaryOperationsMap: Map>): String { return ternaryOperationsMap.entries.joinToString(separator = ",\n") { (function, parameters) -> val methodName = "${function.name}" " ternaryOperation${parameters.first}(\"$methodName\", ${parameters.second}) { a, b, c -> a.$methodName(b, c) }" } } private fun getIrMethodSymbolByName(methodName: String): String { return when (methodName) { IrBuiltIns.OperatorNames.LESS -> "<" IrBuiltIns.OperatorNames.LESS_OR_EQUAL -> "<=" IrBuiltIns.OperatorNames.GREATER -> ">" IrBuiltIns.OperatorNames.GREATER_OR_EQUAL -> ">=" IrBuiltIns.OperatorNames.EQEQ -> "==" IrBuiltIns.OperatorNames.EQEQEQ -> "===" IrBuiltIns.OperatorNames.IEEE754_EQUALS -> "==" IrBuiltIns.OperatorNames.ANDAND -> "&&" IrBuiltIns.OperatorNames.OROR -> "||" else -> throw UnsupportedOperationException("Unknown ir operation \"$methodName\"") } } private fun getIrBuiltIns(): IrBuiltIns { val languageSettings = LanguageVersionSettingsImpl(LanguageVersion.KOTLIN_1_3, ApiVersion.KOTLIN_1_3) val moduleDescriptor = ModuleDescriptorImpl(Name.special(""), LockBasedStorageManager(""), DefaultBuiltIns.Instance) val signaturer = object : IdSignatureComposer { override fun composeSignature(descriptor: DeclarationDescriptor): IdSignature? = null override fun composeEnumEntrySignature(descriptor: ClassDescriptor): IdSignature? = null } val symbolTable = SymbolTable(signaturer, IrFactoryImpl) val typeTranslator = TypeTranslatorImpl(symbolTable, languageSettings, moduleDescriptor) return IrBuiltIns(moduleDescriptor.builtIns, typeTranslator, symbolTable) }