[JS IR] Support init blocks in inline classes

This commit is contained in:
Svyatoslav Kuzmich
2020-12-20 19:02:07 +03:00
parent 07b6f0d871
commit 0945c110bf
6 changed files with 157 additions and 46 deletions
@@ -370,6 +370,13 @@ private val propertyAccessorInlinerLoweringPhase = makeBodyLoweringPhase(
description = "[Optimization] Inline property accessors"
)
private val copyPropertyAccessorBodiesLoweringPass = makeDeclarationTransformerPhase(
::CopyAccessorBodyLowerings,
name = "CopyAccessorBodyLowering",
description = "Copy accessor bodies so that ist can be safely read in PropertyAccessorInlineLowering",
prerequisite = setOf(propertyAccessorInlinerLoweringPhase)
)
private val foldConstantLoweringPhase = makeBodyLoweringPhase(
{ FoldConstantLowering(it, true) },
name = "FoldConstantLowering",
@@ -603,6 +610,12 @@ private val secondaryFactoryInjectorLoweringPhase = makeBodyLoweringPhase(
prerequisite = setOf(innerClassesLoweringPhase)
)
private val constLoweringPhase = makeBodyLoweringPhase(
::ConstLowering,
name = "ConstLowering",
description = "Wrap Long and Char constants into constructor invocation"
)
private val inlineClassDeclarationLoweringPhase = makeDeclarationTransformerPhase(
{ InlineClassLowering(it).inlineClassDeclarationLowering },
name = "InlineClassDeclarationLowering",
@@ -612,7 +625,12 @@ private val inlineClassDeclarationLoweringPhase = makeDeclarationTransformerPhas
private val inlineClassUsageLoweringPhase = makeBodyLoweringPhase(
{ InlineClassLowering(it).inlineClassUsageLowering },
name = "InlineClassUsageLowering",
description = "Handle inline class usages"
description = "Handle inline class usages",
prerequisite = setOf(
// Const lowering generates inline class constructors for unsigned integers
// which should be lowered by this lowering
constLoweringPhase
)
)
private val autoboxingTransformerPhase = makeBodyLoweringPhase(
@@ -640,12 +658,6 @@ private val primitiveCompanionLoweringPhase = makeBodyLoweringPhase(
description = "Replace common companion object access with platform one"
)
private val constLoweringPhase = makeBodyLoweringPhase(
::ConstLowering,
name = "ConstLowering",
description = "Wrap Long and Char constants into constructor invocation"
)
private val callsLoweringPhase = makeBodyLoweringPhase(
::CallsLowering,
name = "CallsLowering",
@@ -743,6 +755,7 @@ val loweringList = listOf<Lowering>(
propertyLazyInitLoweringPhase,
removeInitializersForLazyProperties,
propertyAccessorInlinerLoweringPhase,
copyPropertyAccessorBodiesLoweringPass,
foldConstantLoweringPhase,
privateMembersLoweringPhase,
privateMemberUsagesLoweringPhase,
@@ -763,11 +776,11 @@ val loweringList = listOf<Lowering>(
secondaryConstructorLoweringPhase,
secondaryFactoryInjectorLoweringPhase,
classReferenceLoweringPhase,
constLoweringPhase,
inlineClassDeclarationLoweringPhase,
inlineClassUsageLoweringPhase,
autoboxingTransformerPhase,
blockDecomposerLoweringPhase,
constLoweringPhase,
objectDeclarationLoweringPhase,
invokeStaticInitializersPhase,
objectUsageLoweringPhase,
@@ -0,0 +1,37 @@
/*
* 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.ir.backend.js.lower
import org.jetbrains.kotlin.backend.common.CommonBackendContext
import org.jetbrains.kotlin.backend.common.DeclarationTransformer
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
import org.jetbrains.kotlin.ir.declarations.IrField
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.ir.expressions.IrBlockBody
import org.jetbrains.kotlin.ir.util.deepCopyWithSymbols
// Copies property accessors and initializers so that the PropertyAccessorInilineLowering may access them safely.
class CopyAccessorBodyLowerings(private val context: CommonBackendContext) : DeclarationTransformer {
override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? {
if (declaration is IrSimpleFunction && declaration.correspondingPropertySymbol != null) {
declaration.body?.let { originalBody ->
declaration.body = context.irFactory.createBlockBody(originalBody.startOffset, originalBody.endOffset) {
statements += (originalBody.deepCopyWithSymbols(declaration) as IrBlockBody).statements
}
}
}
if (declaration is IrField) {
declaration.initializer?.let { originalBody ->
declaration.initializer = context.irFactory.createExpressionBody(originalBody.startOffset, originalBody.endOffset) {
this.expression = originalBody.expression.deepCopyWithSymbols(declaration)
}
}
}
return null
}
}
@@ -161,39 +161,36 @@ class IrElementToJsExpressionTransformer : BaseIrElementToJsNodeTransformer<JsEx
val function = expression.symbol.owner
val arguments = translateCallArguments(expression, context, this)
val klass = function.parentAsClass
return if (klass.isInline) {
assert(function.isPrimary) {
"Inline class secondary constructors must be lowered into static methods"
require(!klass.isInline) {
"All inline class constructor calls must be lowered to static function calls"
}
return when {
klass.isEffectivelyExternal() -> {
val refForExternalClass = context.getRefForExternalClass(klass)
val varargParameterIndex = expression.symbol.owner.varargParameterIndex()
if (varargParameterIndex == -1) {
JsNew(refForExternalClass, arguments)
} else {
val argumentsAsSingleArray = argumentsWithVarargAsSingleArray(
JsNullLiteral(),
arguments,
varargParameterIndex
)
JsNew(
JsInvocation(
JsNameRef("apply", JsNameRef("bind", JsNameRef("Function"))),
refForExternalClass,
argumentsAsSingleArray
),
emptyList()
)
}
}
// Argument value constructs unboxed inline class instance
arguments.single()
} else {
when {
klass.isEffectivelyExternal() -> {
val refForExternalClass = context.getRefForExternalClass(klass)
val varargParameterIndex = expression.symbol.owner.varargParameterIndex()
if (varargParameterIndex == -1) {
JsNew(refForExternalClass, arguments)
} else {
val argumentsAsSingleArray = argumentsWithVarargAsSingleArray(
JsNullLiteral(),
arguments,
varargParameterIndex
)
JsNew(
JsInvocation(
JsNameRef("apply", JsNameRef("bind", JsNameRef("Function"))),
refForExternalClass,
argumentsAsSingleArray
),
emptyList()
)
}
}
else -> {
val ref = context.getNameForClass(klass).makeRef()
JsNew(ref, arguments)
}
else -> {
val ref = context.getNameForClass(klass).makeRef()
JsNew(ref, arguments)
}
}
}