[JS IR BE] Initial support for mudule wrapper generation

This commit is contained in:
Svyatoslav Kuzmich
2019-01-31 19:04:37 +03:00
parent d8b1d09566
commit 0ff23544fc
42 changed files with 628 additions and 148 deletions
@@ -48,7 +48,8 @@ class JsIrBackendContext(
val symbolTable: SymbolTable,
irModuleFragment: IrModuleFragment,
override val configuration: CompilerConfiguration,
val dependencies: List<IrModuleFragment>
val dependencies: List<CompiledModule>,
val moduleType: ModuleType
) : CommonBackendContext {
override val builtIns = module.builtIns
@@ -56,6 +57,9 @@ class JsIrBackendContext(
val phaseConfig = PhaseConfig(jsPhases, configuration)
override var inVerbosePhase: Boolean = false
val packageLevelJsModules = mutableListOf<IrFile>()
val declarationLevelJsModules = mutableListOf<IrDeclaration>()
val internalPackageFragmentDescriptor = KnownPackageFragmentDescriptor(builtIns.builtInsModule, FqName("kotlin.js.internal"))
val implicitDeclarationFile by lazy {
IrFileImpl(object : SourceManager.FileEntry {
@@ -176,9 +180,6 @@ class JsIrBackendContext(
val originalModuleIndex = ModuleIndex(irModuleFragment)
lateinit var moduleFragmentCopy: IrModuleFragment
lateinit var jsProgram: JsNode
fun getOperatorByName(name: Name, type: KotlinType) = operatorMap[name]?.get(type)
override val ir = object : Ir<CommonBackendContext>(this, irModuleFragment) {
@@ -291,4 +292,4 @@ class JsIrBackendContext(
/*TODO*/
print(message)
}
}
}
@@ -10,16 +10,13 @@ import org.jetbrains.kotlin.backend.common.lower.*
import org.jetbrains.kotlin.backend.common.phaser.*
import org.jetbrains.kotlin.ir.backend.js.lower.*
import org.jetbrains.kotlin.ir.backend.js.lower.calls.CallsLowering
import org.jetbrains.kotlin.ir.backend.js.lower.coroutines.CoroutineIntrinsicLowering
import org.jetbrains.kotlin.ir.backend.js.lower.coroutines.SuspendFunctionsLowering
import org.jetbrains.kotlin.ir.backend.js.lower.inline.FunctionInlining
import org.jetbrains.kotlin.ir.backend.js.lower.inline.RemoveInlineFunctionsWithReifiedTypeParametersLowering
import org.jetbrains.kotlin.ir.backend.js.lower.inline.ReturnableBlockLowering
import org.jetbrains.kotlin.ir.backend.js.lower.inline.replaceUnboundSymbols
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.IrModuleToJsTransformer
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
import org.jetbrains.kotlin.ir.util.deepCopyWithSymbols
import org.jetbrains.kotlin.ir.util.patchDeclarationParents
private fun DeclarationContainerLoweringPass.runOnFilesPostfix(files: Iterable<IrFile>) = files.forEach { runOnFilePostfix(it) }
@@ -68,8 +65,10 @@ private fun makeCustomJsModulePhase(
}
)
private val moveBodilessDeclarationsToSeparatePlacePhase = makeJsModulePhase(
::MoveBodilessDeclarationsToSeparatePlace,
private val moveBodilessDeclarationsToSeparatePlacePhase = makeCustomJsModulePhase(
{ context, module ->
moveBodilessDeclarationsToSeparatePlace(context, module)
},
name = "MoveBodilessDeclarationsToSeparatePlace",
description = "Move `external` and `built-in` declarations into separate place to make the following lowerings do not care about them"
)
@@ -80,12 +79,6 @@ private val expectDeclarationsRemovingPhase = makeJsModulePhase(
description = "Remove expect declaration from module fragment"
)
private val coroutineIntrinsicLoweringPhase = makeJsModulePhase(
::CoroutineIntrinsicLowering,
name = "CoroutineIntrinsicLowering",
description = "Replace common coroutine intrinsics with platform specific ones"
)
private val arrayInlineConstructorLoweringPhase = makeJsModulePhase(
::ArrayInlineConstructorLowering,
name = "ArrayInlineConstructorLowering",
@@ -98,13 +91,6 @@ private val lateinitLoweringPhase = makeJsModulePhase(
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(
{ context, module ->
FunctionInlining(context).inline(module)
@@ -113,7 +99,7 @@ private val functionInliningPhase = makeCustomJsModulePhase(
},
name = "FunctionInliningPhase",
description = "Perform function inlining",
prerequisite = setOf(moduleCopyingPhase, lateinitLoweringPhase, arrayInlineConstructorLoweringPhase, coroutineIntrinsicLoweringPhase)
prerequisite = setOf(lateinitLoweringPhase, arrayInlineConstructorLoweringPhase)
)
private val removeInlineFunctionsWithReifiedTypeParametersLoweringPhase = makeJsModulePhase(
@@ -196,7 +182,7 @@ private val suspendFunctionsLoweringPhase = makeJsModulePhase(
::SuspendFunctionsLowering,
name = "SuspendFunctionsLowering",
description = "Transform suspend functions into CoroutineImpl instance and build state machine",
prerequisite = setOf(unitMaterializationLoweringPhase, coroutineIntrinsicLoweringPhase)
prerequisite = setOf(unitMaterializationLoweringPhase)
)
private val privateMembersLoweringPhase = makeJsModulePhase(
@@ -347,21 +333,13 @@ private val callsLoweringPhase = makeJsModulePhase(
description = "Handle intrinsics"
)
private val irToJsPhase = makeCustomJsModulePhase(
{ context, module -> context.jsProgram = IrModuleToJsTransformer(context).let { module.accept(it, null) } },
name = "IrModuleToJsTransformer",
description = "Generate JsAst from IrTree"
)
val jsPhases = namedIrModulePhase(
name = "IrModuleLowering",
description = "IR module lowering",
lower = moveBodilessDeclarationsToSeparatePlacePhase then
expectDeclarationsRemovingPhase then
coroutineIntrinsicLoweringPhase then
arrayInlineConstructorLoweringPhase then
lateinitLoweringPhase then
moduleCopyingPhase then
functionInliningPhase then
removeInlineFunctionsWithReifiedTypeParametersLoweringPhase then
throwableSuccessorsLoweringPhase then
@@ -396,6 +374,5 @@ val jsPhases = namedIrModulePhase(
blockDecomposerLoweringPhase then
primitiveCompanionLoweringPhase then
constLoweringPhase then
callsLoweringPhase then
irToJsPhase
)
callsLoweringPhase
)
@@ -7,38 +7,57 @@ package org.jetbrains.kotlin.ir.backend.js
import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.backend.common.phaser.invokeToplevel
import org.jetbrains.kotlin.config.CommonConfigurationKeys
import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.config.languageVersionSettings
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
import org.jetbrains.kotlin.ir.backend.js.lower.coroutines.CoroutineIntrinsicLowering
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.IrModuleToJsTransformer
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
import org.jetbrains.kotlin.ir.util.SymbolTable
import org.jetbrains.kotlin.ir.util.deepCopyWithSymbols
import org.jetbrains.kotlin.js.analyze.TopDownAnalyzerFacadeForJS
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStatus
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi2ir.Psi2IrTranslator
import org.jetbrains.kotlin.utils.DFS
data class Result(val moduleDescriptor: ModuleDescriptor, val generatedCode: String, val moduleFragment: IrModuleFragment)
enum class ModuleType {
TEST_RUNTIME,
SECONDARY,
MAIN
}
class CompiledModule(
val moduleName: String,
val generatedCode: String?,
val moduleFragment: IrModuleFragment?,
val moduleType: ModuleType,
val dependencies: List<CompiledModule>
) {
val descriptor
get() = moduleFragment!!.descriptor as ModuleDescriptorImpl
}
fun compile(
project: Project,
files: List<KtFile>,
configuration: CompilerConfiguration,
export: FqName? = null,
dependencies: List<ModuleDescriptor> = listOf(),
irDependencyModules: List<IrModuleFragment> = listOf(),
builtInsModule: ModuleDescriptorImpl? = null
): Result {
export: List<FqName> = emptyList(),
dependencies: List<CompiledModule> = emptyList(),
builtInsModule: CompiledModule? = null,
moduleType: ModuleType
): CompiledModule {
val analysisResult =
TopDownAnalyzerFacadeForJS.analyzeFiles(
files,
project,
configuration,
dependencies.mapNotNull { it as? ModuleDescriptorImpl },
dependencies.map { it.descriptor },
emptyList(),
thisIsBuiltInsModule = builtInsModule == null,
customBuiltInsModule = builtInsModule
customBuiltInsModule = builtInsModule?.descriptor
)
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled()
@@ -46,7 +65,7 @@ fun compile(
TopDownAnalyzerFacadeForJS.checkForErrors(files, analysisResult.bindingContext)
val symbolTable = SymbolTable()
irDependencyModules.forEach { symbolTable.loadModule(it)}
dependencies.forEach { symbolTable.loadModule(it.moduleFragment!!) }
val psi2IrTranslator = Psi2IrTranslator(configuration.languageVersionSettings)
val psi2IrContext = psi2IrTranslator.createGeneratorContext(analysisResult.moduleDescriptor, analysisResult.bindingContext, symbolTable)
@@ -59,10 +78,43 @@ fun compile(
psi2IrContext.symbolTable,
moduleFragment,
configuration,
irDependencyModules
dependencies,
moduleType
)
// CoroutineIntrinsicLowering currently have to be applied to dependencies
// before running inline pass for current module.
// Therefore we run it here before producing ir for current module.
// TODO: Find a better way to implement coroutine intrinsics
val coroutineIntrinsicLowering = CoroutineIntrinsicLowering(context)
moduleFragment.files.forEach { file -> coroutineIntrinsicLowering.lower(file) }
// TODO: Split compilation into two steps: kt -> ir, ir -> js
val moduleName = configuration[CommonConfigurationKeys.MODULE_NAME]!!
var moduleFragmentCopy: IrModuleFragment? = null
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 -> {
moduleFragmentCopy = moduleFragment.deepCopyWithSymbols()
}
}
jsPhases.invokeToplevel(context.phaseConfig, context, moduleFragment)
return Result(analysisResult.moduleDescriptor, context.jsProgram.toString(), context.moduleFragmentCopy)
}
val jsProgram = moduleFragment.accept(IrModuleToJsTransformer(context), null)
return CompiledModule(moduleName, jsProgram.toString(), moduleFragmentCopy, moduleType, dependencies)
}
@@ -5,25 +5,22 @@
package org.jetbrains.kotlin.ir.backend.js.lower
import org.jetbrains.kotlin.backend.common.FileLoweringPass
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
import org.jetbrains.kotlin.ir.backend.js.lower.inline.addChild
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
import org.jetbrains.kotlin.ir.declarations.IrExternalPackageFragment
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.backend.js.utils.getJsModule
import org.jetbrains.kotlin.ir.backend.js.utils.getJsQualifier
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrExternalPackageFragmentImpl
import org.jetbrains.kotlin.ir.symbols.IrExternalPackageFragmentSymbol
import org.jetbrains.kotlin.ir.util.isEffectivelyExternal
import org.jetbrains.kotlin.ir.util.transformFlat
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
class MoveBodilessDeclarationsToSeparatePlace() : FileLoweringPass {
fun moveBodilessDeclarationsToSeparatePlace(context: JsIrBackendContext, module: IrModuleFragment) {
constructor(context: JsIrBackendContext) : this()
private val builtInClasses = listOf(
val builtInClasses = listOf(
"String",
"Nothing",
"Array",
@@ -44,10 +41,10 @@ class MoveBodilessDeclarationsToSeparatePlace() : FileLoweringPass {
"Double"
).map { Name.identifier(it) }.toSet()
private fun isBuiltInClass(declaration: IrDeclaration): Boolean =
fun isBuiltInClass(declaration: IrDeclaration): Boolean =
declaration is IrClass && declaration.name in builtInClasses
private val packageFragment = IrExternalPackageFragmentImpl(object : IrExternalPackageFragmentSymbol {
val packageFragment = IrExternalPackageFragmentImpl(object : IrExternalPackageFragmentSymbol {
override val descriptor: PackageFragmentDescriptor
get() = error("Operation is unsupported")
@@ -61,16 +58,31 @@ class MoveBodilessDeclarationsToSeparatePlace() : FileLoweringPass {
}
}, FqName.ROOT)
override fun lower(irFile: IrFile) {
fun lowerFile(irFile: IrFile): IrFile? {
if (irFile.getJsModule() != null || irFile.getJsQualifier() != null) {
context.packageLevelJsModules.add(irFile)
return null
}
val it = irFile.declarations.iterator()
while (it.hasNext()) {
val d = it.next()
if (d.isEffectivelyExternal() || isBuiltInClass(d)) {
if (d.getJsModule() != null)
context.declarationLevelJsModules.add(d)
it.remove()
packageFragment.addChild(d)
}
}
return irFile
}
}
module.files.transformFlat { irFile ->
listOfNotNull(lowerFile(irFile))
}
}
@@ -5,47 +5,174 @@
package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs
import org.jetbrains.kotlin.config.CommonConfigurationKeys
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
import org.jetbrains.kotlin.ir.backend.js.ModuleType
import org.jetbrains.kotlin.ir.backend.js.utils.JsGenerationContext
import org.jetbrains.kotlin.ir.backend.js.utils.Namer
import org.jetbrains.kotlin.ir.backend.js.utils.getJsModule
import org.jetbrains.kotlin.ir.backend.js.utils.getJsQualifier
import org.jetbrains.kotlin.ir.declarations.IrDeclarationWithVisibility
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
import org.jetbrains.kotlin.ir.declarations.IrSymbolOwner
import org.jetbrains.kotlin.ir.util.isEffectivelyExternal
import org.jetbrains.kotlin.js.backend.ast.*
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
import org.jetbrains.kotlin.utils.DFS
class IrModuleToJsTransformer(private val backendContext: JsIrBackendContext) : BaseIrElementToJsNodeTransformer<JsNode, Nothing?> {
override fun visitModuleFragment(declaration: IrModuleFragment, data: Nothing?): JsNode {
val program = JsProgram()
val rootContext = JsGenerationContext(JsRootScope(program), backendContext)
val moduleName = backendContext.configuration[CommonConfigurationKeys.MODULE_NAME]!!
private val moduleKind = backendContext.configuration[JSConfigurationKeys.MODULE_KIND]!!
private fun generateModuleBody(module: IrModuleFragment, context: JsGenerationContext): List<JsStatement> {
val statements = mutableListOf<JsStatement>()
// TODO: fix it up with new name generator
val anyName = rootContext.getNameForSymbol(backendContext.irBuiltIns.anyClass)
val throwableName = rootContext.getNameForSymbol(backendContext.irBuiltIns.throwableClass)
val anyName = context.getNameForSymbol(backendContext.irBuiltIns.anyClass)
val throwableName = context.getNameForSymbol(backendContext.irBuiltIns.throwableClass)
program.globalBlock.statements += JsVars(JsVars.JsVar(anyName, Namer.JS_OBJECT))
program.globalBlock.statements += JsVars(JsVars.JsVar(throwableName, Namer.JS_ERROR))
statements += JsVars(JsVars.JsVar(anyName, Namer.JS_OBJECT))
statements += JsVars(JsVars.JsVar(throwableName, Namer.JS_ERROR))
val preDeclarationBlock = JsGlobalBlock()
val postDeclarationBlock = JsGlobalBlock()
val preDeclarationBlock = JsBlock()
val postDeclarationBlock = JsBlock()
program.globalBlock.statements += preDeclarationBlock
statements += preDeclarationBlock
declaration.files.forEach {
program.globalBlock.statements.add(it.accept(IrFileToJsTransformer(), rootContext))
module.files.forEach {
statements.add(it.accept(IrFileToJsTransformer(), context))
}
// sort member forwarding code
processClassModels(rootContext.staticContext.classModels, preDeclarationBlock, postDeclarationBlock)
processClassModels(context.staticContext.classModels, preDeclarationBlock, postDeclarationBlock)
program.globalBlock.statements += postDeclarationBlock
program.globalBlock.statements += rootContext.staticContext.initializerBlock
statements += postDeclarationBlock
statements += context.staticContext.initializerBlock
return statements
}
private fun findModuleExports(module: IrModuleFragment, context: JsGenerationContext): Map<JsName, JsName> {
val publicDeclarations = module.files
.flatMap { it.declarations }
.filterIsInstance<IrDeclarationWithVisibility>()
.filter { it.visibility == Visibilities.PUBLIC }
.filter { !it.isEffectivelyExternal() }
.filterIsInstance<IrSymbolOwner>()
val publicDeclarationNames = publicDeclarations.map {
context.getNameForSymbol(it.symbol)
}
return publicDeclarationNames.associate { it to it }
}
private fun generateModuleInGlobalScope(module: IrModuleFragment): JsProgram {
val program = JsProgram()
val rootContext = JsGenerationContext(JsRootScope(program), backendContext)
val moduleBody = generateModuleBody(module, rootContext)
program.globalBlock.statements += moduleBody
return program
}
private fun generateModule(module: IrModuleFragment): JsProgram {
val program = JsProgram()
val rootContext = JsGenerationContext(JsRootScope(program), backendContext)
val rootFunction = JsFunction(program.rootScope, JsBlock(), "root function")
val internalModuleName = rootFunction.scope.declareName("_")
rootFunction.parameters += JsParameter(internalModuleName)
val declarationLevelJsModules =
backendContext.declarationLevelJsModules.map { externalDeclaration ->
val jsModule = externalDeclaration.getJsModule()!!
val name = rootContext.getNameForDeclaration(externalDeclaration)
JsImportedModule(jsModule, name, name.makeRef())
}
val packageLevelJsModules = mutableListOf<JsImportedModule>()
val importStatements = mutableListOf<JsStatement>()
for (file in backendContext.packageLevelJsModules) {
val jsModule = file.getJsModule()
val jsQualifier = file.getJsQualifier()
assert(jsModule != null || jsQualifier != null)
val qualifiedReference: JsNameRef
if (jsModule != null) {
val internalName = rootFunction.scope.declareFreshName("moduleImport")
packageLevelJsModules += JsImportedModule(jsModule, internalName, null)
qualifiedReference =
if (jsQualifier == null)
internalName.makeRef()
else
JsNameRef(jsQualifier, internalName.makeRef())
} else {
qualifiedReference = JsNameRef(jsQualifier!!)
}
file.declarations.forEach { declaration ->
val declName = rootContext.getNameForDeclaration(declaration)
importStatements.add(
JsExpressionStatement(
jsAssignment(
declName.makeRef(),
JsNameRef(declName, qualifiedReference)
)
)
)
}
}
val importedJsModules = declarationLevelJsModules + packageLevelJsModules
rootFunction.parameters += importedJsModules.map { JsParameter(it.internalName) }
rootFunction.body.statements += importStatements
val moduleBody = generateModuleBody(module, rootContext)
val moduleExports = findModuleExports(module, rootContext)
val exportStatements = moduleExports.map { (from, to) ->
JsExpressionStatement(jsAssignment(JsNameRef(from, internalModuleName.makeRef()), to.makeRef()))
}
rootFunction.body.statements += moduleBody
rootFunction.body.statements += exportStatements
rootFunction.body.statements += JsReturn(internalModuleName.makeRef())
program.globalBlock.statements += ModuleWrapperTranslation.wrap(
moduleName,
rootFunction,
importedJsModules,
program,
kind = moduleKind
)
return program
}
override fun visitModuleFragment(declaration: IrModuleFragment, data: Nothing?): JsNode =
when (backendContext.moduleType) {
ModuleType.MAIN -> generateModule(declaration)
ModuleType.SECONDARY -> JsEmpty
ModuleType.TEST_RUNTIME -> generateModuleInGlobalScope(declaration)
}
private fun processClassModels(
classModelMap: Map<JsName, JsClassModel>,
preDeclarationBlock: JsGlobalBlock,
postDeclarationBlock: JsGlobalBlock
preDeclarationBlock: JsBlock,
postDeclarationBlock: JsBlock
) {
val declarationHandler = object : DFS.AbstractNodeHandler<JsName, Unit>() {
override fun result() {}
@@ -0,0 +1,162 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. 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.ir.backend.js.transformers.irToJs
import org.jetbrains.kotlin.js.backend.ast.*
import org.jetbrains.kotlin.serialization.js.ModuleKind
object ModuleWrapperTranslation {
object Namer {
fun requiresEscaping(name: String) = false
}
fun wrap(
moduleId: String, function: JsExpression, importedModules: List<JsImportedModule>,
program: JsProgram, kind: ModuleKind
): List<JsStatement> {
return when (kind) {
ModuleKind.AMD -> wrapAmd(function, importedModules, program)
ModuleKind.COMMON_JS -> wrapCommonJs(function, importedModules, program)
ModuleKind.UMD -> wrapUmd(moduleId, function, importedModules, program)
ModuleKind.PLAIN -> wrapPlain(moduleId, function, importedModules, program)
}
}
private fun wrapUmd(
moduleId: String, function: JsExpression,
importedModules: List<JsImportedModule>, program: JsProgram
): List<JsStatement> {
val scope = program.scope
val defineName = scope.declareName("define")
val exportsName = scope.declareName("exports")
val adapterBody = JsBlock()
val adapter = JsFunction(program.scope, adapterBody, "Adapter")
val rootName = adapter.scope.declareName("root")
val factoryName = adapter.scope.declareName("factory")
adapter.parameters += JsParameter(rootName)
adapter.parameters += JsParameter(factoryName)
val amdTest = JsAstUtils.and(JsAstUtils.typeOfIs(defineName.makeRef(), JsStringLiteral("function")),
JsNameRef("amd", defineName.makeRef()))
val commonJsTest = JsAstUtils.typeOfIs(exportsName.makeRef(), JsStringLiteral("object"))
val amdBody = JsBlock(wrapAmd(factoryName.makeRef(), importedModules, program))
val commonJsBody = JsBlock(wrapCommonJs(factoryName.makeRef(), importedModules, program))
val plainInvocation = makePlainInvocation(moduleId, factoryName.makeRef(), importedModules, program)
val lhs: JsExpression = if (Namer.requiresEscaping(moduleId)) {
JsArrayAccess(rootName.makeRef(), JsStringLiteral(moduleId))
}
else {
JsNameRef(scope.declareName(moduleId), rootName.makeRef())
}
val plainBlock = JsBlock()
for (importedModule in importedModules) {
plainBlock.statements += addModuleValidation(moduleId, program, importedModule)
}
plainBlock.statements += JsAstUtils.assignment(lhs, plainInvocation).makeStmt()
val selector = JsAstUtils.newJsIf(amdTest, amdBody, JsAstUtils.newJsIf(commonJsTest, commonJsBody, plainBlock))
adapterBody.statements += selector
return listOf(JsInvocation(adapter, JsThisRef(), function).makeStmt())
}
private fun wrapAmd(
function: JsExpression,
importedModules: List<JsImportedModule>, program: JsProgram
): List<JsStatement> {
val scope = program.scope
val defineName = scope.declareName("define")
val invocationArgs = listOf(
JsArrayLiteral(listOf(JsStringLiteral("exports")) + importedModules.map { JsStringLiteral(it.externalName) }),
function
)
val invocation = JsInvocation(defineName.makeRef(), invocationArgs)
return listOf(invocation.makeStmt())
}
private fun wrapCommonJs(
function: JsExpression,
importedModules: List<JsImportedModule>,
program: JsProgram
): List<JsStatement> {
val scope = program.scope
val moduleName = scope.declareName("module")
val requireName = scope.declareName("require")
val invocationArgs = importedModules.map { JsInvocation(requireName.makeRef(), JsStringLiteral(it.externalName)) }
val invocation = JsInvocation(function, listOf(JsNameRef("exports", moduleName.makeRef())) + invocationArgs)
return listOf(invocation.makeStmt())
}
private fun wrapPlain(
moduleId: String, function: JsExpression,
importedModules: List<JsImportedModule>, program: JsProgram
): List<JsStatement> {
val invocation = makePlainInvocation(moduleId, function, importedModules, program)
val statements = mutableListOf<JsStatement>()
for (importedModule in importedModules) {
statements += addModuleValidation(moduleId, program, importedModule)
}
statements += if (Namer.requiresEscaping(moduleId)) {
JsAstUtils.assignment(makePlainModuleRef(moduleId, program), invocation).makeStmt()
}
else {
JsAstUtils.newVar(program.rootScope.declareName(moduleId), invocation)
}
return statements
}
private fun addModuleValidation(
currentModuleId: String,
program: JsProgram,
module: JsImportedModule
): JsStatement {
val moduleRef = makePlainModuleRef(module, program)
val moduleExistsCond = JsAstUtils.typeOfIs(moduleRef, JsStringLiteral("undefined"))
val moduleNotFoundMessage = JsStringLiteral(
"Error loading module '" + currentModuleId + "'. Its dependency '" + module.externalName + "' was not found. " +
"Please, check whether '" + module.externalName + "' is loaded prior to '" + currentModuleId + "'.")
val moduleNotFoundThrow = JsThrow(JsNew(JsNameRef("Error"), listOf<JsExpression>(moduleNotFoundMessage)))
return JsIf(moduleExistsCond, JsBlock(moduleNotFoundThrow))
}
private fun makePlainInvocation(
moduleId: String,
function: JsExpression,
importedModules: List<JsImportedModule>,
program: JsProgram
): JsInvocation {
val invocationArgs = importedModules.map { makePlainModuleRef(it, program) }
val moduleRef = makePlainModuleRef(moduleId, program)
val testModuleDefined = JsAstUtils.typeOfIs(moduleRef, JsStringLiteral("undefined"))
val selfArg = JsConditional(testModuleDefined, JsObjectLiteral(false), moduleRef.deepCopy())
return JsInvocation(function, listOf(selfArg) + invocationArgs)
}
private fun makePlainModuleRef(module: JsImportedModule, program: JsProgram): JsExpression {
return module.plainReference ?: makePlainModuleRef(module.externalName, program)
}
private fun makePlainModuleRef(moduleId: String, program: JsProgram): JsExpression {
// TODO: we could use `this.moduleName` syntax. However, this does not work for `kotlin` module in Rhino, since
// we run kotlin.js in a parent scope. Consider better solution
return if (Namer.requiresEscaping(moduleId)) {
JsArrayAccess(JsThisRef(), JsStringLiteral(moduleId))
}
else {
program.scope.declareName(moduleId).makeRef()
}
}
}
@@ -87,3 +87,107 @@ fun defineProperty(receiver: JsExpression, name: String, value: () -> JsExpressi
val objectDefineProperty = JsNameRef("defineProperty", Namer.JS_OBJECT)
return JsInvocation(objectDefineProperty, receiver, JsStringLiteral(name), value())
}
// Partially copied from org.jetbrains.kotlin.js.translate.utils.JsAstUtils
object JsAstUtils {
private fun deBlockIfPossible(statement: JsStatement): JsStatement {
return if (statement is JsBlock && statement.statements.size == 1) {
statement.statements[0]
} else {
statement
}
}
fun newJsIf(
ifExpression: JsExpression,
thenStatement: JsStatement,
elseStatement: JsStatement? = null
): JsIf {
var elseStatement = elseStatement
elseStatement = if (elseStatement != null) deBlockIfPossible(elseStatement) else null
return JsIf(ifExpression, deBlockIfPossible(thenStatement), elseStatement)
}
fun and(op1: JsExpression, op2: JsExpression): JsBinaryOperation {
return JsBinaryOperation(JsBinaryOperator.AND, op1, op2)
}
fun or(op1: JsExpression, op2: JsExpression): JsBinaryOperation {
return JsBinaryOperation(JsBinaryOperator.OR, op1, op2)
}
fun equality(arg1: JsExpression, arg2: JsExpression): JsBinaryOperation {
return JsBinaryOperation(JsBinaryOperator.REF_EQ, arg1, arg2)
}
fun inequality(arg1: JsExpression, arg2: JsExpression): JsBinaryOperation {
return JsBinaryOperation(JsBinaryOperator.REF_NEQ, arg1, arg2)
}
fun lessThanEq(arg1: JsExpression, arg2: JsExpression): JsBinaryOperation {
return JsBinaryOperation(JsBinaryOperator.LTE, arg1, arg2)
}
fun lessThan(arg1: JsExpression, arg2: JsExpression): JsBinaryOperation {
return JsBinaryOperation(JsBinaryOperator.LT, arg1, arg2)
}
fun greaterThan(arg1: JsExpression, arg2: JsExpression): JsBinaryOperation {
return JsBinaryOperation(JsBinaryOperator.GT, arg1, arg2)
}
fun greaterThanEq(arg1: JsExpression, arg2: JsExpression): JsBinaryOperation {
return JsBinaryOperation(JsBinaryOperator.GTE, arg1, arg2)
}
fun assignment(left: JsExpression, right: JsExpression): JsBinaryOperation {
return JsBinaryOperation(JsBinaryOperator.ASG, left, right)
}
fun assignmentToThisField(fieldName: String, right: JsExpression): JsStatement {
return assignment(JsNameRef(fieldName, JsThisRef()), right).source(right.source).makeStmt()
}
fun decomposeAssignment(expr: JsExpression): Pair<JsExpression, JsExpression>? {
if (expr !is JsBinaryOperation) return null
return if (expr.operator != JsBinaryOperator.ASG) null else Pair(expr.arg1, expr.arg2)
}
fun sum(left: JsExpression, right: JsExpression): JsBinaryOperation {
return JsBinaryOperation(JsBinaryOperator.ADD, left, right)
}
fun addAssign(left: JsExpression, right: JsExpression): JsBinaryOperation {
return JsBinaryOperation(JsBinaryOperator.ASG_ADD, left, right)
}
fun subtract(left: JsExpression, right: JsExpression): JsBinaryOperation {
return JsBinaryOperation(JsBinaryOperator.SUB, left, right)
}
fun mul(left: JsExpression, right: JsExpression): JsBinaryOperation {
return JsBinaryOperation(JsBinaryOperator.MUL, left, right)
}
fun div(left: JsExpression, right: JsExpression): JsBinaryOperation {
return JsBinaryOperation(JsBinaryOperator.DIV, left, right)
}
fun mod(left: JsExpression, right: JsExpression): JsBinaryOperation {
return JsBinaryOperation(JsBinaryOperator.MOD, left, right)
}
fun not(expression: JsExpression): JsPrefixOperation {
return JsPrefixOperation(JsUnaryOperator.NOT, expression)
}
fun typeOfIs(expression: JsExpression, string: JsStringLiteral): JsBinaryOperation {
return equality(JsPrefixOperation(JsUnaryOperator.TYPEOF, expression), string)
}
fun newVar(name: JsName, expr: JsExpression?): JsVars {
return JsVars(JsVars.JsVar(name, expr))
}
}
@@ -0,0 +1,35 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. 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.ir.backend.js.utils
import org.jetbrains.kotlin.ir.declarations.IrAnnotationContainer
import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.expressions.IrConst
import org.jetbrains.kotlin.ir.util.getAnnotation
import org.jetbrains.kotlin.ir.util.hasAnnotation
import org.jetbrains.kotlin.name.FqName
object JsAnnotations {
val jsModuleFqn = FqName("kotlin.js.JsModule")
val jsNonModuleFqn = FqName("kotlin.js.JsNonModule")
val jsNameFqn = FqName("kotlin.js.JsName")
val jsQualifierFqn = FqName("kotlin.js.JsQualifier")
}
private fun IrCall.getSingleConstStringArgument() =
(getValueArgument(0) as IrConst<String>).value
fun IrAnnotationContainer.getJsModule(): String? =
getAnnotation(JsAnnotations.jsModuleFqn)?.getSingleConstStringArgument()
fun IrAnnotationContainer.isJsNonModule(): Boolean =
hasAnnotation(JsAnnotations.jsNonModuleFqn)
fun IrAnnotationContainer.getJsQualifier(): String? =
getAnnotation(JsAnnotations.jsQualifierFqn)?.getSingleConstStringArgument()
fun IrAnnotationContainer.getJsName(): String? =
getAnnotation(JsAnnotations.jsNameFqn)?.getSingleConstStringArgument()
@@ -6,8 +6,7 @@
package org.jetbrains.kotlin.ir.backend.js.utils
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.IrLoop
import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.ir.types.IrType
@@ -44,6 +43,12 @@ class JsGenerationContext {
this.currentFunction = func
}
fun getNameForDeclaration(declaration: IrDeclaration): JsName = when (declaration) {
is IrSymbolOwner -> getNameForSymbol(declaration.symbol)
is IrProperty -> currentScope.declareName(declaration.name.identifier)
else -> error("Unsupported")
}
fun getNameForSymbol(symbol: IrSymbol): JsName = staticContext.getNameForSymbol(symbol, this)
fun getNameForType(type: IrType): JsName = staticContext.getNameForType(type, this)
fun getNameForLoop(loop: IrLoop): JsName? = staticContext.getNameForLoop(loop, this)
@@ -5,7 +5,6 @@
package org.jetbrains.kotlin.ir.backend.js.utils
import org.jetbrains.kotlin.backend.common.ir.isStatic
import org.jetbrains.kotlin.backend.common.ir.isTopLevel
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.ir.declarations.*
@@ -13,7 +12,6 @@ import org.jetbrains.kotlin.ir.expressions.IrLoop
import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.classifierOrFail
import org.jetbrains.kotlin.ir.types.isUnit
import org.jetbrains.kotlin.ir.util.isDynamic
import org.jetbrains.kotlin.ir.util.isEffectivelyExternal
import org.jetbrains.kotlin.ir.util.isInlined
@@ -102,6 +100,11 @@ class SimpleNameGenerator : NameGenerator {
return@getOrPut nameDeclarator(declaration.descriptor.name.asString())
}
val jsName = declaration.getJsName()
if (jsName != null) {
return@getOrPut context.currentScope.declareName(jsName)
}
if (declaration.isEffectivelyExternal()) {
// TODO: descriptors are still used here due to the corresponding declaration doesn't have enough information yet
val descriptorForName = when (descriptor) {
@@ -379,6 +379,11 @@ tailrec fun IrElement.getPackageFragment(): IrPackageFragment? {
}
}
fun IrAnnotationContainer.getAnnotation(name: FqName) =
annotations.find {
it.symbol.owner.parentAsClass.descriptor.fqNameSafe == name
}
fun IrAnnotationContainer.hasAnnotation(name: FqName) =
annotations.any {
it.symbol.owner.parentAsClass.descriptor.fqNameSafe == name
-1
View File
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
class IntRange {
operator fun contains(a: Int) = (1..2).contains(a)
}
@@ -126,6 +126,9 @@ abstract class BasicBoxTest(
val testPackage = testFactory.testPackage
val testFunction = TEST_FUNCTION
val mainModuleName = if (TEST_MODULE in modules) TEST_MODULE else DEFAULT_MODULE
val mainModule = modules[mainModuleName] ?: error("No module with name \"$mainModuleName\"")
val generatedJsFiles = orderedModules.asReversed().mapNotNull { module ->
val dependencies = module.dependencies.map { modules[it]?.outputFileName(outputDir) + ".meta.js" }
val friends = module.friends.map { modules[it]?.outputFileName(outputDir) + ".meta.js" }
@@ -135,15 +138,12 @@ abstract class BasicBoxTest(
file.parent, module, outputFileName, dependencies, friends, modules.size > 1,
!SKIP_SOURCEMAP_REMAPPING.matcher(fileContent).find(),
outputPrefixFile, outputPostfixFile, actualMainCallParameters, testPackage, testFunction,
runtimeType
runtimeType, isMainModule = (mainModuleName == module.name)
)
if (!module.name.endsWith(OLD_MODULE_SUFFIX)) Pair(outputFileName, module) else null
}
val mainModuleName = if (TEST_MODULE in modules) TEST_MODULE else DEFAULT_MODULE
val mainModule = modules[mainModuleName] ?: error("No module with name \"$mainModuleName\"")
val globalCommonFiles = JsTestUtils.getFilesInDirectoryByExtension(COMMON_FILES_DIR_PATH, JavaScript.EXTENSION)
val localCommonFile = file.parent + "/" + COMMON_FILES_NAME + JavaScript.DOT_EXTENSION
val localCommonFiles = if (File(localCommonFile).exists()) listOf(localCommonFile) else emptyList()
@@ -315,7 +315,8 @@ abstract class BasicBoxTest(
mainCallParameters: MainCallParameters,
testPackage: String?,
testFunction: String,
runtime: JsIrTestRuntime
runtime: JsIrTestRuntime,
isMainModule: Boolean
) {
val kotlinFiles = module.files.filter { it.fileName.endsWith(".kt") }
val testFiles = kotlinFiles.map { it.fileName }
@@ -337,7 +338,7 @@ abstract class BasicBoxTest(
val incrementalData = IncrementalData()
translateFiles(
psiFiles.map(TranslationUnit::SourceFile), outputFile, config, outputPrefixFile, outputPostfixFile,
mainCallParameters, incrementalData, remap, testPackage, testFunction, runtime
mainCallParameters, incrementalData, remap, testPackage, testFunction, runtime, isMainModule
)
if (incrementalCompilationChecksEnabled && module.hasFilesToRecompile) {
@@ -385,7 +386,7 @@ abstract class BasicBoxTest(
translateFiles(
translationUnits, recompiledOutputFile, recompiledConfig, outputPrefixFile, outputPostfixFile,
mainCallParameters, incrementalData, remap, testPackage, testFunction, runtime
mainCallParameters, incrementalData, remap, testPackage, testFunction, runtime, false
)
val originalOutput = FileUtil.loadFile(outputFile)
@@ -450,7 +451,8 @@ abstract class BasicBoxTest(
remap: Boolean,
testPackage: String?,
testFunction: String,
runtime: JsIrTestRuntime
runtime: JsIrTestRuntime,
isMainModule: Boolean
) {
val translator = K2JSTranslator(config)
val translationResult = translator.translateUnits(ExceptionThrowingReporter, units, mainCallParameters)
@@ -467,18 +469,9 @@ abstract class BasicBoxTest(
val outputDir = outputFile.parentFile ?: error("Parent file for output file should not be null, outputFilePath: " + outputFile.path)
outputFiles.writeAllTo(outputDir)
if (config.moduleKind == ModuleKind.COMMON_JS) {
if (config.moduleKind != ModuleKind.PLAIN) {
val content = FileUtil.loadFile(outputFile, true)
val wrappedContent = "$KOTLIN_TEST_INTERNAL.beginModule();\n" +
"$content\n" +
"$KOTLIN_TEST_INTERNAL.endModule(\"${StringUtil.escapeStringCharacters(config.moduleId)}\");"
FileUtil.writeToFile(outputFile, wrappedContent)
}
else if (config.moduleKind == ModuleKind.AMD || config.moduleKind == ModuleKind.UMD) {
val content = FileUtil.loadFile(outputFile, true)
val wrappedContent = "if (typeof $KOTLIN_TEST_INTERNAL !== \"undefined\") { " +
"$KOTLIN_TEST_INTERNAL.setModuleId(\"${StringUtil.escapeStringCharacters(config.moduleId)}\"); }\n" +
"$content\n"
val wrappedContent = wrapWithModuleEmulationMarkers(content, moduleId = config.moduleId, moduleKind = config.moduleKind)
FileUtil.writeToFile(outputFile, wrappedContent)
}
@@ -496,6 +489,28 @@ abstract class BasicBoxTest(
checkSourceMap(outputFile, translationResult.program, remap)
}
protected fun wrapWithModuleEmulationMarkers(
content: String,
moduleKind: ModuleKind,
moduleId: String
): String {
val escapedModuleId = StringUtil.escapeStringCharacters(moduleId)
return when (moduleKind) {
ModuleKind.COMMON_JS -> "$KOTLIN_TEST_INTERNAL.beginModule();\n" +
"$content\n" +
"$KOTLIN_TEST_INTERNAL.endModule(\"$escapedModuleId\");"
ModuleKind.AMD, ModuleKind.UMD ->
"if (typeof $KOTLIN_TEST_INTERNAL !== \"undefined\") { " +
"$KOTLIN_TEST_INTERNAL.setModuleId(\"$escapedModuleId\"); }\n" +
"$content\n"
ModuleKind.PLAIN -> content
}
}
private fun processJsProgram(program: JsProgram, psiFiles: List<KtFile>) {
psiFiles.asSequence()
.map { it.text }
@@ -5,20 +5,21 @@
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.descriptors.impl.ModuleDescriptorImpl
import org.jetbrains.kotlin.ir.backend.js.Result
import org.jetbrains.kotlin.ir.backend.js.ModuleType
import org.jetbrains.kotlin.ir.backend.js.CompiledModule
import org.jetbrains.kotlin.ir.backend.js.compile
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
import org.jetbrains.kotlin.js.config.JsConfig
import org.jetbrains.kotlin.js.facade.MainCallParameters
import org.jetbrains.kotlin.js.facade.TranslationUnit
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.test.KotlinTestUtils
import org.jetbrains.kotlin.test.TargetBackend
import java.io.File
private var runtimeResults = mutableMapOf<JsIrTestRuntime, Result>()
private var runtimeResults = mutableMapOf<JsIrTestRuntime, CompiledModule>()
abstract class BasicIrBoxTest(
pathToTestDir: String,
@@ -41,7 +42,7 @@ abstract class BasicIrBoxTest(
// TODO Design incremental compilation for IR and add test support
override val incrementalCompilationChecksEnabled = false
private val compilationCache = mutableMapOf<String, Result>()
private val compilationCache = mutableMapOf<String, CompiledModule>()
override fun doTest(filePath: String, expectedResult: String, mainCallParameters: MainCallParameters, coroutinesPackage: String) {
compilationCache.clear()
@@ -59,7 +60,8 @@ abstract class BasicIrBoxTest(
remap: Boolean,
testPackage: String?,
testFunction: String,
runtime: JsIrTestRuntime
runtime: JsIrTestRuntime,
isMainModule: Boolean
) {
val filesToCompile = units
.map { (it as TranslationUnit.SourceFile).file }
@@ -94,14 +96,15 @@ abstract class BasicIrBoxTest(
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)
runtimeFile.write(result.generatedCode)
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 dependencies = listOf(runtimeResult.moduleDescriptor) + dependencyNames.mapNotNull { compilationCache[it]?.moduleDescriptor }
val irDependencies = listOf(runtimeResult.moduleFragment) + compilationCache.values.map { it.moduleFragment }
val dependencies = listOf(runtimeResult) + dependencyNames.mapNotNull {
compilationCache[it]
}
// config.configuration.put(CommonConfigurationKeys.PHASES_TO_DUMP_STATE, setOf("UnitMaterializationLowering"))
// config.configuration.put(CommonConfigurationKeys.PHASES_TO_DUMP_STATE_BEFORE, setOf("ReturnableBlockLowering"))
@@ -112,18 +115,21 @@ abstract class BasicIrBoxTest(
config.project,
filesToCompile,
config.configuration,
FqName((testPackage?.let { "$it." } ?: "") + testFunction),
listOf(FqName((testPackage?.let { "$it." } ?: "") + testFunction)),
dependencies,
irDependencies,
runtimeResult.moduleDescriptor as ModuleDescriptorImpl
runtimeResult,
moduleType = if (isMainModule) ModuleType.MAIN else ModuleType.SECONDARY
)
compilationCache[outputFile.name.replace(".js", ".meta.js")] = result
// Prefix to help node.js runner find runtime
val runtimePrefix = "// RUNTIME: [\"${runtimeFile.path}\"]\n"
outputFile.write(runtimePrefix + result.generatedCode)
val generatedCode = result.generatedCode
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)
outputFile.write(runtimePrefix + wrappedCode)
}
}
override fun runGeneratedCode(
@@ -137,7 +143,7 @@ abstract class BasicIrBoxTest(
) {
// 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
nashornIrJsTestCheckers[runtime]!!.check(jsFiles, null, null, testFunction, expectedResult, false)
nashornIrJsTestCheckers[runtime]!!.check(jsFiles, testModuleName, null, testFunction, expectedResult, withModuleSystem)
}
}
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
// EXPECTED_REACHABLE_NODES: 1316
// MODULE: lib1
// FILE: lib1.js
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
// EXPECTED_REACHABLE_NODES: 1316
// MODULE: lib-1
// FILE: lib-1.js
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
// EXPECTED_REACHABLE_NODES: 1284
// MODULE: lib1
// FILE: lib1.js
-1
View File
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
// EXPECTED_REACHABLE_NODES: 1283
// MODULE: lib
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
// EXPECTED_REACHABLE_NODES: 1284
// MODULE: lib1
// FILE: lib1.kt
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
// EXPECTED_REACHABLE_NODES: 1284
// MODULE_KIND: AMD
package foo
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
// EXPECTED_REACHABLE_NODES: 1284
// MODULE_KIND: AMD
package foo
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
// EXPECTED_REACHABLE_NODES: 1286
// MODULE_KIND: UMD
package foo
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
// EXPECTED_REACHABLE_NODES: 1288
// MODULE_KIND: UMD
// NO_JS_MODULE_SYSTEM
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
// EXPECTED_REACHABLE_NODES: 1290
// MODULE_KIND: AMD
// FILE: lib.kt
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
// EXPECTED_REACHABLE_NODES: 1290
// FILE: a.kt
// MODULE_KIND: UMD
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
// EXPECTED_REACHABLE_NODES: 1284
// MODULE_KIND: AMD
package foo
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
// EXPECTED_REACHABLE_NODES: 1283
// MODULE_KIND: COMMON_JS
// FUNCTION_CALLED_TIMES: require count=2
-1
View File
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
// EXPECTED_REACHABLE_NODES: 1282
// MODULE: lib
// FILE: lib.kt
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
// EXPECTED_REACHABLE_NODES: 1284
// MODULE: lib
// FILE: lib.kt
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
// EXPECTED_REACHABLE_NODES: 1282
// MODULE: lib
// FILE: lib.kt
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
// EXPECTED_REACHABLE_NODES: 1289
// MODULE: lib
// FILE: lib.kt
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
// EXPECTED_REACHABLE_NODES: 1284
// MODULE: module-1
// FILE: bar.kt
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
// EXPECTED_REACHABLE_NODES: 1284
// MODULE: module1
// FILE: bar.kt
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
// EXPECTED_REACHABLE_NODES: 1284
// MODULE: #my-libr@ry
// FILE: bar.kt
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
// EXPECTED_REACHABLE_NODES: 1285
// MODULE: module-1
// FILE: bar.kt
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
// EXPECTED_REACHABLE_NODES: 1285
// MODULE: module1
// FILE: bar.kt
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
// EXPECTED_REACHABLE_NODES: 1286
// MODULE: module-1
// FILE: bar.kt
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
// EXPECTED_REACHABLE_NODES: 1286
// MODULE: module1
// FILE: bar.kt
@@ -1,3 +1,4 @@
// IGNORE_BACKEND: JS_IR
// EXPECTED_REACHABLE_NODES: 1284
package foo
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
// EXPECTED_REACHABLE_NODES: 1288
package foo
+1 -1
View File
@@ -1,4 +1,4 @@
var kotlin;
var emulatedModules = { kotlin: kotlin };
var module = { exports: {} };
var currentModuleId;
+2 -1
View File
@@ -59,4 +59,5 @@ allFiles.forEach(function(path) {
})
});
console.log(vm.runInContext("box()", sandbox));
// TODO: Support multimodule tests
console.log(vm.runInContext("JS_TESTS.box()", sandbox));