[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:
Sergej Jaskiewicz
2021-12-09 14:29:05 +03:00
committed by Space
parent e5993ab594
commit 4f13717fea
9 changed files with 24 additions and 46 deletions
@@ -28,11 +28,13 @@ private const val INLINE_CLASS_IMPL_SUFFIX = "-impl"
class InlineClassLowering(val context: CommonBackendContext) {
private val transformedFunction = context.mapping.inlineClassMemberToStatic
private fun isClassInlineLike(irClass: IrClass): Boolean = context.inlineClassesUtils.isClassInlineLike(irClass)
val inlineClassDeclarationLowering = object : DeclarationTransformer {
override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? {
val irClass = declaration.parent as? IrClass ?: return null
if (!irClass.isInline) return null
if (!isClassInlineLike(irClass)) return null
return when (declaration) {
is IrConstructor -> transformConstructor(declaration)
@@ -314,7 +316,7 @@ class InlineClassLowering(val context: CommonBackendContext) {
override fun visitConstructorCall(expression: IrConstructorCall): IrExpression {
expression.transformChildrenVoid(this)
val function = expression.symbol.owner
if (!function.parentAsClass.isInline) {
if (!isClassInlineLike(function.parentAsClass)) {
return expression
}
@@ -326,7 +328,7 @@ class InlineClassLowering(val context: CommonBackendContext) {
val function: IrSimpleFunction = expression.symbol.owner
if (function.parent !is IrClass ||
function.isStaticMethodOfClass ||
!function.parentAsClass.isInline ||
!isClassInlineLike(function.parentAsClass) ||
!function.isReal
) {
return expression
@@ -344,7 +346,7 @@ class InlineClassLowering(val context: CommonBackendContext) {
val function = expression.symbol.owner
val klass = function.parentAsClass
return when {
!klass.isInline -> expression
!isClassInlineLike(klass) -> expression
else -> irCall(expression, getOrCreateStaticMethod(function))
}
}
@@ -51,7 +51,7 @@ open class PropertyAccessorInlineLowering(
// TODO: temporary workarounds
if (parent.isExpect || property.isExpect) 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
return true
@@ -211,6 +211,6 @@ class ES6AddInternalParametersToConstructorPhase(val context: JsIrBackendContext
private fun IrConstructor.hasStrictSignature(): Boolean {
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 }
}
}
@@ -380,7 +380,7 @@ class ES6ConstructorLowering(val context: JsIrBackendContext) : BodyLoweringPass
//util
private fun IrConstructor.hasStrictSignature(): Boolean {
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 }
}
}
@@ -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.JsLoweredDeclarationOrigin
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.hasStableJsName
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
@@ -19,6 +18,9 @@ import org.jetbrains.kotlin.ir.util.render
import org.jetbrains.kotlin.name.Name
class JsBridgesConstruction(context: JsIrBackendContext) : BridgesConstruction<JsIrBackendContext>(context) {
private fun IrType.getJsInlinedClass() = context.inlineClassesUtils.getInlinedClass(this)
override fun getFunctionSignature(function: IrSimpleFunction): JsSignature =
if (function.hasStableJsName(context)) {
JsStableNameSignature(function.getJsNameOrKotlinName())
@@ -59,4 +61,4 @@ data class JsNonStableSignature(
data class JsStableNameSignature(
override val name: Name,
) : JsSignature
) : JsSignature
@@ -44,7 +44,7 @@ class SecondaryConstructorLowering(val context: JsIrBackendContext) : Declaratio
if (declaration is IrConstructor && !declaration.isPrimary) {
val irClass = declaration.parentAsClass
if (irClass.isInline) return null
if (context.inlineClassesUtils.isClassInlineLike(irClass)) return null
return transformConstructor(declaration, irClass)
}
@@ -255,7 +255,7 @@ private class CallsiteRedirectionTransformer(private val context: JsIrBackendCon
private val IrConstructor.isSecondaryConstructorCall
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)
@@ -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.ir.isElseBranch
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.ir.backend.js.utils.JsGenerationContext
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.backend.js.utils.*
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.types.isString
@@ -25,6 +22,9 @@ import org.jetbrains.kotlin.js.backend.ast.*
@Suppress("PARAMETER_NAME_CHANGED_ON_OVERRIDE")
class IrElementToJsExpressionTransformer : BaseIrElementToJsNodeTransformer<JsExpression, JsGenerationContext> {
private fun JsGenerationContext.isClassInlineLike(irClass: IrClass) =
staticContext.backendContext.inlineClassesUtils.isClassInlineLike(irClass)
override fun visitComposite(expression: IrComposite, data: JsGenerationContext): JsExpression {
val size = expression.statements.size
if (size == 0) TODO("Empty IrComposite is not supported")
@@ -114,7 +114,7 @@ class IrElementToJsExpressionTransformer : BaseIrElementToJsNodeTransformer<JsEx
.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)
}
val fieldName = context.getNameForField(field)
@@ -163,7 +163,7 @@ class IrElementToJsExpressionTransformer : BaseIrElementToJsNodeTransformer<JsEx
val arguments = translateCallArguments(expression, context, this)
val constructor = expression.symbol.owner
if (constructor.parentAsClass.isInline) {
if (context.isClassInlineLike(constructor.parentAsClass)) {
assert(constructor.isPrimary) {
"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 klass = function.parentAsClass
require(!klass.isInline) {
require(!context.isClassInlineLike(klass)) {
"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)
}
/**
* 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? {
val classifier = type.classifierOrFail
@@ -91,4 +65,4 @@ fun IrType.getClassRef(context: JsGenerationContext): JsNameRef =
context.getNameForClass(klass).makeRef()
else -> context.getNameForStaticDeclaration(klass as IrDeclarationWithName).makeRef()
}
}
@@ -131,7 +131,7 @@ fun jsFunctionSignature(declaration: IrFunction, context: JsIrBackendContext): S
declaration.returnType.let {
// Return type is only used in signature for inline class and Unit types because
// they are binary incompatible with supertypes.
if (it.getJsInlinedClass() != null || it.isUnit()) {
if (context.inlineClassesUtils.isTypeInlined(it) || it.isUnit()) {
nameBuilder.append("_ret$${it.asString()}")
}
}