[JS IR] Cache JsLocation objects and js function signatures
Memory consumption optimization
This commit is contained in:
committed by
Space
parent
ff2f16190d
commit
bf53273b84
@@ -408,4 +408,10 @@ class JsIrBackendContext(
|
|||||||
outlinedJsCodeFunctions[symbol] = parsedJsFunction
|
outlinedJsCodeFunctions[symbol] = parsedJsFunction
|
||||||
return parsedJsFunction
|
return parsedJsFunction
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var irFunctionSignatureCache = hashMapOf<IrFunction, String>()
|
||||||
|
|
||||||
|
fun getFunctionSignatureFromCache(f: IrFunction): String {
|
||||||
|
return irFunctionSignatureCache.getOrPut(f) { calculateJsFunctionSignature(f, this) }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-2
@@ -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) {
|
private inline fun <T : JsNode> T.addSourceInfoIfNeed(node: IrElement, context: JsGenerationContext) {
|
||||||
if (!context.staticContext.genSourcemaps) return
|
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
|
// TODO maybe it's better to fix in JsExpressionStatement
|
||||||
val locationTarget = if (this is JsExpressionStatement) this.expression else this
|
val locationTarget = if (this is JsExpressionStatement) this.expression else this
|
||||||
locationTarget.source = sourceInfo
|
locationTarget.source = cachedLocation
|
||||||
}
|
}
|
||||||
|
|
||||||
fun IrElement.getSourceInfo(container: IrDeclaration): JsLocation? {
|
fun IrElement.getSourceInfo(container: IrDeclaration): JsLocation? {
|
||||||
|
|||||||
+8
-1
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.ir.declarations.*
|
|||||||
import org.jetbrains.kotlin.ir.expressions.IrLoop
|
import org.jetbrains.kotlin.ir.expressions.IrLoop
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrReturnableBlock
|
import org.jetbrains.kotlin.ir.expressions.IrReturnableBlock
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
|
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.JsName
|
||||||
import org.jetbrains.kotlin.js.backend.ast.JsScope
|
import org.jetbrains.kotlin.js.backend.ast.JsScope
|
||||||
|
|
||||||
@@ -27,7 +28,9 @@ class JsGenerationContext(
|
|||||||
val localNames: LocalNameGenerator? = null,
|
val localNames: LocalNameGenerator? = null,
|
||||||
private val nameCache: MutableMap<IrElement, JsName> = mutableMapOf(),
|
private val nameCache: MutableMap<IrElement, JsName> = mutableMapOf(),
|
||||||
private val useBareParameterNames: Boolean = false,
|
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 {
|
fun newFile(file: IrFile, func: IrFunction? = null, localNames: LocalNameGenerator? = null): JsGenerationContext {
|
||||||
return JsGenerationContext(
|
return JsGenerationContext(
|
||||||
currentFile = file,
|
currentFile = file,
|
||||||
@@ -79,4 +82,8 @@ class JsGenerationContext(
|
|||||||
fun checkIfJsCode(symbol: IrFunctionSymbol): Boolean = symbol == staticContext.backendContext.intrinsics.jsCode
|
fun checkIfJsCode(symbol: IrFunctionSymbol): Boolean = symbol == staticContext.backendContext.intrinsics.jsCode
|
||||||
|
|
||||||
fun checkIfHasAssociatedJsCode(symbol: IrFunctionSymbol): Boolean = staticContext.backendContext.getJsCodeForFunction(symbol) != null
|
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 {
|
fun calculateJsFunctionSignature(declaration: IrFunction, context: JsIrBackendContext): String {
|
||||||
require(!declaration.isStaticMethodOfClass)
|
val declarationName = declaration.nameIfPropertyAccessor() ?: declaration.getJsNameOrKotlinName().asString()
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
val nameBuilder = StringBuilder()
|
val nameBuilder = StringBuilder()
|
||||||
nameBuilder.append(declarationName)
|
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
|
) + "_" + 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(
|
class NameTables(
|
||||||
packages: Iterable<IrPackageFragment>,
|
packages: Iterable<IrPackageFragment>,
|
||||||
reservedForGlobal: MutableSet<String> = mutableSetOf(),
|
reservedForGlobal: MutableSet<String> = mutableSetOf(),
|
||||||
@@ -411,7 +413,8 @@ fun sanitizeName(name: String, withHash: Boolean = true): String {
|
|||||||
if (name.isValidES5Identifier()) return name
|
if (name.isValidES5Identifier()) return name
|
||||||
if (name.isEmpty()) return "_"
|
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()
|
val first = name.first()
|
||||||
|
|
||||||
|
|||||||
@@ -19,12 +19,14 @@ package org.jetbrains.kotlin.js.backend.ast
|
|||||||
import java.io.Reader
|
import java.io.Reader
|
||||||
|
|
||||||
data class JsLocation(
|
data class JsLocation(
|
||||||
override val file: String,
|
override val file: String,
|
||||||
override val startLine: Int,
|
override val startLine: Int,
|
||||||
override val startChar: Int
|
override val startChar: Int
|
||||||
) : JsLocationWithSource {
|
) : JsLocationWithSource {
|
||||||
override val identityObject: Any? = null
|
override val identityObject: Any?
|
||||||
override val sourceProvider: () -> Reader? = { null }
|
get() = null
|
||||||
|
override val sourceProvider: () -> Reader?
|
||||||
|
get() = { null }
|
||||||
|
|
||||||
override fun asSimpleLocation(): JsLocation = this
|
override fun asSimpleLocation(): JsLocation = this
|
||||||
}
|
}
|
||||||
@@ -40,7 +42,7 @@ interface JsLocationWithSource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class JsLocationWithEmbeddedSource(
|
class JsLocationWithEmbeddedSource(
|
||||||
private val location: JsLocation,
|
private val location: JsLocation,
|
||||||
override val identityObject: Any?,
|
override val identityObject: Any?,
|
||||||
override val sourceProvider: () -> Reader?
|
override val sourceProvider: () -> Reader?
|
||||||
) : JsLocationWithSource by location
|
) : JsLocationWithSource by location
|
||||||
|
|||||||
Reference in New Issue
Block a user