JNIEXPORT jlong JNICALL Java_io_netty_channel_epoll_Native_writevAddresses(JNIEnv * env, jclass clazz, jint fd, jobjectArray addresses, jint offset, jint length) {
    struct iovec iov[length];
    int i;
    int iovidx = 0;
    for (i = offset; i < length; i++) {
        jobject addressEntry = (*env)->GetObjectArrayElement(env, addresses, i);
        jint readerIndex = (*env)->GetIntField(env, addressEntry, readerIndexFieldId);
        jint writerIndex = (*env)->GetIntField(env, addressEntry, writerIndexFieldId);
        void* memoryAddress = (void*) (*env)->GetLongField(env, addressEntry, memoryAddressFieldId);

        iov[iovidx].iov_base = memoryAddress + readerIndex;
        iov[iovidx].iov_len = (size_t) (writerIndex - readerIndex);
        iovidx++;

        // Explicit delete local reference as otherwise the local references will only be released once the native method returns.
        // Also there may be a lot of these and JNI specification only specify that 16 must be able to be created.
        //
        // See https://github.com/netty/netty/issues/2623
        (*env)->DeleteLocalRef(env, addressEntry);
    }

    jlong res = writev0(env, clazz, fd, iov, length);
    if (res <= 0) {
        return res;
    }
}
JNIEXPORT jlong JNICALL Java_io_netty_channel_epoll_Native_writev(JNIEnv * env, jclass clazz, jint fd, jobjectArray buffers, jint offset, jint length) {
    struct iovec iov[length];
    int i;
    int iovidx = 0;
    for (i = offset; i < length; i++) {
        jobject bufObj = (*env)->GetObjectArrayElement(env, buffers, i);
        jint pos;
        // Get the current position using the (*env)->GetIntField if possible and fallback
        // to slower (*env)->CallIntMethod(...) if needed
        if (posFieldId == NULL) {
            pos = (*env)->CallIntMethod(env, bufObj, posId, NULL);
        } else {
            pos = (*env)->GetIntField(env, bufObj, posFieldId);
        }
        jint limit;
        // Get the current limit using the (*env)->GetIntField if possible and fallback
        // to slower (*env)->CallIntMethod(...) if needed
        if (limitFieldId == NULL) {
            limit = (*env)->CallIntMethod(env, bufObj, limitId, NULL);
        } else {
            limit = (*env)->GetIntField(env, bufObj, limitFieldId);
        }
        void *buffer = (*env)->GetDirectBufferAddress(env, bufObj);
        if (buffer == NULL) {
            throwRuntimeException(env, "Unable to access address of buffer");
            return -1;
        }
        iov[iovidx].iov_base = buffer + pos;
        iov[iovidx].iov_len = (size_t) (limit - pos);
        iovidx++;
    }
    jlong res = writev0(env, clazz, fd, iov, length);
    if (res <= 0) {
        return res;
    }

    // update the position of the written buffers
    int written = res;
    int a;
    for (a = 0; a < length; a++) {
        int len = iov[a].iov_len;
        jobject bufObj = (*env)->GetObjectArrayElement(env, buffers, a + offset);
        if (len >= written) {
            incrementPosition(env, bufObj, written);
            break;
        } else {
            incrementPosition(env, bufObj, len);
            written -= len;
        }
    }
    return res;
}
JNIEXPORT jlong JNICALL Java_io_netty_channel_epoll_Native_writevAddresses(JNIEnv * env, jclass clazz, jint fd, jobjectArray addresses, jint offset, jint length) {
    struct iovec iov[length];
    int i;
    int iovidx = 0;
    for (i = offset; i < length; i++) {
        jobject addressEntry = (*env)->GetObjectArrayElement(env, addresses, i);
        jint readerIndex = (*env)->GetIntField(env, addressEntry, readerIndexFieldId);
        jint writerIndex = (*env)->GetIntField(env, addressEntry, writerIndexFieldId);
        void* memoryAddress = (void*) (*env)->GetLongField(env, addressEntry, memoryAddressFieldId);

        iov[iovidx].iov_base = memoryAddress + readerIndex;
        iov[iovidx].iov_len = (size_t) (writerIndex - readerIndex);
        iovidx++;
    }

    jlong res = writev0(env, clazz, fd, iov, length);
    if (res <= 0) {
        return res;
    }
}
JNIEXPORT jlong JNICALL Java_io_netty_channel_epoll_Native_writev(JNIEnv * env, jclass clazz, jint fd, jobjectArray buffers, jint offset, jint length) {
    struct iovec iov[length];
    int iovidx = 0;
    int i;
    int num = offset + length;
    for (i = offset; i < num; i++) {
        jobject bufObj = (*env)->GetObjectArrayElement(env, buffers, i);
        jint pos;
        // Get the current position using the (*env)->GetIntField if possible and fallback
        // to slower (*env)->CallIntMethod(...) if needed
        if (posFieldId == NULL) {
            pos = (*env)->CallIntMethod(env, bufObj, posId, NULL);
        } else {
            pos = (*env)->GetIntField(env, bufObj, posFieldId);
        }
        jint limit;
        // Get the current limit using the (*env)->GetIntField if possible and fallback
        // to slower (*env)->CallIntMethod(...) if needed
        if (limitFieldId == NULL) {
            limit = (*env)->CallIntMethod(env, bufObj, limitId, NULL);
        } else {
            limit = (*env)->GetIntField(env, bufObj, limitFieldId);
        }
        void *buffer = (*env)->GetDirectBufferAddress(env, bufObj);
        if (buffer == NULL) {
            throwRuntimeException(env, "Unable to access address of buffer");
            return -1;
        }
        iov[iovidx].iov_base = buffer + pos;
        iov[iovidx].iov_len = (size_t) (limit - pos);
        iovidx++;

        // Explicit delete local reference as otherwise the local references will only be released once the native method returns.
        // Also there may be a lot of these and JNI specification only specify that 16 must be able to be created.
        //
        // See https://github.com/netty/netty/issues/2623
        (*env)->DeleteLocalRef(env, bufObj);
    }
    return writev0(env, clazz, fd, iov, length);
}