[IR] Use InlineClassesUtils in lowerings instead of IrClass.isInline
We do it because sometimes we want to treat a regular class as an inline class. For example, in the Wasm backend we treat classes with the `@WasmAutoboxed` annotation as inline classes. Also, in the JS IR backend the `Char` class is declared as a regular class for compatibility reasons, but we want it to be an inline class for performance.
This commit is contained in:
+6
-4
@@ -28,11 +28,13 @@ private const val INLINE_CLASS_IMPL_SUFFIX = "-impl"
|
|||||||
class InlineClassLowering(val context: CommonBackendContext) {
|
class InlineClassLowering(val context: CommonBackendContext) {
|
||||||
private val transformedFunction = context.mapping.inlineClassMemberToStatic
|
private val transformedFunction = context.mapping.inlineClassMemberToStatic
|
||||||
|
|
||||||
|
private fun isClassInlineLike(irClass: IrClass): Boolean = context.inlineClassesUtils.isClassInlineLike(irClass)
|
||||||
|
|
||||||
val inlineClassDeclarationLowering = object : DeclarationTransformer {
|
val inlineClassDeclarationLowering = object : DeclarationTransformer {
|
||||||
|
|
||||||
override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? {
|
override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? {
|
||||||
val irClass = declaration.parent as? IrClass ?: return null
|
val irClass = declaration.parent as? IrClass ?: return null
|
||||||
if (!irClass.isInline) return null
|
if (!isClassInlineLike(irClass)) return null
|
||||||
|
|
||||||
return when (declaration) {
|
return when (declaration) {
|
||||||
is IrConstructor -> transformConstructor(declaration)
|
is IrConstructor -> transformConstructor(declaration)
|
||||||
@@ -314,7 +316,7 @@ class InlineClassLowering(val context: CommonBackendContext) {
|
|||||||
override fun visitConstructorCall(expression: IrConstructorCall): IrExpression {
|
override fun visitConstructorCall(expression: IrConstructorCall): IrExpression {
|
||||||
expression.transformChildrenVoid(this)
|
expression.transformChildrenVoid(this)
|
||||||
val function = expression.symbol.owner
|
val function = expression.symbol.owner
|
||||||
if (!function.parentAsClass.isInline) {
|
if (!isClassInlineLike(function.parentAsClass)) {
|
||||||
return expression
|
return expression
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -326,7 +328,7 @@ class InlineClassLowering(val context: CommonBackendContext) {
|
|||||||
val function: IrSimpleFunction = expression.symbol.owner
|
val function: IrSimpleFunction = expression.symbol.owner
|
||||||
if (function.parent !is IrClass ||
|
if (function.parent !is IrClass ||
|
||||||
function.isStaticMethodOfClass ||
|
function.isStaticMethodOfClass ||
|
||||||
!function.parentAsClass.isInline ||
|
!isClassInlineLike(function.parentAsClass) ||
|
||||||
!function.isReal
|
!function.isReal
|
||||||
) {
|
) {
|
||||||
return expression
|
return expression
|
||||||
@@ -344,7 +346,7 @@ class InlineClassLowering(val context: CommonBackendContext) {
|
|||||||
val function = expression.symbol.owner
|
val function = expression.symbol.owner
|
||||||
val klass = function.parentAsClass
|
val klass = function.parentAsClass
|
||||||
return when {
|
return when {
|
||||||
!klass.isInline -> expression
|
!isClassInlineLike(klass) -> expression
|
||||||
else -> irCall(expression, getOrCreateStaticMethod(function))
|
else -> irCall(expression, getOrCreateStaticMethod(function))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -51,7 +51,7 @@ open class PropertyAccessorInlineLowering(
|
|||||||
// TODO: temporary workarounds
|
// TODO: temporary workarounds
|
||||||
if (parent.isExpect || property.isExpect) return false
|
if (parent.isExpect || property.isExpect) return false
|
||||||
if (parent.parent is IrExternalPackageFragment) return false
|
if (parent.parent is IrExternalPackageFragment) return false
|
||||||
if (parent.isInline) return false
|
if (context.inlineClassesUtils.isClassInlineLike(parent)) return false
|
||||||
}
|
}
|
||||||
if (property.isEffectivelyExternal()) return false
|
if (property.isEffectivelyExternal()) return false
|
||||||
return true
|
return true
|
||||||
|
|||||||
+1
-1
@@ -211,6 +211,6 @@ class ES6AddInternalParametersToConstructorPhase(val context: JsIrBackendContext
|
|||||||
|
|
||||||
private fun IrConstructor.hasStrictSignature(): Boolean {
|
private fun IrConstructor.hasStrictSignature(): Boolean {
|
||||||
val primitives = with(context.irBuiltIns) { primitiveTypesToPrimitiveArrays.values + stringClass }
|
val primitives = with(context.irBuiltIns) { primitiveTypesToPrimitiveArrays.values + stringClass }
|
||||||
return with(parentAsClass) { isExternal || isInline || symbol in primitives }
|
return with(parentAsClass) { isExternal || context.inlineClassesUtils.isClassInlineLike(this) || symbol in primitives }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -380,7 +380,7 @@ class ES6ConstructorLowering(val context: JsIrBackendContext) : BodyLoweringPass
|
|||||||
//util
|
//util
|
||||||
private fun IrConstructor.hasStrictSignature(): Boolean {
|
private fun IrConstructor.hasStrictSignature(): Boolean {
|
||||||
val primitives = with(context.irBuiltIns) { primitiveTypesToPrimitiveArrays.values + stringClass }
|
val primitives = with(context.irBuiltIns) { primitiveTypesToPrimitiveArrays.values + stringClass }
|
||||||
return with(parentAsClass) { isExternal || isInline || symbol in primitives }
|
return with(parentAsClass) { isExternal || context.inlineClassesUtils.isClassInlineLike(this) || symbol in primitives }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+4
-2
@@ -8,7 +8,6 @@ package org.jetbrains.kotlin.ir.backend.js.lower
|
|||||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||||
import org.jetbrains.kotlin.ir.backend.js.JsLoweredDeclarationOrigin
|
import org.jetbrains.kotlin.ir.backend.js.JsLoweredDeclarationOrigin
|
||||||
import org.jetbrains.kotlin.ir.backend.js.utils.eraseGenerics
|
import org.jetbrains.kotlin.ir.backend.js.utils.eraseGenerics
|
||||||
import org.jetbrains.kotlin.ir.backend.js.utils.getJsInlinedClass
|
|
||||||
import org.jetbrains.kotlin.ir.backend.js.utils.getJsNameOrKotlinName
|
import org.jetbrains.kotlin.ir.backend.js.utils.getJsNameOrKotlinName
|
||||||
import org.jetbrains.kotlin.ir.backend.js.utils.hasStableJsName
|
import org.jetbrains.kotlin.ir.backend.js.utils.hasStableJsName
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
|
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
|
||||||
@@ -19,6 +18,9 @@ import org.jetbrains.kotlin.ir.util.render
|
|||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
|
||||||
class JsBridgesConstruction(context: JsIrBackendContext) : BridgesConstruction<JsIrBackendContext>(context) {
|
class JsBridgesConstruction(context: JsIrBackendContext) : BridgesConstruction<JsIrBackendContext>(context) {
|
||||||
|
|
||||||
|
private fun IrType.getJsInlinedClass() = context.inlineClassesUtils.getInlinedClass(this)
|
||||||
|
|
||||||
override fun getFunctionSignature(function: IrSimpleFunction): JsSignature =
|
override fun getFunctionSignature(function: IrSimpleFunction): JsSignature =
|
||||||
if (function.hasStableJsName(context)) {
|
if (function.hasStableJsName(context)) {
|
||||||
JsStableNameSignature(function.getJsNameOrKotlinName())
|
JsStableNameSignature(function.getJsNameOrKotlinName())
|
||||||
@@ -59,4 +61,4 @@ data class JsNonStableSignature(
|
|||||||
|
|
||||||
data class JsStableNameSignature(
|
data class JsStableNameSignature(
|
||||||
override val name: Name,
|
override val name: Name,
|
||||||
) : JsSignature
|
) : JsSignature
|
||||||
|
|||||||
+2
-2
@@ -44,7 +44,7 @@ class SecondaryConstructorLowering(val context: JsIrBackendContext) : Declaratio
|
|||||||
if (declaration is IrConstructor && !declaration.isPrimary) {
|
if (declaration is IrConstructor && !declaration.isPrimary) {
|
||||||
val irClass = declaration.parentAsClass
|
val irClass = declaration.parentAsClass
|
||||||
|
|
||||||
if (irClass.isInline) return null
|
if (context.inlineClassesUtils.isClassInlineLike(irClass)) return null
|
||||||
|
|
||||||
return transformConstructor(declaration, irClass)
|
return transformConstructor(declaration, irClass)
|
||||||
}
|
}
|
||||||
@@ -255,7 +255,7 @@ private class CallsiteRedirectionTransformer(private val context: JsIrBackendCon
|
|||||||
|
|
||||||
private val IrConstructor.isSecondaryConstructorCall
|
private val IrConstructor.isSecondaryConstructorCall
|
||||||
get() =
|
get() =
|
||||||
!isPrimary && this != defaultThrowableConstructor && !isExternal && !parentAsClass.isInline
|
!isPrimary && this != defaultThrowableConstructor && !isExternal && !context.inlineClassesUtils.isClassInlineLike(parentAsClass)
|
||||||
|
|
||||||
override fun visitFunction(declaration: IrFunction, data: IrFunction?): IrStatement = super.visitFunction(declaration, declaration)
|
override fun visitFunction(declaration: IrFunction, data: IrFunction?): IrStatement = super.visitFunction(declaration, declaration)
|
||||||
|
|
||||||
|
|||||||
+7
-7
@@ -8,10 +8,7 @@ package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs
|
|||||||
import org.jetbrains.kotlin.backend.common.compilationException
|
import org.jetbrains.kotlin.backend.common.compilationException
|
||||||
import org.jetbrains.kotlin.backend.common.ir.isElseBranch
|
import org.jetbrains.kotlin.backend.common.ir.isElseBranch
|
||||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||||
import org.jetbrains.kotlin.ir.backend.js.utils.JsGenerationContext
|
import org.jetbrains.kotlin.ir.backend.js.utils.*
|
||||||
import org.jetbrains.kotlin.ir.backend.js.utils.Namer
|
|
||||||
import org.jetbrains.kotlin.ir.backend.js.utils.emptyScope
|
|
||||||
import org.jetbrains.kotlin.ir.backend.js.utils.getJsNameOrKotlinName
|
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.*
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
import org.jetbrains.kotlin.ir.types.isString
|
import org.jetbrains.kotlin.ir.types.isString
|
||||||
@@ -25,6 +22,9 @@ import org.jetbrains.kotlin.js.backend.ast.*
|
|||||||
@Suppress("PARAMETER_NAME_CHANGED_ON_OVERRIDE")
|
@Suppress("PARAMETER_NAME_CHANGED_ON_OVERRIDE")
|
||||||
class IrElementToJsExpressionTransformer : BaseIrElementToJsNodeTransformer<JsExpression, JsGenerationContext> {
|
class IrElementToJsExpressionTransformer : BaseIrElementToJsNodeTransformer<JsExpression, JsGenerationContext> {
|
||||||
|
|
||||||
|
private fun JsGenerationContext.isClassInlineLike(irClass: IrClass) =
|
||||||
|
staticContext.backendContext.inlineClassesUtils.isClassInlineLike(irClass)
|
||||||
|
|
||||||
override fun visitComposite(expression: IrComposite, data: JsGenerationContext): JsExpression {
|
override fun visitComposite(expression: IrComposite, data: JsGenerationContext): JsExpression {
|
||||||
val size = expression.statements.size
|
val size = expression.statements.size
|
||||||
if (size == 0) TODO("Empty IrComposite is not supported")
|
if (size == 0) TODO("Empty IrComposite is not supported")
|
||||||
@@ -114,7 +114,7 @@ class IrElementToJsExpressionTransformer : BaseIrElementToJsNodeTransformer<JsEx
|
|||||||
.also { context.staticContext.polyfills.visitDeclaration(field) }
|
.also { context.staticContext.polyfills.visitDeclaration(field) }
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fieldParent is IrClass && fieldParent.isInline) {
|
if (fieldParent is IrClass && context.isClassInlineLike(fieldParent)) {
|
||||||
return expression.receiver!!.accept(this, context).withSource(expression, context)
|
return expression.receiver!!.accept(this, context).withSource(expression, context)
|
||||||
}
|
}
|
||||||
val fieldName = context.getNameForField(field)
|
val fieldName = context.getNameForField(field)
|
||||||
@@ -163,7 +163,7 @@ class IrElementToJsExpressionTransformer : BaseIrElementToJsNodeTransformer<JsEx
|
|||||||
val arguments = translateCallArguments(expression, context, this)
|
val arguments = translateCallArguments(expression, context, this)
|
||||||
|
|
||||||
val constructor = expression.symbol.owner
|
val constructor = expression.symbol.owner
|
||||||
if (constructor.parentAsClass.isInline) {
|
if (context.isClassInlineLike(constructor.parentAsClass)) {
|
||||||
assert(constructor.isPrimary) {
|
assert(constructor.isPrimary) {
|
||||||
"Delegation to secondary inline constructors must be lowered into simple function calls"
|
"Delegation to secondary inline constructors must be lowered into simple function calls"
|
||||||
}
|
}
|
||||||
@@ -182,7 +182,7 @@ class IrElementToJsExpressionTransformer : BaseIrElementToJsNodeTransformer<JsEx
|
|||||||
val arguments = translateCallArguments(expression, context, this)
|
val arguments = translateCallArguments(expression, context, this)
|
||||||
val klass = function.parentAsClass
|
val klass = function.parentAsClass
|
||||||
|
|
||||||
require(!klass.isInline) {
|
require(!context.isClassInlineLike(klass)) {
|
||||||
"All inline class constructor calls must be lowered to static function calls"
|
"All inline class constructor calls must be lowered to static function calls"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -45,32 +45,6 @@ private fun IrClassifierSymbol.asString() = when (this) {
|
|||||||
else -> error("Unexpected kind of IrClassifierSymbol: " + javaClass.typeName)
|
else -> error("Unexpected kind of IrClassifierSymbol: " + javaClass.typeName)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns inline class for given class or null of type is not inlined
|
|
||||||
*/
|
|
||||||
fun IrType.getJsInlinedClass(): IrClass? {
|
|
||||||
if (this is IrSimpleType) {
|
|
||||||
val erased = erase(this) ?: return null
|
|
||||||
if (erased.isInline) {
|
|
||||||
if (this.isMarkedNullable()) {
|
|
||||||
var fieldType: IrType
|
|
||||||
var fieldInlinedClass = erased
|
|
||||||
while (true) {
|
|
||||||
fieldType = getInlineClassUnderlyingType(fieldInlinedClass)
|
|
||||||
if (fieldType.isMarkedNullable()) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
fieldInlinedClass = fieldType.getJsInlinedClass() ?: break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return erased
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
tailrec fun erase(type: IrType): IrClass? {
|
tailrec fun erase(type: IrType): IrClass? {
|
||||||
val classifier = type.classifierOrFail
|
val classifier = type.classifierOrFail
|
||||||
|
|
||||||
@@ -91,4 +65,4 @@ fun IrType.getClassRef(context: JsGenerationContext): JsNameRef =
|
|||||||
context.getNameForClass(klass).makeRef()
|
context.getNameForClass(klass).makeRef()
|
||||||
|
|
||||||
else -> context.getNameForStaticDeclaration(klass as IrDeclarationWithName).makeRef()
|
else -> context.getNameForStaticDeclaration(klass as IrDeclarationWithName).makeRef()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -131,7 +131,7 @@ fun jsFunctionSignature(declaration: IrFunction, context: JsIrBackendContext): S
|
|||||||
declaration.returnType.let {
|
declaration.returnType.let {
|
||||||
// Return type is only used in signature for inline class and Unit types because
|
// Return type is only used in signature for inline class and Unit types because
|
||||||
// they are binary incompatible with supertypes.
|
// they are binary incompatible with supertypes.
|
||||||
if (it.getJsInlinedClass() != null || it.isUnit()) {
|
if (context.inlineClassesUtils.isTypeInlined(it) || it.isUnit()) {
|
||||||
nameBuilder.append("_ret$${it.asString()}")
|
nameBuilder.append("_ret$${it.asString()}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user