MT tests: rewrite model dump and reading to javax.xml

note that format of the argument part is changed
diff --git a/compiler/cli/build.gradle.kts b/compiler/cli/build.gradle.kts
index 13ce77d..6a499ea 100644
--- a/compiler/cli/build.gradle.kts
+++ b/compiler/cli/build.gradle.kts
@@ -30,6 +30,7 @@
     api(project(":compiler:fir:fir-serialization"))
     api(project(":compiler:ir.inline"))
     api(project(":kotlin-util-io"))
+    implementation(project(":kotlin-build-common"))
 
     compileOnly(toolsJarApi())
     compileOnly(intellijCore())
diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/pipeline/jvm/JvmFrontendPipelinePhase.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/pipeline/jvm/JvmFrontendPipelinePhase.kt
index ee752a1..f91ab58 100644
--- a/compiler/cli/src/org/jetbrains/kotlin/cli/pipeline/jvm/JvmFrontendPipelinePhase.kt
+++ b/compiler/cli/src/org/jetbrains/kotlin/cli/pipeline/jvm/JvmFrontendPipelinePhase.kt
@@ -9,13 +9,6 @@
 import com.intellij.openapi.Disposable
 import com.intellij.openapi.vfs.StandardFileSystems
 import com.intellij.openapi.vfs.VirtualFileManager
-import com.intellij.util.xmlb.SkipDefaultsSerializationFilter
-import com.intellij.util.xmlb.XmlSerializer
-import org.jdom.Attribute
-import org.jdom.Document
-import org.jdom.Element
-import org.jdom.output.Format
-import org.jdom.output.XMLOutputter
 import org.jetbrains.kotlin.KtPsiSourceFile
 import org.jetbrains.kotlin.KtSourceFile
 import org.jetbrains.kotlin.cli.common.*
@@ -38,6 +31,7 @@
 import org.jetbrains.kotlin.cli.pipeline.jvm.JvmFrontendPipelinePhase.createEnvironmentAndSources
 import org.jetbrains.kotlin.compiler.plugin.CompilerPluginRegistrar
 import org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar
+import org.jetbrains.kotlin.compilerRunner.ArgumentUtils
 import org.jetbrains.kotlin.config.*
 import org.jetbrains.kotlin.diagnostics.impl.BaseDiagnosticsCollector
 import org.jetbrains.kotlin.fir.DependencyListForCliModule
@@ -55,6 +49,8 @@
 import org.jetbrains.kotlin.util.PhaseType
 import org.jetbrains.kotlin.utils.fileUtils.descendantRelativeTo
 import java.io.File
+import javax.xml.stream.XMLOutputFactory
+import javax.xml.stream.XMLStreamWriter
 
 object JvmFrontendPipelinePhase : PipelinePhase<ConfigurationPipelineArtifact, JvmFrontendPipelineArtifact>(
     name = "JvmFrontendPipelinePhase",
@@ -66,63 +62,6 @@
         configuration: CompilerConfiguration,
         arguments: CommonCompilerArguments,
     ) {
-        val modules = Element("modules").apply {
-            // Just write out all compiler arguments as is
-            addContent(
-                Element("compilerArguments").apply {
-                    val skipDefaultsFilter = SkipDefaultsSerializationFilter()
-                    val element = XmlSerializer.serialize(arguments, skipDefaultsFilter)
-                    addContent(element)
-                }
-            )
-            for (module in chunk) {
-                addContent(Element("module").apply {
-                    attributes.add(
-                        Attribute("timestamp", System.currentTimeMillis().toString())
-                    )
-
-                    attributes.add(
-                        Attribute("name", module.getModuleName())
-                    )
-                    attributes.add(
-                        Attribute("type", module.getModuleType())
-                    )
-                    attributes.add(
-                        Attribute("outputDir", module.getOutputDirectory())
-                    )
-
-                    for (friendDir in module.getFriendPaths()) {
-                        addContent(Element("friendDir").setAttribute("path", friendDir))
-                    }
-                    for (source in module.getSourceFiles()) {
-                        addContent(Element("sources").setAttribute("path", source))
-                    }
-                    for (javaSourceRoots in module.getJavaSourceRoots()) {
-                        addContent(
-                            Element("javaSourceRoots").apply {
-                                setAttribute("path", javaSourceRoots.path)
-                                javaSourceRoots.packagePrefix?.let { setAttribute("packagePrefix", it) }
-                            }
-                        )
-                    }
-                    for (classpath in configuration.get(CONTENT_ROOTS).orEmpty()) {
-                        if (classpath is JvmClasspathRoot) {
-                            addContent(Element("classpath").setAttribute("path", classpath.file.absolutePath))
-                        } else if (classpath is JvmModulePathRoot) {
-                            addContent(Element("modulepath").setAttribute("path", classpath.file.absolutePath))
-                        }
-                    }
-                    for (commonSources in module.getCommonSourceFiles()) {
-                        addContent(Element("commonSources").setAttribute("path", commonSources))
-                    }
-                    module.modularJdkRoot?.let {
-                        addContent(Element("modularJdkRoot").setAttribute("path", module.modularJdkRoot))
-                    }
-                })
-            }
-        }
-        val document = Document(modules)
-        val outputter = XMLOutputter(Format.getPrettyFormat())
         val dirFile = File(dir)
         if (!dirFile.exists()) {
             dirFile.mkdirs()
@@ -139,10 +78,78 @@
             outputFile = file()
             counter++
         } while (outputFile.exists())
-        outputFile.bufferedWriter().use {
-            outputter.output(document, it)
-        }
 
+        // Write XML using StAX
+        outputFile.bufferedWriter().use { writer ->
+            val xmlFactory = XMLOutputFactory.newInstance()
+            with(xmlFactory.createXMLStreamWriter(writer)) {
+                writeStartDocument("UTF-8", "1.0")
+                val depth = PrettyPrintDepth(0)
+
+                // <modules>
+                start("modules", depth)
+
+                // compilerArguments
+                start("compilerArguments", depth)
+                for (arg in ArgumentUtils.convertArgumentsToStringList(arguments)) {
+                    empty("arg", depth)
+                    writeAttribute("value", arg)
+                }
+                end(depth) // compilerArguments
+
+                // modules
+                for (module in chunk) {
+                    start("module", depth)
+                    writeAttribute("timestamp", System.currentTimeMillis().toString())
+                    writeAttribute("name", module.getModuleName())
+                    writeAttribute("type", module.getModuleType())
+                    writeAttribute("outputDir", module.getOutputDirectory())
+
+                    for (friendDir in module.getFriendPaths()) {
+                        empty("friendDir", depth)
+                        writeAttribute("path", friendDir)
+                    }
+                    for (source in module.getSourceFiles()) {
+                        empty("sources", depth)
+                        writeAttribute("path", source)
+                    }
+                    for (javaSourceRoots in module.getJavaSourceRoots()) {
+                        start("javaSourceRoots", depth)
+                        writeAttribute("path", javaSourceRoots.path)
+                        javaSourceRoots.packagePrefix?.let { writeAttribute("packagePrefix", it) }
+                        end(depth)
+                    }
+                    for (classpath in configuration.get(CONTENT_ROOTS).orEmpty()) {
+                        when (classpath) {
+                            is JvmClasspathRoot -> {
+                                empty("classpath", depth)
+                                writeAttribute("path", classpath.file.absolutePath)
+                            }
+                            is JvmModulePathRoot -> {
+                                empty("modulepath", depth)
+                                writeAttribute("path", classpath.file.absolutePath)
+                            }
+                        }
+                    }
+                    for (commonSources in module.getCommonSourceFiles()) {
+                        empty("commonSources", depth)
+                        writeAttribute("path", commonSources)
+                    }
+                    module.modularJdkRoot?.let {
+                        empty("modularJdkRoot", depth)
+                        writeAttribute("path", it)
+                    }
+
+                    end(depth) // module
+                }
+
+                end(depth) // modules
+                writeCharacters("\n")
+                writeEndDocument()
+                flush()
+                close()
+            }
+        }
     }
 
     override fun executePhase(input: ConfigurationPipelineArtifact): JvmFrontendPipelineArtifact? {
@@ -473,3 +480,29 @@
         )
     }
 }
+
+
+// Pretty-printing helpers for StAX writer
+private data class PrettyPrintDepth(var value: Int)
+
+private fun XMLStreamWriter.indent(depth: PrettyPrintDepth) {
+    writeCharacters("\n")
+    if (depth.value > 0) writeCharacters("  ".repeat(depth.value))
+}
+
+private fun XMLStreamWriter.start(name: String, depth: PrettyPrintDepth) {
+    indent(depth)
+    writeStartElement(name)
+    depth.value++
+}
+
+private fun XMLStreamWriter.end(depth: PrettyPrintDepth) {
+    depth.value--
+    indent(depth)
+    writeEndElement()
+}
+
+private fun XMLStreamWriter.empty(name: String, depth: PrettyPrintDepth) {
+    indent(depth)
+    writeEmptyElement(name)
+}
diff --git a/compiler/fir/modularized-tests/tests/org/jetbrains/kotlin/fir/AbstractModularizedTest.kt b/compiler/fir/modularized-tests/tests/org/jetbrains/kotlin/fir/AbstractModularizedTest.kt
index 9d3ce45..8b135ec 100644
--- a/compiler/fir/modularized-tests/tests/org/jetbrains/kotlin/fir/AbstractModularizedTest.kt
+++ b/compiler/fir/modularized-tests/tests/org/jetbrains/kotlin/fir/AbstractModularizedTest.kt
@@ -5,11 +5,9 @@
 
 package org.jetbrains.kotlin.fir
 
-import com.intellij.openapi.util.JDOMUtil
-import com.intellij.util.xmlb.XmlSerializer
-import org.jdom.Element
 import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments
 import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments
+import org.jetbrains.kotlin.cli.common.arguments.parseCommandLineArguments
 import org.jetbrains.kotlin.config.JvmTarget
 import org.jetbrains.kotlin.fir.scopes.ProcessorAction
 import org.jetbrains.kotlin.test.kotlinPathsForDistDirectoryForTests
@@ -20,6 +18,9 @@
 import java.io.File
 import java.text.SimpleDateFormat
 import java.util.*
+import javax.xml.stream.XMLInputFactory
+import javax.xml.stream.XMLStreamConstants
+import javax.xml.stream.XMLStreamReader
 
 data class ModuleData(
     val name: String,
@@ -180,73 +181,144 @@
 }
 
 internal fun loadModuleDumpFile(file: File): List<ModuleData> {
-    val rootElement = JDOMUtil.load(file)
-    val modules = rootElement.getChildren("module")
-    val arguments = rootElement.getChild("compilerArguments")?.let { loadCompilerArguments(it) }
-    return modules.map { node -> loadModule(node).also { it.arguments = arguments } }
+    val modules = mutableListOf<ModuleData>()
+    var arguments: CommonCompilerArguments? = null
+
+    val xmlFactory = XMLInputFactory.newInstance()
+    file.inputStream().use { input ->
+        val xr = xmlFactory.createXMLStreamReader(input)
+        while (xr.hasNext()) {
+            when (xr.next()) {
+                XMLStreamConstants.START_ELEMENT -> when (xr.localName) {
+                    "compilerArguments" -> {
+                        arguments = readCompilerArguments(xr)
+                        // Assign to already parsed modules as well
+                        modules.forEach { it.arguments = arguments }
+                    }
+                    "module" -> {
+                        val m = readModule(xr)
+                        m.arguments = arguments
+                        modules += m
+                    }
+                    else -> {}
+                }
+                else -> {}
+            }
+        }
+        xr.close()
+    }
+    return modules
 }
 
-private fun loadModule(moduleElement: Element): ModuleData {
-    val outputDir = moduleElement.getAttribute("outputDir").value
-    val moduleName = moduleElement.getAttribute("name").value
+private fun readModule(xr: XMLStreamReader): ModuleData {
+    // reader is positioned at START_ELEMENT <module>
+    val outputDir = xr.getAttributeValue(null, "outputDir") ?: ""
+    val moduleName = xr.getAttributeValue(null, "name") ?: ""
     val moduleNameQualifier = outputDir.substringAfterLast("/")
+    val timestamp = xr.getAttributeValue(null, "timestamp")?.toLongOrNull() ?: 0L
+    val jdkHome = xr.getAttributeValue(null, "jdkHome")
+
     val javaSourceRoots = mutableListOf<JavaSourceRootData<String>>()
     val classpath = mutableListOf<String>()
     val sources = mutableListOf<String>()
     val friendDirs = mutableListOf<String>()
     val optInAnnotations = mutableListOf<String>()
-    val timestamp = moduleElement.getAttribute("timestamp")?.longValue ?: 0
-    val jdkHome = moduleElement.getAttribute("jdkHome")?.value
     var modularJdkRoot: String? = null
     var isCommon = false
 
-    for (item in moduleElement.children) {
-        when (item.name) {
-            "classpath" -> {
-                val path = item.getAttribute("path").value
-                if (path != outputDir) {
-                    classpath += path
+    while (xr.hasNext()) {
+        when (xr.next()) {
+            XMLStreamConstants.START_ELEMENT -> when (xr.localName) {
+                "classpath" -> {
+                    val path = xr.getAttributeValue(null, "path")
+                    if (path != null && path != outputDir) classpath += path
+                    skipElement(xr)
+                }
+                "friendDir" -> {
+                    xr.getAttributeValue(null, "path")?.let { friendDirs += it }
+                    skipElement(xr)
+                }
+                "javaSourceRoots" -> {
+                    val path = xr.getAttributeValue(null, "path")
+                    val pkg = xr.getAttributeValue(null, "packagePrefix")
+                    if (path != null) javaSourceRoots += JavaSourceRootData(path, pkg)
+                    skipElement(xr)
+                }
+                "sources" -> {
+                    xr.getAttributeValue(null, "path")?.let { sources += it }
+                    skipElement(xr)
+                }
+                "commonSources" -> {
+                    isCommon = true
+                    skipElement(xr)
+                }
+                "modularJdkRoot" -> {
+                    modularJdkRoot = xr.getAttributeValue(null, "path")
+                    skipElement(xr)
+                }
+                "useOptIn" -> {
+                    xr.getAttributeValue(null, "annotation")?.let { optInAnnotations += it }
+                    skipElement(xr)
+                }
+                else -> {
+                    // Skip any unknown children fully
+                    skipElement(xr)
                 }
             }
-            "friendDir" -> {
-                val path = item.getAttribute("path").value
-                friendDirs += path
+            XMLStreamConstants.END_ELEMENT -> if (xr.localName == "module") {
+                return ModuleData(
+                    moduleName,
+                    timestamp,
+                    outputDir,
+                    moduleNameQualifier,
+                    classpath,
+                    sources,
+                    javaSourceRoots,
+                    friendDirs,
+                    optInAnnotations,
+                    modularJdkRoot,
+                    jdkHome,
+                    isCommon,
+                )
             }
-            "javaSourceRoots" -> {
-                javaSourceRoots +=
-                    JavaSourceRootData(
-                        item.getAttribute("path").value,
-                        item.getAttribute("packagePrefix")?.value,
-                    )
-            }
-            "sources" -> sources += item.getAttribute("path").value
-            "commonSources" -> isCommon = true
-            "modularJdkRoot" -> modularJdkRoot = item.getAttribute("path").value
-            "useOptIn" -> optInAnnotations += item.getAttribute("annotation").value
         }
     }
-
-    return ModuleData(
-        moduleName,
-        timestamp,
-        outputDir,
-        moduleNameQualifier,
-        classpath,
-        sources,
-        javaSourceRoots,
-        friendDirs,
-        optInAnnotations,
-        modularJdkRoot,
-        jdkHome,
-        isCommon,
-    )
+    error("Unexpected end of XML while reading <module>")
 }
 
-private fun loadCompilerArguments(argumentsRoot: Element): CommonCompilerArguments? {
-    val element = argumentsRoot.children.singleOrNull() ?: return null
-    return when (element.name) {
-        "K2JVMCompilerArguments" -> K2JVMCompilerArguments().also { XmlSerializer.deserializeInto(it, element) }
-        else -> null
+private fun readCompilerArguments(xr: javax.xml.stream.XMLStreamReader): CommonCompilerArguments? {
+    // reader is positioned at START_ELEMENT <compilerArguments>
+    val args = mutableListOf<String>()
+    while (xr.hasNext()) {
+        when (xr.next()) {
+            XMLStreamConstants.START_ELEMENT -> {
+                when (xr.localName) {
+                    "arg" -> {
+                        xr.getAttributeValue(null, "value")?.let { args += it }
+                        skipElement(xr)
+                    }
+                    else -> {
+                        // Unknown format, skip it entirely
+                        skipElement(xr)
+                    }
+                }
+            }
+            XMLStreamConstants.END_ELEMENT -> if (xr.localName == "compilerArguments") {
+                return parseCommandLineArguments<K2JVMCompilerArguments>(args)
+            }
+        }
+    }
+    error("Unexpected end of XML while reading <compilerArguments>")
+}
+
+private fun skipElement(xr: javax.xml.stream.XMLStreamReader) {
+    // Assumes the reader is at START_ELEMENT; consumes until matching END_ELEMENT
+    var depth = 1
+    while (depth > 0 && xr.hasNext()) {
+        when (xr.next()) {
+            XMLStreamConstants.START_ELEMENT -> depth++
+            XMLStreamConstants.END_ELEMENT -> depth--
+        }
     }
 }