This closes #16 issue on Github.
typedef struct {
- njs_vm_t *vm;
- ngx_array_t *paths;
- const njs_extern_t *req_proto;
+ njs_vm_t *vm;
+ ngx_array_t *paths;
+ njs_external_proto_t req_proto;
} ngx_http_js_main_conf_t;
typedef struct {
- ngx_str_t content;
+ ngx_str_t content;
} ngx_http_js_loc_conf_t;
typedef struct {
- njs_vm_t *vm;
- ngx_log_t *log;
- ngx_uint_t done;
- ngx_int_t status;
- njs_opaque_value_t request;
- njs_opaque_value_t request_body;
- ngx_str_t redirect_uri;
- njs_opaque_value_t promise_callbacks[2];
+ njs_vm_t *vm;
+ ngx_log_t *log;
+ ngx_uint_t done;
+ ngx_int_t status;
+ njs_opaque_value_t request;
+ njs_opaque_value_t request_body;
+ ngx_str_t redirect_uri;
+ njs_opaque_value_t promise_callbacks[2];
} ngx_http_js_ctx_t;
typedef struct {
- ngx_http_request_t *request;
- njs_vm_event_t vm_event;
- void *unused;
- ngx_int_t ident;
+ ngx_http_request_t *request;
+ njs_vm_event_t vm_event;
+ void *unused;
+ ngx_int_t ident;
} ngx_http_js_event_t;
static void ngx_http_js_cleanup_ctx(void *data);
static void ngx_http_js_cleanup_vm(void *data);
-static njs_int_t ngx_http_js_ext_get_string(njs_vm_t *vm, njs_value_t *value,
- void *obj, uintptr_t data);
-static njs_int_t ngx_http_js_ext_keys_header(njs_vm_t *vm, void *obj,
+static njs_int_t ngx_http_js_ext_get_string(njs_vm_t *vm,
+ njs_object_prop_t *prop, njs_value_t *value, njs_value_t *setval,
+ njs_value_t *retval);
+static njs_int_t ngx_http_js_ext_keys_header(njs_vm_t *vm, njs_value_t *value,
njs_value_t *keys, uintptr_t data);
static ngx_table_elt_t *ngx_http_js_get_header(ngx_list_part_t *part,
u_char *data, size_t len);
-static njs_int_t ngx_http_js_ext_get_header_out(njs_vm_t *vm,
- njs_value_t *value, void *obj, uintptr_t data);
-static njs_int_t ngx_http_js_ext_set_header_out(njs_vm_t *vm, void *obj,
- uintptr_t data, njs_str_t *value);
-static njs_int_t ngx_http_js_ext_delete_header_out(njs_vm_t *vm, void *obj,
- uintptr_t data, njs_bool_t delete);
-static njs_int_t ngx_http_js_ext_keys_header_out(njs_vm_t *vm, void *obj,
- njs_value_t *keys); /*FIXME*/
-static njs_int_t ngx_http_js_ext_get_status(njs_vm_t *vm, njs_value_t *value,
- void *obj, uintptr_t data);
-static njs_int_t ngx_http_js_ext_set_status(njs_vm_t *vm, void *obj,
- uintptr_t data, njs_str_t *value);
+static njs_int_t ngx_http_js_ext_header_out(njs_vm_t *vm,
+ njs_object_prop_t *prop, njs_value_t *value, njs_value_t *setval,
+ njs_value_t *retval);
+static njs_int_t ngx_http_js_ext_keys_header_out(njs_vm_t *vm,
+ njs_value_t *value, njs_value_t *keys);
+static njs_int_t ngx_http_js_ext_status(njs_vm_t *vm, njs_object_prop_t *prop,
+ njs_value_t *value, njs_value_t *setval, njs_value_t *retval);
static njs_int_t ngx_http_js_ext_send_header(njs_vm_t *vm, njs_value_t *args,
njs_uint_t nargs, njs_index_t unused);
static njs_int_t ngx_http_js_ext_send(njs_vm_t *vm, njs_value_t *args,
njs_value_t *args, njs_uint_t nargs, njs_index_t unused);
static njs_int_t ngx_http_js_ext_log(njs_vm_t *vm, njs_value_t *args,
- njs_uint_t nargs, njs_index_t unused);
-static njs_int_t ngx_http_js_ext_warn(njs_vm_t *vm, njs_value_t *args,
- njs_uint_t nargs, njs_index_t unused);
-static njs_int_t ngx_http_js_ext_error(njs_vm_t *vm, njs_value_t *args,
- njs_uint_t nargs, njs_index_t unused);
-static njs_int_t ngx_http_js_ext_log_core(njs_vm_t *vm, njs_value_t *args,
- njs_uint_t nargs, ngx_uint_t level);
+ njs_uint_t nargs, njs_index_t level);
static njs_int_t ngx_http_js_ext_get_http_version(njs_vm_t *vm,
- njs_value_t *value, void *obj, uintptr_t data);
+ njs_object_prop_t *prop, njs_value_t *value, njs_value_t *setval,
+ njs_value_t *retval);
static njs_int_t ngx_http_js_ext_get_remote_address(njs_vm_t *vm,
- njs_value_t *value, void *obj, uintptr_t data);
+ njs_object_prop_t *prop, njs_value_t *value, njs_value_t *setval,
+ njs_value_t *retval);
static njs_int_t ngx_http_js_ext_get_request_body(njs_vm_t *vm,
- njs_value_t *value, void *obj, uintptr_t data);
-static njs_int_t ngx_http_js_ext_get_header_in(njs_vm_t *vm, njs_value_t *value,
- void *obj, uintptr_t data);
-static njs_int_t ngx_http_js_ext_keys_header_in(njs_vm_t *vm, void *obj,
- njs_value_t *keys); /*FIXME*/
-static njs_int_t ngx_http_js_ext_get_arg(njs_vm_t *vm, njs_value_t *value,
- void *obj, uintptr_t data);
-static njs_int_t ngx_http_js_ext_keys_arg(njs_vm_t *vm, void *obj,
+ njs_object_prop_t *prop, njs_value_t *value, njs_value_t *setval,
+ njs_value_t *retval);
+static njs_int_t ngx_http_js_ext_get_header_in(njs_vm_t *vm,
+ njs_object_prop_t *prop, njs_value_t *value, njs_value_t *setval,
+ njs_value_t *retval);
+static njs_int_t ngx_http_js_ext_keys_header_in(njs_vm_t *vm,
+ njs_value_t *value, njs_value_t *keys);
+static njs_int_t ngx_http_js_ext_get_arg(njs_vm_t *vm,
+ njs_object_prop_t *prop, njs_value_t *value, njs_value_t *setval,
+ njs_value_t *retval);
+static njs_int_t ngx_http_js_ext_keys_arg(njs_vm_t *vm, njs_value_t *value,
njs_value_t *keys);
-static njs_int_t ngx_http_js_ext_get_variable(njs_vm_t *vm, njs_value_t *value,
- void *obj, uintptr_t data);
-static njs_int_t ngx_http_js_ext_set_variable(njs_vm_t *vm, void *obj,
- uintptr_t data, njs_str_t *value);
+static njs_int_t ngx_http_js_ext_variables(njs_vm_t *vm,
+ njs_object_prop_t *prop, njs_value_t *value, njs_value_t *setval,
+ njs_value_t *retval);
static njs_int_t ngx_http_js_ext_subrequest(njs_vm_t *vm, njs_value_t *args,
njs_uint_t nargs, njs_index_t unused);
static ngx_int_t ngx_http_js_subrequest(ngx_http_request_t *r,
ngx_http_request_t **sr);
static ngx_int_t ngx_http_js_subrequest_done(ngx_http_request_t *r,
void *data, ngx_int_t rc);
-static njs_int_t ngx_http_js_ext_get_parent(njs_vm_t *vm, njs_value_t *value,
- void *obj, uintptr_t data);
-static njs_int_t ngx_http_js_ext_get_reply_body(njs_vm_t *vm,
- njs_value_t *value, void *obj, uintptr_t data);
+static njs_int_t ngx_http_js_ext_get_parent(njs_vm_t *vm,
+ njs_object_prop_t *prop, njs_value_t *value, njs_value_t *setval,
+ njs_value_t *retval);
+static njs_int_t ngx_http_js_ext_get_response_body(njs_vm_t *vm,
+ njs_object_prop_t *prop, njs_value_t *value, njs_value_t *setval,
+ njs_value_t *retval);
static njs_host_event_t ngx_http_js_set_timer(njs_external_ptr_t external,
uint64_t delay, njs_vm_event_t vm_event);
static njs_external_t ngx_http_js_ext_request[] = {
- { njs_str("uri"),
- NJS_EXTERN_PROPERTY,
- NULL,
- 0,
- ngx_http_js_ext_get_string,
- NULL,
- NULL,
- NULL,
- NULL,
- offsetof(ngx_http_request_t, uri) },
-
- { njs_str("method"),
- NJS_EXTERN_PROPERTY,
- NULL,
- 0,
- ngx_http_js_ext_get_string,
- NULL,
- NULL,
- NULL,
- NULL,
- offsetof(ngx_http_request_t, method_name) },
-
- { njs_str("httpVersion"),
- NJS_EXTERN_PROPERTY,
- NULL,
- 0,
- ngx_http_js_ext_get_http_version,
- NULL,
- NULL,
- NULL,
- NULL,
- 0 },
-
- { njs_str("remoteAddress"),
- NJS_EXTERN_PROPERTY,
- NULL,
- 0,
- ngx_http_js_ext_get_remote_address,
- NULL,
- NULL,
- NULL,
- NULL,
- 0 },
-
- { njs_str("parent"),
- NJS_EXTERN_PROPERTY,
- NULL,
- 0,
- ngx_http_js_ext_get_parent,
- NULL,
- NULL,
- NULL,
- NULL,
- 0 },
-
- { njs_str("requestBody"),
- NJS_EXTERN_PROPERTY,
- NULL,
- 0,
- ngx_http_js_ext_get_request_body,
- NULL,
- NULL,
- NULL,
- NULL,
- 0 },
-
- { njs_str("responseBody"),
- NJS_EXTERN_PROPERTY,
- NULL,
- 0,
- ngx_http_js_ext_get_reply_body,
- NULL,
- NULL,
- NULL,
- NULL,
- 0 },
-
- { njs_str("headersIn"),
- NJS_EXTERN_OBJECT,
- NULL,
- 0,
- ngx_http_js_ext_get_header_in,
- NULL,
- NULL,
- ngx_http_js_ext_keys_header_in,
- NULL,
- 0 },
-
- { njs_str("args"),
- NJS_EXTERN_OBJECT,
- NULL,
- 0,
- ngx_http_js_ext_get_arg,
- NULL,
- NULL,
- ngx_http_js_ext_keys_arg,
- NULL,
- 0 },
-
- { njs_str("variables"),
- NJS_EXTERN_OBJECT,
- NULL,
- 0,
- ngx_http_js_ext_get_variable,
- ngx_http_js_ext_set_variable,
- NULL,
- NULL,
- NULL,
- 0 },
-
- { njs_str("status"),
- NJS_EXTERN_PROPERTY,
- NULL,
- 0,
- ngx_http_js_ext_get_status,
- ngx_http_js_ext_set_status,
- NULL,
- NULL,
- NULL,
- 0 },
-
- { njs_str("headersOut"),
- NJS_EXTERN_OBJECT,
- NULL,
- 0,
- ngx_http_js_ext_get_header_out,
- ngx_http_js_ext_set_header_out,
- ngx_http_js_ext_delete_header_out,
- ngx_http_js_ext_keys_header_out,
- NULL,
- 0 },
-
- { njs_str("subrequest"),
- NJS_EXTERN_METHOD,
- NULL,
- 0,
- NULL,
- NULL,
- NULL,
- NULL,
- ngx_http_js_ext_subrequest,
- 0 },
-
- { njs_str("log"),
- NJS_EXTERN_METHOD,
- NULL,
- 0,
- NULL,
- NULL,
- NULL,
- NULL,
- ngx_http_js_ext_log,
- 0 },
-
- { njs_str("warn"),
- NJS_EXTERN_METHOD,
- NULL,
- 0,
- NULL,
- NULL,
- NULL,
- NULL,
- ngx_http_js_ext_warn,
- 0 },
-
- { njs_str("error"),
- NJS_EXTERN_METHOD,
- NULL,
- 0,
- NULL,
- NULL,
- NULL,
- NULL,
- ngx_http_js_ext_error,
- 0 },
-
- { njs_str("sendHeader"),
- NJS_EXTERN_METHOD,
- NULL,
- 0,
- NULL,
- NULL,
- NULL,
- NULL,
- ngx_http_js_ext_send_header,
- 0 },
-
- { njs_str("send"),
- NJS_EXTERN_METHOD,
- NULL,
- 0,
- NULL,
- NULL,
- NULL,
- NULL,
- ngx_http_js_ext_send,
- 0 },
-
- { njs_str("finish"),
- NJS_EXTERN_METHOD,
- NULL,
- 0,
- NULL,
- NULL,
- NULL,
- NULL,
- ngx_http_js_ext_finish,
- 0 },
-
- { njs_str("return"),
- NJS_EXTERN_METHOD,
- NULL,
- 0,
- NULL,
- NULL,
- NULL,
- NULL,
- ngx_http_js_ext_return,
- 0 },
-
- { njs_str("internalRedirect"),
- NJS_EXTERN_METHOD,
- NULL,
- 0,
- NULL,
- NULL,
- NULL,
- NULL,
- ngx_http_js_ext_internal_redirect,
- 0 },
-};
+ {
+ .flags = NJS_EXTERN_PROPERTY | NJS_EXTERN_SYMBOL,
+ .name.symbol = NJS_SYMBOL_TO_STRING_TAG,
+ .u.property = {
+ .value = "Request",
+ }
+ },
+
+ {
+ .flags = NJS_EXTERN_PROPERTY,
+ .name.string = njs_str("uri"),
+ .enumerable = 1,
+ .u.property = {
+ .handler = ngx_http_js_ext_get_string,
+ .magic32 = offsetof(ngx_http_request_t, uri),
+ }
+ },
+
+ {
+ .flags = NJS_EXTERN_PROPERTY,
+ .name.string = njs_str("method"),
+ .enumerable = 1,
+ .u.property = {
+ .handler = ngx_http_js_ext_get_string,
+ .magic32 = offsetof(ngx_http_request_t, method_name),
+ }
+ },
+
+ {
+ .flags = NJS_EXTERN_PROPERTY,
+ .name.string = njs_str("httpVersion"),
+ .enumerable = 1,
+ .u.property = {
+ .handler = ngx_http_js_ext_get_http_version,
+ }
+ },
+
+ {
+ .flags = NJS_EXTERN_PROPERTY,
+ .name.string = njs_str("remoteAddress"),
+ .enumerable = 1,
+ .u.property = {
+ .handler = ngx_http_js_ext_get_remote_address,
+ }
+ },
+
+ {
+ .flags = NJS_EXTERN_PROPERTY,
+ .name.string = njs_str("requestBody"),
+ .enumerable = 1,
+ .u.property = {
+ .handler = ngx_http_js_ext_get_request_body,
+ }
+ },
+
+ {
+ .flags = NJS_EXTERN_PROPERTY,
+ .name.string = njs_str("parent"),
+ .u.property = {
+ .handler = ngx_http_js_ext_get_parent,
+ }
+ },
+
+ {
+ .flags = NJS_EXTERN_PROPERTY,
+ .name.string = njs_str("responseBody"),
+ .enumerable = 1,
+ .u.property = {
+ .handler = ngx_http_js_ext_get_response_body,
+ }
+ },
+
+ {
+ .flags = NJS_EXTERN_OBJECT,
+ .name.string = njs_str("headersIn"),
+ .enumerable = 1,
+ .u.object = {
+ .enumerable = 1,
+ .prop_handler = ngx_http_js_ext_get_header_in,
+ .keys = ngx_http_js_ext_keys_header_in,
+ }
+ },
+
+ {
+ .flags = NJS_EXTERN_OBJECT,
+ .name.string = njs_str("args"),
+ .enumerable = 1,
+ .u.object = {
+ .enumerable = 1,
+ .prop_handler = ngx_http_js_ext_get_arg,
+ .keys = ngx_http_js_ext_keys_arg,
+ }
+ },
+
+ {
+ .flags = NJS_EXTERN_OBJECT,
+ .name.string = njs_str("variables"),
+ .u.object = {
+ .writable = 1,
+ .prop_handler = ngx_http_js_ext_variables,
+ }
+ },
+
+ {
+ .flags = NJS_EXTERN_PROPERTY,
+ .name.string = njs_str("status"),
+ .writable = 1,
+ .enumerable = 1,
+ .u.property = {
+ .handler = ngx_http_js_ext_status,
+ }
+ },
+
+ {
+ .flags = NJS_EXTERN_OBJECT,
+ .name.string = njs_str("headersOut"),
+ .enumerable = 1,
+ .u.object = {
+ .writable = 1,
+ .configurable = 1,
+ .enumerable = 1,
+ .prop_handler = ngx_http_js_ext_header_out,
+ .keys = ngx_http_js_ext_keys_header_out,
+ }
+ },
+
+ {
+ .flags = NJS_EXTERN_METHOD,
+ .name.string = njs_str("subrequest"),
+ .writable = 1,
+ .configurable = 1,
+ .enumerable = 1,
+ .u.method = {
+ .native = ngx_http_js_ext_subrequest,
+ }
+ },
+
+ {
+ .flags = NJS_EXTERN_METHOD,
+ .name.string = njs_str("log"),
+ .writable = 1,
+ .configurable = 1,
+ .enumerable = 1,
+ .u.method = {
+ .native = ngx_http_js_ext_log,
+ .magic8 = NGX_LOG_INFO,
+ }
+ },
+
+ {
+ .flags = NJS_EXTERN_METHOD,
+ .name.string = njs_str("warn"),
+ .writable = 1,
+ .configurable = 1,
+ .enumerable = 1,
+ .u.method = {
+ .native = ngx_http_js_ext_log,
+ .magic8 = NGX_LOG_WARN,
+ }
+ },
+ {
+ .flags = NJS_EXTERN_METHOD,
+ .name.string = njs_str("error"),
+ .writable = 1,
+ .configurable = 1,
+ .enumerable = 1,
+ .u.method = {
+ .native = ngx_http_js_ext_log,
+ .magic8 = NGX_LOG_ERR,
+ }
+ },
-static njs_external_t ngx_http_js_externals[] = {
+ {
+ .flags = NJS_EXTERN_METHOD,
+ .name.string = njs_str("sendHeader"),
+ .writable = 1,
+ .configurable = 1,
+ .enumerable = 1,
+ .u.method = {
+ .native = ngx_http_js_ext_send_header,
+ }
+ },
+
+ {
+ .flags = NJS_EXTERN_METHOD,
+ .name.string = njs_str("send"),
+ .writable = 1,
+ .configurable = 1,
+ .enumerable = 1,
+ .u.method = {
+ .native = ngx_http_js_ext_send,
+ }
+ },
+
+ {
+ .flags = NJS_EXTERN_METHOD,
+ .name.string = njs_str("finish"),
+ .writable = 1,
+ .configurable = 1,
+ .enumerable = 1,
+ .u.method = {
+ .native = ngx_http_js_ext_finish,
+ }
+ },
+
+ {
+ .flags = NJS_EXTERN_METHOD,
+ .name.string = njs_str("return"),
+ .writable = 1,
+ .configurable = 1,
+ .enumerable = 1,
+ .u.method = {
+ .native = ngx_http_js_ext_return,
+ }
+ },
+
+ {
+ .flags = NJS_EXTERN_METHOD,
+ .name.string = njs_str("internalRedirect"),
+ .writable = 1,
+ .configurable = 1,
+ .enumerable = 1,
+ .u.method = {
+ .native = ngx_http_js_ext_internal_redirect,
+ }
+ },
- { njs_str("request"),
- NJS_EXTERN_OBJECT,
- ngx_http_js_ext_request,
- njs_nitems(ngx_http_js_ext_request),
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- 0 },
};
}
rc = njs_vm_external_create(ctx->vm, njs_value_arg(&ctx->request),
- jmcf->req_proto, r);
+ jmcf->req_proto, r, 0);
if (rc != NJS_OK) {
return NGX_ERROR;
}
static njs_int_t
-ngx_http_js_ext_get_string(njs_vm_t *vm, njs_value_t *value, void *obj,
- uintptr_t data)
+ngx_http_js_ext_get_string(njs_vm_t *vm, njs_object_prop_t *prop,
+ njs_value_t *value, njs_value_t *setval, njs_value_t *retval)
{
- char *p = obj;
-
+ char *p;
ngx_str_t *field;
- field = (ngx_str_t *) (p + data);
+ p = njs_vm_external(vm, value);
+ if (p == NULL) {
+ njs_value_undefined_set(retval);
+ return NJS_DECLINED;
+ }
+
+ field = (ngx_str_t *) (p + njs_vm_prop_magic32(prop));
- return njs_vm_value_string_set(vm, value, field->data, field->len);
+ return njs_vm_value_string_set(vm, retval, field->data, field->len);
}
static njs_int_t
-ngx_http_js_ext_keys_header(njs_vm_t *vm, void *obj, njs_value_t *keys,
+ngx_http_js_ext_keys_header(njs_vm_t *vm, njs_value_t *value, njs_value_t *keys,
uintptr_t data)
{
- char *p = obj;
-
+ char *p;
njs_int_t rc, cookie, x_for;
ngx_uint_t item;
ngx_list_t *headers;
- njs_value_t *value;
ngx_list_part_t *part;
ngx_table_elt_t *header, *h;
return NJS_ERROR;
}
+ p = njs_vm_external(vm, value);
+ if (p == NULL) {
+ return NJS_OK;
+ }
+
headers = (ngx_list_t *) (p + data);
part = &headers->part;
item = 0;
static njs_int_t
-ngx_http_js_ext_get_header_out(njs_vm_t *vm, njs_value_t *value, void *obj,
- uintptr_t data)
+ngx_http_js_ext_header_out(njs_vm_t *vm, njs_object_prop_t *prop,
+ njs_value_t *value, njs_value_t *setval, njs_value_t *retval)
{
u_char *p, *start;
- njs_str_t *v;
+ njs_int_t rc;
+ ngx_int_t n;
+ njs_str_t *v, s, name;
ngx_str_t *hdr;
ngx_table_elt_t *h;
ngx_http_request_t *r;
u_char content_len[NGX_OFF_T_LEN];
- r = (ngx_http_request_t *) obj;
- v = (njs_str_t *) data;
+ r = njs_vm_external(vm, value);
+ if (r == NULL) {
+ if (retval != NULL) {
+ njs_value_undefined_set(retval);
+ }
- if (v->length == njs_length("Content-Type")
- && ngx_strncasecmp(v->start, (u_char *) "Content-Type",
- v->length) == 0)
- {
- hdr = &r->headers_out.content_type;
- return njs_vm_value_string_set(vm, value, hdr->data, hdr->len);
+ return NJS_DECLINED;
}
- if (v->length == njs_length("Content-Length")
- && ngx_strncasecmp(v->start, (u_char *) "Content-Length",
- v->length) == 0)
- {
- if (r->headers_out.content_length == NULL
- && r->headers_out.content_length_n >= 0)
- {
- p = ngx_sprintf(content_len, "%O", r->headers_out.content_length_n);
+ rc = njs_vm_prop_name(vm, prop, &name);
+ if (rc != NJS_OK) {
+ if (retval != NULL) {
+ njs_value_undefined_set(retval);
+ }
- start = njs_vm_value_string_alloc(vm, value, p - content_len);
- if (start == NULL) {
- return NJS_ERROR;
- }
+ return NJS_DECLINED;
+ }
- ngx_memcpy(start, content_len, p - content_len);
+ v = &name;
- return NJS_OK;
+ if (retval != NULL && setval == NULL) {
+ if (v->length == njs_length("Content-Type")
+ && ngx_strncasecmp(v->start, (u_char *) "Content-Type",
+ v->length) == 0)
+ {
+ hdr = &r->headers_out.content_type;
+ return njs_vm_value_string_set(vm, retval, hdr->data, hdr->len);
}
- }
- h = ngx_http_js_get_header(&r->headers_out.headers.part, v->start,
- v->length);
- if (h == NULL) {
- njs_value_undefined_set(value);
- return NJS_OK;
- }
+ if (v->length == njs_length("Content-Length")
+ && ngx_strncasecmp(v->start, (u_char *) "Content-Length",
+ v->length) == 0)
+ {
+ if (r->headers_out.content_length == NULL
+ && r->headers_out.content_length_n >= 0)
+ {
+ p = ngx_sprintf(content_len, "%O",
+ r->headers_out.content_length_n);
+
+ start = njs_vm_value_string_alloc(vm, retval, p - content_len);
+ if (start == NULL) {
+ return NJS_ERROR;
+ }
- return njs_vm_value_string_set(vm, value, h->value.data, h->value.len);
-}
+ ngx_memcpy(start, content_len, p - content_len);
+ return NJS_OK;
+ }
+ }
-static njs_int_t
-ngx_http_js_ext_set_header_out(njs_vm_t *vm, void *obj, uintptr_t data,
- njs_str_t *value)
-{
- u_char *p;
- ngx_int_t n;
- njs_str_t *v;
- ngx_table_elt_t *h;
- ngx_http_request_t *r;
+ h = ngx_http_js_get_header(&r->headers_out.headers.part, v->start,
+ v->length);
+ if (h == NULL) {
+ njs_value_undefined_set(retval);
+ return NJS_DECLINED;
+ }
- r = (ngx_http_request_t *) obj;
- v = (njs_str_t *) data;
+ return njs_vm_value_string_set(vm, retval, h->value.data, h->value.len);
+ }
+
+ if (setval != NULL) {
+ rc = ngx_http_js_string(vm, setval, &s);
+ if (rc != NJS_OK) {
+ return NJS_ERROR;
+ }
+
+ } else {
+ s.length = 0;
+ s.start = NULL;
+ }
if (v->length == njs_length("Content-Type")
&& ngx_strncasecmp(v->start, (u_char *) "Content-Type",
v->length) == 0)
{
- r->headers_out.content_type.len = value->length;
+ r->headers_out.content_type.len = s.length;
r->headers_out.content_type_len = r->headers_out.content_type.len;
- r->headers_out.content_type.data = value->start;
+ r->headers_out.content_type.data = s.start;
r->headers_out.content_type_lowcase = NULL;
return NJS_OK;
h = ngx_http_js_get_header(&r->headers_out.headers.part, v->start,
v->length);
- if (h != NULL && value->length == 0) {
+ if (h != NULL && s.length == 0) {
h->hash = 0;
h = NULL;
}
- if (h == NULL && value->length != 0) {
+ if (h == NULL && s.length != 0) {
h = ngx_list_push(&r->headers_out.headers);
if (h == NULL) {
return NJS_ERROR;
}
if (h != NULL) {
- p = ngx_pnalloc(r->pool, value->length);
+ p = ngx_pnalloc(r->pool, s.length);
if (p == NULL) {
return NJS_ERROR;
}
- ngx_memcpy(p, value->start, value->length);
+ ngx_memcpy(p, s.start, s.length);
h->value.data = p;
- h->value.len = value->length;
+ h->value.len = s.length;
h->hash = 1;
}
v->length) == 0)
{
if (h != NULL) {
- n = ngx_atoi(value->start, value->length);
+ n = ngx_atoi(s.start, s.length);
if (n == NGX_ERROR) {
h->hash = 0;
njs_vm_error(vm, "failed converting argument to integer");
static njs_int_t
-ngx_http_js_ext_delete_header_out(njs_vm_t *vm, void *obj, uintptr_t data,
- njs_bool_t unused)
+ngx_http_js_ext_keys_header_out(njs_vm_t *vm, njs_value_t *value,
+ njs_value_t *keys)
{
- njs_str_t value;
-
- value = njs_str_value("");
-
- return ngx_http_js_ext_set_header_out(vm, obj, data, &value);
-}
-
-
-static njs_int_t
-ngx_http_js_ext_keys_header_out(njs_vm_t *vm, void *obj, njs_value_t *keys)
-{
- return ngx_http_js_ext_keys_header(vm, obj, keys,
+ return ngx_http_js_ext_keys_header(vm, value, keys,
offsetof(ngx_http_request_t, headers_out.headers));
}
static njs_int_t
-ngx_http_js_ext_get_status(njs_vm_t *vm, njs_value_t *value, void *obj,
- uintptr_t data)
+ngx_http_js_ext_status(njs_vm_t *vm, njs_object_prop_t *prop,
+ njs_value_t *value, njs_value_t *setval, njs_value_t *retval)
{
+ njs_int_t rc;
+ ngx_int_t n;
+ njs_str_t s;
ngx_http_request_t *r;
- r = (ngx_http_request_t *) obj;
-
- njs_value_number_set(value, r->headers_out.status);
-
- return NJS_OK;
-}
+ r = njs_vm_external(vm, value);
+ if (r == NULL) {
+ njs_value_undefined_set(retval);
+ return NJS_DECLINED;
+ }
+ if (setval == NULL) {
+ njs_value_number_set(retval, r->headers_out.status);
+ return NJS_OK;
+ }
-static njs_int_t
-ngx_http_js_ext_set_status(njs_vm_t *vm, void *obj, uintptr_t data,
- njs_str_t *value)
-{
- ngx_int_t n;
- ngx_http_request_t *r;
+ rc = ngx_http_js_string(vm, setval, &s);
+ if (rc != NJS_OK) {
+ return NJS_ERROR;
+ }
- n = ngx_atoi(value->start, value->length);
+ n = ngx_atoi(s.start, s.length);
if (n == NGX_ERROR) {
return NJS_ERROR;
}
- r = (ngx_http_request_t *) obj;
-
r->headers_out.status = n;
return NJS_OK;
ngx_http_request_t *r;
r = njs_vm_external(vm, njs_arg(args, nargs, 0));
- if (njs_slow_path(r == NULL)) {
+ if (r == NULL) {
+ njs_vm_error(vm, "\"this\" is not an external");
return NJS_ERROR;
}
ngx_http_request_t *r;
r = njs_vm_external(vm, njs_arg(args, nargs, 0));
- if (njs_slow_path(r == NULL)) {
+ if (r == NULL) {
+ njs_vm_error(vm, "\"this\" is not an external");
return NJS_ERROR;
}
ngx_http_request_t *r;
r = njs_vm_external(vm, njs_arg(args, nargs, 0));
- if (njs_slow_path(r == NULL)) {
+ if (r == NULL) {
+ njs_vm_error(vm, "\"this\" is not an external");
return NJS_ERROR;
}
ngx_http_complex_value_t cv;
r = njs_vm_external(vm, njs_arg(args, nargs, 0));
- if (njs_slow_path(r == NULL)) {
+ if (r == NULL) {
+ njs_vm_error(vm, "\"this\" is not an external");
return NJS_ERROR;
}
ngx_http_request_t *r;
r = njs_vm_external(vm, njs_arg(args, nargs, 0));
- if (njs_slow_path(r == NULL)) {
+ if (r == NULL) {
+ njs_vm_error(vm, "\"this\" is not an external");
return NJS_ERROR;
}
static njs_int_t
ngx_http_js_ext_log(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
- njs_index_t unused)
-{
- return ngx_http_js_ext_log_core(vm, args, nargs, NGX_LOG_INFO);
-}
-
-
-static njs_int_t
-ngx_http_js_ext_warn(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
- njs_index_t unused)
-{
- return ngx_http_js_ext_log_core(vm, args, nargs, NGX_LOG_WARN);
-}
-
-
-static njs_int_t
-ngx_http_js_ext_error(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
- njs_index_t unused)
-{
- return ngx_http_js_ext_log_core(vm, args, nargs, NGX_LOG_ERR);
-}
-
-
-static njs_int_t
-ngx_http_js_ext_log_core(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
- ngx_uint_t level)
+ njs_index_t level)
{
njs_str_t msg;
ngx_connection_t *c;
ngx_http_request_t *r;
r = njs_vm_external(vm, njs_arg(args, nargs, 0));
- if (njs_slow_path(r == NULL)) {
+ if (r == NULL) {
return NJS_ERROR;
}
static njs_int_t
-ngx_http_js_ext_get_http_version(njs_vm_t *vm, njs_value_t *value, void *obj,
- uintptr_t data)
+ngx_http_js_ext_get_http_version(njs_vm_t *vm, njs_object_prop_t *prop,
+ njs_value_t *value, njs_value_t *setval, njs_value_t *retval)
{
ngx_str_t v;
ngx_http_request_t *r;
- r = (ngx_http_request_t *) obj;
+ r = njs_vm_external(vm, value);
+ if (r == NULL) {
+ njs_value_undefined_set(retval);
+ return NJS_DECLINED;
+ }
switch (r->http_version) {
break;
}
- return njs_vm_value_string_set(vm, value, v.data, v.len);
+ return njs_vm_value_string_set(vm, retval, v.data, v.len);
}
static njs_int_t
-ngx_http_js_ext_get_remote_address(njs_vm_t *vm, njs_value_t *value, void *obj,
- uintptr_t data)
+ngx_http_js_ext_get_remote_address(njs_vm_t *vm, njs_object_prop_t *prop,
+ njs_value_t *value, njs_value_t *setval, njs_value_t *retval)
{
ngx_connection_t *c;
ngx_http_request_t *r;
- r = (ngx_http_request_t *) obj;
+ r = njs_vm_external(vm, value);
+ if (r == NULL) {
+ njs_value_undefined_set(retval);
+ return NJS_DECLINED;
+ }
+
c = r->connection;
- return njs_vm_value_string_set(vm, value, c->addr_text.data,
+ return njs_vm_value_string_set(vm, retval, c->addr_text.data,
c->addr_text.len);
}
static njs_int_t
-ngx_http_js_ext_get_request_body(njs_vm_t *vm, njs_value_t *value, void *obj,
- uintptr_t data)
+ngx_http_js_ext_get_request_body(njs_vm_t *vm, njs_object_prop_t *prop,
+ njs_value_t *value, njs_value_t *setval, njs_value_t *retval)
{
u_char *p, *body;
size_t len;
ngx_http_js_ctx_t *ctx;
ngx_http_request_t *r;
- r = (ngx_http_request_t *) obj;
+ r = njs_vm_external(vm, value);
+ if (r == NULL) {
+ njs_value_undefined_set(retval);
+ return NJS_DECLINED;
+ }
ctx = ngx_http_get_module_ctx(r, ngx_http_js_module);
request_body = (njs_value_t *) &ctx->request_body;
if (!njs_value_is_null(request_body)) {
- njs_value_assign(value, request_body);
+ njs_value_assign(retval, request_body);
return NJS_OK;
}
if (r->request_body == NULL || r->request_body->bufs == NULL) {
- njs_value_undefined_set(value);
- return NJS_OK;
+ njs_value_undefined_set(retval);
+ return NJS_DECLINED;
}
if (r->request_body->temp_file) {
return NJS_ERROR;
}
- njs_value_assign(value, request_body);
+ njs_value_assign(retval, request_body);
return NJS_OK;
}
static njs_int_t
-ngx_http_js_ext_get_header_in(njs_vm_t *vm, njs_value_t *value, void *obj,
- uintptr_t data)
+ngx_http_js_ext_get_header_in(njs_vm_t *vm, njs_object_prop_t *prop,
+ njs_value_t *value, njs_value_t *setval, njs_value_t *retval)
{
u_char *p, *end, sep;
size_t len;
- njs_str_t *v;
+ njs_int_t rc;
+ njs_str_t *v, name;
ngx_uint_t i, n;
ngx_array_t *a;
ngx_table_elt_t *h, **hh;
ngx_http_request_t *r;
- r = (ngx_http_request_t *) obj;
- v = (njs_str_t *) data;
+ r = njs_vm_external(vm, value);
+ if (r == NULL) {
+ njs_value_undefined_set(retval);
+ return NJS_DECLINED;
+ }
+
+ rc = njs_vm_prop_name(vm, prop, &name);
+ if (rc != NJS_OK) {
+ njs_value_undefined_set(retval);
+ return NJS_DECLINED;
+ }
+
+ v = &name;
if (v->length == njs_length("Cookie")
&& ngx_strncasecmp(v->start, (u_char *) "Cookie",
h = ngx_http_js_get_header(&r->headers_in.headers.part, v->start,
v->length);
if (h == NULL) {
- njs_value_undefined_set(value);
- return NJS_OK;
+ njs_value_undefined_set(retval);
+ return NJS_DECLINED;
}
- return njs_vm_value_string_set(vm, value, h->value.data, h->value.len);
+ return njs_vm_value_string_set(vm, retval, h->value.data, h->value.len);
multi:
}
if (len == 0) {
- njs_value_undefined_set(value);
- return NJS_OK;
+ njs_value_undefined_set(retval);
+ return NJS_DECLINED;
}
len -= 2;
if (n == 1) {
- return njs_vm_value_string_set(vm, value, (*hh)->value.data,
+ return njs_vm_value_string_set(vm, retval, (*hh)->value.data,
(*hh)->value.len);
}
- p = njs_vm_value_string_alloc(vm, value, len);
+ p = njs_vm_value_string_alloc(vm, retval, len);
if (p == NULL) {
return NJS_ERROR;
}
static njs_int_t
-ngx_http_js_ext_keys_header_in(njs_vm_t *vm, void *obj, njs_value_t *keys)
+ngx_http_js_ext_keys_header_in(njs_vm_t *vm, njs_value_t *value,
+ njs_value_t *keys)
{
- return ngx_http_js_ext_keys_header(vm, obj, keys,
+ return ngx_http_js_ext_keys_header(vm, value, keys,
offsetof(ngx_http_request_t, headers_in.headers));
}
static njs_int_t
-ngx_http_js_ext_get_arg(njs_vm_t *vm, njs_value_t *value, void *obj,
- uintptr_t data)
+ngx_http_js_ext_get_arg(njs_vm_t *vm, njs_object_prop_t *prop,
+ njs_value_t *value, njs_value_t *setval, njs_value_t *retval)
{
- njs_str_t *v;
+ njs_int_t rc;
+ njs_str_t *v, key;
ngx_str_t arg;
ngx_http_request_t *r;
- r = (ngx_http_request_t *) obj;
- v = (njs_str_t *) data;
+ r = njs_vm_external(vm, value);
+ if (r == NULL) {
+ njs_value_undefined_set(retval);
+ return NJS_DECLINED;
+ }
+
+ rc = njs_vm_prop_name(vm, prop, &key);
+ if (rc != NJS_OK) {
+ njs_value_undefined_set(retval);
+ return NJS_DECLINED;
+ }
+
+ v = &key;
if (ngx_http_arg(r, v->start, v->length, &arg) == NGX_OK) {
- return njs_vm_value_string_set(vm, value, arg.data, arg.len);
+ return njs_vm_value_string_set(vm, retval, arg.data, arg.len);
}
- njs_value_undefined_set(value);
+ njs_value_undefined_set(retval);
- return NJS_OK;
+ return NJS_DECLINED;
}
static njs_int_t
-ngx_http_js_ext_keys_arg(njs_vm_t *vm, void *obj, njs_value_t *keys)
+ngx_http_js_ext_keys_arg(njs_vm_t *vm, njs_value_t *value, njs_value_t *keys)
{
u_char *v, *p, *start, *end;
njs_int_t rc;
- njs_value_t *value;
ngx_http_request_t *r;
- r = (ngx_http_request_t *) obj;
-
rc = njs_vm_array_alloc(vm, keys, 8);
if (rc != NJS_OK) {
return NJS_ERROR;
}
+ r = njs_vm_external(vm, value);
+ if (r == NULL) {
+ return NJS_OK;
+ }
+
start = r->args.data;
end = start + r->args.len;
static njs_int_t
-ngx_http_js_ext_get_variable(njs_vm_t *vm, njs_value_t *value, void *obj,
- uintptr_t data)
+ngx_http_js_ext_variables(njs_vm_t *vm, njs_object_prop_t *prop,
+ njs_value_t *value, njs_value_t *setval, njs_value_t *retval)
{
- njs_str_t *v;
+ njs_int_t rc;
+ njs_str_t val, s;
ngx_str_t name;
ngx_uint_t key;
ngx_http_request_t *r;
+ ngx_http_variable_t *v;
+ ngx_http_core_main_conf_t *cmcf;
ngx_http_variable_value_t *vv;
- r = (ngx_http_request_t *) obj;
- v = (njs_str_t *) data;
-
- name.data = v->start;
- name.len = v->length;
-
- key = ngx_hash_strlow(name.data, name.data, name.len);
+ r = njs_vm_external(vm, value);
+ if (r == NULL) {
+ njs_value_undefined_set(retval);
+ return NJS_DECLINED;
+ }
- vv = ngx_http_get_variable(r, &name, key);
- if (vv == NULL || vv->not_found) {
- njs_value_undefined_set(value);
- return NJS_OK;
+ rc = njs_vm_prop_name(vm, prop, &val);
+ if (rc != NJS_OK) {
+ njs_value_undefined_set(retval);
+ return NJS_DECLINED;
}
- return njs_vm_value_string_set(vm, value, vv->data, vv->len);
-}
+ name.data = val.start;
+ name.len = val.length;
+ if (setval == NULL) {
+ key = ngx_hash_strlow(name.data, name.data, name.len);
-static njs_int_t
-ngx_http_js_ext_set_variable(njs_vm_t *vm, void *obj, uintptr_t data,
- njs_str_t *value)
-{
- njs_str_t *val;
- ngx_str_t name;
- ngx_uint_t key;
- ngx_http_request_t *r;
- ngx_http_variable_t *v;
- ngx_http_variable_value_t *vv;
- ngx_http_core_main_conf_t *cmcf;
-
- r = (ngx_http_request_t *) obj;
- val = (njs_str_t *) data;
+ vv = ngx_http_get_variable(r, &name, key);
+ if (vv == NULL || vv->not_found) {
+ njs_value_undefined_set(retval);
+ return NJS_DECLINED;
+ }
- name.data = val->start;
- name.len = val->length;
+ return njs_vm_value_string_set(vm, retval, vv->data, vv->len);
+ }
cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
return NJS_ERROR;
}
+ rc = ngx_http_js_string(vm, setval, &s);
+ if (rc != NJS_OK) {
+ return NJS_ERROR;
+ }
+
if (v->set_handler != NULL) {
vv = ngx_pcalloc(r->pool, sizeof(ngx_http_variable_value_t));
if (vv == NULL) {
vv->valid = 1;
vv->not_found = 0;
- vv->data = value->start;
- vv->len = value->length;
+ vv->data = s.start;
+ vv->len = s.length;
v->set_handler(r, vv, v->data);
vv->valid = 1;
vv->not_found = 0;
- vv->data = ngx_pnalloc(r->pool, value->length);
+ vv->data = ngx_pnalloc(r->pool, s.length);
if (vv->data == NULL) {
njs_vm_error(vm, "internal error");
return NJS_ERROR;
}
- vv->len = value->length;
- ngx_memcpy(vv->data, value->start, vv->len);
+ vv->len = s.length;
+ ngx_memcpy(vv->data, s.start, vv->len);
return NJS_OK;
}
static const njs_str_t detached_key = njs_str("detached");
r = njs_vm_external(vm, njs_arg(args, nargs, 0));
- if (njs_slow_path(r == NULL)) {
- njs_vm_error(vm, "this is not an external");
+ if (r == NULL) {
+ njs_vm_error(vm, "\"this\" is not an external");
return NJS_ERROR;
}
}
ret = njs_vm_external_create(ctx->vm, njs_value_arg(&reply),
- jmcf->req_proto, r);
+ jmcf->req_proto, r, 0);
if (ret != NJS_OK) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"js subrequest reply creation failed");
static njs_int_t
-ngx_http_js_ext_get_parent(njs_vm_t *vm, njs_value_t *value, void *obj,
- uintptr_t data)
+ngx_http_js_ext_get_parent(njs_vm_t *vm, njs_object_prop_t *prop,
+ njs_value_t *value, njs_value_t *setval, njs_value_t *retval)
{
ngx_http_js_ctx_t *ctx;
ngx_http_request_t *r;
- r = (ngx_http_request_t *) obj;
+ r = njs_vm_external(vm, value);
+ if (r == NULL) {
+ njs_value_undefined_set(retval);
+ return NJS_DECLINED;
+ }
ctx = r->parent ? ngx_http_get_module_ctx(r->parent, ngx_http_js_module)
: NULL;
if (ctx == NULL || ctx->vm != vm) {
- njs_value_undefined_set(value);
- return NJS_OK;
+ njs_value_undefined_set(retval);
+ return NJS_DECLINED;
}
- njs_value_assign(value, njs_value_arg(&ctx->request));
+ njs_value_assign(retval, njs_value_arg(&ctx->request));
return NJS_OK;
}
static njs_int_t
-ngx_http_js_ext_get_reply_body(njs_vm_t *vm, njs_value_t *value, void *obj,
- uintptr_t data)
+ngx_http_js_ext_get_response_body(njs_vm_t *vm, njs_object_prop_t *prop,
+ njs_value_t *value, njs_value_t *setval, njs_value_t *retval)
{
size_t len;
u_char *p;
ngx_buf_t *b;
ngx_http_request_t *r;
- r = (ngx_http_request_t *) obj;
+ r = njs_vm_external(vm, value);
+ if (r == NULL) {
+ njs_value_undefined_set(retval);
+ return NJS_DECLINED;
+ }
b = r->out ? r->out->buf : NULL;
len = b ? b->last - b->pos : 0;
- p = njs_vm_value_string_alloc(vm, value, len);
+ p = njs_vm_value_string_alloc(vm, retval, len);
if (p == NULL) {
return NJS_ERROR;
}
njs_vm_opt_t options;
ngx_file_info_t fi;
ngx_pool_cleanup_t *cln;
+ njs_external_proto_t proto;
if (jmcf->vm) {
return "is duplicate";
}
}
- jmcf->req_proto = njs_vm_external_prototype(jmcf->vm,
- &ngx_http_js_externals[0]);
- if (jmcf->req_proto == NULL) {
+ proto = njs_vm_external_prototype(jmcf->vm, ngx_http_js_ext_request,
+ njs_nitems(ngx_http_js_ext_request));
+ if (proto == NULL) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "failed to add request proto");
return NGX_CONF_ERROR;
}
+ jmcf->req_proto = proto;
+
rc = njs_vm_compile(jmcf->vm, &start, end);
if (rc != NJS_OK) {
typedef struct {
njs_vm_t *vm;
ngx_array_t *paths;
- const njs_extern_t *proto;
+ njs_external_proto_t proto;
} ngx_stream_js_main_conf_t;
njs_str_t *event);
static njs_int_t ngx_stream_js_ext_get_remote_address(njs_vm_t *vm,
- njs_value_t *value, void *obj, uintptr_t data);
+ njs_object_prop_t *prop, njs_value_t *value, njs_value_t *setval,
+ njs_value_t *retval);
static njs_int_t ngx_stream_js_ext_done(njs_vm_t *vm, njs_value_t *args,
njs_uint_t nargs, njs_index_t unused);
-static njs_int_t ngx_stream_js_ext_deny(njs_vm_t *vm, njs_value_t *args,
- njs_uint_t nargs, njs_index_t unused);
-static njs_int_t ngx_stream_js_ext_decline(njs_vm_t *vm, njs_value_t *args,
- njs_uint_t nargs, njs_index_t unused);
-static njs_int_t ngx_stream_js_ext_set_status(njs_vm_t *vm, njs_value_t *args,
- njs_uint_t nargs, ngx_int_t status);
static njs_int_t ngx_stream_js_ext_log(njs_vm_t *vm, njs_value_t *args,
njs_uint_t nargs, njs_index_t unused);
-static njs_int_t ngx_stream_js_ext_warn(njs_vm_t *vm, njs_value_t *args,
- njs_uint_t nargs, njs_index_t unused);
-static njs_int_t ngx_stream_js_ext_error(njs_vm_t *vm, njs_value_t *args,
- njs_uint_t nargs, njs_index_t unused);
-static njs_int_t ngx_stream_js_ext_log_core(njs_vm_t *vm, njs_value_t *args,
- njs_uint_t nargs, ngx_uint_t level);
static njs_int_t ngx_stream_js_ext_on(njs_vm_t *vm, njs_value_t *args,
njs_uint_t nargs, njs_index_t unused);
static njs_int_t ngx_stream_js_ext_off(njs_vm_t *vm, njs_value_t *args,
static njs_int_t ngx_stream_js_ext_send(njs_vm_t *vm, njs_value_t *args,
njs_uint_t nargs, njs_index_t unused);
-static njs_int_t ngx_stream_js_ext_get_variable(njs_vm_t *vm,
- njs_value_t *value, void *obj, uintptr_t data);
-static njs_int_t ngx_stream_js_ext_set_variable(njs_vm_t *vm, void *obj,
- uintptr_t data, njs_str_t *value);
+static njs_int_t ngx_stream_js_ext_variables(njs_vm_t *vm,
+ njs_object_prop_t *prop, njs_value_t *value, njs_value_t *setval,
+ njs_value_t *retval);
static njs_host_event_t ngx_stream_js_set_timer(njs_external_ptr_t external,
uint64_t delay, njs_vm_event_t vm_event);
static njs_external_t ngx_stream_js_ext_session[] = {
- { njs_str("remoteAddress"),
- NJS_EXTERN_PROPERTY,
- NULL,
- 0,
- ngx_stream_js_ext_get_remote_address,
- NULL,
- NULL,
- NULL,
- NULL,
- 0 },
-
- { njs_str("variables"),
- NJS_EXTERN_OBJECT,
- NULL,
- 0,
- ngx_stream_js_ext_get_variable,
- ngx_stream_js_ext_set_variable,
- NULL,
- NULL,
- NULL,
- 0 },
-
- { njs_str("allow"),
- NJS_EXTERN_METHOD,
- NULL,
- 0,
- NULL,
- NULL,
- NULL,
- NULL,
- ngx_stream_js_ext_done,
- 0 },
-
- { njs_str("deny"),
- NJS_EXTERN_METHOD,
- NULL,
- 0,
- NULL,
- NULL,
- NULL,
- NULL,
- ngx_stream_js_ext_deny,
- 0 },
-
- { njs_str("decline"),
- NJS_EXTERN_METHOD,
- NULL,
- 0,
- NULL,
- NULL,
- NULL,
- NULL,
- ngx_stream_js_ext_decline,
- 0 },
-
- { njs_str("done"),
- NJS_EXTERN_METHOD,
- NULL,
- 0,
- NULL,
- NULL,
- NULL,
- NULL,
- ngx_stream_js_ext_done,
- 0 },
-
- { njs_str("log"),
- NJS_EXTERN_METHOD,
- NULL,
- 0,
- NULL,
- NULL,
- NULL,
- NULL,
- ngx_stream_js_ext_log,
- 0 },
-
- { njs_str("warn"),
- NJS_EXTERN_METHOD,
- NULL,
- 0,
- NULL,
- NULL,
- NULL,
- NULL,
- ngx_stream_js_ext_warn,
- 0 },
-
- { njs_str("error"),
- NJS_EXTERN_METHOD,
- NULL,
- 0,
- NULL,
- NULL,
- NULL,
- NULL,
- ngx_stream_js_ext_error,
- 0 },
-
- { njs_str("on"),
- NJS_EXTERN_METHOD,
- NULL,
- 0,
- NULL,
- NULL,
- NULL,
- NULL,
- ngx_stream_js_ext_on,
- 0 },
-
- { njs_str("off"),
- NJS_EXTERN_METHOD,
- NULL,
- 0,
- NULL,
- NULL,
- NULL,
- NULL,
- ngx_stream_js_ext_off,
- 0 },
-
- { njs_str("send"),
- NJS_EXTERN_METHOD,
- NULL,
- 0,
- NULL,
- NULL,
- NULL,
- NULL,
- ngx_stream_js_ext_send,
- 0 },
+ {
+ .flags = NJS_EXTERN_PROPERTY | NJS_EXTERN_SYMBOL,
+ .name.symbol = NJS_SYMBOL_TO_STRING_TAG,
+ .u.property = {
+ .value = "Stream Session",
+ }
+ },
-};
+ {
+ .flags = NJS_EXTERN_PROPERTY,
+ .name.string = njs_str("remoteAddress"),
+ .enumerable = 1,
+ .u.property = {
+ .handler = ngx_stream_js_ext_get_remote_address,
+ }
+ },
+ {
+ .flags = NJS_EXTERN_OBJECT,
+ .name.string = njs_str("variables"),
+ .u.object = {
+ .writable = 1,
+ .prop_handler = ngx_stream_js_ext_variables,
+ }
+ },
-static njs_external_t ngx_stream_js_externals[] = {
+ {
+ .flags = NJS_EXTERN_METHOD,
+ .name.string = njs_str("allow"),
+ .writable = 1,
+ .configurable = 1,
+ .enumerable = 1,
+ .u.method = {
+ .native = ngx_stream_js_ext_done,
+ .magic8 = NGX_OK,
+ }
+ },
+
+ {
+ .flags = NJS_EXTERN_METHOD,
+ .name.string = njs_str("deny"),
+ .writable = 1,
+ .configurable = 1,
+ .enumerable = 1,
+ .u.method = {
+ .native = ngx_stream_js_ext_done,
+ .magic8 = -NGX_DONE,
+ }
+ },
+
+ {
+ .flags = NJS_EXTERN_METHOD,
+ .name.string = njs_str("decline"),
+ .writable = 1,
+ .configurable = 1,
+ .enumerable = 1,
+ .u.method = {
+ .native = ngx_stream_js_ext_done,
+ .magic8 = -NGX_DECLINED,
+ }
+ },
+
+ {
+ .flags = NJS_EXTERN_METHOD,
+ .name.string = njs_str("done"),
+ .writable = 1,
+ .configurable = 1,
+ .enumerable = 1,
+ .u.method = {
+ .native = ngx_stream_js_ext_done,
+ .magic8 = NGX_OK,
+
+ }
+ },
+
+ {
+ .flags = NJS_EXTERN_METHOD,
+ .name.string = njs_str("log"),
+ .writable = 1,
+ .configurable = 1,
+ .enumerable = 1,
+ .u.method = {
+ .native = ngx_stream_js_ext_log,
+ .magic8 = NGX_LOG_INFO,
+ }
+ },
+
+ {
+ .flags = NJS_EXTERN_METHOD,
+ .name.string = njs_str("warn"),
+ .writable = 1,
+ .configurable = 1,
+ .enumerable = 1,
+ .u.method = {
+ .native = ngx_stream_js_ext_log,
+ .magic8 = NGX_LOG_WARN,
+ }
+ },
+
+ {
+ .flags = NJS_EXTERN_METHOD,
+ .name.string = njs_str("error"),
+ .writable = 1,
+ .configurable = 1,
+ .enumerable = 1,
+ .u.method = {
+ .native = ngx_stream_js_ext_log,
+ .magic8 = NGX_LOG_ERR,
+ }
+ },
+
+ {
+ .flags = NJS_EXTERN_METHOD,
+ .name.string = njs_str("on"),
+ .writable = 1,
+ .configurable = 1,
+ .enumerable = 1,
+ .u.method = {
+ .native = ngx_stream_js_ext_on,
+ }
+ },
+
+ {
+ .flags = NJS_EXTERN_METHOD,
+ .name.string = njs_str("off"),
+ .writable = 1,
+ .configurable = 1,
+ .enumerable = 1,
+ .u.method = {
+ .native = ngx_stream_js_ext_off,
+ }
+ },
+
+ {
+ .flags = NJS_EXTERN_METHOD,
+ .name.string = njs_str("send"),
+ .writable = 1,
+ .configurable = 1,
+ .enumerable = 1,
+ .u.method = {
+ .native = ngx_stream_js_ext_send,
+ }
+ },
- { njs_str("stream"),
- NJS_EXTERN_OBJECT,
- ngx_stream_js_ext_session,
- njs_nitems(ngx_stream_js_ext_session),
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- 0 },
};
}
rc = njs_vm_external_create(ctx->vm, njs_value_arg(&ctx->args[0]),
- jmcf->proto, s);
+ jmcf->proto, s, 0);
if (rc != NJS_OK) {
return NGX_ERROR;
}
static njs_int_t
-ngx_stream_js_ext_get_remote_address(njs_vm_t *vm, njs_value_t *value,
- void *obj, uintptr_t data)
+ngx_stream_js_ext_get_remote_address(njs_vm_t *vm,
+ njs_object_prop_t *prop, njs_value_t *value, njs_value_t *setval,
+ njs_value_t *retval)
{
ngx_connection_t *c;
ngx_stream_session_t *s;
- s = (ngx_stream_session_t *) obj;
+ s = njs_vm_external(vm, value);
+ if (s == NULL) {
+ njs_value_undefined_set(retval);
+ return NJS_DECLINED;
+ }
+
c = s->connection;
- return njs_vm_value_string_set(vm, value, c->addr_text.data,
+ return njs_vm_value_string_set(vm, retval, c->addr_text.data,
c->addr_text.len);
}
static njs_int_t
-ngx_stream_js_ext_done(njs_vm_t *vm, njs_value_t *args,
- njs_uint_t nargs, njs_index_t unused)
-{
- return ngx_stream_js_ext_set_status(vm, args, nargs, NGX_OK);
-}
-
-
-static njs_int_t
-ngx_stream_js_ext_deny(njs_vm_t *vm, njs_value_t *args,
- njs_uint_t nargs, njs_index_t unused)
-{
- return ngx_stream_js_ext_set_status(vm, args, njs_min(nargs, 1),
- NGX_STREAM_FORBIDDEN);
-}
-
-
-static njs_int_t
-ngx_stream_js_ext_decline(njs_vm_t *vm, njs_value_t *args,
- njs_uint_t nargs, njs_index_t unused)
-{
- return ngx_stream_js_ext_set_status(vm, args, njs_min(nargs, 1),
- NGX_DECLINED);
-}
-
-
-static njs_int_t
-ngx_stream_js_ext_set_status(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
- ngx_int_t status)
+ngx_stream_js_ext_done(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
+ njs_index_t magic)
{
+ ngx_int_t status;
njs_value_t *code;
ngx_stream_js_ctx_t *ctx;
ngx_stream_session_t *s;
s = njs_vm_external(vm, njs_arg(args, nargs, 0));
- if (njs_slow_path(s == NULL)) {
+ if (s == NULL) {
+ njs_vm_error(vm, "\"this\" is not an external");
return NJS_ERROR;
}
+ status = (ngx_int_t) magic;
+ status = -status;
+
+ if (status == NGX_DONE) {
+ status = NGX_STREAM_FORBIDDEN;
+ }
+
code = njs_arg(args, nargs, 1);
if (!njs_value_is_undefined(code)) {
}
}
+
ctx = ngx_stream_get_module_ctx(s, ngx_stream_js_module);
ngx_log_debug1(NGX_LOG_DEBUG_STREAM, s->connection->log, 0,
static njs_int_t
ngx_stream_js_ext_log(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
- njs_index_t unused)
-{
- return ngx_stream_js_ext_log_core(vm, args, nargs, NGX_LOG_INFO);
-}
-
-
-static njs_int_t
-ngx_stream_js_ext_warn(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
- njs_index_t unused)
-{
- return ngx_stream_js_ext_log_core(vm, args, nargs, NGX_LOG_WARN);
-}
-
-
-static njs_int_t
-ngx_stream_js_ext_error(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
- njs_index_t unused)
-{
- return ngx_stream_js_ext_log_core(vm, args, nargs, NGX_LOG_ERR);
-}
-
-
-static njs_int_t
-ngx_stream_js_ext_log_core(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
- ngx_uint_t level)
+ njs_index_t level)
{
njs_str_t msg;
ngx_connection_t *c;
ngx_stream_session_t *s;
s = njs_vm_external(vm, njs_arg(args, nargs, 0));
- if (njs_slow_path(s == NULL)) {
+ if (s == NULL) {
+ njs_vm_error(vm, "\"this\" is not an external");
return NJS_ERROR;
}
ngx_stream_session_t *s;
s = njs_vm_external(vm, njs_arg(args, nargs, 0));
- if (njs_slow_path(s == NULL)) {
+ if (s == NULL) {
+ njs_vm_error(vm, "\"this\" is not an external");
return NJS_ERROR;
}
ngx_stream_session_t *s;
s = njs_vm_external(vm, njs_arg(args, nargs, 0));
- if (njs_slow_path(s == NULL)) {
+ if (s == NULL) {
+ njs_vm_error(vm, "\"this\" is not an external");
return NJS_ERROR;
}
static const njs_str_t flush_key = njs_str("flush");
s = njs_vm_external(vm, njs_arg(args, nargs, 0));
- if (njs_slow_path(s == NULL)) {
+ if (s == NULL) {
+ njs_vm_error(vm, "\"this\" is not an external");
return NJS_ERROR;
}
static njs_int_t
-ngx_stream_js_ext_get_variable(njs_vm_t *vm, njs_value_t *value, void *obj,
- uintptr_t data)
+ngx_stream_js_ext_variables(njs_vm_t *vm, njs_object_prop_t *prop,
+ njs_value_t *value, njs_value_t *setval, njs_value_t *retval)
{
- njs_str_t *v;
+ njs_int_t rc;
+ njs_str_t val;
ngx_str_t name;
ngx_uint_t key;
+ ngx_stream_variable_t *v;
ngx_stream_session_t *s;
+ ngx_stream_core_main_conf_t *cmcf;
ngx_stream_variable_value_t *vv;
- s = (ngx_stream_session_t *) obj;
- v = (njs_str_t *) data;
-
- name.data = v->start;
- name.len = v->length;
-
- key = ngx_hash_strlow(name.data, name.data, name.len);
+ s = njs_vm_external(vm, value);
+ if (s == NULL) {
+ njs_value_undefined_set(retval);
+ return NJS_DECLINED;
+ }
- vv = ngx_stream_get_variable(s, &name, key);
- if (vv == NULL || vv->not_found) {
- njs_value_undefined_set(value);
- return NJS_OK;
+ rc = njs_vm_prop_name(vm, prop, &val);
+ if (rc != NJS_OK) {
+ njs_value_undefined_set(retval);
+ return NJS_DECLINED;
}
- return njs_vm_value_string_set(vm, value, vv->data, vv->len);
-}
+ name.data = val.start;
+ name.len = val.length;
+ if (setval == NULL) {
+ key = ngx_hash_strlow(name.data, name.data, name.len);
-static njs_int_t
-ngx_stream_js_ext_set_variable(njs_vm_t *vm, void *obj, uintptr_t data,
- njs_str_t *value)
-{
- njs_str_t *val;
- ngx_str_t name;
- ngx_uint_t key;
- ngx_stream_variable_t *v;
- ngx_stream_session_t *s;
- ngx_stream_core_main_conf_t *cmcf;
- ngx_stream_variable_value_t *vv;
-
- s = (ngx_stream_session_t *) obj;
- val = (njs_str_t *) data;
+ vv = ngx_stream_get_variable(s, &name, key);
+ if (vv == NULL || vv->not_found) {
+ njs_value_undefined_set(retval);
+ return NJS_DECLINED;
+ }
- name.data = val->start;
- name.len = val->length;
+ return njs_vm_value_string_set(vm, retval, vv->data, vv->len);
+ }
cmcf = ngx_stream_get_module_main_conf(s, ngx_stream_core_module);
return NJS_ERROR;
}
+ rc = ngx_stream_js_string(vm, setval, &val);
+ if (rc != NJS_OK) {
+ return NJS_ERROR;
+ }
+
if (v->set_handler != NULL) {
vv = ngx_pcalloc(s->connection->pool,
sizeof(ngx_stream_variable_value_t));
vv->valid = 1;
vv->not_found = 0;
- vv->data = value->start;
- vv->len = value->length;
+ vv->data = val.start;
+ vv->len = val.length;
v->set_handler(s, vv, v->data);
vv->valid = 1;
vv->not_found = 0;
- vv->data = ngx_pnalloc(s->connection->pool, value->length);
+ vv->data = ngx_pnalloc(s->connection->pool, val.length);
if (vv->data == NULL) {
return NJS_ERROR;
}
- vv->len = value->length;
- ngx_memcpy(vv->data, value->start, vv->len);
+ vv->len = val.length;
+ ngx_memcpy(vv->data, val.start, vv->len);
return NJS_OK;
}
njs_vm_opt_t options;
ngx_file_info_t fi;
ngx_pool_cleanup_t *cln;
+ njs_external_proto_t proto;
if (jmcf->vm) {
return "is duplicate";
}
}
- jmcf->proto = njs_vm_external_prototype(jmcf->vm,
- &ngx_stream_js_externals[0]);
+ proto = njs_vm_external_prototype(jmcf->vm, ngx_stream_js_ext_session,
+ njs_nitems(ngx_stream_js_ext_session));
- if (jmcf->proto == NULL) {
+ if (proto == NULL) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "failed to add stream proto");
return NGX_CONF_ERROR;
}
+ jmcf->proto = proto;
+
rc = njs_vm_compile(jmcf->vm, &start, end);
if (rc != NJS_OK) {
#include <njs_auto_config.h>
-#define NJS_VERSION "0.3.10"
+#define NJS_VERSION "0.4.0"
#include <unistd.h> /* STDOUT_FILENO, STDERR_FILENO */
typedef uintptr_t njs_index_t;
typedef struct njs_vm_s njs_vm_t;
typedef union njs_value_s njs_value_t;
-typedef struct njs_extern_s njs_extern_t;
typedef struct njs_function_s njs_function_t;
typedef struct njs_vm_shared_s njs_vm_shared_t;
+typedef struct njs_object_prop_s njs_object_prop_t;
+typedef struct njs_external_s njs_external_t;
+typedef void * njs_external_proto_t;
/*
* njs_opaque_value_t is the external storage type for native njs_value_t type.
njs_vm_value_error_set(vm, njs_vm_retval(vm), fmt, ##__VA_ARGS__)
-typedef njs_int_t (*njs_extern_get_t)(njs_vm_t *vm, njs_value_t *value,
- void *obj, uintptr_t data);
-typedef njs_int_t (*njs_extern_set_t)(njs_vm_t *vm, void *obj, uintptr_t data,
- njs_str_t *value);
-typedef njs_int_t (*njs_extern_find_t)(njs_vm_t *vm, void *obj, uintptr_t data,
- njs_bool_t delete);
-typedef njs_int_t (*njs_extern_keys_t)(njs_vm_t *vm, void *obj,
- njs_value_t *keys);
-typedef njs_int_t (*njs_extern_method_t)(njs_vm_t *vm, njs_value_t *args,
- njs_uint_t nargs, njs_index_t unused);
-
+/*
+ * njs_prop_handler_t operates as a property getter/setter or delete handler.
+ * - retval != NULL && setval == NULL - GET context.
+ * - retval != NULL && setval != NULL - SET context.
+ * - retval == NULL - DELETE context.
+ *
+ * njs_prop_handler_t is expected to return:
+ * NJS_OK - handler executed successfully;
+ * NJS_ERROR - some error, vm->retval contains appropriate exception;
+ * NJS_DECLINED - handler was applied to inappropriate object, vm->retval
+ * contains undefined value.
+ */
+typedef njs_int_t (*njs_prop_handler_t) (njs_vm_t *vm, njs_object_prop_t *prop,
+ njs_value_t *value, njs_value_t *setval, njs_value_t *retval);
+typedef njs_int_t (*njs_exotic_keys_t)(njs_vm_t *vm, njs_value_t *value,
+ njs_value_t *retval);
+typedef njs_int_t (*njs_function_native_t) (njs_vm_t *vm, njs_value_t *args,
+ njs_uint_t nargs, njs_index_t magic8);
+
+
+typedef enum {
+ NJS_SYMBOL_INVALID,
+ NJS_SYMBOL_ASYNC_ITERATOR,
+ NJS_SYMBOL_HAS_INSTANCE,
+ NJS_SYMBOL_IS_CONCAT_SPREADABLE,
+ NJS_SYMBOL_ITERATOR,
+ NJS_SYMBOL_MATCH,
+ NJS_SYMBOL_MATCH_ALL,
+ NJS_SYMBOL_REPLACE,
+ NJS_SYMBOL_SEARCH,
+ NJS_SYMBOL_SPECIES,
+ NJS_SYMBOL_SPLIT,
+ NJS_SYMBOL_TO_PRIMITIVE,
+ NJS_SYMBOL_TO_STRING_TAG,
+ NJS_SYMBOL_UNSCOPABLES,
+ NJS_SYMBOL_KNOWN_MAX,
+} njs_wellknown_symbol_t;
+
+
+typedef enum {
+ NJS_EXTERN_PROPERTY = 0,
+ NJS_EXTERN_METHOD = 1,
+ NJS_EXTERN_OBJECT = 2,
+ NJS_EXTERN_SYMBOL = 4,
+} njs_extern_flag_t;
-typedef struct njs_external_s njs_external_t;
struct njs_external_s {
- njs_str_t name;
-
-#define NJS_EXTERN_PROPERTY 0x00
-#define NJS_EXTERN_METHOD 0x01
-#define NJS_EXTERN_OBJECT 0x80
-#define NJS_EXTERN_CASELESS_OBJECT 0x81
-
- uintptr_t type;
-
- njs_external_t *properties;
- njs_uint_t nproperties;
-
- njs_extern_get_t get;
- njs_extern_set_t set;
- njs_extern_find_t find;
-
- njs_extern_keys_t keys;
-
- njs_extern_method_t method;
-
- uintptr_t data;
+ njs_extern_flag_t flags;
+
+ union {
+ njs_str_t string;
+ uint32_t symbol;
+ } name;
+
+ unsigned writable;
+ unsigned configurable;
+ unsigned enumerable;
+
+ union {
+ struct {
+ const char value[15]; /* NJS_STRING_SHORT + 1. */
+ njs_prop_handler_t handler;
+ uint32_t magic32;
+ } property;
+
+ struct {
+ njs_function_native_t native;
+ uint8_t magic8;
+ } method;
+
+ struct {
+ njs_external_t *properties;
+ njs_uint_t nproperties;
+
+ unsigned writable;
+ unsigned configurable;
+ unsigned enumerable;
+ njs_prop_handler_t prop_handler;
+ njs_exotic_keys_t keys;
+ } object;
+ } u;
};
-typedef njs_int_t (*njs_function_native_t) (njs_vm_t *vm, njs_value_t *args,
- njs_uint_t nargs, njs_index_t retval);
-
/*
* NJS and event loops.
*
NJS_EXPORT njs_int_t njs_vm_add_path(njs_vm_t *vm, const njs_str_t *path);
-NJS_EXPORT const njs_extern_t *njs_vm_external_prototype(njs_vm_t *vm,
- njs_external_t *external);
-NJS_EXPORT njs_int_t njs_vm_external_create(njs_vm_t *vm,
- njs_value_t *value, const njs_extern_t *proto, njs_external_ptr_t object);
+NJS_EXPORT njs_external_proto_t njs_vm_external_prototype(njs_vm_t *vm,
+ const njs_external_t *definition, njs_uint_t n);
+NJS_EXPORT njs_int_t njs_vm_external_create(njs_vm_t *vm, njs_value_t *value,
+ njs_external_proto_t proto, njs_external_ptr_t external, njs_bool_t shared);
NJS_EXPORT njs_external_ptr_t njs_vm_external(njs_vm_t *vm,
const njs_value_t *value);
NJS_EXPORT void *njs_value_data(const njs_value_t *value);
NJS_EXPORT njs_function_t *njs_value_function(const njs_value_t *value);
+NJS_EXPORT uint16_t njs_vm_prop_magic16(njs_object_prop_t *prop);
+NJS_EXPORT uint32_t njs_vm_prop_magic32(njs_object_prop_t *prop);
+NJS_EXPORT njs_int_t njs_vm_prop_name(njs_vm_t *vm, njs_object_prop_t *prop,
+ njs_str_t *dst);
+
NJS_EXPORT njs_int_t njs_value_is_null(const njs_value_t *value);
NJS_EXPORT njs_int_t njs_value_is_undefined(const njs_value_t *value);
NJS_EXPORT njs_int_t njs_value_is_null_or_undefined(const njs_value_t *value);
njs_lvlhsh_init(&array->object.hash);
array->object.shared_hash = vm->shared->array_instance_hash;
array->object.__proto__ = &vm->prototypes[NJS_OBJ_TYPE_ARRAY].object;
+ array->object.slots = NULL;
array->object.type = NJS_ARRAY;
array->object.shared = 0;
array->object.extensible = 1;
njs_array_t *
-njs_array_keys(njs_vm_t *vm, const njs_value_t *object, njs_bool_t all)
+njs_array_keys(njs_vm_t *vm, njs_value_t *object, njs_bool_t all)
{
njs_array_t *keys;
njs_array_t *
-njs_array_indices(njs_vm_t *vm, const njs_value_t *object)
+njs_array_indices(njs_vm_t *vm, njs_value_t *object)
{
double idx;
uint32_t i;
uint32_t length);
njs_int_t njs_array_length_set(njs_vm_t *vm, njs_value_t *value,
njs_object_prop_t *prev, njs_value_t *setval);
-njs_array_t *njs_array_keys(njs_vm_t *vm, const njs_value_t *array,
- njs_bool_t all);
-njs_array_t *njs_array_indices(njs_vm_t *vm, const njs_value_t *object);
+njs_array_t *njs_array_keys(njs_vm_t *vm, njs_value_t *array, njs_bool_t all);
+njs_array_t *njs_array_indices(njs_vm_t *vm, njs_value_t *object);
njs_int_t njs_array_string_add(njs_vm_t *vm, njs_array_t *array,
const u_char *start, size_t size, size_t length);
njs_int_t njs_array_expand(njs_vm_t *vm, njs_array_t *array, uint32_t prepend,
njs_lvlhsh_init(&array->object.hash);
njs_lvlhsh_init(&array->object.shared_hash);
array->object.__proto__ = proto;
+ array->object.slots = NULL;
array->object.type = NJS_ARRAY_BUFFER;
array->object.shared = 0;
array->object.extensible = 1;
ov->object.fast_array = 0;
ov->object.__proto__ = &vm->prototypes[type].object;
+ ov->object.slots = NULL;
return ov;
}
date->object.error_data = 0;
date->object.fast_array = 0;
date->object.__proto__ = &vm->prototypes[NJS_OBJ_TYPE_DATE].object;
+ date->object.slots = NULL;
date->time = time;
error->fast_array = 0;
error->error_data = 1;
error->__proto__ = &vm->prototypes[type].object;
+ error->slots = NULL;
lhq.replace = 0;
lhq.pool = vm->mem_pool;
njs_lvlhsh_init(&object->hash);
njs_lvlhsh_init(&object->shared_hash);
object->__proto__ = &prototypes[NJS_OBJ_TYPE_INTERNAL_ERROR].object;
+ object->slots = NULL;
object->type = NJS_OBJECT;
object->shared = 1;
#include <njs_main.h>
-typedef struct njs_extern_part_s njs_extern_part_t;
-
-struct njs_extern_part_s {
- njs_extern_part_t *next;
- njs_str_t str;
-};
+static njs_int_t njs_external_prop_handler(njs_vm_t *vm,
+ njs_object_prop_t *self, njs_value_t *value, njs_value_t *setval,
+ njs_value_t *retval);
static njs_int_t
-njs_extern_hash_test(njs_lvlhsh_query_t *lhq, void *data)
+njs_external_add(njs_vm_t *vm, njs_arr_t *protos,
+ const njs_external_t *external, njs_uint_t n)
{
- njs_extern_t *ext;
+ size_t size;
+ ssize_t length;
+ njs_int_t ret;
+ njs_lvlhsh_t *hash;
+ const u_char *start;
+ njs_function_t *function;
+ njs_object_prop_t *prop;
+ njs_lvlhsh_query_t lhq;
+ njs_exotic_slots_t *slot, *next;
- ext = (njs_extern_t *) data;
+ slot = njs_arr_add(protos);
+ njs_memzero(slot, sizeof(njs_exotic_slots_t));
- if (njs_strstr_eq(&lhq->key, &ext->name)) {
- return NJS_OK;
- }
+ hash = &slot->external_shared_hash;
+ njs_lvlhsh_init(hash);
- return NJS_DECLINED;
-}
+ lhq.replace = 0;
+ lhq.proto = &njs_object_hash_proto;
+ lhq.pool = vm->mem_pool;
+ while (n != 0) {
+ prop = njs_object_prop_alloc(vm, &njs_string_empty,
+ &njs_value_invalid, 1);
+ if (njs_slow_path(prop == NULL)) {
+ goto memory_error;
+ }
-const njs_lvlhsh_proto_t njs_extern_hash_proto
- njs_aligned(64) =
-{
- NJS_LVLHSH_DEFAULT,
- njs_extern_hash_test,
- njs_lvlhsh_alloc,
- njs_lvlhsh_free,
-};
+ prop->writable = external->writable;
+ prop->configurable = external->configurable;
+ prop->enumerable = external->enumerable;
+ if (external->flags & 4) {
+ njs_set_symbol(&prop->name, external->name.symbol);
-static njs_extern_t *
-njs_vm_external_add(njs_vm_t *vm, njs_lvlhsh_t *hash, njs_external_t *external,
- njs_uint_t n)
-{
- njs_int_t ret;
- njs_extern_t *ext, *child;
- njs_function_t *function;
- njs_lvlhsh_query_t lhq;
+ lhq.key_hash = external->name.symbol;
- do {
- ext = njs_mp_alloc(vm->mem_pool, sizeof(njs_extern_t));
- if (njs_slow_path(ext == NULL)) {
- goto memory_error;
- }
-
- ext->name = external->name;
+ } else {
+ ret = njs_string_set(vm, &prop->name, external->name.string.start,
+ external->name.string.length);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return NJS_ERROR;
+ }
- njs_lvlhsh_init(&ext->hash);
+ lhq.key = external->name.string;
+ lhq.key_hash = njs_djb_hash(lhq.key.start, lhq.key.length);
+ }
- ext->type = external->type;
- ext->get = external->get;
- ext->set = external->set;
- ext->find = external->find;
- ext->keys = external->keys;
- ext->data = external->data;
+ lhq.value = prop;
- if (external->method != NULL) {
+ switch (external->flags & 3) {
+ case NJS_EXTERN_METHOD:
function = njs_mp_zalloc(vm->mem_pool, sizeof(njs_function_t));
if (njs_slow_path(function == NULL)) {
goto memory_error;
}
- /*
- * njs_mp_zalloc() does also:
- * njs_lvlhsh_init(&function->object.hash);
- * function->object.__proto__ = NULL;
- * function->ctor = 0;
- */
-
- function->object.__proto__ =
- &vm->prototypes[NJS_OBJ_TYPE_FUNCTION].object;
function->object.shared_hash = vm->shared->arrow_instance_hash;
function->object.type = NJS_FUNCTION;
function->object.shared = 1;
function->object.extensible = 1;
function->args_offset = 1;
function->native = 1;
- function->u.native = external->method;
+ function->magic8 = external->u.method.magic8;
+ function->u.native = external->u.method.native;
- ext->function = function;
+ njs_set_function(&prop->value, function);
- } else {
- ext->function = NULL;
- }
+ break;
- if (external->properties != NULL) {
- child = njs_vm_external_add(vm, &ext->hash, external->properties,
- external->nproperties);
- if (njs_slow_path(child == NULL)) {
- goto memory_error;
+ case NJS_EXTERN_PROPERTY:
+ if (external->u.property.handler != NULL) {
+ prop->type = NJS_PROPERTY_HANDLER;
+ prop->value.type = NJS_INVALID;
+ prop->value.data.truth = 1;
+ prop->value.data.magic16 = 0;
+ prop->value.data.magic32 = external->u.property.magic32;
+ prop->value.data.u.prop_handler = external->u.property.handler;
+
+ } else {
+ start = (u_char *) external->u.property.value;
+ size = njs_strlen(start);
+ length = njs_utf8_length(start, size);
+ if (njs_slow_path(length < 0)) {
+ length = 0;
+ }
+
+ ret = njs_string_new(vm, &prop->value, start, size, length);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return NJS_ERROR;
+ }
}
- }
- if (hash != NULL) {
- lhq.key_hash = njs_djb_hash(external->name.start,
- external->name.length);
- lhq.key = ext->name;
- lhq.replace = 0;
- lhq.value = ext;
- lhq.pool = vm->mem_pool;
- lhq.proto = &njs_extern_hash_proto;
+ break;
+
+ case NJS_EXTERN_OBJECT:
+ default:
+ next = njs_arr_item(protos, protos->items);
- ret = njs_lvlhsh_insert(hash, &lhq);
+ ret = njs_external_add(vm, protos, external->u.object.properties,
+ external->u.object.nproperties);
if (njs_slow_path(ret != NJS_OK)) {
- njs_internal_error(vm, "lvlhsh insert failed");
- return NULL;
+ return ret;
}
+
+ prop->type = NJS_PROPERTY_HANDLER;
+ prop->value.type = NJS_INVALID;
+ prop->value.data.truth = 1;
+ prop->value.data.magic16 = next - slot;
+ prop->value.data.magic32 = lhq.key_hash;
+ prop->value.data.u.prop_handler = njs_external_prop_handler;
+
+ next->writable = external->u.object.writable;
+ next->configurable = external->u.object.configurable;
+ next->enumerable = external->u.object.enumerable;
+ next->prop_handler = external->u.object.prop_handler;
+ next->keys = external->u.object.keys;
+
+ break;
}
- external++;
- n--;
+ ret = njs_lvlhsh_insert(hash, &lhq);
+ if (njs_slow_path(ret != NJS_OK)) {
+ njs_internal_error(vm, "lvlhsh insert failed");
+ return NJS_ERROR;
+ }
- } while (n != 0);
+ n--;
+ external++;
+ }
- return ext;
+ return NJS_OK;
memory_error:
njs_memory_error(vm);
- return NULL;
+ return NJS_ERROR;
}
-const njs_extern_t *
-njs_vm_external_prototype(njs_vm_t *vm, njs_external_t *external)
-{
- return njs_vm_external_add(vm, &vm->external_prototypes_hash, external, 1);
-}
-
-
-njs_int_t
-njs_vm_external_create(njs_vm_t *vm, njs_value_t *ext_val,
- const njs_extern_t *proto, njs_external_ptr_t object)
+static njs_int_t
+njs_external_prop_handler(njs_vm_t *vm, njs_object_prop_t *self,
+ njs_value_t *value, njs_value_t *setval, njs_value_t *retval)
{
- void *obj;
- uint32_t n;
- njs_arr_t *externals;
+ njs_int_t ret;
+ njs_object_prop_t *prop;
+ njs_external_ptr_t external;
+ njs_object_value_t *ov;
+ njs_lvlhsh_query_t lhq;
+ njs_exotic_slots_t *slots;
- if (njs_slow_path(proto == NULL)) {
- return NJS_ERROR;
+ if (njs_slow_path(retval == NULL)) {
+ return NJS_DECLINED;
}
- if (vm->external_objects->mem_pool != vm->mem_pool) {
+ slots = NULL;
- /* Making a local copy of externals in shared VM. */
+ if (njs_slow_path(setval != NULL)) {
+ *retval = *setval;
- n = vm->external_objects->items;
+ } else {
+ external = njs_vm_external(vm, value);
+ if (njs_slow_path(external == NULL)) {
+ njs_value_undefined_set(retval);
+ return NJS_OK;
+ }
- externals = njs_arr_create(vm->mem_pool, n + 4, sizeof(void *));
- if (njs_slow_path(externals == NULL)) {
+ ov = njs_mp_alloc(vm->mem_pool, sizeof(njs_object_value_t));
+ if (njs_slow_path(ov == NULL)) {
+ njs_memory_error(vm);
return NJS_ERROR;
}
- if (n > 0) {
- memcpy(externals->start, vm->external_objects->start,
- n * sizeof(void *));
- externals->items = n;
- }
+ slots = njs_object(value)->slots + self->value.data.magic16;
- vm->external_objects = externals;
+ njs_lvlhsh_init(&ov->object.hash);
+ ov->object.shared_hash = slots->external_shared_hash;
+ ov->object.type = NJS_OBJECT;
+ ov->object.shared = 0;
+ ov->object.extensible = 1;
+ ov->object.error_data = 0;
+ ov->object.fast_array = 0;
+ ov->object.__proto__ = &vm->prototypes[NJS_OBJ_TYPE_OBJECT].object;
+ ov->object.slots = slots;
+
+ njs_set_data(&ov->value, external);
+ njs_set_object_value(retval, ov);
}
- obj = njs_arr_add(vm->external_objects);
- if (njs_slow_path(obj == NULL)) {
+ prop = njs_object_prop_alloc(vm, &self->name, retval, 1);
+ if (njs_slow_path(prop == NULL)) {
return NJS_ERROR;
}
- memcpy(obj, &object, sizeof(void *));
-
- if (proto->type != NJS_EXTERN_METHOD) {
- ext_val->type = NJS_EXTERNAL;
- ext_val->data.truth = 1;
- ext_val->external.proto = proto;
- ext_val->external.index = vm->external_objects->items - 1;
-
- } else {
- njs_set_function(ext_val, proto->function);
+ if (slots != NULL) {
+ prop->writable = slots->writable;
+ prop->configurable = slots->configurable;
+ prop->enumerable = slots->enumerable;
}
- return NJS_OK;
-}
-
+ lhq.value = prop;
+ njs_string_get(&self->name, &lhq.key);
+ lhq.key_hash = self->value.data.magic32;
+ lhq.replace = 1;
+ lhq.pool = vm->mem_pool;
+ lhq.proto = &njs_object_hash_proto;
-njs_external_ptr_t
-njs_vm_external(njs_vm_t *vm, const njs_value_t *value)
-{
- if (njs_fast_path(njs_is_external(value))) {
- return njs_extern_object(vm, value);
+ ret = njs_lvlhsh_insert(njs_object_hash(value), &lhq);
+ if (njs_slow_path(ret != NJS_OK)) {
+ njs_internal_error(vm, "lvlhsh insert/replace failed");
+ return NJS_ERROR;
}
- njs_type_error(vm, "external value is expected");
-
- return NULL;
+ return NJS_OK;
}
-njs_array_t *
-njs_extern_keys_array(njs_vm_t *vm, const njs_extern_t *external)
+static njs_uint_t
+njs_external_protos(const njs_external_t *external, njs_uint_t size)
{
- uint32_t n, keys_length;
- njs_int_t ret;
- njs_array_t *keys;
- const njs_lvlhsh_t *hash;
- njs_lvlhsh_each_t lhe;
- const njs_extern_t *ext;
-
- keys_length = 0;
-
- njs_lvlhsh_each_init(&lhe, &njs_extern_hash_proto);
-
- hash = &external->hash;
+ njs_uint_t n;
- for ( ;; ) {
- ext = njs_lvlhsh_each(hash, &lhe);
+ n = 1;
- if (ext == NULL) {
- break;
- }
-
- keys_length++;
- }
-
- keys = njs_array_alloc(vm, 1, keys_length, NJS_ARRAY_SPARE);
- if (njs_slow_path(keys == NULL)) {
- return NULL;
- }
-
- n = 0;
-
- njs_lvlhsh_each_init(&lhe, &njs_extern_hash_proto);
-
- for ( ;; ) {
- ext = njs_lvlhsh_each(hash, &lhe);
-
- if (ext == NULL) {
- break;
+ while (size != 0) {
+ if ((external->flags & 3) == NJS_EXTERN_OBJECT) {
+ n += njs_external_protos(external->u.object.properties,
+ external->u.object.nproperties);
}
- ret = njs_string_new(vm, &keys->start[n++], ext->name.start,
- ext->name.length, 0);
-
- if (ret != NJS_OK) {
- return NULL;
- }
+ size--;
+ external++;
}
- return keys;
+ return n;
}
-static njs_int_t
-njs_external_match(njs_vm_t *vm, njs_function_native_t func, njs_extern_t *ext,
- njs_str_t *name, njs_extern_part_t *head, njs_extern_part_t *ppart)
+njs_external_proto_t
+njs_vm_external_prototype(njs_vm_t *vm, const njs_external_t *definition,
+ njs_uint_t n)
{
- u_char *buf, *p;
- size_t len;
- njs_int_t ret;
- njs_extern_t *prop;
- njs_extern_part_t part, *pr;
- njs_lvlhsh_each_t lhe;
-
- ppart->next = ∂
-
- njs_lvlhsh_each_init(&lhe, &njs_extern_hash_proto);
-
- for ( ;; ) {
- prop = njs_lvlhsh_each(&ext->hash, &lhe);
- if (prop == NULL) {
- break;
- }
+ njs_arr_t *protos;
+ njs_int_t ret;
+ njs_uint_t size;
- part.next = NULL;
- part.str = prop->name;
+ size = njs_external_protos(definition, n) + 1;
- if (prop->function && prop->function->u.native == func) {
- goto found;
- }
+ protos = njs_arr_create(vm->mem_pool, size, sizeof(njs_exotic_slots_t));
+ if (njs_slow_path(protos == NULL)) {
+ njs_memory_error(vm);
+ return NULL;
+ }
- ret = njs_external_match(vm, func, prop, name, head, &part);
- if (ret != NJS_DECLINED) {
- return ret;
- }
+ ret = njs_external_add(vm, protos, definition, n);
+ if (njs_slow_path(ret != NJS_OK)) {
+ njs_internal_error(vm, "njs_vm_external_add() failed");
+ return NULL;
}
- return NJS_DECLINED;
+ return protos;
+}
-found:
- len = 0;
+njs_int_t
+njs_vm_external_create(njs_vm_t *vm, njs_value_t *value,
+ njs_external_proto_t proto, njs_external_ptr_t external, njs_bool_t shared)
+{
+ njs_arr_t *protos;
+ njs_object_value_t *ov;
+ njs_exotic_slots_t *slots;
- for (pr = head; pr != NULL; pr = pr->next) {
- len += pr->str.length + njs_length(".");
+ if (njs_slow_path(proto == NULL)) {
+ return NJS_ERROR;
}
- buf = njs_mp_zalloc(vm->mem_pool, len);
- if (buf == NULL) {
+ ov = njs_mp_alloc(vm->mem_pool, sizeof(njs_object_value_t));
+ if (njs_slow_path(ov == NULL)) {
+ njs_memory_error(vm);
return NJS_ERROR;
}
- p = buf;
+ protos = proto;
+ slots = protos->start;
- for (pr = head; pr != NULL; pr = pr->next) {
- p = njs_sprintf(p, buf + len, "%V.", &pr->str);
- }
+ njs_lvlhsh_init(&ov->object.hash);
+ ov->object.shared_hash = slots->external_shared_hash;
+ ov->object.type = NJS_OBJECT;
+ ov->object.shared = shared;
+ ov->object.extensible = 1;
+ ov->object.error_data = 0;
+ ov->object.fast_array = 0;
+ ov->object.__proto__ = &vm->prototypes[NJS_OBJ_TYPE_OBJECT].object;
+ ov->object.slots = slots;
- name->start = (u_char *) buf;
- name->length = len - 1;
+ njs_set_object_value(value, ov);
+ njs_set_data(&ov->value, external);
return NJS_OK;
}
-njs_int_t
-njs_external_match_native_function(njs_vm_t *vm, njs_function_native_t func,
- njs_str_t *name)
+njs_external_ptr_t
+njs_vm_external(njs_vm_t *vm, const njs_value_t *value)
{
- njs_int_t ret;
- njs_extern_t *ext;
- njs_extern_part_t part;
- njs_lvlhsh_each_t lhe;
-
- njs_lvlhsh_each_init(&lhe, &njs_extern_hash_proto);
-
- for ( ;; ) {
- ext = njs_lvlhsh_each(&vm->external_prototypes_hash, &lhe);
- if (ext == NULL) {
- break;
- }
-
- part.next = NULL;
- part.str = ext->name;
-
- ret = njs_external_match(vm, func, ext, name, &part, &part);
- if (ret != NJS_DECLINED) {
- return ret;
+ if (njs_fast_path(njs_is_object_value(value))) {
+ value = njs_object_value(value);
+ if (njs_fast_path(njs_is_data(value))) {
+ return njs_value_data(value);
}
}
- return NJS_DECLINED;
+ return NULL;
}
+++ /dev/null
-
-/*
- * Copyright (C) Igor Sysoev
- * Copyright (C) NGINX, Inc.
- */
-
-#ifndef _NJS_EXTERN_H_INCLUDED_
-#define _NJS_EXTERN_H_INCLUDED_
-
-
-#define njs_extern_object(vm, ext) \
- (*(void **) njs_arr_item((vm)->external_objects, (ext)->external.index))
-
-#define njs_extern_index(vm, idx) \
- (*(void **) njs_arr_item((vm)->external_objects, idx))
-
-
-struct njs_extern_s {
- /* A hash of inclusive njs_extern_t. */
- njs_lvlhsh_t hash;
-
- uintptr_t type;
- njs_str_t name;
-
- njs_extern_get_t get;
- njs_extern_set_t set;
- njs_extern_find_t find;
-
- njs_extern_keys_t keys;
-
- njs_function_t *function;
-
- uintptr_t data;
-};
-
-
-njs_array_t *njs_extern_keys_array(njs_vm_t *vm, const njs_extern_t *external);
-njs_int_t njs_external_match_native_function(njs_vm_t *vm,
- njs_function_native_t func, njs_str_t *name);
-
-
-extern const njs_lvlhsh_proto_t njs_extern_hash_proto;
-
-
-#endif /* _NJS_EXTERN_H_INCLUDED_ */
call = target->u.native;
}
- ret = call(vm, native->arguments, native->nargs, function->magic);
+ ret = call(vm, native->arguments, native->nargs, function->magic8);
if (njs_slow_path(ret == NJS_ERROR)) {
return ret;
}
njs_inline njs_bool_t
njs_native_function_same(const njs_function_t *f1, const njs_function_t *f2)
{
- return f1->u.native == f2->u.native && f1->magic == f2->magic;
+ return f1->u.native == f2->u.native && f1->magic8 == f2->magic8;
}
static njs_json_state_t *
njs_json_push_stringify_state(njs_vm_t *vm, njs_json_stringify_t *stringify,
- const njs_value_t *value)
+ njs_value_t *value)
{
njs_int_t ret;
njs_json_state_t *state;
return (((value)->type == NJS_OBJECT)
|| ((value)->type == NJS_ARRAY)
|| ((value)->type == NJS_OBJECT_SYMBOL)
- || ((value)->type == NJS_EXTERNAL)
|| ((value)->type >= NJS_REGEXP));
}
}
-njs_inline njs_bool_t
-njs_dump_is_external_object(const njs_value_t *value)
-{
- if (!njs_is_external(value)) {
- return 0;
- }
-
- return value->external.proto->type == NJS_EXTERN_OBJECT;
-}
-
-
njs_inline njs_bool_t
njs_dump_is_recursive(const njs_value_t *value)
{
return (value->type == NJS_OBJECT && !njs_object(value)->error_data)
|| (value->type == NJS_ARRAY)
- || (value->type >= NJS_OBJECT_SPECIAL_MAX)
- || njs_dump_is_external_object(value);
+ || (value->type >= NJS_OBJECT_SPECIAL_MAX);
}
#include <njs_crypto.h>
#include <njs_event.h>
-#include <njs_extern.h>
#include <njs_module.h>
object = &module->object;
object->__proto__ = &vm->prototypes[NJS_OBJ_TYPE_OBJECT].object;
+ object->slots = NULL;
object->shared = 0;
object->extensible = 1;
object->error_data = 0;
njs_lvlhsh_init(&object->hash);
njs_lvlhsh_init(&object->shared_hash);
object->__proto__ = &vm->prototypes[NJS_OBJ_TYPE_OBJECT].object;
+ object->slots = NULL;
object->type = NJS_OBJECT;
object->shared = 0;
object->extensible = 1;
njs_object_t *
njs_object_value_copy(njs_vm_t *vm, njs_value_t *value)
{
+ size_t size;
njs_object_t *object;
object = njs_object(value);
return object;
}
- object = njs_mp_alloc(vm->mem_pool, sizeof(njs_object_t));
+ size = njs_is_object_value(value) ? sizeof(njs_object_value_t)
+ : sizeof(njs_object_t);
+ object = njs_mp_alloc(vm->mem_pool, size);
if (njs_fast_path(object != NULL)) {
- *object = *njs_object(value);
+ memcpy(object, njs_object(value), size);
object->__proto__ = &vm->prototypes[NJS_OBJ_TYPE_OBJECT].object;
object->shared = 0;
value->data.u.object = object;
index = njs_primitive_prototype_index(type);
ov->object.__proto__ = &vm->prototypes[index].object;
+ ov->object.slots = NULL;
ov->value = *value;
njs_prop_private_copy(njs_vm_t *vm, njs_property_query_t *pq)
{
njs_int_t ret;
+ njs_value_t *value;
+ njs_object_t *object;
njs_function_t *function;
njs_object_prop_t *prop, *shared;
return NJS_OK;
}
- if (!njs_is_function(&prop->value)) {
+ value = &prop->value;
+
+ switch (value->type) {
+ case NJS_OBJECT:
+ case NJS_OBJECT_VALUE:
+ object = njs_object_value_copy(vm, value);
+ if (njs_slow_path(object == NULL)) {
+ return NJS_ERROR;
+ }
+
+ value->data.u.object = object;
return NJS_OK;
- }
- function = njs_function_value_copy(vm, &prop->value);
- if (njs_slow_path(function == NULL)) {
- return NJS_ERROR;
+ case NJS_FUNCTION:
+ function = njs_function_value_copy(vm, &prop->value);
+ if (njs_slow_path(function == NULL)) {
+ return NJS_ERROR;
+ }
+
+ return njs_function_name_set(vm, function, &prop->name, 0);
+
+ default:
+ break;
}
- return njs_function_name_set(vm, function, &prop->name, 0);
+ return NJS_OK;
}
promise->object.error_data = 0;
promise->object.fast_array = 0;
promise->object.__proto__ = &vm->prototypes[NJS_OBJ_TYPE_PROMISE].object;
+ promise->object.slots = NULL;
data = (njs_promise_data_t *) ((uint8_t *) promise + sizeof(njs_promise_t));
njs_lvlhsh_init(®exp->object.hash);
regexp->object.shared_hash = vm->shared->regexp_instance_hash;
regexp->object.__proto__ = &vm->prototypes[NJS_OBJ_TYPE_REGEXP].object;
+ regexp->object.slots = NULL;
regexp->object.type = NJS_REGEXP;
regexp->object.shared = 0;
regexp->object.extensible = 1;
#endif
static njs_int_t njs_ext_console_log(njs_vm_t *vm, njs_value_t *args,
- njs_uint_t nargs, njs_index_t unused);
-static njs_int_t njs_ext_console_dump(njs_vm_t *vm, njs_value_t *args,
- njs_uint_t nargs, njs_index_t unused);
+ njs_uint_t nargs, njs_index_t indent);
static njs_int_t njs_ext_console_time(njs_vm_t *vm, njs_value_t *args,
njs_uint_t nargs, njs_index_t unused);
static njs_int_t njs_ext_console_time_end(njs_vm_t *vm, njs_value_t *args,
static njs_external_t njs_ext_console[] = {
- { njs_str("log"),
- NJS_EXTERN_METHOD,
- NULL,
- 0,
- NULL,
- NULL,
- NULL,
- NULL,
- njs_ext_console_log,
- 0 },
-
- { njs_str("dump"),
- NJS_EXTERN_METHOD,
- NULL,
- 0,
- NULL,
- NULL,
- NULL,
- NULL,
- njs_ext_console_dump,
- 0 },
-
- { njs_str("time"),
- NJS_EXTERN_METHOD,
- NULL,
- 0,
- NULL,
- NULL,
- NULL,
- NULL,
- njs_ext_console_time,
- 0 },
-
- { njs_str("timeEnd"),
- NJS_EXTERN_METHOD,
- NULL,
- 0,
- NULL,
- NULL,
- NULL,
- NULL,
- njs_ext_console_time_end,
- 0 },
-};
+ {
+ .flags = NJS_EXTERN_METHOD,
+ .name.string = njs_str("dump"),
+ .writable = 1,
+ .configurable = 1,
+ .enumerable = 1,
+ .u.method = {
+ .native = njs_ext_console_log,
+ .magic8 = 1,
+ }
+ },
+
+ {
+ .flags = NJS_EXTERN_METHOD,
+ .name.string = njs_str("log"),
+ .writable = 1,
+ .configurable = 1,
+ .enumerable = 1,
+ .u.method = {
+ .native = njs_ext_console_log,
+ }
+ },
+
+ {
+ .flags = NJS_EXTERN_PROPERTY | NJS_EXTERN_SYMBOL,
+ .name.symbol = NJS_SYMBOL_TO_STRING_TAG,
+ .u.property = {
+ .value = "Console",
+ }
+ },
+
+ {
+ .flags = NJS_EXTERN_METHOD,
+ .name.string = njs_str("time"),
+ .writable = 1,
+ .configurable = 1,
+ .enumerable = 1,
+ .u.method = {
+ .native = njs_ext_console_time,
+ }
+ },
+
+ {
+ .flags = NJS_EXTERN_METHOD,
+ .name.string = njs_str("timeEnd"),
+ .writable = 1,
+ .configurable = 1,
+ .enumerable = 1,
+ .u.method = {
+ .native = njs_ext_console_time_end,
+ }
+ },
-static njs_external_t njs_externals[] = {
-
- { njs_str("console"),
- NJS_EXTERN_OBJECT,
- njs_ext_console,
- njs_nitems(njs_ext_console),
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- 0 },
};
}
-static njs_int_t
-njs_externals_add(njs_vm_t *vm, njs_external_t *definition,
- const njs_str_t *name, njs_external_ptr_t object)
+static njs_value_t *
+njs_external_add(njs_vm_t *vm, njs_external_t *definition,
+ njs_uint_t n, const njs_str_t *name, njs_external_ptr_t external)
{
- njs_int_t ret;
- njs_value_t *value;
- const njs_extern_t *proto;
+ njs_int_t ret;
+ njs_value_t *value;
+ njs_external_proto_t proto;
- proto = njs_vm_external_prototype(vm, definition);
+ proto = njs_vm_external_prototype(vm, definition, n);
if (njs_slow_path(proto == NULL)) {
njs_stderror("failed to add \"%V\" proto\n", name);
- return NJS_ERROR;
+ return NULL;
}
value = njs_mp_zalloc(vm->mem_pool, sizeof(njs_opaque_value_t));
if (njs_slow_path(value == NULL)) {
- return NJS_ERROR;
+ return NULL;
}
- ret = njs_vm_external_create(vm, value, proto, object);
+ ret = njs_vm_external_create(vm, value, proto, external, 0);
if (njs_slow_path(ret != NJS_OK)) {
- return NJS_ERROR;
+ return NULL;
+ }
+
+ ret = njs_vm_bind(vm, name, value, 0);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return NULL;
}
- return njs_vm_bind(vm, name, value, 1);
+ return value;
}
static njs_int_t
njs_externals_init(njs_vm_t *vm, njs_console_t *console)
{
- njs_int_t ret;
+ njs_int_t ret;
+ njs_value_t *value, method;
static const njs_str_t console_name = njs_str("console");
static const njs_str_t print_name = njs_str("print");
+ static const njs_value_t string_log = njs_string("log");
- ret = njs_externals_add(vm, &njs_externals[0], &console_name, console);
+ value = njs_external_add(vm, njs_ext_console, njs_nitems(njs_ext_console),
+ &console_name, console);
+ if (njs_slow_path(value == NULL)) {
+ return NJS_ERROR;
+ }
+
+ ret = njs_value_property(vm, value, njs_value_arg(&string_log), &method);
if (njs_slow_path(ret != NJS_OK)) {
return NJS_ERROR;
}
- ret = njs_externals_add(vm, &njs_ext_console[0], &print_name, console);
+ ret = njs_vm_bind(vm, &print_name, &method, 0);
if (njs_slow_path(ret != NJS_OK)) {
return NJS_ERROR;
}
static njs_int_t
njs_ext_console_log(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
- njs_index_t unused)
-{
- njs_str_t msg;
- njs_uint_t n;
-
- n = 1;
-
- while (n < nargs) {
- if (njs_vm_value_dump(vm, &msg, njs_argument(args, n), 1, 0)
- == NJS_ERROR)
- {
- return NJS_ERROR;
- }
-
- njs_printf("%s", (n != 1) ? " " : "");
- njs_print(msg.start, msg.length);
-
- n++;
- }
-
- if (nargs > 1) {
- njs_printf("\n");
- }
-
- njs_set_undefined(&vm->retval);
-
- return NJS_OK;
-}
-
-
-static njs_int_t
-njs_ext_console_dump(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
- njs_index_t unused)
+ njs_index_t indent)
{
njs_str_t msg;
njs_uint_t n;
n = 1;
while (n < nargs) {
- if (njs_vm_value_dump(vm, &msg, njs_argument(args, n), 1, 1)
+ if (njs_vm_value_dump(vm, &msg, njs_argument(args, n), 1, indent)
== NJS_ERROR)
{
return NJS_ERROR;
console = njs_vm_external(vm, njs_arg(args, nargs, 0));
if (njs_slow_path(console == NULL)) {
+ njs_type_error(vm, "external value is expected");
return NJS_ERROR;
}
console = njs_vm_external(vm, njs_arg(args, nargs, 0));
if (njs_slow_path(console == NULL)) {
+ njs_type_error(vm, "external value is expected");
return NJS_ERROR;
}
#ifndef _NJS_SYMBOL_H_INCLUDED_
#define _NJS_SYMBOL_H_INCLUDED_
-typedef enum {
- NJS_SYMBOL_INVALID = 0,
- NJS_SYMBOL_ASYNC_ITERATOR = 1,
- NJS_SYMBOL_HAS_INSTANCE = 2,
- NJS_SYMBOL_IS_CONCAT_SPREADABLE = 3,
- NJS_SYMBOL_ITERATOR = 4,
- NJS_SYMBOL_MATCH = 5,
- NJS_SYMBOL_MATCH_ALL = 6,
- NJS_SYMBOL_REPLACE = 7,
- NJS_SYMBOL_SEARCH = 8,
- NJS_SYMBOL_SPECIES = 9,
- NJS_SYMBOL_SPLIT = 10,
- NJS_SYMBOL_TO_PRIMITIVE = 11,
- NJS_SYMBOL_TO_STRING_TAG = 12,
- NJS_SYMBOL_UNSCOPABLES = 13,
-#define NJS_SYMBOL_KNOWN_MAX (NJS_SYMBOL_UNSCOPABLES + 1)
-} njs_wellknown_symbol_t;
-
-
njs_int_t njs_symbol_to_string(njs_vm_t *vm, njs_value_t *dst,
const njs_value_t *value);
static njs_int_t njs_string_property_query(njs_vm_t *vm,
njs_property_query_t *pq, njs_value_t *object, uint32_t index);
static njs_int_t njs_external_property_query(njs_vm_t *vm,
- njs_property_query_t *pq, njs_value_t *object);
-static njs_int_t njs_external_property_set(njs_vm_t *vm,
- njs_object_prop_t *prop, njs_value_t *value, njs_value_t *setval,
- njs_value_t *retval);
-static njs_int_t njs_external_property_delete(njs_vm_t *vm,
- njs_object_prop_t *prop, njs_value_t *value, njs_value_t *setval,
- njs_value_t *retval);
+ njs_property_query_t *pq, njs_value_t *value);
const njs_value_t njs_value_null = njs_value(NJS_NULL, 0, 0.0);
njs_array_t *
-njs_value_enumerate(njs_vm_t *vm, const njs_value_t *value,
+njs_value_enumerate(njs_vm_t *vm, njs_value_t *value,
njs_object_enum_t kind, njs_object_enum_type_t type, njs_bool_t all)
{
- void *obj;
njs_int_t ret;
njs_value_t keys;
njs_object_value_t obj_val;
- const njs_extern_t *ext_proto;
+ njs_exotic_slots_t *slots;
if (njs_is_object(value)) {
- return njs_object_enumerate(vm, njs_object(value), kind, type, all);
- }
-
- if (value->type != NJS_STRING) {
- if (kind == NJS_ENUM_KEYS
- && (type & NJS_ENUM_STRING)
- && njs_is_external(value))
- {
- ext_proto = value->external.proto;
-
- if (ext_proto->keys != NULL) {
- obj = njs_extern_object(vm, value);
-
- ret = ext_proto->keys(vm, obj, &keys);
+ if (kind == NJS_ENUM_KEYS && (type & NJS_ENUM_STRING)) {
+ slots = njs_object_slots(value);
+ if (slots != NULL && slots->keys != NULL) {
+ ret = slots->keys(vm, value, &keys);
if (njs_slow_path(ret != NJS_OK)) {
return NULL;
}
return njs_array(&keys);
}
-
- return njs_extern_keys_array(vm, ext_proto);
}
+ return njs_object_enumerate(vm, njs_object(value), kind, type, all);
+ }
+
+ if (value->type != NJS_STRING) {
return njs_array_alloc(vm, 1, 0, NJS_ARRAY_SPARE);
}
njs_array_t *
-njs_value_own_enumerate(njs_vm_t *vm, const njs_value_t *value,
+njs_value_own_enumerate(njs_vm_t *vm, njs_value_t *value,
njs_object_enum_t kind, njs_object_enum_type_t type, njs_bool_t all)
{
- void *obj;
njs_int_t ret;
njs_value_t keys;
njs_object_value_t obj_val;
- const njs_extern_t *ext_proto;
+ njs_exotic_slots_t *slots;
if (njs_is_object(value)) {
- return njs_object_own_enumerate(vm, njs_object(value), kind, type, all);
- }
-
- if (value->type != NJS_STRING) {
- if (kind == NJS_ENUM_KEYS
- && (type & NJS_ENUM_STRING)
- && njs_is_external(value))
- {
- ext_proto = value->external.proto;
-
- if (ext_proto->keys != NULL) {
- obj = njs_extern_object(vm, value);
-
- ret = ext_proto->keys(vm, obj, &keys);
+ if (kind == NJS_ENUM_KEYS && (type & NJS_ENUM_STRING)) {
+ slots = njs_object_slots(value);
+ if (slots != NULL && slots->keys != NULL) {
+ ret = slots->keys(vm, value, &keys);
if (njs_slow_path(ret != NJS_OK)) {
return NULL;
}
return njs_array(&keys);
}
-
- return njs_extern_keys_array(vm, ext_proto);
}
+ return njs_object_own_enumerate(vm, njs_object(value), kind, type, all);
+ }
+
+ if (value->type != NJS_STRING) {
return njs_array_alloc(vm, 1, 0, NJS_ARRAY_SPARE);
}
case NJS_STRING:
return "string";
- case NJS_EXTERNAL:
- return "external";
-
case NJS_INVALID:
return "invalid";
case NJS_OBJECT:
+ case NJS_OBJECT_VALUE:
return "object";
case NJS_ARRAY:
obj = &function->object;
break;
- case NJS_EXTERNAL:
- obj = NULL;
- break;
-
case NJS_UNDEFINED:
case NJS_NULL:
default:
pq->lhq.key.length);
}
- if (obj == NULL) {
- pq->own = 1;
+ ret = njs_object_property_query(vm, pq, obj, key);
+
+ if (njs_slow_path(ret == NJS_DECLINED && obj->slots != NULL)) {
return njs_external_property_query(vm, pq, value);
}
-
- return njs_object_property_query(vm, pq, obj, key);
}
return ret;
static njs_int_t
njs_external_property_query(njs_vm_t *vm, njs_property_query_t *pq,
- njs_value_t *object)
+ njs_value_t *value)
{
- void *obj;
- njs_int_t ret;
- uintptr_t data;
njs_object_prop_t *prop;
- const njs_extern_t *ext_proto;
+ njs_exotic_slots_t *slots;
+
+ slots = njs_object_slots(value);
+
+ if (njs_slow_path(slots->prop_handler == NULL)) {
+ return NJS_DECLINED;
+ }
prop = &pq->scratch;
* njs_set_null(&prop->setter);
*/
- prop->enumerable = 1;
-
- ext_proto = object->external.proto;
-
- pq->lhq.proto = &njs_extern_hash_proto;
- ret = njs_lvlhsh_find(&ext_proto->hash, &pq->lhq);
-
- if (ret == NJS_OK) {
- ext_proto = pq->lhq.value;
+ prop->name = pq->key;
- prop->value.type = NJS_EXTERNAL;
- prop->value.data.truth = 1;
- prop->value.external.proto = ext_proto;
- prop->value.external.index = object->external.index;
-
- if ((ext_proto->type & NJS_EXTERN_OBJECT) != 0) {
- goto done;
- }
-
- data = ext_proto->data;
-
- } else {
-
- if (pq->lhq.key.start == NULL) {
- /* Symbol.toStringTag is not supported yet. */
- goto done;
- }
+ pq->lhq.value = prop;
- data = (uintptr_t) &pq->lhq.key;
- }
+ prop->writable = slots->writable;
+ prop->configurable = slots->configurable;
+ prop->enumerable = slots->enumerable;
switch (pq->query) {
case NJS_PROPERTY_QUERY_GET:
- if (ext_proto->get != NULL) {
- obj = njs_extern_object(vm, object);
- ret = ext_proto->get(vm, &prop->value, obj, data);
- if (njs_slow_path(ret != NJS_OK)) {
- return ret;
- }
- }
-
- break;
+ return slots->prop_handler(vm, prop, value, NULL, &prop->value);
case NJS_PROPERTY_QUERY_SET:
- case NJS_PROPERTY_QUERY_DELETE:
-
- prop->type = NJS_PROPERTY_HANDLER;
- prop->name = *object;
-
- if (pq->query == NJS_PROPERTY_QUERY_SET) {
- prop->writable = (ext_proto->set != NULL);
- prop->value.data.u.prop_handler = njs_external_property_set;
-
- } else {
- prop->configurable = (ext_proto->find != NULL);
- prop->value.data.u.prop_handler = njs_external_property_delete;
+ if (slots->writable == 0) {
+ return NJS_OK;
}
- pq->ext_data = data;
- pq->ext_proto = ext_proto;
- pq->ext_index = object->external.index;
-
- pq->lhq.value = prop;
-
- vm->stash = (uintptr_t) pq;
-
- return NJS_OK;
- }
-
-done:
-
- if (ext_proto->type == NJS_EXTERN_METHOD) {
- njs_set_function(&prop->value, ext_proto->function);
- }
-
- pq->lhq.value = prop;
-
- return ret;
-}
-
-
-static njs_int_t
-njs_external_property_set(njs_vm_t *vm, njs_object_prop_t *prop,
- njs_value_t *value, njs_value_t *setval, njs_value_t *retval)
-{
- void *obj;
- njs_int_t ret;
- njs_str_t s;
- njs_property_query_t *pq;
-
- pq = (njs_property_query_t *) vm->stash;
+ break;
- if (!njs_is_null_or_undefined(setval)) {
- ret = njs_vm_value_to_string(vm, &s, setval);
- if (njs_slow_path(ret != NJS_OK)) {
- return ret;
+ case NJS_PROPERTY_QUERY_DELETE:
+ if (slots->configurable == 0) {
+ return NJS_OK;
}
- } else {
- s = njs_str_value("");
+ break;
}
- *retval = *setval;
-
- obj = njs_extern_index(vm, pq->ext_index);
-
- return pq->ext_proto->set(vm, obj, pq->ext_data, &s);
-}
-
+ prop->type = NJS_PROPERTY_HANDLER;
+ prop->value.data.u.prop_handler = slots->prop_handler;
-static njs_int_t
-njs_external_property_delete(njs_vm_t *vm, njs_object_prop_t *prop,
- njs_value_t *value, njs_value_t *unused, njs_value_t *unused2)
-{
- void *obj;
- njs_property_query_t *pq;
-
- pq = (njs_property_query_t *) vm->stash;
-
- obj = njs_extern_index(vm, pq->ext_index);
-
- return pq->ext_proto->find(vm, obj, pq->ext_data, 1);
+ return NJS_OK;
}
switch (prop->type) {
case NJS_PROPERTY_HANDLER:
- if (njs_is_external(value)) {
+ if (njs_is_object(value) && njs_object_slots(value) != NULL) {
ret = prop->value.data.u.prop_handler(vm, prop, value, NULL, NULL);
- if (njs_slow_path(ret != NJS_OK)) {
- return NJS_ERROR;
+ if (njs_slow_path(ret != NJS_DECLINED)) {
+ return ret;
}
-
- return NJS_OK;
}
/* Fall through. */
NJS_DATA,
- /* The type is external code. */
- NJS_EXTERNAL,
-
/*
* The invalid value type is used:
* for uninitialized array members,
} njs_value_type_t;
-typedef struct njs_object_prop_s njs_object_prop_t;
typedef struct njs_string_s njs_string_t;
typedef struct njs_object_s njs_object_t;
typedef struct njs_object_value_s njs_object_value_t;
typedef struct njs_object_init_s njs_object_init_t;
-/*
- * njs_prop_handler_t operates as a property getter and/or setter.
- * The handler receives NULL setval if it is invoked in GET context and
- * non-null otherwise.
- *
- * njs_prop_handler_t is expected to return:
- * NJS_OK - handler executed successfully;
- * NJS_ERROR - some error, vm->retval contains appropriate exception;
- * NJS_DECLINED - handler was applied to inappropriate object, vm->retval
- * contains undefined value.
- */
-typedef njs_int_t (*njs_prop_handler_t) (njs_vm_t *vm, njs_object_prop_t *prop,
- njs_value_t *value, njs_value_t *setval, njs_value_t *retval);
-
#if (!NJS_HAVE_GCC_ATTRIBUTE_ALIGNED)
#error "aligned attribute is required"
#endif
njs_string_t *data;
} long_string;
- struct {
- njs_value_type_t type:8; /* 6 bits */
- uint8_t truth;
+ njs_value_type_t type:8; /* 6 bits */
+};
- uint16_t _spare;
- uint32_t index;
- const njs_extern_t *proto;
- } external;
+typedef struct {
+ /* Get, also Set if writable, also Delete if configurable. */
+ njs_prop_handler_t prop_handler;
+ unsigned writable:1;
+ unsigned configurable:1;
+ unsigned enumerable:1;
- njs_value_type_t type:8; /* 6 bits */
-};
+ njs_exotic_keys_t keys;
+
+ /* A shared hash of njs_object_prop_t for externals. */
+ njs_lvlhsh_t external_shared_hash;
+} njs_exotic_slots_t;
struct njs_object_s {
/* A shared hash of njs_object_prop_t. */
njs_lvlhsh_t shared_hash;
- /* An object __proto__. */
njs_object_t *__proto__;
+ njs_exotic_slots_t *slots;
/* The type is used in constructor prototypes. */
njs_value_type_t type:8;
uint8_t ctor:1;
uint8_t global_this:1;
- uint8_t magic;
+ uint8_t magic8;
union {
njs_function_lambda_t *lambda;
/* scratch is used to get the value of an NJS_PROPERTY_HANDLER property. */
njs_object_prop_t scratch;
- /* These three fields are used for NJS_EXTERNAL setters. */
- uintptr_t ext_data;
- const njs_extern_t *ext_proto;
- uint32_t ext_index;
-
njs_value_t key;
njs_object_t *prototype;
njs_object_prop_t *own_whiteout;
#define _njs_function(_function, _args_count, _ctor, _magic) { \
.native = 1, \
- .magic = _magic, \
+ .magic8 = _magic, \
.args_count = _args_count, \
.ctor = _ctor, \
.args_offset = 1, \
((value)->type == NJS_OBJECT && njs_object(value)->error_data)
-#define njs_is_external(value) \
- ((value)->type == NJS_EXTERNAL)
-
-
#define njs_is_valid(value) \
((value)->type != NJS_INVALID)
(&(value)->data.u.object->hash)
+#define njs_object_slots(value) \
+ ((value)->data.u.object->slots)
+
+
#define njs_object_hash_is_empty(value) \
(njs_lvlhsh_is_empty(njs_object_hash(value)))
}
+njs_inline void
+njs_set_symbol(njs_value_t *value, uint32_t symbol)
+{
+ value->data.magic32 = symbol;
+ value->type = NJS_SYMBOL;
+ value->data.truth = 1;
+}
+
+
njs_inline void
njs_set_data(njs_value_t *value, void *data)
{
void njs_value_release(njs_vm_t *vm, njs_value_t *value);
njs_int_t njs_value_to_primitive(njs_vm_t *vm, njs_value_t *dst,
njs_value_t *value, njs_uint_t hint);
-njs_array_t *njs_value_enumerate(njs_vm_t *vm, const njs_value_t *value,
+njs_array_t *njs_value_enumerate(njs_vm_t *vm, njs_value_t *value,
njs_object_enum_t kind, njs_object_enum_type_t type, njs_bool_t all);
-njs_array_t *njs_value_own_enumerate(njs_vm_t *vm, const njs_value_t *value,
+njs_array_t *njs_value_own_enumerate(njs_vm_t *vm, njs_value_t *value,
njs_object_enum_t kind, njs_object_enum_type_t type, njs_bool_t all);
njs_int_t njs_value_length(njs_vm_t *vm, njs_value_t *value, uint64_t *dst);
const char *njs_type_string(njs_value_type_t type);
vm->external = options->external;
- vm->external_objects = njs_arr_create(vm->mem_pool, 4, sizeof(void *));
- if (njs_slow_path(vm->external_objects == NULL)) {
- return NULL;
- }
-
- njs_lvlhsh_init(&vm->external_prototypes_hash);
-
vm->trace.level = NJS_LEVEL_TRACE;
vm->trace.size = 2048;
vm->trace.handler = njs_parser_trace_handler;
}
+uint16_t
+njs_vm_prop_magic16(njs_object_prop_t *prop)
+{
+ return prop->value.data.magic16;
+}
+
+
+uint32_t
+njs_vm_prop_magic32(njs_object_prop_t *prop)
+{
+ return prop->value.data.magic32;
+}
+
+
+njs_int_t
+njs_vm_prop_name(njs_vm_t *vm, njs_object_prop_t *prop, njs_str_t *dst)
+{
+ if (njs_slow_path(!njs_is_string(&prop->name))) {
+ njs_type_error(vm, "property name is not a string");
+ return NJS_ERROR;
+ }
+
+ njs_string_get(&prop->name, dst);
+
+ return NJS_OK;
+}
+
+
njs_noinline void
njs_vm_value_error_set(njs_vm_t *vm, njs_value_t *value, const char *fmt, ...)
{
return NJS_OK;
}
- ret = njs_external_match_native_function(vm, function->u.native,
- &be->name);
- if (ret == NJS_OK) {
- return NJS_OK;
- }
-
be->name = njs_entry_native;
return NJS_OK;
njs_native_frame_t *top_frame;
njs_frame_t *active_frame;
- njs_arr_t *external_objects; /* of njs_external_ptr_t */
-
- njs_lvlhsh_t external_prototypes_hash;
-
njs_rbtree_t *variables_hash;
njs_lvlhsh_t values_hash;
njs_arr_t *debug;
- /*
- * njs_property_query() uses it to store reference to a temporary
- * PROPERTY_HANDLERs for NJS_EXTERNAL values in NJS_PROPERTY_QUERY_SET
- * and NJS_PROPERTY_QUERY_DELETE modes.
- */
- uintptr_t stash; /* njs_property_query_t * */
-
uint64_t symbol_generator;
};
njs_benchmark_test(njs_vm_t *parent, njs_opts_t *opts, njs_value_t *report,
njs_benchmark_test_t *test)
{
- u_char *start;
- njs_vm_t *vm, *nvm;
- uint64_t us;
- njs_int_t ret;
- njs_str_t s, *expected;
- njs_uint_t i, n;
- njs_bool_t success;
- njs_value_t *result, name, usec, times;
- njs_vm_opt_t options;
+ u_char *start;
+ njs_vm_t *vm, *nvm;
+ uint64_t us;
+ njs_int_t ret;
+ njs_str_t s, *expected;
+ njs_uint_t i, n;
+ njs_bool_t success;
+ njs_value_t *result, name, usec, times;
+ njs_vm_opt_t options;
+ njs_external_proto_t proto;
static const njs_value_t name_key = njs_string("name");
static const njs_value_t usec_key = njs_string("usec");
goto done;
}
- ret = njs_externals_init(vm);
- if (ret != NJS_OK) {
+ proto = njs_externals_shared_init(vm);
+ if (proto == NULL) {
goto done;
}
njs_str("20000000"),
1 },
- { "external property ($r.uri)",
- njs_str("$r.uri"),
- njs_str("АБВ"),
+ { "external property ($shared.uri)",
+ njs_str("$shared.uri"),
+ njs_str("shared"),
1000 },
- { "external object property ($r.props.a)",
- njs_str("$r.props.a"),
- njs_str("1"),
+ { "external object property ($shared.props.a)",
+ njs_str("$shared.props.a"),
+ njs_str("4294967295"),
1000 },
- { "external dump (JSON.stringify($r.header))",
- njs_str("JSON.stringify($r.header)"),
+ { "external dump (JSON.stringify($shared.header))",
+ njs_str("JSON.stringify($shared.header)"),
njs_str("{\"01\":\"01|АБВ\",\"02\":\"02|АБВ\",\"03\":\"03|АБВ\"}"),
1000 },
- { "external method ($r.some_method('YES'))",
- njs_str("$r.some_method('YES')"),
- njs_str("АБВ"),
+ { "external method ($shared.method('YES'))",
+ njs_str("$shared.method('YES')"),
+ njs_str("shared"),
1000 },
};
typedef struct {
njs_lvlhsh_t hash;
- const njs_extern_t *proto;
- njs_mp_t *pool;
+ njs_external_proto_t proto;
uint32_t a;
+ uint32_t d;
njs_str_t uri;
njs_opaque_value_t value;
static njs_int_t
-lvlhsh_unit_test_add(njs_unit_test_req_t *r, njs_unit_test_prop_t *prop)
+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.replace = 1;
lhq.value = (void *) prop;
lhq.proto = &lvlhsh_proto;
- lhq.pool = r->pool;
+ lhq.pool = pool;
switch (njs_lvlhsh_insert(&r->hash, &lhq)) {
static njs_int_t
-njs_unit_test_r_get_uri_external(njs_vm_t *vm, njs_value_t *value, void *obj,
- uintptr_t data)
+njs_unit_test_r_uri(njs_vm_t *vm, njs_object_prop_t *prop,
+ njs_value_t *value, njs_value_t *setval, njs_value_t *retval)
{
char *p;
njs_str_t *field;
- p = obj;
- field = (njs_str_t *) (p + data);
-
- return njs_vm_value_string_set(vm, value, field->start, field->length);
-}
-
-
-static njs_int_t
-njs_unit_test_r_set_uri_external(njs_vm_t *vm, void *obj, uintptr_t data,
- njs_str_t *value)
-{
- char *p;
- njs_str_t *field;
+ p = njs_vm_external(vm, value);
+ if (p == NULL) {
+ njs_value_undefined_set(retval);
+ return NJS_DECLINED;
+ }
- p = obj;
- field = (njs_str_t *) (p + data);
+ field = (njs_str_t *) (p + njs_vm_prop_magic32(prop));
- *field = *value;
+ if (setval != NULL) {
+ return njs_vm_value_to_string(vm, field, setval);
+ }
- return NJS_OK;
+ return njs_vm_value_string_set(vm, retval, field->start, field->length);
}
static njs_int_t
-njs_unit_test_r_get_a_external(njs_vm_t *vm, njs_value_t *value, void *obj,
- uintptr_t data)
+njs_unit_test_r_a(njs_vm_t *vm, njs_object_prop_t *prop,
+ njs_value_t *value, njs_value_t *unused, njs_value_t *retval)
{
u_char *p;
njs_unit_test_req_t *r;
u_char buf[16];
- r = (njs_unit_test_req_t *) obj;
+ r = njs_vm_external(vm, 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_set(vm, value, buf, p - buf);
+ return njs_vm_value_string_set(vm, retval, buf, p - buf);
}
static njs_int_t
-njs_unit_test_r_get_b_external(njs_vm_t *vm, njs_value_t *value, void *obj,
- uintptr_t data)
+njs_unit_test_r_b(njs_vm_t *vm, njs_object_prop_t *prop,
+ njs_value_t *value, njs_value_t *unused, njs_value_t *retval)
{
- njs_value_number_set(value, data);
+ njs_value_number_set(retval, njs_vm_prop_magic32(prop));
return NJS_OK;
}
static njs_int_t
-njs_unit_test_host_external(njs_vm_t *vm, njs_value_t *value, void *obj,
- uintptr_t data)
+njs_unit_test_r_d(njs_vm_t *vm, njs_object_prop_t *prop,
+ njs_value_t *value, njs_value_t *unused, njs_value_t *retval)
{
- return njs_vm_value_string_set(vm, value, (u_char *) "АБВГДЕЁЖЗИЙ", 22);
-}
-
-
-static njs_int_t
-njs_unit_test_r_get_vars(njs_vm_t *vm, njs_value_t *value, void *obj,
- uintptr_t data)
-{
- njs_int_t ret;
- njs_str_t *key;
- njs_lvlhsh_query_t lhq;
- njs_unit_test_req_t *r;
- njs_unit_test_prop_t *prop;
-
- r = (njs_unit_test_req_t *) obj;
- key = (njs_str_t *) data;
-
- lhq.key = *key;
- lhq.key_hash = njs_djb_hash(key->start, key->length);
- lhq.proto = &lvlhsh_proto;
-
- ret = njs_lvlhsh_find(&r->hash, &lhq);
-
- prop = lhq.value;
+ njs_unit_test_req_t *r;
- if (ret == NJS_OK && njs_is_valid(&prop->value)) {
- *value = prop->value;
- return NJS_OK;
+ r = njs_vm_external(vm, value);
+ if (r == NULL) {
+ njs_value_undefined_set(retval);
+ return NJS_DECLINED;
}
- njs_value_undefined_set(value);
+ njs_value_number_set(retval, r->d);
return NJS_OK;
}
static njs_int_t
-njs_unit_test_r_set_vars(njs_vm_t *vm, void *obj, uintptr_t data,
- njs_str_t *value)
+njs_unit_test_r_host(njs_vm_t *vm, njs_object_prop_t *prop,
+ njs_value_t *value, njs_value_t *setval, njs_value_t *retval)
+{
+ return njs_vm_value_string_set(vm, retval, (u_char *) "АБВГДЕЁЖЗИЙ", 22);
+}
+
+
+static njs_int_t
+njs_unit_test_r_vars(njs_vm_t *vm, njs_object_prop_t *self,
+ njs_value_t *value, njs_value_t *setval, njs_value_t *retval)
{
njs_int_t ret;
- njs_str_t *key;
- njs_value_t name, val;
+ njs_value_t name;
+ njs_lvlhsh_query_t lhq;
njs_unit_test_req_t *r;
njs_unit_test_prop_t *prop;
- r = (njs_unit_test_req_t *) obj;
- key = (njs_str_t *) data;
-
- if (key->length == 5 && memcmp(key->start, "error", 5) == 0) {
- njs_vm_error(vm, "cannot set \"error\" prop");
- return NJS_ERROR;
+ r = njs_vm_external(vm, value);
+ if (r == NULL) {
+ njs_value_undefined_set(retval);
+ return NJS_DECLINED;
}
- njs_vm_value_string_set(vm, &name, key->start, key->length);
- njs_vm_value_string_set(vm, &val, value->start, value->length);
+ ret = njs_vm_prop_name(vm, self, &lhq.key);
+ if (ret != NJS_OK) {
+ if (setval == NULL && retval != NULL) {
+ /* Get. */
+ njs_value_undefined_set(retval);
+ return NJS_DECLINED;
+ }
- prop = lvlhsh_unit_test_alloc(vm->mem_pool, &name, &val);
- if (prop == NULL) {
- njs_memory_error(vm);
return NJS_ERROR;
}
- ret = lvlhsh_unit_test_add(r, prop);
- if (ret != NJS_OK) {
- njs_vm_error(vm, "lvlhsh_unit_test_add() failed");
- 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;
+ }
}
- return NJS_OK;
-}
-
-
-static njs_int_t
-njs_unit_test_r_del_vars(njs_vm_t *vm, void *obj, uintptr_t data,
- njs_bool_t delete)
-{
- njs_int_t ret;
- njs_str_t *key;
- njs_lvlhsh_query_t lhq;
- njs_unit_test_req_t *r;
- njs_unit_test_prop_t *prop;
+ if (setval != NULL) {
+ /* Set. */
+ njs_vm_value_string_set(vm, &name, lhq.key.start, lhq.key.length);
+ prop = lvlhsh_unit_test_alloc(vm->mem_pool, &name, setval);
+ if (prop == NULL) {
+ njs_memory_error(vm);
+ return NJS_ERROR;
+ }
- r = (njs_unit_test_req_t *) obj;
- key = (njs_str_t *) data;
+ ret = lvlhsh_unit_test_add(vm->mem_pool, r, prop);
+ if (ret != NJS_OK) {
+ njs_vm_error(vm, "lvlhsh_unit_test_add() failed");
+ return NJS_ERROR;
+ }
- if (key->length == 5 && memcmp(key->start, "error", 5) == 0) {
- njs_vm_error(vm, "cannot delete \"error\" prop");
- return NJS_ERROR;
+ return NJS_OK;
}
- lhq.key = *key;
- lhq.key_hash = njs_djb_hash(key->start, key->length);
+ /* 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);
prop = lhq.value;
if (ret == NJS_OK) {
- njs_set_invalid(&prop->value);
+ if (retval == NULL) {
+ njs_set_invalid(&prop->value);
+ return NJS_OK;
+ }
+
+ if (njs_is_valid(&prop->value)) {
+ *retval = prop->value;
+ return NJS_OK;
+ }
}
- return NJS_OK;
+ if (retval != NULL) {
+ njs_value_undefined_set(retval);
+ }
+
+ return NJS_DECLINED;
}
static njs_int_t
-njs_unit_test_header_external(njs_vm_t *vm, njs_value_t *value, void *obj,
- uintptr_t data)
+njs_unit_test_r_header(njs_vm_t *vm, njs_object_prop_t *prop,
+ njs_value_t *value, njs_value_t *unused, njs_value_t *retval)
{
u_char *p;
uint32_t size;
- njs_str_t *h;
+ njs_int_t ret;
+ njs_str_t h;
- h = (njs_str_t *) data;
+ ret = njs_vm_prop_name(vm, prop, &h);
+ if (ret == NJS_OK) {
+ size = 7 + h.length;
- size = 7 + h->length;
+ p = njs_vm_value_string_alloc(vm, retval, size);
+ if (p == NULL) {
+ return NJS_ERROR;
+ }
- p = njs_vm_value_string_alloc(vm, value, size);
- if (p == NULL) {
- return NJS_ERROR;
+ p = njs_cpymem(p, h.start, h.length);
+ *p++ = '|';
+ memcpy(p, "АБВ", njs_length("АБВ"));
+ return NJS_OK;
}
- p = njs_cpymem(p, h->start, h->length);
- *p++ = '|';
- memcpy(p, "АБВ", 6);
+ njs_value_undefined_set(retval);
- return NJS_OK;
+ return NJS_DECLINED;
}
static njs_int_t
-njs_unit_test_header_keys_external(njs_vm_t *vm, void *obj, njs_value_t *keys)
+njs_unit_test_r_header_keys(njs_vm_t *vm, njs_value_t *value, njs_value_t *keys)
{
- njs_int_t rc, i;
- njs_value_t *value;
+ njs_int_t ret, i;
+ njs_value_t *push;
u_char k[2];
- rc = njs_vm_array_alloc(vm, keys, 4);
- if (rc != NJS_OK) {
+ ret = njs_vm_array_alloc(vm, keys, 4);
+ if (ret != NJS_OK) {
return NJS_ERROR;
}
k[1] = '1';
for (i = 0; i < 3; i++) {
- value = njs_vm_array_push(vm, keys);
- if (value == NULL) {
+ push = njs_vm_array_push(vm, keys);
+ if (push == NULL) {
return NJS_ERROR;
}
- (void) njs_vm_value_string_set(vm, value, k, 2);
+ (void) njs_vm_value_string_set(vm, push, k, 2);
k[1]++;
}
static njs_int_t
-njs_unit_test_method_external(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
+njs_unit_test_r_method(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
njs_index_t unused)
{
njs_int_t ret;
r = njs_vm_external(vm, njs_arg(args, nargs, 0));
if (r == NULL) {
+ njs_type_error(vm, "\"this\" is not an external");
return NJS_ERROR;
}
static njs_int_t
-njs_unit_test_create_external(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
+njs_unit_test_r_create(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
njs_index_t unused)
{
njs_int_t ret;
- njs_str_t uri;
- njs_value_t *value;
njs_unit_test_req_t *r, *sr;
r = njs_vm_external(vm, njs_arg(args, nargs, 0));
if (r == NULL) {
+ njs_type_error(vm, "\"this\" is not an external");
return NJS_ERROR;
}
- if (njs_vm_value_to_string(vm, &uri, njs_arg(args, nargs, 1)) != NJS_OK) {
- return NJS_ERROR;
- }
-
- value = njs_mp_zalloc(r->pool, sizeof(njs_opaque_value_t));
- if (value == NULL) {
+ sr = njs_mp_zalloc(vm->mem_pool, sizeof(njs_unit_test_req_t));
+ if (sr == NULL) {
goto memory_error;
}
- sr = njs_mp_zalloc(r->pool, sizeof(njs_unit_test_req_t));
- if (sr == NULL) {
- goto memory_error;
+ if (njs_vm_value_to_string(vm, &sr->uri, njs_arg(args, nargs, 1))
+ != NJS_OK)
+ {
+ return NJS_ERROR;
}
- sr->uri = uri;
- sr->pool = r->pool;
sr->proto = r->proto;
- ret = njs_vm_external_create(vm, value, sr->proto, sr);
+ ret = njs_vm_external_create(vm, &vm->retval, sr->proto, sr, 0);
if (ret != NJS_OK) {
return NJS_ERROR;
}
- njs_vm_retval_set(vm, value);
-
return NJS_OK;
memory_error:
static njs_int_t
-njs_unit_test_bind_external(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
+njs_unit_test_r_bind(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
njs_index_t unused)
{
njs_str_t name;
r = njs_vm_external(vm, njs_arg(args, nargs, 0));
if (r == NULL) {
+ njs_type_error(vm, "\"this\" is not an external");
return NJS_ERROR;
}
}
+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[] = {
- { njs_str("a"),
- NJS_EXTERN_PROPERTY,
- NULL,
- 0,
- njs_unit_test_r_get_a_external,
- NULL,
- NULL,
- NULL,
- NULL,
- 0 },
-
- { njs_str("b"),
- NJS_EXTERN_PROPERTY,
- NULL,
- 0,
- njs_unit_test_r_get_b_external,
- NULL,
- NULL,
- NULL,
- NULL,
- 42 },
+ {
+ .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_external[] = {
+static njs_external_t njs_unit_test_r_header_props[] = {
- { njs_str("uri"),
- NJS_EXTERN_PROPERTY,
- NULL,
- 0,
- njs_unit_test_r_get_uri_external,
- njs_unit_test_r_set_uri_external,
- NULL,
- NULL,
- NULL,
- offsetof(njs_unit_test_req_t, uri) },
-
- { njs_str("host"),
- NJS_EXTERN_PROPERTY,
- NULL,
- 0,
- njs_unit_test_host_external,
- NULL,
- NULL,
- NULL,
- NULL,
- 0 },
-
- { njs_str("props"),
- NJS_EXTERN_OBJECT,
- njs_unit_test_r_props,
- njs_nitems(njs_unit_test_r_props),
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- 0 },
-
- { njs_str("vars"),
- NJS_EXTERN_OBJECT,
- NULL,
- 0,
- njs_unit_test_r_get_vars,
- njs_unit_test_r_set_vars,
- njs_unit_test_r_del_vars,
- NULL,
- NULL,
- 0 },
-
- { njs_str("consts"),
- NJS_EXTERN_OBJECT,
- NULL,
- 0,
- njs_unit_test_r_get_vars,
- NULL,
- NULL,
- NULL,
- NULL,
- 0 },
-
- { njs_str("header"),
- NJS_EXTERN_OBJECT,
- NULL,
- 0,
- njs_unit_test_header_external,
- NULL,
- NULL,
- njs_unit_test_header_keys_external,
- NULL,
- 0 },
-
- { njs_str("some_method"),
- NJS_EXTERN_METHOD,
- NULL,
- 0,
- NULL,
- NULL,
- NULL,
- NULL,
- njs_unit_test_method_external,
- 0 },
-
- { njs_str("create"),
- NJS_EXTERN_METHOD,
- NULL,
- 0,
- NULL,
- NULL,
- NULL,
- NULL,
- njs_unit_test_create_external,
- 0 },
-
- { njs_str("bind"),
- NJS_EXTERN_METHOD,
- NULL,
- 0,
- NULL,
- NULL,
- NULL,
- NULL,
- njs_unit_test_bind_external,
- 0 },
+ {
+ .flags = NJS_EXTERN_PROPERTY | NJS_EXTERN_SYMBOL,
+ .name.symbol = NJS_SYMBOL_TO_STRING_TAG,
+ .u.property = {
+ .value = "Header",
+ }
+ },
};
-static njs_external_t njs_test_external[] = {
+static njs_external_t njs_unit_test_r_external[] = {
- { njs_str("request.proto"),
- NJS_EXTERN_OBJECT,
- njs_unit_test_r_external,
- njs_nitems(njs_unit_test_r_external),
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- 0 },
+ {
+ .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_PROPERTY,
+ .name.string = njs_str("host"),
+ .enumerable = 1,
+ .u.property = {
+ .handler = njs_unit_test_r_host,
+ }
+ },
+
+ {
+ .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_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,
+ }
+ },
};
njs_str_t name;
njs_unit_test_req_t request;
njs_unit_test_prop_t props[2];
-} njs_unit_test_req_t_init_t;
+} njs_unit_test_req_init_t;
-static const njs_unit_test_req_t_init_t njs_test_requests[] = {
+static njs_unit_test_req_init_t njs_test_requests[] = {
+
+ { njs_str("$shared"),
+ {
+ .uri = njs_str("shared"),
+ .a = -1,
+ .d = -2,
+ },
+ {
+ { njs_string("r"), njs_string("rval") },
+ { njs_string("r2"), njs_string("r2val") },
+ }
+ },
{ njs_str("$r"),
- {
- .uri = njs_str("АБВ"),
- .a = 1
- },
- {
- { njs_string("p"), njs_string("pval") },
- { njs_string("p2"), njs_string("p2val") },
- }
+ {
+ .uri = njs_str("АБВ"),
+ .a = 1,
+ .d = 1024,
+ },
+ {
+ { njs_string("p"), njs_string("pval") },
+ { njs_string("p2"), njs_string("p2val") },
+ }
},
{ njs_str("$r2"),
- {
- .uri = njs_str("αβγ"),
- .a = 2
- },
- {
- { njs_string("q"), njs_string("qval") },
- { njs_string("q2"), njs_string("q2val") },
- }
+ {
+ .uri = njs_str("αβγ"),
+ .a = 2,
+ .d = 1025,
+ },
+ {
+ { njs_string("q"), njs_string("qval") },
+ { njs_string("q2"), njs_string("q2val") },
+ }
},
{ njs_str("$r3"),
- {
- .uri = njs_str("abc"),
- .a = 3
- },
- {
- { njs_string("k"), njs_string("kval") },
- { njs_string("k2"), njs_string("k2val") },
- }
+ {
+ .uri = njs_str("abc"),
+ .a = 3,
+ .d = 1026,
+ },
+ {
+ { njs_string("k"), njs_string("kval") },
+ { njs_string("k2"), njs_string("k2val") },
+ }
},
};
-njs_int_t
-njs_externals_init(njs_vm_t *vm)
+static njs_external_proto_t
+njs_externals_init_internal(njs_vm_t *vm, njs_external_proto_t proto,
+ njs_unit_test_req_init_t *init, njs_uint_t n, njs_bool_t shared)
{
njs_int_t ret;
njs_uint_t i, j;
- const njs_extern_t *proto;
njs_unit_test_req_t *requests;
njs_unit_test_prop_t *prop;
- proto = njs_vm_external_prototype(vm, &njs_test_external[0]);
- if (njs_slow_path(proto == NULL)) {
- njs_printf("njs_vm_external_prototype() failed\n");
- return NJS_ERROR;
+ if (proto == NULL) {
+ proto = njs_vm_external_prototype(vm, njs_unit_test_r_external,
+ njs_nitems(njs_unit_test_r_external));
+ if (njs_slow_path(proto == NULL)) {
+ njs_printf("njs_vm_external_prototype() failed\n");
+ return NULL;
+ }
}
- requests = njs_mp_zalloc(vm->mem_pool, njs_nitems(njs_test_requests)
- * sizeof(njs_unit_test_req_t));
+ requests = njs_mp_zalloc(vm->mem_pool, n * sizeof(njs_unit_test_req_t));
if (njs_slow_path(requests == NULL)) {
- return NJS_ERROR;
+ return NULL;
}
- for (i = 0; i < njs_nitems(njs_test_requests); i++) {
+ for (i = 0; i < n; i++) {
- requests[i] = njs_test_requests[i].request;
- requests[i].pool = vm->mem_pool;
+ requests[i] = init[i].request;
requests[i].proto = proto;
ret = njs_vm_external_create(vm, njs_value_arg(&requests[i].value),
- proto, &requests[i]);
+ proto, &requests[i], shared);
if (njs_slow_path(ret != NJS_OK)) {
njs_printf("njs_vm_external_create() failed\n");
- return NJS_ERROR;
+ return NULL;
}
- ret = njs_vm_bind(vm, &njs_test_requests[i].name,
- njs_value_arg(&requests[i].value), 1);
+ 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;
+ return NULL;
}
- for (j = 0; j < njs_nitems(njs_test_requests[i].props); j++) {
- prop = lvlhsh_unit_test_alloc(vm->mem_pool,
- &njs_test_requests[i].props[j].name,
- &njs_test_requests[i].props[j].value);
+ for (j = 0; j < njs_nitems(init[i].props); j++) {
+ prop = lvlhsh_unit_test_alloc(vm->mem_pool, &init[i].props[j].name,
+ &init[i].props[j].value);
if (njs_slow_path(prop == NULL)) {
njs_printf("lvlhsh_unit_test_alloc() failed\n");
- return NJS_ERROR;
+ return NULL;
}
- ret = lvlhsh_unit_test_add(&requests[i], prop);
+ ret = lvlhsh_unit_test_add(vm->mem_pool, &requests[i], prop);
if (njs_slow_path(ret != NJS_OK)) {
njs_printf("lvlhsh_unit_test_add() failed\n");
- return NJS_ERROR;
+ return NULL;
}
}
}
+ return proto;
+}
+
+
+njs_external_proto_t
+njs_externals_shared_init(njs_vm_t *vm)
+{
+ return njs_externals_init_internal(vm, NULL, njs_test_requests, 1, 1);
+}
+
+
+njs_int_t
+njs_externals_init(njs_vm_t *vm, njs_external_proto_t proto)
+{
+ proto = njs_externals_init_internal(vm, proto, &njs_test_requests[1], 3, 0);
+ if (proto == NULL) {
+ return NJS_ERROR;
+ }
+
return NJS_OK;
}
#define _NJS_EXTERNALS_TEST_H_INCLUDED_
-njs_int_t njs_externals_init(njs_vm_t *vm);
+njs_external_proto_t njs_externals_shared_init(njs_vm_t *vm);
+njs_int_t njs_externals_init(njs_vm_t *vm, njs_external_proto_t proto);
#endif /* _NJS_EXTERNALS_TEST_H_INCLUDED_ */
" at eval (native)\n"
" at main (native)\n") },
- { njs_str("$r.some_method({}.a.a)" ENTER),
+ { njs_str("$r.method({}.a.a)" ENTER),
njs_str("TypeError: cannot get property \"a\" of undefined\n"
- " at request.proto.some_method (native)\n"
+ " at $r3.method (native)\n"
" at main (native)\n") },
{ njs_str("new Function(\n\n@)" ENTER),
goto done;
}
- ret = njs_externals_init(vm);
+ ret = njs_externals_init(vm, NULL);
if (ret != NJS_OK) {
goto done;
}
"} a"),
njs_str("A123DT") },
- { njs_str("var t; "
- "switch ($r3.uri) {"
- "case 'abc': "
- " t='A'; "
- " break; "
- "default: "
- " t='F'; "
- "}; t"),
- njs_str("A") },
-
{ njs_str("[isNaN, undefined, isFinite]."
"map((v)=>{switch(v) { case isNaN: return 1; default: return 0;}})"),
njs_str("1,0,0") },
" valueOf: function() { return 0 } }; '12'[n]"),
njs_str("2") },
- /* Externals. */
-
- { njs_str("typeof $r"),
- njs_str("external") },
-
- { njs_str("var a = $r.uri, s = a.fromUTF8(); s.length +' '+ s"),
- njs_str("3 АБВ") },
-
- { njs_str("var a = $r.uri, b = $r2.uri, c = $r3.uri; a+b+c"),
- njs_str("АБВαβγabc") },
-
- { njs_str("var a = $r.uri; $r.uri = $r2.uri; $r2.uri = a; $r2.uri+$r.uri"),
- njs_str("АБВαβγ") },
-
- { njs_str("var a = $r.uri, s = a.fromUTF8(2); s.length +' '+ s"),
- njs_str("2 БВ") },
-
- { njs_str("var a = $r.uri, s = a.fromUTF8(2, 4); s.length +' '+ s"),
- njs_str("1 Б") },
-
- { njs_str("var a = $r.uri; a +' '+ a.length +' '+ a"),
- njs_str("АБВ 6 АБВ") },
-
- { njs_str("$r.uri = 'αβγ'; var a = $r.uri; a.length +' '+ a"),
- njs_str("6 αβγ") },
-
- { njs_str("$r.uri.length +' '+ $r.uri"),
- njs_str("6 АБВ") },
-
- { njs_str("$r.uri = $r.uri.substr(2); $r.uri.length +' '+ $r.uri"),
- njs_str("4 БВ") },
-
- { njs_str("'' + $r.props.a + $r2.props.a + $r.props.a"),
- njs_str("121") },
-
- { njs_str("var p1 = $r.props, p2 = $r2.props; '' + p2.a + p1.a"),
- njs_str("21") },
-
- { njs_str("var p1 = $r.props, p2 = $r2.props; '' + p1.a + p2.a"),
- njs_str("12") },
-
- { njs_str("var p = $r3.props; p.a = 1"),
- njs_str("TypeError: Cannot assign to read-only property \"a\" of external") },
- { njs_str("var p = $r3.props; delete p.a"),
- njs_str("TypeError: Cannot delete property \"a\" of external") },
-
- { njs_str("$r.vars.p + $r2.vars.q + $r3.vars.k"),
- njs_str("pvalqvalkval") },
-
- { njs_str("$r.vars.unset"),
- njs_str("undefined") },
-
- { njs_str("var v = $r3.vars; v.k"),
- njs_str("kval") },
-
- { njs_str("var v = $r3.vars; v.unset = 1; v.unset"),
- njs_str("1") },
-
- { njs_str("$r.vars.unset = 'a'; $r2.vars.unset = 'b';"
- "$r.vars.unset + $r2.vars.unset"),
- njs_str("ab") },
-
- { njs_str("$r.vars.unset = 1; $r2.vars.unset = 2;"
- "$r.vars.unset + $r2.vars.unset"),
- njs_str("12") },
-
- { njs_str("$r3.vars.p = 'a'; $r3.vars.p2 = 'b';"
- "$r3.vars.p + $r3.vars.p2"),
- njs_str("ab") },
-
- { njs_str("$r3.vars.p = 'a'; delete $r3.vars.p; $r3.vars.p"),
- njs_str("undefined") },
-
- { njs_str("$r3.vars.p = 'a'; delete $r3.vars.p; $r3.vars.p = 'b'; $r3.vars.p"),
- njs_str("b") },
-
- { njs_str("$r3.vars.error = 1"),
- njs_str("Error: cannot set \"error\" prop") },
-
- { njs_str("delete $r3.vars.error"),
- njs_str("Error: cannot delete \"error\" prop") },
-
- { njs_str("delete $r3.vars.e"),
- njs_str("true") },
-
- { njs_str("$r3.consts.k"),
- njs_str("kval") },
-
- { njs_str("$r3.consts.k = 1"),
- njs_str("TypeError: Cannot assign to read-only property \"k\" of external") },
-
- { njs_str("delete $r3.consts.k"),
- njs_str("TypeError: Cannot delete property \"k\" of external") },
-
- { njs_str("delete $r3.vars.p; $r3.vars.p"),
- njs_str("undefined") },
-
- { njs_str("var a = $r.host; a +' '+ a.length +' '+ a"),
- njs_str("АБВГДЕЁЖЗИЙ 22 АБВГДЕЁЖЗИЙ") },
-
- { njs_str("var a = $r.host; a.substr(2, 2)"),
- njs_str("Б") },
-
- { njs_str("var a = $r.header['User-Agent']; a +' '+ a.length +' '+ a"),
- njs_str("User-Agent|АБВ 17 User-Agent|АБВ") },
-
- { njs_str("var a='', p;"
- "for (p in $r.header) { a += p +':'+ $r.header[p] +',' }"
- "a"),
- njs_str("01:01|АБВ,02:02|АБВ,03:03|АБВ,") },
-
- { njs_str("$r.some_method('YES')"),
- njs_str("АБВ") },
-
- { njs_str("$r.create('XXX').uri"),
- njs_str("XXX") },
-
- { njs_str("var sr = $r.create('XXX'); sr.uri = 'YYY'; sr.uri"),
- njs_str("YYY") },
-
- { njs_str("var sr = $r.create('XXX'), sr2 = $r.create('YYY');"
- "sr.uri = 'ZZZ'; "
- "sr.uri + sr2.uri"),
- njs_str("ZZZYYY") },
-
- { njs_str("var sr = $r.create('XXX'); sr.vars.p = 'a'; sr.vars.p"),
- njs_str("a") },
-
- { njs_str("var p; for (p in $r.some_method);"),
- njs_str("undefined") },
-
- { njs_str("'uri' in $r"),
- njs_str("true") },
-
- { njs_str("'one' in $r"),
- njs_str("false") },
-
- { njs_str("'a' in $r.props"),
- njs_str("true") },
-
- { njs_str("delete $r.uri"),
- njs_str("TypeError: Cannot delete property \"uri\" of external") },
-
- { njs_str("delete $r.one"),
- njs_str("TypeError: Cannot delete property \"one\" of external") },
-
- { njs_str("$r.some_method.call($r, 'YES')"),
- njs_str("АБВ") },
-
- { njs_str("var f = $r.some_method.bind($r); f('YES')"),
- njs_str("АБВ") },
-
- { njs_str("function f(fn, arg) {return fn(arg);}; f($r.some_method.bind($r), 'YES')"),
- njs_str("АБВ") },
-
- { njs_str("$r.some_method.apply($r, ['YES'])"),
- njs_str("АБВ") },
-
- { njs_str("$r.some_method.call([], 'YES')"),
- njs_str("TypeError: external value is expected") },
-
- { njs_str("$r.nonexistent"),
- njs_str("undefined") },
-
- { njs_str("$r.error = 'OK'"),
- njs_str("TypeError: Cannot assign to read-only property \"error\" of external") },
-
{ njs_str("var a = { toString: function() { return 1 } }; a"),
njs_str("1") },
{ njs_str("({})[{}] = 'test'"),
njs_str("test") },
- { njs_str("var o = {b:$r.props.b}; o.b"),
- njs_str("42") },
-
- { njs_str("$r2.uri == 'αβγ' && $r2.uri === 'αβγ'"),
- njs_str("true") },
-
/**/
{ njs_str("'абвгдеёжзийклмнопрстуфхцчшщъыьэюя'.charCodeAt(5)"),
{ njs_str("Object.getOwnPropertyNames(this).includes('NaN')"),
njs_str("true") },
- { njs_str("Object.keys(this).sort()"),
- njs_str("$r,$r2,$r3,global,njs,process") },
-
- { njs_str("[this, global, globalThis]"
- ".every(v=> { var r = njs.dump(v); return ['$r', 'global', njs.version].every(v=>r.includes(v))})"),
- njs_str("true") },
-
{ njs_str("this.a = 1; this.a"),
njs_str("1") },
{ njs_str("var e = URIError('e'); e.foo = 'E'; JSON.stringify(e)"),
njs_str("{\"foo\":\"E\"}") },
- { njs_str("var r = JSON.parse(JSON.stringify($r));"
- "[r.uri, r.host, r.props.a, njs.dump(r.vars), njs.dump(r.consts), r.header['02']]"),
- njs_str("АБВ,АБВГДЕЁЖЗИЙ,1,{},{},02|АБВ") },
-
{ njs_str("JSON.stringify({get key() {throw new Error('Oops')}})"),
njs_str("Error: Oops") },
{ njs_str("var o = Object.defineProperty({}, 'a', { set(){}, enumerable: true }); njs.dump(o)"),
njs_str("{a:'[Setter]'}") },
- { njs_str("njs.dump($r.props)"),
- njs_str("{a:'1',b:42}") },
-
- { njs_str("njs.dump($r.header)"),
- njs_str("{01:'01|АБВ',02:'02|АБВ',03:'03|АБВ'}") },
-
{ njs_str("njs.dump(njs) == `njs {version:'${njs.version}'}`"),
njs_str("true") },
};
+static njs_unit_test_t njs_externals_test[] =
+{
+ { njs_str("typeof $r"),
+ njs_str("object") },
+
+ { njs_str("var a = $r.uri, s = a.fromUTF8(); s.length +' '+ s"),
+ njs_str("3 АБВ") },
+
+ { njs_str("var a = $r.uri, b = $r2.uri, c = $r3.uri; a+b+c"),
+ njs_str("АБВαβγabc") },
+
+ { njs_str("var a = $r.uri; $r.uri = $r2.uri; $r2.uri = a; $r2.uri+$r.uri"),
+ njs_str("АБВαβγ") },
+
+ { njs_str("var a = $r.uri, s = a.fromUTF8(2); s.length +' '+ s"),
+ njs_str("2 БВ") },
+
+ { njs_str("var a = $r.uri, s = a.fromUTF8(2, 4); s.length +' '+ s"),
+ njs_str("1 Б") },
+
+ { njs_str("var a = $r.uri; a +' '+ a.length +' '+ a"),
+ njs_str("АБВ 6 АБВ") },
+
+ { njs_str("$r.uri = 'αβγ'; var a = $r.uri; a.length +' '+ a"),
+ njs_str("6 αβγ") },
+
+ { njs_str("$r.uri.length +' '+ $r.uri"),
+ njs_str("6 АБВ") },
+
+ { njs_str("var t; "
+ "switch ($r3.uri) {"
+ "case 'abc': "
+ " t='A'; "
+ " break; "
+ "default: "
+ " t='F'; "
+ "}; t"),
+ njs_str("A") },
+
+ { njs_str("$r.uri = $r.uri.substr(2); $r.uri.length +' '+ $r.uri"),
+ njs_str("4 БВ") },
+
+ { njs_str("'' + $r.props.a + $r2.props.a + $r.props.a"),
+ njs_str("121") },
+
+ { njs_str("var p1 = $r.props, p2 = $r2.props; '' + p2.a + p1.a"),
+ njs_str("21") },
+
+ { njs_str("$r.props = $r2.props; $r.props.a"),
+ njs_str("2") },
+
+ { njs_str("var p1 = $r.props, p2 = $r2.props; '' + p1.a + p2.a"),
+ njs_str("12") },
+
+ { njs_str("var p = $r3.props; p.a = 1"),
+ njs_str("TypeError: Cannot assign to read-only property \"a\" of object") },
+
+ { njs_str("var p = $r3.props; delete p.a"),
+ njs_str("TypeError: Cannot delete property \"a\" of object") },
+
+ { njs_str("$r.vars.p + $r2.vars.q + $r3.vars.k"),
+ njs_str("pvalqvalkval") },
+
+ { njs_str("$r.vars.unset"),
+ njs_str("undefined") },
+
+ { njs_str("['k', 'unknown'].map(v=>v in $r3.consts)"),
+ njs_str("true,false") },
+
+ { njs_str("['a', 'unknown'].map(v=>v in $r3.props)"),
+ njs_str("true,false") },
+
+ { njs_str("var v = $r3.vars; v.k"),
+ njs_str("kval") },
+
+ { njs_str("var v = $r3.vars; v.unset = 1; v.unset"),
+ njs_str("1") },
+
+ { njs_str("$r3.a = 1; Object.getOwnPropertyDescriptors($r3).a.value"),
+ njs_str("1") },
+
+ { njs_str("Object.defineProperty($r3.vars, 'a', {value:1}); $r3.vars.a"),
+ njs_str("1") },
+
+ { njs_str("$r3.vars.p = 'a'; delete $r3.vars.p; $r3.vars.p"),
+ njs_str("undefined") },
+
+ { njs_str("$r3.vars.p = 'a'; delete $r3.vars.p; $r3.vars.p = 'b'; $r3.vars.p"),
+ njs_str("b") },
+
+ { njs_str("$r3.vars.error = 1"),
+ njs_str("Error: cannot set \"error\" prop") },
+
+ { njs_str("delete $r3.vars.error"),
+ njs_str("Error: cannot delete \"error\" prop") },
+
+ { njs_str("delete $r3.vars.e"),
+ njs_str("true") },
+
+ { njs_str("delete $r.consts"),
+ njs_str("true") },
+
+ { njs_str("$r3.consts.k"),
+ njs_str("kval") },
+
+ { njs_str("$r3.consts.k = 1"),
+ njs_str("TypeError: Cannot assign to read-only property \"k\" of object") },
+
+ { njs_str("delete $r3.consts.k"),
+ njs_str("TypeError: Cannot delete property \"k\" of object") },
+
+ { njs_str("delete $r3.vars.p; $r3.vars.p"),
+ njs_str("undefined") },
+
+ { njs_str("var a = $r.host; a +' '+ a.length +' '+ a"),
+ njs_str("АБВГДЕЁЖЗИЙ 22 АБВГДЕЁЖЗИЙ") },
+
+ { njs_str("var a = $r.host; a.substr(2, 2)"),
+ njs_str("Б") },
+
+ { njs_str("var a = $r.header['User-Agent']; a +' '+ a.length +' '+ a"),
+ njs_str("User-Agent|АБВ 17 User-Agent|АБВ") },
+
+ { njs_str("var a='', p;"
+ "for (p in $r.header) { a += p +':'+ $r.header[p] +',' }"
+ "a"),
+ njs_str("01:01|АБВ,02:02|АБВ,03:03|АБВ,") },
+
+ { njs_str("$r.method('YES')"),
+ njs_str("АБВ") },
+
+ { njs_str("$r.create('XXX').uri"),
+ njs_str("XXX") },
+
+ { njs_str("var sr = $r.create('XXX'); sr.uri = 'YYY'; sr.uri"),
+ njs_str("YYY") },
+
+ { njs_str("var sr = $r.create('XXX'), sr2 = $r.create('YYY');"
+ "sr.uri = 'ZZZ'; "
+ "sr.uri + sr2.uri"),
+ njs_str("ZZZYYY") },
+
+ { njs_str("var sr = $r.create('XXX'); sr.vars.p = 'a'; sr.vars.p"),
+ njs_str("a") },
+
+ { njs_str("var p; for (p in $r.method);"),
+ njs_str("undefined") },
+
+ { njs_str("'uri' in $r"),
+ njs_str("true") },
+
+ { njs_str("'one' in $r"),
+ njs_str("false") },
+
+ { njs_str("'a' in $r.props"),
+ njs_str("true") },
+
+ { njs_str("delete $r.uri"),
+ njs_str("TypeError: Cannot delete property \"uri\" of object") },
+
+ { njs_str("delete $shared.uri"),
+ njs_str("TypeError: Cannot delete property \"uri\" of object") },
+
+ { njs_str("delete $r.one"),
+ njs_str("true") },
+
+ { njs_str("delete $r.vars"),
+ njs_str("TypeError: Cannot delete property \"vars\" of object") },
+
+ { njs_str("delete $r.header; $r.header"),
+ njs_str("undefined") },
+
+ { njs_str("$r.header = 1; $r.header"),
+ njs_str("1") },
+
+ { njs_str("$r.method.call($r, 'YES')"),
+ njs_str("АБВ") },
+
+ { njs_str("var f = $r.method.bind($r); f('YES')"),
+ njs_str("АБВ") },
+
+ { njs_str("function f(fn, arg) {return fn(arg);}; f($r.method.bind($r), 'YES')"),
+ njs_str("АБВ") },
+
+ { njs_str("$r.method.apply($r, ['YES'])"),
+ njs_str("АБВ") },
+
+ { njs_str("$shared.method.apply($r, ['YES'])"),
+ njs_str("АБВ") },
+
+ { njs_str("$r.method.call([], 'YES')"),
+ njs_str("TypeError: \"this\" is not an external") },
+
+ { njs_str("$r.nonexistent"),
+ njs_str("undefined") },
+
+ { njs_str("$shared.nonexistent"),
+ njs_str("undefined") },
+
+ { njs_str("njs.dump($r).startsWith('External')"),
+ njs_str("true") },
+
+ { njs_str("njs.dump($r.header)"),
+ njs_str("Header {01:'01|АБВ',02:'02|АБВ',03:'03|АБВ'}") },
+
+ { njs_str("var o = {b:$r.props.b}; o.b"),
+ njs_str("42") },
+
+ { njs_str("$r2.uri == 'αβγ' && $r2.uri === 'αβγ'"),
+ njs_str("true") },
+
+ { njs_str("Object.keys(this).sort()"),
+ njs_str("$r,$r2,$r3,$shared,global,njs,process") },
+
+ { njs_str("Object.getOwnPropertySymbols($r2)[0] == Symbol.toStringTag"),
+ njs_str("true") },
+
+ { njs_str("Object.getOwnPropertyDescriptors($r2)[Symbol.toStringTag].value"),
+ njs_str("External") },
+
+ { njs_str("Object.getPrototypeOf($r3) === Object.prototype"),
+ njs_str("true") },
+
+ { njs_str("Object.isExtensible($r3)"),
+ njs_str("true") },
+
+ { njs_str("$r3[0] = 0; $r3[1] = 1; $r3.length = 2;"
+ "Array.prototype.join.call($r3, '|')"),
+ njs_str("0|1") },
+
+ { njs_str("$r3.toJSON = ()=> 'R3';"
+ "JSON.stringify($r3)"),
+ njs_str("\"R3\"") },
+
+ { njs_str("$r3[0] = 0; $r3[1] = 1; $r3.length = 2;"
+ "$r3.__proto__ = Array.prototype; $r3.join('|')"),
+ njs_str("0|1") },
+
+ { njs_str("[this, global, globalThis]"
+ ".every(v=> { var r = njs.dump(v); return ['$r', 'global', njs.version].every(v=>r.includes(v))})"),
+ njs_str("true") },
+
+ { njs_str("var r = JSON.parse(JSON.stringify($r));"
+ "[r.uri, r.host, r.props.a, njs.dump(r.vars), njs.dump(r.consts), r.header['02']]"),
+ njs_str("АБВ,АБВГДЕЁЖЗИЙ,1,{},{},02|АБВ") },
+};
+
static njs_unit_test_t njs_shared_test[] =
{
{ njs_str("var cr = require('crypto'); cr.createHash"),
{ njs_str("isNaN(function(){})"),
njs_str("true") },
+ { njs_str("var a = $r.uri; $r.uri = $r2.uri; $r2.uri = a; $r2.uri + $r.uri"),
+ njs_str("АБВαβγ") },
+
+ { njs_str("njs.dump($r.props)"),
+ njs_str("{a:'1',b:42,c:{d:1024}}") },
+
+ { njs_str("njs.dump($shared.props)"),
+ njs_str("{a:'4294967295',b:42,c:{d:4294967294}}") },
+
+ { njs_str("var r = JSON.parse(JSON.stringify($shared));"
+ "[r.uri, r.host, r.props.a, njs.dump(r.vars), njs.dump(r.consts), r.header['02']]"),
+ njs_str("shared,АБВГДЕЁЖЗИЙ,4294967295,{},{},02|АБВ") },
+
+ { njs_str("$shared.toString()"),
+ njs_str("[object External]") },
+
+ { njs_str("$shared.toString().length"),
+ njs_str("17") },
+
+ { njs_str("delete $shared.method; $shared.method"),
+ njs_str("undefined") },
+
+ { njs_str("$shared.method = () => 1; $shared.method()"),
+ njs_str("1") },
+
+ { njs_str("$shared.method = function() {return this.props.a;}; $shared.method()"),
+ njs_str("4294967295") },
+
{ njs_str("var r; for (var i = 0; i < 2**10; i++) {r = $r.create('XXX').uri;}"),
njs_str("undefined") },
+ { njs_str("$r.vars.unset = 'a'; $r2.vars.unset = 'b';"
+ "$r.vars.unset + $r2.vars.unset"),
+ njs_str("ab") },
+
+ { njs_str("$r.vars.unset = 1; $r2.vars.unset = 2;"
+ "$r.vars.unset + $r2.vars.unset"),
+ njs_str("3") },
+
+ { njs_str("$r3.vars.p = 'a'; $r3.vars.p2 = 'b';"
+ "$r3.vars.p + $r3.vars.p2"),
+ njs_str("ab") },
+
{ njs_str("delete $r3.vars.p; $r3.vars.p"),
njs_str("undefined") },
njs_bool_t unsafe;
njs_bool_t module;
njs_uint_t repeat;
+ njs_uint_t externals;
} njs_opts_t;
njs_unit_test(njs_unit_test_t tests[], size_t num, const char *name,
njs_opts_t *opts, njs_stat_t *stat)
{
- u_char *start;
- njs_vm_t *vm, *nvm;
- njs_int_t ret;
- njs_str_t s;
- njs_uint_t i, repeat;
- njs_stat_t prev;
- njs_bool_t success;
- njs_vm_opt_t options;
+ u_char *start;
+ njs_vm_t *vm, *nvm;
+ njs_int_t ret;
+ njs_str_t s;
+ njs_uint_t i, repeat;
+ njs_stat_t prev;
+ njs_bool_t success;
+ njs_vm_opt_t options;
+ njs_external_proto_t proto;
vm = NULL;
nvm = NULL;
+ proto = NULL;
prev = *stat;
goto done;
}
- ret = njs_externals_init(vm);
- if (ret != NJS_OK) {
- goto done;
+ if (opts->externals) {
+ proto = njs_externals_shared_init(vm);
+ if (proto == NULL) {
+ goto done;
+ }
}
start = tests[i].script.start;
goto done;
}
+ if (opts->externals) {
+ ret = njs_externals_init(nvm, proto);
+ if (ret != NJS_OK) {
+ goto done;
+ }
+ }
+
ret = njs_vm_start(nvm);
} while (--repeat != 0);
njs_mm_denormals(0);
- ret = njs_unit_test(njs_test, njs_nitems(njs_test),
- "script tests (disabled denormals)", &opts, &stat);
- if (ret != NJS_OK) {
- return ret;
- }
-
ret = njs_unit_test(njs_disabled_denormals_test,
njs_nitems(njs_disabled_denormals_test),
"disabled denormals tests", &opts, &stat);
}
opts.module = 0;
+ opts.externals = 1;
+
+ ret = njs_unit_test(njs_externals_test, njs_nitems(njs_externals_test),
+ "externals tests", &opts, &stat);
+ if (ret != NJS_OK) {
+ return ret;
+ }
+
opts.repeat = 128;
ret = njs_unit_test(njs_shared_test, njs_nitems(njs_shared_test),
# console object
njs_test {
+ {"console[Symbol.toStringTag]\r\n"
+ "console\\\[Symbol.toStringTag]\r\n'Console'\r\n>> "}
+ {"Object.prototype.toString.call(console)\r\n"
+ "Object.prototype.toString.call(console)\r\n'\\\[object Console]'\r\n>> "}
+ {"console.toString()\r\n"
+ "console.toString()\r\n'\\\[object Console]'\r\n>> "}
+ {"console\r\n"
+ "console\r\nConsole *>> "}
+ {"delete console.log\r\n"
+ "delete console.log\r\ntrue\r\n>>"}
+ {"console\r\n"
+ "console\r\nConsole *>> "}
+}
+
+# console log functions
+njs_test {
+ {"console[Symbol.toStringTag]\r\n"
+ "console\\\[Symbol.toStringTag]\r\n'Console'\r\n>> "}
+ {"console\r\n"
+ "console\r\nConsole *>> "}
{"console.log()\r\n"
"console.log()\r\nundefined\r\n>> "}
{"console.log('')\r\n"
{"var print = console.dump.bind(console); print(1, 'a', [1, 2])\r\n"
"1 a \\\[\r\n 1,\r\n 2\r\n]\r\nundefined\r\n>> "}
{"var print = console.log.bind(console); print(console.a.a)\r\n"
- "TypeError: cannot get property \"a\" of undefined*at print"}
+ "TypeError: cannot get property \"a\" of undefined*at console.log"}
{"print(console.a.a)\r\n"
- "TypeError: cannot get property \"a\" of undefined*at print"}
+ "TypeError: cannot get property \"a\" of undefined*at console.log"}
}
# Backtraces for external objects
njs_test {
{"console.log(console.a.a)\r\n"
- "console.log(console.a.a)\r\nThrown:\r\nTypeError:*at print (native)"}
+ "console.log(console.a.a)\r\nThrown:\r\nTypeError:*at console.log (native)"}
}
# dumper