njs_value_property(njs_vm_t *vm, njs_value_t *value, njs_value_t *key,
    njs_value_t *retval)
{
    double                num;
    uint32_t              index;
    njs_int_t             ret;
    njs_array_t          *array;
    njs_object_prop_t     *prop;
    njs_typed_array_t     *tarray;
    njs_property_query_t  pq;

    if (njs_fast_path(njs_is_number(key))) {
        num = njs_number(key);

        if (njs_slow_path(!njs_number_is_integer_index(num))) {
            goto slow_path;
        }

        index = (uint32_t) num;

        if (njs_is_typed_array(value)) {
            tarray = njs_typed_array(value);

            if (njs_slow_path(njs_is_detached_buffer(tarray->buffer))) {
                njs_type_error(vm, "detached buffer");
                return NJS_ERROR;
            }

            if (njs_slow_path(index >= njs_typed_array_length(tarray))) {
                goto slow_path;
            }

            njs_set_number(retval, njs_typed_array_prop(tarray, index));

            return NJS_OK;
        }

        if (njs_slow_path(!(njs_is_object(value)
                            && njs_object(value)->fast_array)))
        {
            goto slow_path;
        }

        /* njs_is_fast_array() */

        array = njs_array(value);

        if (njs_slow_path(index >= array->length
                          || !njs_is_valid(&array->start[index])))
        {
            goto slow_path;
        }

        *retval = array->start[index];

        return NJS_OK;
    }

slow_path:

    njs_property_query_init(&pq, NJS_PROPERTY_QUERY_GET, 0);

    ret = njs_property_query(vm, &pq, value, key);

    switch (ret) {

    case NJS_OK:
        prop = pq.lhq.value;

        switch (prop->type) {

        case NJS_PROPERTY:
            if (njs_is_data_descriptor(prop)) {
                *retval = prop->value;
                break;
            }

            if (njs_is_undefined(&prop->getter)) {
                njs_set_undefined(retval);
                break;
            }

            return njs_function_apply(vm, njs_function(&prop->getter), value,
                                      1, retval);

        case NJS_PROPERTY_HANDLER:
            pq.scratch = *prop;
            prop = &pq.scratch;
            ret = prop->value.data.u.prop_handler(vm, prop, value, NULL,
                                                  &prop->value);

            if (njs_slow_path(ret != NJS_OK)) {
                if (ret == NJS_ERROR) {
                    return ret;
                }

                njs_set_undefined(&prop->value);
            }

            *retval = prop->value;

            break;

        default:
            njs_internal_error(vm, "unexpected property type \"%s\" "
                               "while getting",
                               njs_prop_type_string(prop->type));

            return NJS_ERROR;
        }

        break;

    case NJS_DECLINED:
        njs_set_undefined(retval);

        return NJS_DECLINED;

    case NJS_ERROR:
    default:

        return ret;
    }

    return NJS_OK;
}
njs_value_property(njs_vm_t *vm, njs_value_t *value, njs_value_t *key,
    njs_value_t *retval)
{
    double                num;
    uint32_t              index;
    njs_int_t             ret;
    njs_array_t          *array;
    njs_object_prop_t     *prop;
    njs_typed_array_t     *tarray;
    njs_property_query_t  pq;

    if (njs_fast_path(njs_is_number(key))) {
        num = njs_number(key);

        if (njs_slow_path(!njs_number_is_integer_index(num))) {
            goto slow_path;
        }

        index = (uint32_t) num;

        if (njs_is_typed_array(value)) {
            tarray = njs_typed_array(value);

            if (njs_slow_path(njs_is_detached_buffer(tarray->buffer))) {
                njs_type_error(vm, "detached buffer");
                return NJS_ERROR;
            }

            if (njs_slow_path(index >= njs_typed_array_length(tarray))) {
                goto slow_path;
            }

            njs_set_number(retval, njs_typed_array_prop(tarray, index));

            return NJS_OK;
        }

        if (njs_slow_path(!(njs_is_object(value)
                            && njs_object(value)->fast_array)))
        {
            goto slow_path;
        }

         

        array = njs_array(value);

        if (njs_slow_path(index >= array->length
                          || !njs_is_valid(&array->start[index])))
        {
            goto slow_path;
        }

        *retval = array->start[index];

        return NJS_OK;
    }

slow_path:

    njs_property_query_init(&pq, NJS_PROPERTY_QUERY_GET, 0);

    ret = njs_property_query(vm, &pq, value, key);

    switch (ret) {

    case NJS_OK:
        prop = pq.lhq.value;

        switch (prop->type) {

        case NJS_PROPERTY:
            if (njs_is_data_descriptor(prop)) {
                *retval = prop->value;
                break;
            }

            if (njs_is_undefined(&prop->getter)) {
                njs_set_undefined(retval);
                break;
            }

            return njs_function_apply(vm, njs_function(&prop->getter), value,
                                      1, retval);

        case NJS_PROPERTY_HANDLER:
            pq.scratch = *prop;
            prop = &pq.scratch;
            ret = prop->value.data.u.prop_handler(vm, prop, value, NULL,
                                                  &prop->value);

            if (njs_slow_path(ret != NJS_OK)) {
                if (ret == NJS_ERROR) {
                    return ret;
                }

                njs_set_undefined(&prop->value);
            }

            *retval = prop->value;

            break;

        default:
            njs_internal_error(vm, "unexpected property type \"%s\" "
                               "while getting",
                               njs_prop_type_string(prop->type));

            return NJS_ERROR;
        }

        break;

    case NJS_DECLINED:
        njs_set_undefined(retval);

        return NJS_DECLINED;

    case NJS_ERROR:
    default:

        return ret;
    }

    return NJS_OK;
}