From 5dcb0ee016d52f6735c7bb8d5ce251142ddc0c42 Mon Sep 17 00:00:00 2001 From: Svyatoslav Kuzmich Date: Thu, 27 Jun 2019 18:32:34 +0300 Subject: [PATCH] [JS IR BE] Reduce JsScope usage in codegen --- .../irToJs/IrDeclarationToJsTransformer.kt | 7 +------ .../IrElementToJsExpressionTransformer.kt | 4 ++-- .../irToJs/IrElementToJsStatementTransformer.kt | 3 ++- .../irToJs/IrFileToJsTransformer.kt | 12 +++++------- .../irToJs/IrModuleToJsTransformer.kt | 10 +++------- .../js/transformers/irToJs/JsClassGenerator.kt | 11 ++++++----- .../irToJs/JsIntrinsicTransformers.kt | 5 +++-- .../js/transformers/irToJs/jsAstUtils.kt | 10 +++++----- .../ir/backend/js/transformers/irToJs/jsCode.kt | 12 ++++++------ .../ir/backend/js/utils/JsGenerationContext.kt | 17 +++++++++-------- 10 files changed, 42 insertions(+), 49 deletions(-) diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrDeclarationToJsTransformer.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrDeclarationToJsTransformer.kt index 58a62fe6350..a09ff04aa0a 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrDeclarationToJsTransformer.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrDeclarationToJsTransformer.kt @@ -24,12 +24,7 @@ class IrDeclarationToJsTransformer : BaseIrElementToJsNodeTransformer { - override fun visitFile(declaration: IrFile, data: JsGenerationContext): JsStatement { - val fileContext = data.newDeclaration(JsDeclarationScope(data.currentScope, "scope for file ${declaration.path}")) - val block = fileContext.currentBlock +class IrFileToJsTransformer : BaseIrElementToJsNodeTransformer { + override fun visitFile(declaration: IrFile, data: JsGenerationContext): JsBlock { + val fileContext = data.newDeclaration() + val block = JsBlock() declaration.declarations.forEach { block.statements.add(it.accept(IrDeclarationToJsTransformer(), fileContext)) diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrModuleToJsTransformer.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrModuleToJsTransformer.kt index 7322ad7ae74..8daf9aa65ed 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrModuleToJsTransformer.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/IrModuleToJsTransformer.kt @@ -6,7 +6,6 @@ package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs import org.jetbrains.kotlin.config.CommonConfigurationKeys -import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext import org.jetbrains.kotlin.ir.backend.js.utils.* @@ -50,7 +49,7 @@ class IrModuleToJsTransformer( module.files.forEach { statements.add(JsDocComment(mapOf("file" to it.path)).makeStmt()) - statements.add(it.accept(IrFileToJsTransformer(), context)) + statements.addAll(it.accept(IrFileToJsTransformer(), context).statements) } // sort member forwarding code @@ -145,20 +144,17 @@ class IrModuleToJsTransformer( irNamer = nameGenerator ) val rootContext = JsGenerationContext( - parent = null, - currentBlock = program.globalBlock, currentFunction = null, - currentScope = program.rootScope, staticContext = staticContext ) val rootFunction = JsFunction(program.rootScope, JsBlock(), "root function") - val internalModuleName = rootFunction.scope.declareName("_") + val internalModuleName = JsName("_") val (importStatements, importedJsModules) = generateImportStatements( getNameForExternalDeclaration = { rootContext.getNameForStaticDeclaration(it) }, - declareFreshGlobal = { rootFunction.scope.declareFreshName(sanitizeName(it)) } + declareFreshGlobal = { JsName(sanitizeName(it)) } // TODO: Declare fresh name ) val moduleBody = generateModuleBody(module, rootContext) diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/JsClassGenerator.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/JsClassGenerator.kt index 1c4dc89db32..f3ab84ad4d5 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/JsClassGenerator.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/JsClassGenerator.kt @@ -10,6 +10,7 @@ import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.ir.backend.js.utils.JsGenerationContext import org.jetbrains.kotlin.ir.backend.js.utils.Namer +import org.jetbrains.kotlin.ir.backend.js.utils.emptyScope import org.jetbrains.kotlin.ir.backend.js.utils.realOverrideTarget import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.symbols.IrClassSymbol @@ -126,7 +127,7 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo val getterName = context.getNameForMemberFunction(delegate) val returnStatement = JsReturn(JsInvocation(JsNameRef(getterName, JsThisRef()))) - return JsFunction(JsFunctionScope(context.currentScope, ""), JsBlock(returnStatement), "") + return JsFunction(emptyScope, JsBlock(returnStatement), "") } private fun generateMemberFunction(declaration: IrSimpleFunction): JsStatement? { @@ -182,7 +183,7 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo private fun maybeGenerateObjectInstance(): List { val instanceVarName = className.objectInstanceName() val getInstanceFunName = "${className.ident}_getInstance" - val jsVarNode = context.currentScope.declareName(instanceVarName) + val jsVarNode = JsName(instanceVarName) // TODO: Use namer? val varStmt = JsVars(JsVars.JsVar(jsVarNode)) val function = generateGetInstanceFunction(jsVarNode, getInstanceFunName) return listOf(varStmt, function.makeStmt()) @@ -190,8 +191,8 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo private fun generateGetInstanceFunction(instanceVar: JsName, instanceFunName: String): JsFunction { val functionBody = JsBlock() - val func = JsFunction(JsFunctionScope(context.currentScope, "getInstance for ${irClass.name} object"), functionBody, "getInstance") - func.name = context.currentScope.declareName(instanceFunName) + val func = JsFunction(emptyScope, functionBody, "getInstance") + func.name = JsName(instanceFunName) // TODO: Use namer? functionBody.statements += JsIf( JsBinaryOperation(JsBinaryOperator.REF_EQ, instanceVar.makeRef(), JsPrefixOperation(JsUnaryOperator.VOID, JsIntLiteral(0))), @@ -204,7 +205,7 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo private fun maybeGeneratePrimaryConstructor() { if (!irClass.declarations.any { it is IrConstructor }) { - val func = JsFunction(JsFunctionScope(context.currentScope, "Ctor for ${irClass.name}"), JsBlock(), "Ctor for ${irClass.name}") + val func = JsFunction(emptyScope, JsBlock(), "Ctor for ${irClass.name}") func.name = className classBlock.statements += func.makeStmt() classModel.preDeclarationBlock.statements += generateInheritanceCode() diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/JsIntrinsicTransformers.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/JsIntrinsicTransformers.kt index ac0211eb33f..fc11f18048c 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/JsIntrinsicTransformers.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/JsIntrinsicTransformers.kt @@ -8,6 +8,7 @@ package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext import org.jetbrains.kotlin.ir.backend.js.utils.JsGenerationContext import org.jetbrains.kotlin.ir.backend.js.utils.Namer +import org.jetbrains.kotlin.ir.backend.js.utils.emptyScope import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.expressions.IrCall import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression @@ -121,12 +122,12 @@ class JsIntrinsicTransformers(backendContext: JsIrBackendContext) { } addIfNotNull(intrinsics.jsCode) { call, context -> - val jsCode = translateJsCode(call as IrCall, context.currentScope) + val jsCode = translateJsCode(call as IrCall) when (jsCode) { is JsExpression -> jsCode // TODO don't generate function for this case - else -> JsInvocation(JsFunction(context.currentScope, jsCode as? JsBlock ?: JsBlock(jsCode as JsStatement), "")) + else -> JsInvocation(JsFunction(emptyScope, jsCode as? JsBlock ?: JsBlock(jsCode as JsStatement), "")) } } 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 1cc4e8815fc..cd4abaf3537 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 @@ -9,6 +9,7 @@ import org.jetbrains.kotlin.backend.common.descriptors.isSuspend import org.jetbrains.kotlin.backend.common.ir.isElseBranch import org.jetbrains.kotlin.ir.backend.js.utils.JsGenerationContext import org.jetbrains.kotlin.ir.backend.js.utils.Namer +import org.jetbrains.kotlin.ir.backend.js.utils.emptyScope import org.jetbrains.kotlin.ir.declarations.IrFunction import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression @@ -42,18 +43,17 @@ fun jsAssignment(left: JsExpression, right: JsExpression) = JsBinaryOperation(Js fun prototypeOf(classNameRef: JsExpression) = JsNameRef(Namer.PROTOTYPE_NAME, classNameRef) fun translateFunction(declaration: IrFunction, name: JsName?, isObjectConstructor: Boolean, context: JsGenerationContext): JsFunction { - val functionScope = JsFunctionScope(context.currentScope, "scope for ${name ?: "annon"}") - val functionContext = context.newDeclaration(functionScope, declaration) + val functionContext = context.newDeclaration(declaration) val functionParams = declaration.valueParameters.map { functionContext.getNameForValueDeclaration(it) } val body = declaration.body?.accept(IrElementToJsStatementTransformer(), functionContext) as? JsBlock ?: JsBlock() val functionBody = if (isObjectConstructor) { - val instanceName = context.currentScope.declareName(name!!.objectInstanceName()) + val instanceName = JsName(name!!.objectInstanceName()) val assignObject = jsAssignment(JsNameRef(instanceName), JsThisRef()) JsBlock(assignObject.makeStmt(), body) } else body - val function = JsFunction(functionScope, functionBody, "member function ${name ?: "annon"}") + val function = JsFunction(emptyScope, functionBody, "member function ${name ?: "annon"}") function.name = name @@ -64,7 +64,7 @@ fun translateFunction(declaration: IrFunction, name: JsName?, isObjectConstructo declaration.extensionReceiverParameter?.let { function.addParameter(functionContext.getNameForValueDeclaration(it)) } functionParams.forEach { function.addParameter(it) } if (declaration.descriptor.isSuspend) { - function.addParameter(context.currentScope.declareName(Namer.CONTINUATION)) + function.addParameter(JsName(Namer.CONTINUATION)) // TODO: Use namer? } return function diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/jsCode.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/jsCode.kt index 129e975999a..e361c7210bc 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/jsCode.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/transformers/irToJs/jsCode.kt @@ -19,7 +19,7 @@ import org.jetbrains.kotlin.js.backend.ast.* import org.jetbrains.kotlin.js.parser.parse -fun translateJsCode(call: IrCall, scope: JsScope): JsNode { +fun translateJsCode(call: IrCall): JsNode { //TODO check non simple compile time constants (expressions) fun foldString(expression: IrExpression): String { @@ -38,7 +38,7 @@ fun translateJsCode(call: IrCall, scope: JsScope): JsNode { } val code = call.getValueArgument(0)!! - val statements = parseJsCode(code.run(::foldString), JsFunctionScope(scope, "")).orEmpty() + val statements = parseJsCode(foldString(code)).orEmpty() val size = statements.size return when (size) { @@ -48,15 +48,15 @@ fun translateJsCode(call: IrCall, scope: JsScope): JsNode { } } -private fun parseJsCode(jsCode: String, currentScope: JsScope): List? { +private fun parseJsCode(jsCode: String): List? { // Parser can change local or global scope. // In case of js we want to keep new local names, // but no new global ones. - assert(currentScope is JsFunctionScope) { "Usage of js outside of function is unexpected" } + val temporaryRootScope = JsRootScope(JsProgram()) - val scope = DelegatingJsFunctionScopeWithTemporaryParent(currentScope as JsFunctionScope, temporaryRootScope) + val currentScope = JsFunctionScope(temporaryRootScope, "js") // TODO write debug info, see how it's done in CallExpressionTranslator.parseJsCode - return parse(jsCode, ThrowExceptionOnErrorReporter, scope, "") + return parse(jsCode, ThrowExceptionOnErrorReporter, currentScope, "") } \ No newline at end of file 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 4318f778034..5efc7f290e9 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 @@ -9,18 +9,19 @@ import org.jetbrains.kotlin.ir.declarations.IrFunction import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction import org.jetbrains.kotlin.js.backend.ast.* +val emptyScope: JsScope + get() = object : JsScope("nil") { + override fun doCreateName(ident: String): JsName { + error("Trying to create name in empty scope") + } + } + class JsGenerationContext( - val parent: JsGenerationContext?, - val currentBlock: JsBlock, - val currentScope: JsScope, val currentFunction: IrFunction?, val staticContext: JsStaticContext ): IrNamer by staticContext { - fun newDeclaration(scope: JsScope, func: IrFunction? = null): JsGenerationContext { + fun newDeclaration(func: IrFunction? = null): JsGenerationContext { return JsGenerationContext( - parent = this, - currentBlock = if (func != null) JsBlock() else JsGlobalBlock(), - currentScope = scope, currentFunction = func, staticContext = staticContext ) @@ -31,7 +32,7 @@ class JsGenerationContext( JsThisRef() } else { if (currentFunction!!.descriptor.isSuspend) { - JsNameRef(currentScope.declareName(Namer.CONTINUATION)) + JsNameRef(Namer.CONTINUATION) } else { getNameForValueDeclaration(currentFunction.valueParameters.last()).makeRef() }