[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" 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( private val enumClassConstructorLoweringPhase = makeJsModulePhase(
::EnumClassConstructorLowering, ::EnumClassConstructorLowering,
name = "EnumClassConstructorLowering", name = "EnumClassConstructorLowering",
@@ -201,8 +194,7 @@ private val innerClassConstructorCallsLoweringPhase = makeJsModulePhase(
private val suspendFunctionsLoweringPhase = makeJsModulePhase( private val suspendFunctionsLoweringPhase = makeJsModulePhase(
::JsSuspendFunctionsLowering, ::JsSuspendFunctionsLowering,
name = "SuspendFunctionsLowering", name = "SuspendFunctionsLowering",
description = "Transform suspend functions into CoroutineImpl instance and build state machine", description = "Transform suspend functions into CoroutineImpl instance and build state machine"
prerequisite = setOf(unitMaterializationLoweringPhase)
) )
private val privateMembersLoweringPhase = makeJsModulePhase( private val privateMembersLoweringPhase = makeJsModulePhase(
@@ -389,7 +381,6 @@ val jsPhases = namedIrModulePhase(
enumClassLoweringPhase then enumClassLoweringPhase then
enumUsageLoweringPhase then enumUsageLoweringPhase then
returnableBlockLoweringPhase then returnableBlockLoweringPhase then
unitMaterializationLoweringPhase then
suspendFunctionsLoweringPhase then suspendFunctionsLoweringPhase then
privateMembersLoweringPhase then privateMembersLoweringPhase then
callableReferenceLoweringPhase 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 // Ported from from jvm.lower.BridgeLowering
private fun createBridge( private fun createBridge(
function: IrSimpleFunction, function: IrSimpleFunction,
@@ -168,18 +166,7 @@ class BridgesConstruction(val context: JsIrBackendContext) : ClassLoweringPass {
call.putValueArgument(i, irCastIfNeeded(irGet(valueParameter), delegateTo.valueParameters[i].type)) call.putValueArgument(i, irCastIfNeeded(irGet(valueParameter), delegateTo.valueParameters[i].type))
} }
// This is required for Unit materialization +irReturn(call)
// 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)
}.apply { }.apply {
irFunction.body = this irFunction.body = this
} }
@@ -5,12 +5,14 @@
package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs 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.descriptors.ClassKind
import org.jetbrains.kotlin.ir.backend.js.utils.* import org.jetbrains.kotlin.ir.backend.js.utils.*
import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrConstructor import org.jetbrains.kotlin.ir.declarations.IrConstructor
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.types.isUnit
import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.js.backend.ast.* import org.jetbrains.kotlin.js.backend.ast.*
import org.jetbrains.kotlin.util.OperatorNameConventions import org.jetbrains.kotlin.util.OperatorNameConventions
@@ -309,8 +311,16 @@ class IrElementToJsExpressionTransformer : BaseIrElementToJsNodeTransformer<JsEx
} }
override fun visitWhen(expression: IrWhen, context: JsGenerationContext): JsExpression { override fun visitWhen(expression: IrWhen, context: JsGenerationContext): JsExpression {
// TODO check when w/o else branch and empty when val lastBranch = expression.branches.lastOrNull()
return expression.toJsNode(this, context, ::JsConditional)!! 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 { 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( fun <T : JsNode> IrWhen.toJsNode(
tr: BaseIrElementToJsNodeTransformer<T, JsGenerationContext>, tr: BaseIrElementToJsNodeTransformer<T, JsGenerationContext>,
data: JsGenerationContext, data: JsGenerationContext,
node: (JsExpression, T, T?) -> T node: (JsExpression, T, T?) -> T,
implicitElse: T? = null
): T? = ): T? =
branches.foldRight(null) { br, n -> branches.foldRight(implicitElse) { br, n ->
val body = br.result.accept(tr, data) val body = br.result.accept(tr, data)
if (isElseBranch(br)) body if (isElseBranch(br)) body
else { else {