[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
|
||||
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
|
||||
|
||||
+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.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
|
||||
}
|
||||
|
||||
+34
-17
@@ -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()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user