[Wasm] Generate [K][Suspend]FunctionN on demand and support big arity
This commit is contained in:
@@ -341,13 +341,6 @@ private val wasmNullSpecializationLowering = makeWasmModulePhase(
|
||||
description = "Specialize assigning Nothing? values to other types."
|
||||
)
|
||||
|
||||
private val wasmFunctionInterfaceReplacer = makeWasmModulePhase(
|
||||
::WasmFunctionInterfaceReplacer,
|
||||
name = "WasmFunctionInterfaceReplacer",
|
||||
description = "Replace function interface with concrete runtime interfaces"
|
||||
)
|
||||
|
||||
|
||||
private val staticMembersLoweringPhase = makeWasmModulePhase(
|
||||
::StaticMembersLowering,
|
||||
name = "StaticMembersLowering",
|
||||
@@ -527,7 +520,6 @@ val wasmPhases = NamedCompilerPhase(
|
||||
|
||||
virtualDispatchReceiverExtractionPhase then
|
||||
staticMembersLoweringPhase then
|
||||
wasmFunctionInterfaceReplacer then
|
||||
wasmNullSpecializationLowering then
|
||||
validateIrAfterLowering
|
||||
)
|
||||
|
||||
@@ -168,18 +168,6 @@ class WasmSymbols(
|
||||
|
||||
val kTypeStub = getInternalFunction("kTypeStub")
|
||||
|
||||
private val functionNInterfaces = (0..22).map { arity ->
|
||||
getIrClass(FqName("kotlin.wasm.internal.Function$arity"))
|
||||
}
|
||||
|
||||
val functionNInvokeMethods by lazy {
|
||||
functionNInterfaces.map { interfaceSymbol ->
|
||||
interfaceSymbol.owner.declarations.filterIsInstance<IrSimpleFunction>().single { method ->
|
||||
method.name == OperatorNameConventions.INVOKE
|
||||
}.symbol
|
||||
}
|
||||
}
|
||||
|
||||
val arraysCopyInto = findFunctions(collectionsPackage.memberScope, Name.identifier("copyInto"))
|
||||
.map { symbolTable.referenceSimpleFunction(it) }
|
||||
|
||||
@@ -208,9 +196,6 @@ class WasmSymbols(
|
||||
}
|
||||
}
|
||||
|
||||
override fun functionN(n: Int): IrClassSymbol =
|
||||
functionNInterfaces[n]
|
||||
|
||||
private fun findClass(memberScope: MemberScope, name: Name): ClassDescriptor =
|
||||
memberScope.getContributedClassifier(name, NoLookupLocation.FROM_BACKEND) as ClassDescriptor
|
||||
|
||||
|
||||
@@ -32,7 +32,12 @@ fun compileWasm(
|
||||
): WasmCompilerResult {
|
||||
val mainModule = depsDescriptors.mainModule
|
||||
val configuration = depsDescriptors.compilerConfiguration
|
||||
val (moduleFragment, dependencyModules, irBuiltIns, symbolTable, deserializer) = loadIr(depsDescriptors, irFactory, verifySignatures = false)
|
||||
val (moduleFragment, dependencyModules, irBuiltIns, symbolTable, deserializer) = loadIr(
|
||||
depsDescriptors,
|
||||
irFactory,
|
||||
verifySignatures = false,
|
||||
loadFunctionInterfacesIntoStdlib = true,
|
||||
)
|
||||
|
||||
val allModules = when (mainModule) {
|
||||
is MainModule.SourceFiles -> dependencyModules + listOf(moduleFragment)
|
||||
|
||||
-6
@@ -180,12 +180,6 @@ class WasmModuleCodegenContextImpl(
|
||||
|
||||
|
||||
override fun referenceInterfaceId(irInterface: IrClassSymbol): WasmSymbol<Int> {
|
||||
// HACK to substitute kotlin.Function5 with kotlin.wasm.internal.Function5
|
||||
val defaultType = irInterface.defaultType
|
||||
if (defaultType.isFunction()) {
|
||||
val n = irInterface.owner.typeParameters.size - 1
|
||||
return wasmFragment.interfaceId.reference(backendContext.wasmSymbols.functionN(n))
|
||||
}
|
||||
return wasmFragment.interfaceId.reference(irInterface)
|
||||
}
|
||||
|
||||
|
||||
-15
@@ -123,24 +123,9 @@ class BuiltInsLowering(val context: WasmBackendContext) : FileLoweringPass {
|
||||
}
|
||||
}
|
||||
|
||||
val nativeInvokeArity = getKotlinFunctionInvokeArity(call)
|
||||
if (nativeInvokeArity != null) {
|
||||
return irCall(call, symbols.functionNInvokeMethods[nativeInvokeArity])
|
||||
}
|
||||
|
||||
return call
|
||||
}
|
||||
|
||||
private fun getKotlinFunctionInvokeArity(call: IrCall): Int? {
|
||||
val simpleFunction = call.symbol.owner as? IrSimpleFunction ?: return null
|
||||
val receiverType = simpleFunction.dispatchReceiverParameter?.type ?: return null
|
||||
if (simpleFunction.isSuspend) return null
|
||||
if (simpleFunction.name == OperatorNameConventions.INVOKE && receiverType.isFunction()) {
|
||||
return simpleFunction.valueParameters.size
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
override fun lower(irFile: IrFile) {
|
||||
val builder = context.createIrBuilder(irFile.symbol)
|
||||
irFile.transformChildrenVoid(object : IrElementTransformerVoidWithContext() {
|
||||
|
||||
-54
@@ -1,54 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.backend.wasm.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext
|
||||
import org.jetbrains.kotlin.backend.wasm.WasmBackendContext
|
||||
import org.jetbrains.kotlin.ir.IrStatement
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||
import org.jetbrains.kotlin.ir.types.IrSimpleType
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.types.typeWithArguments
|
||||
import org.jetbrains.kotlin.ir.util.isFunction
|
||||
import org.jetbrains.kotlin.ir.util.render
|
||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
|
||||
/**
|
||||
* Replace kotlin.Function{N} etc super types with kotlin.wasm.internal.Function{N} super types.
|
||||
* This is a workaround for having a concrete IR for these interfaces.
|
||||
*/
|
||||
class WasmFunctionInterfaceReplacer(val context: WasmBackendContext) : FileLoweringPass {
|
||||
|
||||
private fun replaceType(type: IrType): IrType {
|
||||
if (type.isFunction()) {
|
||||
require(type is IrSimpleType)
|
||||
val klass: IrClass = type.classifier.owner as IrClass
|
||||
|
||||
// No need to replace just "kotlin.Function"
|
||||
if (klass.name.identifier == "Function") {
|
||||
return type
|
||||
}
|
||||
|
||||
val arity = klass.typeParameters.size - 1
|
||||
return context.wasmSymbols.functionN(arity).typeWithArguments(type.arguments)
|
||||
}
|
||||
|
||||
return type
|
||||
}
|
||||
|
||||
override fun lower(irFile: IrFile) {
|
||||
irFile.transformChildrenVoid(object : IrElementTransformerVoidWithContext() {
|
||||
override fun visitClassNew(declaration: IrClass): IrStatement {
|
||||
if (declaration.superTypes.any { it.isFunction() }) {
|
||||
declaration.superTypes = declaration.superTypes.map { replaceType(it) }
|
||||
}
|
||||
return super.visitClassNew(declaration)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
+8
-4
@@ -83,8 +83,12 @@ abstract class IrAbstractDescriptorBasedFunctionFactory {
|
||||
|
||||
@OptIn(ObsoleteDescriptorBasedAPI::class)
|
||||
class IrDescriptorBasedFunctionFactory(
|
||||
private val irBuiltIns: IrBuiltInsOverDescriptors, private val symbolTable: SymbolTable
|
||||
private val irBuiltIns: IrBuiltInsOverDescriptors,
|
||||
private val symbolTable: SymbolTable,
|
||||
getPackageFragment: ((PackageFragmentDescriptor) -> IrPackageFragment)? = null
|
||||
) : IrAbstractDescriptorBasedFunctionFactory() {
|
||||
val getPackageFragment =
|
||||
getPackageFragment ?: symbolTable::declareExternalPackageFragmentIfNotExists
|
||||
|
||||
// TODO: Lazieness
|
||||
|
||||
@@ -230,18 +234,18 @@ class IrDescriptorBasedFunctionFactory(
|
||||
|
||||
private val kotlinPackageFragment: IrPackageFragment by lazy {
|
||||
irBuiltIns.builtIns.getFunction(0).let {
|
||||
symbolTable.declareExternalPackageFragmentIfNotExists(it.containingDeclaration as PackageFragmentDescriptor)
|
||||
getPackageFragment(it.containingDeclaration as PackageFragmentDescriptor)
|
||||
}
|
||||
}
|
||||
private val kotlinCoroutinesPackageFragment: IrPackageFragment by lazy {
|
||||
irBuiltIns.builtIns.getSuspendFunction(0).let {
|
||||
symbolTable.declareExternalPackageFragmentIfNotExists(it.containingDeclaration as PackageFragmentDescriptor)
|
||||
getPackageFragment(it.containingDeclaration as PackageFragmentDescriptor)
|
||||
}
|
||||
}
|
||||
|
||||
private val kotlinReflectPackageFragment: IrPackageFragment by lazy {
|
||||
irBuiltIns.kPropertyClass.descriptor.let {
|
||||
symbolTable.declareExternalPackageFragmentIfNotExists(it.containingDeclaration as PackageFragmentDescriptor)
|
||||
getPackageFragment(it.containingDeclaration as PackageFragmentDescriptor)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.config.*
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
|
||||
import org.jetbrains.kotlin.incremental.components.LookupTracker
|
||||
import org.jetbrains.kotlin.ir.IrBuiltIns
|
||||
@@ -38,13 +39,12 @@ import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsManglerDesc
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsManglerIr
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFactory
|
||||
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFileImpl
|
||||
import org.jetbrains.kotlin.ir.descriptors.IrBuiltInsOverDescriptors
|
||||
import org.jetbrains.kotlin.ir.descriptors.IrDescriptorBasedFunctionFactory
|
||||
import org.jetbrains.kotlin.ir.linkage.IrDeserializer
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
||||
import org.jetbrains.kotlin.ir.util.ExternalDependenciesGenerator
|
||||
import org.jetbrains.kotlin.ir.util.IrMessageLogger
|
||||
import org.jetbrains.kotlin.ir.util.SymbolTable
|
||||
import org.jetbrains.kotlin.ir.util.noUnboundLeft
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
||||
import org.jetbrains.kotlin.js.analyzer.JsAnalysisResult
|
||||
import org.jetbrains.kotlin.js.config.ErrorTolerancePolicy
|
||||
@@ -256,7 +256,8 @@ fun loadIr(
|
||||
depsDescriptors: ModulesStructure,
|
||||
irFactory: IrFactory,
|
||||
verifySignatures: Boolean,
|
||||
filesToLoad: Set<String>? = null
|
||||
filesToLoad: Set<String>? = null,
|
||||
loadFunctionInterfacesIntoStdlib: Boolean = false,
|
||||
): IrModuleInfo {
|
||||
val project = depsDescriptors.project
|
||||
val mainModule = depsDescriptors.mainModule
|
||||
@@ -268,11 +269,26 @@ fun loadIr(
|
||||
val signaturer = IdSignatureDescriptor(JsManglerDesc)
|
||||
val symbolTable = SymbolTable(signaturer, irFactory)
|
||||
|
||||
lateinit var stdlibModule: IrModuleFragment
|
||||
|
||||
val createFunctionFactoryCallback =
|
||||
if (loadFunctionInterfacesIntoStdlib) {
|
||||
{ packageFragmentDescriptor: PackageFragmentDescriptor ->
|
||||
IrFileImpl(NaiveSourceBasedFileEntryImpl("[K][Suspend]Functions"), packageFragmentDescriptor, stdlibModule)
|
||||
.also { stdlibModule.files += it }
|
||||
}
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
when (mainModule) {
|
||||
is MainModule.SourceFiles -> {
|
||||
assert(filesToLoad == null)
|
||||
val (psi2IrContext, _) = preparePsi2Ir(depsDescriptors, errorPolicy, symbolTable)
|
||||
val irBuiltIns = psi2IrContext.irBuiltIns
|
||||
(irBuiltIns as IrBuiltInsOverDescriptors).functionFactory =
|
||||
IrDescriptorBasedFunctionFactory(irBuiltIns, symbolTable, createFunctionFactoryCallback)
|
||||
|
||||
val feContext = psi2IrContext.run {
|
||||
JsIrLinker.JsFePluginContext(moduleDescriptor, symbolTable, typeTranslator, irBuiltIns)
|
||||
}
|
||||
@@ -301,6 +317,7 @@ fun loadIr(
|
||||
}
|
||||
}
|
||||
}
|
||||
stdlibModule = deserializedModuleFragments.first()
|
||||
|
||||
val moduleFragment = psi2IrContext.generateModuleFragmentWithPlugins(project, mainModule.files, irLinker, messageLogger)
|
||||
symbolTable.noUnboundLeft("Unbound symbols left after linker")
|
||||
@@ -332,6 +349,7 @@ fun loadIr(
|
||||
val typeTranslator =
|
||||
TypeTranslatorImpl(symbolTable, depsDescriptors.compilerConfiguration.languageVersionSettings, moduleDescriptor)
|
||||
val irBuiltIns = IrBuiltInsOverDescriptors(moduleDescriptor.builtIns, typeTranslator, symbolTable)
|
||||
irBuiltIns.functionFactory = IrDescriptorBasedFunctionFactory(irBuiltIns, symbolTable, createFunctionFactoryCallback)
|
||||
|
||||
val loweredIcData = if (!depsDescriptors.icUseStdlibCache && !depsDescriptors.icUseStdlibCache) emptyMap() else {
|
||||
val result = mutableMapOf<ModuleDescriptor, SerializedIcData>()
|
||||
@@ -390,6 +408,7 @@ fun loadIr(
|
||||
}
|
||||
}
|
||||
}
|
||||
stdlibModule = deserializedModuleFragments.first()
|
||||
|
||||
val moduleFragment = deserializedModuleFragments.last()
|
||||
|
||||
|
||||
-2
@@ -1,5 +1,3 @@
|
||||
// IGNORE_BACKEND: WASM
|
||||
// WASM_MUTE_REASON: BIG_ARITY
|
||||
// !LANGUAGE: +NewInference
|
||||
|
||||
fun foo(
|
||||
|
||||
-2
@@ -1,5 +1,3 @@
|
||||
// IGNORE_BACKEND: WASM
|
||||
// WASM_MUTE_REASON: FUNCTION_REFERENCES
|
||||
// WITH_RUNTIME
|
||||
// IGNORE_BACKEND: JS
|
||||
|
||||
|
||||
Vendored
-2
@@ -1,5 +1,3 @@
|
||||
// IGNORE_BACKEND: WASM
|
||||
// WASM_MUTE_REASON: BIG_ARITY
|
||||
// IGNORE_BACKEND: NATIVE
|
||||
var result = "Fail"
|
||||
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
// IGNORE_BACKEND: WASM
|
||||
// WASM_MUTE_REASON: BIG_ARITY
|
||||
// !LANGUAGE: +FunctionTypesWithBigArity
|
||||
|
||||
class A(val value: Int) {
|
||||
|
||||
-2
@@ -1,5 +1,3 @@
|
||||
// IGNORE_BACKEND: WASM
|
||||
// WASM_MUTE_REASON: BIG_ARITY
|
||||
// !LANGUAGE: +FunctionTypesWithBigArity
|
||||
// IGNORE_BACKEND: JS_IR, JS
|
||||
// IGNORE_BACKEND: JS_IR_ES6
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
// IGNORE_BACKEND: WASM
|
||||
// WASM_MUTE_REASON: BIG_ARITY
|
||||
// !LANGUAGE: +FunctionTypesWithBigArity
|
||||
|
||||
class A
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
// IGNORE_BACKEND: WASM
|
||||
// WASM_MUTE_REASON: BIG_ARITY
|
||||
// !LANGUAGE: +FunctionTypesWithBigArity
|
||||
|
||||
class A(val value: Int)
|
||||
|
||||
-2
@@ -1,5 +1,3 @@
|
||||
// IGNORE_BACKEND: WASM
|
||||
// WASM_MUTE_REASON: BIG_ARITY
|
||||
// !LANGUAGE: +FunctionTypesWithBigArity
|
||||
|
||||
class A {
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
// IGNORE_BACKEND: WASM
|
||||
// WASM_MUTE_REASON: BIG_ARITY
|
||||
interface A
|
||||
object O : A
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: WASM
|
||||
|
||||
inline class Z(val value: Long)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user