Rewrote callable reference lowering

For each callable reference a class inherited from KFunctionImpl is built.
This commit is contained in:
Igor Chevdar
2017-05-12 18:41:26 +03:00
parent dc80ba3492
commit a41552b3c8
12 changed files with 528 additions and 326 deletions
@@ -52,10 +52,13 @@ abstract internal class IrElementTransformerVoidWithContext : IrElementTransform
}
override final fun visitField(declaration: IrField): IrStatement {
val isDelegated = declaration.descriptor.isDelegated
if (isDelegated) scopeStack.push(ScopeWithIr(Scope(declaration.descriptor), declaration))
val peek = scopeStack.peek()
val fieldDiffersFromProperty = peek == null || peek.scope.scopeOwner != declaration.descriptor
if (fieldDiffersFromProperty)
scopeStack.push(ScopeWithIr(Scope(declaration.descriptor), declaration))
val result = visitFieldNew(declaration)
if (isDelegated) scopeStack.pop()
if (fieldDiffersFromProperty)
scopeStack.pop()
return result
}
@@ -55,6 +55,7 @@ class LocalDeclarationsLowering(val context: BackendContext) : DeclarationContai
when (memberDeclaration) {
is IrFunction -> LocalDeclarationsTransformer(memberDeclaration).lowerLocalDeclarations()
is IrProperty -> LocalDeclarationsTransformer(memberDeclaration).lowerLocalDeclarations()
is IrField -> LocalDeclarationsTransformer(memberDeclaration).lowerLocalDeclarations()
is IrAnonymousInitializer -> LocalDeclarationsTransformer(memberDeclaration).lowerLocalDeclarations()
else -> null
}
@@ -101,34 +101,35 @@ internal class SpecialDescriptorsFactory(val context: Context) {
descriptor: FunctionDescriptor,
bridgeDirections: Array<BridgeDirection>) {
val returnType = when (bridgeDirections[0]) {
BridgeDirection.TO_VALUE_TYPE -> descriptor.returnType!!
BridgeDirection.NOT_NEEDED -> descriptor.returnType
BridgeDirection.TO_VALUE_TYPE -> descriptor.returnType!!
BridgeDirection.NOT_NEEDED -> descriptor.returnType
BridgeDirection.FROM_VALUE_TYPE -> context.builtIns.anyType
}
val extensionReceiverType = when (bridgeDirections[1]) {
BridgeDirection.TO_VALUE_TYPE -> descriptor.extensionReceiverParameter!!.type
BridgeDirection.NOT_NEEDED -> descriptor.extensionReceiverParameter?.type
BridgeDirection.TO_VALUE_TYPE -> descriptor.extensionReceiverParameter!!.type
BridgeDirection.NOT_NEEDED -> descriptor.extensionReceiverParameter?.type
BridgeDirection.FROM_VALUE_TYPE -> context.builtIns.anyType
}
val valueParameters = descriptor.valueParameters.mapIndexed { index, valueParameterDescriptor ->
when (bridgeDirections[index + 2]) {
BridgeDirection.TO_VALUE_TYPE -> valueParameterDescriptor
BridgeDirection.NOT_NEEDED -> valueParameterDescriptor
BridgeDirection.FROM_VALUE_TYPE -> ValueParameterDescriptorImpl(
containingDeclaration = valueParameterDescriptor.containingDeclaration,
original = null,
index = index,
annotations = Annotations.EMPTY,
name = valueParameterDescriptor.name,
outType = context.builtIns.anyType,
declaresDefaultValue = valueParameterDescriptor.declaresDefaultValue(),
isCrossinline = valueParameterDescriptor.isCrossinline,
isNoinline = valueParameterDescriptor.isNoinline,
varargElementType = valueParameterDescriptor.varargElementType,
source = SourceElement.NO_SOURCE)
}
val outType = when (bridgeDirections[index + 2]) {
BridgeDirection.TO_VALUE_TYPE -> valueParameterDescriptor.type
BridgeDirection.NOT_NEEDED -> valueParameterDescriptor.type
BridgeDirection.FROM_VALUE_TYPE -> context.builtIns.anyType
}
ValueParameterDescriptorImpl(
containingDeclaration = valueParameterDescriptor.containingDeclaration,
original = null,
index = index,
annotations = Annotations.EMPTY,
name = valueParameterDescriptor.name,
outType = outType,
declaresDefaultValue = valueParameterDescriptor.declaresDefaultValue(),
isCrossinline = valueParameterDescriptor.isCrossinline,
isNoinline = valueParameterDescriptor.isNoinline,
varargElementType = valueParameterDescriptor.varargElementType,
source = SourceElement.NO_SOURCE)
}
bridgeDescriptor.initialize(
/* receiverParameterType = */ extensionReceiverType,
@@ -29,19 +29,17 @@ enum class KonanPhase(val description: String,
/* ... */ LOWER("IR Lowering"),
/* ... ... */ LOWER_INLINE("Functions inlining"),
/* ... ... ... */ DESERIALIZER("Deserialize inline bodies"),
/* ... ... */ LOWER_INTEROP("Interop lowering"),
/* ... ... */ LOWER_ENUMS("Enum classes lowering"),
/* ... ... */ LOWER_DELEGATION("Delegation lowering"),
/* ... ... */ LOWER_INITIALIZERS("Initializers lowering", LOWER_ENUMS),
/* ... ... */ LOWER_SHARED_VARIABLES("Shared Variable Lowering", LOWER_INITIALIZERS),
/* ... ... */ LOWER_CALLABLES("Callable references Lowering",
LOWER_INTEROP, LOWER_INITIALIZERS, LOWER_DELEGATION),
/* ... ... */ LOWER_VARARG("Vararg lowering", LOWER_CALLABLES),
/* ... ... */ LOWER_LOCAL_FUNCTIONS("Local Function Lowering", LOWER_SHARED_VARIABLES),
/* ... ... */ LOWER_INTEROP("Interop lowering", LOWER_LOCAL_FUNCTIONS),
/* ... ... */ LOWER_CALLABLES("Callable references Lowering", LOWER_INTEROP, LOWER_DELEGATION, LOWER_LOCAL_FUNCTIONS),
/* ... ... */ LOWER_VARARG("Vararg lowering", LOWER_CALLABLES),
/* ... ... */ LOWER_TAILREC("tailrec lowering", LOWER_LOCAL_FUNCTIONS),
/* ... ... */ LOWER_FINALLY("Finally blocks lowering", LOWER_INITIALIZERS, LOWER_LOCAL_FUNCTIONS, LOWER_TAILREC),
/* ... ... */ LOWER_DEFAULT_PARAMETER_EXTENT("Default Parameter Extent Lowering",
LOWER_TAILREC, LOWER_ENUMS),
/* ... ... */ LOWER_DEFAULT_PARAMETER_EXTENT("Default Parameter Extent Lowering", LOWER_TAILREC, LOWER_ENUMS),
/* ... ... */ LOWER_INNER_CLASSES("Inner classes lowering", LOWER_DEFAULT_PARAMETER_EXTENT),
/* ... ... */ LOWER_LATEINIT("Lateinit properties lowering"),
/* ... ... */ LOWER_BUILTIN_OPERATORS("BuiltIn Operators Lowering", LOWER_DEFAULT_PARAMETER_EXTENT, LOWER_LATEINIT),
@@ -40,7 +40,6 @@ enum class ValueType(val classFqName: FqNameUnsafe, val isNullable: Boolean = fa
FLOAT(KotlinBuiltIns.FQ_NAMES._float),
DOUBLE(KotlinBuiltIns.FQ_NAMES._double),
UNBOUND_CALLABLE_REFERENCE(FqNameUnsafe("konan.internal.UnboundCallableReference")),
NATIVE_PTR(KonanBuiltIns.FqNames.nativePtr),
NATIVE_POINTED(InteropBuiltIns.FqNames.nativePointed, isNullable = true),
@@ -137,8 +137,6 @@ internal fun KonanBuiltIns.getKonanInternalFunctions(name: String): List<Functio
return konanInternal.getContributedFunctions(Name.identifier(name), NoLookupLocation.FROM_BACKEND).toList()
}
internal fun KotlinType.isUnboundCallableReference() = this.isRepresentedAs(ValueType.UNBOUND_CALLABLE_REFERENCE)
internal val KotlinType.isFunctionOrKFunctionType: Boolean
get() {
val kind = constructor.declarationDescriptor?.getFunctionalClassKind()
@@ -33,7 +33,6 @@ private val valueTypes = ValueType.values().associate {
ValueType.FLOAT -> LLVMFloatType()
ValueType.DOUBLE -> LLVMDoubleType()
ValueType.UNBOUND_CALLABLE_REFERENCE,
ValueType.NATIVE_PTR, ValueType.NATIVE_POINTED, ValueType.C_POINTER -> int8TypePtr
}!!
}
@@ -689,7 +689,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
is IrBreak -> return evaluateBreak (value)
is IrContinue -> return evaluateContinue (value)
is IrGetObjectValue -> return evaluateGetObjectValue (value)
is IrCallableReference -> return evaluateCallableReference (value)
is IrFunctionReference -> return evaluateFunctionReference (value)
is IrSuspendableExpression ->
return evaluateSuspendableExpression (value)
is IrSuspensionPoint -> return evaluateSuspensionPoint (value)
@@ -1744,17 +1744,16 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
//-------------------------------------------------------------------------//
private fun evaluateCallableReference(expression: IrCallableReference): LLVMValueRef {
private fun evaluateFunctionReference(expression: IrFunctionReference): LLVMValueRef {
// TODO: consider creating separate IR element for pointer to function.
assert (expression.type.isUnboundCallableReference() ||
TypeUtils.getClassDescriptor(expression.type) == context.interopBuiltIns.cPointer)
assert (TypeUtils.getClassDescriptor(expression.type) == context.interopBuiltIns.cPointer)
assert (expression.getArguments().isEmpty())
val descriptor = expression.descriptor
assert (descriptor.dispatchReceiverParameter == null)
val entry = codegen.functionEntryPointAddress(descriptor as FunctionDescriptor)
val entry = codegen.functionEntryPointAddress(descriptor)
return entry
}
@@ -1822,10 +1821,6 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
val argsWithContinuationIfNeeded = if (descriptor.isSuspend)
args + getContinuation()
else args
if (descriptor.isFunctionInvoke) {
return evaluateFunctionInvoke(descriptor, argsWithContinuationIfNeeded, resultLifetime)
}
if (descriptor.isIntrinsic) {
return evaluateIntrinsicCall(callee, argsWithContinuationIfNeeded)
}
@@ -1840,40 +1835,6 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
//-------------------------------------------------------------------------//
private val functionImplUnboundRefGetter by lazy {
context.builtIns.getKonanInternalClass("FunctionImpl")
.unsubstitutedMemberScope.getContributedDescriptors()
.filterIsInstance<PropertyDescriptor>()
.single { it.name.asString() == "unboundRef" }
.getter!!
}
private fun evaluateFunctionInvoke(descriptor: FunctionDescriptor,
args: List<LLVMValueRef>, resultLifetime: Lifetime): LLVMValueRef {
// Note: the whole function code below is written in the assumption that
// `invoke` method receiver is passed as first argument.
val functionImpl = args[0] // Instance of `konan.internal.FunctionImpl`.
// `functionImpl.unboundRef` is the pointer to (static) function of type
// `(FunctionImpl, Arg_1, ..., Arg_n): Ret`. See [CallableReferenceLowering] for details.
// LLVM type for such function is equal to type for `FunctionImpl.invoke(Arg_1, ..., Arg_n): Ret`.
// So we can use the latter for simplicity:
val unboundRefType = codegen.getLlvmFunctionType(descriptor)
// Get `functionImpl.unboundRef`:
val unboundRef = evaluateSimpleFunctionCall(functionImplUnboundRefGetter,
listOf(functionImpl), Lifetime.IRRELEVANT /* unboundRef isn't managed reference */)
// Cast `functionImpl.unboundRef` to pointer to function:
val entryPtr = codegen.bitcast(pointerType(unboundRefType), unboundRef, "entry")
return call(descriptor, entryPtr, args, resultLifetime)
}
//-------------------------------------------------------------------------//
private fun evaluateSimpleFunctionCall(
descriptor: FunctionDescriptor, args: List<LLVMValueRef>,
resultLifetime: Lifetime, superClass: ClassDescriptor? = null): LLVMValueRef {
@@ -18,256 +18,502 @@ package org.jetbrains.kotlin.backend.konan.lower
import org.jetbrains.kotlin.backend.common.DeclarationContainerLoweringPass
import org.jetbrains.kotlin.backend.common.descriptors.explicitParameters
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.backend.konan.KonanBackendContext
import org.jetbrains.kotlin.backend.common.lower.*
import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.descriptors.getKonanInternalClass
import org.jetbrains.kotlin.backend.konan.descriptors.isFunctionOrKFunctionType
import org.jetbrains.kotlin.backend.konan.descriptors.synthesizedName
import org.jetbrains.kotlin.backend.konan.ir.createFakeOverrideDescriptor
import org.jetbrains.kotlin.backend.konan.llvm.functionName
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.ValueParameterDescriptorImpl
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.descriptors.impl.*
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.ir.builders.*
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
import org.jetbrains.kotlin.ir.expressions.IrCallableReference
import org.jetbrains.kotlin.ir.declarations.impl.*
import org.jetbrains.kotlin.ir.expressions.IrConstKind
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.IrFunctionReference
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrFunctionReferenceImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrVarargImpl
import org.jetbrains.kotlin.ir.util.addArguments
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrDelegatingConstructorCallImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrInstanceInitializerCallImpl
import org.jetbrains.kotlin.ir.util.createParameterDeclarations
import org.jetbrains.kotlin.ir.util.getArguments
import org.jetbrains.kotlin.ir.util.transformFlat
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeProjectionImpl
import org.jetbrains.kotlin.types.TypeSubstitutor
import org.jetbrains.kotlin.types.replace
import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
import org.jetbrains.kotlin.ir.util.transformFlat
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
/**
* This lowering pass lowers all [IrCallableReference]s to unbound ones.
*/
internal class CallableReferenceLowering(val context: KonanBackendContext) : DeclarationContainerLoweringPass {
internal class CallableReferenceLowering(val context: Context): DeclarationContainerLoweringPass {
var callableReferenceCount = 0
private var functionReferenceCount = 0
override fun lower(irDeclarationContainer: IrDeclarationContainer) {
irDeclarationContainer.declarations.transformFlat { declaration ->
if (declaration !is IrDeclarationContainer)
lowerCallableReferences(this, irDeclarationContainer, declaration)
lowerFunctionReferences(irDeclarationContainer, declaration)
else
null
}
}
}
/**
* Replaces all callable references in the function body to unbound ones.
* Returns the list of this function and all created ones.
*/
private fun lowerCallableReferences(lower: CallableReferenceLowering,
irDeclarationContainer: IrDeclarationContainer,
declaration: IrDeclaration): List<IrDeclaration> {
val containingDeclaration = when (irDeclarationContainer) {
is IrClass -> irDeclarationContainer.descriptor
is IrFile -> irDeclarationContainer.packageFragmentDescriptor
else -> throw AssertionError("Unexpected declaration container: $irDeclarationContainer")
}
val transformer = CallableReferencesUnbinder(lower, containingDeclaration)
declaration.transformChildrenVoid(transformer)
return listOf(declaration) + transformer.createdFunctions
}
private object DECLARATION_ORIGIN_FUNCTION_FOR_CALLABLE_REFERENCE :
IrDeclarationOriginImpl("FUNCTION_FOR_CALLABLE_REFERENCE")
/**
* Replaces all callable references in the function body to unbound ones.
* Adds all created functions to [createdFunctions].
*/
private class CallableReferencesUnbinder(val lower: CallableReferenceLowering,
val containingDeclaration: DeclarationDescriptor) : IrElementTransformerVoid() {
val createdFunctions = mutableListOf<IrFunction>()
private val builtIns = lower.context.builtIns
override fun visitElement(element: IrElement): IrElement {
return super.visitElement(element)
}
private val unboundCallableReferenceType by lazy {
builtIns.getKonanInternalClass("UnboundCallableReference").defaultType
}
private val simpleFunctionImplClass by lazy {
builtIns.getKonanInternalClass("SimpleFunctionImpl")
}
private val simpleFunctionImplBoundArgsGetter by lazy {
simpleFunctionImplClass.defaultType.memberScope.getContributedDescriptors()
.filterIsInstance<PropertyDescriptor>()
.single { it.name.asString() == "boundArgs" }
.getter!!
}
override fun visitClass(declaration: IrClass): IrStatement {
// Class is a declaration container - it will be visited by the main visitor (CallableReferenceLowering).
return declaration
}
override fun visitFunctionReference(expression: IrFunctionReference): IrExpression {
expression.transformChildrenVoid(this)
if (!expression.type.isFunctionOrKFunctionType) {
// Not a subject of this lowering.
return expression
private fun lowerFunctionReferences(irDeclarationContainer: IrDeclarationContainer,
declaration: IrDeclaration): List<IrDeclaration> {
val containingDeclaration = when (irDeclarationContainer) {
is IrClass -> irDeclarationContainer.descriptor
is IrFile -> irDeclarationContainer.packageFragmentDescriptor
else -> throw AssertionError("Unexpected declaration container: $irDeclarationContainer")
}
val createdClasses = mutableListOf<IrDeclaration>()
declaration.transformChildrenVoid(object: IrElementTransformerVoid() {
val descriptor = expression.descriptor
val boundArgs = expression.getArguments()
val boundParams = boundArgs.map { it.first }
val allParams = descriptor.explicitParameters
val unboundParams = allParams - boundParams
val startOffset = expression.startOffset
val endOffset = expression.endOffset
// The code below creates a call to `SimpleFunctionImpl` constructor which creates the object implementing
// the function type.
// Create the function to be used as `unboundRef` of `SimpleFunctionImpl`:
val newFunction = createSimpleFunctionImplTarget(descriptor, unboundParams, boundParams, startOffset, endOffset)
createdFunctions.add(newFunction)
// Create the call to constructor and its arguments:
val unboundRef = IrFunctionReferenceImpl(startOffset, endOffset,
unboundCallableReferenceType, newFunction.descriptor, null)
val simpleFunctionImplClassConstructor = simpleFunctionImplClass.unsubstitutedPrimaryConstructor!!
val boundArgsVarargParam = simpleFunctionImplClassConstructor.valueParameters[1]
val boundArgsVararg = IrVarargImpl(
startOffset, endOffset,
boundArgsVarargParam.type,
boundArgsVarargParam.varargElementType!!,
boundArgs.map { it.second }
)
return IrCallImpl(startOffset, endOffset, simpleFunctionImplClassConstructor).apply {
putValueArgument(0, unboundRef)
putValueArgument(1, boundArgsVararg)
}
}
/**
* For given function [descriptor] creates the function which calls [descriptor] but
* takes all [boundParams] packed into `SimpleFunctionImpl` (and all [unboundParams] as is).
*/
private fun createSimpleFunctionImplTarget(descriptor: FunctionDescriptor,
unboundParams: List<ParameterDescriptor>,
boundParams: List<ParameterDescriptor>,
startOffset: Int, endOffset: Int): IrFunctionImpl {
// Create new function descriptor:
val newDescriptor = createSimpleFunctionImplTargetDescriptor(descriptor, unboundParams)
val builder = lower.context.createIrBuilder(newDescriptor)
val blockBody = builder.irBlockBody(startOffset, endOffset) {
val boundArgsGet = irCall(simpleFunctionImplBoundArgsGetter).apply {
dispatchReceiver = irGet(newDescriptor.valueParameters[0])
override fun visitClass(declaration: IrClass): IrStatement {
// Class is a declaration container - it will be visited by the main visitor (CallableReferenceLowering).
return declaration
}
+irLet(boundArgsGet) { boundArgs ->
val arrayGet = boundArgs.type.memberScope.getContributedDescriptors()
.filterIsInstance<FunctionDescriptor>().single { it.name.asString() == "get" }
override fun visitFunctionReference(expression: IrFunctionReference): IrExpression {
expression.transformChildrenVoid(this)
// TODO: some handling for type parameters is probably required here.
// Call to old function from new function:
val call = irCall(descriptor).apply {
// unboundParams are received as all new function parameters except first:
val newUnboundParams = newDescriptor.valueParameters.drop(1)
assert (unboundParams.size == newUnboundParams.size)
addArguments(unboundParams.mapIndexed { index, param ->
param to irGet(newUnboundParams[index])
})
// boundParams are received in `SimpleFunctionImpl.boundArgs`:
addArguments(boundParams.mapIndexed { index, param ->
param to irCall(arrayGet).apply {
dispatchReceiver = irGet(boundArgs)
putValueArgument(0, irInt(index))
}
})
if (!expression.type.isFunctionOrKFunctionType) {
// Not a subject of this lowering.
return expression
}
irReturn(call)
val loweredFunctionReference = FunctionReferenceBuilder(containingDeclaration, expression).build()
createdClasses += loweredFunctionReference.functionReferenceClass
return IrCallImpl(
startOffset = expression.startOffset,
endOffset = expression.endOffset,
calleeDescriptor = loweredFunctionReference.functionReferenceConstructorDescriptor).apply {
expression.getArguments().forEachIndexed { index, argument ->
putValueArgument(index, argument.second)
}
}
}
})
return listOf(declaration) + createdClasses
}
private abstract class DescriptorWithIrBuilder<out D : DeclarationDescriptor, out B : IrDeclaration> {
protected abstract fun buildDescriptor(): D
protected open fun doInitialize() {}
protected abstract fun buildIr(): B
val descriptor by lazy { buildDescriptor() }
private val builtIr by lazy { buildIr() }
private var initialized: Boolean = false
fun initialize() {
doInitialize()
initialized = true
}
val ir: B
get() {
if (!initialized)
throw Error("Access to IR before initialization")
return builtIr
}
}
private class BuiltFunctionReference(val functionReferenceClass: IrClass,
val functionReferenceConstructorDescriptor: ClassConstructorDescriptor)
private inner class FunctionReferenceBuilder(val containingDeclaration: DeclarationDescriptor,
val functionReference: IrFunctionReference) {
private val functionDescriptor = functionReference.descriptor
private val functionParameters = functionDescriptor.explicitParameters
private val boundFunctionParameters = functionReference.getArguments().map { it.first }
private val unboundFunctionParameters = functionParameters - boundFunctionParameters
private lateinit var functionReferenceClassDescriptor: ClassDescriptorImpl
private lateinit var argumentToPropertiesMap: Map<ParameterDescriptor, PropertyDescriptor>
private val functionReferenceMembers = mutableListOf<IrDeclaration>()
private fun KotlinType.replace(types: List<KotlinType>) = this.replace(types.map(::TypeProjectionImpl))
private val kFunctionImplClassDescriptor = context.builtIns.getKonanInternalClass("KFunctionImpl")
fun build(): BuiltFunctionReference {
val startOffset = functionReference.startOffset
val endOffset = functionReference.endOffset
val superTypes = mutableListOf<KotlinType>(
kFunctionImplClassDescriptor.defaultType.replace(listOf(functionDescriptor.returnType!!))
)
var suspendFunctionClassDescriptor: ClassDescriptor? = null
val functionClassDescriptor = context.reflectionTypes.getKFunction(unboundFunctionParameters.size)
val types = unboundFunctionParameters.map { it.type } + functionDescriptor.returnType!!
superTypes += functionClassDescriptor.defaultType.replace(types)
functionReferenceClassDescriptor = ClassDescriptorImpl(
/* containingDeclaration = */ containingDeclaration,
/* name = */ "${functionDescriptor.name}\$${functionReferenceCount++}".synthesizedName,
/* modality = */ Modality.FINAL,
/* kind = */ ClassKind.CLASS,
/* superTypes = */ superTypes,
/* source = */ SourceElement.NO_SOURCE,
/* isExternal = */ false
)
val constructorBuilder = createConstructorBuilder()
val typeSubstitutor = TypeSubstitutor.create(
functionClassDescriptor.declaredTypeParameters
.withIndex()
.associateBy({ it.value.typeConstructor }, { TypeProjectionImpl(types[it.index]) })
)
val invokeFunctionDescriptor = functionClassDescriptor.unsubstitutedMemberScope
.getContributedFunctions(Name.identifier("invoke"), NoLookupLocation.FROM_BACKEND).single().substitute(typeSubstitutor)!!
val invokeMethodBuilder = createInvokeMethodBuilder(invokeFunctionDescriptor)
val inheritedKFunctionImpl = kFunctionImplClassDescriptor.unsubstitutedMemberScope
.getContributedDescriptors()
.map { it.createFakeOverrideDescriptor(functionReferenceClassDescriptor) }
.filterNotNull()
val contributedDescriptors = (
inheritedKFunctionImpl + invokeMethodBuilder.descriptor
).toList()
functionReferenceClassDescriptor.initialize(SimpleMemberScope(contributedDescriptors), setOf(constructorBuilder.descriptor), null)
constructorBuilder.initialize()
functionReferenceMembers.add(constructorBuilder.ir)
invokeMethodBuilder.initialize()
functionReferenceMembers.add(invokeMethodBuilder.ir)
val functionReferenceClass = IrClassImpl(
startOffset = startOffset,
endOffset = endOffset,
origin = DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL,
descriptor = functionReferenceClassDescriptor,
members = functionReferenceMembers
)
functionReferenceClass.createParameterDeclarations()
return BuiltFunctionReference(functionReferenceClass, constructorBuilder.descriptor)
}
private fun ParameterDescriptor.copyAsValueParameter(newOwner: CallableDescriptor, index: Int)
= when (this) {
is ValueParameterDescriptor -> this.copy(newOwner, name, index)
is ReceiverParameterDescriptor -> ValueParameterDescriptorImpl(
containingDeclaration = newOwner,
original = null,
index = index,
annotations = annotations,
name = name,
outType = type,
declaresDefaultValue = false,
isCrossinline = false,
isNoinline = false,
varargElementType = null,
source = source
)
else -> throw Error("Unexpected parameter descriptor: $this")
}
private fun createConstructorBuilder()
= object : DescriptorWithIrBuilder<ClassConstructorDescriptorImpl, IrConstructor>() {
private val kFunctionImplConstructorDescriptor = kFunctionImplClassDescriptor.constructors.single()
private lateinit var constructorParameters: List<ValueParameterDescriptor>
override fun buildDescriptor(): ClassConstructorDescriptorImpl {
return ClassConstructorDescriptorImpl.create(
/* containingDeclaration = */ functionReferenceClassDescriptor,
/* annotations = */ Annotations.EMPTY,
/* isPrimary = */ false,
/* source = */ SourceElement.NO_SOURCE
)
}
override fun doInitialize() {
constructorParameters = boundFunctionParameters.mapIndexed { index, parameter ->
parameter.copyAsValueParameter(descriptor, index)
}
descriptor.initialize(constructorParameters, Visibilities.PUBLIC)
descriptor.returnType = functionReferenceClassDescriptor.defaultType
}
override fun buildIr(): IrConstructor {
argumentToPropertiesMap = boundFunctionParameters.associate {
it to buildPropertyWithBackingField(it.name, it.type, false)
}
val startOffset = functionReference.startOffset
val endOffset = functionReference.endOffset
val irBuilder = context.createIrBuilder(descriptor, startOffset, endOffset)
return IrConstructorImpl(
startOffset = startOffset,
endOffset = endOffset,
origin = DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL,
descriptor = descriptor).apply {
createParameterDeclarations()
body = irBuilder.irBlockBody {
+IrDelegatingConstructorCallImpl(startOffset, endOffset, kFunctionImplConstructorDescriptor).apply {
val name = IrConstImpl<String>(startOffset, endOffset, context.builtIns.stringType,
IrConstKind.String, functionDescriptor.name.asString())
putValueArgument(0, name)
val fqName = IrConstImpl<String>(startOffset, endOffset, context.builtIns.stringType, IrConstKind.String,
functionDescriptor.fullName)
putValueArgument(1, fqName)
val bound = IrConstImpl.boolean(startOffset, endOffset, context.builtIns.booleanType,
boundFunctionParameters.isNotEmpty())
putValueArgument(2, bound)
val needReceiver = boundFunctionParameters.singleOrNull() is ReceiverParameterDescriptor
val receiver = if (needReceiver) irGet(constructorParameters.single()) else irNull()
putValueArgument(3, receiver)
}
+IrInstanceInitializerCallImpl(startOffset, endOffset, functionReferenceClassDescriptor)
// Save all arguments to fields.
boundFunctionParameters.forEachIndexed { index, parameter ->
+irSetField(irThis(), argumentToPropertiesMap[parameter]!!, irGet(constructorParameters[index]))
}
}
}
}
}
val newFunction = IrFunctionImpl(
startOffset, endOffset, DECLARATION_ORIGIN_FUNCTION_FOR_CALLABLE_REFERENCE,
newDescriptor,
blockBody
)
// TODO: what about private package level functions?
private val DeclarationDescriptor.fullName: String
get() {
return when (this) {
is PackageFragmentDescriptor -> fqNameSafe.asString()
is ClassDescriptor -> containingDeclaration.fullName + "." + fqNameSafe
is FunctionDescriptor -> containingDeclaration.fullName + "." + functionName
is PropertyDescriptor -> containingDeclaration.fullName + "." + fqNameSafe
else -> TODO("$this")
}
}
newFunction.createParameterDeclarations()
private fun createInvokeMethodBuilder(functionInvokeFunctionDescriptor: FunctionDescriptor)
= object : DescriptorWithIrBuilder<SimpleFunctionDescriptorImpl, IrFunction>() {
return newFunction
}
override fun buildDescriptor() = SimpleFunctionDescriptorImpl.create(
/* containingDeclaration = */ functionReferenceClassDescriptor,
/* annotations = */ Annotations.EMPTY,
/* name = */ Name.identifier("invoke"),
/* kind = */ CallableMemberDescriptor.Kind.DECLARATION,
/* source = */ SourceElement.NO_SOURCE)
/**
* Creates descriptor for [createSimpleFunctionImplTarget].
*/
private fun createSimpleFunctionImplTargetDescriptor(descriptor: CallableDescriptor,
unboundParams: List<ParameterDescriptor>): FunctionDescriptor {
override fun doInitialize() {
val valueParameters = functionInvokeFunctionDescriptor.valueParameters
.map { it.copyAsValueParameter(this.descriptor, it.index) }
val newName = Name.identifier("${descriptor.name}\$bound-${lower.callableReferenceCount++}")
this.descriptor.initialize(
/* receiverParameterType = */ null,
/* dispatchReceiverParameter = */ functionReferenceClassDescriptor.thisAsReceiverParameter,
/* typeParameters = */ emptyList(),
/* unsubstitutedValueParameters = */ valueParameters,
/* unsubstitutedReturnType = */ functionInvokeFunctionDescriptor.returnType,
/* modality = */ Modality.FINAL,
/* visibility = */ Visibilities.PRIVATE).apply {
overriddenDescriptors += functionInvokeFunctionDescriptor
}
}
val newDescriptor = SimpleFunctionDescriptorImpl.create(
containingDeclaration, Annotations.EMPTY,
newName, CallableMemberDescriptor.Kind.SYNTHESIZED, SourceElement.NO_SOURCE)
override fun buildIr(): IrFunction {
val startOffset = functionReference.startOffset
val endOffset = functionReference.endOffset
val ourDescriptor = this.descriptor
val irBuilder = context.createIrBuilder(this.descriptor, startOffset, endOffset)
return IrFunctionImpl(
startOffset = startOffset,
endOffset = endOffset,
origin = DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL,
descriptor = this.descriptor).apply {
val simpleFunctionImplType = simpleFunctionImplClass.defaultType
createParameterDeclarations()
// Map each unbound param of original function to parameter of new function.
val newUnboundParams = unboundParams.mapIndexed { index, param ->
ValueParameterDescriptorImpl(
containingDeclaration = newDescriptor,
original = null,
index = index + 1,
annotations = Annotations.EMPTY,
name = param.name,
outType = builtIns.nullableAnyType, // Use erased type.
declaresDefaultValue = false,
isCrossinline = false, isNoinline = false,
varargElementType = null,
source = SourceElement.NO_SOURCE)
body = irBuilder.irBlockBody(startOffset, endOffset) {
+irReturn(
irCall(functionReference.descriptor).apply {
var unboundIndex = 0
val unboundArgsSet = unboundFunctionParameters.toSet()
functionParameters.forEach {
val argument = if (unboundArgsSet.contains(it))
irGet(ourDescriptor.valueParameters[unboundIndex++])
else
irGet(irThis(), argumentToPropertiesMap[it]!!)
when (it) {
functionDescriptor.dispatchReceiverParameter -> dispatchReceiver = argument
functionDescriptor.extensionReceiverParameter -> extensionReceiver = argument
else -> putValueArgument((it as ValueParameterDescriptor).index, argument)
}
}
assert(unboundIndex == ourDescriptor.valueParameters.size,
{ "Not all arguments of <invoke> are used" })
}
)
}
}
}
}
// `<func>: SimpleFunctionImpl`
val functionParameter = ValueParameterDescriptorImpl(
containingDeclaration = newDescriptor,
original = null,
index = 0,
annotations = Annotations.EMPTY,
name = Name.special("<func>"),
outType = simpleFunctionImplType,
declaresDefaultValue = false,
isCrossinline = false, isNoinline = false,
varargElementType = null,
source = SourceElement.NO_SOURCE)
private fun createPropertyGetterBuilder(propertyDescriptor: PropertyDescriptor, type: KotlinType)
= object : DescriptorWithIrBuilder<PropertyGetterDescriptorImpl, IrFunction>() {
val newValueParameters = listOf(functionParameter) + newUnboundParams
override fun buildDescriptor() = PropertyGetterDescriptorImpl(
/* correspondingProperty = */ propertyDescriptor,
/* annotations = */ Annotations.EMPTY,
/* modality = */ Modality.FINAL,
/* visibility = */ Visibilities.PRIVATE,
/* isDefault = */ false,
/* isExternal = */ false,
/* isInline = */ false,
/* kind = */ CallableMemberDescriptor.Kind.DECLARATION,
/* original = */ null,
/* source = */ SourceElement.NO_SOURCE
)
val newReturnType = builtIns.nullableAnyType // Use erased type.
override fun doInitialize() {
descriptor.apply {
initialize(type)
}
}
newDescriptor.initialize(null, null, descriptor.typeParameters, newValueParameters,
newReturnType, Modality.FINAL, Visibilities.PRIVATE)
override fun buildIr() = IrFunctionImpl(
startOffset = functionReference.startOffset,
endOffset = functionReference.endOffset,
origin = DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL,
descriptor = descriptor).apply {
return newDescriptor
createParameterDeclarations()
body = context.createIrBuilder(descriptor, startOffset, endOffset).irBlockBody {
+irReturn(irGetField(irThis(), propertyDescriptor))
}
}
}
private fun createPropertySetterBuilder(propertyDescriptor: PropertyDescriptor, type: KotlinType)
= object : DescriptorWithIrBuilder<PropertySetterDescriptorImpl, IrFunction>() {
override fun buildDescriptor() = PropertySetterDescriptorImpl(
/* correspondingProperty = */ propertyDescriptor,
/* annotations = */ Annotations.EMPTY,
/* modality = */ Modality.FINAL,
/* visibility = */ Visibilities.PRIVATE,
/* isDefault = */ false,
/* isExternal = */ false,
/* isInline = */ false,
/* kind = */ CallableMemberDescriptor.Kind.DECLARATION,
/* original = */ null,
/* source = */ SourceElement.NO_SOURCE
)
lateinit var valueParameterDescriptor: ValueParameterDescriptor
override fun doInitialize() {
descriptor.apply {
valueParameterDescriptor = ValueParameterDescriptorImpl(
containingDeclaration = this,
original = null,
index = 0,
annotations = Annotations.EMPTY,
name = Name.identifier("value"),
outType = type,
declaresDefaultValue = false,
isCrossinline = false,
isNoinline = false,
varargElementType = null,
source = SourceElement.NO_SOURCE
)
initialize(valueParameterDescriptor)
}
}
override fun buildIr() = IrFunctionImpl(
startOffset = functionReference.startOffset,
endOffset = functionReference.endOffset,
origin = DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL,
descriptor = descriptor).apply {
createParameterDeclarations()
body = context.createIrBuilder(descriptor, startOffset, endOffset).irBlockBody {
+irSetField(irThis(), propertyDescriptor, irGet(valueParameterDescriptor))
}
}
}
private fun createPropertyWithBackingFieldBuilder(name: Name, type: KotlinType, isMutable: Boolean)
= object : DescriptorWithIrBuilder<PropertyDescriptorImpl, IrProperty>() {
private lateinit var getterBuilder: DescriptorWithIrBuilder<PropertyGetterDescriptorImpl, IrFunction>
private var setterBuilder: DescriptorWithIrBuilder<PropertySetterDescriptorImpl, IrFunction>? = null
override fun buildDescriptor() = PropertyDescriptorImpl.create(
/* containingDeclaration = */ functionReferenceClassDescriptor,
/* annotations = */ Annotations.EMPTY,
/* modality = */ Modality.FINAL,
/* visibility = */ Visibilities.PRIVATE,
/* isVar = */ isMutable,
/* name = */ name,
/* kind = */ CallableMemberDescriptor.Kind.DECLARATION,
/* source = */ SourceElement.NO_SOURCE,
/* lateInit = */ false,
/* isConst = */ false,
/* isHeader = */ false,
/* isImpl = */ false,
/* isExternal = */ false,
/* isDelegated = */ false)
override fun doInitialize() {
getterBuilder = createPropertyGetterBuilder(descriptor, type).apply { initialize() }
if (isMutable)
setterBuilder = createPropertySetterBuilder(descriptor, type).apply { initialize() }
descriptor.initialize(getterBuilder.descriptor, setterBuilder?.descriptor)
val receiverType: KotlinType? = null
descriptor.setType(type, emptyList(), functionReferenceClassDescriptor.thisAsReceiverParameter, receiverType)
}
override fun buildIr(): IrProperty {
val startOffset = functionReference.startOffset
val endOffset = functionReference.endOffset
val backingField = IrFieldImpl(
startOffset = startOffset,
endOffset = endOffset,
origin = DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL,
descriptor = descriptor)
return IrPropertyImpl(
startOffset = startOffset,
endOffset = endOffset,
origin = DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL,
isDelegated = false,
descriptor = descriptor,
backingField = backingField,
getter = getterBuilder.ir,
setter = setterBuilder?.ir)
}
}
private fun buildPropertyWithBackingField(name: Name, type: KotlinType, isMutable: Boolean): PropertyDescriptor {
val propertyBuilder = createPropertyWithBackingFieldBuilder(name, type, isMutable).apply { initialize() }
functionReferenceMembers.add(propertyBuilder.ir)
return propertyBuilder.descriptor
}
private object DECLARATION_ORIGIN_FUNCTION_REFERENCE_IMPL :
IrDeclarationOriginImpl("FUNCTION_REFERENCE_IMPL")
}
}
@@ -1,39 +0,0 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package konan.internal
/**
* Represents the reference to callable without any bound arguments.
* It is supposed to be represented at runtime as native pointer to code.
*
* TODO: it seems to be very closely related to native interop types.
*/
abstract class UnboundCallableReference internal constructor()
/**
* Values of function types are represented at runtime as instances of this class (and its subclasses).
*
* [FunctionImpl] is a reference to callable with itself as single bound argument,
* i.e. when calling this function with arguments `args`, [unboundRef] is called with arguments `(this, *args)`.
* So the instance is supposed to contain all implicit (bound) arguments of target function, e.g. captured values.
*/
open class FunctionImpl(val unboundRef: UnboundCallableReference)
/**
* Simple [FunctionImpl] implementation: all bound arguments of target callable to be placed into [boundArgs].
*/
class SimpleFunctionImpl(unboundRef: UnboundCallableReference, vararg val boundArgs: Any?) : FunctionImpl(unboundRef)
@@ -0,0 +1,35 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package konan.internal
import kotlin.reflect.KFunction
@FixmeReflection
open class KFunctionImpl<out R>(override val name: String, val fqName: String, val bound: Boolean, val receiver: Any?): KFunction<R> {
override fun equals(other: Any?): Boolean {
if (other !is KFunctionImpl<*>) return false
return fqName == other.fqName && bound == other.bound && receiver == other.receiver
}
override fun hashCode(): Int {
return (fqName.hashCode() * 31 + if (bound) 1 else 0) * 31 + receiver.hashCode()
}
override fun toString(): String {
return fqName
}
}
@@ -65,11 +65,11 @@ public interface KProperty<out R> : KCallable<R> {
//
@FixmeReflection
public interface KProperty0<out R> : kotlin.reflect.KProperty<R>/* TODO , (T) -> R*/ {
public interface KProperty0<out R> : kotlin.reflect.KProperty<R>, () -> R {
// public abstract val getter: kotlin.reflect.KProperty1.Getter<T, R>
public abstract fun get(): R
public abstract operator fun invoke(): R
public override abstract operator fun invoke(): R
// @kotlin.SinceKotlin public abstract fun getDelegate(receiver: T): kotlin.Any?
//
@@ -78,11 +78,11 @@ public interface KProperty0<out R> : kotlin.reflect.KProperty<R>/* TODO , (T) ->
}
@FixmeReflection
public interface KProperty1<T, out R> : kotlin.reflect.KProperty<R>/* TODO , (T) -> R*/ {
public interface KProperty1<T, out R> : kotlin.reflect.KProperty<R>, (T) -> R {
// public abstract val getter: kotlin.reflect.KProperty1.Getter<T, R>
public abstract fun get(receiver: T): R
public abstract operator fun invoke(receiver: T): R
public override abstract operator fun invoke(receiver: T): R
// @kotlin.SinceKotlin public abstract fun getDelegate(receiver: T): kotlin.Any?
//
@@ -91,11 +91,11 @@ public interface KProperty1<T, out R> : kotlin.reflect.KProperty<R>/* TODO , (T)
}
@FixmeReflection
public interface KProperty2<T1, T2, out R> : kotlin.reflect.KProperty<R>/* TODO , (T) -> R*/ {
public interface KProperty2<T1, T2, out R> : kotlin.reflect.KProperty<R>, (T1, T2) -> R {
// public abstract val getter: kotlin.reflect.KProperty1.Getter<T, R>
public abstract fun get(receiver1: T1, receiver2: T2): R
public abstract operator fun invoke(receiver1: T1, receiver2: T2): R
public override abstract operator fun invoke(receiver1: T1, receiver2: T2): R
// @kotlin.SinceKotlin public abstract fun getDelegate(receiver: T): kotlin.Any?
//