[Wasm] Fix JsName external declarations

This commit is contained in:
Igor Yakovlev
2022-11-25 19:09:43 +01:00
committed by teamcity
parent 4bd187ccea
commit 4dedd47172
4 changed files with 82 additions and 51 deletions
@@ -68,11 +68,7 @@ class DeclarationGenerator(
} }
val wasmImportModule = declaration.getWasmImportDescriptor() val wasmImportModule = declaration.getWasmImportDescriptor()
val jsCode = if (declaration.isExternal) declaration.getJsFunAnnotation() else null
val jsCode = declaration.getJsFunAnnotation()
// TODO: Why are we importing declarations by with raw declaration.name.asString() jsCode?
?: if (declaration.isExternal && wasmImportModule == null) declaration.name.asString() else null
val importedName = when { val importedName = when {
wasmImportModule != null -> { wasmImportModule != null -> {
check(declaration.isExternal) { "Non-external fun with @WasmImport ${declaration.fqNameWhenAvailable}"} check(declaration.isExternal) { "Non-external fun with @WasmImport ${declaration.fqNameWhenAvailable}"}
@@ -5,7 +5,6 @@
package org.jetbrains.kotlin.backend.wasm.lower package org.jetbrains.kotlin.backend.wasm.lower
import org.jetbrains.kotlin.backend.common.BodyLoweringPass
import org.jetbrains.kotlin.backend.common.FileLoweringPass import org.jetbrains.kotlin.backend.common.FileLoweringPass
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.backend.wasm.WasmBackendContext import org.jetbrains.kotlin.backend.wasm.WasmBackendContext
@@ -333,9 +332,46 @@ class ComplexExternalDeclarationsToTopLevelFunctionsLowering(val context: WasmBa
/** /**
* Redirect usages of complex declarations to top-level functions * Redirect usages of complex declarations to top-level functions
*/ */
class ComplexExternalDeclarationsUsageLowering(val context: WasmBackendContext) : BodyLoweringPass { class ComplexExternalDeclarationsUsageLowering(val context: WasmBackendContext) : FileLoweringPass {
override fun lower(irBody: IrBody, container: IrDeclaration) { private val nestedExternalToNewTopLevelFunctions = context.mapping.wasmNestedExternalToNewTopLevelFunction
irBody.transformChildrenVoid(object : IrElementTransformerVoid() { private val objectToGetInstanceFunctions = context.mapping.wasmExternalObjectToGetInstanceFunction
override fun lower(irFile: IrFile) {
irFile.acceptVoid(declarationTransformer)
}
private val declarationTransformer = object : IrElementVisitorVoid {
override fun visitElement(element: IrElement) {
element.acceptChildrenVoid(this)
}
override fun visitFile(declaration: IrFile) {
process(declaration)
}
override fun visitClass(declaration: IrClass) {
if (!declaration.isExternal) {
process(declaration)
}
}
private fun process(container: IrDeclarationContainer) {
container.declarations.transformFlat { member ->
if (nestedExternalToNewTopLevelFunctions.keys.contains(member)) {
emptyList()
} else {
member.acceptVoid(this)
null
}
}
}
override fun visitBody(body: IrBody) {
body.transformChildrenVoid(usagesTransformer)
}
}
private val usagesTransformer = object : IrElementTransformerVoid() {
override fun visitCall(expression: IrCall): IrExpression { override fun visitCall(expression: IrCall): IrExpression {
expression.transformChildrenVoid() expression.transformChildrenVoid()
return transformCall(expression) return transformCall(expression)
@@ -347,27 +383,21 @@ class ComplexExternalDeclarationsUsageLowering(val context: WasmBackendContext)
} }
override fun visitGetObjectValue(expression: IrGetObjectValue): IrExpression { override fun visitGetObjectValue(expression: IrGetObjectValue): IrExpression {
val externalGetInstance = context.mapping.wasmExternalObjectToGetInstanceFunction[expression.symbol.owner] val externalGetInstance = objectToGetInstanceFunctions[expression.symbol.owner] ?: return expression
return if (externalGetInstance != null) { return IrCallImpl(
IrCallImpl( startOffset = expression.startOffset,
expression.startOffset, endOffset = expression.endOffset,
expression.endOffset, type = expression.type,
expression.type, symbol = externalGetInstance.symbol,
externalGetInstance.symbol,
valueArgumentsCount = 0, valueArgumentsCount = 0,
typeArgumentsCount = 0 typeArgumentsCount = 0
) )
} else {
expression
}
} }
fun transformCall(call: IrFunctionAccessExpression): IrExpression { fun transformCall(call: IrFunctionAccessExpression): IrExpression {
val oldFun = call.symbol.owner.realOverrideTarget val oldFun = call.symbol.owner.realOverrideTarget
val newFun: IrSimpleFunction? = val newFun: IrSimpleFunction = nestedExternalToNewTopLevelFunctions[oldFun] ?: return call
context.mapping.wasmNestedExternalToNewTopLevelFunction[oldFun]
return if (newFun != null) {
val newCall = irCall(call, newFun, receiversAsArguments = true) val newCall = irCall(call, newFun, receiversAsArguments = true)
// Add default arguments flags if needed // Add default arguments flags if needed
@@ -381,14 +411,9 @@ class ComplexExternalDeclarationsUsageLowering(val context: WasmBackendContext)
IrConstImpl.int(UNDEFINED_OFFSET, UNDEFINED_OFFSET, context.irBuiltIns.intType, value) IrConstImpl.int(UNDEFINED_OFFSET, UNDEFINED_OFFSET, context.irBuiltIns.intType, value)
) )
} }
return newCall
newCall
} else {
call
} }
} }
})
}
} }
private fun numDefaultParametersForExternalFunction(function: IrFunction): Int { private fun numDefaultParametersForExternalFunction(function: IrFunction): Int {
@@ -53,6 +53,7 @@ class JsInteropFunctionsLowering(val context: WasmBackendContext) : DeclarationT
if (declaration.getWasmImportDescriptor() != null) return null if (declaration.getWasmImportDescriptor() != null) return null
check(!(isExported && isExternal)) { "Exported external declarations are not supported: ${declaration.fqNameWhenAvailable}" } check(!(isExported && isExternal)) { "Exported external declarations are not supported: ${declaration.fqNameWhenAvailable}" }
check(declaration.parent !is IrClass) { "Interop members are not supported: ${declaration.fqNameWhenAvailable}" } check(declaration.parent !is IrClass) { "Interop members are not supported: ${declaration.fqNameWhenAvailable}" }
if (context.mapping.wasmNestedExternalToNewTopLevelFunction.keys.contains(declaration)) return null
additionalDeclarations.clear() additionalDeclarations.clear()
currentParent = declaration.parent currentParent = declaration.parent
@@ -435,6 +436,7 @@ class JsInteropFunctionsLowering(val context: WasmBackendContext) : DeclarationT
val result = context.irFactory.buildFun { val result = context.irFactory.buildFun {
name = Name.identifier("__convertKotlinClosureToJsClosure_${info.hashString}") name = Name.identifier("__convertKotlinClosureToJsClosure_${info.hashString}")
returnType = context.wasmSymbols.externalInterfaceType returnType = context.wasmSymbols.externalInterfaceType
isExternal = true
} }
result.parent = currentParent result.parent = currentParent
result.addValueParameter { result.addValueParameter {
@@ -551,6 +553,7 @@ class JsInteropFunctionsLowering(val context: WasmBackendContext) : DeclarationT
val result = context.irFactory.buildFun { val result = context.irFactory.buildFun {
name = Name.identifier("__callJsClosure_${info.hashString}") name = Name.identifier("__callJsClosure_${info.hashString}")
returnType = info.adaptedResultType returnType = info.adaptedResultType
isExternal = true
} }
result.parent = currentParent result.parent = currentParent
result.addValueParameter { result.addValueParameter {
@@ -55,6 +55,9 @@ const externalObj = {
c: class { x = "(new externalObj.c()).x" } c: class { x = "(new externalObj.c()).x" }
} }
function jsRenamed() {
return 'renamed'
}
// FILE: externals.kt // FILE: externals.kt
external interface Obj { external interface Obj {
@@ -112,6 +115,9 @@ external object externalObj {
} }
} }
@JsName("jsRenamed")
external fun testJsName(): String
fun box(): String { fun box(): String {
val obj = createObject() val obj = createObject()
setX(obj, 100) setX(obj, 100)
@@ -164,6 +170,7 @@ fun box(): String {
if (10 as Any is C1) return "Fail 23" if (10 as Any is C1) return "Fail 23"
if (c1 as Any is C2) return "Fail 24" if (c1 as Any is C2) return "Fail 24"
if (testJsName() != "renamed") return "Fail 25"
return "OK" return "OK"
} }