[IR JS BE] update NameTables for working with repl

This commit is contained in:
Vitaliy.Tikhonov
2019-08-30 15:52:57 +03:00
committed by romanart
parent 184ae2fa43
commit 24cfd0e88c
3 changed files with 148 additions and 65 deletions
@@ -262,12 +262,18 @@ class JsIntrinsics(private val irBuiltIns: IrBuiltIns, val context: JsIrBackendC
// TODO move CharSequence-related stiff to IntrinsifyCallsLowering
val charSequenceClassSymbol = context.symbolTable.referenceClass(context.getClass(FqName("kotlin.CharSequence")))
val charSequenceLengthPropertyGetterSymbol =
charSequenceClassSymbol.owner.declarations.filterIsInstance<IrProperty>().first { it.name.asString() == "length" }.getter!!.symbol
val charSequenceGetFunctionSymbol =
val charSequenceLengthPropertyGetterSymbol by lazy {
with(charSequenceClassSymbol.owner.declarations) {
filterIsInstance<IrProperty>().firstOrNull { it.name.asString() == "length" }?.getter ?:
filterIsInstance<IrFunction>().first { it.name.asString() == "<get-length>" }
}.symbol
}
val charSequenceGetFunctionSymbol by lazy {
charSequenceClassSymbol.owner.declarations.filterIsInstance<IrFunction>().single { it.name.asString() == "get" }.symbol
val charSequenceSubSequenceFunctionSymbol =
}
val charSequenceSubSequenceFunctionSymbol by lazy {
charSequenceClassSymbol.owner.declarations.filterIsInstance<IrFunction>().single { it.name.asString() == "subSequence" }.symbol
}
val jsCharSequenceGet = getInternalFunction("charSequenceGet")
@@ -73,7 +73,7 @@ class IrModuleToJsTransformer(
module.files.forEach { StaticMembersLowering(backendContext).lower(it) }
val namer = NameTables(module.files + additionalPackages)
namer.merge(module.files, additionalPackages)
val program = JsProgram()
@@ -102,25 +102,33 @@ class IrModuleToJsTransformer(
val exportStatements = ExportModelToJsStatements(internalModuleName, namer)
.generateModuleExport(exportedModule)
with(rootFunction) {
parameters += JsParameter(internalModuleName)
parameters += importedJsModules.map { JsParameter(it.internalName) }
with(body) {
if (generateScriptModule) {
with(program.globalBlock) {
statements += importStatements
statements += moduleBody
statements += exportStatements
statements += generateCallToMain(rootContext)
statements += JsReturn(internalModuleName.makeRef())
}
}
} else {
with(rootFunction) {
parameters += JsParameter(internalModuleName)
parameters += importedJsModules.map { JsParameter(it.internalName) }
with(body) {
statements += importStatements
statements += moduleBody
statements += exportStatements
statements += generateCallToMain(rootContext)
statements += JsReturn(internalModuleName.makeRef())
}
}
program.globalBlock.statements += ModuleWrapperTranslation.wrap(
moduleName,
rootFunction,
importedJsModules,
program,
kind = moduleKind
)
program.globalBlock.statements += ModuleWrapperTranslation.wrap(
moduleName,
rootFunction,
importedJsModules,
program,
kind = moduleKind
)
}
return CompilerResult(program.toString(), dts)
}
@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.backend.common.ir.isMethodOfAny
import org.jetbrains.kotlin.backend.common.ir.isTopLevel
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.backend.js.JsLoweredDeclarationOrigin
import org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir.JsMangler
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.IrLoop
import org.jetbrains.kotlin.ir.types.isUnit
@@ -21,10 +22,24 @@ import org.jetbrains.kotlin.js.naming.isES5IdentifierStart
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.utils.addToStdlib.ifNotEmpty
fun <T> mapToKey(declaration: T): String {
return with(JsMangler) {
if (declaration is IrDeclaration && isPublic(declaration)) {
declaration.hashedMangle.toString()
} else if (declaration is Signature) {
declaration.toString().hashMangle.toString()
} else "key_have_not_generated"
}
}
fun JsMangler.isPublic(declaration: IrDeclaration) =
declaration.isExported() && declaration !is IrScript && declaration !is IrVariable && declaration !is IrValueParameter
class NameTable<T>(
val parent: NameTable<*>? = null,
private val reserved: MutableSet<String> = mutableSetOf(),
val sanitizer: (String) -> String = ::sanitizeName
val reserved: MutableSet<String> = mutableSetOf(),
val sanitizer: (String) -> String = ::sanitizeName,
val mappedNames: MutableMap<String, String> = mutableMapOf()
) {
var finished = false
val names = mutableMapOf<T, String>()
@@ -40,6 +55,7 @@ class NameTable<T>(
assert(!finished)
names[declaration] = name
reserved.add(name)
mappedNames[mapToKey(declaration)] = name
}
fun declareFreshName(declaration: T, suggestedName: String): String {
@@ -134,7 +150,12 @@ fun functionSignature(declaration: IrFunction): Signature {
return ParameterTypeBasedSignature(signature, declarationName)
}
class NameTables(packages: List<IrPackageFragment>) {
class NameTables(
packages: List<IrPackageFragment>,
reservedForGlobal: MutableSet<String> = mutableSetOf(),
reservedForMember: MutableSet<String> = mutableSetOf(),
val mappedNames: MutableMap<String, String> = mutableMapOf()
) {
val globalNames: NameTable<IrDeclaration>
private val memberNames: NameTable<Signature>
private val localNames = mutableMapOf<IrDeclaration, NameTable<IrDeclaration>>()
@@ -144,61 +165,108 @@ class NameTables(packages: List<IrPackageFragment>) {
val stableNamesCollector = StableNamesCollector()
packages.forEach { it.acceptChildrenVoid(stableNamesCollector) }
globalNames = NameTable(reserved = stableNamesCollector.staticNames)
memberNames = NameTable(reserved = stableNamesCollector.memberNames)
globalNames = NameTable(
reserved = (stableNamesCollector.staticNames + reservedForGlobal).toMutableSet(),
mappedNames = mappedNames
)
memberNames = NameTable(
reserved = (stableNamesCollector.memberNames + reservedForMember).toMutableSet(),
mappedNames = mappedNames
)
mappedNames.addAllIfAbsent(mappedNames)
val classDeclaration = mutableListOf<IrClass>()
for (p in packages) {
for (declaration in p.declarations) {
generateNamesForTopLevelDecl(declaration)
if (declaration is IrScript) {
for (memberDecl in declaration.declarations) {
generateNamesForTopLevelDecl(memberDecl)
if (memberDecl is IrClass) {
classDeclaration += memberDecl
}
}
}
}
}
globalNames.finished = true
for (declaration in classDeclaration) {
acceptDeclaration(declaration)
}
for (p in packages) {
for (declaration in p.declarations) {
val localNameGenerator = LocalNameGenerator(declaration)
if (declaration is IrClass) {
if (declaration.isEffectivelyExternal()) {
declaration.acceptChildrenVoid(object : IrElementVisitorVoid {
override fun visitElement(element: IrElement) {
element.acceptChildrenVoid(this)
}
override fun visitSimpleFunction(declaration: IrSimpleFunction) {
val parent = declaration.parent
if (parent is IrClass && !parent.isEnumClass) {
generateNameForMemberFunction(declaration)
}
}
override fun visitField(declaration: IrField) {
val parent = declaration.parent
if (parent is IrClass && !parent.isEnumClass) {
generateNameForMemberField(declaration)
}
}
})
} else {
declaration.thisReceiver!!.acceptVoid(localNameGenerator)
for (memberDecl in declaration.declarations) {
memberDecl.acceptChildrenVoid(LocalNameGenerator(memberDecl))
when (memberDecl) {
is IrSimpleFunction ->
generateNameForMemberFunction(memberDecl)
is IrField ->
generateNameForMemberField(memberDecl)
}
}
}
} else {
declaration.acceptChildrenVoid(localNameGenerator)
}
acceptDeclaration(declaration)
}
}
}
private fun acceptDeclaration(declaration: IrDeclaration) {
val localNameGenerator = LocalNameGenerator(declaration)
if (declaration is IrClass) {
if (declaration.isEffectivelyExternal()) {
declaration.acceptChildrenVoid(object : IrElementVisitorVoid {
override fun visitElement(element: IrElement) {
element.acceptChildrenVoid(this)
}
override fun visitSimpleFunction(declaration: IrSimpleFunction) {
val parent = declaration.parent
if (parent is IrClass && !parent.isEnumClass) {
generateNameForMemberFunction(declaration)
}
}
override fun visitField(declaration: IrField) {
val parent = declaration.parent
if (parent is IrClass && !parent.isEnumClass) {
generateNameForMemberField(declaration)
}
}
})
} else {
declaration.thisReceiver!!.acceptVoid(localNameGenerator)
for (memberDecl in declaration.declarations) {
memberDecl.acceptChildrenVoid(LocalNameGenerator(memberDecl))
when (memberDecl) {
is IrSimpleFunction ->
generateNameForMemberFunction(memberDecl)
is IrField ->
generateNameForMemberField(memberDecl)
}
}
}
} else {
declaration.acceptChildrenVoid(localNameGenerator)
}
}
private fun <T, K> MutableMap<T, K>.addAllIfAbsent(other: Map<T, K>) {
this += other.filter { it.key !in this }
}
private fun packagesAdded() = mappedNames.isEmpty()
fun merge(files: List<IrPackageFragment>, additionalPackages: List<IrPackageFragment>) {
val packages = mutableListOf<IrPackageFragment>().also { it.addAll(files) }
if (packagesAdded()) packages.addAll(additionalPackages)
val table = NameTables(packages, globalNames.reserved, memberNames.reserved, mappedNames)
globalNames.names.addAllIfAbsent(table.globalNames.names)
memberNames.names.addAllIfAbsent(table.memberNames.names)
localNames.addAllIfAbsent(table.localNames)
loopNames.addAllIfAbsent(table.loopNames)
globalNames.reserved.addAll(table.globalNames.reserved)
memberNames.reserved.addAll(table.memberNames.reserved)
}
private fun generateNameForMemberField(field: IrField) {
require(!field.isTopLevel)
require(!field.isStatic)
@@ -257,12 +325,13 @@ class NameTables(packages: List<IrPackageFragment>) {
parent = parent.parent
}
error("Can't find name for declaration ${declaration.fqNameWhenAvailable}")
return mappedNames[mapToKey(declaration)] ?: error("Can't find name for declaration ${declaration.fqNameWhenAvailable}")
}
fun getNameForMemberField(field: IrField): String {
val signature = fieldSignature(field)
val name = memberNames.names[signature]
val name = memberNames.names[signature] ?: mappedNames[mapToKey(signature)]
require(name != null) {
"Can't find name for member field $field"
}
@@ -271,7 +340,7 @@ class NameTables(packages: List<IrPackageFragment>) {
fun getNameForMemberFunction(function: IrSimpleFunction): String {
val signature = functionSignature(function)
val name = memberNames.names[signature]
val name = memberNames.names[signature] ?: mappedNames[mapToKey(signature)]
// TODO: Fix hack: Coroutines runtime currently relies on stable names
// of `invoke` functions in FunctionN interfaces