diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsIrBackendContext.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsIrBackendContext.kt index 24bdd1a649f..9cb95504339 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsIrBackendContext.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsIrBackendContext.kt @@ -408,4 +408,10 @@ class JsIrBackendContext( outlinedJsCodeFunctions[symbol] = parsedJsFunction return parsedJsFunction } + + private var irFunctionSignatureCache = hashMapOf() + + fun getFunctionSignatureFromCache(f: IrFunction): String { + return irFunctionSignatureCache.getOrPut(f) { calculateJsFunctionSignature(f, this) } + } } diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/jsAstUtils.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/jsAstUtils.kt index 70d9331642d..c0fa58c570b 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/jsAstUtils.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/jsAstUtils.kt @@ -494,11 +494,15 @@ internal fun T.withSource(node: IrElement, context: JsGenerationCon private inline fun 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? { diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/JsGenerationContext.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/JsGenerationContext.kt index 8bc3e62548e..ca8d95431be 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/JsGenerationContext.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/JsGenerationContext.kt @@ -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 = mutableMapOf(), private val useBareParameterNames: Boolean = false, -): IrNamer by staticContext { +) : IrNamer by staticContext { + private val locationCache = mutableMapOf() + 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) } diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/NameTables.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/NameTables.kt index cee1a2b0fa3..5e9cb1b396d 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/NameTables.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/NameTables.kt @@ -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, reservedForGlobal: MutableSet = 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() diff --git a/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/JsLocation.kt b/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/JsLocation.kt index 4519d9af843..0ccd76f85ba 100644 --- a/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/JsLocation.kt +++ b/js/js.ast/src/org/jetbrains/kotlin/js/backend/ast/JsLocation.kt @@ -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 \ No newline at end of file + private val location: JsLocation, + override val identityObject: Any?, + override val sourceProvider: () -> Reader? +) : JsLocationWithSource by location