[Wasm] Backend support for wasi mode

This commit is contained in:
Igor Yakovlev
2023-07-31 15:43:48 +02:00
committed by Space Team
parent 22a3000789
commit 5e14ccbccc
8 changed files with 107 additions and 51 deletions
@@ -23,6 +23,8 @@ import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.SymbolTable import org.jetbrains.kotlin.ir.util.SymbolTable
import org.jetbrains.kotlin.ir.util.constructors import org.jetbrains.kotlin.ir.util.constructors
import org.jetbrains.kotlin.ir.util.render import org.jetbrains.kotlin.ir.util.render
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
import org.jetbrains.kotlin.js.config.WasmTarget
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.scopes.MemberScope import org.jetbrains.kotlin.resolve.scopes.MemberScope
@@ -78,8 +80,6 @@ class WasmSymbols(
internal val initAssociatedObjects = getInternalFunction("initAssociatedObjects") internal val initAssociatedObjects = getInternalFunction("initAssociatedObjects")
internal val addAssociatedObject = getInternalFunction("addAssociatedObject") internal val addAssociatedObject = getInternalFunction("addAssociatedObject")
internal val throwAsJsException: IrSimpleFunctionSymbol = getInternalFunction("throwAsJsException")
override val throwNullPointerException = getInternalFunction("THROW_NPE") override val throwNullPointerException = getInternalFunction("THROW_NPE")
override val throwISE = getInternalFunction("THROW_ISE") override val throwISE = getInternalFunction("THROW_ISE")
override val throwTypeCastException = getInternalFunction("THROW_CCE") override val throwTypeCastException = getInternalFunction("THROW_CCE")
@@ -189,7 +189,6 @@ class WasmSymbols(
val booleanAnd = getInternalFunction("wasm_i32_and") val booleanAnd = getInternalFunction("wasm_i32_and")
val refEq = getInternalFunction("wasm_ref_eq") val refEq = getInternalFunction("wasm_ref_eq")
val refIsNull = getInternalFunction("wasm_ref_is_null") val refIsNull = getInternalFunction("wasm_ref_is_null")
val externRefIsNull = getInternalFunction("wasm_externref_is_null")
val refTest = getInternalFunction("wasm_ref_test") val refTest = getInternalFunction("wasm_ref_test")
val refCastNull = getInternalFunction("wasm_ref_cast_null") val refCastNull = getInternalFunction("wasm_ref_cast_null")
val wasmArrayCopy = getInternalFunction("wasm_array_copy") val wasmArrayCopy = getInternalFunction("wasm_array_copy")
@@ -237,9 +236,6 @@ class WasmSymbols(
val unsafeGetScratchRawMemory = getInternalFunction("unsafeGetScratchRawMemory") val unsafeGetScratchRawMemory = getInternalFunction("unsafeGetScratchRawMemory")
val returnArgumentIfItIsKotlinAny = getInternalFunction("returnArgumentIfItIsKotlinAny") val returnArgumentIfItIsKotlinAny = getInternalFunction("returnArgumentIfItIsKotlinAny")
val newJsArray = getInternalFunction("newJsArray")
val jsArrayPush = getInternalFunction("jsArrayPush")
val startCoroutineUninterceptedOrReturnIntrinsics = val startCoroutineUninterceptedOrReturnIntrinsics =
(0..2).map { getInternalFunction("startCoroutineUninterceptedOrReturnIntrinsic$it") } (0..2).map { getInternalFunction("startCoroutineUninterceptedOrReturnIntrinsic$it") }
@@ -309,9 +305,6 @@ class WasmSymbols(
val wasmAnyRefClass = getIrClass(FqName("kotlin.wasm.internal.reftypes.anyref")) val wasmAnyRefClass = getIrClass(FqName("kotlin.wasm.internal.reftypes.anyref"))
private val jsAnyClass = getIrClass(FqName("kotlin.js.JsAny"))
val jsAnyType by lazy { jsAnyClass.defaultType }
inner class JsInteropAdapters { inner class JsInteropAdapters {
val kotlinToJsStringAdapter = getInternalFunction("kotlinToJsStringAdapter") val kotlinToJsStringAdapter = getInternalFunction("kotlinToJsStringAdapter")
val kotlinToJsAnyAdapter = getInternalFunction("kotlinToJsAnyAdapter") val kotlinToJsAnyAdapter = getInternalFunction("kotlinToJsAnyAdapter")
@@ -342,18 +335,42 @@ class WasmSymbols(
val kotlinCharToExternRefAdapter = getInternalFunction("kotlinCharToExternRefAdapter") val kotlinCharToExternRefAdapter = getInternalFunction("kotlinCharToExternRefAdapter")
} }
val jsInteropAdapters = JsInteropAdapters() inner class JsRelatedSymbols {
val jsInteropAdapters = JsInteropAdapters()
private val jsExportClass = getIrClass(FqName("kotlin.js.JsExport")) private val jsExportClass = getIrClass(FqName("kotlin.js.JsExport"))
val jsExportConstructor by lazy { jsExportClass.constructors.single() } val jsExportConstructor by lazy { jsExportClass.constructors.single() }
private val jsNameClass = getIrClass(FqName("kotlin.js.JsName")) private val jsNameClass = getIrClass(FqName("kotlin.js.JsName"))
val jsNameConstructor by lazy { jsNameClass.constructors.single() } val jsNameConstructor by lazy { jsNameClass.constructors.single() }
private val jsFunClass = getIrClass(FqName("kotlin.JsFun")) private val jsFunClass = getIrClass(FqName("kotlin.JsFun"))
val jsFunConstructor by lazy { jsFunClass.constructors.single() } val jsFunConstructor by lazy { jsFunClass.constructors.single() }
val jsCode = getFunction("js", kotlinJsPackage) val jsCode = getFunction("js", kotlinJsPackage)
val jsAnyType: IrType by lazy { getIrClass(FqName("kotlin.js.JsAny")).defaultType }
val newJsArray = getInternalFunction("newJsArray")
val jsArrayPush = getInternalFunction("jsArrayPush")
val externRefIsNull = getInternalFunction("wasm_externref_is_null")
internal val throwAsJsException: IrSimpleFunctionSymbol =
getInternalFunction("throwAsJsException")
}
private val wasmExportClass = getIrClass(FqName("kotlin.wasm.WasmExport"))
val wasmExportConstructor by lazy { wasmExportClass.constructors.single() }
private val jsRelatedSymbolsIfNonWasi =
when (context.configuration.get(JSConfigurationKeys.WASM_TARGET, WasmTarget.JS) == WasmTarget.JS) {
true -> JsRelatedSymbols()
else -> null
}
val jsRelatedSymbols get() = jsRelatedSymbolsIfNonWasi ?: error("Cannot access to js related std in wasi mode")
private fun findClass(memberScope: MemberScope, name: Name): ClassDescriptor = private fun findClass(memberScope: MemberScope, name: Name): ClassDescriptor =
memberScope.getContributedClassifier(name, NoLookupLocation.FROM_BACKEND) as ClassDescriptor memberScope.getContributedClassifier(name, NoLookupLocation.FROM_BACKEND) as ClassDescriptor
@@ -381,7 +398,7 @@ class WasmSymbols(
return symbolTable.descriptorExtension.referenceSimpleFunction(tmp.single()) return symbolTable.descriptorExtension.referenceSimpleFunction(tmp.single())
} }
private fun getInternalFunction(name: String) = getFunction(name, wasmInternalPackage) private fun getInternalFunction(name: String): IrSimpleFunctionSymbol = getFunction(name, wasmInternalPackage)
private fun getEnumsFunction(name: String) = getFunction(name, enumsInternalPackage) private fun getEnumsFunction(name: String) = getFunction(name, enumsInternalPackage)
@@ -25,6 +25,8 @@ import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
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.transformChildrenVoid import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
import org.jetbrains.kotlin.js.config.WasmTarget
import org.jetbrains.kotlin.name.parentOrNull import org.jetbrains.kotlin.name.parentOrNull
class BuiltInsLowering(val context: WasmBackendContext) : FileLoweringPass { class BuiltInsLowering(val context: WasmBackendContext) : FileLoweringPass {
@@ -56,7 +58,13 @@ class BuiltInsLowering(val context: WasmBackendContext) : FileLoweringPass {
irBuiltins.eqeqSymbol, irBuiltins.eqeqSymbol,
irBuiltins.eqeqeqSymbol -> { irBuiltins.eqeqeqSymbol -> {
fun callRefIsNull(expr: IrExpression): IrCall { fun callRefIsNull(expr: IrExpression): IrCall {
val refIsNull = if (expr.type.erasedUpperBound?.isExternal == true) symbols.externRefIsNull else symbols.refIsNull if (
context.configuration.get(JSConfigurationKeys.WASM_TARGET, WasmTarget.JS) == WasmTarget.WASI &&
expr.type.erasedUpperBound?.isExternal == true
) {
error("Unexpected external refs in wasi mode")
}
val refIsNull = if (expr.type.erasedUpperBound?.isExternal == true) symbols.jsRelatedSymbols.externRefIsNull else symbols.refIsNull
return builder.irCall(refIsNull).apply { putValueArgument(0, expr) } return builder.irCall(refIsNull).apply { putValueArgument(0, expr) }
} }
@@ -418,7 +418,7 @@ fun createExternalJsFunction(
isExternal = true isExternal = true
} }
val builder = context.createIrBuilder(res.symbol) val builder = context.createIrBuilder(res.symbol)
res.annotations += builder.irCallConstructor(context.wasmSymbols.jsFunConstructor, typeArguments = emptyList()).also { res.annotations += builder.irCallConstructor(context.wasmSymbols.jsRelatedSymbols.jsFunConstructor, typeArguments = emptyList()).also {
it.putValueArgument(0, builder.irString(jsCode)) it.putValueArgument(0, builder.irString(jsCode))
} }
return res return res
@@ -13,12 +13,17 @@ import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.types.defaultType import org.jetbrains.kotlin.ir.types.defaultType
import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
import org.jetbrains.kotlin.js.config.WasmTarget
/** /**
* Lower calls to `js(code)` into `@JsFun(code) external` functions. * Lower calls to `js(code)` into `@JsFun(code) external` functions.
*/ */
class JsCodeCallsLowering(val context: WasmBackendContext) : FileLoweringPass { class JsCodeCallsLowering(val context: WasmBackendContext) : FileLoweringPass {
private val jsRelatedSymbols get() = context.wasmSymbols.jsRelatedSymbols
override fun lower(irFile: IrFile) { override fun lower(irFile: IrFile) {
if (context.configuration.get(JSConfigurationKeys.WASM_TARGET, WasmTarget.JS) == WasmTarget.WASI) return
irFile.transformDeclarationsFlat { declaration -> irFile.transformDeclarationsFlat { declaration ->
when (declaration) { when (declaration) {
is IrSimpleFunction -> transformFunction(declaration) is IrSimpleFunction -> transformFunction(declaration)
@@ -81,7 +86,7 @@ class JsCodeCallsLowering(val context: WasmBackendContext) : FileLoweringPass {
} }
val builder = context.createIrBuilder(function.symbol) val builder = context.createIrBuilder(function.symbol)
function.annotations += builder.irCallConstructor(context.wasmSymbols.jsFunConstructor, typeArguments = emptyList()).also { function.annotations += builder.irCallConstructor(jsRelatedSymbols.jsFunConstructor, typeArguments = emptyList()).also {
it.putValueArgument(0, builder.irString(jsFunCode)) it.putValueArgument(0, builder.irString(jsFunCode))
} }
function.body = null function.body = null
@@ -106,7 +111,7 @@ class JsCodeCallsLowering(val context: WasmBackendContext) : FileLoweringPass {
private fun IrExpression.getJsCode(): String? { private fun IrExpression.getJsCode(): String? {
val call = this as? IrCall ?: return null val call = this as? IrCall ?: return null
if (call.symbol != context.wasmSymbols.jsCode) return null if (call.symbol != jsRelatedSymbols.jsCode) return null
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
return (call.getValueArgument(0) as IrConst<String>).value return (call.getValueArgument(0) as IrConst<String>).value
} }
@@ -31,6 +31,8 @@ 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
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
import org.jetbrains.kotlin.js.config.WasmTarget
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.util.OperatorNameConventions import org.jetbrains.kotlin.util.OperatorNameConventions
@@ -41,12 +43,15 @@ import org.jetbrains.kotlin.util.OperatorNameConventions
class JsInteropFunctionsLowering(val context: WasmBackendContext) : DeclarationTransformer { class JsInteropFunctionsLowering(val context: WasmBackendContext) : DeclarationTransformer {
val builtIns = context.irBuiltIns val builtIns = context.irBuiltIns
val symbols = context.wasmSymbols val symbols = context.wasmSymbols
val adapters = symbols.jsInteropAdapters val jsRelatedSymbols get() = context.wasmSymbols.jsRelatedSymbols
val adapters get() = jsRelatedSymbols.jsInteropAdapters
val additionalDeclarations = mutableListOf<IrDeclaration>() val additionalDeclarations = mutableListOf<IrDeclaration>()
lateinit var currentParent: IrDeclarationParent lateinit var currentParent: IrDeclarationParent
override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? { override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? {
if (context.configuration.get(JSConfigurationKeys.WASM_TARGET, WasmTarget.JS) == WasmTarget.WASI) return null
if (declaration.isFakeOverride) return null if (declaration.isFakeOverride) return null
if (declaration !is IrSimpleFunction) return null if (declaration !is IrSimpleFunction) return null
val isExported = declaration.isJsExport() val isExported = declaration.isJsExport()
@@ -176,10 +181,10 @@ class JsInteropFunctionsLowering(val context: WasmBackendContext) : DeclarationT
val builder: DeclarationIrBuilder = context.createIrBuilder(newFun.symbol) val builder: DeclarationIrBuilder = context.createIrBuilder(newFun.symbol)
newFun.body = createAdapterFunctionBody(builder, newFun, function, valueParametersAdapters, resultAdapter) newFun.body = createAdapterFunctionBody(builder, newFun, function, valueParametersAdapters, resultAdapter)
newFun.annotations += builder.irCallConstructor(context.wasmSymbols.jsNameConstructor, typeArguments = emptyList()).also { newFun.annotations += builder.irCallConstructor(jsRelatedSymbols.jsNameConstructor, typeArguments = emptyList()).also {
it.putValueArgument(0, builder.irString(function.getJsNameOrKotlinName().identifier)) it.putValueArgument(0, builder.irString(function.getJsNameOrKotlinName().identifier))
} }
function.annotations = function.annotations.filter { it.symbol != context.wasmSymbols.jsExportConstructor } function.annotations = function.annotations.filter { it.symbol != jsRelatedSymbols.jsExportConstructor }
return listOf(function, newFun) return listOf(function, newFun)
} }
@@ -202,15 +207,17 @@ class JsInteropFunctionsLowering(val context: WasmBackendContext) : DeclarationT
) )
} }
val primitivesToExternRefAdapters: Map<IrType, InteropTypeAdapter> = mapOf( val primitivesToExternRefAdapters: Map<IrType, InteropTypeAdapter> by lazy {
builtIns.byteType to adapters.kotlinByteToExternRefAdapter, mapOf(
builtIns.shortType to adapters.kotlinShortToExternRefAdapter, builtIns.byteType to adapters.kotlinByteToExternRefAdapter,
builtIns.charType to adapters.kotlinCharToExternRefAdapter, builtIns.shortType to adapters.kotlinShortToExternRefAdapter,
builtIns.intType to adapters.kotlinIntToExternRefAdapter, builtIns.charType to adapters.kotlinCharToExternRefAdapter,
builtIns.longType to adapters.kotlinLongToExternRefAdapter, builtIns.intType to adapters.kotlinIntToExternRefAdapter,
builtIns.floatType to adapters.kotlinFloatToExternRefAdapter, builtIns.longType to adapters.kotlinLongToExternRefAdapter,
builtIns.doubleType to adapters.kotlinDoubleToExternRefAdapter, builtIns.floatType to adapters.kotlinFloatToExternRefAdapter,
).mapValues { FunctionBasedAdapter(it.value.owner) } builtIns.doubleType to adapters.kotlinDoubleToExternRefAdapter,
).mapValues { FunctionBasedAdapter(it.value.owner) }
}
private fun IrType.kotlinToJsAdapterIfNeeded(isReturn: Boolean): InteropTypeAdapter? { private fun IrType.kotlinToJsAdapterIfNeeded(isReturn: Boolean): InteropTypeAdapter? {
if (isReturn && this == builtIns.unitType) if (isReturn && this == builtIns.unitType)
@@ -458,7 +465,7 @@ class JsInteropFunctionsLowering(val context: WasmBackendContext) : DeclarationT
} }
// TODO find out a better way to export the such declarations only when it's required. Also, fix building roots for DCE, then. // TODO find out a better way to export the such declarations only when it's required. Also, fix building roots for DCE, then.
result.annotations += builder.irCallConstructor(context.wasmSymbols.jsExportConstructor, typeArguments = emptyList()) result.annotations += builder.irCallConstructor(jsRelatedSymbols.jsExportConstructor, typeArguments = emptyList())
additionalDeclarations += result additionalDeclarations += result
return result return result
} }
@@ -466,7 +473,7 @@ class JsInteropFunctionsLowering(val context: WasmBackendContext) : DeclarationT
private fun createKotlinToJsClosureConvertor(info: FunctionTypeInfo): IrSimpleFunction { private fun createKotlinToJsClosureConvertor(info: FunctionTypeInfo): IrSimpleFunction {
val result = context.irFactory.buildFun { val result = context.irFactory.buildFun {
name = Name.identifier("__convertKotlinClosureToJsClosure_${info.signatureString}") name = Name.identifier("__convertKotlinClosureToJsClosure_${info.signatureString}")
returnType = context.wasmSymbols.jsAnyType returnType = jsRelatedSymbols.jsAnyType
isExternal = true isExternal = true
} }
result.parent = currentParent result.parent = currentParent
@@ -487,7 +494,7 @@ class JsInteropFunctionsLowering(val context: WasmBackendContext) : DeclarationT
append(")") append(")")
} }
result.annotations += builder.irCallConstructor(context.wasmSymbols.jsFunConstructor, typeArguments = emptyList()).also { result.annotations += builder.irCallConstructor(jsRelatedSymbols.jsFunConstructor, typeArguments = emptyList()).also {
it.putValueArgument(0, builder.irString(jsCode)) it.putValueArgument(0, builder.irString(jsCode))
} }
@@ -507,7 +514,7 @@ class JsInteropFunctionsLowering(val context: WasmBackendContext) : DeclarationT
result.parent = currentParent result.parent = currentParent
result.addValueParameter { result.addValueParameter {
name = Name.identifier("f") name = Name.identifier("f")
type = context.wasmSymbols.jsAnyType type = jsRelatedSymbols.jsAnyType
} }
val closureClass = context.irFactory.buildClass { val closureClass = context.irFactory.buildClass {
@@ -520,7 +527,7 @@ class JsInteropFunctionsLowering(val context: WasmBackendContext) : DeclarationT
val closureClassField = closureClass.addField { val closureClassField = closureClass.addField {
name = Name.identifier("jsClosure") name = Name.identifier("jsClosure")
type = context.wasmSymbols.jsAnyType type = jsRelatedSymbols.jsAnyType
visibility = DescriptorVisibilities.PRIVATE visibility = DescriptorVisibilities.PRIVATE
isFinal = true isFinal = true
} }
@@ -589,7 +596,7 @@ class JsInteropFunctionsLowering(val context: WasmBackendContext) : DeclarationT
result.parent = currentParent result.parent = currentParent
result.addValueParameter { result.addValueParameter {
name = Name.identifier("f") name = Name.identifier("f")
type = symbols.jsAnyType type = jsRelatedSymbols.jsAnyType
} }
val arity = info.adaptedParameterTypes.size val arity = info.adaptedParameterTypes.size
repeat(arity) { paramIndex -> repeat(arity) { paramIndex ->
@@ -607,7 +614,7 @@ class JsInteropFunctionsLowering(val context: WasmBackendContext) : DeclarationT
append(")") append(")")
} }
result.annotations += builder.irCallConstructor(context.wasmSymbols.jsFunConstructor, typeArguments = emptyList()).also { result.annotations += builder.irCallConstructor(jsRelatedSymbols.jsFunConstructor, typeArguments = emptyList()).also {
it.putValueArgument(0, builder.irString(jsFun)) it.putValueArgument(0, builder.irString(jsFun))
} }
@@ -817,7 +824,7 @@ class JsInteropFunctionsLowering(val context: WasmBackendContext) : DeclarationT
private val fromElementType: IrType, private val fromElementType: IrType,
) : InteropTypeAdapter { ) : InteropTypeAdapter {
override val toType: IrType = override val toType: IrType =
context.wasmSymbols.jsAnyType jsRelatedSymbols.jsAnyType
private val elementAdapter = private val elementAdapter =
primitivesToExternRefAdapters[fromElementType] primitivesToExternRefAdapters[fromElementType]
@@ -837,7 +844,7 @@ class JsInteropFunctionsLowering(val context: WasmBackendContext) : DeclarationT
// newJsArray.push(adapt(originalArray[index])); // newJsArray.push(adapt(originalArray[index]));
// index++ // index++
// } // }
val newJsArrayVar = irTemporary(irCall(symbols.newJsArray)) val newJsArrayVar = irTemporary(irCall(jsRelatedSymbols.newJsArray))
val indexVar = irTemporary(irInt(0), isMutable = true) val indexVar = irTemporary(irInt(0), isMutable = true)
val arraySizeVar = irTemporary(irCall(sizeMethod).apply { dispatchReceiver = irGet(originalArrayVar) }) val arraySizeVar = irTemporary(irCall(sizeMethod).apply { dispatchReceiver = irGet(originalArrayVar) })
@@ -854,7 +861,7 @@ class JsInteropFunctionsLowering(val context: WasmBackendContext) : DeclarationT
), ),
this@irBlock this@irBlock
) )
+irCall(symbols.jsArrayPush).apply { +irCall(jsRelatedSymbols.jsArrayPush).apply {
putValueArgument(0, irGet(newJsArrayVar)) putValueArgument(0, irGet(newJsArrayVar))
putValueArgument(1, adaptedValue) putValueArgument(1, adaptedValue)
} }
@@ -885,6 +892,7 @@ internal fun StringBuilder.appendParameterList(size: Int, name: String = "p", is
*/ */
class JsInteropFunctionCallsLowering(val context: WasmBackendContext) : BodyLoweringPass { class JsInteropFunctionCallsLowering(val context: WasmBackendContext) : BodyLoweringPass {
override fun lower(irBody: IrBody, container: IrDeclaration) { override fun lower(irBody: IrBody, container: IrDeclaration) {
if (context.configuration.get(JSConfigurationKeys.WASM_TARGET, WasmTarget.JS) == WasmTarget.WASI) return
irBody.transformChildrenVoid(object : IrElementTransformerVoid() { irBody.transformChildrenVoid(object : IrElementTransformerVoid() {
override fun visitCall(expression: IrCall): IrExpression { override fun visitCall(expression: IrCall): IrExpression {
expression.transformChildrenVoid() expression.transformChildrenVoid()
@@ -20,6 +20,8 @@ import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.expressions.IrBlockBody import org.jetbrains.kotlin.ir.expressions.IrBlockBody
import org.jetbrains.kotlin.ir.expressions.IrExpressionBody import org.jetbrains.kotlin.ir.expressions.IrExpressionBody
import org.jetbrains.kotlin.ir.util.toIrConst import org.jetbrains.kotlin.ir.util.toIrConst
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
import org.jetbrains.kotlin.js.config.WasmTarget
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
// This pass needed to wrap around unhandled exceptions from JsExport functions and throw JS exception for call from JS site // This pass needed to wrap around unhandled exceptions from JsExport functions and throw JS exception for call from JS site
@@ -47,7 +49,7 @@ import org.jetbrains.kotlin.name.Name
internal class UnhandledExceptionLowering(val context: WasmBackendContext) : FileLoweringPass { internal class UnhandledExceptionLowering(val context: WasmBackendContext) : FileLoweringPass {
private val throwableType = context.irBuiltIns.throwableType private val throwableType = context.irBuiltIns.throwableType
private val irBooleanType = context.wasmSymbols.irBuiltIns.booleanType private val irBooleanType = context.wasmSymbols.irBuiltIns.booleanType
private val throwAsJsException = context.wasmSymbols.throwAsJsException private val throwAsJsException get() = context.wasmSymbols.jsRelatedSymbols.throwAsJsException
private val isNotFirstWasmExportCallGetter = context.wasmSymbols.isNotFirstWasmExportCall.owner.getter!!.symbol private val isNotFirstWasmExportCallGetter = context.wasmSymbols.isNotFirstWasmExportCall.owner.getter!!.symbol
private val isNotFirstWasmExportCallSetter = context.wasmSymbols.isNotFirstWasmExportCall.owner.setter!!.symbol private val isNotFirstWasmExportCallSetter = context.wasmSymbols.isNotFirstWasmExportCall.owner.setter!!.symbol
@@ -131,6 +133,7 @@ internal class UnhandledExceptionLowering(val context: WasmBackendContext) : Fil
} }
override fun lower(irFile: IrFile) { override fun lower(irFile: IrFile) {
if (context.configuration.get(JSConfigurationKeys.WASM_TARGET, WasmTarget.JS) == WasmTarget.WASI) return
for (declaration in irFile.declarations) { for (declaration in irFile.declarations) {
if (declaration is IrFunction && declaration.isExported()) { if (declaration is IrFunction && declaration.isExported()) {
processExportFunction(declaration) processExportFunction(declaration)
@@ -23,6 +23,8 @@ import org.jetbrains.kotlin.ir.expressions.*
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.transformChildrenVoid import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
import org.jetbrains.kotlin.js.config.WasmTarget
class WasmTypeOperatorLowering(val context: WasmBackendContext) : FileLoweringPass { class WasmTypeOperatorLowering(val context: WasmBackendContext) : FileLoweringPass {
@@ -34,11 +36,11 @@ class WasmTypeOperatorLowering(val context: WasmBackendContext) : FileLoweringPa
class WasmBaseTypeOperatorTransformer(val context: WasmBackendContext) : IrElementTransformerVoidWithContext() { class WasmBaseTypeOperatorTransformer(val context: WasmBackendContext) : IrElementTransformerVoidWithContext() {
private val symbols = context.wasmSymbols private val symbols = context.wasmSymbols
private val builtIns = context.irBuiltIns private val builtIns = context.irBuiltIns
private val jsToKotlinAnyAdapter get() = symbols.jsRelatedSymbols.jsInteropAdapters.jsToKotlinAnyAdapter
private val kotlinToJsAnyAdapter get() = symbols.jsRelatedSymbols.jsInteropAdapters.kotlinToJsAnyAdapter
private lateinit var builder: DeclarationIrBuilder private lateinit var builder: DeclarationIrBuilder
override fun visitSimpleFunction(declaration: IrSimpleFunction): IrStatement {
return super.visitSimpleFunction(declaration)
}
override fun visitTypeOperator(expression: IrTypeOperatorCall): IrExpression { override fun visitTypeOperator(expression: IrTypeOperatorCall): IrExpression {
super.visitTypeOperator(expression) super.visitTypeOperator(expression)
builder = context.createIrBuilder(currentScope!!.scope.scopeOwnerSymbol).at(expression) builder = context.createIrBuilder(currentScope!!.scope.scopeOwnerSymbol).at(expression)
@@ -213,7 +215,10 @@ class WasmBaseTypeOperatorTransformer(val context: WasmBackendContext) : IrEleme
} }
if (fromClass.isExternal && !toClass.isExternal) { if (fromClass.isExternal && !toClass.isExternal) {
val narrowingToAny = builder.irCall(symbols.jsInteropAdapters.jsToKotlinAnyAdapter).also { if (context.configuration.get(JSConfigurationKeys.WASM_TARGET, WasmTarget.JS) == WasmTarget.WASI) {
TODO("Implement externalize adapter for wasi mode")
}
val narrowingToAny = builder.irCall(jsToKotlinAnyAdapter).also {
it.putValueArgument(0, value) it.putValueArgument(0, value)
} }
// Continue narrowing from Any to expected type // Continue narrowing from Any to expected type
@@ -221,7 +226,10 @@ class WasmBaseTypeOperatorTransformer(val context: WasmBackendContext) : IrEleme
} }
if (toClass.isExternal && !fromClass.isExternal) { if (toClass.isExternal && !fromClass.isExternal) {
return builder.irCall(symbols.jsInteropAdapters.kotlinToJsAnyAdapter).also { if (context.configuration.get(JSConfigurationKeys.WASM_TARGET, WasmTarget.JS) == WasmTarget.WASI) {
TODO("Implement internalize adapter for wasi mode")
}
return builder.irCall(kotlinToJsAnyAdapter).also {
it.putValueArgument(0, value) it.putValueArgument(0, value)
} }
} }
@@ -11,17 +11,24 @@ import org.jetbrains.kotlin.ir.builders.irCallConstructor
import org.jetbrains.kotlin.ir.declarations.IrFile import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.IrFunction import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
import org.jetbrains.kotlin.js.config.WasmTarget
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
/** /**
* Mark declarations from [exportedFqNames] with @JsExport annotation * Mark declarations from [exportedFqNames] with @JsExport annotation
*/ */
fun markExportedDeclarations(context: WasmBackendContext, irFile: IrFile, exportedFqNames: Set<FqName>) { fun markExportedDeclarations(context: WasmBackendContext, irFile: IrFile, exportedFqNames: Set<FqName>) {
val exportConstructor = when (context.configuration.get(JSConfigurationKeys.WASM_TARGET, WasmTarget.JS)) {
WasmTarget.WASI -> context.wasmSymbols.wasmExportConstructor
else -> context.wasmSymbols.jsRelatedSymbols.jsExportConstructor
}
for (declaration in irFile.declarations) { for (declaration in irFile.declarations) {
if (declaration is IrFunction && declaration.fqNameWhenAvailable in exportedFqNames) { if (declaration is IrFunction && declaration.fqNameWhenAvailable in exportedFqNames) {
val builder = context.createIrBuilder(irFile.symbol) val builder = context.createIrBuilder(irFile.symbol)
declaration.annotations += declaration.annotations +=
builder.irCallConstructor(context.wasmSymbols.jsExportConstructor, typeArguments = emptyList()) builder.irCallConstructor(exportConstructor, typeArguments = emptyList())
} }
} }
} }