[Wasm] Support exporting functions via @kotlin.js.JsExport

Previously we exported main function only.
Extend this feature to arbitrary number of annotated functions.
Type restrictions and conversions are similar to imported functions.
This commit is contained in:
Svyatoslav Kuzmich
2021-09-08 13:05:07 +03:00
parent de7fa8c778
commit 35a5c9ea71
2 changed files with 25 additions and 11 deletions
@@ -172,7 +172,21 @@ class BodyGenerator(val context: WasmFunctionCodegenContext) : IrElementVisitorV
}
override fun visitGetValue(expression: IrGetValue) {
body.buildGetLocal(context.referenceLocal(expression.symbol))
val valueSymbol = expression.symbol
body.buildGetLocal(context.referenceLocal(valueSymbol))
val valueDeclaration = valueSymbol.owner
if (valueSymbol.owner is IrValueParameter) {
val parent = valueDeclaration.parent
if (parent is IrFunction && parent.isExported(backendContext)) {
val type = context.transformType(valueDeclaration.type)
if (type is WasmRefNullType) {
// TODO: Add these casts as IR-2-IR lowering instead
generateTypeRTT(valueDeclaration.type)
body.buildRefCast()
}
}
}
}
override fun visitSetValue(expression: IrSetValue) {
@@ -296,7 +310,7 @@ class BodyGenerator(val context: WasmFunctionCodegenContext) : IrElementVisitorV
// Return types of imported functions cannot have concrete struct/array references.
// Non-primitive return types are represented as eqref which need to be casted back to expected type on call site.
if (function.getWasmImportAnnotation() != null || function.getJsFunAnnotation() != null || function.isExternal) {
if (function.getWasmImportAnnotation() != null || function.getJsFunAnnotation() != null || function.isExternal || function.isExported(backendContext)) {
val resT = context.transformResultType(function.returnType)
if (resT is WasmRefNullType) {
generateTypeRTT(function.returnType)
@@ -71,30 +71,30 @@ class DeclarationGenerator(val context: WasmModuleCodegenContext) : IrElementVis
val watName = declaration.fqNameWhenAvailable.toString()
val irParameters = declaration.getEffectiveValueParameters()
// TODO: Exported types should be transformed in a separate lowering by creating shim functions for each export.
val isExported = declaration.isExported(context.backendContext)
val resultType =
when {
declaration.isExported(context.backendContext) -> context.transformExportedResultType(declaration.returnType)
isExported -> context.transformExportedResultType(declaration.returnType)
// Unit_getInstance returns true Unit reference instead of "void"
declaration == unitGetInstanceFunction -> context.transformType(declaration.returnType)
else -> context.transformResultType(declaration.returnType)
}
val isExportedOrImported = isExported || importedName != null
val wasmFunctionType =
WasmFunctionType(
name = watName,
parameterTypes = irParameters.map {
val t = context.transformValueParameterType(it)
if (importedName != null && t is WasmRefNullType) {
WasmEqRef
if (isExportedOrImported && t is WasmRefNullType) {
WasmRefNullType(WasmHeapType.Simple.Data)
} else {
t
}
},
resultTypes = listOfNotNull(
run {
if (importedName != null && resultType is WasmRefNullType)
WasmEqRef
else
resultType
resultType.let {
if (isExportedOrImported && it is WasmRefNullType) WasmRefNullType(WasmHeapType.Simple.Data) else it
}
)
)
@@ -377,4 +377,4 @@ fun IrFunction.getEffectiveValueParameters(): List<IrValueParameter> {
}
fun IrFunction.isExported(context: WasmBackendContext): Boolean =
visibility == DescriptorVisibilities.PUBLIC && fqNameWhenAvailable in context.additionalExportedDeclarations
fqNameWhenAvailable in context.additionalExportedDeclarations || isJsExport()