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);
|
||||
assert classDescriptor != null : "class descriptor for coroutine " + descriptor + " should not be null";
|
||||
|
||||
StackValue coroutineReceiver = StackValue.thisOrOuter(this, classDescriptor, /* isSuper =*/ false, /* castReceiver */ false);
|
||||
return StackValue.coercion(
|
||||
StackValue.field(
|
||||
final StackValue coroutineReceiver = StackValue.thisOrOuter(this, classDescriptor, /* isSuper =*/ false, /* castReceiver */ false);
|
||||
|
||||
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(
|
||||
AsmTypes.COROUTINE_IMPL,
|
||||
AsmTypes.OBJECT_TYPE,
|
||||
CoroutineCodegenUtilKt.COROUTINE_CONTROLLER_FIELD_NAME
|
||||
),
|
||||
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);
|
||||
|
||||
+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_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"
|
||||
|
||||
data class ResolvedCallWithRealDescriptor(val resolvedCall: ResolvedCall<*>, val fakeThisExpression: KtExpression)
|
||||
|
||||
@@ -87,12 +87,19 @@ public class InlineUtil {
|
||||
return false;
|
||||
}
|
||||
|
||||
DeclarationDescriptor containingFunctionDescriptor = context.trace.get(BindingContext.DECLARATION_TO_DESCRIPTOR, containingFunction);
|
||||
if (containingFunctionDescriptor == null) {
|
||||
return false;
|
||||
}
|
||||
return checkNonLocalReturnUsage(
|
||||
fromFunction, context.trace.get(BindingContext.DECLARATION_TO_DESCRIPTOR, containingFunction), containingFunction,
|
||||
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) {
|
||||
if (!isInlinedArgument((KtFunction) containingFunction, bindingContext, true)) {
|
||||
|
||||
@@ -17,10 +17,12 @@
|
||||
package kotlin.jvm.internal
|
||||
|
||||
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)
|
||||
// Also there might be needed a way to access a controller by Continuation instance when it's inherited from CoroutineImpl
|
||||
@JvmField
|
||||
var controller: Any? = null
|
||||
val controller: Any? get() = _controller
|
||||
|
||||
// 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),
|
||||
|
||||
Reference in New Issue
Block a user