~ wip
diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/compiler.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/compiler.kt
index 51385c9..5397a6a 100644
--- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/compiler.kt
+++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/compiler.kt
@@ -7,6 +7,7 @@
 
 import com.intellij.openapi.project.Project
 import org.jetbrains.kotlin.analyzer.AbstractAnalyzerWithCompilerReport
+import org.jetbrains.kotlin.backend.common.lower
 import org.jetbrains.kotlin.backend.common.phaser.PhaseConfig
 import org.jetbrains.kotlin.backend.common.phaser.invokeToplevel
 import org.jetbrains.kotlin.config.CompilerConfiguration
@@ -47,7 +48,8 @@
     dceDriven: Boolean = false,
     es6mode: Boolean = false,
     multiModule: Boolean = false,
-    relativeRequirePath: Boolean = false
+    relativeRequirePath: Boolean = false,
+    useStdlibCache: Boolean = false,
 ): CompilerResult {
     val irFactory = PersistentIrFactory()
 
@@ -70,6 +72,18 @@
     deserializer.postProcess()
     symbolTable.noUnboundLeft("Unbound symbols at the end of linker")
 
+    if (useStdlibCache) {
+        // TODO maybe populate caches here? e.g. load fully, lower, save IC caches, and then load again?
+        // Try load stdlib lowered IR
+        prepareIcCaches(project, analyzer, configuration, allDependencies)
+
+        // Inject carriers, new declarations and mappings into the stdlib IrModule
+        //loadIrForIc()
+
+        // Remove stdlib from allModules
+//        allModules = allModules.subList(1, allModules.size)
+    }
+
     // This won't work incrementally
     allModules.forEach { module ->
         moveBodilessDeclarationsToSeparatePlace(context, module)
@@ -99,9 +113,8 @@
         )
         return transformer.generateModule(allModules)
     } else {
-        // TODO need to use a special StageController here
+        lowerPreservingIcData(allModules, irFactory, context)
 
-        jsPhases.invokeToplevel(phaseConfig, context, allModules)
         val transformer = IrModuleToJsTransformer(
             context,
             mainArguments,
@@ -111,10 +124,7 @@
             relativeRequirePath = relativeRequirePath
         )
 
-        // TODO serialize the data
-        // All the declarations
-        // Mappings
-
+        // TODO stdlib code?
         return transformer.generateModule(allModules)
     }
 }
@@ -130,3 +140,38 @@
     val transformer = IrModuleToJsTransformer(context, null, true, nameTables)
     return transformer.generateModule(listOf(moduleFragment)).jsCode!!.mainModule
 }
+
+// Only allows to apply a lowering to the whole world and save the result
+class WholeWorldStageController : StageController() {
+    override var currentStage: Int = 0
+
+    // TODO assert lowered
+}
+
+fun lowerPreservingIcData(allModules: Iterable<IrModuleFragment>, irFactory: PersistentIrFactory, context: JsIrBackendContext) {
+    val controller = WholeWorldStageController()
+
+    irFactory.stageController = controller
+
+    // TODO what about other lowering?
+    val lowerings = loweringList.filter { it is DeclarationLowering || it is BodyLowering }
+
+    // TODO skip stdlib in lowerings
+    // Lower all the things
+    lowerings.forEachIndexed { i, lowering ->
+        controller.currentStage = i + 1
+        when (lowering) {
+            is DeclarationLowering ->
+                lowering.declarationTransformer(context).let { declarationTransformer ->
+                    allModules.forEach { declarationTransformer.lower(it) }
+                }
+            is BodyLowering ->
+                lowering.bodyLowering(context).let { bodyLoweringPass ->
+                    allModules.forEach { bodyLoweringPass.lower(it) }
+                }
+            // else -> TODO what about other lowerings?
+        }
+    }
+
+    controller.currentStage++
+}
\ No newline at end of file
diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic.kt
new file mode 100644
index 0000000..65fe279
--- /dev/null
+++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ic.kt
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.ir.backend.js
+
+import com.intellij.openapi.project.Project
+import org.jetbrains.kotlin.analyzer.AbstractAnalyzerWithCompilerReport
+import org.jetbrains.kotlin.config.CompilerConfiguration
+import org.jetbrains.kotlin.config.languageVersionSettings
+import org.jetbrains.kotlin.ir.backend.js.lower.generateTests
+import org.jetbrains.kotlin.ir.backend.js.lower.moveBodilessDeclarationsToSeparatePlace
+import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
+import org.jetbrains.kotlin.ir.declarations.persistent.PersistentIrFactory
+import org.jetbrains.kotlin.ir.util.ExternalDependenciesGenerator
+import org.jetbrains.kotlin.ir.util.noUnboundLeft
+import org.jetbrains.kotlin.library.resolver.KotlinLibraryResolveResult
+
+// TODO test purpose only
+// klib path -> ic data path
+val icCache = mutableMapOf<String, SerializedIcData>()
+
+fun prepareIcCaches(
+    project: Project,
+    analyzer: AbstractAnalyzerWithCompilerReport,
+    configuration: CompilerConfiguration,
+    allDependencies: KotlinLibraryResolveResult,
+) {
+    val irFactory = PersistentIrFactory()
+
+    // only process stdlib for now
+    val stdlibResolved = findStdlib(allDependencies)
+    val stdlibKlib = stdlibResolved.getFullList().single()
+
+    icCache.getOrPut(stdlibKlib.libraryName) {
+        val mainModule = MainModule.Klib(stdlibKlib)
+
+        val (moduleFragment: IrModuleFragment, dependencyModules, irBuiltIns, symbolTable, deserializer) =
+            loadIr(project, mainModule, analyzer, configuration, stdlibResolved, emptyList(), irFactory)
+
+        val moduleDescriptor = moduleFragment.descriptor
+
+        val context = JsIrBackendContext(moduleDescriptor, irBuiltIns, symbolTable, moduleFragment, emptySet(), configuration, irFactory)
+
+        // Load declarations referenced during `context` initialization
+        val irProviders = listOf(deserializer)
+        ExternalDependenciesGenerator(symbolTable, irProviders, configuration.languageVersionSettings).generateUnboundSymbolsAsDependencies()
+
+        deserializer.postProcess()
+        symbolTable.noUnboundLeft("Unbound symbols at the end of linker")
+
+        // This won't work incrementally
+        moveBodilessDeclarationsToSeparatePlace(context, moduleFragment)
+
+        // TODO should be done incrementally
+        generateTests(context, moduleFragment)
+
+        lowerPreservingIcData(listOf(moduleFragment), irFactory, context)
+
+        irFactory.allDeclarations.forEach {
+            // filter newly created
+            // group by file
+            // group by stage
+            //    serialize declaration
+            //    serialize Carriers
+            //    serialize mappings
+        }
+
+        SerializedIcData()
+    }
+}
+
+private fun findStdlib(allDependencies: KotlinLibraryResolveResult): KotlinLibraryResolveResult {
+    var result: KotlinLibraryResolveResult? = null
+
+    allDependencies.forEach { klib, _ ->
+        val resolvedLib = allDependencies.filterRoots {
+            it.library == klib
+        }
+
+        if (resolvedLib.getFullList().size == 1) result = resolvedLib
+    }
+
+    return result!!
+}
+
+fun loadIrForIc(stdlibIcCachePath: String) {
+
+}
+
+fun serializeIrForIc(stdlibIcCachePath: String) {
+
+}
+
+class SerializedIcData()
\ No newline at end of file
diff --git a/compiler/ir/ir.tree.persistent/src/org/jetbrains/kotlin/ir/declarations/persistent/PersistentIrEnumEntry.kt b/compiler/ir/ir.tree.persistent/src/org/jetbrains/kotlin/ir/declarations/persistent/PersistentIrEnumEntry.kt
index d886a1a..9c7181c 100644
--- a/compiler/ir/ir.tree.persistent/src/org/jetbrains/kotlin/ir/declarations/persistent/PersistentIrEnumEntry.kt
+++ b/compiler/ir/ir.tree.persistent/src/org/jetbrains/kotlin/ir/declarations/persistent/PersistentIrEnumEntry.kt
@@ -15,6 +15,7 @@
 import org.jetbrains.kotlin.ir.declarations.persistent.carriers.EnumEntryCarrier
 import org.jetbrains.kotlin.ir.expressions.IrConstructorCall
 import org.jetbrains.kotlin.ir.expressions.IrExpressionBody
+import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
 import org.jetbrains.kotlin.ir.symbols.IrEnumEntrySymbol
 import org.jetbrains.kotlin.name.Name
 
@@ -49,13 +50,13 @@
     override val descriptor: ClassDescriptor
         get() = symbol.descriptor
 
-    override var correspondingClassField: IrClass? = null
+    override var correspondingClassField: IrClassSymbol? = null
 
     override var correspondingClass: IrClass?
-        get() = getCarrier().correspondingClassField
+        get() = getCarrier().correspondingClassField?.owner
         set(v) {
             if (correspondingClass !== v) {
-                setCarrier().correspondingClassField = v
+                setCarrier().correspondingClassField = v?.symbol
             }
         }
 
diff --git a/compiler/ir/ir.tree.persistent/src/org/jetbrains/kotlin/ir/declarations/persistent/PersistentIrFactory.kt b/compiler/ir/ir.tree.persistent/src/org/jetbrains/kotlin/ir/declarations/persistent/PersistentIrFactory.kt
index 54e20d9..81697d0 100644
--- a/compiler/ir/ir.tree.persistent/src/org/jetbrains/kotlin/ir/declarations/persistent/PersistentIrFactory.kt
+++ b/compiler/ir/ir.tree.persistent/src/org/jetbrains/kotlin/ir/declarations/persistent/PersistentIrFactory.kt
@@ -23,6 +23,8 @@
 
     override var stageController = StageController()
 
+    val allDeclarations = mutableListOf<IrDeclaration>()
+
     override fun createAnonymousInitializer(
         startOffset: Int,
         endOffset: Int,
@@ -30,7 +32,7 @@
         symbol: IrAnonymousInitializerSymbol,
         isStatic: Boolean,
     ): IrAnonymousInitializer =
-        PersistentIrAnonymousInitializer(startOffset, endOffset, origin, symbol, isStatic, this)
+        PersistentIrAnonymousInitializer(startOffset, endOffset, origin, symbol, isStatic, this).also { allDeclarations += it }
 
     override fun createClass(
         startOffset: Int,
@@ -54,7 +56,7 @@
             startOffset, endOffset, origin, symbol, name, kind, visibility, modality,
             isCompanion, isInner, isData, isExternal, isInline, isExpect, isFun, source,
             this
-        )
+        ).also { allDeclarations += it }
 
     override fun createConstructor(
         startOffset: Int,
@@ -73,7 +75,7 @@
         PersistentIrConstructor(
             startOffset, endOffset, origin, symbol, name, visibility, returnType, isInline, isExternal, isPrimary, isExpect,
             containerSource, this
-        )
+        ).also { allDeclarations += it }
 
     override fun createEnumEntry(
         startOffset: Int,
@@ -82,14 +84,14 @@
         symbol: IrEnumEntrySymbol,
         name: Name,
     ): IrEnumEntry =
-        PersistentIrEnumEntry(startOffset, endOffset, origin, symbol, name, this)
+        PersistentIrEnumEntry(startOffset, endOffset, origin, symbol, name, this).also { allDeclarations += it }
 
     override fun createErrorDeclaration(
         startOffset: Int,
         endOffset: Int,
         descriptor: DeclarationDescriptor,
     ): IrErrorDeclaration =
-        PersistentIrErrorDeclaration(startOffset, endOffset, descriptor, this)
+        PersistentIrErrorDeclaration(startOffset, endOffset, descriptor, this).also { allDeclarations += it }
 
     override fun createField(
         startOffset: Int,
@@ -103,7 +105,7 @@
         isExternal: Boolean,
         isStatic: Boolean,
     ): IrField =
-        PersistentIrField(startOffset, endOffset, origin, symbol, name, type, visibility, isFinal, isExternal, isStatic, this)
+        PersistentIrField(startOffset, endOffset, origin, symbol, name, type, visibility, isFinal, isExternal, isStatic, this).also { allDeclarations += it }
 
     override fun createFunction(
         startOffset: Int,
@@ -128,7 +130,7 @@
             startOffset, endOffset, origin, symbol, name, visibility, modality, returnType,
             isInline, isExternal, isTailrec, isSuspend, isOperator, isInfix, isExpect, isFakeOverride,
             containerSource, this
-        )
+        ).also { allDeclarations += it }
 
     override fun createFakeOverrideFunction(
         startOffset: Int,
@@ -149,7 +151,7 @@
         PersistentIrFakeOverrideFunction(
             startOffset, endOffset, origin, name, visibility, modality, returnType,
             isInline, isExternal, isTailrec, isSuspend, isOperator, isInfix, isExpect, this
-        )
+        ).also { allDeclarations += it }
 
     override fun createLocalDelegatedProperty(
         startOffset: Int,
@@ -162,7 +164,7 @@
     ): IrLocalDelegatedProperty =
         PersistentIrLocalDelegatedProperty(
             startOffset, endOffset, origin, symbol, name, type, isVar, this
-        )
+        ).also { allDeclarations += it }
 
     override fun createProperty(
         startOffset: Int,
@@ -185,7 +187,7 @@
             startOffset, endOffset, origin, symbol, name, visibility, modality,
             isVar, isConst, isLateinit, isDelegated, isExternal, isExpect, isFakeOverride,
             containerSource, this
-        )
+        ).also { allDeclarations += it }
 
     override fun createFakeOverrideProperty(
         startOffset: Int,
@@ -205,7 +207,7 @@
             startOffset, endOffset, origin, name, visibility, modality,
             isVar, isConst, isLateinit, isDelegated, isExternal, isExpect,
             this
-        )
+        ).also { allDeclarations += it }
 
     override fun createTypeAlias(
         startOffset: Int,
@@ -217,7 +219,7 @@
         isActual: Boolean,
         origin: IrDeclarationOrigin,
     ): IrTypeAlias =
-        PersistentIrTypeAlias(startOffset, endOffset, symbol, name, visibility, expandedType, isActual, origin, this)
+        PersistentIrTypeAlias(startOffset, endOffset, symbol, name, visibility, expandedType, isActual, origin, this).also { allDeclarations += it }
 
     override fun createTypeParameter(
         startOffset: Int,
@@ -229,7 +231,7 @@
         isReified: Boolean,
         variance: Variance,
     ): IrTypeParameter =
-        PersistentIrTypeParameter(startOffset, endOffset, origin, symbol, name, index, isReified, variance, this)
+        PersistentIrTypeParameter(startOffset, endOffset, origin, symbol, name, index, isReified, variance, this).also { allDeclarations += it }
 
     override fun createValueParameter(
         startOffset: Int,
@@ -247,7 +249,7 @@
     ): IrValueParameter =
         PersistentIrValueParameter(
             startOffset, endOffset, origin, symbol, name, index, type, varargElementType, isCrossinline, isNoinline, isHidden, isAssignable, this
-        )
+        ).also { allDeclarations += it }
 
     override fun createExpressionBody(
         startOffset: Int,
diff --git a/compiler/ir/ir.tree.persistent/src/org/jetbrains/kotlin/ir/declarations/persistent/carriers/EnumEntryCarrier.kt b/compiler/ir/ir.tree.persistent/src/org/jetbrains/kotlin/ir/declarations/persistent/carriers/EnumEntryCarrier.kt
index 310adc1..38dac84 100644
--- a/compiler/ir/ir.tree.persistent/src/org/jetbrains/kotlin/ir/declarations/persistent/carriers/EnumEntryCarrier.kt
+++ b/compiler/ir/ir.tree.persistent/src/org/jetbrains/kotlin/ir/declarations/persistent/carriers/EnumEntryCarrier.kt
@@ -10,11 +10,12 @@
 import org.jetbrains.kotlin.ir.declarations.IrDeclarationParent
 import org.jetbrains.kotlin.ir.expressions.IrConstructorCall
 import org.jetbrains.kotlin.ir.expressions.IrExpressionBody
+import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
 
 // Auto-generated by compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/persistentIrGenerator/Main.kt. DO NOT EDIT!
 
 internal interface EnumEntryCarrier : DeclarationCarrier{
-    var correspondingClassField: IrClass?
+    var correspondingClassField: IrClassSymbol?
     var initializerExpressionField: IrExpressionBody?
 
     override fun clone(): EnumEntryCarrier {
@@ -34,6 +35,6 @@
     override var parentField: IrDeclarationParent?,
     override var originField: IrDeclarationOrigin,
     override var annotationsField: List<IrConstructorCall>,
-    override var correspondingClassField: IrClass?,
+    override var correspondingClassField: IrClassSymbol?,
     override var initializerExpressionField: IrExpressionBody?
 ) : EnumEntryCarrier