From 261edd5f4c8b4ea4fd1d7bd3fae4af7c8e0a6596 Mon Sep 17 00:00:00 2001 From: Roman Artemev Date: Mon, 14 May 2018 18:50:57 +0300 Subject: [PATCH] [JS IR BE] Implement property reference Add cache for direct (which has no closured parameters) KCallable references Refactor FunctionReferenceLowering * Rename FunctionReferenceLowering -> CallableReferenceLowering * Add util method to create value parameters --- .../ir/backend/js/JsDescriptorsFactory.kt | 22 +- .../kotlin/ir/backend/js/JsIntrinsics.kt | 34 +- .../ir/backend/js/JsIrBackendContext.kt | 2 +- .../ir/backend/js/JsSharedVariablesManager.kt | 17 +- .../kotlin/ir/backend/js/compiler.kt | 4 +- .../backend/js/descriptors/SymbolBuilder.kt | 26 +- .../kotlin/ir/backend/js/ir/IrBuilder.kt | 1 + .../js/lower/BlockDecomposerLowering.kt | 13 +- .../js/lower/CallableReferenceLowering.kt | 353 ++++++++++++++++++ .../js/lower/FunctionReferenceLowering.kt | 183 --------- .../js/lower/IntrinsicifyCallsLowering.kt | 38 ++ .../irToJs/IrDeclarationToJsTransformer.kt | 9 +- .../transformers/irToJs/JsClassGenerator.kt | 8 +- .../irToJs/JsIntrinsicTransformers.kt | 32 ++ .../kotlin/ir/backend/js/utils/Namer.kt | 7 + .../backend/js/utils/descriptorBasedUtils.kt | 30 +- .../function/functionReferenceName.kt | 24 ++ 17 files changed, 546 insertions(+), 257 deletions(-) create mode 100644 compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/CallableReferenceLowering.kt delete mode 100644 compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/FunctionReferenceLowering.kt create mode 100644 js/js.translator/testData/box/callableReference/function/functionReferenceName.kt diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsDescriptorsFactory.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsDescriptorsFactory.kt index 8177b962eb0..3dfd81115c7 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsDescriptorsFactory.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsDescriptorsFactory.kt @@ -18,12 +18,12 @@ package org.jetbrains.kotlin.backend.js import org.jetbrains.kotlin.backend.common.descriptors.DescriptorsFactory import org.jetbrains.kotlin.builtins.CompanionObjectMapping.isMappedIntrinsicCompanionObject -import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.impl.ClassConstructorDescriptorImpl import org.jetbrains.kotlin.descriptors.impl.PropertyDescriptorImpl -import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl +import org.jetbrains.kotlin.ir.backend.js.utils.Namer +import org.jetbrains.kotlin.ir.backend.js.utils.createValueParameter import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.IrConstructor import org.jetbrains.kotlin.ir.symbols.* @@ -34,9 +34,7 @@ import org.jetbrains.kotlin.ir.util.dump import org.jetbrains.kotlin.name.Name import java.util.* -class JsDescriptorsFactory( - private val builtIns: KotlinBuiltIns -) : DescriptorsFactory { +class JsDescriptorsFactory : DescriptorsFactory { private val singletonFieldDescriptors = HashMap, IrFieldSymbol>() private val outerThisFieldSymbols = HashMap() private val innerClassConstructors = HashMap() @@ -93,19 +91,7 @@ class JsDescriptorsFactory( classDescriptor, oldDescriptor.annotations, oldDescriptor.isPrimary, oldDescriptor.source ) - val outerThisValueParameter = ValueParameterDescriptorImpl( - newDescriptor, - null, - 0, - Annotations.EMPTY, - Name.identifier("\$outer"), - outerThisType, - false, - false, - false, - null, - SourceElement.NO_SOURCE - ) + val outerThisValueParameter = createValueParameter(newDescriptor, 0, Namer.OUTER_NAME, outerThisType) val newValueParameters = listOf(outerThisValueParameter) + diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsIntrinsics.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsIntrinsics.kt index 1cbb1602954..1969b6cee09 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsIntrinsics.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsIntrinsics.kt @@ -9,6 +9,7 @@ import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl import org.jetbrains.kotlin.descriptors.impl.TypeParameterDescriptorImpl +import org.jetbrains.kotlin.ir.backend.js.utils.createValueParameter import org.jetbrains.kotlin.ir.backend.js.utils.getFunctions import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns @@ -74,11 +75,19 @@ class JsIntrinsics(private val module: ModuleDescriptor, private val irBuiltIns: val jsBitShiftL = binOpInt("jsBitShiftL") + // KFunction operations: + + val jsName = unOp("kCallableName", irBuiltIns.string) + val jsPropertyGet = binOp("kPropertyGet") + val jsPropertySet = tripleOp("kPropertySet", irBuiltIns.unit) + // Other: val jsInstanceOf = binOpBool("jsInstanceOf") - val jsObjectCreate: IrSimpleFunction = defineObjectCreateIntrinsic() + val jsObjectCreate = defineObjectCreateIntrinsic() + + val jsSetJSField = defineSetJSPropertyIntrinsic() val jsCode = module.getFunctions(FqName("kotlin.js.js")).singleOrNull()?.let { symbolTable.referenceFunction(it) } @@ -112,6 +121,26 @@ class JsIntrinsics(private val module: ModuleDescriptor, private val irBuiltIns: return stubBuilder.generateFunctionStub(desc) } + + private fun defineSetJSPropertyIntrinsic(): IrSimpleFunction { + val returnType = irBuiltIns.unit + + val desc = SimpleFunctionDescriptorImpl.create( + module, + Annotations.EMPTY, + Name.identifier("\$setJSProperty\$"), + CallableMemberDescriptor.Kind.SYNTHESIZED, + SourceElement.NO_SOURCE + ).apply { + + val parameterDescriptors = listOf("receiver", "fieldName", "fieldValue") + .mapIndexed { i, name -> createValueParameter(this, i, name, irBuiltIns.any) } + initialize(null, null, emptyList(), parameterDescriptors, returnType, Modality.FINAL, Visibilities.PUBLIC) + } + + return stubBuilder.generateFunctionStub(desc) + } + private fun unOp(name: String, returnType: KotlinType = irBuiltIns.anyN) = irBuiltIns.run { defineOperator(name, returnType, listOf(anyN)) } @@ -121,6 +150,9 @@ class JsIntrinsics(private val module: ModuleDescriptor, private val irBuiltIns: private fun binOp(name: String, returnType: KotlinType = irBuiltIns.anyN) = irBuiltIns.run { defineOperator(name, returnType, listOf(anyN, anyN)) } + private fun tripleOp(name: String, returnType: KotlinType = irBuiltIns.anyN) = + irBuiltIns.run { defineOperator(name, returnType, listOf(anyN, anyN, anyN)) } + private fun binOpBool(name: String) = binOp(name, irBuiltIns.bool) private fun binOpInt(name: String) = binOp(name, irBuiltIns.int) } 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 505390da94c..85862270a76 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 @@ -40,7 +40,7 @@ class JsIrBackendContext( override val builtIns = module.builtIns override val sharedVariablesManager = JsSharedVariablesManager(builtIns, KnownPackageFragmentDescriptor(builtIns.builtInsModule, FqName("kotlin.js.internal"))) - override val descriptorsFactory = JsDescriptorsFactory(builtIns) + override val descriptorsFactory = JsDescriptorsFactory() override val reflectionTypes: ReflectionTypes by lazy(LazyThreadSafetyMode.PUBLICATION) { // TODO diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsSharedVariablesManager.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsSharedVariablesManager.kt index 5b70247c7c0..8beecdcf04b 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsSharedVariablesManager.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/JsSharedVariablesManager.kt @@ -13,8 +13,7 @@ import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.impl.ClassConstructorDescriptorImpl import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor import org.jetbrains.kotlin.descriptors.impl.PropertyDescriptorImpl -import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl -import org.jetbrains.kotlin.ir.IrStatement +import org.jetbrains.kotlin.ir.backend.js.utils.createValueParameter import org.jetbrains.kotlin.ir.declarations.IrVariable import org.jetbrains.kotlin.ir.declarations.impl.IrVariableImpl import org.jetbrains.kotlin.ir.expressions.IrExpression @@ -136,19 +135,7 @@ class JsSharedVariablesManager(val builtIns: KotlinBuiltIns, val jsInterinalPack listOf(), true ) - val paramDesc = ValueParameterDescriptorImpl( - this, - null, - 0, - Annotations.EMPTY, - Name.identifier("v"), - parameterType, - false, - false, - false, - null, - SourceElement.NO_SOURCE - ) + val paramDesc = createValueParameter(this, 0, "v", parameterType) initialize(listOf(paramDesc), Visibilities.PUBLIC) returnType = KotlinTypeFactory.simpleNotNullType( diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/compiler.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/compiler.kt index 12532de39b4..a37ef7fbc21 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/compiler.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/compiler.kt @@ -10,7 +10,7 @@ import org.jetbrains.kotlin.backend.common.lower.* import org.jetbrains.kotlin.backend.common.runOnFilePostfix import org.jetbrains.kotlin.config.CompilerConfiguration import org.jetbrains.kotlin.ir.backend.js.lower.BlockDecomposerLowering -import org.jetbrains.kotlin.ir.backend.js.lower.FunctionReferenceLowering +import org.jetbrains.kotlin.ir.backend.js.lower.CallableReferenceLowering import org.jetbrains.kotlin.ir.backend.js.lower.IntrinsicifyCallsLowering import org.jetbrains.kotlin.ir.backend.js.lower.SecondaryCtorLowering import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.IrModuleToJsTransformer @@ -67,6 +67,6 @@ fun JsIrBackendContext.lower(file: IrFile) { InitializersLowering(this, JsLoweredDeclarationOrigin.CLASS_STATIC_INITIALIZER, false).runOnFilePostfix(file) BlockDecomposerLowering(this).runOnFilePostfix(file) SecondaryCtorLowering(this).runOnFilePostfix(file) + CallableReferenceLowering(this).lower(file) IntrinsicifyCallsLowering(this).lower(file) - FunctionReferenceLowering(this).lower(file) } \ No newline at end of file diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/descriptors/SymbolBuilder.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/descriptors/SymbolBuilder.kt index f5d520fb7bc..048fcb85ee5 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/descriptors/SymbolBuilder.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/descriptors/SymbolBuilder.kt @@ -11,7 +11,7 @@ import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.impl.FunctionDescriptorImpl import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl -import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl +import org.jetbrains.kotlin.ir.backend.js.utils.createValueParameter import org.jetbrains.kotlin.ir.descriptors.IrTemporaryVariableDescriptorImpl import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol @@ -23,28 +23,8 @@ import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.types.KotlinType object JsSymbolBuilder { - fun buildValueParameter( - containingSymbol: IrSimpleFunctionSymbol, - index: Int, - type: KotlinType, - name: String? = null, - hasDefault: Boolean = false - ) = - IrValueParameterSymbolImpl( - ValueParameterDescriptorImpl( - containingSymbol.descriptor, - null, - index, - Annotations.EMPTY, - Name.identifier(name ?: "param$index"), - type, - hasDefault, - false, - false, - null, - SourceElement.NO_SOURCE - ) - ) + fun buildValueParameter(containingSymbol: IrSimpleFunctionSymbol, index: Int, type: KotlinType, name: String? = null) = + IrValueParameterSymbolImpl(createValueParameter(containingSymbol.descriptor, index, name ?: "param$index", type)) fun buildSimpleFunction( containingDeclaration: DeclarationDescriptor, diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ir/IrBuilder.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ir/IrBuilder.kt index 7cc62ed7b28..98b8af13dae 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ir/IrBuilder.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/ir/IrBuilder.kt @@ -78,4 +78,5 @@ object JsIrBuilder { fun buildNull(type: KotlinType) = IrConstImpl.constNull(UNDEFINED_OFFSET, UNDEFINED_OFFSET, type) fun buildBoolean(type: KotlinType, v: Boolean) = IrConstImpl.boolean(UNDEFINED_OFFSET, UNDEFINED_OFFSET, type, v) + fun buildString(type: KotlinType, s: String) = IrConstImpl.string(UNDEFINED_OFFSET, UNDEFINED_OFFSET, type, s) } \ No newline at end of file diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/BlockDecomposerLowering.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/BlockDecomposerLowering.kt index b2bf86dfee9..7c378003594 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/BlockDecomposerLowering.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/BlockDecomposerLowering.kt @@ -10,9 +10,9 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext -import org.jetbrains.kotlin.ir.backend.js.descriptors.JsSymbolBuilder -import org.jetbrains.kotlin.ir.backend.js.descriptors.initialize import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder +import org.jetbrains.kotlin.ir.backend.js.symbols.JsSymbolBuilder +import org.jetbrains.kotlin.ir.backend.js.symbols.initialize import org.jetbrains.kotlin.ir.backend.js.utils.Namer import org.jetbrains.kotlin.ir.declarations.IrField import org.jetbrains.kotlin.ir.declarations.IrFunction @@ -393,16 +393,16 @@ class BlockDecomposerLowering(val context: JsIrBackendContext) : FunctionLowerin collectingList += tempResult.runIfChangedOrDefault(listOf(statement)) { statements } } - if (lastStatement != null) { + return if (lastStatement != null) { val result = lastStatement.accept(expressionVisitor, data).runIfChangedOrDefault(lastStatement as IrExpression) { collectingList += statements resultValue } collectingList += JsIrBuilder.buildSetVariable(variable, result) - return DecomposedResult(mutableListOf(varDeclaration, body), JsIrBuilder.buildGetValue(variable)) + DecomposedResult(mutableListOf(varDeclaration, body), JsIrBuilder.buildGetValue(variable)) } else { // do not allow variable to be uninitialized - return DecomposedResult(mutableListOf(), unitValue) + DecomposedResult(mutableListOf(), unitValue) } } @@ -562,7 +562,8 @@ class BlockDecomposerLowering(val context: JsIrBackendContext) : FunctionLowerin expression.endOffset, expression.type, expression.varargElementType, - newArguments) + newArguments + ) return DecomposedResult(newStatements, newExpression) } diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/CallableReferenceLowering.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/CallableReferenceLowering.kt new file mode 100644 index 00000000000..cbe7b0e45f2 --- /dev/null +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/CallableReferenceLowering.kt @@ -0,0 +1,353 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.ir.backend.js.lower + +import org.jetbrains.kotlin.backend.common.DeclarationContainerLoweringPass +import org.jetbrains.kotlin.backend.common.FileLoweringPass +import org.jetbrains.kotlin.backend.common.lower.copyAsValueParameter +import org.jetbrains.kotlin.backend.common.runOnFilePostfix +import org.jetbrains.kotlin.descriptors.CallableDescriptor +import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor +import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor +import org.jetbrains.kotlin.ir.IrElement +import org.jetbrains.kotlin.ir.IrStatement +import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext +import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder +import org.jetbrains.kotlin.ir.backend.js.utils.Namer +import org.jetbrains.kotlin.ir.declarations.* +import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl +import org.jetbrains.kotlin.ir.expressions.* +import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl +import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol +import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol +import org.jetbrains.kotlin.ir.symbols.IrValueParameterSymbol +import org.jetbrains.kotlin.ir.symbols.IrValueSymbol +import org.jetbrains.kotlin.ir.util.transformFlat +import org.jetbrains.kotlin.ir.visitors.* +import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe +import org.jetbrains.kotlin.types.KotlinType + +class CallableReferenceLowering(val context: JsIrBackendContext) : FileLoweringPass, DeclarationContainerLoweringPass { + + private val callableToGetterFunction = mutableMapOf() + + // TODO: replace descriptor usage with symbol instead + private val collectedReferenceMap = mutableMapOf() + + private val callableNameConst = JsIrBuilder.buildString(context.irBuiltIns.string, Namer.KCALLABLE_NAME) + private val getterConst = JsIrBuilder.buildString(context.irBuiltIns.string, Namer.KPROPERTY_GET) + private val setterConst = JsIrBuilder.buildString(context.irBuiltIns.string, Namer.KPROPERTY_SET) + + override fun lower(irFile: IrFile) { + irFile.acceptVoid(CallableReferenceCollector()) + runOnFilePostfix(irFile) + irFile.transformChildrenVoid(CallableReferenceTransformer()) + } + + inner class CallableReferenceCollector : IrElementVisitorVoid { + override fun visitFunctionReference(expression: IrFunctionReference) { + collectedReferenceMap[expression.symbol.owner] = expression + } + + override fun visitPropertyReference(expression: IrPropertyReference) { + //Note: The getter is taken because the `invoke()` function of the resulted reference has to be corresponding getter call + collectedReferenceMap[expression.getter!!.owner] = expression + } + + override fun visitElement(element: IrElement) { + element.acceptChildrenVoid(this) + } + } + + override fun lower(irDeclarationContainer: IrDeclarationContainer) { + irDeclarationContainer.declarations.transformFlat { d -> + collectedReferenceMap[d]?.accept(object : IrElementVisitor, IrFunction> { + override fun visitElement(element: IrElement, data: IrFunction) = error("Unreachable execution") + override fun visitFunctionReference(expression: IrFunctionReference, data: IrFunction) = + lowerKFunctionReference(data, expression) + + override fun visitPropertyReference(expression: IrPropertyReference, data: IrFunction) = + lowerKPropertyReference(data, expression) + }, d as IrFunction) + } + } + + inner class CallableReferenceTransformer : IrElementTransformerVoid() { + override fun visitCallableReference(expression: IrCallableReference) = callableToGetterFunction[expression.descriptor]?.let { + redirectToFunction(expression, it) + } ?: expression + + private fun redirectToFunction(callable: IrCallableReference, newTarget: IrFunction) = + IrCallImpl(callable.startOffset, callable.endOffset, newTarget.symbol, callable.origin).apply { + copyTypeArgumentsFrom(callable) + var index = 0 + for (i in 0 until callable.valueArgumentsCount) { + val arg = callable.getValueArgument(i) + if (arg != null) { + putValueArgument(index++, arg) + } + } + } + } + + private fun createClosureGetterName(descriptor: CallableDescriptor) = createHelperFunctionName(descriptor, "KReferenceGet") + private fun createPropertyClosureGetterName(descriptor: CallableDescriptor) = createHelperFunctionName(descriptor, "KPropertyGet") + private fun createClosureInstanceName(descriptor: CallableDescriptor) = createHelperFunctionName(descriptor, "KReferenceClosure") + + private fun createHelperFunctionName(descriptor: CallableDescriptor, suffix: String): String { + val nameBuilder = StringBuilder() + if (descriptor is ClassConstructorDescriptor) { + nameBuilder.append(descriptor.constructedClass.fqNameSafe) + nameBuilder.append('_') + } + nameBuilder.append(descriptor.name) + nameBuilder.append('_') + nameBuilder.append(suffix) + return nameBuilder.toString() + } + + + private fun getReferenceName(descriptor: CallableDescriptor): String { + if (descriptor is ClassConstructorDescriptor) { + return descriptor.constructedClass.name.identifier + } + return descriptor.name.identifier + } + + private fun lowerKFunctionReference(declaration: IrFunction, functionReference: IrFunctionReference): List { + // transform + // x = Foo::bar -> + // x = Foo_bar_KreferenceGet(c1: closure$C1, c2: closure$C2) : KFunctionN { + // [ if ($cache$ == null) { ] // in case reference has no closure param cache it + // val x = fun Foo_bar_KreferenceClosure(p0: Foo, p1: T2, p2: T3): TReturn { + // return p0.bar(c1, c2, p1, p2) + // } + // x.callableName = "bar" + // [ $cache$ = x } ] + // return {$cache$|x} + // } + + // KFunctionN, arguments.size = N + 1 + + val refGetFunction = buildGetFunction(declaration, functionReference.type, createClosureGetterName(declaration.descriptor)) + val refClosureFunction = buildClosureFunction(declaration, refGetFunction) + + val additionalDeclarations = generateGetterBodyWithGuard(refGetFunction) { + val irClosureReference = JsIrBuilder.buildFunctionReference(functionReference.type, refClosureFunction.symbol) + val irVarSymbol = JsSymbolBuilder.buildTempVar(refGetFunction.symbol, irClosureReference.type) + val irVar = JsIrBuilder.buildVar(irVarSymbol, irClosureReference) + + // TODO: fill other fields of callable reference (returnType, parameters, isFinal, etc.) + val irSetName = JsIrBuilder.buildCall(context.intrinsics.jsSetJSField.symbol).apply { + putValueArgument(0, JsIrBuilder.buildGetValue(irVarSymbol)) + putValueArgument(1, callableNameConst) + putValueArgument(2, JsIrBuilder.buildString(context.irBuiltIns.string, getReferenceName(declaration.descriptor))) + } + Pair(listOf(irVar, irSetName), irVarSymbol) + } + + callableToGetterFunction[functionReference.descriptor] = refGetFunction + + return additionalDeclarations + listOf(declaration, refGetFunction) + } + + private fun lowerKPropertyReference(getterDeclaration: IrFunction, propertyReference: IrPropertyReference): List { + // transform + // x = Foo::bar -> + // x = Foo_bar_KreferenceGet() : KPropertyN { + // if ($cache$ == null) { // very likely property reference is going to be cached + // val x = fun Foo_bar_KreferenceClosure_get(r: Foo): PType { + // return r.() + // } + // x.get = x + // x.callableName = "bar" + // if (mutable) { + // x.set = fun Foo_bar_KreferenceClosure_set(r: Foo, v: PType>) { + // r.(v) + // } + // } + // $cache$ = x + // } + // return $cache$ + // } + + val getterName = createPropertyClosureGetterName(propertyReference.descriptor) + val refGetFunction = buildGetFunction(propertyReference.getter!!.owner, propertyReference.type, getterName) + + val getterFunction = propertyReference.getter?.let { buildClosureFunction(it.owner, refGetFunction) }!! + val setterFunction = propertyReference.setter?.let { buildClosureFunction(it.owner, refGetFunction) } + + val additionalDeclarations = generateGetterBodyWithGuard(refGetFunction) { + val statements = mutableListOf() + + val getterFunctionType = context.builtIns.getFunction(getterFunction.valueParameters.size + 1) + val irGetReference = JsIrBuilder.buildFunctionReference(getterFunctionType.defaultType, getterFunction.symbol) + val irVarSymbol = JsSymbolBuilder.buildTempVar(refGetFunction.symbol, getterFunctionType.defaultType) + + statements += JsIrBuilder.buildVar(irVarSymbol, irGetReference) + + JsIrBuilder.buildCall(context.intrinsics.jsSetJSField.symbol).run { + putValueArgument(0, JsIrBuilder.buildGetValue(irVarSymbol)) + putValueArgument(1, getterConst) + putValueArgument(2, JsIrBuilder.buildGetValue(irVarSymbol)) + statements += this + } + + if (setterFunction != null) { + val setterFunctionType = context.builtIns.getFunction(setterFunction.valueParameters.size + 1) + val irSetReference = JsIrBuilder.buildFunctionReference(setterFunctionType.defaultType, setterFunction.symbol) + JsIrBuilder.buildCall(context.intrinsics.jsSetJSField.symbol).run { + putValueArgument(0, JsIrBuilder.buildGetValue(irVarSymbol)) + putValueArgument(1, setterConst) + putValueArgument(2, irSetReference) + statements += this + } + } + + // TODO: fill other fields of callable reference (returnType, parameters, isFinal, etc.) + JsIrBuilder.buildCall(context.intrinsics.jsSetJSField.symbol).run { + putValueArgument(0, JsIrBuilder.buildGetValue(irVarSymbol)) + putValueArgument(1, callableNameConst) + putValueArgument(2, JsIrBuilder.buildString(context.irBuiltIns.string, getReferenceName(propertyReference.descriptor))) + statements += this + } + + Pair(statements, irVarSymbol) + } + + callableToGetterFunction[propertyReference.descriptor] = refGetFunction + + return additionalDeclarations + listOf(getterDeclaration, refGetFunction) + } + + private fun generateGetterBodyWithGuard( + getterFunction: IrSimpleFunction, + builder: () -> Pair, IrValueSymbol> + ): List { + + val (bodyStatements, varSymbol) = builder() + val statements = mutableListOf() + val returnValue: IrExpression + val returnStatements: List + if (getterFunction.valueParameters.isEmpty()) { + // compose cache for 'direct' closure + // if ($cache$ === null) { + // $cache$ = + // } + // + val cacheName = "${getterFunction.name}_${Namer.KCALLABLE_CACHE_SUFFIX}" + val cacheVarSymbol = + JsSymbolBuilder.buildVar(getterFunction.descriptor.containingDeclaration, getterFunction.returnType, cacheName, true) + val irCacheNull = JsIrBuilder.buildNull(cacheVarSymbol.descriptor.type) + val irCacheDeclaration = JsIrBuilder.buildVar(cacheVarSymbol, irCacheNull) + val irCacheValue = JsIrBuilder.buildGetValue(cacheVarSymbol) + val irIfCondition = JsIrBuilder.buildCall(context.irBuiltIns.eqeqeqSymbol).apply { + putValueArgument(0, irCacheValue) + putValueArgument(1, irCacheNull) + } + val irSetCache = JsIrBuilder.buildSetVariable(cacheVarSymbol, JsIrBuilder.buildGetValue(varSymbol)) + val thenStatements = mutableListOf().apply { + addAll(bodyStatements) + add(irSetCache) + } + val irThenBranch = JsIrBuilder.buildBlock(context.irBuiltIns.unit, thenStatements) + val irIfNode = JsIrBuilder.buildIfElse(context.irBuiltIns.unit, irIfCondition, irThenBranch) + statements += irIfNode + returnValue = irCacheValue + returnStatements = listOf(irCacheDeclaration) + } else { + statements += bodyStatements + returnValue = JsIrBuilder.buildGetValue(varSymbol) + returnStatements = emptyList() + } + statements += JsIrBuilder.buildReturn(getterFunction.symbol, returnValue) + + getterFunction.body = JsIrBuilder.buildBlockBody(statements) + return returnStatements + } + + private fun generateSignatureForClosure( + callable: IrFunctionSymbol, + getter: IrSimpleFunctionSymbol, + closure: IrSimpleFunctionSymbol + ): List { + val result = mutableListOf() + + callable.owner.dispatchReceiverParameter?.run { result.add(JsSymbolBuilder.buildValueParameter(closure, result.size, type)) } + callable.owner.extensionReceiverParameter?.run { result.add(JsSymbolBuilder.buildValueParameter(closure, result.size, type)) } + + for (i in getter.owner.valueParameters.size until callable.owner.valueParameters.size) { + val param = callable.owner.valueParameters[i] + val paramName = param.name.run { if (!isSpecial) identifier else null } + result += JsSymbolBuilder.buildValueParameter(closure, result.size, param.type, paramName) + } + + return result + } + + private fun buildGetFunction(declaration: IrFunction, callableType: KotlinType, getterName: String): IrSimpleFunction { + + val closureParams = callableType.arguments.dropLast(1) // drop return type + var kFunctionValueParamsCount = closureParams.size + if (declaration.dispatchReceiverParameter != null) kFunctionValueParamsCount-- + if (declaration.extensionReceiverParameter != null) kFunctionValueParamsCount-- + + assert(kFunctionValueParamsCount >= 0) + + // The `getter` function takes only closure parameters + val getterValueParameters = declaration.valueParameters.dropLast(kFunctionValueParamsCount) + + val refGetSymbol = JsSymbolBuilder.buildSimpleFunction(declaration.descriptor.containingDeclaration, getterName).apply { + initialize( + valueParameters = getterValueParameters.mapIndexed { i, p -> p.descriptor.copyAsValueParameter(descriptor, i) }, + type = callableType + ) + } + + return JsIrBuilder.buildFunction(refGetSymbol).apply { + for (i in 0 until getterValueParameters.size) { + val p = getterValueParameters[i] + valueParameters += IrValueParameterImpl(p.startOffset, p.endOffset, p.origin, refGetSymbol.descriptor.valueParameters[i]) + } + } + } + + private fun buildClosureFunction(declaration: IrFunction, refGetFunction: IrSimpleFunction): IrFunction { + val closureName = createClosureInstanceName(declaration.descriptor) + val refClosureSymbol = JsSymbolBuilder.buildSimpleFunction(refGetFunction.descriptor, closureName) + + // the params which are passed to closure + val closureParamSymbols = generateSignatureForClosure(declaration.symbol, refGetFunction.symbol, refClosureSymbol) + val closureParamDescriptors = closureParamSymbols.map { it.descriptor as ValueParameterDescriptor } + + refClosureSymbol.initialize(valueParameters = closureParamDescriptors, type = declaration.returnType) + + return JsIrBuilder.buildFunction(refClosureSymbol).apply { + for (it in closureParamSymbols) { + valueParameters += JsIrBuilder.buildValueParameter(it) + } + + val irCall = JsIrBuilder.buildCall(declaration.symbol) + + var p = 0 + declaration.dispatchReceiverParameter?.run { irCall.dispatchReceiver = JsIrBuilder.buildGetValue(closureParamSymbols[p++]) } + declaration.extensionReceiverParameter?.run { irCall.extensionReceiver = JsIrBuilder.buildGetValue(closureParamSymbols[p++]) } + + var j = 0 + for (v in refGetFunction.valueParameters) { + irCall.putValueArgument(j++, JsIrBuilder.buildGetValue(v.symbol)) + } + + for (i in p until closureParamSymbols.size) { + irCall.putValueArgument(j++, JsIrBuilder.buildGetValue(closureParamSymbols[i])) + } + + val irClosureReturn = JsIrBuilder.buildReturn(symbol, irCall) + + body = JsIrBuilder.buildBlockBody(listOf(irClosureReturn)) + } + } +} \ No newline at end of file diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/FunctionReferenceLowering.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/FunctionReferenceLowering.kt deleted file mode 100644 index fa8814341a3..00000000000 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/FunctionReferenceLowering.kt +++ /dev/null @@ -1,183 +0,0 @@ -/* - * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license - * that can be found in the license/LICENSE.txt file. - */ - -package org.jetbrains.kotlin.ir.backend.js.lower - -import org.jetbrains.kotlin.backend.common.DeclarationContainerLoweringPass -import org.jetbrains.kotlin.backend.common.FileLoweringPass -import org.jetbrains.kotlin.backend.common.lower.copyAsValueParameter -import org.jetbrains.kotlin.backend.common.runOnFilePostfix -import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor -import org.jetbrains.kotlin.ir.IrElement -import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext -import org.jetbrains.kotlin.ir.backend.js.descriptors.JsSymbolBuilder -import org.jetbrains.kotlin.ir.backend.js.descriptors.initialize -import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder -import org.jetbrains.kotlin.ir.declarations.* -import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl -import org.jetbrains.kotlin.ir.expressions.IrExpression -import org.jetbrains.kotlin.ir.expressions.IrFunctionReference -import org.jetbrains.kotlin.ir.expressions.copyTypeArgumentsFrom -import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl -import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol -import org.jetbrains.kotlin.ir.util.transformFlat -import org.jetbrains.kotlin.ir.visitors.* -import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe -import org.jetbrains.kotlin.types.KotlinType - -// TODO replace with DeclarationContainerLowerPass && do flatTransform -class FunctionReferenceLowering(val context: JsIrBackendContext) : FileLoweringPass, DeclarationContainerLoweringPass { - - private val lambdas = mutableMapOf() - private val oldToNewDeclarationMap = mutableMapOf() - - override fun lower(irFile: IrFile) { - irFile.acceptVoid(FunctionReferenceCollector()) - runOnFilePostfix(irFile) - irFile.transformChildrenVoid(FunctionReferenceVisitor()) - } - - inner class FunctionReferenceCollector : IrElementVisitorVoid { - override fun visitFunctionReference(expression: IrFunctionReference) { - lambdas[expression.symbol.owner as IrFunction] = expression.type - } - - override fun visitElement(element: IrElement) { - element.acceptChildrenVoid(this) - } - } - - override fun lower(irDeclarationContainer: IrDeclarationContainer) { - irDeclarationContainer.declarations.transformFlat { d -> - if (d is IrFunction) { - lambdas[d]?.let { - lowerKFunctionReference(d, it) - } - } else null - } - } - - inner class FunctionReferenceVisitor : IrElementTransformerVoid() { - - override fun visitFunctionReference(expression: IrFunctionReference): IrExpression { - val newTarget = oldToNewDeclarationMap[expression.symbol] - - return if (newTarget != null) IrCallImpl(expression.startOffset, expression.endOffset, newTarget.symbol, expression.origin).apply { - copyTypeArgumentsFrom(expression) - var index = 0 - for (i in 0 until expression.valueArgumentsCount) { - val arg = expression.getValueArgument(i) - if (arg != null) { - putValueArgument(index++, arg) - } - } - } else expression - } - } - - private fun createClosureGetterName(declaration: IrFunction) = createHelperFunctionName(declaration, "KreferenceGet") - private fun createClosureInstanceName(declaration: IrFunction) = createHelperFunctionName(declaration, "KreferenceClosure") - - private fun createHelperFunctionName(declaration: IrFunction, suffix: String): String { - val nameBuilder = StringBuilder() - if (declaration is IrConstructor) { - nameBuilder.append(declaration.descriptor.constructedClass.fqNameSafe) - nameBuilder.append('_') - } - nameBuilder.append(declaration.descriptor.name) - nameBuilder.append('_') - nameBuilder.append(suffix) - return nameBuilder.toString() - } - - private fun lowerKFunctionReference(declaration: IrFunction, functionType: KotlinType): List { - // TODO: property reference - - // transform - // x = Foo::bar -> - // x = Foo_bar_KreferenceGet(c1: closure$C1, c2: closure$C2) : KFunctionN { - // return fun Foo_bar_KreferenceClosure(p0: Foo, p1: T2, p2: T3): TReturn { - // return p0.bar(c1, c2, p1, p2) - // } - // } - - // KFunctionN, arguments.size = N + 1 - - val closureParams = functionType.arguments.dropLast(1) // drop return type - var kFunctionValueParamsCount = closureParams.size - if (declaration.dispatchReceiverParameter != null) kFunctionValueParamsCount-- - if (declaration.extensionReceiverParameter != null) kFunctionValueParamsCount-- - - assert(kFunctionValueParamsCount >= 0) - - // The `getter` function takes only parameters which have to be closured - val getterValueParameters = declaration.valueParameters.dropLast(kFunctionValueParamsCount) - val getterName = createClosureGetterName(declaration) - - val refGetSymbol = - JsSymbolBuilder.buildSimpleFunction(declaration.descriptor.containingDeclaration, getterName).apply { - initialize( - valueParameters = getterValueParameters.mapIndexed { i, p -> p.descriptor.copyAsValueParameter(this.descriptor, i) }, - type = functionType - ) - } - - val refGetFunction = JsIrBuilder.buildFunction(refGetSymbol).apply { - getterValueParameters.mapIndexed { i, p -> - valueParameters += IrValueParameterImpl(p.startOffset, p.endOffset, p.origin, refGetSymbol.descriptor.valueParameters[i]) - } - } - - val closureName = createClosureInstanceName(declaration) - val refClosureSymbol = JsSymbolBuilder.buildSimpleFunction(refGetSymbol.descriptor, closureName) - - // the params which are passed to closure - val closureParamSymbols = closureParams.mapIndexed { index, p -> - // TODO: re-use original parameter names - JsSymbolBuilder.buildValueParameter(refClosureSymbol, index, p.type) - } - - val closureParamDescriptors = closureParamSymbols.map { it.descriptor as ValueParameterDescriptor } - - refClosureSymbol.initialize(valueParameters = closureParamDescriptors, type = declaration.returnType) - - JsIrBuilder.buildFunction(refClosureSymbol).apply { - closureParamSymbols.forEach { valueParameters += JsIrBuilder.buildValueParameter(it) } - - val irClosureCall = JsIrBuilder.buildCall(declaration.symbol).apply { - var p = 0 - if (declaration.dispatchReceiverParameter != null) { - dispatchReceiver = JsIrBuilder.buildGetValue(closureParamSymbols[p++]) - } - if (declaration.extensionReceiverParameter != null) { - extensionReceiver = JsIrBuilder.buildGetValue(closureParamSymbols[p++]) - } - - var j = 0 - refGetFunction.valueParameters.forEach { v -> - putValueArgument(j++, JsIrBuilder.buildGetValue(v.symbol)) - } - - closureParamSymbols.drop(p).forEach { v -> - putValueArgument(j++, JsIrBuilder.buildGetValue(v)) - } - } - - val irClosureReturn = JsIrBuilder.buildReturn(refClosureSymbol, irClosureCall) - - body = JsIrBuilder.buildBlockBody(listOf(irClosureReturn)) - } - - refGetFunction.apply { - val irClosureReference = JsIrBuilder.buildFunctionReference(functionType, refClosureSymbol) - val irGetterReturn = JsIrBuilder.buildReturn(refGetSymbol, irClosureReference) - body = JsIrBuilder.buildBlockBody(listOf(irGetterReturn)) - } - - oldToNewDeclarationMap[declaration.symbol] = refGetFunction - - return listOf(declaration, refGetFunction) - } -} \ No newline at end of file diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/IntrinsicifyCallsLowering.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/IntrinsicifyCallsLowering.kt index 61624103814..a867e0adba9 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/IntrinsicifyCallsLowering.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/IntrinsicifyCallsLowering.kt @@ -6,8 +6,10 @@ package org.jetbrains.kotlin.ir.backend.js.lower import org.jetbrains.kotlin.backend.common.FileLoweringPass +import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext +import org.jetbrains.kotlin.ir.backend.js.utils.Namer import org.jetbrains.kotlin.ir.declarations.IrFile import org.jetbrains.kotlin.ir.declarations.IrFunction import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction @@ -20,6 +22,7 @@ import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.SimpleType import org.jetbrains.kotlin.util.OperatorNameConventions @@ -30,11 +33,16 @@ class IntrinsicifyCallsLowering(private val context: JsIrBackendContext) : FileL private val memberToTransformer: Map IrCall> private val memberToIrFunction: Map private val symbolToIrFunction: Map + private val nameToIrTransformer: Map IrCall> + + val kCallable = context.builtIns.getBuiltInClassByFqName(KotlinBuiltIns.FQ_NAMES.kCallable.toSafe()) + val kProperty = context.builtIns.getBuiltInClassByFqName(KotlinBuiltIns.FQ_NAMES.kProperty.asSingleFqName()) init { memberToIrFunction = mutableMapOf() symbolToIrFunction = mutableMapOf() memberToTransformer = mutableMapOf() + nameToIrTransformer = mutableMapOf() val primitiveNumbers = context.irBuiltIns.run { listOf(int, short, byte, float, double) } @@ -103,6 +111,25 @@ class IntrinsicifyCallsLowering(private val context: JsIrBackendContext) : FileL } } } + + nameToIrTransformer.run { + addWithPredicate( + Name.special(Namer.KCALLABLE_GET_NAME), + { call -> call.symbol.owner.dispatchReceiverParameter?.run { DescriptorUtils.isSubtypeOfClass(type, kCallable) } ?: false }, + { call -> irCall(call, context.intrinsics.jsName.symbol, dispatchReceiverAsFirstArgument = true) }) + + addWithPredicate( + Name.identifier(Namer.KPROPERTY_GET), + { call -> call.symbol.owner.dispatchReceiverParameter?.run { DescriptorUtils.isSubtypeOfClass(type, kProperty) } ?: false }, + { call -> irCall(call, context.intrinsics.jsPropertyGet.symbol, dispatchReceiverAsFirstArgument = true)} + ) + + addWithPredicate( + Name.identifier(Namer.KPROPERTY_SET), + { call -> call.symbol.owner.dispatchReceiverParameter?.run { DescriptorUtils.isSubtypeOfClass(type, kProperty) } ?: false}, + { call -> irCall(call, context.intrinsics.jsPropertySet.symbol, dispatchReceiverAsFirstArgument = true)} + ) + } } override fun lower(irFile: IrFile) { @@ -132,7 +159,12 @@ class IntrinsicifyCallsLowering(private val context: JsIrBackendContext) : FileL return it(call) } } + + nameToIrTransformer[symbol.owner.name]?.let { + return it(call) + } } + } return call @@ -196,4 +228,10 @@ private fun MutableMap.add(from: IrFunctionSymbol, to: put(from, to) } +private fun MutableMap IrCall>.addWithPredicate(from: K, predicate: (IrCall) -> Boolean, action: (IrCall) -> IrCall) { + put(from) { call: IrCall -> select({ predicate(call) }, { action(call) }, { call }) } +} + +private inline fun select(crossinline predicate: () -> Boolean, crossinline ifTrue: () -> T, crossinline ifFalse: () -> T): T = if (predicate()) ifTrue() else ifFalse() + private data class SimpleMemberKey(val klass: KotlinType, val name: Name) 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 90deb139059..882884e8a24 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 @@ -6,10 +6,7 @@ package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs import org.jetbrains.kotlin.ir.backend.js.utils.JsGenerationContext -import org.jetbrains.kotlin.ir.declarations.IrClass -import org.jetbrains.kotlin.ir.declarations.IrConstructor -import org.jetbrains.kotlin.ir.declarations.IrField -import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction +import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.js.backend.ast.* class IrDeclarationToJsTransformer : BaseIrElementToJsNodeTransformer { @@ -35,4 +32,8 @@ class IrDeclarationToJsTransformer : BaseIrElementToJsNodeTransformer { - classBlock.statements += declaration.accept(transformer, context).makeStmt() + classBlock.statements += declaration.accept(transformer, context) classBlock.statements += generateInheritanceCode() } is IrSimpleFunction -> { @@ -48,6 +49,9 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo is IrClass -> { classBlock.statements += JsClassGenerator(declaration, context).generate() } + is IrVariable -> { + classBlock.statements += declaration.accept(transformer, context) + } else -> { } } 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 3df7757644c..da1860b1584 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 @@ -70,6 +70,17 @@ class JsIntrinsicTransformers(backendContext: JsIrBackendContext) { JsInvocation(Namer.JS_OBJECT_CREATE_FUNCTION, prototype) } + add(intrinsics.jsSetJSField) { call, context -> + val args = translateCallArguments(call, context) + val receiver = args[0] + val fieldName = args[1] as JsStringLiteral + val fieldValue = args[2] + + val fieldNameLiteral = fieldName.value!! + + jsAssignment(JsNameRef(fieldNameLiteral, receiver), fieldValue) + } + add(backendContext.sharedVariablesManager.closureBoxConstructorTypeSymbol) { call, context -> val args = translateCallArguments(call, context) val initializer = args[0] @@ -86,6 +97,27 @@ class JsIntrinsicTransformers(backendContext: JsIrBackendContext) { else -> JsInvocation(JsFunction(context.currentScope, jsCode as? JsBlock ?: JsBlock(jsCode as JsStatement), "")) } } + + add(intrinsics.jsName) { call: IrCall, context -> + val args = translateCallArguments(call, context) + val receiver = args[0] + JsNameRef(Namer.KCALLABLE_NAME, receiver) + } + + add(intrinsics.jsPropertyGet) { call: IrCall, context -> + val args = translateCallArguments(call, context) + val reference = args[0] + val receiver = args[1] + JsInvocation(JsNameRef(Namer.KPROPERTY_GET, reference), listOf(receiver)) + } + + add(intrinsics.jsPropertySet) { call: IrCall, context -> + val args = translateCallArguments(call, context) + val reference = args[0] + val receiver = args[1] + val value = args[2] + JsInvocation(JsNameRef(Namer.KPROPERTY_SET, reference), listOf(receiver, value)) + } } } diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/Namer.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/Namer.kt index 799cd91f7b2..161c6d6597b 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/Namer.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/Namer.kt @@ -37,6 +37,7 @@ object Namer { val SLICE_FUNCTION = "slice" val CONCAT_FUNCTION = "concat" + val OUTER_NAME = "\$outer" val UNREACHABLE_NAME = "\$unreachable" val OUTER_FIELD_NAME = "\$outer" @@ -85,6 +86,12 @@ object Namer { val GETTER_PREFIX = "get_" val SETTER_PREFIX = "set_" + val KCALLABLE_GET_NAME = "" + val KCALLABLE_NAME = "callableName" + val KPROPERTY_GET = "get" + val KPROPERTY_SET = "set" + val KCALLABLE_CACHE_SUFFIX = "\$cache" + val SETTER_ARGUMENT = "\$setValue" val THIS_SPECIAL_NAME = "" diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/descriptorBasedUtils.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/descriptorBasedUtils.kt index 5b16fa54cec..af181cd9263 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/descriptorBasedUtils.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/utils/descriptorBasedUtils.kt @@ -6,13 +6,15 @@ package org.jetbrains.kotlin.ir.backend.js.utils import org.jetbrains.kotlin.builtins.KotlinBuiltIns -import org.jetbrains.kotlin.descriptors.FunctionDescriptor -import org.jetbrains.kotlin.descriptors.ModuleDescriptor +import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.descriptors.annotations.Annotations +import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.ir.symbols.IrClassSymbol import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.types.KotlinType val IrConstructorSymbol.constructedClass get() = descriptor.constructedClass @@ -25,3 +27,27 @@ fun ModuleDescriptor.getFunctions(fqName: FqName): List { fun ModuleDescriptor.getFunctions(packageFqName: FqName, name: Name): List { return getPackage(packageFqName).memberScope.getContributedFunctions(name, NoLookupLocation.FROM_BACKEND).toList() } + +fun ModuleDescriptor.getClassifier(fqName: FqName): ClassifierDescriptor? { + return getClassifier(fqName.parent(), fqName.shortName()) +} + +fun ModuleDescriptor.getClassifier(packageFqName: FqName, name: Name): ClassifierDescriptor? { + return getPackage(packageFqName).memberScope.getContributedClassifier(name, NoLookupLocation.FROM_BACKEND) +} + +fun createValueParameter(containingDeclaration: CallableDescriptor, index: Int, name: String, type: KotlinType): ValueParameterDescriptor { + return ValueParameterDescriptorImpl( + containingDeclaration = containingDeclaration, + original = null, + index = index, + annotations = Annotations.EMPTY, + name = Name.identifier(name), + outType = type, + declaresDefaultValue = false, + isCrossinline = false, + isNoinline = false, + varargElementType = null, + source = SourceElement.NO_SOURCE + ) +} \ No newline at end of file diff --git a/js/js.translator/testData/box/callableReference/function/functionReferenceName.kt b/js/js.translator/testData/box/callableReference/function/functionReferenceName.kt new file mode 100644 index 00000000000..a41b9101b6a --- /dev/null +++ b/js/js.translator/testData/box/callableReference/function/functionReferenceName.kt @@ -0,0 +1,24 @@ +// EXPECTED_REACHABLE_NODES: 1109 +// This test was adapted from compiler/testData/codegen/box/callableReference/function/local/. +package foo + +import kotlin.reflect.KFunction + +fun foo0() = "OK" +fun foo1(a: String) = "O" + a +fun foo2(a: String, b: String) = a + b + +fun refName0(ref: KFunction) = ref.name +//fun refName1(ref: KFunction1) = ref.name +//fun refName2(ref: KFunction2) = ref.name + +fun box(): String { + val name = refName0(::foo0) + val f1 = ::foo1 + val f2 = ::foo2 + + if (name != "foo0") return "Fail: " + name + if (f1.name != "foo1") return "Fail: " + f1.name + if (f2.name != "foo2") return "Fail: " + f2.name + return "OK" +}