Optimize visibility for controller field in CoroutineImpl
While it's impossible to declare a property with protected field and public getter we split these entities - `_controller` field is used inside coroutines - `controller` getter is used for accesing controller from noinline lambdas (also it can be used to obtain controller from continuation by explicit cast)
This commit is contained in:
@@ -3044,18 +3044,41 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
|||||||
ClassDescriptor classDescriptor = bindingContext.get(CodegenBinding.CLASS_FOR_CALLABLE, descriptor);
|
ClassDescriptor classDescriptor = bindingContext.get(CodegenBinding.CLASS_FOR_CALLABLE, descriptor);
|
||||||
assert classDescriptor != null : "class descriptor for coroutine " + descriptor + " should not be null";
|
assert classDescriptor != null : "class descriptor for coroutine " + descriptor + " should not be null";
|
||||||
|
|
||||||
StackValue coroutineReceiver = StackValue.thisOrOuter(this, classDescriptor, /* isSuper =*/ false, /* castReceiver */ false);
|
final StackValue coroutineReceiver = StackValue.thisOrOuter(this, classDescriptor, /* isSuper =*/ false, /* castReceiver */ false);
|
||||||
return StackValue.coercion(
|
|
||||||
StackValue.field(
|
StackValue controllerValue;
|
||||||
|
if (InlineUtil.checkNonLocalReturnUsage(
|
||||||
|
context.getFunctionDescriptor(),
|
||||||
|
descriptor, DescriptorToSourceUtils.descriptorToDeclaration(descriptor), bindingContext
|
||||||
|
)) {
|
||||||
|
// This branch should work for major part of cases and it's needed mostly for optimizations purpose
|
||||||
|
// else branch must have just the same semantics
|
||||||
|
controllerValue = StackValue.field(
|
||||||
FieldInfo.createForHiddenField(
|
FieldInfo.createForHiddenField(
|
||||||
AsmTypes.COROUTINE_IMPL,
|
AsmTypes.COROUTINE_IMPL,
|
||||||
AsmTypes.OBJECT_TYPE,
|
AsmTypes.OBJECT_TYPE,
|
||||||
CoroutineCodegenUtilKt.COROUTINE_CONTROLLER_FIELD_NAME
|
CoroutineCodegenUtilKt.COROUTINE_CONTROLLER_FIELD_NAME
|
||||||
),
|
),
|
||||||
coroutineReceiver
|
coroutineReceiver
|
||||||
),
|
);
|
||||||
typeMapper.mapType(coroutineControllerType)
|
}
|
||||||
);
|
else {
|
||||||
|
controllerValue = StackValue.functionCall(AsmTypes.OBJECT_TYPE, new Function1<InstructionAdapter, Unit>() {
|
||||||
|
@Override
|
||||||
|
public Unit invoke(InstructionAdapter adapter) {
|
||||||
|
coroutineReceiver.put(AsmTypes.COROUTINE_IMPL, adapter);
|
||||||
|
adapter.invokevirtual(
|
||||||
|
AsmTypes.COROUTINE_IMPL.getInternalName(),
|
||||||
|
CoroutineCodegenUtilKt.COROUTINE_CONTROLLER_GETTER_NAME,
|
||||||
|
"()" + AsmTypes.OBJECT_TYPE,
|
||||||
|
false
|
||||||
|
);
|
||||||
|
return Unit.INSTANCE;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return StackValue.coercion(controllerValue, typeMapper.mapType(coroutineControllerType));
|
||||||
}
|
}
|
||||||
|
|
||||||
return context.generateReceiver(descriptor, state, false);
|
return context.generateReceiver(descriptor, state, false);
|
||||||
|
|||||||
+2
-1
@@ -47,7 +47,8 @@ const val AFTER_SUSPENSION_POINT_MARKER_NAME = "afterSuspensionPoint"
|
|||||||
const val HANDLE_EXCEPTION_MARKER_NAME = "handleException"
|
const val HANDLE_EXCEPTION_MARKER_NAME = "handleException"
|
||||||
const val HANDLE_EXCEPTION_ARGUMENT_MARKER_NAME = "handleExceptionArgument"
|
const val HANDLE_EXCEPTION_ARGUMENT_MARKER_NAME = "handleExceptionArgument"
|
||||||
|
|
||||||
const val COROUTINE_CONTROLLER_FIELD_NAME = "controller"
|
const val COROUTINE_CONTROLLER_FIELD_NAME = "_controller"
|
||||||
|
const val COROUTINE_CONTROLLER_GETTER_NAME = "getController"
|
||||||
const val COROUTINE_LABEL_FIELD_NAME = "label"
|
const val COROUTINE_LABEL_FIELD_NAME = "label"
|
||||||
|
|
||||||
data class ResolvedCallWithRealDescriptor(val resolvedCall: ResolvedCall<*>, val fakeThisExpression: KtExpression)
|
data class ResolvedCallWithRealDescriptor(val resolvedCall: ResolvedCall<*>, val fakeThisExpression: KtExpression)
|
||||||
|
|||||||
@@ -87,12 +87,19 @@ public class InlineUtil {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
DeclarationDescriptor containingFunctionDescriptor = context.trace.get(BindingContext.DECLARATION_TO_DESCRIPTOR, containingFunction);
|
return checkNonLocalReturnUsage(
|
||||||
if (containingFunctionDescriptor == null) {
|
fromFunction, context.trace.get(BindingContext.DECLARATION_TO_DESCRIPTOR, containingFunction), containingFunction,
|
||||||
return false;
|
context.trace.getBindingContext()
|
||||||
}
|
);
|
||||||
|
}
|
||||||
|
|
||||||
BindingContext bindingContext = context.trace.getBindingContext();
|
public static boolean checkNonLocalReturnUsage(
|
||||||
|
@NotNull DeclarationDescriptor fromFunction,
|
||||||
|
@Nullable DeclarationDescriptor containingFunctionDescriptor,
|
||||||
|
@Nullable PsiElement containingFunction,
|
||||||
|
@NotNull BindingContext bindingContext
|
||||||
|
) {
|
||||||
|
if (containingFunctionDescriptor == null) return false;
|
||||||
|
|
||||||
while (canBeInlineArgument(containingFunction) && fromFunction != containingFunctionDescriptor) {
|
while (canBeInlineArgument(containingFunction) && fromFunction != containingFunctionDescriptor) {
|
||||||
if (!isInlinedArgument((KtFunction) containingFunction, bindingContext, true)) {
|
if (!isInlinedArgument((KtFunction) containingFunction, bindingContext, true)) {
|
||||||
|
|||||||
@@ -17,10 +17,12 @@
|
|||||||
package kotlin.jvm.internal
|
package kotlin.jvm.internal
|
||||||
|
|
||||||
abstract class CoroutineImpl(arity: Int) : Lambda(arity), Continuation<Any?> {
|
abstract class CoroutineImpl(arity: Int) : Lambda(arity), Continuation<Any?> {
|
||||||
|
@JvmField
|
||||||
|
protected var _controller: Any? = null
|
||||||
|
|
||||||
// It's not protected because can be used from noinline lambdas inside coroutine (when calling non-suspend functions)
|
// It's not protected because can be used from noinline lambdas inside coroutine (when calling non-suspend functions)
|
||||||
// Also there might be needed a way to access a controller by Continuation instance when it's inherited from CoroutineImpl
|
// Also there might be needed a way to access a controller by Continuation instance when it's inherited from CoroutineImpl
|
||||||
@JvmField
|
val controller: Any? get() = _controller
|
||||||
var controller: Any? = null
|
|
||||||
|
|
||||||
// Any label state less then zero indicates that coroutine is not run and can't be resumed in any way.
|
// Any label state less then zero indicates that coroutine is not run and can't be resumed in any way.
|
||||||
// Specific values do not matter by now, but currently -2 used for uninitialized coroutine (no controller is assigned),
|
// Specific values do not matter by now, but currently -2 used for uninitialized coroutine (no controller is assigned),
|
||||||
|
|||||||
Reference in New Issue
Block a user