[Wasm] Make Arrays' constructors with size and lambda inline

Fixed #KT-58746
This commit is contained in:
Igor Yakovlev
2023-05-18 19:19:12 +02:00
committed by Space Team
parent 1d5c080dd8
commit 78b72efd32
7 changed files with 218 additions and 50 deletions
@@ -18,6 +18,8 @@ import org.jetbrains.kotlin.backend.common.lower.optimizations.PropertyAccessorI
import org.jetbrains.kotlin.backend.common.phaser.*
import org.jetbrains.kotlin.backend.common.toMultiModuleAction
import org.jetbrains.kotlin.backend.wasm.lower.*
import org.jetbrains.kotlin.backend.wasm.lower.WasmArrayConstructorLowering
import org.jetbrains.kotlin.backend.wasm.lower.WasmArrayConstructorReferenceLowering
import org.jetbrains.kotlin.ir.backend.js.lower.*
import org.jetbrains.kotlin.ir.backend.js.lower.coroutines.AddContinuationToFunctionCallsLowering
import org.jetbrains.kotlin.ir.backend.js.lower.coroutines.JsSuspendFunctionsLowering
@@ -113,6 +115,19 @@ private val lateinitUsageLoweringPhase = makeWasmModulePhase(
description = "Insert checks for lateinit field references"
)
private val arrayConstructorReferencePhase = makeWasmModulePhase(
::WasmArrayConstructorReferenceLowering,
name = "ArrayConstructorReference",
description = "Transform `::Array` into a lambda"
)
private val arrayConstructorPhase = makeWasmModulePhase(
::WasmArrayConstructorLowering,
name = "ArrayConstructor",
description = "Transform `Array(size) { index -> value }` into a loop",
prerequisite = setOf(arrayConstructorReferencePhase)
)
private val sharedVariablesLoweringPhase = makeWasmModulePhase(
::SharedVariablesLowering,
name = "SharedVariablesLowering",
@@ -607,6 +622,8 @@ val wasmPhases = SameTypeNamedCompilerPhase(
lateinitNullableFieldsPhase then
lateinitDeclarationLoweringPhase then
lateinitUsageLoweringPhase then
arrayConstructorReferencePhase then
arrayConstructorPhase then
sharedVariablesLoweringPhase then
localClassesInInlineLambdasPhase then
localClassesInInlineFunctionsPhase then
@@ -194,6 +194,18 @@ class WasmSymbols(
val wasmArrayCopy = getInternalFunction("wasm_array_copy")
val wasmArrayNewData0 = getInternalFunction("array_new_data0")
val primitiveTypeToCreateTypedArray = mapOf(
context.irBuiltIns.arrayClass to getFunction("createAnyArray", kotlinTopLevelPackage),
context.irBuiltIns.booleanArray to getFunction("createBooleanArray", kotlinTopLevelPackage),
context.irBuiltIns.byteArray to getFunction("createByteArray", kotlinTopLevelPackage),
context.irBuiltIns.shortArray to getFunction("createShortArray", kotlinTopLevelPackage),
context.irBuiltIns.charArray to getFunction("createCharArray", kotlinTopLevelPackage),
context.irBuiltIns.intArray to getFunction("createIntArray", kotlinTopLevelPackage),
context.irBuiltIns.longArray to getFunction("createLongArray", kotlinTopLevelPackage),
context.irBuiltIns.floatArray to getFunction("createFloatArray", kotlinTopLevelPackage),
context.irBuiltIns.doubleArray to getFunction("createDoubleArray", kotlinTopLevelPackage),
)
val intToLong = getInternalFunction("wasm_i64_extend_i32_s")
val rangeCheck = getInternalFunction("rangeCheck")
@@ -141,6 +141,12 @@ internal class WasmUsefulDeclarationProcessor(
irClass.getWasmArrayAnnotation()?.type
?.enqueueType(irClass, "array type for wasm array annotated")
if (irClass.symbol in context.wasmSymbols.primitiveTypeToCreateTypedArray.keys) {
irClass.declarations.forEach {
(it as? IrField)?.enqueue(irClass, "preserve all fields for primitive arrays")
}
}
if (context.inlineClassesUtils.isClassInlineLike(irClass)) {
irClass.declarations
.firstIsInstanceOrNull<IrConstructor>()
@@ -166,7 +172,11 @@ internal class WasmUsefulDeclarationProcessor(
irFunction.getEffectiveValueParameters().forEach { it.enqueueValueParameterType(irFunction) }
irFunction.returnType.enqueueType(irFunction, "function return type")
kotlinClosureToJsClosureConvertFunToKotlinClosureCallFun[irFunction]?.enqueue(irFunction, "kotlin closure to JS closure conversion", false)
kotlinClosureToJsClosureConvertFunToKotlinClosureCallFun[irFunction]?.enqueue(
irFunction,
"kotlin closure to JS closure conversion",
false
)
}
override fun processSimpleFunction(irFunction: IrSimpleFunction) {
@@ -0,0 +1,92 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. 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.wasm.lower
import org.jetbrains.kotlin.backend.common.BodyLoweringPass
import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.backend.wasm.WasmBackendContext
import org.jetbrains.kotlin.ir.builders.irBlock
import org.jetbrains.kotlin.ir.builders.irCall
import org.jetbrains.kotlin.ir.declarations.IrConstructor
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
import org.jetbrains.kotlin.ir.declarations.IrSymbolOwner
import org.jetbrains.kotlin.ir.expressions.IrBody
import org.jetbrains.kotlin.ir.expressions.IrConstructorCall
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrFunctionReference
import org.jetbrains.kotlin.ir.expressions.impl.IrFunctionReferenceImpl
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.ir.util.constructedClass
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
class WasmArrayConstructorLowering(val context: WasmBackendContext) : BodyLoweringPass {
override fun lower(irBody: IrBody, container: IrDeclaration) {
irBody.transformChildrenVoid(ArrayConstructorTransformer(context, container as IrSymbolOwner))
}
}
private class ArrayConstructorTransformer(
val context: WasmBackendContext,
val container: IrSymbolOwner
) : IrElementTransformerVoidWithContext() {
// Array(size, init) -> create###Array(size, init)
companion object {
internal fun arrayInlineToSizeCreator(context: WasmBackendContext, irConstructor: IrConstructor): IrFunctionSymbol? =
when (irConstructor.valueParameters.size) {
2 -> context.wasmSymbols.primitiveTypeToCreateTypedArray[irConstructor.constructedClass.symbol]
else -> null
}
}
override fun visitConstructorCall(expression: IrConstructorCall): IrExpression {
val creator = arrayInlineToSizeCreator(context, expression.symbol.owner)
?: return super.visitConstructorCall(expression)
expression.transformChildrenVoid()
val scope = (currentScope ?: createScope(container)).scope
return context.createIrBuilder(scope.scopeOwnerSymbol).irBlock(expression.startOffset, expression.endOffset) {
+irCall(creator, expression.type).also { call ->
repeat(expression.typeArgumentsCount) { call.putTypeArgument(it, expression.getTypeArgument(it)) }
repeat(expression.valueArgumentsCount) { call.putValueArgument(it, expression.getValueArgument(it)) }
}
}
}
}
class WasmArrayConstructorReferenceLowering(val context: WasmBackendContext) : BodyLoweringPass {
override fun lower(irBody: IrBody, container: IrDeclaration) {
irBody.transformChildrenVoid(ArrayConstructorReferenceTransformer(context))
}
private class ArrayConstructorReferenceTransformer(val context: WasmBackendContext) : IrElementTransformerVoid() {
override fun visitFunctionReference(expression: IrFunctionReference): IrExpression {
expression.transformChildrenVoid()
val target = expression.symbol.owner
if (target !is IrConstructor) return expression
val creator = ArrayConstructorTransformer.arrayInlineToSizeCreator(context, target)
?: return super.visitFunctionReference(expression)
return IrFunctionReferenceImpl(
startOffset = expression.startOffset,
endOffset = expression.endOffset,
type = expression.type,
symbol = creator,
typeArgumentsCount = expression.typeArgumentsCount,
valueArgumentsCount = expression.valueArgumentsCount,
reflectionTarget = creator,
origin = expression.origin
).also { reference ->
repeat(expression.typeArgumentsCount) { reference.putTypeArgument(it, expression.getTypeArgument(it)) }
repeat(expression.valueArgumentsCount) { reference.putValueArgument(it, expression.getValueArgument(it)) }
}
}
}
}
@@ -1,5 +1,3 @@
// IGNORE_BACKEND: WASM
// WASM_MUTE_REASON: INLINE_ARRAY_CONSTRUCTOR
typealias ArrayS = Array<String>
fun testArray() {