diff --git a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/WasmLoweringPhases.kt b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/WasmLoweringPhases.kt index 6bac1868f58..321532cf7c7 100644 --- a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/WasmLoweringPhases.kt +++ b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/WasmLoweringPhases.kt @@ -504,9 +504,6 @@ val wasmPhases = NamedCompilerPhase( excludeDeclarationsFromCodegenPhase then expectDeclarationsRemovingPhase then - jsInteropFunctionsLowering then - jsInteropFunctionCallsLowering then - // TODO: Need some helpers from stdlib // arrayConstructorPhase then wrapInlineDeclarationsWithReifiedTypeParametersPhase then @@ -535,6 +532,9 @@ val wasmPhases = NamedCompilerPhase( delegateToPrimaryConstructorLoweringPhase then // Common prefix ends + jsInteropFunctionsLowering then + jsInteropFunctionCallsLowering then + enumEntryInstancesLoweringPhase then enumEntryInstancesBodyLoweringPhase then enumClassCreateInitializerLoweringPhase then diff --git a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/lower/JsInteropFunctionsLowering.kt b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/lower/JsInteropFunctionsLowering.kt index 8b537ed9550..c0a81cd5ffe 100644 --- a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/lower/JsInteropFunctionsLowering.kt +++ b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/lower/JsInteropFunctionsLowering.kt @@ -7,6 +7,7 @@ package org.jetbrains.kotlin.backend.wasm.lower import org.jetbrains.kotlin.backend.common.BodyLoweringPass import org.jetbrains.kotlin.backend.common.DeclarationTransformer +import org.jetbrains.kotlin.backend.common.ir.createImplicitParameterDeclarationWithWrappedDescriptor import org.jetbrains.kotlin.backend.common.ir.createStaticFunctionWithReceivers import org.jetbrains.kotlin.backend.common.lower.DeclarationIrBuilder import org.jetbrains.kotlin.backend.common.lower.createIrBuilder @@ -14,17 +15,13 @@ import org.jetbrains.kotlin.backend.wasm.WasmBackendContext import org.jetbrains.kotlin.backend.wasm.ir2wasm.isBuiltInWasmRefType import org.jetbrains.kotlin.backend.wasm.ir2wasm.isExported import org.jetbrains.kotlin.backend.wasm.ir2wasm.isExternalType -import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET +import org.jetbrains.kotlin.descriptors.DescriptorVisibilities import org.jetbrains.kotlin.ir.backend.js.utils.getJsNameOrKotlinName import org.jetbrains.kotlin.ir.builders.* -import org.jetbrains.kotlin.ir.builders.declarations.addValueParameter -import org.jetbrains.kotlin.ir.builders.declarations.buildFun -import org.jetbrains.kotlin.ir.declarations.IrClass -import org.jetbrains.kotlin.ir.declarations.IrDeclaration -import org.jetbrains.kotlin.ir.declarations.IrDeclarationParent -import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction +import org.jetbrains.kotlin.ir.builders.declarations.* +import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.expressions.* -import org.jetbrains.kotlin.ir.expressions.impl.IrFunctionExpressionImpl +import org.jetbrains.kotlin.ir.expressions.impl.IrInstanceInitializerCallImpl import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid @@ -386,46 +383,73 @@ class JsInteropFunctionsLowering(val context: WasmBackendContext) : DeclarationT name = Name.identifier("f") type = context.wasmSymbols.externalInterfaceType } - val builder = context.createIrBuilder(result.symbol) - val backendContext = context - result.body = builder.irBlockBody { - val lambda = context.irFactory.buildFun { - name = Name.identifier("kotlinClosure_${info.hashString}") - returnType = info.originalResultType + + val closureClass = context.irFactory.buildClass { + name = Name.identifier("__JsClosureToKotlinClosure_${info.hashString}") + }.apply { + createImplicitParameterDeclarationWithWrappedDescriptor() + superTypes = listOf(functionType) + parent = currentParent + } + + val closureClassField = closureClass.addField { + name = Name.identifier("jsClosure") + type = context.wasmSymbols.externalInterfaceType + visibility = DescriptorVisibilities.PRIVATE + isFinal = true + } + + val closureClassConstructor = closureClass.addConstructor { + isPrimary = true + }.apply { + val parameter = addValueParameter { + name = closureClassField.name + type = closureClassField.type } - lambda.parent = result - val lambdaBuilder = backendContext.createIrBuilder(lambda.symbol) + body = context.createIrBuilder(symbol).irBlockBody(startOffset, endOffset) { + +irDelegatingConstructorCall(context.irBuiltIns.anyClass.owner.constructors.single()) + +irSetField(irGet(closureClass.thisReceiver!!), closureClassField, irGet(parameter)) + +IrInstanceInitializerCallImpl(startOffset, endOffset, closureClass.symbol, context.irBuiltIns.unitType) + } + } + + closureClass.addFunction { + name = Name.identifier("invoke") + returnType = info.originalResultType + }.apply { + addDispatchReceiver { type = closureClass.defaultType } info.originalParameterTypes.forEachIndexed { index, irType -> - lambda.addValueParameter { + addValueParameter { name = Name.identifier("p$index") type = irType } } - lambda.body = lambdaBuilder.irBlockBody { + val lambdaBuilder = context.createIrBuilder(symbol) + body = lambdaBuilder.irBlockBody { val jsClosureCallerCall = irCall(jsClosureCaller) - jsClosureCallerCall.putValueArgument(0, irGet(result.valueParameters[0])) + jsClosureCallerCall.putValueArgument(0, irGetField(irGet(dispatchReceiverParameter!!), closureClassField)) for ((adapterIndex, paramAdapter) in info.parametersAdapters.withIndex()) { jsClosureCallerCall.putValueArgument( adapterIndex + 1, paramAdapter.adaptIfNeeded( - irGet(lambda.valueParameters[adapterIndex]), + irGet(valueParameters[adapterIndex]), lambdaBuilder ) ) } +irReturn(info.resultAdapter.adaptIfNeeded(jsClosureCallerCall, lambdaBuilder)) } - +irReturn( - IrFunctionExpressionImpl( - UNDEFINED_OFFSET, - UNDEFINED_OFFSET, - functionType, - lambda, - origin = KOTLIN_WASM_CLOSURE_FOR_JS_CLOSURE, - ) - ) + + overriddenSymbols = + overriddenSymbols + functionType.classOrNull!!.functions.single { it.owner.name == Name.identifier("invoke") } } + val builder = context.createIrBuilder(result.symbol) + result.body = builder.irBlockBody { + +irReturn(irCall(closureClassConstructor).also { it.putValueArgument(0, irGet(result.valueParameters[0])) }) + } + + additionalDeclarations += closureClass additionalDeclarations += result return result } diff --git a/compiler/testData/codegen/boxWasmJsInterop/functionTypes.kt b/compiler/testData/codegen/boxWasmJsInterop/functionTypes.kt index 9a9e9874e98..318497460be 100644 --- a/compiler/testData/codegen/boxWasmJsInterop/functionTypes.kt +++ b/compiler/testData/codegen/boxWasmJsInterop/functionTypes.kt @@ -199,25 +199,42 @@ fun box(): String { ) if (externalWithLambdas2Count != 11) return "Fail externalWithLambdas2" - - val jsLambda = createJsLambda() - - val jsLambdaCount = jsLambda( - true, - 100.toByte(), - 200.toShort(), - 'я', - 300, - 400L, - 500.5f, - 600.5, - "700", - create123Array(), - DC(800, 800), + val externalWithLambdas2Ref = ::externalWithLambdas2 + val externalWithLambdas2RefCount = externalWithLambdas2Ref.invoke( + { true }, + { 100.toByte() }, + { 200.toShort() }, + { 'я' }, + { 300 }, + { 400L }, + { 500.5f }, + { 600.5 }, + { "700" }, + { create123Array() }, + { DC(800, 800) }, { it.y } ) - if (jsLambdaCount != 11) - return "Fail 3" + if (externalWithLambdas2RefCount != 11) return "Fail externalWithLambdas2" + + val createJsLambdaRef = ::createJsLambda + for (jsLambda in arrayOf(createJsLambda(), createJsLambdaRef.invoke())) { + val jsLambdaCount = jsLambda( + true, + 100.toByte(), + 200.toShort(), + 'я', + 300, + 400L, + 500.5f, + 600.5, + "700", + create123Array(), + DC(800, 800), + { it.y } + ) + if (jsLambdaCount != 11) + return "Fail 3" + } complexHigherOrerTest()