/* * Copyright (C) Dmitry Volyntsev * Copyright (C) NGINX, Inc. */ #include #include #include #include #include "njs_externals_test.h" typedef struct { njs_lvlhsh_t hash; uint32_t a; uint32_t d; njs_str_t uri; njs_opaque_value_t value; } njs_unit_test_req_t; typedef struct { njs_str_t name; njs_opaque_value_t value; } njs_unit_test_prop_t; static njs_int_t njs_externals_262_init(njs_vm_t *vm); static njs_int_t njs_externals_shared_preinit(njs_vm_t *vm); static njs_int_t njs_externals_shared_init(njs_vm_t *vm); njs_int_t njs_array_buffer_detach(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused, njs_value_t *retval); static njs_int_t njs_external_r_proto_id; static njs_int_t njs_external_null_proto_id; static njs_int_t njs_external_error_ctor_id; njs_module_t njs_unit_test_262_module = { .name = njs_str("$262"), .preinit = NULL, .init = njs_externals_262_init, }; njs_module_t njs_unit_test_external_module = { .name = njs_str("external"), .preinit = njs_externals_shared_preinit, .init = njs_externals_shared_init, }; static njs_int_t lvlhsh_unit_test_key_test(njs_lvlhsh_query_t *lhq, void *data) { njs_str_t name; njs_unit_test_prop_t *prop; prop = *(njs_unit_test_prop_t **) data; name = prop->name; if (name.length != lhq->key.length) { return NJS_DECLINED; } if (memcmp(name.start, lhq->key.start, lhq->key.length) == 0) { return NJS_OK; } return NJS_DECLINED; } static void * lvlhsh_unit_test_pool_alloc(void *pool, size_t size) { return njs_mp_align(pool, NJS_MAX_ALIGNMENT, size); } static void lvlhsh_unit_test_pool_free(void *pool, void *p, size_t size) { njs_mp_free(pool, p); } static const njs_lvlhsh_proto_t lvlhsh_proto njs_aligned(64) = { NJS_LVLHSH_LARGE_SLAB, lvlhsh_unit_test_key_test, lvlhsh_unit_test_pool_alloc, lvlhsh_unit_test_pool_free, }; static njs_unit_test_prop_t * lvlhsh_unit_test_alloc(njs_mp_t *pool, const njs_str_t *name, const njs_value_t *value) { njs_unit_test_prop_t *prop; prop = njs_mp_alloc(pool, sizeof(njs_unit_test_prop_t) + name->length); if (prop == NULL) { return NULL; } prop->name.length = name->length; prop->name.start = (u_char *) prop + sizeof(njs_unit_test_prop_t); memcpy(prop->name.start, name->start, name->length); njs_value_assign(&prop->value, value); return prop; } static njs_int_t lvlhsh_unit_test_add(njs_mp_t *pool, njs_unit_test_req_t *r, njs_unit_test_prop_t *prop) { njs_lvlhsh_query_t lhq; lhq.key = prop->name; lhq.key_hash = njs_djb_hash(lhq.key.start, lhq.key.length); lhq.replace = 1; lhq.proto = &lvlhsh_proto; lhq.pool = pool; switch (njs_lvlhsh_insert(&r->hash, &lhq)) { case NJS_OK: ((njs_flathsh_elt_t *) lhq.value)->value[0] = (void *) prop; return NJS_OK; case NJS_DECLINED: default: return NJS_ERROR; } } static njs_int_t njs_unit_test_r_uri(njs_vm_t *vm, njs_object_prop_t *prop, uint32_t unused, njs_value_t *value, njs_value_t *setval, njs_value_t *retval) { char *p; njs_str_t *field; p = njs_vm_external(vm, njs_external_r_proto_id, value); if (p == NULL) { njs_value_undefined_set(retval); return NJS_DECLINED; } field = (njs_str_t *) (p + njs_vm_prop_magic32(prop)); if (setval != NULL) { return njs_vm_value_to_bytes(vm, field, setval); } return njs_vm_value_string_create(vm, retval, field->start, field->length); } static njs_int_t njs_unit_test_r_a(njs_vm_t *vm, njs_object_prop_t *prop, uint32_t unused, njs_value_t *value, njs_value_t *unused2, njs_value_t *retval) { u_char *p; njs_unit_test_req_t *r; u_char buf[16]; r = njs_vm_external(vm, njs_external_r_proto_id, value); if (r == NULL) { njs_value_undefined_set(retval); return NJS_DECLINED; } p = njs_sprintf(buf, buf + njs_length(buf), "%uD", r->a); return njs_vm_value_string_create(vm, retval, buf, p - buf); } static njs_int_t njs_unit_test_r_b(njs_vm_t *vm, njs_object_prop_t *prop, uint32_t unused, njs_value_t *value, njs_value_t *unused2, njs_value_t *retval) { njs_value_number_set(retval, njs_vm_prop_magic32(prop)); return NJS_OK; } static njs_int_t njs_unit_test_r_d(njs_vm_t *vm, njs_object_prop_t *prop, uint32_t unused, njs_value_t *value, njs_value_t *unused2, njs_value_t *retval) { njs_unit_test_req_t *r; r = njs_vm_external(vm, njs_external_r_proto_id, value); if (r == NULL) { njs_value_undefined_set(retval); return NJS_DECLINED; } njs_value_number_set(retval, r->d); return NJS_OK; } static njs_int_t njs_unit_test_r_host(njs_vm_t *vm, njs_object_prop_t *prop, uint32_t unused, njs_value_t *value, njs_value_t *setval, njs_value_t *retval) { return njs_vm_value_string_create(vm, retval, (u_char *) "АБВГДЕЁЖЗИЙ", 22); } static njs_int_t njs_unit_test_r_buffer(njs_vm_t *vm, njs_object_prop_t *prop, uint32_t unused, njs_value_t *value, njs_value_t *setval, njs_value_t *retval) { return njs_vm_value_buffer_set(vm, retval, (u_char *) "АБВГДЕЁЖЗИЙ", 22); } static njs_int_t njs_unit_test_r_vars(njs_vm_t *vm, njs_object_prop_t *self, uint32_t atom_id, njs_value_t *value, njs_value_t *setval, njs_value_t *retval) { njs_int_t ret; njs_lvlhsh_query_t lhq; njs_unit_test_req_t *r; njs_unit_test_prop_t *prop; r = njs_vm_external(vm, njs_external_r_proto_id, value); if (r == NULL) { njs_value_undefined_set(retval); return NJS_DECLINED; } ret = njs_vm_prop_name(vm, atom_id, &lhq.key); if (ret != NJS_OK) { if (setval == NULL && retval != NULL) { /* Get. */ njs_value_undefined_set(retval); return NJS_DECLINED; } return NJS_ERROR; } if (setval != NULL || retval == NULL) { /* Set or Delete. */ if (lhq.key.length == 5 && memcmp(lhq.key.start, "error", 5) == 0) { njs_vm_error(vm, "cannot %s \"error\" prop", retval != NULL ? "set" : "delete"); return NJS_ERROR; } } if (setval != NULL) { /* Set. */ prop = lvlhsh_unit_test_alloc(njs_vm_memory_pool(vm), &lhq.key, setval); if (prop == NULL) { njs_vm_memory_error(vm); return NJS_ERROR; } ret = lvlhsh_unit_test_add(njs_vm_memory_pool(vm), r, prop); if (ret != NJS_OK) { njs_vm_error(vm, "lvlhsh_unit_test_add() failed"); return NJS_ERROR; } return NJS_OK; } /* Get or Delete. */ lhq.key_hash = njs_djb_hash(lhq.key.start, lhq.key.length); lhq.proto = &lvlhsh_proto; ret = njs_lvlhsh_find(&r->hash, &lhq); if (ret == NJS_OK) { prop = ((njs_flathsh_elt_t *) lhq.value)->value[0]; if (retval == NULL) { njs_value_invalid_set(njs_value_arg(&prop->value)); return NJS_OK; } if (njs_value_is_valid(njs_value_arg(&prop->value))) { njs_value_assign(retval, njs_value_arg(&prop->value)); return NJS_OK; } } if (retval != NULL) { njs_value_undefined_set(retval); } return NJS_DECLINED; } static njs_int_t njs_unit_test_r_header(njs_vm_t *vm, njs_object_prop_t *prop, uint32_t atom_id, njs_value_t *value, njs_value_t *unused, njs_value_t *retval) { njs_int_t ret; njs_str_t h; njs_chb_t chain; ret = njs_vm_prop_name(vm, atom_id, &h); if (ret == NJS_OK) { NJS_CHB_MP_INIT(&chain, njs_vm_memory_pool(vm)); njs_chb_append(&chain, h.start, h.length); njs_chb_append(&chain, (u_char *) "|АБВ", njs_length("|АБВ")); ret = njs_vm_value_string_create_chb(vm, retval, &chain); njs_chb_destroy(&chain); return ret; } njs_value_undefined_set(retval); return NJS_DECLINED; } static njs_int_t njs_unit_test_r_header_keys(njs_vm_t *vm, njs_value_t *value, njs_value_t *keys) { njs_int_t ret, i; njs_value_t *push; u_char k[2]; ret = njs_vm_array_alloc(vm, keys, 4); if (ret != NJS_OK) { return NJS_ERROR; } k[0] = '0'; k[1] = '1'; for (i = 0; i < 3; i++) { push = njs_vm_array_push(vm, keys); if (push == NULL) { return NJS_ERROR; } (void) njs_vm_value_string_create(vm, push, k, 2); k[1]++; } return NJS_OK; } static njs_int_t njs_unit_test_r_method(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused, njs_value_t *retval) { njs_int_t ret; njs_str_t s; njs_unit_test_req_t *r; r = njs_vm_external(vm, njs_external_r_proto_id, njs_argument(args, 0)); if (r == NULL) { njs_vm_type_error(vm, "\"this\" is not an external"); return NJS_ERROR; } ret = njs_vm_value_to_bytes(vm, &s, njs_arg(args, nargs, 1)); if (ret == NJS_OK && s.length == 3 && memcmp(s.start, "YES", 3) == 0) { return njs_vm_value_string_create(vm, retval, r->uri.start, r->uri.length); } njs_value_undefined_set(retval); return NJS_OK; } static njs_int_t njs_unit_test_promise_trampoline(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused, njs_value_t *retval) { njs_function_t *callback; callback = njs_value_function(njs_argument(args, 1)); if (callback != NULL) { return njs_vm_invoke(vm, callback, njs_argument(args, 2), 1, retval); } return NJS_OK; } static njs_int_t njs_unit_test_r_subrequest(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused, njs_value_t *retval) { njs_int_t ret; njs_value_t *argument, *select; njs_function_t *callback; njs_external_ev_t *ev; njs_external_env_t *env; njs_opaque_value_t value; njs_unit_test_req_t *r; r = njs_vm_external(vm, njs_external_r_proto_id, njs_argument(args, 0)); if (r == NULL) { njs_vm_type_error(vm, "\"this\" is not an external"); return NJS_ERROR; } ev = njs_mp_alloc(njs_vm_memory_pool(vm), sizeof(njs_external_ev_t)); if (ev == NULL) { njs_vm_memory_error(vm); return NJS_ERROR; } ret = njs_vm_promise_create(vm, njs_value_arg(&value), njs_value_arg(&ev->callbacks[0])); if (ret != NJS_OK) { return NJS_ERROR; } callback = njs_vm_function_alloc(vm, njs_unit_test_promise_trampoline, 0, 0); if (callback == NULL) { return NJS_ERROR; } argument = njs_arg(args, nargs, 1); select = njs_arg(args, nargs, 2); ev->function = callback; ev->data = r; ev->nargs = 2; njs_value_assign(&ev->args[0], &ev->callbacks[!!njs_value_bool(select)]); njs_value_assign(&ev->args[1], argument); env = njs_vm_external_ptr(vm); njs_queue_insert_tail(&env->events, &ev->link); njs_value_assign(retval, &value); return NJS_OK; } static njs_int_t njs_unit_test_r_retval(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused, njs_value_t *retval) { njs_external_env_t *env; env = njs_vm_external_ptr(vm); njs_value_assign(&env->retval, njs_arg(args, nargs, 1)); njs_value_undefined_set(retval); return NJS_OK; } static njs_int_t njs_unit_test_r_custom_exception(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused, njs_value_t *retval) { njs_vm_error3(vm, njs_external_error_ctor_id, "Oops", NULL); return NJS_ERROR; } static njs_int_t njs_unit_test_r_create(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused, njs_value_t *retval) { njs_int_t ret; njs_unit_test_req_t *r, *sr; r = njs_vm_external(vm, njs_external_r_proto_id, njs_argument(args, 0)); if (r == NULL) { njs_vm_type_error(vm, "\"this\" is not an external"); return NJS_ERROR; } sr = njs_mp_zalloc(njs_vm_memory_pool(vm), sizeof(njs_unit_test_req_t)); if (sr == NULL) { goto memory_error; } if (njs_vm_value_to_bytes(vm, &sr->uri, njs_arg(args, nargs, 1)) != NJS_OK) { return NJS_ERROR; } ret = njs_vm_external_create(vm, retval, njs_external_r_proto_id, sr, 0); if (ret != NJS_OK) { return NJS_ERROR; } return NJS_OK; memory_error: njs_vm_memory_error(vm); return NJS_ERROR; } static njs_int_t njs_unit_test_r_bind(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused, njs_value_t *retval) { njs_str_t name; njs_unit_test_req_t *r; r = njs_vm_external(vm, njs_external_r_proto_id, njs_argument(args, 0)); if (r == NULL) { njs_vm_type_error(vm, "\"this\" is not an external"); return NJS_ERROR; } if (njs_vm_value_to_bytes(vm, &name, njs_arg(args, nargs, 1)) != NJS_OK) { return NJS_ERROR; } return njs_vm_bind(vm, &name, njs_arg(args, nargs, 2), 0); } static njs_int_t njs_unit_test_null_get(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused, njs_value_t *retval) { double *d; njs_value_t *this; this = njs_argument(args, 0); if (!njs_value_is_external(this, njs_external_null_proto_id)) { njs_vm_type_error(vm, "\"this\" is not a null external"); return NJS_ERROR; } d = njs_value_external(this); if (d == NULL) { njs_value_undefined_set(retval); } else { njs_value_number_set(retval, *d); } return NJS_OK; } static njs_int_t njs_unit_test_null_set(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused, njs_value_t *retval) { double *d; njs_value_t *this; this = njs_argument(args, 0); if (!njs_value_is_external(this, njs_external_null_proto_id)) { njs_vm_type_error(vm, "\"this\" is not a null external"); return NJS_ERROR; } d = njs_value_external(this); if (d == NULL) { d = njs_mp_alloc(njs_vm_memory_pool(vm), sizeof(double)); if (d == NULL) { njs_vm_memory_error(vm); return NJS_ERROR; } } *d = njs_value_number(njs_arg(args, nargs, 1)); njs_value_external_set(this, d); njs_value_undefined_set(retval); return NJS_OK; } static njs_int_t njs_unit_test_constructor(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused, njs_value_t *retval) { njs_unit_test_req_t *sr; sr = njs_mp_zalloc(njs_vm_memory_pool(vm), sizeof(njs_unit_test_req_t)); if (sr == NULL) { njs_vm_memory_error(vm); return NJS_ERROR; } if (njs_vm_value_to_bytes(vm, &sr->uri, njs_arg(args, nargs, 1)) != NJS_OK) { return NJS_ERROR; } return njs_vm_external_create(vm, retval, njs_external_r_proto_id, sr, 0); } static njs_int_t njs_unit_test_error_name(njs_vm_t *vm, njs_object_prop_t *prop, uint32_t unused, njs_value_t *value, njs_value_t *setval, njs_value_t *retval) { return njs_vm_value_string_create(vm, retval, (u_char *) "ExternalError", 13); } static njs_int_t njs_unit_test_error_message(njs_vm_t *vm, njs_object_prop_t *prop, uint32_t unused, njs_value_t *value, njs_value_t *setval, njs_value_t *retval) { return njs_vm_value_string_create(vm, retval, (u_char *) "", 0); } static njs_external_t njs_unit_test_262_external[] = { { .flags = NJS_EXTERN_PROPERTY | NJS_EXTERN_SYMBOL, .name.symbol = NJS_SYMBOL_TO_STRING_TAG, .u.property = { .value = "$262", } }, { .flags = NJS_EXTERN_METHOD, .name.string = njs_str("detachArrayBuffer"), .writable = 1, .configurable = 1, .enumerable = 1, .u.method = { .native = njs_array_buffer_detach, } }, }; static njs_external_t njs_unit_test_r_c[] = { { .flags = NJS_EXTERN_PROPERTY, .name.string = njs_str("d"), .enumerable = 1, .u.property = { .handler = njs_unit_test_r_d, } }, }; static njs_external_t njs_unit_test_r_props[] = { { .flags = NJS_EXTERN_PROPERTY, .name.string = njs_str("a"), .enumerable = 1, .u.property = { .handler = njs_unit_test_r_a, } }, { .flags = NJS_EXTERN_PROPERTY, .name.string = njs_str("b"), .enumerable = 1, .u.property = { .handler = njs_unit_test_r_b, .magic32 = 42, } }, { .flags = NJS_EXTERN_OBJECT, .name.string = njs_str("c"), .enumerable = 1, .u.object = { .properties = njs_unit_test_r_c, .nproperties = njs_nitems(njs_unit_test_r_c), } }, }; static njs_external_t njs_unit_test_r_header_props[] = { { .flags = NJS_EXTERN_PROPERTY | NJS_EXTERN_SYMBOL, .name.symbol = NJS_SYMBOL_TO_STRING_TAG, .u.property = { .value = "Header", } }, }; static njs_external_t njs_unit_test_r_header_props2[] = { { .flags = NJS_EXTERN_PROPERTY | NJS_EXTERN_SYMBOL, .name.symbol = NJS_SYMBOL_TO_STRING_TAG, .u.property = { .value = "Header2", } }, { .flags = NJS_EXTERN_SELF, .u.object = { .enumerable = 1, .prop_handler = njs_unit_test_r_header, .keys = njs_unit_test_r_header_keys, } }, }; static njs_external_t njs_unit_test_r_external[] = { { .flags = NJS_EXTERN_PROPERTY | NJS_EXTERN_SYMBOL, .name.symbol = NJS_SYMBOL_TO_STRING_TAG, .u.property = { .value = "External", } }, { .flags = NJS_EXTERN_METHOD, .name.string = njs_str("bind"), .writable = 1, .configurable = 1, .enumerable = 1, .u.method = { .native = njs_unit_test_r_bind, } }, { .flags = NJS_EXTERN_OBJECT, .name.string = njs_str("consts"), .writable = 1, .configurable = 1, .enumerable = 1, .u.object = { .enumerable = 1, .prop_handler = njs_unit_test_r_vars, } }, { .flags = NJS_EXTERN_METHOD, .name.string = njs_str("create"), .writable = 1, .configurable = 1, .enumerable = 1, .u.method = { .native = njs_unit_test_r_create, } }, { .flags = NJS_EXTERN_OBJECT, .name.string = njs_str("header"), .writable = 1, .configurable = 1, .enumerable = 1, .u.object = { .properties = njs_unit_test_r_header_props, .nproperties = njs_nitems(njs_unit_test_r_header_props), .enumerable = 1, .prop_handler = njs_unit_test_r_header, .keys = njs_unit_test_r_header_keys, } }, { .flags = NJS_EXTERN_OBJECT, .name.string = njs_str("header2"), .writable = 1, .configurable = 1, .u.object = { .properties = njs_unit_test_r_header_props2, .nproperties = njs_nitems(njs_unit_test_r_header_props2), } }, { .flags = NJS_EXTERN_PROPERTY, .name.string = njs_str("host"), .enumerable = 1, .u.property = { .handler = njs_unit_test_r_host, } }, { .flags = NJS_EXTERN_PROPERTY, .name.string = njs_str("buffer"), .enumerable = 1, .u.property = { .handler = njs_unit_test_r_buffer, } }, { .flags = NJS_EXTERN_METHOD, .name.string = njs_str("method"), .writable = 1, .configurable = 1, .enumerable = 1, .u.method = { .native = njs_unit_test_r_method, } }, { .flags = NJS_EXTERN_METHOD, .name.string = njs_str("subrequest"), .writable = 1, .configurable = 1, .enumerable = 1, .u.method = { .native = njs_unit_test_r_subrequest, } }, { .flags = NJS_EXTERN_METHOD, .name.string = njs_str("retval"), .writable = 1, .configurable = 1, .enumerable = 1, .u.method = { .native = njs_unit_test_r_retval, } }, { .flags = NJS_EXTERN_METHOD, .name.string = njs_str("customException"), .writable = 1, .configurable = 1, .enumerable = 1, .u.method = { .native = njs_unit_test_r_custom_exception, } }, { .flags = NJS_EXTERN_OBJECT, .name.string = njs_str("props"), .enumerable = 1, .writable = 1, .u.object = { .enumerable = 1, .properties = njs_unit_test_r_props, .nproperties = njs_nitems(njs_unit_test_r_props), } }, { .flags = NJS_EXTERN_PROPERTY, .name.string = njs_str("uri"), .writable = 1, .enumerable = 1, .u.property = { .handler = njs_unit_test_r_uri, .magic32 = offsetof(njs_unit_test_req_t, uri), } }, { .flags = NJS_EXTERN_OBJECT, .name.string = njs_str("vars"), .enumerable = 1, .u.object = { .writable = 1, .configurable = 1, .enumerable = 1, .prop_handler = njs_unit_test_r_vars, } }, }; static njs_external_t njs_unit_test_null_external[] = { { .flags = NJS_EXTERN_PROPERTY | NJS_EXTERN_SYMBOL, .name.symbol = NJS_SYMBOL_TO_STRING_TAG, .u.property = { .value = "Null", } }, { .flags = NJS_EXTERN_METHOD, .name.string = njs_str("get"), .writable = 1, .configurable = 1, .enumerable = 1, .u.method = { .native = njs_unit_test_null_get, } }, { .flags = NJS_EXTERN_METHOD, .name.string = njs_str("set"), .writable = 1, .configurable = 1, .enumerable = 1, .u.method = { .native = njs_unit_test_null_set, } }, }; static njs_external_t njs_unit_test_ctor_props[] = { { .flags = NJS_EXTERN_PROPERTY, .name.string = njs_str("name"), .enumerable = 1, .u.property = { .handler = njs_unit_test_error_name, } }, { .flags = NJS_EXTERN_PROPERTY, .name.string = njs_str("prototype"), .enumerable = 1, .u.property = { .handler = njs_object_prototype_create, } }, }; static njs_external_t njs_unit_test_proto_props[] = { { .flags = NJS_EXTERN_PROPERTY, .name.string = njs_str("name"), .enumerable = 1, .u.property = { .handler = njs_unit_test_error_name, } }, { .flags = NJS_EXTERN_PROPERTY, .name.string = njs_str("message"), .enumerable = 1, .u.property = { .handler = njs_unit_test_error_message, } }, { .flags = NJS_EXTERN_PROPERTY, .name.string = njs_str("constructor"), .enumerable = 1, .u.property = { .handler = njs_object_prototype_create_constructor, } }, }; typedef struct { njs_str_t name; njs_str_t value; } njs_unit_test_prop_init_t; typedef struct { njs_str_t name; njs_unit_test_req_t request; njs_unit_test_prop_init_t props[2]; } njs_unit_test_req_init_t; static njs_unit_test_req_init_t njs_test_requests[] = { { njs_str("$shared"), { .uri = njs_str("shared"), .a = 11, .d = 13, }, { { njs_str("r"), njs_str("rval") }, { njs_str("r2"), njs_str("r2val") }, } }, { njs_str("$r"), { .uri = njs_str("АБВ"), .a = 1, .d = 1024, }, { { njs_str("p"), njs_str("pval") }, { njs_str("p2"), njs_str("p2val") }, } }, { njs_str("$r2"), { .uri = njs_str("αβγ"), .a = 2, .d = 1025, }, { { njs_str("q"), njs_str("qval") }, { njs_str("q2"), njs_str("q2val") }, } }, { njs_str("$r3"), { .uri = njs_str("abc"), .a = 3, .d = 1026, }, { { njs_str("k"), njs_str("kval") }, { njs_str("k2"), njs_str("k2val") }, } }, }; static njs_int_t njs_externals_init_internal(njs_vm_t *vm, njs_unit_test_req_init_t *init, njs_uint_t n, njs_bool_t shared) { njs_int_t ret; njs_uint_t i, j; njs_opaque_value_t value; njs_unit_test_req_t *requests; njs_unit_test_prop_t *prop; requests = njs_mp_zalloc(njs_vm_memory_pool(vm), n * sizeof(njs_unit_test_req_t)); if (njs_slow_path(requests == NULL)) { return NJS_ERROR; } for (i = 0; i < n; i++) { requests[i] = init[i].request; ret = njs_vm_external_create(vm, njs_value_arg(&requests[i].value), njs_external_r_proto_id, &requests[i], shared); if (njs_slow_path(ret != NJS_OK)) { njs_printf("njs_vm_external_create() failed\n"); return NJS_ERROR; } ret = njs_vm_bind(vm, &init[i].name, njs_value_arg(&requests[i].value), shared); if (njs_slow_path(ret != NJS_OK)) { njs_printf("njs_vm_bind() failed\n"); return NJS_ERROR; } for (j = 0; j < njs_nitems(init[i].props); j++) { ret = njs_vm_value_string_create(vm, njs_value_arg(&value), init[i].props[j].value.start, init[i].props[j].value.length); if (njs_slow_path(ret != NJS_OK)) { return NJS_ERROR; } prop = lvlhsh_unit_test_alloc(njs_vm_memory_pool(vm), &init[i].props[j].name, njs_value_arg(&value)); if (njs_slow_path(prop == NULL)) { njs_printf("lvlhsh_unit_test_alloc() failed\n"); return NJS_ERROR; } ret = lvlhsh_unit_test_add(njs_vm_memory_pool(vm), &requests[i], prop); if (njs_slow_path(ret != NJS_OK)) { njs_printf("lvlhsh_unit_test_add() failed\n"); return NJS_ERROR; } } } return NJS_OK; } static njs_int_t njs_externals_262_init(njs_vm_t *vm) { njs_int_t ret, proto_id; njs_opaque_value_t value; static const njs_str_t dollar_262 = njs_str("$262"); proto_id = njs_vm_external_prototype(vm, njs_unit_test_262_external, njs_nitems(njs_unit_test_262_external)); if (njs_slow_path(proto_id < 0)) { njs_printf("njs_vm_external_prototype() failed\n"); return NJS_ERROR; } ret = njs_vm_external_create(vm, njs_value_arg(&value), proto_id, NULL, 1); if (njs_slow_path(ret != NJS_OK)) { njs_printf("njs_vm_external_create() failed\n"); return NJS_ERROR; } ret = njs_vm_bind(vm, &dollar_262, njs_value_arg(&value), 1); if (njs_slow_path(ret != NJS_OK)) { njs_printf("njs_vm_bind() failed\n"); return NJS_ERROR; } return NJS_OK; } static njs_int_t njs_externals_shared_preinit(njs_vm_t *vm) { static const njs_str_t external_error = njs_str("ExternalError"); njs_external_r_proto_id = njs_vm_external_prototype(vm, njs_unit_test_r_external, njs_nitems(njs_unit_test_r_external)); if (njs_slow_path(njs_external_r_proto_id < 0)) { njs_printf("njs_vm_external_prototype() failed\n"); return NJS_ERROR; } njs_external_null_proto_id = njs_vm_external_prototype(vm, njs_unit_test_null_external, njs_nitems(njs_unit_test_null_external)); if (njs_slow_path(njs_external_null_proto_id < 0)) { njs_printf("njs_vm_external_prototype() failed\n"); return NJS_ERROR; } njs_external_error_ctor_id = njs_vm_external_constructor(vm, &external_error, njs_error_constructor, njs_unit_test_ctor_props, njs_nitems(njs_unit_test_ctor_props), njs_unit_test_proto_props, njs_nitems(njs_unit_test_proto_props)); if (njs_slow_path(njs_external_error_ctor_id < 0)) { njs_printf("njs_vm_external_constructor() failed\n"); return NJS_ERROR; } return NJS_OK; } static njs_int_t njs_externals_shared_init(njs_vm_t *vm) { njs_int_t ret; njs_function_t *f; njs_opaque_value_t value; static const njs_str_t external_ctor = njs_str("ExternalConstructor"); static const njs_str_t external_null = njs_str("ExternalNull"); f = njs_vm_function_alloc(vm, njs_unit_test_constructor, 1, 1); if (f == NULL) { njs_printf("njs_vm_function_alloc() failed\n"); return NJS_ERROR; } njs_value_function_set(njs_value_arg(&value), f); ret = njs_vm_bind(vm, &external_ctor, njs_value_arg(&value), 1); if (njs_slow_path(ret != NJS_OK)) { njs_printf("njs_vm_bind() failed\n"); return NJS_ERROR; } ret = njs_vm_external_create(vm, njs_value_arg(&value), njs_external_null_proto_id, NULL, 1); if (njs_slow_path(ret != NJS_OK)) { return NJS_ERROR; } ret = njs_vm_bind(vm, &external_null, njs_value_arg(&value), 1); if (njs_slow_path(ret != NJS_OK)) { njs_printf("njs_vm_bind() failed\n"); return NJS_ERROR; } return njs_externals_init_internal(vm, &njs_test_requests[0], 1, 1); } njs_int_t njs_externals_init(njs_vm_t *vm) { return njs_externals_init_internal(vm, &njs_test_requests[1], 3, 0); } njs_int_t njs_external_env_init(njs_external_env_t *env) { if (env != NULL) { njs_value_invalid_set(njs_value_arg(&env->retval)); njs_queue_init(&env->events); } return NJS_OK; } njs_int_t njs_external_process_events(njs_vm_t *vm, njs_external_env_t *env) { njs_int_t ret; njs_queue_t *events; njs_queue_link_t *link; njs_external_ev_t *ev; if (env == NULL) { return NJS_OK; } events = &env->events; for ( ;; ) { link = njs_queue_first(events); if (link == njs_queue_tail(events)) { break; } ev = njs_queue_link_data(link, njs_external_ev_t, link); njs_queue_remove(&ev->link); ev->link.prev = NULL; ev->link.next = NULL; ret = njs_vm_call(vm, ev->function, njs_value_arg(ev->args), ev->nargs); if (ret == NJS_ERROR) { return NJS_ERROR; } } return njs_vm_pending(vm) ? NJS_AGAIN: NJS_OK; } njs_int_t njs_external_call(njs_vm_t *vm, const njs_str_t *fname, njs_value_t *args, njs_uint_t nargs) { njs_int_t ret; njs_function_t *func; func = njs_vm_function(vm, fname); if (func == NULL) { njs_stderror("njs_external_call(): function \"%V\" not found\n", fname); return NJS_ERROR; } ret = njs_vm_call(vm, func, args, nargs); if (ret == NJS_ERROR) { return NJS_ERROR; } for ( ;; ) { ret = njs_vm_execute_pending_job(vm); if (ret <= NJS_OK) { if (ret == NJS_ERROR) { return NJS_ERROR; } break; } } return NJS_OK; }