njs_array_property_query(njs_vm_t *vm, njs_property_query_t *pq,
    njs_array_t *array, uint32_t index)
{
    int64_t            length;
    uint64_t           size;
    njs_int_t          ret;
    njs_value_t        *setval, value;
    njs_object_prop_t  *prop;

    if (pq->query == NJS_PROPERTY_QUERY_SET) {
        if (!array->object.extensible) {
            return NJS_DECLINED;
        }

        if (njs_fast_path(array->object.fast_array)) {
            if (njs_fast_path(index < NJS_ARRAY_LARGE_OBJECT_LENGTH)) {
                if (index >= array->length) {
                    size = index - array->length + 1;

                    ret = njs_array_expand(vm, array, 0, size);
                    if (njs_slow_path(ret != NJS_OK)) {
                        return ret;
                    }

                    setval = &array->start[array->length];

                    while (size != 0) {
                        njs_set_invalid(setval);
                        setval++;
                        size--;
                    }

                    array->length = index + 1;
                }

                goto prop;
            }

            ret = njs_array_convert_to_slow_array(vm, array);
            if (njs_slow_path(ret != NJS_OK)) {
                return ret;
            }
        }

        njs_set_array(&value, array);

        ret = njs_object_length(vm, &value, &length);
        if (njs_slow_path(ret != NJS_OK)) {
            return ret;
        }

        if ((index + 1) > length) {
            ret = njs_array_length_redefine(vm, &value, index + 1);
            if (njs_slow_path(ret != NJS_OK)) {
                return ret;
            }
        }

        ret = njs_lvlhsh_find(&array->object.hash, &pq->lhq);
        if (ret == NJS_OK) {
            prop = pq->lhq.value;

            if (prop->type != NJS_WHITEOUT) {
                return NJS_OK;
            }

            if (pq->own) {
                pq->own_whiteout = prop;
            }

            return NJS_DECLINED;
        }

        return NJS_DONE;
    }

    if (njs_slow_path(!array->object.fast_array)) {
        return NJS_DECLINED;
    }

    if (index >= array->length) {
        return NJS_DECLINED;
    }

prop:

    prop = &pq->scratch;

    if (pq->query == NJS_PROPERTY_QUERY_GET) {
        if (!njs_is_valid(&array->start[index])) {
            return NJS_DECLINED;
        }

        prop->value = array->start[index];
        prop->type = NJS_PROPERTY;

    } else {
        prop->value.data.u.value = &array->start[index];
        prop->type = NJS_PROPERTY_REF;
    }

    njs_set_number(&prop->name, index);

    prop->writable = 1;
    prop->enumerable = 1;
    prop->configurable = 1;

    pq->lhq.value = prop;

    return NJS_OK;
}
njs_array_property_query(njs_vm_t *vm, njs_property_query_t *pq,
    njs_array_t *array, uint32_t index)
{
    int64_t            length;
    uint64_t           size;
    njs_int_t          ret;
    njs_value_t        *setval, value;
    njs_object_prop_t  *prop;

    if (pq->query == NJS_PROPERTY_QUERY_SET) {
        if (!array->object.extensible) {
            return NJS_DECLINED;
        }

        if (njs_fast_path(array->object.fast_array)) {
            if (njs_fast_path(index < NJS_ARRAY_LARGE_OBJECT_LENGTH)) {
                if (index >= array->length) {
                    size = index - array->length + 1;

                    ret = njs_array_expand(vm, array, 0, size);
                    if (njs_slow_path(ret != NJS_OK)) {
                        return ret;
                    }

                    setval = &array->start[array->length];

                    while (size != 0) {
                        njs_set_invalid(setval);
                        setval++;
                        size--;
                    }

                    array->length = index + 1;
                }

                goto prop;
            }

            ret = njs_array_convert_to_slow_array(vm, array);
            if (njs_slow_path(ret != NJS_OK)) {
                return ret;
            }
        }

        njs_set_array(&value, array);

        ret = njs_object_length(vm, &value, &length);
        if (njs_slow_path(ret != NJS_OK)) {
            return ret;
        }

        if ((index + 1) > length) {
            ret = njs_array_length_redefine(vm, &value, index + 1);
            if (njs_slow_path(ret != NJS_OK)) {
                return ret;
            }
        }

        ret = njs_lvlhsh_find(&array->object.hash, &pq->lhq);
        if (ret == NJS_OK) {
            prop = pq->lhq.value;

            if (prop->type != NJS_WHITEOUT) {
                return NJS_OK;
            }

            if (pq->own) {
                pq->own_whiteout = prop;
            }

            return NJS_DECLINED;
        }

        return NJS_DONE;
    }

    if (njs_slow_path(!array->object.fast_array)) {
        return NJS_DECLINED;
    }

    if (index >= array->length) {
        return NJS_DECLINED;
    }

prop:

    prop = &pq->scratch;

    if (pq->query == NJS_PROPERTY_QUERY_GET) {
        if (!njs_is_valid(&array->start[index])) {
            return NJS_DECLINED;
        }

        prop->value = array->start[index];
        prop->type = NJS_PROPERTY;

    } else {
        prop->value.data.u.value = &array->start[index];
        prop->type = NJS_PROPERTY_REF;
    }

    njs_set_number(&prop->name, index);

    prop->writable = 1;
    prop->enumerable = 1;
    prop->configurable = 1;

    pq->lhq.value = prop;

    return NJS_OK;
}