[Wasm] Support callable references to external functions
1. Move jsInteropFunctionsLowering after callable reference lowering, so it can continue to deal with just functions and function calls. 2. Generate lowered closure class in JsInteropFunctionsLowering because
This commit is contained in:
+3
-3
@@ -504,9 +504,6 @@ val wasmPhases = NamedCompilerPhase(
|
|||||||
excludeDeclarationsFromCodegenPhase then
|
excludeDeclarationsFromCodegenPhase then
|
||||||
expectDeclarationsRemovingPhase then
|
expectDeclarationsRemovingPhase then
|
||||||
|
|
||||||
jsInteropFunctionsLowering then
|
|
||||||
jsInteropFunctionCallsLowering then
|
|
||||||
|
|
||||||
// TODO: Need some helpers from stdlib
|
// TODO: Need some helpers from stdlib
|
||||||
// arrayConstructorPhase then
|
// arrayConstructorPhase then
|
||||||
wrapInlineDeclarationsWithReifiedTypeParametersPhase then
|
wrapInlineDeclarationsWithReifiedTypeParametersPhase then
|
||||||
@@ -535,6 +532,9 @@ val wasmPhases = NamedCompilerPhase(
|
|||||||
delegateToPrimaryConstructorLoweringPhase then
|
delegateToPrimaryConstructorLoweringPhase then
|
||||||
// Common prefix ends
|
// Common prefix ends
|
||||||
|
|
||||||
|
jsInteropFunctionsLowering then
|
||||||
|
jsInteropFunctionCallsLowering then
|
||||||
|
|
||||||
enumEntryInstancesLoweringPhase then
|
enumEntryInstancesLoweringPhase then
|
||||||
enumEntryInstancesBodyLoweringPhase then
|
enumEntryInstancesBodyLoweringPhase then
|
||||||
enumClassCreateInitializerLoweringPhase then
|
enumClassCreateInitializerLoweringPhase then
|
||||||
|
|||||||
+53
-29
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.backend.wasm.lower
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.backend.common.BodyLoweringPass
|
import org.jetbrains.kotlin.backend.common.BodyLoweringPass
|
||||||
import org.jetbrains.kotlin.backend.common.DeclarationTransformer
|
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.ir.createStaticFunctionWithReceivers
|
||||||
import org.jetbrains.kotlin.backend.common.lower.DeclarationIrBuilder
|
import org.jetbrains.kotlin.backend.common.lower.DeclarationIrBuilder
|
||||||
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
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.isBuiltInWasmRefType
|
||||||
import org.jetbrains.kotlin.backend.wasm.ir2wasm.isExported
|
import org.jetbrains.kotlin.backend.wasm.ir2wasm.isExported
|
||||||
import org.jetbrains.kotlin.backend.wasm.ir2wasm.isExternalType
|
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.backend.js.utils.getJsNameOrKotlinName
|
||||||
import org.jetbrains.kotlin.ir.builders.*
|
import org.jetbrains.kotlin.ir.builders.*
|
||||||
import org.jetbrains.kotlin.ir.builders.declarations.addValueParameter
|
import org.jetbrains.kotlin.ir.builders.declarations.*
|
||||||
import org.jetbrains.kotlin.ir.builders.declarations.buildFun
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
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.expressions.*
|
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.types.*
|
||||||
import org.jetbrains.kotlin.ir.util.*
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||||
@@ -386,46 +383,73 @@ class JsInteropFunctionsLowering(val context: WasmBackendContext) : DeclarationT
|
|||||||
name = Name.identifier("f")
|
name = Name.identifier("f")
|
||||||
type = context.wasmSymbols.externalInterfaceType
|
type = context.wasmSymbols.externalInterfaceType
|
||||||
}
|
}
|
||||||
val builder = context.createIrBuilder(result.symbol)
|
|
||||||
val backendContext = context
|
val closureClass = context.irFactory.buildClass {
|
||||||
result.body = builder.irBlockBody {
|
name = Name.identifier("__JsClosureToKotlinClosure_${info.hashString}")
|
||||||
val lambda = context.irFactory.buildFun {
|
}.apply {
|
||||||
name = Name.identifier("kotlinClosure_${info.hashString}")
|
createImplicitParameterDeclarationWithWrappedDescriptor()
|
||||||
returnType = info.originalResultType
|
superTypes = listOf(functionType)
|
||||||
|
parent = currentParent
|
||||||
}
|
}
|
||||||
lambda.parent = result
|
|
||||||
val lambdaBuilder = backendContext.createIrBuilder(lambda.symbol)
|
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
|
||||||
|
}
|
||||||
|
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 ->
|
info.originalParameterTypes.forEachIndexed { index, irType ->
|
||||||
lambda.addValueParameter {
|
addValueParameter {
|
||||||
name = Name.identifier("p$index")
|
name = Name.identifier("p$index")
|
||||||
type = irType
|
type = irType
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
lambda.body = lambdaBuilder.irBlockBody {
|
val lambdaBuilder = context.createIrBuilder(symbol)
|
||||||
|
body = lambdaBuilder.irBlockBody {
|
||||||
val jsClosureCallerCall = irCall(jsClosureCaller)
|
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()) {
|
for ((adapterIndex, paramAdapter) in info.parametersAdapters.withIndex()) {
|
||||||
jsClosureCallerCall.putValueArgument(
|
jsClosureCallerCall.putValueArgument(
|
||||||
adapterIndex + 1,
|
adapterIndex + 1,
|
||||||
paramAdapter.adaptIfNeeded(
|
paramAdapter.adaptIfNeeded(
|
||||||
irGet(lambda.valueParameters[adapterIndex]),
|
irGet(valueParameters[adapterIndex]),
|
||||||
lambdaBuilder
|
lambdaBuilder
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
+irReturn(info.resultAdapter.adaptIfNeeded(jsClosureCallerCall, lambdaBuilder))
|
+irReturn(info.resultAdapter.adaptIfNeeded(jsClosureCallerCall, lambdaBuilder))
|
||||||
}
|
}
|
||||||
+irReturn(
|
|
||||||
IrFunctionExpressionImpl(
|
overriddenSymbols =
|
||||||
UNDEFINED_OFFSET,
|
overriddenSymbols + functionType.classOrNull!!.functions.single { it.owner.name == Name.identifier("invoke") }
|
||||||
UNDEFINED_OFFSET,
|
|
||||||
functionType,
|
|
||||||
lambda,
|
|
||||||
origin = KOTLIN_WASM_CLOSURE_FOR_JS_CLOSURE,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
additionalDeclarations += result
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|||||||
+19
-2
@@ -199,9 +199,25 @@ fun box(): String {
|
|||||||
)
|
)
|
||||||
if (externalWithLambdas2Count != 11) return "Fail externalWithLambdas2"
|
if (externalWithLambdas2Count != 11) return "Fail externalWithLambdas2"
|
||||||
|
|
||||||
|
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 (externalWithLambdas2RefCount != 11) return "Fail externalWithLambdas2"
|
||||||
|
|
||||||
val jsLambda = createJsLambda()
|
val createJsLambdaRef = ::createJsLambda
|
||||||
|
for (jsLambda in arrayOf(createJsLambda(), createJsLambdaRef.invoke())) {
|
||||||
val jsLambdaCount = jsLambda(
|
val jsLambdaCount = jsLambda(
|
||||||
true,
|
true,
|
||||||
100.toByte(),
|
100.toByte(),
|
||||||
@@ -218,6 +234,7 @@ fun box(): String {
|
|||||||
)
|
)
|
||||||
if (jsLambdaCount != 11)
|
if (jsLambdaCount != 11)
|
||||||
return "Fail 3"
|
return "Fail 3"
|
||||||
|
}
|
||||||
|
|
||||||
complexHigherOrerTest()
|
complexHigherOrerTest()
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user