[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
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
body = context.createIrBuilder(symbol).irBlockBody(startOffset, endOffset) {
|
||||||
val lambdaBuilder = backendContext.createIrBuilder(lambda.symbol)
|
+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
|
||||||
}
|
}
|
||||||
|
|||||||
+34
-17
@@ -199,25 +199,42 @@ fun box(): String {
|
|||||||
)
|
)
|
||||||
if (externalWithLambdas2Count != 11) return "Fail externalWithLambdas2"
|
if (externalWithLambdas2Count != 11) return "Fail externalWithLambdas2"
|
||||||
|
|
||||||
|
val externalWithLambdas2Ref = ::externalWithLambdas2
|
||||||
val jsLambda = createJsLambda()
|
val externalWithLambdas2RefCount = externalWithLambdas2Ref.invoke(
|
||||||
|
{ true },
|
||||||
val jsLambdaCount = jsLambda(
|
{ 100.toByte() },
|
||||||
true,
|
{ 200.toShort() },
|
||||||
100.toByte(),
|
{ 'я' },
|
||||||
200.toShort(),
|
{ 300 },
|
||||||
'я',
|
{ 400L },
|
||||||
300,
|
{ 500.5f },
|
||||||
400L,
|
{ 600.5 },
|
||||||
500.5f,
|
{ "700" },
|
||||||
600.5,
|
{ create123Array() },
|
||||||
"700",
|
{ DC(800, 800) },
|
||||||
create123Array(),
|
|
||||||
DC(800, 800),
|
|
||||||
{ it.y }
|
{ it.y }
|
||||||
)
|
)
|
||||||
if (jsLambdaCount != 11)
|
if (externalWithLambdas2RefCount != 11) return "Fail externalWithLambdas2"
|
||||||
return "Fail 3"
|
|
||||||
|
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()
|
complexHigherOrerTest()
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user