Review feedback, part 1
This commit is contained in:
committed by
SvyatoslavScherbina
parent
4dec392880
commit
7d4074a1a4
+7
-1
@@ -1588,13 +1588,19 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
|||||||
// Note: the whole function code below is written in the assumption that
|
// Note: the whole function code below is written in the assumption that
|
||||||
// `invoke` method receiver is passed as first argument.
|
// `invoke` method receiver is passed as first argument.
|
||||||
|
|
||||||
val functionImpl = args[0]
|
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)
|
val unboundRefType = codegen.getLlvmFunctionType(descriptor)
|
||||||
|
|
||||||
|
// Get `functionImpl.unboundRef`:
|
||||||
val unboundRef = evaluateSimpleFunctionCall(codegen.newVar(),
|
val unboundRef = evaluateSimpleFunctionCall(codegen.newVar(),
|
||||||
functionImplUnboundRefGetter, listOf(functionImpl))
|
functionImplUnboundRefGetter, listOf(functionImpl))
|
||||||
|
|
||||||
|
// Cast `functionImpl.unboundRef` to pointer to function:
|
||||||
val entryPtr = codegen.bitcast(pointerType(unboundRefType), unboundRef, "entry")
|
val entryPtr = codegen.bitcast(pointerType(unboundRefType), unboundRef, "entry")
|
||||||
|
|
||||||
return call(descriptor, entryPtr, args, tmpVariableName)
|
return call(descriptor, entryPtr, args, tmpVariableName)
|
||||||
|
|||||||
+51
-28
@@ -25,10 +25,13 @@ import org.jetbrains.kotlin.utils.addToStdlib.singletonList
|
|||||||
* This lowering pass lowers all [IrCallableReference]s to unbound ones.
|
* This lowering pass lowers all [IrCallableReference]s to unbound ones.
|
||||||
*/
|
*/
|
||||||
internal class CallableReferenceLowering(val context: KonanBackendContext) : DeclarationContainerLoweringPass {
|
internal class CallableReferenceLowering(val context: KonanBackendContext) : DeclarationContainerLoweringPass {
|
||||||
|
|
||||||
|
var callableReferenceCount = 0
|
||||||
|
|
||||||
override fun lower(irDeclarationContainer: IrDeclarationContainer) {
|
override fun lower(irDeclarationContainer: IrDeclarationContainer) {
|
||||||
irDeclarationContainer.declarations.transformFlat { memberDeclaration ->
|
irDeclarationContainer.declarations.transformFlat { memberDeclaration ->
|
||||||
if (memberDeclaration is IrFunction)
|
if (memberDeclaration is IrFunction)
|
||||||
lowerCallableReferences(context, memberDeclaration)
|
lowerCallableReferences(this, memberDeclaration)
|
||||||
else
|
else
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
@@ -39,31 +42,43 @@ internal class CallableReferenceLowering(val context: KonanBackendContext) : Dec
|
|||||||
* Replaces all callable references in the function body to unbound ones.
|
* Replaces all callable references in the function body to unbound ones.
|
||||||
* Returns the list of this function and all created ones.
|
* Returns the list of this function and all created ones.
|
||||||
*/
|
*/
|
||||||
private fun lowerCallableReferences(context: KonanBackendContext, function: IrFunction): List<IrFunction> {
|
private fun lowerCallableReferences(lower: CallableReferenceLowering, function: IrFunction): List<IrFunction> {
|
||||||
val transformer = CallableReferencesUnbinder(context, function)
|
val transformer = CallableReferencesUnbinder(lower, function)
|
||||||
function.transformChildrenVoid(transformer)
|
function.transformChildrenVoid(transformer)
|
||||||
return function.singletonList() + transformer.createdFunctions
|
return function.singletonList() + 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.
|
* Replaces all callable references in the function body to unbound ones.
|
||||||
* Adds all created functions to [createdFunctions].
|
* Adds all created functions to [createdFunctions].
|
||||||
*/
|
*/
|
||||||
private class CallableReferencesUnbinder(val context: KonanBackendContext,
|
private class CallableReferencesUnbinder(val lower: CallableReferenceLowering,
|
||||||
val function: IrFunction) : IrElementTransformerVoid() {
|
val function: IrFunction) : IrElementTransformerVoid() {
|
||||||
|
|
||||||
val createdFunctions = mutableListOf<IrFunction>()
|
val createdFunctions = mutableListOf<IrFunction>()
|
||||||
|
|
||||||
|
private val builtIns = lower.context.builtIns
|
||||||
|
|
||||||
override fun visitElement(element: IrElement): IrElement {
|
override fun visitElement(element: IrElement): IrElement {
|
||||||
return super.visitElement(element)
|
return super.visitElement(element)
|
||||||
}
|
}
|
||||||
|
|
||||||
private val unboundCallableReferenceType by lazy {
|
private val unboundCallableReferenceType by lazy {
|
||||||
context.builtIns.getKonanInternalClass("UnboundCallableReference").defaultType
|
builtIns.getKonanInternalClass("UnboundCallableReference").defaultType
|
||||||
}
|
}
|
||||||
|
|
||||||
private val simpleFunctionImplClass by lazy {
|
private val simpleFunctionImplClass by lazy {
|
||||||
context.builtIns.getKonanInternalClass("SimpleFunctionImpl")
|
builtIns.getKonanInternalClass("SimpleFunctionImpl")
|
||||||
|
}
|
||||||
|
|
||||||
|
private val simpleFunctionImplBoundArgsGetter by lazy {
|
||||||
|
simpleFunctionImplClass.defaultType.memberScope.getContributedDescriptors()
|
||||||
|
.filterIsInstance<PropertyDescriptor>()
|
||||||
|
.single { it.name.asString() == "boundArgs" }
|
||||||
|
.getter!!
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitCallableReference(expression: IrCallableReference): IrExpression {
|
override fun visitCallableReference(expression: IrCallableReference): IrExpression {
|
||||||
@@ -77,8 +92,8 @@ private class CallableReferencesUnbinder(val context: KonanBackendContext,
|
|||||||
val startOffset = expression.startOffset
|
val startOffset = expression.startOffset
|
||||||
val endOffset = expression.endOffset
|
val endOffset = expression.endOffset
|
||||||
|
|
||||||
// The code below creates a call to `SimpleFunctionImpl` constructor which creates the value to be used
|
// The code below creates a call to `SimpleFunctionImpl` constructor which creates the object implementing
|
||||||
// as required callable reference.
|
// the function type.
|
||||||
|
|
||||||
// Create the function to be used as `unboundRef` of `SimpleFunctionImpl`:
|
// Create the function to be used as `unboundRef` of `SimpleFunctionImpl`:
|
||||||
val newFunction = createSimpleFunctionImplTarget(descriptor, unboundParams, boundParams, startOffset, endOffset)
|
val newFunction = createSimpleFunctionImplTarget(descriptor, unboundParams, boundParams, startOffset, endOffset)
|
||||||
@@ -119,20 +134,13 @@ private class CallableReferencesUnbinder(val context: KonanBackendContext,
|
|||||||
|
|
||||||
// Create new function declaration:
|
// Create new function declaration:
|
||||||
|
|
||||||
val origin = object : IrDeclarationOriginImpl("FUNCTION_FOR_CALLABLE_REFERENCE") {}
|
|
||||||
|
|
||||||
val simpleFunctionImplBoundArgsGetter =
|
|
||||||
simpleFunctionImplClass.defaultType.memberScope.getContributedDescriptors()
|
|
||||||
.filterIsInstance<PropertyDescriptor>().filter { it.name.asString() == "boundArgs" }
|
|
||||||
.single().getter!!
|
|
||||||
|
|
||||||
val boundArgsArray = IrCallImpl(startOffset, endOffset, simpleFunctionImplBoundArgsGetter, null).apply {
|
val boundArgsArray = IrCallImpl(startOffset, endOffset, simpleFunctionImplBoundArgsGetter, null).apply {
|
||||||
dispatchReceiver = IrGetValueImpl(startOffset, endOffset, newDescriptor.valueParameters[0])
|
dispatchReceiver = IrGetValueImpl(startOffset, endOffset, newDescriptor.valueParameters[0])
|
||||||
}
|
}
|
||||||
// TODO: do not call boundArgs getter for each bound argument.
|
// TODO: do not call boundArgs getter for each bound argument.
|
||||||
|
|
||||||
val arrayGet = boundArgsArray.type.memberScope.getContributedDescriptors()
|
val arrayGet = boundArgsArray.type.memberScope.getContributedDescriptors()
|
||||||
.filterIsInstance<FunctionDescriptor>().filter { it.name.asString() == "get" }.single()
|
.filterIsInstance<FunctionDescriptor>().single { it.name.asString() == "get" }
|
||||||
|
|
||||||
// TODO: some handling for type parameters is probably required here.
|
// TODO: some handling for type parameters is probably required here.
|
||||||
|
|
||||||
@@ -150,14 +158,14 @@ private class CallableReferencesUnbinder(val context: KonanBackendContext,
|
|||||||
call.addArguments(boundParams.mapIndexed { index, param ->
|
call.addArguments(boundParams.mapIndexed { index, param ->
|
||||||
param to IrCallImpl(startOffset, endOffset, arrayGet).apply {
|
param to IrCallImpl(startOffset, endOffset, arrayGet).apply {
|
||||||
dispatchReceiver = boundArgsArray
|
dispatchReceiver = boundArgsArray
|
||||||
putValueArgument(0, IrConstImpl.int(startOffset, endOffset, context.builtIns.intType, index))
|
putValueArgument(0, IrConstImpl.int(startOffset, endOffset, builtIns.intType, index))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
val ret = IrReturnImpl(startOffset, endOffset, newDescriptor, call)
|
val ret = IrReturnImpl(startOffset, endOffset, newDescriptor, call)
|
||||||
|
|
||||||
val newFunction = IrFunctionImpl(
|
val newFunction = IrFunctionImpl(
|
||||||
startOffset, endOffset, origin,
|
startOffset, endOffset, DECLARATION_ORIGIN_FUNCTION_FOR_CALLABLE_REFERENCE,
|
||||||
newDescriptor,
|
newDescriptor,
|
||||||
IrBlockBodyImpl(startOffset, endOffset, listOf(ret))
|
IrBlockBodyImpl(startOffset, endOffset, listOf(ret))
|
||||||
)
|
)
|
||||||
@@ -171,7 +179,7 @@ private class CallableReferencesUnbinder(val context: KonanBackendContext,
|
|||||||
private fun createSimpleFunctionImplTargetDescriptor(descriptor: CallableDescriptor,
|
private fun createSimpleFunctionImplTargetDescriptor(descriptor: CallableDescriptor,
|
||||||
unboundParams: List<ParameterDescriptor>): FunctionDescriptor {
|
unboundParams: List<ParameterDescriptor>): FunctionDescriptor {
|
||||||
|
|
||||||
val newName = Name.identifier(descriptor.hashCode().toString()) // FIXME
|
val newName = Name.identifier("${descriptor.name}\$bound-${lower.callableReferenceCount++}")
|
||||||
|
|
||||||
val newDescriptor = SimpleFunctionDescriptorImpl.create(
|
val newDescriptor = SimpleFunctionDescriptorImpl.create(
|
||||||
function.descriptor.containingDeclaration, Annotations.EMPTY,
|
function.descriptor.containingDeclaration, Annotations.EMPTY,
|
||||||
@@ -179,19 +187,34 @@ private class CallableReferencesUnbinder(val context: KonanBackendContext,
|
|||||||
|
|
||||||
val simpleFunctionImplType = simpleFunctionImplClass.defaultType
|
val simpleFunctionImplType = simpleFunctionImplClass.defaultType
|
||||||
|
|
||||||
// Maps each unbound param of original function to parameter of new function
|
// Map each unbound param of original function to parameter of new function.
|
||||||
val newUnboundParams = unboundParams.mapIndexed { index, param ->
|
val newUnboundParams = unboundParams.mapIndexed { index, param ->
|
||||||
ValueParameterDescriptorImpl(newDescriptor, null, index + 1,
|
ValueParameterDescriptorImpl(
|
||||||
Annotations.EMPTY, param.name, param.type,
|
containingDeclaration = newDescriptor,
|
||||||
false, false, false, false,
|
original = null,
|
||||||
(param as? ValueParameterDescriptor)?.varargElementType,
|
index = index + 1,
|
||||||
SourceElement.NO_SOURCE)
|
annotations = Annotations.EMPTY,
|
||||||
|
name = param.name,
|
||||||
|
outType = param.type,
|
||||||
|
declaresDefaultValue = false,
|
||||||
|
isCrossinline = false, isNoinline = false,
|
||||||
|
isCoroutine = false,
|
||||||
|
varargElementType = (param as? ValueParameterDescriptor)?.varargElementType,
|
||||||
|
source = SourceElement.NO_SOURCE)
|
||||||
}
|
}
|
||||||
|
|
||||||
// `<func>: SimpleFunctionImpl`
|
// `<func>: SimpleFunctionImpl`
|
||||||
val functionParameter = ValueParameterDescriptorImpl(newDescriptor, null, 0, Annotations.EMPTY,
|
val functionParameter = ValueParameterDescriptorImpl(
|
||||||
Name.special("<func>"),
|
containingDeclaration = newDescriptor,
|
||||||
simpleFunctionImplType, false, false, false, false, null, SourceElement.NO_SOURCE)
|
original = null,
|
||||||
|
index = 0,
|
||||||
|
annotations = Annotations.EMPTY,
|
||||||
|
name = Name.special("<func>"),
|
||||||
|
outType = simpleFunctionImplType,
|
||||||
|
declaresDefaultValue = false,
|
||||||
|
isCrossinline = false, isNoinline = false,
|
||||||
|
isCoroutine = false, varargElementType = null,
|
||||||
|
source = SourceElement.NO_SOURCE)
|
||||||
|
|
||||||
val newValueParameters = listOf(functionParameter) + newUnboundParams
|
val newValueParameters = listOf(functionParameter) + newUnboundParams
|
||||||
|
|
||||||
|
|||||||
@@ -185,7 +185,7 @@ KConstRef Kotlin_getCurrentStackTrace() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: consider handling it with compiler magic instead.
|
// TODO: consider handling it with compiler magic instead.
|
||||||
KRef Kotlin_internal_undefined() {
|
KRef Kotlin_konan_internal_undefined() {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ KString Kotlin_String_subSequence(KString thiz, KInt startIndex, KInt endIndex);
|
|||||||
|
|
||||||
KConstRef Kotlin_getCurrentStackTrace();
|
KConstRef Kotlin_getCurrentStackTrace();
|
||||||
|
|
||||||
KRef Kotlin_internal_undefined();
|
KRef Kotlin_konan_internal_undefined();
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,5 +4,5 @@ package konan.internal
|
|||||||
* Returns undefined value of type `T`.
|
* Returns undefined value of type `T`.
|
||||||
* This method is unsafe and should be used with care.
|
* This method is unsafe and should be used with care.
|
||||||
*/
|
*/
|
||||||
@SymbolName("Kotlin_internal_undefined")
|
@SymbolName("Kotlin_konan_internal_undefined")
|
||||||
internal external fun <T> undefined(): T
|
internal external fun <T> undefined(): T
|
||||||
Reference in New Issue
Block a user