[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
@@ -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));