feat: add polyfills insertion for ES Next used features
This commit is contained in:
@@ -20,6 +20,7 @@ import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||
import org.jetbrains.kotlin.ir.backend.js.codegen.JsGenerationGranularity
|
||||
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.JsInnerClassesSupport
|
||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.JsPolyfills
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.JsInlineClassesUtils
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.OperatorNames
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.addFunction
|
||||
@@ -65,7 +66,7 @@ class JsIrBackendContext(
|
||||
val granularity: JsGenerationGranularity = JsGenerationGranularity.WHOLE_PROGRAM,
|
||||
val icCompatibleIr2Js: Boolean = false,
|
||||
) : JsCommonBackendContext {
|
||||
|
||||
val polyfills = JsPolyfills()
|
||||
val fieldToInitializer: MutableMap<IrField, IrExpression> = mutableMapOf()
|
||||
|
||||
val localClassNames: MutableMap<IrClass, String> = mutableMapOf()
|
||||
|
||||
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.backend.common.phaser.invokeToplevel
|
||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||
import org.jetbrains.kotlin.ir.IrBuiltIns
|
||||
import org.jetbrains.kotlin.ir.backend.js.codegen.JsGenerationGranularity
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.collectNativeImplementations
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.generateJsTests
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.moveBodilessDeclarationsToSeparatePlace
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsIrLinker
|
||||
@@ -140,6 +141,7 @@ fun compileIr(
|
||||
}
|
||||
|
||||
allModules.forEach { module ->
|
||||
collectNativeImplementations(context, module)
|
||||
moveBodilessDeclarationsToSeparatePlace(context, module)
|
||||
}
|
||||
|
||||
@@ -158,6 +160,7 @@ fun generateJsCode(
|
||||
moduleFragment: IrModuleFragment,
|
||||
nameTables: NameTables
|
||||
): String {
|
||||
collectNativeImplementations(context, moduleFragment)
|
||||
moveBodilessDeclarationsToSeparatePlace(context, moduleFragment)
|
||||
jsPhases.invokeToplevel(PhaseConfig(jsPhases), context, listOf(moduleFragment))
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||
import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI
|
||||
import org.jetbrains.kotlin.ir.backend.js.ic.ModuleCache
|
||||
import org.jetbrains.kotlin.ir.backend.js.ic.PersistentCacheConsumer
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.collectNativeImplementations
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.generateJsTests
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.moveBodilessDeclarationsToSeparatePlace
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsIrLinker
|
||||
@@ -80,6 +81,7 @@ fun compileWithIC(
|
||||
symbolTable.noUnboundLeft("Unbound symbols at the end of linker")
|
||||
|
||||
allModules.forEach {
|
||||
collectNativeImplementations(context, module)
|
||||
moveBodilessDeclarationsToSeparatePlace(context, it)
|
||||
}
|
||||
|
||||
|
||||
@@ -34,9 +34,11 @@ fun eliminateDeadDeclarations(
|
||||
|
||||
val uselessDeclarationsProcessor =
|
||||
UselessDeclarationsRemover(removeUnusedAssociatedObjects, usefulDeclarations, context, context.dceRuntimeDiagnostic)
|
||||
|
||||
modules.forEach { module ->
|
||||
module.files.forEach {
|
||||
it.acceptVoid(uselessDeclarationsProcessor)
|
||||
context.polyfills.saveOnlyIntersectionOfNextDeclarationsFor(it, usefulDeclarations)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -55,7 +57,15 @@ private fun IrDeclaration.addRootsTo(
|
||||
setter?.addRootsTo(nestedVisitor, context)
|
||||
}
|
||||
isEffectivelyExternal() -> {
|
||||
acceptVoid(nestedVisitor)
|
||||
val correspondingProperty = when (this) {
|
||||
is IrField -> correspondingPropertySymbol?.owner
|
||||
is IrSimpleFunction -> correspondingPropertySymbol?.owner
|
||||
else -> null
|
||||
}
|
||||
|
||||
if (!hasJsPolyfill() && correspondingProperty?.hasJsPolyfill() != true) {
|
||||
acceptVoid(nestedVisitor)
|
||||
}
|
||||
}
|
||||
isExported(context) -> {
|
||||
acceptVoid(nestedVisitor)
|
||||
|
||||
+16
-1
@@ -55,9 +55,24 @@ abstract class UsefulDeclarationProcessor(
|
||||
expression.symbol.owner.enqueue(data, "raw function access")
|
||||
}
|
||||
|
||||
override fun visitBlock(expression: IrBlock, data: IrDeclaration) {
|
||||
super.visitBlock(expression, data)
|
||||
if (expression !is IrReturnableBlock) return
|
||||
expression.inlineFunctionSymbol?.owner?.enqueue(data, "inline function usage")
|
||||
}
|
||||
|
||||
override fun visitFieldAccess(expression: IrFieldAccessExpression, data: IrDeclaration) {
|
||||
super.visitFieldAccess(expression, data)
|
||||
expression.symbol.owner.enqueue(data, "field access")
|
||||
|
||||
val field = expression.symbol.owner.apply { enqueue(data, "field access") }
|
||||
val correspondingProperty = field.correspondingPropertySymbol?.owner ?: return
|
||||
|
||||
if (
|
||||
field.origin == IrDeclarationOrigin.PROPERTY_BACKING_FIELD &&
|
||||
correspondingProperty.hasJsPolyfill()
|
||||
) {
|
||||
correspondingProperty.enqueue(field, "property backing field")
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitStringConcatenation(expression: IrStringConcatenation, data: IrDeclaration) {
|
||||
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.DeclarationTransformer
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclarationBase
|
||||
import org.jetbrains.kotlin.ir.declarations.IrExternalPackageFragment
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
||||
|
||||
fun collectNativeImplementations(context: JsIrBackendContext, moduleFragment: IrModuleFragment) =
|
||||
CollectNativeImplementationsVisitor(context).let { collector ->
|
||||
moduleFragment.files.forEach { it.accept(collector, null) }
|
||||
}
|
||||
|
||||
|
||||
class CollectNativeImplementationsVisitor(private val context: JsIrBackendContext) : IrElementVisitorVoid {
|
||||
override fun visitElement(element: IrElement) {}
|
||||
|
||||
override fun visitFile(declaration: IrFile) {
|
||||
declaration.declarations.forEach {
|
||||
context.polyfills.registerDeclarationNativeImplementation(declaration, it)
|
||||
}
|
||||
super.visitFile(declaration)
|
||||
}
|
||||
}
|
||||
-8
@@ -114,7 +114,6 @@ class IrElementToJsExpressionTransformer : BaseIrElementToJsNodeTransformer<JsEx
|
||||
expression
|
||||
)
|
||||
return JsNameRef(field.getJsNameOrKotlinName().identifier, receiver).withSource(expression, context)
|
||||
.also { context.staticContext.polyfills.visitDeclaration(field) }
|
||||
}
|
||||
|
||||
if (fieldParent is IrClass && context.isClassInlineLike(fieldParent)) {
|
||||
@@ -129,7 +128,6 @@ class IrElementToJsExpressionTransformer : BaseIrElementToJsNodeTransformer<JsEx
|
||||
if (owner.isThisReceiver()) return JsThisRef().withSource(expression, context)
|
||||
|
||||
return context.getNameForValueDeclaration(owner).makeRef().withSource(expression, context)
|
||||
.also { context.staticContext.polyfills.visitDeclaration(owner) }
|
||||
}
|
||||
|
||||
override fun visitGetObjectValue(expression: IrGetObjectValue, context: JsGenerationContext): JsExpression {
|
||||
@@ -146,7 +144,6 @@ class IrElementToJsExpressionTransformer : BaseIrElementToJsNodeTransformer<JsEx
|
||||
val dest = jsElementAccess(fieldName.ident, expression.receiver?.accept(this, context))
|
||||
val source = expression.value.accept(this, context)
|
||||
return jsAssignment(dest, source).withSource(expression, context)
|
||||
.also { context.staticContext.polyfills.visitDeclaration(field) }
|
||||
}
|
||||
|
||||
override fun visitSetValue(expression: IrSetValue, context: JsGenerationContext): JsExpression {
|
||||
@@ -154,7 +151,6 @@ class IrElementToJsExpressionTransformer : BaseIrElementToJsNodeTransformer<JsEx
|
||||
val ref = JsNameRef(context.getNameForValueDeclaration(field))
|
||||
val value = expression.value.accept(this, context)
|
||||
return JsBinaryOperation(JsBinaryOperator.ASG, ref, value).withSource(expression, context)
|
||||
.also { context.staticContext.polyfills.visitDeclaration(field) }
|
||||
}
|
||||
|
||||
override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall, context: JsGenerationContext): JsExpression {
|
||||
@@ -225,10 +221,6 @@ class IrElementToJsExpressionTransformer : BaseIrElementToJsNodeTransformer<JsEx
|
||||
return JsCallTransformer(expression, context).generateExpression()
|
||||
}
|
||||
return translateCall(expression, context, this).withSource(expression, context)
|
||||
.also {
|
||||
val function = expression.symbol.owner
|
||||
context.staticContext.polyfills.visitDeclaration(function.correspondingPropertySymbol?.owner ?: function)
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitWhen(expression: IrWhen, context: JsGenerationContext): JsExpression {
|
||||
|
||||
+1
-4
@@ -86,9 +86,7 @@ class IrElementToJsStatementTransformer : BaseIrElementToJsNodeTransformer<JsSta
|
||||
override fun visitSetValue(expression: IrSetValue, context: JsGenerationContext): JsStatement {
|
||||
val owner = expression.symbol.owner
|
||||
val ref = JsNameRef(context.getNameForValueDeclaration(owner))
|
||||
return expression.value
|
||||
.maybeOptimizeIntoSwitch(context) { jsAssignment(ref, it).withSource(expression, context).makeStmt() }
|
||||
.also { context.staticContext.polyfills.visitDeclaration(owner) }
|
||||
return expression.value.maybeOptimizeIntoSwitch(context) { jsAssignment(ref, it).withSource(expression, context).makeStmt() }
|
||||
}
|
||||
|
||||
override fun visitReturn(expression: IrReturn, context: JsGenerationContext): JsStatement {
|
||||
@@ -139,7 +137,6 @@ class IrElementToJsStatementTransformer : BaseIrElementToJsNodeTransformer<JsSta
|
||||
return JsCallTransformer(expression, data).generateStatement()
|
||||
}
|
||||
return translateCall(expression, data, IrElementToJsExpressionTransformer()).withSource(expression, data).makeStmt()
|
||||
.also { data.staticContext.polyfills.visitDeclaration(expression.symbol.owner) }
|
||||
}
|
||||
|
||||
override fun visitInstanceInitializerCall(expression: IrInstanceInitializerCall, context: JsGenerationContext): JsStatement {
|
||||
|
||||
+16
-6
@@ -98,7 +98,7 @@ class IrModuleToJsTransformer(
|
||||
exportedModule,
|
||||
namer,
|
||||
refInfo,
|
||||
generateMainCall = true
|
||||
generateMainCall = true,
|
||||
)
|
||||
|
||||
val dependencies = others.mapIndexed { index, module ->
|
||||
@@ -112,7 +112,7 @@ class IrModuleToJsTransformer(
|
||||
ExportedModule(moduleName, exportedModule.moduleKind, exportedDeclarations),
|
||||
namer,
|
||||
refInfo,
|
||||
generateMainCall = false
|
||||
generateMainCall = false,
|
||||
)
|
||||
}.reversed()
|
||||
|
||||
@@ -123,7 +123,8 @@ class IrModuleToJsTransformer(
|
||||
emptyList(),
|
||||
exportedModule,
|
||||
namer,
|
||||
EmptyCrossModuleReferenceInfo
|
||||
EmptyCrossModuleReferenceInfo,
|
||||
generateMainCall = true,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -134,7 +135,7 @@ class IrModuleToJsTransformer(
|
||||
exportedModule: ExportedModule,
|
||||
namer: NameTables,
|
||||
refInfo: CrossModuleReferenceInfo,
|
||||
generateMainCall: Boolean = true
|
||||
generateMainCall: Boolean = true,
|
||||
): CompilationOutputs {
|
||||
|
||||
val nameGenerator = refInfo.withReferenceTracking(
|
||||
@@ -147,6 +148,7 @@ class IrModuleToJsTransformer(
|
||||
globalNameScope = namer.globalNames
|
||||
)
|
||||
|
||||
val polyfillStatements = generatePolyfillStatements(modules)
|
||||
val (importStatements, importedJsModules) =
|
||||
generateImportStatements(
|
||||
getNameForExternalDeclaration = { staticContext.getNameForStaticDeclaration(it) },
|
||||
@@ -163,8 +165,10 @@ class IrModuleToJsTransformer(
|
||||
val crossModuleExports = generateCrossModuleExports(modules, refInfo, internalModuleName)
|
||||
|
||||
val program = JsProgram()
|
||||
|
||||
if (generateScriptModule) {
|
||||
with(program.globalBlock) {
|
||||
statements.addWithComment("block: polyfills", polyfillStatements)
|
||||
statements.addWithComment("block: imports", importStatements + crossModuleImports)
|
||||
statements += moduleBody
|
||||
statements.addWithComment("block: exports", exportStatements + crossModuleExports)
|
||||
@@ -185,6 +189,7 @@ class IrModuleToJsTransformer(
|
||||
}
|
||||
}
|
||||
|
||||
program.globalBlock.statements.addWithComment("block: polyfills", polyfillStatements)
|
||||
program.globalBlock.statements += ModuleWrapperTranslation.wrap(
|
||||
exportedModule.name,
|
||||
rootFunction,
|
||||
@@ -223,7 +228,6 @@ class IrModuleToJsTransformer(
|
||||
null
|
||||
}
|
||||
|
||||
staticContext.polyfills.addAllNeededPolyfillsTo(jsCode)
|
||||
program.accept(JsToStringGenerationVisitor(jsCode, sourceMapBuilderConsumer ?: NoOpSourceLocationConsumer))
|
||||
|
||||
return CompilationOutputs(
|
||||
@@ -290,7 +294,6 @@ class IrModuleToJsTransformer(
|
||||
val statements = mutableListOf<JsStatement>()
|
||||
|
||||
val preDeclarationBlock = JsGlobalBlock()
|
||||
|
||||
val postDeclarationBlock = JsGlobalBlock()
|
||||
|
||||
statements.addWithComment("block: pre-declaration", preDeclarationBlock)
|
||||
@@ -394,6 +397,13 @@ class IrModuleToJsTransformer(
|
||||
} ?: emptyList()
|
||||
}
|
||||
|
||||
private fun generatePolyfillStatements(modules: Iterable<IrModuleFragment>): List<JsStatement> {
|
||||
return modules.asSequence()
|
||||
.flatMap { it.files }
|
||||
.flatMap { backendContext.polyfills.getAllPolyfillsFor(it) }
|
||||
.toList()
|
||||
}
|
||||
|
||||
private fun generateImportStatements(
|
||||
getNameForExternalDeclaration: (IrDeclarationWithName) -> JsName,
|
||||
declareFreshGlobal: (String) -> JsName
|
||||
|
||||
+12
-7
@@ -147,13 +147,16 @@ class IrModuleToJsTransformerTmp(
|
||||
modules: Iterable<IrModuleFragment>,
|
||||
exportData: Map<IrModuleFragment, Map<IrFile, List<ExportedDeclaration>>>,
|
||||
): JsIrProgram {
|
||||
|
||||
return JsIrProgram(
|
||||
modules.map { m ->
|
||||
JsIrModule(m.safeName, m.externalModuleName(), m.files.map { f ->
|
||||
val exports = exportData[m]!![f]!!
|
||||
generateProgramFragment(f, exports)
|
||||
})
|
||||
JsIrModule(
|
||||
m.safeName,
|
||||
m.externalModuleName(),
|
||||
m.files.map {
|
||||
val exports = exportData[m]!![it]!!
|
||||
generateProgramFragment(it, exports)
|
||||
},
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -172,7 +175,9 @@ class IrModuleToJsTransformerTmp(
|
||||
globalNameScope = globalNameScope
|
||||
)
|
||||
|
||||
val result = JsIrProgramFragment(file.fqName.asString())
|
||||
val result = JsIrProgramFragment(file.fqName.asString()).apply {
|
||||
polyfills.statements += backendContext.polyfills.getAllPolyfillsFor(file)
|
||||
}
|
||||
|
||||
val internalModuleName = ReservedJsNames.makeInternalModuleName()
|
||||
val globalNames = NameTable<String>(globalNameScope)
|
||||
@@ -364,7 +369,7 @@ private fun generateSingleWrappedModuleBody(
|
||||
sourceMapsInfo: SourceMapsInfo?,
|
||||
generateScriptModule: Boolean,
|
||||
generateCallToMain: Boolean,
|
||||
crossModuleReferences: CrossModuleReferences = CrossModuleReferences.Empty
|
||||
crossModuleReferences: CrossModuleReferences = CrossModuleReferences.Empty,
|
||||
): CompilationOutputs {
|
||||
val program = Merger(
|
||||
moduleName,
|
||||
|
||||
+6
-1
@@ -21,9 +21,14 @@ class JsIrProgramFragment(val packageFqn: String) {
|
||||
var testFunInvocation: JsStatement? = null
|
||||
var suiteFn: JsName? = null
|
||||
val definitions = mutableSetOf<String>()
|
||||
val polyfills = JsGlobalBlock()
|
||||
}
|
||||
|
||||
class JsIrModule(val moduleName: String, val externalModuleName: String, val fragments: List<JsIrProgramFragment>)
|
||||
class JsIrModule(
|
||||
val moduleName: String,
|
||||
val externalModuleName: String,
|
||||
val fragments: List<JsIrProgramFragment>,
|
||||
)
|
||||
|
||||
class JsIrProgram(val modules: List<JsIrModule>) {
|
||||
val mainModule = modules.last()
|
||||
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.transformers.irToJs
|
||||
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.getJsPolyfill
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.hasJsPolyfill
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsStatement
|
||||
|
||||
class JsPolyfills {
|
||||
private val polyfillsPerFile = hashMapOf<IrFile, HashSet<IrDeclaration>>()
|
||||
|
||||
fun registerDeclarationNativeImplementation(file: IrFile, declaration: IrDeclaration) {
|
||||
if (!declaration.hasJsPolyfill()) return
|
||||
val declarations = polyfillsPerFile[file] ?: hashSetOf()
|
||||
declarations.add(declaration)
|
||||
polyfillsPerFile[file] = declarations
|
||||
}
|
||||
|
||||
fun saveOnlyIntersectionOfNextDeclarationsFor(file: IrFile, declarations: Set<IrDeclaration>) {
|
||||
val polyfills = polyfillsPerFile[file] ?: return
|
||||
polyfillsPerFile[file] = polyfills.intersect(declarations).toHashSet()
|
||||
}
|
||||
|
||||
fun getAllPolyfillsFor(file: IrFile): List<JsStatement> =
|
||||
polyfillsPerFile[file].orEmpty().asImplementationList()
|
||||
|
||||
private fun Iterable<IrDeclaration>.asImplementationList() =
|
||||
asSequence().asImplementationList()
|
||||
|
||||
private fun Sequence<IrDeclaration>.asImplementationList(): List<JsStatement> =
|
||||
map { it.getJsPolyfill()!! }
|
||||
.distinct()
|
||||
.flatMap { parseJsCode(it).orEmpty() }
|
||||
.toList()
|
||||
}
|
||||
-28
@@ -1,28 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.transformers.irToJs
|
||||
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.getJsNativeImplementation
|
||||
import org.jetbrains.kotlin.ir.util.isEffectivelyExternal
|
||||
import org.jetbrains.kotlin.js.util.TextOutput
|
||||
|
||||
class JsPolyfillsVisitor {
|
||||
private val polyfills = mutableSetOf<String>()
|
||||
|
||||
fun visitDeclaration(declaration: IrDeclaration) {
|
||||
if (!declaration.isEffectivelyExternal()) return
|
||||
val implementation = declaration.getJsNativeImplementation() ?: return
|
||||
polyfills.add(implementation)
|
||||
}
|
||||
|
||||
fun addAllNeededPolyfillsTo(output: TextOutput) {
|
||||
if (polyfills.isEmpty()) return
|
||||
output.print("// region block: polyfills")
|
||||
output.print(polyfills.joinToString("\n"))
|
||||
output.print("// endregion\n")
|
||||
}
|
||||
}
|
||||
+18
-9
@@ -159,21 +159,22 @@ class Merger(
|
||||
|
||||
linkJsNames()
|
||||
|
||||
val moduleBody = mutableListOf<JsStatement>().also {
|
||||
if (!generateScriptModule) it += JsStringLiteral("use strict").makeStmt()
|
||||
}
|
||||
val moduleBody = mutableListOf<JsStatement>()
|
||||
|
||||
val preDeclarationBlock = JsGlobalBlock()
|
||||
val postDeclarationBlock = JsGlobalBlock()
|
||||
val polyfillDeclarationBlock = JsGlobalBlock()
|
||||
|
||||
moduleBody.addWithComment("block: pre-declaration", preDeclarationBlock)
|
||||
|
||||
val classModels = mutableMapOf<JsName, JsIrIcClassModel>()
|
||||
val initializerBlock = JsGlobalBlock()
|
||||
|
||||
fragments.forEach {
|
||||
moduleBody += it.declarations.statements
|
||||
classModels += it.classes
|
||||
initializerBlock.statements += it.initializers.statements
|
||||
polyfillDeclarationBlock.statements += it.polyfills.statements
|
||||
}
|
||||
|
||||
// sort member forwarding code
|
||||
@@ -213,9 +214,13 @@ class Merger(
|
||||
|
||||
if (generateScriptModule) {
|
||||
with(program.globalBlock) {
|
||||
this.statements.addWithComment("block: imports", importStatements)
|
||||
this.statements += moduleBody
|
||||
this.statements.addWithComment("block: exports", exportStatements)
|
||||
if (!generateScriptModule) {
|
||||
statements += JsStringLiteral("use strict").makeStmt()
|
||||
}
|
||||
statements.addWithComment("block: polyfills", polyfillDeclarationBlock.statements)
|
||||
statements.addWithComment("block: imports", importStatements)
|
||||
statements += moduleBody
|
||||
statements.addWithComment("block: exports", exportStatements)
|
||||
}
|
||||
} else {
|
||||
val internalModuleName = ReservedJsNames.makeInternalModuleName()
|
||||
@@ -223,9 +228,12 @@ class Merger(
|
||||
parameters += JsParameter(internalModuleName)
|
||||
parameters += (importedJsModules).map { JsParameter(it.internalName) }
|
||||
with(body) {
|
||||
this.statements.addWithComment("block: imports", importStatements)
|
||||
this.statements += moduleBody
|
||||
this.statements.addWithComment("block: exports", exportStatements)
|
||||
if (!generateScriptModule) {
|
||||
statements += JsStringLiteral("use strict").makeStmt()
|
||||
}
|
||||
statements.addWithComment("block: imports", importStatements)
|
||||
statements += moduleBody
|
||||
statements.addWithComment("block: exports", exportStatements)
|
||||
if (generateCallToMain) {
|
||||
callToMain?.let { this.statements += it }
|
||||
}
|
||||
@@ -233,6 +241,7 @@ class Merger(
|
||||
}
|
||||
}
|
||||
|
||||
program.globalBlock.statements.addWithComment("block: polyfills", polyfillDeclarationBlock.statements)
|
||||
program.globalBlock.statements += ModuleWrapperTranslation.wrap(
|
||||
moduleName,
|
||||
rootFunction,
|
||||
|
||||
+6
-3
@@ -27,7 +27,7 @@ object JsAnnotations {
|
||||
val jsNativeSetter = FqName("kotlin.js.nativeSetter")
|
||||
val jsNativeInvoke = FqName("kotlin.js.nativeInvoke")
|
||||
val jsFunFqn = FqName("kotlin.js.JsFun")
|
||||
val jsNativeImplementationFqn = FqName("kotlin.js.JsNativeImplementation")
|
||||
val JsPolyfillFqn = FqName("kotlin.js.JsPolyfill")
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
@@ -46,8 +46,11 @@ fun IrAnnotationContainer.getJsQualifier(): String? =
|
||||
fun IrAnnotationContainer.getJsName(): String? =
|
||||
getAnnotation(JsAnnotations.jsNameFqn)?.getSingleConstStringArgument()
|
||||
|
||||
fun IrAnnotationContainer.getJsNativeImplementation(): String? =
|
||||
getAnnotation(JsAnnotations.jsNativeImplementationFqn)?.getSingleConstStringArgument()
|
||||
fun IrAnnotationContainer.getJsPolyfill(): String? =
|
||||
getAnnotation(JsAnnotations.JsPolyfillFqn)?.getSingleConstStringArgument()
|
||||
|
||||
fun IrAnnotationContainer.hasJsPolyfill(): Boolean =
|
||||
hasAnnotation(JsAnnotations.JsPolyfillFqn)
|
||||
|
||||
fun IrAnnotationContainer.getJsFunAnnotation(): String? =
|
||||
getAnnotation(JsAnnotations.jsFunFqn)?.getSingleConstStringArgument()
|
||||
|
||||
@@ -8,7 +8,6 @@ package org.jetbrains.kotlin.ir.backend.js.utils
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.JsIntrinsicTransformers
|
||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.JsIrClassModel
|
||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.JsPolyfillsVisitor
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsGlobalBlock
|
||||
@@ -20,7 +19,6 @@ class JsStaticContext(
|
||||
private val irNamer: IrNamer,
|
||||
val globalNameScope: NameTable<IrDeclaration>,
|
||||
) : IrNamer by irNamer {
|
||||
val polyfills = JsPolyfillsVisitor()
|
||||
val intrinsics = JsIntrinsicTransformers(backendContext)
|
||||
val classModels = mutableMapOf<IrClassSymbol, JsIrClassModel>()
|
||||
val coroutineImplDeclaration = backendContext.ir.symbols.coroutineImpl.owner
|
||||
|
||||
+3
-2
@@ -5,7 +5,6 @@
|
||||
|
||||
package org.jetbrains.kotlin.ir.backend.js.utils.serialization
|
||||
|
||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.JsIrClassModel
|
||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.JsIrIcClassModel
|
||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.JsIrProgramFragment
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.emptyScope
|
||||
@@ -60,6 +59,9 @@ class JsIrAstDeserializer : JsAstDeserializerBase() {
|
||||
if (proto.hasExportBlock()) {
|
||||
fragment.exports.statements += deserializeGlobalBlock(proto.exportBlock).statements
|
||||
}
|
||||
if (proto.hasPolyfills()) {
|
||||
fragment.polyfills.statements += deserializeGlobalBlock(proto.polyfills).statements
|
||||
}
|
||||
|
||||
proto.nameBindingList.associateTo(fragment.nameBindings) { nameBindingProto ->
|
||||
deserializeString(nameBindingProto.signatureId) to deserializeName(nameBindingProto.nameId)
|
||||
@@ -80,7 +82,6 @@ class JsIrAstDeserializer : JsAstDeserializerBase() {
|
||||
}
|
||||
|
||||
fragment.dts = proto.dts
|
||||
|
||||
fragment.definitions += proto.definitionsList.map { deserializeString(it) }
|
||||
|
||||
return fragment
|
||||
|
||||
+2
@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.JsIrProgramFragmen
|
||||
import org.jetbrains.kotlin.js.backend.ast.*
|
||||
import org.jetbrains.kotlin.serialization.js.ast.JsAstProtoBuf.*
|
||||
import org.jetbrains.kotlin.serialization.js.ast.JsAstSerializerBase
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.ifNotEmpty
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
import java.io.OutputStream
|
||||
|
||||
@@ -60,6 +61,7 @@ class JsIrAstSerializer: JsAstSerializerBase() {
|
||||
fragmentBuilder.declarationBlock = serializeBlock(fragment.declarations)
|
||||
fragmentBuilder.initializerBlock = serializeBlock(fragment.initializers)
|
||||
fragmentBuilder.exportBlock = serializeBlock(fragment.exports)
|
||||
fragmentBuilder.polyfills = serializeBlock(fragment.polyfills)
|
||||
|
||||
for ((key, name) in fragment.nameBindings.entries) {
|
||||
val nameBindingBuilder = NameBinding.newBuilder()
|
||||
|
||||
Reference in New Issue
Block a user