njs_value_property_set(njs_vm_t *vm, njs_value_t *value, njs_value_t *key,
    njs_value_t *setval)
{
    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;

    static const njs_str_t  length_key = njs_str("length");

    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_fast_path(index < njs_typed_array_length(tarray))) {
                return njs_typed_array_set_value(vm, tarray, index, setval);
            }

            return NJS_OK;
        }

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

        /* NJS_ARRAY */

        array = njs_array(value);

        if (njs_slow_path(index >= array->length)) {
            goto slow_path;
        }

        array->start[index] = *setval;

        return NJS_OK;
    }

slow_path:

    if (njs_is_primitive(value)) {
        njs_type_error(vm, "property set on primitive %s type",
                       njs_type_string(value->type));
        return NJS_ERROR;
    }

    njs_property_query_init(&pq, NJS_PROPERTY_QUERY_SET, 0);

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

    switch (ret) {

    case NJS_OK:
        prop = pq.lhq.value;

        if (njs_is_data_descriptor(prop)) {
            if (!prop->writable) {
                njs_key_string_get(vm, &pq.key,  &pq.lhq.key);
                njs_type_error(vm,
                             "Cannot assign to read-only property \"%V\" of %s",
                               &pq.lhq.key, njs_type_string(value->type));
                return NJS_ERROR;
            }

        } else {
            if (njs_is_function(&prop->setter)) {
                return njs_function_call(vm, njs_function(&prop->setter),
                                         value, setval, 1, &vm->retval);
            }

            njs_key_string_get(vm, &pq.key,  &pq.lhq.key);
            njs_type_error(vm,
                     "Cannot set property \"%V\" of %s which has only a getter",
                           &pq.lhq.key, njs_type_string(value->type));
            return NJS_ERROR;
        }

        if (prop->type == NJS_PROPERTY_HANDLER) {
            ret = prop->value.data.u.prop_handler(vm, prop, value, setval,
                                                  &vm->retval);
            if (njs_slow_path(ret != NJS_DECLINED)) {
                return ret;
            }
        }

        if (pq.own) {
            switch (prop->type) {
            case NJS_PROPERTY:
                if (njs_slow_path(pq.lhq.key_hash == NJS_LENGTH_HASH)) {
                    if (njs_strstr_eq(&pq.lhq.key, &length_key)) {
                        ret = njs_array_length_set(vm, value, prop, setval);
                        if (ret != NJS_DECLINED) {
                            return ret;
                        }
                    }
                }

                goto found;

            case NJS_PROPERTY_REF:
                *prop->value.data.u.value = *setval;
                return NJS_OK;

            case NJS_PROPERTY_TYPED_ARRAY_REF:
                return njs_typed_array_set_value(vm,
                                                 njs_typed_array(&prop->value),
                                                 prop->value.data.magic32,
                                                 setval);

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

                return NJS_ERROR;
            }

            break;
        }

        /* Fall through. */

    case NJS_DECLINED:
        if (njs_slow_path(pq.own_whiteout != NULL)) {
            /* Previously deleted property. */
            if (!njs_object(value)->extensible) {
                goto fail;
            }

            prop = pq.own_whiteout;

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

            goto found;
        }

        if (njs_slow_path(pq.own && njs_is_typed_array(value)
                          && njs_is_string(key)))
        {
            /* Integer-Indexed Exotic Objects [[DefineOwnProperty]]. */
            if (!isnan(njs_string_to_index(key))) {
                return NJS_OK;
            }
        }

        break;

    case NJS_ERROR:
    default:

        return ret;
    }

    if (njs_slow_path(!njs_object(value)->extensible)) {
        goto fail;
    }

    prop = njs_object_prop_alloc(vm, &pq.key, &njs_value_undefined, 1);
    if (njs_slow_path(prop == NULL)) {
        return NJS_ERROR;
    }

    pq.lhq.replace = 0;
    pq.lhq.value = prop;
    pq.lhq.pool = vm->mem_pool;

    ret = njs_lvlhsh_insert(njs_object_hash(value), &pq.lhq);
    if (njs_slow_path(ret != NJS_OK)) {
        njs_internal_error(vm, "lvlhsh insert failed");
        return NJS_ERROR;
    }

found:

    prop->value = *setval;

    return NJS_OK;

fail:

    njs_key_string_get(vm, &pq.key, &pq.lhq.key);
    njs_type_error(vm, "Cannot add property \"%V\", object is not extensible",
                   &pq.lhq.key);

    return NJS_ERROR;
}
njs_value_property_set(njs_vm_t *vm, njs_value_t *value, njs_value_t *key,
    njs_value_t *setval)
{
    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;

    static const njs_str_t  length_key = njs_str("length");

    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_fast_path(index < njs_typed_array_length(tarray))) {
                return njs_typed_array_set_value(vm, tarray, index, setval);
            }

            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)) {
            goto slow_path;
        }

        array->start[index] = *setval;

        return NJS_OK;
    }

slow_path:

    if (njs_is_primitive(value)) {
        njs_type_error(vm, "property set on primitive %s type",
                       njs_type_string(value->type));
        return NJS_ERROR;
    }

    njs_property_query_init(&pq, NJS_PROPERTY_QUERY_SET, 0);

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

    switch (ret) {

    case NJS_OK:
        prop = pq.lhq.value;

        if (njs_is_data_descriptor(prop)) {
            if (!prop->writable) {
                njs_key_string_get(vm, &pq.key,  &pq.lhq.key);
                njs_type_error(vm,
                             "Cannot assign to read-only property \"%V\" of %s",
                               &pq.lhq.key, njs_type_string(value->type));
                return NJS_ERROR;
            }

        } else {
            if (njs_is_function(&prop->setter)) {
                return njs_function_call(vm, njs_function(&prop->setter),
                                         value, setval, 1, &vm->retval);
            }

            njs_key_string_get(vm, &pq.key,  &pq.lhq.key);
            njs_type_error(vm,
                     "Cannot set property \"%V\" of %s which has only a getter",
                           &pq.lhq.key, njs_type_string(value->type));
            return NJS_ERROR;
        }

        if (prop->type == NJS_PROPERTY_HANDLER) {
            ret = prop->value.data.u.prop_handler(vm, prop, value, setval,
                                                  &vm->retval);
            if (njs_slow_path(ret != NJS_DECLINED)) {
                return ret;
            }
        }

        if (pq.own) {
            switch (prop->type) {
            case NJS_PROPERTY:
                if (njs_slow_path(pq.lhq.key_hash == NJS_LENGTH_HASH)) {
                    if (njs_strstr_eq(&pq.lhq.key, &length_key)) {
                        ret = njs_array_length_set(vm, value, prop, setval);
                        if (ret != NJS_DECLINED) {
                            return ret;
                        }
                    }
                }

                goto found;

            case NJS_PROPERTY_REF:
                *prop->value.data.u.value = *setval;
                return NJS_OK;

            case NJS_PROPERTY_TYPED_ARRAY_REF:
                return njs_typed_array_set_value(vm,
                                                 njs_typed_array(&prop->value),
                                                 prop->value.data.magic32,
                                                 setval);

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

                return NJS_ERROR;
            }

            break;
        }

         

    case NJS_DECLINED:
        if (njs_slow_path(pq.own_whiteout != NULL)) {
             
            if (!njs_object(value)->extensible) {
                goto fail;
            }

            prop = pq.own_whiteout;

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

            goto found;
        }

        if (njs_slow_path(pq.own && njs_is_typed_array(value)
                          && njs_is_string(key)))
        {
             
            if (!isnan(njs_string_to_index(key))) {
                return NJS_OK;
            }
        }

        break;

    case NJS_ERROR:
    default:

        return ret;
    }

    if (njs_slow_path(!njs_object(value)->extensible)) {
        goto fail;
    }

    prop = njs_object_prop_alloc(vm, &pq.key, &njs_value_undefined, 1);
    if (njs_slow_path(prop == NULL)) {
        return NJS_ERROR;
    }

    pq.lhq.replace = 0;
    pq.lhq.value = prop;
    pq.lhq.pool = vm->mem_pool;

    ret = njs_lvlhsh_insert(njs_object_hash(value), &pq.lhq);
    if (njs_slow_path(ret != NJS_OK)) {
        njs_internal_error(vm, "lvlhsh insert failed");
        return NJS_ERROR;
    }

found:

    prop->value = *setval;

    return NJS_OK;

fail:

    njs_key_string_get(vm, &pq.key, &pq.lhq.key);
    njs_type_error(vm, "Cannot add property \"%V\", object is not extensible",
                   &pq.lhq.key);

    return NJS_ERROR;
}