[JS IR BE] Support compilation and tests against klib

This commit is contained in:
Roman Artemev
2019-02-19 22:16:36 +03:00
committed by romanart
parent b99377fd69
commit 079f2534c7
15 changed files with 290 additions and 410 deletions
@@ -15,8 +15,8 @@ import org.jetbrains.kotlin.backend.js.JsDeclarationFactory
import org.jetbrains.kotlin.builtins.PrimitiveType import org.jetbrains.kotlin.builtins.PrimitiveType
import org.jetbrains.kotlin.config.CompilerConfiguration import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.SourceManager import org.jetbrains.kotlin.ir.SourceManager
@@ -34,7 +34,6 @@ import org.jetbrains.kotlin.ir.types.impl.IrDynamicTypeImpl
import org.jetbrains.kotlin.ir.util.SymbolTable import org.jetbrains.kotlin.ir.util.SymbolTable
import org.jetbrains.kotlin.ir.util.getPropertyDeclaration import org.jetbrains.kotlin.ir.util.getPropertyDeclaration
import org.jetbrains.kotlin.ir.util.kotlinPackageFqn import org.jetbrains.kotlin.ir.util.kotlinPackageFqn
import org.jetbrains.kotlin.js.backend.ast.JsNode
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
@@ -43,13 +42,12 @@ import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.types.createDynamicType import org.jetbrains.kotlin.types.createDynamicType
class JsIrBackendContext( class JsIrBackendContext(
val module: ModuleDescriptor, val module: ModuleDescriptorImpl,
override val irBuiltIns: IrBuiltIns, override val irBuiltIns: IrBuiltIns,
val symbolTable: SymbolTable, val symbolTable: SymbolTable,
irModuleFragment: IrModuleFragment, irModuleFragment: IrModuleFragment,
override val configuration: CompilerConfiguration, override val configuration: CompilerConfiguration,
val dependencies: List<CompiledModule>, val compilationMode: CompilationMode
val moduleType: ModuleType
) : CommonBackendContext { ) : CommonBackendContext {
override val builtIns = module.builtIns override val builtIns = module.builtIns
@@ -131,8 +129,9 @@ class JsIrBackendContext(
private val operatorMap = referenceOperators() private val operatorMap = referenceOperators()
// TODO: get rid of this // TODO: get rid of this
val functions = (0..22).map { symbolTable.referenceClass(builtIns.getFunction(it)) }
val suspendFunctions = (0..22).map { symbolTable.referenceClass(builtIns.getSuspendFunction(it)) } fun functionN(n: Int) = symbolTable.lazyWrapper.referenceClass(builtIns.getFunction(n))
fun suspendFunctionN(n: Int) = symbolTable.lazyWrapper.referenceClass(builtIns.getSuspendFunction(n))
private fun primitivesWithImplicitCompanionObject(): List<Name> { private fun primitivesWithImplicitCompanionObject(): List<Name> {
val numbers = PrimitiveType.NUMBER_TYPES val numbers = PrimitiveType.NUMBER_TYPES
@@ -144,10 +143,6 @@ class JsIrBackendContext(
val dynamicType = IrDynamicTypeImpl(createDynamicType(builtIns), emptyList(), Variance.INVARIANT) val dynamicType = IrDynamicTypeImpl(createDynamicType(builtIns), emptyList(), Variance.INVARIANT)
val originalModuleIndex = ModuleIndex(irModuleFragment)
lateinit var moduleFragmentCopy: IrModuleFragment
fun getOperatorByName(name: Name, type: KotlinType) = operatorMap[name]?.get(type) fun getOperatorByName(name: Name, type: KotlinType) = operatorMap[name]?.get(type)
override val ir = object : Ir<CommonBackendContext>(this, irModuleFragment) { override val ir = object : Ir<CommonBackendContext>(this, irModuleFragment) {
@@ -99,13 +99,6 @@ private val lateinitLoweringPhase = makeJsModulePhase(
description = "Insert checks for lateinit field references" description = "Insert checks for lateinit field references"
) )
private val moduleCopyingPhase = makeCustomJsModulePhase(
{ context, module -> context.moduleFragmentCopy = module.deepCopyWithSymbols() },
name = "ModuleCopying",
description = "<Supposed to be removed> Copy current module to make it accessible from different one",
prerequisite = setOf(lateinitLoweringPhase)
)
private val functionInliningPhase = makeCustomJsModulePhase( private val functionInliningPhase = makeCustomJsModulePhase(
{ context, module -> { context, module ->
FunctionInlining(context).inline(module) FunctionInlining(context).inline(module)
@@ -114,7 +107,7 @@ private val functionInliningPhase = makeCustomJsModulePhase(
}, },
name = "FunctionInliningPhase", name = "FunctionInliningPhase",
description = "Perform function inlining", description = "Perform function inlining",
prerequisite = setOf(moduleCopyingPhase, lateinitLoweringPhase, arrayInlineConstructorLoweringPhase, coroutineIntrinsicLoweringPhase) prerequisite = setOf(lateinitLoweringPhase, arrayInlineConstructorLoweringPhase, coroutineIntrinsicLoweringPhase)
) )
private val removeInlineFunctionsWithReifiedTypeParametersLoweringPhase = makeJsModulePhase( private val removeInlineFunctionsWithReifiedTypeParametersLoweringPhase = makeJsModulePhase(
@@ -356,7 +349,6 @@ val jsPhases = namedIrModulePhase(
coroutineIntrinsicLoweringPhase then coroutineIntrinsicLoweringPhase then
arrayInlineConstructorLoweringPhase then arrayInlineConstructorLoweringPhase then
lateinitLoweringPhase then lateinitLoweringPhase then
moduleCopyingPhase then
functionInliningPhase then functionInliningPhase then
removeInlineFunctionsWithReifiedTypeParametersLoweringPhase then removeInlineFunctionsWithReifiedTypeParametersLoweringPhase then
throwableSuccessorsLoweringPhase then throwableSuccessorsLoweringPhase then
@@ -14,7 +14,6 @@ import org.jetbrains.kotlin.config.CommonConfigurationKeys
import org.jetbrains.kotlin.config.CompilerConfiguration import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.config.languageVersionSettings import org.jetbrains.kotlin.config.languageVersionSettings
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.impl.CompositePackageFragmentProvider import org.jetbrains.kotlin.descriptors.impl.CompositePackageFragmentProvider
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
import org.jetbrains.kotlin.incremental.components.LookupTracker import org.jetbrains.kotlin.incremental.components.LookupTracker
@@ -34,52 +33,30 @@ import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStatus import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStatus
import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi2ir.Psi2IrTranslator import org.jetbrains.kotlin.psi2ir.Psi2IrTranslator
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.CompilerDeserializationConfiguration import org.jetbrains.kotlin.resolve.CompilerDeserializationConfiguration
import org.jetbrains.kotlin.storage.LockBasedStorageManager import org.jetbrains.kotlin.storage.LockBasedStorageManager
import org.jetbrains.kotlin.utils.DFS import org.jetbrains.kotlin.utils.DFS
import java.io.File import java.io.File
enum class ModuleType {
TEST_RUNTIME,
SECONDARY,
MAIN
}
class CompiledModule( class CompiledModule(
val moduleName: String, val moduleName: String,
val generatedCode: String?, val generatedCode: String?,
val moduleFragment: IrModuleFragment?, var moduleDescriptor: ModuleDescriptorImpl?,
val moduleType: ModuleType, val klibPath: String,
val dependencies: List<CompiledModule> val dependencies: List<CompiledModule>,
) { val isBuiltIn: Boolean
val descriptor )
get() = moduleFragment!!.descriptor as ModuleDescriptorImpl
}
enum class CompilationMode(val generateJS: Boolean) { enum class CompilationMode(val generateJS: Boolean, val generateKlib: Boolean) {
KLIB(false), KLIB(false, true),
KLIB_WITH_JS(true), KLIB_WITH_JS(true, true),
TEST_AGAINST_CACHE(true), JS_AGAINST_KLIB(true, false)
TEST_AGAINST_KLIB(true),
} }
private val runtimeKlibPath = "js/js.translator/testData/out/klibs/runtime/"
private val moduleHeaderFileName = "module.kji" private val moduleHeaderFileName = "module.kji"
private val declarationsDirName = "ir/" private val declarationsDirName = "ir/"
private val debugDataFileName = "debug.txt" private val debugDataFileName = "debug.txt"
private fun metadataFileName(moduleName: String) = "$moduleName.${JsKlibMetadataSerializationUtil.CLASS_METADATA_FILE_EXTENSION}"
private val JS_IR_RUNTIME_MODULE_NAME = "JS_IR_RUNTIME"
data class JsKlib(
val moduleDescriptor: ModuleDescriptor,
val moduleIr: IrModuleFragment,
val symbolTable: SymbolTable,
val irBuiltIns: IrBuiltIns
)
private val logggg = object : LoggingContext { private val logggg = object : LoggingContext {
override var inVerbosePhase: Boolean override var inVerbosePhase: Boolean
get() = TODO("not implemented") get() = TODO("not implemented")
@@ -88,63 +65,40 @@ private val logggg = object : LoggingContext {
override fun log(message: () -> String) {} override fun log(message: () -> String) {}
} }
private fun deserializeRuntimeMetadata( private fun metadataFileName(moduleName: String) = "$moduleName.${JsKlibMetadataSerializationUtil.CLASS_METADATA_FILE_EXTENSION}"
klibDirFile: File,
moduleName: String,
lookupTracker: LookupTracker,
metadataVersion: JsKlibMetadataVersion,
languageVersionSettings: LanguageVersionSettings
): ModuleDescriptor {
val metadataFile = File(klibDirFile, metadataFileName(moduleName))
val storageManager = LockBasedStorageManager("JsConfig")
val serializer = JsKlibMetadataSerializationUtil
val parts = serializer.readModuleAsProto(metadataFile.readBytes())
val builtIns = object : KotlinBuiltIns(storageManager) {}//analysisResult.moduleDescriptor.builtIns
val md = ModuleDescriptorImpl(Name.special("<$moduleName>"), storageManager, builtIns)
builtIns.builtInsModule = md
val packageProviders = listOf(
functionInterfacePackageFragmentProvider(storageManager, md),
createJsKlibMetadataPackageFragmentProvider(
storageManager, md, parts.header, parts.body, metadataVersion,
CompilerDeserializationConfiguration(languageVersionSettings),
lookupTracker
)
)
md.initialize(CompositePackageFragmentProvider(packageProviders))
md.setDependencies(listOf(md))
return md
}
private fun deserializeRuntimeIr( data class JsKlib(
moduleDescriptor: ModuleDescriptor, val moduleDescriptor: ModuleDescriptorImpl,
klibDirFile: File, val moduleIr: IrModuleFragment,
deserializeDeclaration: Boolean, val symbolTable: SymbolTable,
symbolTable: SymbolTable, val irBuiltIns: IrBuiltIns,
irBuiltIns: IrBuiltIns val deserializer: IrKlibProtoBufModuleDeserializer
): IrModuleFragment { )
val moduleFile = File(klibDirFile, moduleHeaderFileName)
val deserializer = IrKlibProtoBufModuleDeserializer(
moduleDescriptor,
logggg,
irBuiltIns,
klibDirFile,
symbolTable,
null
)
return deserializer.deserializeIrModule(moduleDescriptor, moduleFile.readBytes(), deserializeDeclaration)
}
private fun deserializerRuntimeKlib(
private fun deserializeModuleFromKlib(
locationDir: String, locationDir: String,
moduleName: String, moduleName: String,
lookupTracker: LookupTracker, lookupTracker: LookupTracker,
storageManager: LockBasedStorageManager,
metadataVersion: JsKlibMetadataVersion, metadataVersion: JsKlibMetadataVersion,
languageVersionSettings: LanguageVersionSettings, languageVersionSettings: LanguageVersionSettings,
deserializeDeclaration: Boolean dependencies: List<CompiledModule>,
builtinsModule: ModuleDescriptorImpl?
): JsKlib { ): JsKlib {
val klibDirFile = File(locationDir) val klibDirFile = File(locationDir)
val md = deserializeRuntimeMetadata(klibDirFile, moduleName, lookupTracker, metadataVersion, languageVersionSettings) val md = loadKlibMetadata(
moduleName,
locationDir,
builtinsModule == null,
lookupTracker,
storageManager,
metadataVersion,
languageVersionSettings,
builtinsModule,
dependencies
)
val st = SymbolTable() val st = SymbolTable()
val typeTranslator = TypeTranslator(st, languageVersionSettings).also { val typeTranslator = TypeTranslator(st, languageVersionSettings).also {
@@ -153,9 +107,17 @@ private fun deserializerRuntimeKlib(
val irBuiltIns = IrBuiltIns(md.builtIns, typeTranslator, st) val irBuiltIns = IrBuiltIns(md.builtIns, typeTranslator, st)
val moduleFragment = deserializeRuntimeIr(md, klibDirFile, deserializeDeclaration, st, irBuiltIns) val moduleFile = File(klibDirFile, moduleHeaderFileName)
val deserializer = IrKlibProtoBufModuleDeserializer(md, logggg, irBuiltIns, st, null)
return JsKlib(md, moduleFragment, st, irBuiltIns) dependencies.forEach {
val dependencyKlibDir = File(it.klibPath, moduleHeaderFileName)
deserializer.deserializeIrModule(it.moduleDescriptor!!, dependencyKlibDir.readBytes(), File(it.klibPath), false)
}
val moduleFragment = deserializer.deserializeIrModule(md, moduleFile.readBytes(), klibDirFile, true)
return JsKlib(md, moduleFragment, st, irBuiltIns, deserializer)
} }
fun compile( fun compile(
@@ -163,247 +125,235 @@ fun compile(
files: List<KtFile>, files: List<KtFile>,
configuration: CompilerConfiguration, configuration: CompilerConfiguration,
export: List<FqName> = emptyList(), export: List<FqName> = emptyList(),
compileMode: CompilationMode = CompilationMode.TEST_AGAINST_CACHE, compileMode: CompilationMode,
dependencies: List<CompiledModule> = emptyList(), dependencies: List<CompiledModule> = emptyList(),
builtInsModule: CompiledModule? = null, klibPath: String
moduleType: ModuleType
): CompiledModule { ): CompiledModule {
return when (compileMode) {
CompilationMode.KLIB, CompilationMode.KLIB_WITH_JS ->
compileIntoKlib(files, project, configuration, dependencies, builtInsModule, moduleType, compileMode.generateJS)
CompilationMode.TEST_AGAINST_CACHE ->
compileIntoJsAgainstCachedDeps(files, project, configuration, dependencies, builtInsModule, moduleType)
CompilationMode.TEST_AGAINST_KLIB -> compileIntoJsAgainstKlib(files, project, configuration, dependencies, moduleType)
}
}
private fun compileIntoJsAgainstKlib(
files: List<KtFile>,
project: Project,
configuration: CompilerConfiguration,
dependencies: List<CompiledModule>,
moduleType: ModuleType
): CompiledModule {
val runtimeKlib = File(runtimeKlibPath)
val metadataVersion = configuration.get(CommonConfigurationKeys.METADATA_VERSION) as? JsKlibMetadataVersion val metadataVersion = configuration.get(CommonConfigurationKeys.METADATA_VERSION) as? JsKlibMetadataVersion
?: JsKlibMetadataVersion.INSTANCE ?: JsKlibMetadataVersion.INSTANCE
val lookupTracker = configuration.get(CommonConfigurationKeys.LOOKUP_TRACKER, LookupTracker.DO_NOTHING) val lookupTracker = LookupTracker.DO_NOTHING
val languageSettings = configuration.languageVersionSettings val languageSettings = configuration.languageVersionSettings
val storageManeger = LockBasedStorageManager("JsDepencencies")
val runtimeModule = deserializeRuntimeMetadata( val dfsHandler: MetadataDFSHandler = DependencyMetadataLoader(lookupTracker, metadataVersion, languageSettings, storageManeger)
runtimeKlib, val sortedDeps = DFS.dfs(dependencies, CompiledModule::dependencies, dfsHandler)
JS_IR_RUNTIME_MODULE_NAME, val builtInModule = sortedDeps.firstOrNull()?.moduleDescriptor // null in case compiling builtInModule itself
lookupTracker,
metadataVersion,
languageSettings
)
val analysisResult = val analysisResult =
TopDownAnalyzerFacadeForJS.analyzeFiles( TopDownAnalyzerFacadeForJS.analyzeFiles(
files, files,
project, project,
configuration, configuration,
sortedDeps.mapNotNull { it.moduleDescriptor },
emptyList(), emptyList(),
emptyList(), thisIsBuiltInsModule = builtInModule == null,
thisIsBuiltInsModule = false, customBuiltInsModule = builtInModule
customBuiltInsModule = runtimeModule as ModuleDescriptorImpl
) )
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled() ProgressIndicatorAndCompilationCanceledStatus.checkCanceled()
TopDownAnalyzerFacadeForJS.checkForErrors(files, analysisResult.bindingContext) TopDownAnalyzerFacadeForJS.checkForErrors(files, analysisResult.bindingContext)
val moduleDescriptor = analysisResult.moduleDescriptor as ModuleDescriptorImpl
val symbolTable = SymbolTable() val symbolTable = SymbolTable()
val psi2IrTranslator = Psi2IrTranslator(languageSettings) val psi2IrTranslator = Psi2IrTranslator(languageSettings)
val psi2IrContext = psi2IrTranslator.createGeneratorContext(analysisResult.moduleDescriptor, analysisResult.bindingContext, symbolTable) val psi2IrContext = psi2IrTranslator.createGeneratorContext(moduleDescriptor, analysisResult.bindingContext, symbolTable)
val moduleFile = File(runtimeKlib, moduleHeaderFileName) val irBuiltIns = psi2IrContext.irBuiltIns
val deserializer = IrKlibProtoBufModuleDeserializer(
runtimeModule,
logggg,
psi2IrContext.irBuiltIns,
runtimeKlib,
symbolTable,
null
)
val runtimeModuleFragment = deserializer.deserializeIrModule(runtimeModule, moduleFile.readBytes(), false)
val moduleFragment = psi2IrTranslator.generateModuleFragment(psi2IrContext, files, deserializer) var deserializer = IrKlibProtoBufModuleDeserializer(moduleDescriptor, logggg, irBuiltIns, symbolTable, null)
val context = JsIrBackendContext( val deserializedModuleFragments = sortedDeps.map {
analysisResult.moduleDescriptor, val moduleFile = File(it.klibPath, moduleHeaderFileName)
psi2IrContext.irBuiltIns, deserializer.deserializeIrModule(it.moduleDescriptor!!, moduleFile.readBytes(), File(it.klibPath), false)
psi2IrContext.symbolTable,
moduleFragment,
configuration,
dependencies,
moduleType
)
ExternalDependenciesGenerator(
runtimeModuleFragment.descriptor,
context.symbolTable,
context.irBuiltIns,
deserializer
).generateUnboundSymbolsAsDependencies(runtimeModuleFragment)
val files = runtimeModuleFragment.files + moduleFragment.files
moduleFragment.files.clear()
moduleFragment.files += files
moduleFragment.patchDeclarationParents()
jsPhases.invokeToplevel(context.phaseConfig, context, moduleFragment)
val jsProgram = moduleFragment.accept(IrModuleToJsTransformer(context), null)
return CompiledModule(project.name, jsProgram.toString(), null, moduleType, emptyList())
}
private fun compileIntoJsAgainstCachedDeps(
files: List<KtFile>,
project: Project,
configuration: CompilerConfiguration,
dependencies: List<CompiledModule>,
builtInsModule: CompiledModule?,
moduleType: ModuleType
): CompiledModule {
val analysisResult =
TopDownAnalyzerFacadeForJS.analyzeFiles(
files,
project,
configuration,
dependencies.map { it.descriptor },
emptyList(),
thisIsBuiltInsModule = builtInsModule == null,
customBuiltInsModule = builtInsModule?.descriptor
)
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled()
TopDownAnalyzerFacadeForJS.checkForErrors(files, analysisResult.bindingContext)
val irDependencies = dependencies.mapNotNull { it.moduleFragment }
val symbolTable = SymbolTable()
irDependencies.forEach { symbolTable.loadModule(it) }
val psi2IrTranslator = Psi2IrTranslator(configuration.languageVersionSettings)
val psi2IrContext = psi2IrTranslator.createGeneratorContext(analysisResult.moduleDescriptor, analysisResult.bindingContext, symbolTable)
val moduleFragment = psi2IrTranslator.generateModuleFragment(psi2IrContext, files)
// TODO: Split compilation into two steps: kt -> ir, ir -> js
val moduleName = configuration[CommonConfigurationKeys.MODULE_NAME]!!
when (moduleType) {
ModuleType.MAIN -> {
val moduleDependencies: List<CompiledModule> =
DFS.topologicalOrder(dependencies, CompiledModule::dependencies)
.filter { it.moduleType == ModuleType.SECONDARY }
val fileDependencies = moduleDependencies.flatMap { it.moduleFragment!!.files }
moduleFragment.files.addAll(0, fileDependencies)
}
ModuleType.SECONDARY -> {
return CompiledModule(moduleName, null, moduleFragment, moduleType, dependencies)
}
ModuleType.TEST_RUNTIME -> {
}
} }
val context = JsIrBackendContext( var moduleFragment = psi2IrTranslator.generateModuleFragment(psi2IrContext, files, deserializer)
analysisResult.moduleDescriptor, val moduleName = configuration.get(CommonConfigurationKeys.MODULE_NAME) as String
psi2IrContext.irBuiltIns,
psi2IrContext.symbolTable,
moduleFragment,
configuration,
dependencies,
moduleType
)
jsPhases.invokeToplevel(context.phaseConfig, context, moduleFragment) val context = if (compileMode.generateKlib) {
deserializedModuleFragments.forEach {
val jsProgram = moduleFragment.accept(IrModuleToJsTransformer(context), null) ExternalDependenciesGenerator(it.descriptor, symbolTable, irBuiltIns, null).generateUnboundSymbolsAsDependencies(it)
}
return CompiledModule(moduleName, jsProgram.toString(), context.moduleFragmentCopy, moduleType, dependencies) deserializedModuleFragments.forEach { it.patchDeclarationParents() }
} serializeModuleIntoKlib(
moduleName,
private fun compileIntoKlib( metadataVersion,
files: List<KtFile>, languageSettings,
project: Project, symbolTable,
configuration: CompilerConfiguration, psi2IrContext.bindingContext,
dependencies: List<CompiledModule>, klibPath,
builtInsModule: CompiledModule?, dependencies,
moduleType: ModuleType, moduleFragment
generateJsCode: Boolean
): CompiledModule {
val analysisResult =
TopDownAnalyzerFacadeForJS.analyzeFiles(
files,
project,
configuration,
dependencies.map { it.descriptor },
emptyList(),
thisIsBuiltInsModule = builtInsModule == null,
customBuiltInsModule = builtInsModule?.descriptor
) )
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled() if (compileMode.generateJS) {
deserializeModuleFromKlib(
klibPath,
moduleName,
lookupTracker,
LockBasedStorageManager("JsDeserialized"),
metadataVersion,
languageSettings,
sortedDeps,
builtInModule
).let {
deserializer = it.deserializer
moduleFragment = it.moduleIr
TopDownAnalyzerFacadeForJS.checkForErrors(files, analysisResult.bindingContext) JsIrBackendContext(it.moduleDescriptor, it.irBuiltIns, it.symbolTable, it.moduleIr, configuration, compileMode).also {
moduleFragment.replaceUnboundSymbols(it)
}
}
} else {
return CompiledModule(moduleName, null, null, klibPath, dependencies, builtInModule == null)
}
} else JsIrBackendContext(moduleDescriptor, irBuiltIns, symbolTable, moduleFragment, configuration, compileMode)
val irDependencies = dependencies.mapNotNull { it.moduleFragment } val jsProgram = if (compileMode.generateJS) {
deserializedModuleFragments.forEach {
ExternalDependenciesGenerator(
it.descriptor,
context.symbolTable,
context.irBuiltIns,
deserializer
).generateUnboundSymbolsAsDependencies(it)
}
val symbolTable = SymbolTable() val irFiles = deserializedModuleFragments.flatMap { it.files } + moduleFragment.files
val psi2IrTranslator = Psi2IrTranslator(configuration.languageVersionSettings) moduleFragment.files.clear()
val psi2IrContext = psi2IrTranslator.createGeneratorContext(analysisResult.moduleDescriptor, analysisResult.bindingContext, symbolTable) moduleFragment.files += irFiles
val moduleFragment = psi2IrTranslator.generateModuleFragment(psi2IrContext, files) ExternalDependenciesGenerator(
moduleDescriptor = context.module,
symbolTable = context.symbolTable,
irBuiltIns = context.irBuiltIns
).generateUnboundSymbolsAsDependencies(moduleFragment)
moduleFragment.patchDeclarationParents()
val declarationTable = DeclarationTable(moduleFragment.irBuiltins, DescriptorTable(), psi2IrContext.symbolTable)
jsPhases.invokeToplevel(context.phaseConfig, context, moduleFragment)
moduleFragment.accept(IrModuleToJsTransformer(context), null)
} else null
return CompiledModule(moduleName, jsProgram?.toString(), null, klibPath, dependencies, builtInModule == null)
}
private fun loadKlibMetadata(
moduleName: String,
klibPath: String,
isBuiltIn: Boolean,
lookupTracker: LookupTracker,
storageManager: LockBasedStorageManager,
metadataVersion: JsKlibMetadataVersion,
languageVersionSettings: LanguageVersionSettings,
builtinsModule: ModuleDescriptorImpl?,
dependencies: List<CompiledModule>
): ModuleDescriptorImpl {
assert(isBuiltIn == (builtinsModule === null))
val metadataFile = File(klibPath, metadataFileName(moduleName))
val serializer = JsKlibMetadataSerializationUtil
val parts = serializer.readModuleAsProto(metadataFile.readBytes())
val builtIns = builtinsModule?.builtIns ?: object : KotlinBuiltIns(storageManager) {}
val md = ModuleDescriptorImpl(Name.special("<$moduleName>"), storageManager, builtIns)
if (isBuiltIn) builtIns.builtInsModule = md
val currentModuleFragmentProvider = createJsKlibMetadataPackageFragmentProvider(
storageManager, md, parts.header, parts.body, metadataVersion,
CompilerDeserializationConfiguration(languageVersionSettings),
lookupTracker
)
val packageFragmentProvider = if (isBuiltIn) {
val functionFragmentProvider = functionInterfacePackageFragmentProvider(storageManager, md)
CompositePackageFragmentProvider(listOf(functionFragmentProvider, currentModuleFragmentProvider))
} else currentModuleFragmentProvider
md.initialize(packageFragmentProvider)
md.setDependencies(listOf(md) + dependencies.mapNotNull { it.moduleDescriptor })
return md
}
typealias MetadataDFSHandler = DFS.NodeHandler<CompiledModule, List<CompiledModule>>
private class DependencyMetadataLoader(
private val lookupTracker: LookupTracker,
private val metadataVersion: JsKlibMetadataVersion,
private val languageVersionSettings: LanguageVersionSettings,
private val storageManager: LockBasedStorageManager
) : MetadataDFSHandler {
private val sortedDependencies = mutableListOf<CompiledModule>()
private var runtimeModule: ModuleDescriptorImpl? = null
override fun beforeChildren(current: CompiledModule) = true
override fun afterChildren(current: CompiledModule) {
val md = current.moduleDescriptor ?: loadKlibMetadata(
current.moduleName,
current.klibPath,
current.isBuiltIn,
lookupTracker,
storageManager,
metadataVersion,
languageVersionSettings,
runtimeModule,
current.dependencies
).also { current.moduleDescriptor = it }
sortedDependencies += current
if (current.isBuiltIn) runtimeModule = md
}
override fun result() = sortedDependencies
}
fun serializeModuleIntoKlib(
moduleName: String,
metadataVersion: JsKlibMetadataVersion,
languageVersionSettings: LanguageVersionSettings,
symbolTable: SymbolTable,
bindingContext: BindingContext,
klibPath: String,
dependencies: List<CompiledModule>,
moduleFragment: IrModuleFragment
) {
val declarationTable = DeclarationTable(moduleFragment.irBuiltins, DescriptorTable(), symbolTable)
val serializedIr = IrModuleSerializer(logggg, declarationTable/*, onlyForInlines = false*/).serializedIrModule(moduleFragment) val serializedIr = IrModuleSerializer(logggg, declarationTable/*, onlyForInlines = false*/).serializedIrModule(moduleFragment)
val serializer = JsKlibMetadataSerializationUtil val serializer = JsKlibMetadataSerializationUtil
val moduleName = configuration.get(CommonConfigurationKeys.MODULE_NAME) as String
val metadataVersion = configuration.get(CommonConfigurationKeys.METADATA_VERSION) as? JsKlibMetadataVersion
?: JsKlibMetadataVersion.INSTANCE
val moduleDescription = val moduleDescription =
JsKlibMetadataModuleDescriptor(moduleName, irDependencies.map { it.name.asString() }, moduleFragment.descriptor) JsKlibMetadataModuleDescriptor(moduleName, dependencies.map { it.moduleName }, moduleFragment.descriptor)
val serializedData = serializer.serializeMetadata( val serializedData = serializer.serializeMetadata(
psi2IrContext.bindingContext, bindingContext,
moduleDescription, moduleDescription,
configuration.get(CommonConfigurationKeys.LANGUAGE_VERSION_SETTINGS)!!, languageVersionSettings,
metadataVersion metadataVersion
) { declarationDescriptor -> ) { declarationDescriptor ->
val index = declarationTable.descriptorTable.get(declarationDescriptor) val index = declarationTable.descriptorTable.get(declarationDescriptor)
index?.let { newDescriptorUniqId(it) } index?.let { newDescriptorUniqId(it) }
} }
val stdKlibDir = File(runtimeKlibPath).also { val klibDir = File(klibPath).also {
it.deleteRecursively() it.deleteRecursively()
it.mkdirs() it.mkdirs()
} }
val moduleFile = File(stdKlibDir, moduleHeaderFileName) val moduleFile = File(klibDir, moduleHeaderFileName)
moduleFile.writeBytes(serializedIr.module) moduleFile.writeBytes(serializedIr.module)
val irDeclarationDir = File(stdKlibDir, declarationsDirName).also { it.mkdir() } val irDeclarationDir = File(klibDir, declarationsDirName).also { it.mkdir() }
for ((id, data) in serializedIr.declarations) { for ((id, data) in serializedIr.declarations) {
val file = File(irDeclarationDir, id.declarationFileName) val file = File(irDeclarationDir, id.declarationFileName)
file.writeBytes(data) file.writeBytes(data)
} }
val debugFile = File(klibDir, debugDataFileName)
val debugFile = File(stdKlibDir, debugDataFileName)
for ((id, data) in serializedIr.debugIndex) { for ((id, data) in serializedIr.debugIndex) {
debugFile.appendText(id.toString()) debugFile.appendText(id.toString())
@@ -412,29 +362,7 @@ private fun compileIntoKlib(
debugFile.appendText("\n") debugFile.appendText("\n")
} }
File(stdKlibDir, "${moduleDescription.name}.${JsKlibMetadataSerializationUtil.CLASS_METADATA_FILE_EXTENSION}").also { File(klibDir, "${moduleDescription.name}.${JsKlibMetadataSerializationUtil.CLASS_METADATA_FILE_EXTENSION}").also {
it.writeBytes(serializedData.asByteArray()) it.writeBytes(serializedData.asByteArray())
} }
}
val jsProgram = if (generateJsCode) {
val lookupTracker = configuration.get(CommonConfigurationKeys.LOOKUP_TRACKER, LookupTracker.DO_NOTHING)
val (md, deserializedModuleFragment, st, irBuiltIns) = deserializerRuntimeKlib(
runtimeKlibPath,
JS_IR_RUNTIME_MODULE_NAME,
lookupTracker,
metadataVersion,
configuration.languageVersionSettings,
true
)
val context = JsIrBackendContext(md, irBuiltIns, st, deserializedModuleFragment, configuration, dependencies, moduleType)
deserializedModuleFragment.replaceUnboundSymbols(context)
jsPhases.invokeToplevel(context.phaseConfig, context, deserializedModuleFragment)
deserializedModuleFragment.accept(IrModuleToJsTransformer(context), null)
} else null
return CompiledModule(moduleName, jsProgram?.toString(), null, moduleType, emptyList())
}
@@ -29,7 +29,7 @@ import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl
import org.jetbrains.kotlin.ir.types.IrSimpleType import org.jetbrains.kotlin.ir.types.IrSimpleType
import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.IrTypeProjection import org.jetbrains.kotlin.ir.types.IrTypeProjection
import org.jetbrains.kotlin.ir.types.toIrType import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
import org.jetbrains.kotlin.ir.util.isInlined import org.jetbrains.kotlin.ir.util.isInlined
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
@@ -211,10 +211,11 @@ class CallableReferenceLowering(val context: JsIrBackendContext) : FileLoweringP
val additionalDeclarations = generateFactoryBodyWithGuard(factoryFunction) { val additionalDeclarations = generateFactoryBodyWithGuard(factoryFunction) {
val statements = mutableListOf<IrStatement>(getterFunction) val statements = mutableListOf<IrStatement>(getterFunction)
val getterFunctionType = context.builtIns.getFunction(getterFunction.valueParameters.size + 1) val getterFunctionTypeSymbol = context.functionN(getterFunction.valueParameters.size + 1)
val type = getterFunctionType.toIrType(symbolTable = context.symbolTable)
val irGetReference = JsIrBuilder.buildFunctionReference(type, getterFunction.symbol) val getterFunctionIrType = IrSimpleTypeImpl(getterFunctionTypeSymbol, false, emptyList(), emptyList())
val irVar = JsIrBuilder.buildVar(type, factoryFunction, initializer = irGetReference) val irGetReference = JsIrBuilder.buildFunctionReference(getterFunctionIrType, getterFunction.symbol)
val irVar = JsIrBuilder.buildVar(getterFunctionIrType, factoryFunction, initializer = irGetReference)
statements += irVar statements += irVar
@@ -226,11 +227,9 @@ class CallableReferenceLowering(val context: JsIrBackendContext) : FileLoweringP
if (setterFunction != null) { if (setterFunction != null) {
statements += setterFunction statements += setterFunction
val setterFunctionType = context.builtIns.getFunction(setterFunction.valueParameters.size + 1) val setterFunctionTypeSymbol = context.functionN(setterFunction.valueParameters.size + 1)
val irSetReference = JsIrBuilder.buildFunctionReference( val setterFunctionIrType = IrSimpleTypeImpl(setterFunctionTypeSymbol, false, emptyList(), emptyList())
setterFunctionType.toIrType(symbolTable = context.symbolTable), val irSetReference = JsIrBuilder.buildFunctionReference(setterFunctionIrType, setterFunction.symbol)
setterFunction.symbol
)
statements += JsIrBuilder.buildCall(context.intrinsics.jsSetJSField.symbol).apply { statements += JsIrBuilder.buildCall(context.intrinsics.jsSetJSField.symbol).apply {
putValueArgument(0, JsIrBuilder.buildGetValue(irVar.symbol)) putValueArgument(0, JsIrBuilder.buildGetValue(irVar.symbol))
putValueArgument(1, setterConst) putValueArgument(1, setterConst)
@@ -282,10 +281,10 @@ class CallableReferenceLowering(val context: JsIrBackendContext) : FileLoweringP
val additionalDeclarations = generateFactoryBodyWithGuard(factoryFunction) { val additionalDeclarations = generateFactoryBodyWithGuard(factoryFunction) {
val statements = mutableListOf<IrStatement>(closureFunction) val statements = mutableListOf<IrStatement>(closureFunction)
val getterFunctionType = context.builtIns.getFunction(closureFunction.valueParameters.size + 1) val getterFunctionTypeSymbol = context.functionN(closureFunction.valueParameters.size + 1)
val type = getterFunctionType.toIrType(symbolTable = context.symbolTable) val getterFunctionIrType = IrSimpleTypeImpl(getterFunctionTypeSymbol, false, emptyList(), emptyList())
val irGetReference = JsIrBuilder.buildFunctionReference(type, closureFunction.symbol) val irGetReference = JsIrBuilder.buildFunctionReference(getterFunctionIrType, closureFunction.symbol)
val irVar = JsIrBuilder.buildVar(type, factoryFunction, initializer = irGetReference) val irVar = JsIrBuilder.buildVar(getterFunctionIrType, factoryFunction, initializer = irGetReference)
val irVarSymbol = irVar.symbol val irVarSymbol = irVar.symbol
statements += irVar statements += irVar
@@ -51,7 +51,7 @@ class JsDefaultArgumentStubGenerator(override val context: JsIrBackendContext) :
private fun resolveInvoke(paramCount: Int): IrSimpleFunction { private fun resolveInvoke(paramCount: Int): IrSimpleFunction {
assert(paramCount > 0) assert(paramCount > 0)
val fqn = FqName.fromSegments(listOf("kotlin", "Function$paramCount")) val fqn = FqName.fromSegments(listOf("kotlin", "Function$paramCount"))
val functionKlass = context.run { symbolTable.lazyWrapper.referenceClass(getClass(fqn)) }.owner val functionKlass = context.functionN(paramCount).owner
return functionKlass.declarations.filterIsInstance<IrSimpleFunction>().first { it.name == Name.identifier("invoke") } return functionKlass.declarations.filterIsInstance<IrSimpleFunction>().first { it.name == Name.identifier("invoke") }
} }
} }
@@ -307,12 +307,12 @@ internal class SuspendFunctionsLowering(val context: JsIrBackendContext): FileLo
if (unboundFunctionParameters != null) { if (unboundFunctionParameters != null) {
// Suspend lambda inherits SuspendFunction. // Suspend lambda inherits SuspendFunction.
val numberOfParameters = unboundFunctionParameters.size val numberOfParameters = unboundFunctionParameters.size
suspendFunctionClass = context.suspendFunctions[numberOfParameters].owner suspendFunctionClass = context.suspendFunctionN(numberOfParameters).owner
val unboundParameterTypes = unboundFunctionParameters.map { it.type } val unboundParameterTypes = unboundFunctionParameters.map { it.type }
suspendFunctionClassTypeArguments = unboundParameterTypes + irFunction.returnType suspendFunctionClassTypeArguments = unboundParameterTypes + irFunction.returnType
superTypes += suspendFunctionClass.typeWith(suspendFunctionClassTypeArguments) superTypes += suspendFunctionClass.typeWith(suspendFunctionClassTypeArguments)
functionClass = context.functions[numberOfParameters + 1].owner functionClass = context.functionN(numberOfParameters + 1).owner
val continuationType = continuationClassSymbol.typeWith(irFunction.returnType) val continuationType = continuationClassSymbol.typeWith(irFunction.returnType)
functionClassTypeArguments = unboundParameterTypes + continuationType + context.irBuiltIns.anyNType functionClassTypeArguments = unboundParameterTypes + continuationType + context.irBuiltIns.anyNType
superTypes += functionClass.typeWith(functionClassTypeArguments) superTypes += functionClass.typeWith(functionClassTypeArguments)
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.ir.backend.js.lower.inline package org.jetbrains.kotlin.ir.backend.js.lower.inline
import org.jetbrains.kotlin.builtins.functions.FunctionClassDescriptor import org.jetbrains.kotlin.builtins.functions.FunctionClassDescriptor
import org.jetbrains.kotlin.builtins.functions.FunctionInvokeDescriptor
import org.jetbrains.kotlin.builtins.getFunctionalClassKind import org.jetbrains.kotlin.builtins.getFunctionalClassKind
import org.jetbrains.kotlin.builtins.isFunctionType import org.jetbrains.kotlin.builtins.isFunctionType
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
@@ -54,11 +55,12 @@ internal val FunctionDescriptor.isFunctionInvoke: Boolean
internal val IrFunction.isFunctionInvoke: Boolean internal val IrFunction.isFunctionInvoke: Boolean
get() { get() {
val dispatchReceiver = dispatchReceiverParameter ?: return false // val dispatchReceiver = dispatchReceiverParameter ?: return false
assert(!dispatchReceiver.type.isKFunction()) // assert(!dispatchReceiver.type.isKFunction())
//
return dispatchReceiver.type.isFunctionTypeOrSubtype() && // return dispatchReceiver.type.isFunctionTypeOrSubtype() &&
/*this.isOperator &&*/ this.name == OperatorNameConventions.INVOKE // /*this.isOperator &&*/ this.name == OperatorNameConventions.INVOKE
return descriptor is FunctionInvokeDescriptor
} }
// It is possible to declare "external inline fun", // It is possible to declare "external inline fun",
@@ -30,7 +30,6 @@ class IrKlibProtoBufModuleDeserializer(
currentModule: ModuleDescriptor, currentModule: ModuleDescriptor,
logger: LoggingContext, logger: LoggingContext,
builtIns: IrBuiltIns, builtIns: IrBuiltIns,
libraryDir: File,
symbolTable: SymbolTable, symbolTable: SymbolTable,
val forwardModuleDescriptor: ModuleDescriptor?) val forwardModuleDescriptor: ModuleDescriptor?)
: IrModuleDeserializer(logger, builtIns, symbolTable) { : IrModuleDeserializer(logger, builtIns, symbolTable) {
@@ -53,8 +52,10 @@ class IrKlibProtoBufModuleDeserializer(
builtIns.builtIns.getBuiltInClassByFqName(it) builtIns.builtIns.getBuiltInClassByFqName(it)
}) })
val moduleRoot = libraryDir val descriptorToDirectoryMap = mutableMapOf<ModuleDescriptor, File>()
val irDirectory = File(libraryDir, "ir/")
// val moduleRoot = libraryDir
private fun irDirectory(m: ModuleDescriptor): File = descriptorToDirectoryMap[m]!!
private val FUNCTION_INDEX_START: Long private val FUNCTION_INDEX_START: Long
@@ -204,7 +205,7 @@ class IrKlibProtoBufModuleDeserializer(
} }
private fun loadTopLevelDeclarationProto(uniqIdKey: UniqIdKey): IrKlibProtoBuf.IrDeclaration { private fun loadTopLevelDeclarationProto(uniqIdKey: UniqIdKey): IrKlibProtoBuf.IrDeclaration {
val file = File(irDirectory, uniqIdKey.uniqId.declarationFileName) val file = File(irDirectory(deserializedModuleDescriptor!!), uniqIdKey.uniqId.declarationFileName)
return IrKlibProtoBuf.IrDeclaration.parseFrom(file.readBytes().codedInputStream, JsKlibMetadataSerializerProtocol.extensionRegistry) return IrKlibProtoBuf.IrDeclaration.parseFrom(file.readBytes().codedInputStream, JsKlibMetadataSerializerProtocol.extensionRegistry)
} }
@@ -347,7 +348,8 @@ class IrKlibProtoBufModuleDeserializer(
return module return module
} }
fun deserializeIrModule(moduleDescriptor: ModuleDescriptor, byteArray: ByteArray, deserializeAllDeclarations: Boolean = false): IrModuleFragment { fun deserializeIrModule(moduleDescriptor: ModuleDescriptor, byteArray: ByteArray, klibLocation: File, deserializeAllDeclarations: Boolean = false): IrModuleFragment {
descriptorToDirectoryMap[moduleDescriptor] = File(klibLocation, "ir/")
val proto = IrKlibProtoBuf.IrModule.parseFrom(byteArray.codedInputStream, JsKlibMetadataSerializerProtocol.extensionRegistry) val proto = IrKlibProtoBuf.IrModule.parseFrom(byteArray.codedInputStream, JsKlibMetadataSerializerProtocol.extensionRegistry)
return deserializeIrModule(proto, moduleDescriptor, deserializeAllDeclarations) return deserializeIrModule(proto, moduleDescriptor, deserializeAllDeclarations)
} }
@@ -8,7 +8,6 @@ package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs
import org.jetbrains.kotlin.config.CommonConfigurationKeys import org.jetbrains.kotlin.config.CommonConfigurationKeys
import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
import org.jetbrains.kotlin.ir.backend.js.ModuleType
import org.jetbrains.kotlin.ir.backend.js.utils.* import org.jetbrains.kotlin.ir.backend.js.utils.*
import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrDeclarationWithVisibility import org.jetbrains.kotlin.ir.declarations.IrDeclarationWithVisibility
@@ -187,11 +186,8 @@ class IrModuleToJsTransformer(private val backendContext: JsIrBackendContext) :
} }
override fun visitModuleFragment(declaration: IrModuleFragment, data: Nothing?): JsNode = override fun visitModuleFragment(declaration: IrModuleFragment, data: Nothing?): JsNode =
when (backendContext.moduleType) { if (backendContext.compilationMode.generateKlib) generateModuleInGlobalScope(declaration)
ModuleType.MAIN -> generateModule(declaration) else generateModule(declaration)
ModuleType.SECONDARY -> JsEmpty
ModuleType.TEST_RUNTIME -> generateModuleInGlobalScope(declaration)
}
private fun processClassModels( private fun processClassModels(
@@ -114,14 +114,11 @@ class SimpleNameGenerator : NameGenerator {
} }
if (declaration.name.isSpecial || declaration.visibility == Visibilities.LOCAL) { nameDeclarator = context.staticContext.rootScope::declareFreshName
if (declaration.descriptor !is DeserializedClassDescriptor) { if (declaration.kind == ClassKind.OBJECT || declaration.name.isSpecial || declaration.visibility == Visibilities.LOCAL) {
// TODO: temporary workaround for Unit instance
nameDeclarator = context.staticContext.rootScope::declareFreshName
}
val parent = declaration.parent val parent = declaration.parent
when (parent) { when (parent) {
is IrDeclarationWithName -> nameBuilder.append(getNameForDeclaration(parent, context)) is IrDeclaration -> nameBuilder.append(getNameForDeclaration(parent, context))
is IrPackageFragment -> nameBuilder.append(parent.fqName.asString()) is IrPackageFragment -> nameBuilder.append(parent.fqName.asString())
} }
} }
@@ -61,11 +61,13 @@ class ExternalDependenciesGenerator(
deserializer?.declareForwardDeclarations() deserializer?.declareForwardDeclarations()
// assert(symbolTable.unboundClasses.isEmpty()) if (deserializer != null) return
assert(symbolTable.unboundClasses.isEmpty())
assert(symbolTable.unboundConstructors.isEmpty()) assert(symbolTable.unboundConstructors.isEmpty())
assert(symbolTable.unboundEnumEntries.isEmpty()) assert(symbolTable.unboundEnumEntries.isEmpty())
assert(symbolTable.unboundFields.isEmpty()) assert(symbolTable.unboundFields.isEmpty())
// assert(symbolTable.unboundSimpleFunctions.isEmpty()) assert(symbolTable.unboundSimpleFunctions.isEmpty())
assert(symbolTable.unboundTypeParameters.isEmpty()) assert(symbolTable.unboundTypeParameters.isEmpty())
} }
} }
@@ -56,10 +56,11 @@ object TopDownAnalyzerFacadeForJS {
"Can't simultaneously use custom built-ins module and set current module as built-ins" "Can't simultaneously use custom built-ins module and set current module as built-ins"
} }
val projectContext = ProjectContext(project) val projectContext = ProjectContext(project)
val builtIns = if (thisIsBuiltInsModule || customBuiltInsModule != null) {
object : KotlinBuiltIns(projectContext.storageManager) {} val builtIns = when {
} else { thisIsBuiltInsModule -> object : KotlinBuiltIns(projectContext.storageManager) {}
JsPlatform.builtIns customBuiltInsModule != null -> customBuiltInsModule.builtIns
else -> JsPlatform.builtIns
} }
val moduleName = configuration[CommonConfigurationKeys.MODULE_NAME]!! val moduleName = configuration[CommonConfigurationKeys.MODULE_NAME]!!
@@ -72,10 +73,6 @@ object TopDownAnalyzerFacadeForJS {
val additionalPackages = mutableListOf<PackageFragmentProvider>() val additionalPackages = mutableListOf<PackageFragmentProvider>()
if (customBuiltInsModule != null) {
builtIns.builtInsModule = customBuiltInsModule
}
if (thisIsBuiltInsModule) { if (thisIsBuiltInsModule) {
builtIns.builtInsModule = context.module builtIns.builtInsModule = context.module
additionalPackages += functionInterfacePackageFragmentProvider(context.storageManager, context.module) additionalPackages += functionInterfacePackageFragmentProvider(context.storageManager, context.module)
@@ -13,13 +13,11 @@ import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
import org.jetbrains.kotlin.config.* import org.jetbrains.kotlin.config.*
import org.jetbrains.kotlin.ir.backend.js.CompilationMode import org.jetbrains.kotlin.ir.backend.js.CompilationMode
import org.jetbrains.kotlin.ir.backend.js.ModuleType
import org.jetbrains.kotlin.ir.backend.js.compile import org.jetbrains.kotlin.ir.backend.js.compile
import org.jetbrains.kotlin.js.config.JSConfigurationKeys import org.jetbrains.kotlin.js.config.JSConfigurationKeys
import org.jetbrains.kotlin.js.test.JsIrTestRuntime import org.jetbrains.kotlin.js.test.JsIrTestRuntime
import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.serialization.js.ModuleKind import org.jetbrains.kotlin.serialization.js.ModuleKind
import org.jetbrains.kotlin.test.KotlinTestUtils
import java.io.File import java.io.File
fun buildConfiguration(environment: KotlinCoreEnvironment): CompilerConfiguration { fun buildConfiguration(environment: KotlinCoreEnvironment): CompilerConfiguration {
@@ -42,9 +40,8 @@ fun buildConfiguration(environment: KotlinCoreEnvironment): CompilerConfiguratio
return runtimeConfiguration return runtimeConfiguration
} }
private val stdKlibFile = File("js/js.translator/testData/out/klibs/stdlib.klib")
private val resultJs = "js/js.translator/testData/out/klibs/result.js" private val resultJs = "js/js.translator/testData/out/klibs/result.js"
private val runtimeKlibPath = "js/js.translator/testData/out/klibs/runtime/"
fun main() { fun main() {
@@ -66,11 +63,8 @@ fun main() {
emptyList(), emptyList(),
CompilationMode.KLIB_WITH_JS, CompilationMode.KLIB_WITH_JS,
emptyList(), emptyList(),
null, runtimeKlibPath
ModuleType.TEST_RUNTIME
) )
File(resultJs).writeText(result.generatedCode!!) result.generatedCode?.let { File(resultJs).writeText(it) }
// TODO("Write library into $stdKlibFile")
} }
@@ -5,11 +5,8 @@
package org.jetbrains.kotlin.js.test package org.jetbrains.kotlin.js.test
import com.intellij.openapi.util.io.FileUtil
import com.intellij.openapi.util.text.StringUtil
import org.jetbrains.kotlin.config.* import org.jetbrains.kotlin.config.*
import org.jetbrains.kotlin.ir.backend.js.CompilationMode import org.jetbrains.kotlin.ir.backend.js.CompilationMode
import org.jetbrains.kotlin.ir.backend.js.ModuleType
import org.jetbrains.kotlin.ir.backend.js.CompiledModule import org.jetbrains.kotlin.ir.backend.js.CompiledModule
import org.jetbrains.kotlin.ir.backend.js.compile import org.jetbrains.kotlin.ir.backend.js.compile
import org.jetbrains.kotlin.js.config.JSConfigurationKeys import org.jetbrains.kotlin.js.config.JSConfigurationKeys
@@ -17,12 +14,17 @@ import org.jetbrains.kotlin.js.config.JsConfig
import org.jetbrains.kotlin.js.facade.MainCallParameters import org.jetbrains.kotlin.js.facade.MainCallParameters
import org.jetbrains.kotlin.js.facade.TranslationUnit import org.jetbrains.kotlin.js.facade.TranslationUnit
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.test.KotlinTestUtils
import org.jetbrains.kotlin.test.TargetBackend import org.jetbrains.kotlin.test.TargetBackend
import java.io.File import java.io.File
private var runtimeResults = mutableMapOf<JsIrTestRuntime, CompiledModule>() private var runtimeResults = mutableMapOf<JsIrTestRuntime, CompiledModule>()
private val runtimeKlibPath = "js/js.translator/testData/out/klibs/runtime/"
private val JS_IR_RUNTIME_MODULE_NAME = "JS_IR_RUNTIME"
private val runtimeKlib = CompiledModule(JS_IR_RUNTIME_MODULE_NAME, null, null, runtimeKlibPath, emptyList(), true)
abstract class BasicIrBoxTest( abstract class BasicIrBoxTest(
pathToTestDir: String, pathToTestDir: String,
testGroupOutputDirPrefix: String, testGroupOutputDirPrefix: String,
@@ -80,31 +82,8 @@ abstract class BasicIrBoxTest(
) )
) )
val runtimeConfiguration = config.configuration.copy()
// TODO: is it right in general? Maybe sometimes we need to compile with newer versions or with additional language features.
runtimeConfiguration.languageVersionSettings = LanguageVersionSettingsImpl(
LanguageVersion.LATEST_STABLE, ApiVersion.LATEST_STABLE,
specificFeatures = mapOf(
LanguageFeature.AllowContractsForCustomFunctions to LanguageFeature.State.ENABLED,
LanguageFeature.MultiPlatformProjects to LanguageFeature.State.ENABLED
),
analysisFlags = mapOf(
AnalysisFlags.useExperimental to listOf("kotlin.contracts.ExperimentalContracts", "kotlin.Experimental"),
AnalysisFlags.allowResultReturnType to true
)
)
val runtimeFile = File(runtime.path)
val runtimeResult = runtimeResults.getOrPut(runtime) {
runtimeConfiguration.put(CommonConfigurationKeys.MODULE_NAME, "JS_IR_RUNTIME")
val result = compile(config.project, runtime.sources.map(::createPsiFile), runtimeConfiguration, moduleType = ModuleType.TEST_RUNTIME)
runtimeFile.write(result.generatedCode!!)
result
}
val dependencyNames = config.configuration[JSConfigurationKeys.LIBRARIES]!!.map { File(it).name } val dependencyNames = config.configuration[JSConfigurationKeys.LIBRARIES]!!.map { File(it).name }
val dependencies = listOf(runtimeResult) + dependencyNames.mapNotNull { val dependencies = listOf(runtimeKlib) + dependencyNames.mapNotNull {
compilationCache[it] compilationCache[it]
} }
@@ -113,25 +92,26 @@ abstract class BasicIrBoxTest(
// config.configuration.put(CommonConfigurationKeys.PHASES_TO_DUMP_STATE_AFTER, setOf("MultipleCatchesLowering")) // config.configuration.put(CommonConfigurationKeys.PHASES_TO_DUMP_STATE_AFTER, setOf("MultipleCatchesLowering"))
// config.configuration.put(CommonConfigurationKeys.PHASES_TO_VALIDATE, setOf("ALL")) // config.configuration.put(CommonConfigurationKeys.PHASES_TO_VALIDATE, setOf("ALL"))
val actualOutputFile = outputFile.absolutePath.let {
if (!isMainModule) it.replace("_v5.js", "/") else it
}
val result = compile( val result = compile(
config.project, config.project,
filesToCompile, filesToCompile,
config.configuration, config.configuration,
listOf(FqName((testPackage?.let { "$it." } ?: "") + testFunction)), listOf(FqName((testPackage?.let { "$it." } ?: "") + testFunction)),
CompilationMode.TEST_AGAINST_CACHE,//CompilationMode.TEST_AGAINST_KLIB, if (isMainModule) CompilationMode.JS_AGAINST_KLIB else CompilationMode.KLIB,
dependencies, dependencies,
runtimeResult, klibPath = actualOutputFile
moduleType = if (isMainModule) ModuleType.MAIN else ModuleType.SECONDARY
) )
compilationCache[outputFile.name.replace(".js", ".meta.js")] = result compilationCache[outputFile.name.replace(".js", ".meta.js")] = result
val generatedCode = result.generatedCode val generatedCode = result.generatedCode
if (generatedCode != null) { if (generatedCode != null) {
// Prefix to help node.js runner find runtime
val runtimePrefix = "// RUNTIME: [\"${runtimeFile.path}\"]\n"
val wrappedCode = wrapWithModuleEmulationMarkers(generatedCode, moduleId = config.moduleId, moduleKind = config.moduleKind) val wrappedCode = wrapWithModuleEmulationMarkers(generatedCode, moduleId = config.moduleId, moduleKind = config.moduleKind)
outputFile.write(runtimePrefix + wrappedCode) outputFile.write(wrappedCode)
} }
} }
@@ -146,7 +126,8 @@ abstract class BasicIrBoxTest(
) { ) {
// TODO: should we do anything special for module systems? // TODO: should we do anything special for module systems?
// TODO: return list of js from translateFiles and provide then to this function with other js files // TODO: return list of js from translateFiles and provide then to this function with other js files
nashornIrJsTestCheckers[runtime]!!.check(jsFiles, testModuleName, null, testFunction, expectedResult, withModuleSystem)
NashornIrJsTestChecker().check(jsFiles, testModuleName, null, testFunction, expectedResult, withModuleSystem)
} }
} }
@@ -147,20 +147,15 @@ object NashornJsTestChecker : AbstractNashornJsTestChecker() {
} }
} }
class NashornIrJsTestChecker(private val runtime: JsIrTestRuntime) : AbstractNashornJsTestChecker() { class NashornIrJsTestChecker : AbstractNashornJsTestChecker() {
override fun createScriptEngineForTest(): ScriptEngine { override fun createScriptEngineForTest(): ScriptEngine {
val engine = createScriptEngine() val engine = createScriptEngine()
listOf( listOfNotNull(
BasicBoxTest.TEST_DATA_DIR_PATH + "nashorn-polyfills.js", BasicBoxTest.TEST_DATA_DIR_PATH + "nashorn-polyfills.js",
"libraries/stdlib/js/src/js/polyfills.js", "libraries/stdlib/js/src/js/polyfills.js"
runtime.path
).forEach(engine::loadFile) ).forEach(engine::loadFile)
return engine return engine
} }
} }
val nashornIrJsTestCheckers = JsIrTestRuntime.values().associate {
it to NashornIrJsTestChecker(it)
}