|  | @@ -117,9 +117,19 @@ class CallbackUnaryHandler : public ::grpc::internal::MethodHandler {
 | 
	
		
			
				|  |  |    class ServerCallbackUnaryImpl : public ServerCallbackUnary {
 | 
	
		
			
				|  |  |     public:
 | 
	
		
			
				|  |  |      void Finish(::grpc::Status s) override {
 | 
	
		
			
				|  |  | +      // A callback that only contains a call to MaybeDone can be run as an
 | 
	
		
			
				|  |  | +      // inline callback regardless of whether or not OnDone is inlineable
 | 
	
		
			
				|  |  | +      // because if the actual OnDone callback needs to be scheduled, MaybeDone
 | 
	
		
			
				|  |  | +      // is responsible for dispatching to an executor thread if needed. Thus,
 | 
	
		
			
				|  |  | +      // when setting up the finish_tag_, we can set its own callback to
 | 
	
		
			
				|  |  | +      // inlineable.
 | 
	
		
			
				|  |  |        finish_tag_.Set(
 | 
	
		
			
				|  |  | -          call_.call(), [this](bool) { MaybeDone(); }, &finish_ops_,
 | 
	
		
			
				|  |  | -          reactor_.load(std::memory_order_relaxed)->InternalInlineable());
 | 
	
		
			
				|  |  | +          call_.call(),
 | 
	
		
			
				|  |  | +          [this](bool) {
 | 
	
		
			
				|  |  | +            this->MaybeDone(
 | 
	
		
			
				|  |  | +                reactor_.load(std::memory_order_relaxed)->InternalInlineable());
 | 
	
		
			
				|  |  | +          },
 | 
	
		
			
				|  |  | +          &finish_ops_, /*can_inline=*/true);
 | 
	
		
			
				|  |  |        finish_ops_.set_core_cq_tag(&finish_tag_);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |        if (!ctx_->sent_initial_metadata_) {
 | 
	
	
		
			
				|  | @@ -144,13 +154,19 @@ class CallbackUnaryHandler : public ::grpc::internal::MethodHandler {
 | 
	
		
			
				|  |  |      void SendInitialMetadata() override {
 | 
	
		
			
				|  |  |        GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_);
 | 
	
		
			
				|  |  |        this->Ref();
 | 
	
		
			
				|  |  | +      // The callback for this function should not be marked inline because it
 | 
	
		
			
				|  |  | +      // is directly invoking a user-controlled reaction
 | 
	
		
			
				|  |  | +      // (OnSendInitialMetadataDone). Thus it must be dispatched to an executor
 | 
	
		
			
				|  |  | +      // thread. However, any OnDone needed after that can be inlined because it
 | 
	
		
			
				|  |  | +      // is already running on an executor thread.
 | 
	
		
			
				|  |  |        meta_tag_.Set(call_.call(),
 | 
	
		
			
				|  |  |                      [this](bool ok) {
 | 
	
		
			
				|  |  | -                      reactor_.load(std::memory_order_relaxed)
 | 
	
		
			
				|  |  | -                          ->OnSendInitialMetadataDone(ok);
 | 
	
		
			
				|  |  | -                      MaybeDone();
 | 
	
		
			
				|  |  | +                      ServerUnaryReactor* reactor =
 | 
	
		
			
				|  |  | +                          reactor_.load(std::memory_order_relaxed);
 | 
	
		
			
				|  |  | +                      reactor->OnSendInitialMetadataDone(ok);
 | 
	
		
			
				|  |  | +                      this->MaybeDone(/*inlineable_ondone=*/true);
 | 
	
		
			
				|  |  |                      },
 | 
	
		
			
				|  |  | -                    &meta_ops_, false);
 | 
	
		
			
				|  |  | +                    &meta_ops_, /*can_inline=*/false);
 | 
	
		
			
				|  |  |        meta_ops_.SendInitialMetadata(&ctx_->initial_metadata_,
 | 
	
		
			
				|  |  |                                      ctx_->initial_metadata_flags());
 | 
	
		
			
				|  |  |        if (ctx_->compression_level_set()) {
 | 
	
	
		
			
				|  | @@ -184,22 +200,20 @@ class CallbackUnaryHandler : public ::grpc::internal::MethodHandler {
 | 
	
		
			
				|  |  |        reactor_.store(reactor, std::memory_order_relaxed);
 | 
	
		
			
				|  |  |        this->BindReactor(reactor);
 | 
	
		
			
				|  |  |        this->MaybeCallOnCancel(reactor);
 | 
	
		
			
				|  |  | -      this->MaybeDone();
 | 
	
		
			
				|  |  | +      this->MaybeDone(reactor->InternalInlineable());
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      const RequestType* request() { return allocator_state_->request(); }
 | 
	
		
			
				|  |  |      ResponseType* response() { return allocator_state_->response(); }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    void MaybeDone() override {
 | 
	
		
			
				|  |  | -      if (GPR_UNLIKELY(this->Unref() == 1)) {
 | 
	
		
			
				|  |  | -        reactor_.load(std::memory_order_relaxed)->OnDone();
 | 
	
		
			
				|  |  | -        grpc_call* call = call_.call();
 | 
	
		
			
				|  |  | -        auto call_requester = std::move(call_requester_);
 | 
	
		
			
				|  |  | -        allocator_state_->Release();
 | 
	
		
			
				|  |  | -        this->~ServerCallbackUnaryImpl();  // explicitly call destructor
 | 
	
		
			
				|  |  | -        ::grpc::g_core_codegen_interface->grpc_call_unref(call);
 | 
	
		
			
				|  |  | -        call_requester();
 | 
	
		
			
				|  |  | -      }
 | 
	
		
			
				|  |  | +    void CallOnDone() override {
 | 
	
		
			
				|  |  | +      reactor_.load(std::memory_order_relaxed)->OnDone();
 | 
	
		
			
				|  |  | +      grpc_call* call = call_.call();
 | 
	
		
			
				|  |  | +      auto call_requester = std::move(call_requester_);
 | 
	
		
			
				|  |  | +      allocator_state_->Release();
 | 
	
		
			
				|  |  | +      this->~ServerCallbackUnaryImpl();  // explicitly call destructor
 | 
	
		
			
				|  |  | +      ::grpc::g_core_codegen_interface->grpc_call_unref(call);
 | 
	
		
			
				|  |  | +      call_requester();
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      ServerReactor* reactor() override {
 | 
	
	
		
			
				|  | @@ -255,8 +269,13 @@ class CallbackClientStreamingHandler : public ::grpc::internal::MethodHandler {
 | 
	
		
			
				|  |  |              static_cast<::grpc_impl::CallbackServerContext*>(
 | 
	
		
			
				|  |  |                  param.server_context),
 | 
	
		
			
				|  |  |              param.call, std::move(param.call_requester));
 | 
	
		
			
				|  |  | +    // Inlineable OnDone can be false in the CompletionOp callback because there
 | 
	
		
			
				|  |  | +    // is no read reactor that has an inlineable OnDone; this only applies to
 | 
	
		
			
				|  |  | +    // the DefaultReactor (which is unary).
 | 
	
		
			
				|  |  |      param.server_context->BeginCompletionOp(
 | 
	
		
			
				|  |  | -        param.call, [reader](bool) { reader->MaybeDone(); }, reader);
 | 
	
		
			
				|  |  | +        param.call,
 | 
	
		
			
				|  |  | +        [reader](bool) { reader->MaybeDone(/*inlineable_ondone=*/false); },
 | 
	
		
			
				|  |  | +        reader);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      ServerReadReactor<RequestType>* reactor = nullptr;
 | 
	
		
			
				|  |  |      if (param.status.ok()) {
 | 
	
	
		
			
				|  | @@ -287,8 +306,17 @@ class CallbackClientStreamingHandler : public ::grpc::internal::MethodHandler {
 | 
	
		
			
				|  |  |    class ServerCallbackReaderImpl : public ServerCallbackReader<RequestType> {
 | 
	
		
			
				|  |  |     public:
 | 
	
		
			
				|  |  |      void Finish(::grpc::Status s) override {
 | 
	
		
			
				|  |  | -      finish_tag_.Set(call_.call(), [this](bool) { MaybeDone(); }, &finish_ops_,
 | 
	
		
			
				|  |  | -                      false);
 | 
	
		
			
				|  |  | +      // A finish tag with only MaybeDone can have its callback inlined
 | 
	
		
			
				|  |  | +      // regardless even if OnDone is not inlineable because this callback just
 | 
	
		
			
				|  |  | +      // checks a ref and then decides whether or not to dispatch OnDone.
 | 
	
		
			
				|  |  | +      finish_tag_.Set(call_.call(),
 | 
	
		
			
				|  |  | +                      [this](bool) {
 | 
	
		
			
				|  |  | +                        // Inlineable OnDone can be false here because there is
 | 
	
		
			
				|  |  | +                        // no read reactor that has an inlineable OnDone; this
 | 
	
		
			
				|  |  | +                        // only applies to the DefaultReactor (which is unary).
 | 
	
		
			
				|  |  | +                        this->MaybeDone(/*inlineable_ondone=*/false);
 | 
	
		
			
				|  |  | +                      },
 | 
	
		
			
				|  |  | +                      &finish_ops_, /*can_inline=*/true);
 | 
	
		
			
				|  |  |        if (!ctx_->sent_initial_metadata_) {
 | 
	
		
			
				|  |  |          finish_ops_.SendInitialMetadata(&ctx_->initial_metadata_,
 | 
	
		
			
				|  |  |                                          ctx_->initial_metadata_flags());
 | 
	
	
		
			
				|  | @@ -311,13 +339,17 @@ class CallbackClientStreamingHandler : public ::grpc::internal::MethodHandler {
 | 
	
		
			
				|  |  |      void SendInitialMetadata() override {
 | 
	
		
			
				|  |  |        GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_);
 | 
	
		
			
				|  |  |        this->Ref();
 | 
	
		
			
				|  |  | +      // The callback for this function should not be inlined because it invokes
 | 
	
		
			
				|  |  | +      // a user-controlled reaction, but any resulting OnDone can be inlined in
 | 
	
		
			
				|  |  | +      // the executor to which this callback is dispatched.
 | 
	
		
			
				|  |  |        meta_tag_.Set(call_.call(),
 | 
	
		
			
				|  |  |                      [this](bool ok) {
 | 
	
		
			
				|  |  | -                      reactor_.load(std::memory_order_relaxed)
 | 
	
		
			
				|  |  | -                          ->OnSendInitialMetadataDone(ok);
 | 
	
		
			
				|  |  | -                      MaybeDone();
 | 
	
		
			
				|  |  | +                      ServerReadReactor<RequestType>* reactor =
 | 
	
		
			
				|  |  | +                          reactor_.load(std::memory_order_relaxed);
 | 
	
		
			
				|  |  | +                      reactor->OnSendInitialMetadataDone(ok);
 | 
	
		
			
				|  |  | +                      this->MaybeDone(/*inlineable_ondone=*/true);
 | 
	
		
			
				|  |  |                      },
 | 
	
		
			
				|  |  | -                    &meta_ops_, false);
 | 
	
		
			
				|  |  | +                    &meta_ops_, /*can_inline=*/false);
 | 
	
		
			
				|  |  |        meta_ops_.SendInitialMetadata(&ctx_->initial_metadata_,
 | 
	
		
			
				|  |  |                                      ctx_->initial_metadata_flags());
 | 
	
		
			
				|  |  |        if (ctx_->compression_level_set()) {
 | 
	
	
		
			
				|  | @@ -344,31 +376,35 @@ class CallbackClientStreamingHandler : public ::grpc::internal::MethodHandler {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      void SetupReactor(ServerReadReactor<RequestType>* reactor) {
 | 
	
		
			
				|  |  |        reactor_.store(reactor, std::memory_order_relaxed);
 | 
	
		
			
				|  |  | +      // The callback for this function should not be inlined because it invokes
 | 
	
		
			
				|  |  | +      // a user-controlled reaction, but any resulting OnDone can be inlined in
 | 
	
		
			
				|  |  | +      // the executor to which this callback is dispatched.
 | 
	
		
			
				|  |  |        read_tag_.Set(call_.call(),
 | 
	
		
			
				|  |  | -                    [this](bool ok) {
 | 
	
		
			
				|  |  | -                      reactor_.load(std::memory_order_relaxed)->OnReadDone(ok);
 | 
	
		
			
				|  |  | -                      MaybeDone();
 | 
	
		
			
				|  |  | +                    [this, reactor](bool ok) {
 | 
	
		
			
				|  |  | +                      reactor->OnReadDone(ok);
 | 
	
		
			
				|  |  | +                      this->MaybeDone(/*inlineable_ondone=*/true);
 | 
	
		
			
				|  |  |                      },
 | 
	
		
			
				|  |  | -                    &read_ops_, false);
 | 
	
		
			
				|  |  | +                    &read_ops_, /*can_inline=*/false);
 | 
	
		
			
				|  |  |        read_ops_.set_core_cq_tag(&read_tag_);
 | 
	
		
			
				|  |  |        this->BindReactor(reactor);
 | 
	
		
			
				|  |  |        this->MaybeCallOnCancel(reactor);
 | 
	
		
			
				|  |  | -      this->MaybeDone();
 | 
	
		
			
				|  |  | +      // Inlineable OnDone can be false here because there is no read
 | 
	
		
			
				|  |  | +      // reactor that has an inlineable OnDone; this only applies to the
 | 
	
		
			
				|  |  | +      // DefaultReactor (which is unary).
 | 
	
		
			
				|  |  | +      this->MaybeDone(/*inlineable_ondone=*/false);
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      ~ServerCallbackReaderImpl() {}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      ResponseType* response() { return &resp_; }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    void MaybeDone() override {
 | 
	
		
			
				|  |  | -      if (GPR_UNLIKELY(this->Unref() == 1)) {
 | 
	
		
			
				|  |  | -        reactor_.load(std::memory_order_relaxed)->OnDone();
 | 
	
		
			
				|  |  | -        grpc_call* call = call_.call();
 | 
	
		
			
				|  |  | -        auto call_requester = std::move(call_requester_);
 | 
	
		
			
				|  |  | -        this->~ServerCallbackReaderImpl();  // explicitly call destructor
 | 
	
		
			
				|  |  | -        ::grpc::g_core_codegen_interface->grpc_call_unref(call);
 | 
	
		
			
				|  |  | -        call_requester();
 | 
	
		
			
				|  |  | -      }
 | 
	
		
			
				|  |  | +    void CallOnDone() override {
 | 
	
		
			
				|  |  | +      reactor_.load(std::memory_order_relaxed)->OnDone();
 | 
	
		
			
				|  |  | +      grpc_call* call = call_.call();
 | 
	
		
			
				|  |  | +      auto call_requester = std::move(call_requester_);
 | 
	
		
			
				|  |  | +      this->~ServerCallbackReaderImpl();  // explicitly call destructor
 | 
	
		
			
				|  |  | +      ::grpc::g_core_codegen_interface->grpc_call_unref(call);
 | 
	
		
			
				|  |  | +      call_requester();
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      ServerReactor* reactor() override {
 | 
	
	
		
			
				|  | @@ -419,8 +455,13 @@ class CallbackServerStreamingHandler : public ::grpc::internal::MethodHandler {
 | 
	
		
			
				|  |  |                  param.server_context),
 | 
	
		
			
				|  |  |              param.call, static_cast<RequestType*>(param.request),
 | 
	
		
			
				|  |  |              std::move(param.call_requester));
 | 
	
		
			
				|  |  | +    // Inlineable OnDone can be false in the CompletionOp callback because there
 | 
	
		
			
				|  |  | +    // is no write reactor that has an inlineable OnDone; this only applies to
 | 
	
		
			
				|  |  | +    // the DefaultReactor (which is unary).
 | 
	
		
			
				|  |  |      param.server_context->BeginCompletionOp(
 | 
	
		
			
				|  |  | -        param.call, [writer](bool) { writer->MaybeDone(); }, writer);
 | 
	
		
			
				|  |  | +        param.call,
 | 
	
		
			
				|  |  | +        [writer](bool) { writer->MaybeDone(/*inlineable_ondone=*/false); },
 | 
	
		
			
				|  |  | +        writer);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      ServerWriteReactor<ResponseType>* reactor = nullptr;
 | 
	
		
			
				|  |  |      if (param.status.ok()) {
 | 
	
	
		
			
				|  | @@ -467,8 +508,17 @@ class CallbackServerStreamingHandler : public ::grpc::internal::MethodHandler {
 | 
	
		
			
				|  |  |    class ServerCallbackWriterImpl : public ServerCallbackWriter<ResponseType> {
 | 
	
		
			
				|  |  |     public:
 | 
	
		
			
				|  |  |      void Finish(::grpc::Status s) override {
 | 
	
		
			
				|  |  | -      finish_tag_.Set(call_.call(), [this](bool) { MaybeDone(); }, &finish_ops_,
 | 
	
		
			
				|  |  | -                      false);
 | 
	
		
			
				|  |  | +      // A finish tag with only MaybeDone can have its callback inlined
 | 
	
		
			
				|  |  | +      // regardless even if OnDone is not inlineable because this callback just
 | 
	
		
			
				|  |  | +      // checks a ref and then decides whether or not to dispatch OnDone.
 | 
	
		
			
				|  |  | +      finish_tag_.Set(call_.call(),
 | 
	
		
			
				|  |  | +                      [this](bool) {
 | 
	
		
			
				|  |  | +                        // Inlineable OnDone can be false here because there is
 | 
	
		
			
				|  |  | +                        // no write reactor that has an inlineable OnDone; this
 | 
	
		
			
				|  |  | +                        // only applies to the DefaultReactor (which is unary).
 | 
	
		
			
				|  |  | +                        this->MaybeDone(/*inlineable_ondone=*/false);
 | 
	
		
			
				|  |  | +                      },
 | 
	
		
			
				|  |  | +                      &finish_ops_, /*can_inline=*/true);
 | 
	
		
			
				|  |  |        finish_ops_.set_core_cq_tag(&finish_tag_);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |        if (!ctx_->sent_initial_metadata_) {
 | 
	
	
		
			
				|  | @@ -486,13 +536,17 @@ class CallbackServerStreamingHandler : public ::grpc::internal::MethodHandler {
 | 
	
		
			
				|  |  |      void SendInitialMetadata() override {
 | 
	
		
			
				|  |  |        GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_);
 | 
	
		
			
				|  |  |        this->Ref();
 | 
	
		
			
				|  |  | +      // The callback for this function should not be inlined because it invokes
 | 
	
		
			
				|  |  | +      // a user-controlled reaction, but any resulting OnDone can be inlined in
 | 
	
		
			
				|  |  | +      // the executor to which this callback is dispatched.
 | 
	
		
			
				|  |  |        meta_tag_.Set(call_.call(),
 | 
	
		
			
				|  |  |                      [this](bool ok) {
 | 
	
		
			
				|  |  | -                      reactor_.load(std::memory_order_relaxed)
 | 
	
		
			
				|  |  | -                          ->OnSendInitialMetadataDone(ok);
 | 
	
		
			
				|  |  | -                      MaybeDone();
 | 
	
		
			
				|  |  | +                      ServerWriteReactor<ResponseType>* reactor =
 | 
	
		
			
				|  |  | +                          reactor_.load(std::memory_order_relaxed);
 | 
	
		
			
				|  |  | +                      reactor->OnSendInitialMetadataDone(ok);
 | 
	
		
			
				|  |  | +                      this->MaybeDone(/*inlineable_ondone=*/true);
 | 
	
		
			
				|  |  |                      },
 | 
	
		
			
				|  |  | -                    &meta_ops_, false);
 | 
	
		
			
				|  |  | +                    &meta_ops_, /*can_inline=*/false);
 | 
	
		
			
				|  |  |        meta_ops_.SendInitialMetadata(&ctx_->initial_metadata_,
 | 
	
		
			
				|  |  |                                      ctx_->initial_metadata_flags());
 | 
	
		
			
				|  |  |        if (ctx_->compression_level_set()) {
 | 
	
	
		
			
				|  | @@ -547,31 +601,34 @@ class CallbackServerStreamingHandler : public ::grpc::internal::MethodHandler {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      void SetupReactor(ServerWriteReactor<ResponseType>* reactor) {
 | 
	
		
			
				|  |  |        reactor_.store(reactor, std::memory_order_relaxed);
 | 
	
		
			
				|  |  | -      write_tag_.Set(
 | 
	
		
			
				|  |  | -          call_.call(),
 | 
	
		
			
				|  |  | -          [this](bool ok) {
 | 
	
		
			
				|  |  | -            reactor_.load(std::memory_order_relaxed)->OnWriteDone(ok);
 | 
	
		
			
				|  |  | -            MaybeDone();
 | 
	
		
			
				|  |  | -          },
 | 
	
		
			
				|  |  | -          &write_ops_, false);
 | 
	
		
			
				|  |  | +      // The callback for this function should not be inlined because it invokes
 | 
	
		
			
				|  |  | +      // a user-controlled reaction, but any resulting OnDone can be inlined in
 | 
	
		
			
				|  |  | +      // the executor to which this callback is dispatched.
 | 
	
		
			
				|  |  | +      write_tag_.Set(call_.call(),
 | 
	
		
			
				|  |  | +                     [this, reactor](bool ok) {
 | 
	
		
			
				|  |  | +                       reactor->OnWriteDone(ok);
 | 
	
		
			
				|  |  | +                       this->MaybeDone(/*inlineable_ondone=*/true);
 | 
	
		
			
				|  |  | +                     },
 | 
	
		
			
				|  |  | +                     &write_ops_, /*can_inline=*/false);
 | 
	
		
			
				|  |  |        write_ops_.set_core_cq_tag(&write_tag_);
 | 
	
		
			
				|  |  |        this->BindReactor(reactor);
 | 
	
		
			
				|  |  |        this->MaybeCallOnCancel(reactor);
 | 
	
		
			
				|  |  | -      this->MaybeDone();
 | 
	
		
			
				|  |  | +      // Inlineable OnDone can be false here because there is no write
 | 
	
		
			
				|  |  | +      // reactor that has an inlineable OnDone; this only applies to the
 | 
	
		
			
				|  |  | +      // DefaultReactor (which is unary).
 | 
	
		
			
				|  |  | +      this->MaybeDone(/*inlineable_ondone=*/false);
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |      ~ServerCallbackWriterImpl() { req_->~RequestType(); }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      const RequestType* request() { return req_; }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    void MaybeDone() override {
 | 
	
		
			
				|  |  | -      if (GPR_UNLIKELY(this->Unref() == 1)) {
 | 
	
		
			
				|  |  | -        reactor_.load(std::memory_order_relaxed)->OnDone();
 | 
	
		
			
				|  |  | -        grpc_call* call = call_.call();
 | 
	
		
			
				|  |  | -        auto call_requester = std::move(call_requester_);
 | 
	
		
			
				|  |  | -        this->~ServerCallbackWriterImpl();  // explicitly call destructor
 | 
	
		
			
				|  |  | -        ::grpc::g_core_codegen_interface->grpc_call_unref(call);
 | 
	
		
			
				|  |  | -        call_requester();
 | 
	
		
			
				|  |  | -      }
 | 
	
		
			
				|  |  | +    void CallOnDone() override {
 | 
	
		
			
				|  |  | +      reactor_.load(std::memory_order_relaxed)->OnDone();
 | 
	
		
			
				|  |  | +      grpc_call* call = call_.call();
 | 
	
		
			
				|  |  | +      auto call_requester = std::move(call_requester_);
 | 
	
		
			
				|  |  | +      this->~ServerCallbackWriterImpl();  // explicitly call destructor
 | 
	
		
			
				|  |  | +      ::grpc::g_core_codegen_interface->grpc_call_unref(call);
 | 
	
		
			
				|  |  | +      call_requester();
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      ServerReactor* reactor() override {
 | 
	
	
		
			
				|  | @@ -620,8 +677,13 @@ class CallbackBidiHandler : public ::grpc::internal::MethodHandler {
 | 
	
		
			
				|  |  |              static_cast<::grpc_impl::CallbackServerContext*>(
 | 
	
		
			
				|  |  |                  param.server_context),
 | 
	
		
			
				|  |  |              param.call, std::move(param.call_requester));
 | 
	
		
			
				|  |  | +    // Inlineable OnDone can be false in the CompletionOp callback because there
 | 
	
		
			
				|  |  | +    // is no bidi reactor that has an inlineable OnDone; this only applies to
 | 
	
		
			
				|  |  | +    // the DefaultReactor (which is unary).
 | 
	
		
			
				|  |  |      param.server_context->BeginCompletionOp(
 | 
	
		
			
				|  |  | -        param.call, [stream](bool) { stream->MaybeDone(); }, stream);
 | 
	
		
			
				|  |  | +        param.call,
 | 
	
		
			
				|  |  | +        [stream](bool) { stream->MaybeDone(/*inlineable_ondone=*/false); },
 | 
	
		
			
				|  |  | +        stream);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      ServerBidiReactor<RequestType, ResponseType>* reactor = nullptr;
 | 
	
		
			
				|  |  |      if (param.status.ok()) {
 | 
	
	
		
			
				|  | @@ -652,8 +714,17 @@ class CallbackBidiHandler : public ::grpc::internal::MethodHandler {
 | 
	
		
			
				|  |  |        : public ServerCallbackReaderWriter<RequestType, ResponseType> {
 | 
	
		
			
				|  |  |     public:
 | 
	
		
			
				|  |  |      void Finish(::grpc::Status s) override {
 | 
	
		
			
				|  |  | -      finish_tag_.Set(call_.call(), [this](bool) { MaybeDone(); }, &finish_ops_,
 | 
	
		
			
				|  |  | -                      false);
 | 
	
		
			
				|  |  | +      // A finish tag with only MaybeDone can have its callback inlined
 | 
	
		
			
				|  |  | +      // regardless even if OnDone is not inlineable because this callback just
 | 
	
		
			
				|  |  | +      // checks a ref and then decides whether or not to dispatch OnDone.
 | 
	
		
			
				|  |  | +      finish_tag_.Set(call_.call(),
 | 
	
		
			
				|  |  | +                      [this](bool) {
 | 
	
		
			
				|  |  | +                        // Inlineable OnDone can be false here because there is
 | 
	
		
			
				|  |  | +                        // no bidi reactor that has an inlineable OnDone; this
 | 
	
		
			
				|  |  | +                        // only applies to the DefaultReactor (which is unary).
 | 
	
		
			
				|  |  | +                        this->MaybeDone(/*inlineable_ondone=*/false);
 | 
	
		
			
				|  |  | +                      },
 | 
	
		
			
				|  |  | +                      &finish_ops_, /*can_inline=*/true);
 | 
	
		
			
				|  |  |        finish_ops_.set_core_cq_tag(&finish_tag_);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |        if (!ctx_->sent_initial_metadata_) {
 | 
	
	
		
			
				|  | @@ -671,13 +742,17 @@ class CallbackBidiHandler : public ::grpc::internal::MethodHandler {
 | 
	
		
			
				|  |  |      void SendInitialMetadata() override {
 | 
	
		
			
				|  |  |        GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_);
 | 
	
		
			
				|  |  |        this->Ref();
 | 
	
		
			
				|  |  | +      // The callback for this function should not be inlined because it invokes
 | 
	
		
			
				|  |  | +      // a user-controlled reaction, but any resulting OnDone can be inlined in
 | 
	
		
			
				|  |  | +      // the executor to which this callback is dispatched.
 | 
	
		
			
				|  |  |        meta_tag_.Set(call_.call(),
 | 
	
		
			
				|  |  |                      [this](bool ok) {
 | 
	
		
			
				|  |  | -                      reactor_.load(std::memory_order_relaxed)
 | 
	
		
			
				|  |  | -                          ->OnSendInitialMetadataDone(ok);
 | 
	
		
			
				|  |  | -                      MaybeDone();
 | 
	
		
			
				|  |  | +                      ServerBidiReactor<RequestType, ResponseType>* reactor =
 | 
	
		
			
				|  |  | +                          reactor_.load(std::memory_order_relaxed);
 | 
	
		
			
				|  |  | +                      reactor->OnSendInitialMetadataDone(ok);
 | 
	
		
			
				|  |  | +                      this->MaybeDone(/*inlineable_ondone=*/true);
 | 
	
		
			
				|  |  |                      },
 | 
	
		
			
				|  |  | -                    &meta_ops_, false);
 | 
	
		
			
				|  |  | +                    &meta_ops_, /*can_inline=*/false);
 | 
	
		
			
				|  |  |        meta_ops_.SendInitialMetadata(&ctx_->initial_metadata_,
 | 
	
		
			
				|  |  |                                      ctx_->initial_metadata_flags());
 | 
	
		
			
				|  |  |        if (ctx_->compression_level_set()) {
 | 
	
	
		
			
				|  | @@ -733,35 +808,38 @@ class CallbackBidiHandler : public ::grpc::internal::MethodHandler {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      void SetupReactor(ServerBidiReactor<RequestType, ResponseType>* reactor) {
 | 
	
		
			
				|  |  |        reactor_.store(reactor, std::memory_order_relaxed);
 | 
	
		
			
				|  |  | -      write_tag_.Set(
 | 
	
		
			
				|  |  | -          call_.call(),
 | 
	
		
			
				|  |  | -          [this](bool ok) {
 | 
	
		
			
				|  |  | -            reactor_.load(std::memory_order_relaxed)->OnWriteDone(ok);
 | 
	
		
			
				|  |  | -            MaybeDone();
 | 
	
		
			
				|  |  | -          },
 | 
	
		
			
				|  |  | -          &write_ops_, false);
 | 
	
		
			
				|  |  | +      // The callbacks for these functions should not be inlined because they
 | 
	
		
			
				|  |  | +      // invoke user-controlled reactions, but any resulting OnDones can be
 | 
	
		
			
				|  |  | +      // inlined in the executor to which a callback is dispatched.
 | 
	
		
			
				|  |  | +      write_tag_.Set(call_.call(),
 | 
	
		
			
				|  |  | +                     [this, reactor](bool ok) {
 | 
	
		
			
				|  |  | +                       reactor->OnWriteDone(ok);
 | 
	
		
			
				|  |  | +                       this->MaybeDone(/*inlineable_ondone=*/true);
 | 
	
		
			
				|  |  | +                     },
 | 
	
		
			
				|  |  | +                     &write_ops_, /*can_inline=*/false);
 | 
	
		
			
				|  |  |        write_ops_.set_core_cq_tag(&write_tag_);
 | 
	
		
			
				|  |  |        read_tag_.Set(call_.call(),
 | 
	
		
			
				|  |  | -                    [this](bool ok) {
 | 
	
		
			
				|  |  | -                      reactor_.load(std::memory_order_relaxed)->OnReadDone(ok);
 | 
	
		
			
				|  |  | -                      MaybeDone();
 | 
	
		
			
				|  |  | +                    [this, reactor](bool ok) {
 | 
	
		
			
				|  |  | +                      reactor->OnReadDone(ok);
 | 
	
		
			
				|  |  | +                      this->MaybeDone(/*inlineable_ondone=*/true);
 | 
	
		
			
				|  |  |                      },
 | 
	
		
			
				|  |  | -                    &read_ops_, false);
 | 
	
		
			
				|  |  | +                    &read_ops_, /*can_inline=*/false);
 | 
	
		
			
				|  |  |        read_ops_.set_core_cq_tag(&read_tag_);
 | 
	
		
			
				|  |  |        this->BindReactor(reactor);
 | 
	
		
			
				|  |  |        this->MaybeCallOnCancel(reactor);
 | 
	
		
			
				|  |  | -      this->MaybeDone();
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    void MaybeDone() override {
 | 
	
		
			
				|  |  | -      if (GPR_UNLIKELY(this->Unref() == 1)) {
 | 
	
		
			
				|  |  | -        reactor_.load(std::memory_order_relaxed)->OnDone();
 | 
	
		
			
				|  |  | -        grpc_call* call = call_.call();
 | 
	
		
			
				|  |  | -        auto call_requester = std::move(call_requester_);
 | 
	
		
			
				|  |  | -        this->~ServerCallbackReaderWriterImpl();  // explicitly call destructor
 | 
	
		
			
				|  |  | -        ::grpc::g_core_codegen_interface->grpc_call_unref(call);
 | 
	
		
			
				|  |  | -        call_requester();
 | 
	
		
			
				|  |  | -      }
 | 
	
		
			
				|  |  | +      // Inlineable OnDone can be false here because there is no bidi
 | 
	
		
			
				|  |  | +      // reactor that has an inlineable OnDone; this only applies to the
 | 
	
		
			
				|  |  | +      // DefaultReactor (which is unary).
 | 
	
		
			
				|  |  | +      this->MaybeDone(/*inlineable_ondone=*/false);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    void CallOnDone() override {
 | 
	
		
			
				|  |  | +      reactor_.load(std::memory_order_relaxed)->OnDone();
 | 
	
		
			
				|  |  | +      grpc_call* call = call_.call();
 | 
	
		
			
				|  |  | +      auto call_requester = std::move(call_requester_);
 | 
	
		
			
				|  |  | +      this->~ServerCallbackReaderWriterImpl();  // explicitly call destructor
 | 
	
		
			
				|  |  | +      ::grpc::g_core_codegen_interface->grpc_call_unref(call);
 | 
	
		
			
				|  |  | +      call_requester();
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      ServerReactor* reactor() override {
 |