[JS IR BE] Remove conservative unit materialization

Remove UnitMaterializationLowering
Remove Unit insertion in BridgeConstruction
Fix codegen for when expressions without else branch
This commit is contained in:
Svyatoslav Kuzmich
2019-05-14 19:10:16 +03:00
parent c448def95f
commit e8933738ac
5 changed files with 17 additions and 73 deletions
@@ -1,45 +0,0 @@
/*
* Copyright 2010-2018 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.lower
import org.jetbrains.kotlin.backend.common.BackendContext
import org.jetbrains.kotlin.backend.common.FileLoweringPass
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.impl.IrCompositeImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrGetObjectValueImpl
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.types.classifierOrFail
import org.jetbrains.kotlin.ir.types.isUnit
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
class UnitMaterializationLowering(context: BackendContext) : FileLoweringPass {
private val unitType = context.irBuiltIns.unitType
private val unitValue
get() = IrGetObjectValueImpl(
UNDEFINED_OFFSET,
UNDEFINED_OFFSET,
unitType,
unitType.classifierOrFail as IrClassSymbol
)
override fun lower(irFile: IrFile) {
irFile.transformChildrenVoid(object : IrElementTransformerVoid() {
override fun visitCall(expression: IrCall): IrExpression {
expression.transformChildrenVoid(this)
return if (expression.type.isUnit()) expression.let {
IrCompositeImpl(it.startOffset, it.endOffset, it.type, it.origin, listOf(it, unitValue))
}
else expression
}
})
}
}
@@ -133,13 +133,6 @@ private val tailrecLoweringPhase = makeJsModulePhase(
description = "Replace `tailrec` callsites with equivalent loop"
)
private val unitMaterializationLoweringPhase = makeJsModulePhase(
::UnitMaterializationLowering,
name = "UnitMaterializationLowering",
description = "Insert Unit object where it is supposed to be",
prerequisite = setOf(tailrecLoweringPhase)
)
private val enumClassConstructorLoweringPhase = makeJsModulePhase(
::EnumClassConstructorLowering,
name = "EnumClassConstructorLowering",
@@ -201,8 +194,7 @@ private val innerClassConstructorCallsLoweringPhase = makeJsModulePhase(
private val suspendFunctionsLoweringPhase = makeJsModulePhase(
::JsSuspendFunctionsLowering,
name = "SuspendFunctionsLowering",
description = "Transform suspend functions into CoroutineImpl instance and build state machine",
prerequisite = setOf(unitMaterializationLoweringPhase)
description = "Transform suspend functions into CoroutineImpl instance and build state machine"
)
private val privateMembersLoweringPhase = makeJsModulePhase(
@@ -389,7 +381,6 @@ val jsPhases = namedIrModulePhase(
enumClassLoweringPhase then
enumUsageLoweringPhase then
returnableBlockLoweringPhase then
unitMaterializationLoweringPhase then
suspendFunctionsLoweringPhase then
privateMembersLoweringPhase then
callableReferenceLoweringPhase then
@@ -105,8 +105,6 @@ class BridgesConstruction(val context: JsIrBackendContext) : ClassLoweringPass {
}
}
private val unitValue = JsIrBuilder.buildGetObjectValue(context.irBuiltIns.unitType, context.irBuiltIns.unitClass)
// Ported from from jvm.lower.BridgeLowering
private fun createBridge(
function: IrSimpleFunction,
@@ -168,18 +166,7 @@ class BridgesConstruction(val context: JsIrBackendContext) : ClassLoweringPass {
call.putValueArgument(i, irCastIfNeeded(irGet(valueParameter), delegateTo.valueParameters[i].type))
}
// This is required for Unit materialization
// TODO: generalize for boxed types and inline classes
// TODO: use return type in signature too
val returnValue = if (delegateTo.returnType.isUnit() && !function.returnType.isUnit()) {
irComposite(resultType = irFunction.returnType) {
+call
+unitValue
}
} else {
call
}
+irReturn(returnValue)
+irReturn(call)
}.apply {
irFunction.body = this
}
@@ -5,12 +5,14 @@
package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs
import org.jetbrains.kotlin.backend.common.ir.isElseBranch
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.ir.backend.js.utils.*
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrConstructor
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.types.isUnit
import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.js.backend.ast.*
import org.jetbrains.kotlin.util.OperatorNameConventions
@@ -309,8 +311,16 @@ class IrElementToJsExpressionTransformer : BaseIrElementToJsNodeTransformer<JsEx
}
override fun visitWhen(expression: IrWhen, context: JsGenerationContext): JsExpression {
// TODO check when w/o else branch and empty when
return expression.toJsNode(this, context, ::JsConditional)!!
val lastBranch = expression.branches.lastOrNull()
val implicitElse =
if (lastBranch == null || !isElseBranch(lastBranch))
JsPrefixOperation(JsUnaryOperator.VOID, JsIntLiteral(0))
else
null
assert(implicitElse == null || expression.type.isUnit()) { "Non unit when-expression must have else branch" }
return expression.toJsNode(this, context, ::JsConditional, implicitElse)!!
}
override fun visitTypeOperator(expression: IrTypeOperatorCall, data: JsGenerationContext): JsExpression {
@@ -23,9 +23,10 @@ fun jsVar(name: JsName, initializer: IrExpression?, context: JsGenerationContext
fun <T : JsNode> IrWhen.toJsNode(
tr: BaseIrElementToJsNodeTransformer<T, JsGenerationContext>,
data: JsGenerationContext,
node: (JsExpression, T, T?) -> T
node: (JsExpression, T, T?) -> T,
implicitElse: T? = null
): T? =
branches.foldRight(null) { br, n ->
branches.foldRight(implicitElse) { br, n ->
val body = br.result.accept(tr, data)
if (isElseBranch(br)) body
else {