[JS IR BE] Reduce JsScope usage in codegen
This commit is contained in:
+1
-6
@@ -24,12 +24,7 @@ class IrDeclarationToJsTransformer : BaseIrElementToJsNodeTransformer<JsStatemen
|
||||
override fun visitClass(declaration: IrClass, context: JsGenerationContext): JsStatement {
|
||||
return JsClassGenerator(
|
||||
declaration,
|
||||
context.newDeclaration(
|
||||
JsDeclarationScope(
|
||||
context.currentScope,
|
||||
"scope for class ${declaration.name.asString()}"
|
||||
)
|
||||
)
|
||||
context.newDeclaration()
|
||||
).generate()
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -277,7 +277,7 @@ class IrElementToJsExpressionTransformer : BaseIrElementToJsNodeTransformer<JsEx
|
||||
if (jsDispatchReceiver != null) {
|
||||
// TODO: Do not create IIFE when receiver expression is simple or has no side effects
|
||||
// TODO: Do not create IIFE at all? (Currently there is no reliable way to create temporary variable in current scope)
|
||||
val receiverName = context.currentScope.declareFreshName("\$externalVarargReceiverTmp")
|
||||
val receiverName = JsName("\$externalVarargReceiverTmp")
|
||||
val receiverRef = receiverName.makeRef()
|
||||
JsInvocation(
|
||||
// Create scope for temporary variable holding dispatch receiver
|
||||
@@ -285,7 +285,7 @@ class IrElementToJsExpressionTransformer : BaseIrElementToJsNodeTransformer<JsEx
|
||||
JsNameRef(
|
||||
"call",
|
||||
JsFunction(
|
||||
context.currentScope,
|
||||
emptyScope,
|
||||
JsBlock(
|
||||
JsVars(JsVars.JsVar(receiverName, jsDispatchReceiver)),
|
||||
JsReturn(
|
||||
|
||||
+2
-1
@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.backend.common.ir.isElseBranch
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.coroutines.COROUTINE_SWITCH
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.JsGenerationContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.emptyScope
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
import org.jetbrains.kotlin.ir.declarations.IrVariable
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
@@ -83,7 +84,7 @@ class IrElementToJsStatementTransformer : BaseIrElementToJsNodeTransformer<JsSta
|
||||
val jsCatch = aTry.catches.singleOrNull()?.let {
|
||||
val name = context.getNameForValueDeclaration(it.catchParameter)
|
||||
val jsCatchBlock = it.result.accept(this, context)
|
||||
JsCatch(context.currentScope, name.ident, jsCatchBlock)
|
||||
JsCatch(emptyScope, name.ident, jsCatchBlock)
|
||||
}
|
||||
|
||||
val jsFinallyBlock = aTry.finallyExpression?.accept(this, context)?.asBlock()
|
||||
|
||||
+5
-7
@@ -7,14 +7,12 @@ package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs
|
||||
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.JsGenerationContext
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||
import org.jetbrains.kotlin.ir.declarations.path
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsDeclarationScope
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsStatement
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsBlock
|
||||
|
||||
class IrFileToJsTransformer : BaseIrElementToJsNodeTransformer<JsStatement, JsGenerationContext> {
|
||||
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<JsBlock, JsGenerationContext> {
|
||||
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))
|
||||
|
||||
+3
-7
@@ -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)
|
||||
|
||||
+6
-5
@@ -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<JsStatement> {
|
||||
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()
|
||||
|
||||
+3
-2
@@ -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), ""))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+5
-5
@@ -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
|
||||
|
||||
+6
-6
@@ -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, "<js-code>")).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<JsStatement>? {
|
||||
private fun parseJsCode(jsCode: String): List<JsStatement>? {
|
||||
// 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, "<js-code>")
|
||||
return parse(jsCode, ThrowExceptionOnErrorReporter, currentScope, "<js-code>")
|
||||
}
|
||||
+9
-8
@@ -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()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user