[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
This commit is contained in:
committed by
Roman Artemev
parent
fb1fbf1473
commit
261edd5f4c
+4
-18
@@ -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<IrBindableSymbol<*, *>, IrFieldSymbol>()
|
||||
private val outerThisFieldSymbols = HashMap<IrClass, IrFieldSymbol>()
|
||||
private val innerClassConstructors = HashMap<IrConstructorSymbol, IrConstructorSymbol>()
|
||||
@@ -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) +
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
+2
-15
@@ -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(
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
+3
-23
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
+7
-6
@@ -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)
|
||||
}
|
||||
|
||||
+353
@@ -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<CallableDescriptor, IrFunction>()
|
||||
|
||||
// TODO: replace descriptor usage with symbol instead
|
||||
private val collectedReferenceMap = mutableMapOf<IrDeclaration, IrCallableReference>()
|
||||
|
||||
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<List<IrDeclaration>, 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<IrDeclaration> {
|
||||
// transform
|
||||
// x = Foo::bar ->
|
||||
// x = Foo_bar_KreferenceGet(c1: closure$C1, c2: closure$C2) : KFunctionN<Foo, T2, ..., TN, TReturn> {
|
||||
// [ 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<Foo, T2, ..., TN, TReturn>, 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<IrDeclaration> {
|
||||
// transform
|
||||
// x = Foo::bar ->
|
||||
// x = Foo_bar_KreferenceGet() : KPropertyN<Foo, PType> {
|
||||
// if ($cache$ == null) { // very likely property reference is going to be cached
|
||||
// val x = fun Foo_bar_KreferenceClosure_get(r: Foo): PType {
|
||||
// return r.<get>()
|
||||
// }
|
||||
// x.get = x
|
||||
// x.callableName = "bar"
|
||||
// if (mutable) {
|
||||
// x.set = fun Foo_bar_KreferenceClosure_set(r: Foo, v: PType>) {
|
||||
// r.<set>(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<IrStatement>()
|
||||
|
||||
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<List<IrStatement>, IrValueSymbol>
|
||||
): List<IrDeclaration> {
|
||||
|
||||
val (bodyStatements, varSymbol) = builder()
|
||||
val statements = mutableListOf<IrStatement>()
|
||||
val returnValue: IrExpression
|
||||
val returnStatements: List<IrDeclaration>
|
||||
if (getterFunction.valueParameters.isEmpty()) {
|
||||
// compose cache for 'direct' closure
|
||||
// if ($cache$ === null) {
|
||||
// $cache$ = <body>
|
||||
// }
|
||||
//
|
||||
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<IrStatement>().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<IrValueParameterSymbol> {
|
||||
val result = mutableListOf<IrValueParameterSymbol>()
|
||||
|
||||
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))
|
||||
}
|
||||
}
|
||||
}
|
||||
-183
@@ -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<IrDeclaration, KotlinType>()
|
||||
private val oldToNewDeclarationMap = mutableMapOf<IrFunctionSymbol, IrFunction>()
|
||||
|
||||
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<IrFunction> {
|
||||
// TODO: property reference
|
||||
|
||||
// transform
|
||||
// x = Foo::bar ->
|
||||
// x = Foo_bar_KreferenceGet(c1: closure$C1, c2: closure$C2) : KFunctionN<Foo, T2, ..., TN, TReturn> {
|
||||
// return fun Foo_bar_KreferenceClosure(p0: Foo, p1: T2, p2: T3): TReturn {
|
||||
// return p0.bar(c1, c2, p1, p2)
|
||||
// }
|
||||
// }
|
||||
|
||||
// KFunctionN<Foo, T2, ..., TN, TReturn>, 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)
|
||||
}
|
||||
}
|
||||
+38
@@ -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<SimpleMemberKey, (IrCall) -> IrCall>
|
||||
private val memberToIrFunction: Map<SimpleMemberKey, IrSimpleFunction>
|
||||
private val symbolToIrFunction: Map<IrFunctionSymbol, IrSimpleFunction>
|
||||
private val nameToIrTransformer: Map<Name, (IrCall) -> 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 <V> MutableMap<IrFunctionSymbol, V>.add(from: IrFunctionSymbol, to:
|
||||
put(from, to)
|
||||
}
|
||||
|
||||
private fun <K> MutableMap<K, (IrCall) -> IrCall>.addWithPredicate(from: K, predicate: (IrCall) -> Boolean, action: (IrCall) -> IrCall) {
|
||||
put(from) { call: IrCall -> select({ predicate(call) }, { action(call) }, { call }) }
|
||||
}
|
||||
|
||||
private inline fun <T> 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)
|
||||
|
||||
+5
-4
@@ -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<JsStatement, JsGenerationContext> {
|
||||
@@ -35,4 +32,8 @@ class IrDeclarationToJsTransformer : BaseIrElementToJsNodeTransformer<JsStatemen
|
||||
)
|
||||
return jsAssignment(JsNameRef(fieldName, JsThisRef()), initExpression).makeStmt()
|
||||
}
|
||||
|
||||
override fun visitVariable(declaration: IrVariable, context: JsGenerationContext): JsStatement {
|
||||
return declaration.accept(IrElementToJsStatementTransformer(), context)
|
||||
}
|
||||
}
|
||||
|
||||
+6
-2
@@ -15,6 +15,7 @@ import org.jetbrains.kotlin.ir.backend.js.utils.isAny
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrConstructor
|
||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||
import org.jetbrains.kotlin.ir.declarations.IrVariable
|
||||
import org.jetbrains.kotlin.ir.symbols.impl.IrClassSymbolImpl
|
||||
import org.jetbrains.kotlin.ir.util.isInterface
|
||||
import org.jetbrains.kotlin.ir.util.isReal
|
||||
@@ -34,12 +35,12 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
|
||||
fun generate(): JsStatement {
|
||||
|
||||
maybeGeneratePrimaryConstructor()
|
||||
val transformer = IrFunctionToJsTransformer()
|
||||
val transformer = IrDeclarationToJsTransformer()
|
||||
|
||||
for (declaration in irClass.declarations) {
|
||||
when (declaration) {
|
||||
is IrConstructor -> {
|
||||
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 -> {
|
||||
}
|
||||
}
|
||||
|
||||
+32
@@ -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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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 = "<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 = "<this>"
|
||||
|
||||
+28
-2
@@ -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<FunctionDescriptor> {
|
||||
fun ModuleDescriptor.getFunctions(packageFqName: FqName, name: Name): List<FunctionDescriptor> {
|
||||
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
|
||||
)
|
||||
}
|
||||
+24
@@ -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<String>) = ref.name
|
||||
//fun refName1(ref: KFunction1<String, String>) = ref.name
|
||||
//fun refName2(ref: KFunction2<String, String, String>) = 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"
|
||||
}
|
||||
Reference in New Issue
Block a user