Repository: netty/netty
File: codec-base/src/main/java/io/netty/handler/codec/ByteToMessageDecoder.java (Java)

Code before:
                                    //noinspection ThrowFromFinallyBlock
                                    throw new IllegalReferenceCountException(
                                            getClass().getSimpleName() +
                                                    "#decode() might have released its input buffer, " +
                                                    "or passed it down the pipeline without a retain() call, " +
                                                    "which is not allowed.", e);
                                }
                                cumulation = null;
                            } else if (++numReads >= discardAfterReads) {
                                // We did enough reads already try to discard some bytes, so we not risk to see a OOME.
                                // See https://github.com/netty/netty/issues/4275
                                numReads = 0;
                                discardSomeReadBytes();
                            }

                            int size = out.size();
                            firedChannelRead |= out.insertSinceRecycled();
                            fireChannelRead(ctx, out, size);
                        } finally {
                            out.recycle();
                        }
                    }
                } else {
                    ctx.fireChannelRead(input);
                }
            } while (inputMessages != null && (input = inputMessages.pollFirst()) != null);
        } else {
            // Reentrant call. Bail out here and let original call process our message.
            if (inputMessages == null) {
                inputMessages = new ArrayDeque<>();
            }
            inputMessages.offerLast(input);
        }
    }

    /**
     * Get {@code numElements} out of the {@link List} and forward these through the pipeline.
     */
    static void fireChannelRead(ChannelHandlerContext ctx, List<Object> msgs, int numElements) {
        if (msgs instanceof CodecOutputList) {
            fireChannelRead(ctx, (CodecOutputList) msgs, numElements);
        } else {
            for (int i = 0; i < numElements; i++) {
                ctx.fireChannelRead(msgs.get(i));
            }
        }
    }

    /**
     * Get {@code numElements} out of the {@link CodecOutputList} and forward these through the pipeline.
     */

Review comment (suggestion):
I also wonder if we need to do anything special in `handlerRemoved` now.

Code after:
                                    throw new IllegalReferenceCountException(
                                            getClass().getSimpleName() +
                                                    "#decode() might have released its input buffer, " +
                                                    "or passed it down the pipeline without a retain() call, " +
                                                    "which is not allowed.", e);
                                }
                                cumulation = null;
                            } else if (++numReads >= discardAfterReads) {
                                // We did enough reads already try to discard some bytes, so we not risk to see a OOME.
                                // See https://github.com/netty/netty/issues/4275
                                numReads = 0;
                                discardSomeReadBytes();
                            }

                            int size = out.size();
                            firedChannelRead |= out.insertSinceRecycled();
                            fireChannelRead(ctx, out, size);
                        } finally {
                            out.recycle();
                        }
                    }
                } else {
                    ctx.fireChannelRead(input);
                }
            } while (inputMessages != null && (input = inputMessages.poll()) != null);
        } else {
            // Reentrant call. Bail out here and let original call process our message.
            if (inputMessages == null) {
                inputMessages = new ArrayDeque<>(2);
            }
            inputMessages.offer(input);
        }
    }

    /**
     * Get {@code numElements} out of the {@link List} and forward these through the pipeline.
     */
    static void fireChannelRead(ChannelHandlerContext ctx, List<Object> msgs, int numElements) {
        if (msgs instanceof CodecOutputList) {
            fireChannelRead(ctx, (CodecOutputList) msgs, numElements);
        } else {
            for (int i = 0; i < numElements; i++) {
                ctx.fireChannelRead(msgs.get(i));
            }
        }
    }

    /**
     * Get {@code numElements} out of the {@link CodecOutputList} and forward these through the pipeline.
     */
    static void fireChannelRead(ChannelHandlerContext ctx, CodecOutputList msgs, int numElements) {