[JS IR] Cache JsLocation objects and js function signatures

Memory consumption optimization
This commit is contained in:
Alexander Korepanov
2022-08-25 17:00:12 +02:00
committed by Space
parent ff2f16190d
commit bf53273b84
5 changed files with 52 additions and 30 deletions
@@ -408,4 +408,10 @@ class JsIrBackendContext(
outlinedJsCodeFunctions[symbol] = parsedJsFunction
return parsedJsFunction
}
private var irFunctionSignatureCache = hashMapOf<IrFunction, String>()
fun getFunctionSignatureFromCache(f: IrFunction): String {
return irFunctionSignatureCache.getOrPut(f) { calculateJsFunctionSignature(f, this) }
}
}
@@ -494,11 +494,15 @@ internal fun <T : JsNode> T.withSource(node: IrElement, context: JsGenerationCon
private inline fun <T : JsNode> T.addSourceInfoIfNeed(node: IrElement, context: JsGenerationContext) {
if (!context.staticContext.genSourcemaps) return
val sourceInfo = node.getSourceInfo(context.currentFile.fileEntry) ?: return
var cachedLocation = context.getLocationFromCache(node)
if (cachedLocation == null) {
cachedLocation = node.getSourceInfo(context.currentFile.fileEntry) ?: return
context.saveLocationToCache(node, cachedLocation)
}
// TODO maybe it's better to fix in JsExpressionStatement
val locationTarget = if (this is JsExpressionStatement) this.expression else this
locationTarget.source = sourceInfo
locationTarget.source = cachedLocation
}
fun IrElement.getSourceInfo(container: IrDeclaration): JsLocation? {
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.IrLoop
import org.jetbrains.kotlin.ir.expressions.IrReturnableBlock
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
import org.jetbrains.kotlin.js.backend.ast.JsLocation
import org.jetbrains.kotlin.js.backend.ast.JsName
import org.jetbrains.kotlin.js.backend.ast.JsScope
@@ -27,7 +28,9 @@ class JsGenerationContext(
val localNames: LocalNameGenerator? = null,
private val nameCache: MutableMap<IrElement, JsName> = mutableMapOf(),
private val useBareParameterNames: Boolean = false,
): IrNamer by staticContext {
) : IrNamer by staticContext {
private val locationCache = mutableMapOf<Int, JsLocation>()
fun newFile(file: IrFile, func: IrFunction? = null, localNames: LocalNameGenerator? = null): JsGenerationContext {
return JsGenerationContext(
currentFile = file,
@@ -79,4 +82,8 @@ class JsGenerationContext(
fun checkIfJsCode(symbol: IrFunctionSymbol): Boolean = symbol == staticContext.backendContext.intrinsics.jsCode
fun checkIfHasAssociatedJsCode(symbol: IrFunctionSymbol): Boolean = staticContext.backendContext.getJsCodeForFunction(symbol) != null
fun getLocationFromCache(node: IrElement) = locationCache[node.startOffset]
fun saveLocationToCache(node: IrElement, location: JsLocation) = locationCache.put(node.startOffset, location)
}
@@ -115,23 +115,8 @@ fun Int.toJsIdentifier(): String {
}
}
fun jsFunctionSignature(declaration: IrFunction, context: JsIrBackendContext): String {
require(!declaration.isStaticMethodOfClass)
require(declaration.dispatchReceiverParameter != null)
var declarationName = declaration.getJsNameOrKotlinName().asString()
if (declaration.hasStableJsName(context)) {
// TODO: Handle reserved suffix in FE
require(!declarationName.endsWith(RESERVED_MEMBER_NAME_SUFFIX)) {
"Function ${declaration.fqNameWhenAvailable} uses reserved name suffix \"$RESERVED_MEMBER_NAME_SUFFIX\""
}
return declarationName
}
declaration.nameIfPropertyAccessor()?.let {
declarationName = it
}
fun calculateJsFunctionSignature(declaration: IrFunction, context: JsIrBackendContext): String {
val declarationName = declaration.nameIfPropertyAccessor() ?: declaration.getJsNameOrKotlinName().asString()
val nameBuilder = StringBuilder()
nameBuilder.append(declarationName)
@@ -170,6 +155,23 @@ fun jsFunctionSignature(declaration: IrFunction, context: JsIrBackendContext): S
) + "_" + abs(signature.hashCode()).toString(Character.MAX_RADIX) + RESERVED_MEMBER_NAME_SUFFIX
}
fun jsFunctionSignature(declaration: IrFunction, context: JsIrBackendContext): String {
require(!declaration.isStaticMethodOfClass)
require(declaration.dispatchReceiverParameter != null)
if (declaration.hasStableJsName(context)) {
val declarationName = declaration.getJsNameOrKotlinName().asString()
// TODO: Handle reserved suffix in FE
require(!declarationName.endsWith(RESERVED_MEMBER_NAME_SUFFIX)) {
"Function ${declaration.fqNameWhenAvailable} uses reserved name suffix \"$RESERVED_MEMBER_NAME_SUFFIX\""
}
return declarationName
}
val declarationSignature = (declaration as? IrSimpleFunction)?.resolveFakeOverride() ?: declaration
return context.getFunctionSignatureFromCache(declarationSignature)
}
class NameTables(
packages: Iterable<IrPackageFragment>,
reservedForGlobal: MutableSet<String> = mutableSetOf(),
@@ -411,7 +413,8 @@ fun sanitizeName(name: String, withHash: Boolean = true): String {
if (name.isValidES5Identifier()) return name
if (name.isEmpty()) return "_"
val builder = StringBuilder()
// 7 = _ + MAX_INT.toString(Character.MAX_RADIX)
val builder = StringBuilder(name.length + if (withHash) 7 else 0)
val first = name.first()
@@ -19,12 +19,14 @@ package org.jetbrains.kotlin.js.backend.ast
import java.io.Reader
data class JsLocation(
override val file: String,
override val startLine: Int,
override val startChar: Int
override val file: String,
override val startLine: Int,
override val startChar: Int
) : JsLocationWithSource {
override val identityObject: Any? = null
override val sourceProvider: () -> Reader? = { null }
override val identityObject: Any?
get() = null
override val sourceProvider: () -> Reader?
get() = { null }
override fun asSimpleLocation(): JsLocation = this
}
@@ -40,7 +42,7 @@ interface JsLocationWithSource {
}
class JsLocationWithEmbeddedSource(
private val location: JsLocation,
override val identityObject: Any?,
override val sourceProvider: () -> Reader?
) : JsLocationWithSource by location
private val location: JsLocation,
override val identityObject: Any?,
override val sourceProvider: () -> Reader?
) : JsLocationWithSource by location