]> git.kaiwu.me - njs.git/commitdiff
Externals refactored.
authorDmitry Volyntsev <xeioex@nginx.com>
Tue, 20 Feb 2018 16:12:53 +0000 (19:12 +0300)
committerDmitry Volyntsev <xeioex@nginx.com>
Tue, 20 Feb 2018 16:12:53 +0000 (19:12 +0300)
Public API is rectified to allow the creation of external objects in
runtime.
    1) njs_vm_external_add() is replaced with njs_vm_external_prototype().
    The later functions returns a pointer to a prototype object which can
    be used to create a value with such a prototype in runtime.

    2) njs_vm_external() is split into njs_vm_external_create() and
    njs_vm_external_bind(). The former creates a variable with a specified
    prototype and associates it with an external pointer. The latter binds
    a variable to a name in the global namespace.

18 files changed:
nginx/ngx_http_js_module.c
nginx/ngx_stream_js_module.c
njs/njs.c
njs/njs_builtin.c
njs/njs_extern.c
njs/njs_extern.h
njs/njs_parser.c
njs/njs_parser.h
njs/njs_vm.c
njs/njs_vm.h
njs/njscript.c
njs/njscript.h
njs/test/njs_benchmark.c
njs/test/njs_interactive_test.c
njs/test/njs_unit_test.c
nxt/nxt_array.h
nxt/nxt_lvlhsh.c
nxt/nxt_lvlhsh.h

index b717334c4c01775280a535a4c33b563c43fb0b01..d6d0f5b4502670b42f2fb9d41304732824b9be44 100644 (file)
 #include <nxt_string.h>
 #include <nxt_stub.h>
 #include <nxt_array.h>
-#include <nxt_random.h>
-#include <nxt_lvlhsh.h>
-#include <nxt_mem_cache_pool.h>
 
 #include <njscript.h>
 
 
-#define NGX_HTTP_JS_MCP_CLUSTER_SIZE    (2 * ngx_pagesize)
-#define NGX_HTTP_JS_MCP_PAGE_ALIGNMENT  128
-#define NGX_HTTP_JS_MCP_PAGE_SIZE       512
-#define NGX_HTTP_JS_MCP_MIN_CHUNK_SIZE  16
-
-
-#define ngx_http_js_create_mem_cache_pool()                                   \
-    nxt_mem_cache_pool_create(&ngx_http_js_mem_cache_pool_proto, NULL, NULL,  \
-                              NGX_HTTP_JS_MCP_CLUSTER_SIZE,                   \
-                              NGX_HTTP_JS_MCP_PAGE_ALIGNMENT,                 \
-                              NGX_HTTP_JS_MCP_PAGE_SIZE,                      \
-                              NGX_HTTP_JS_MCP_MIN_CHUNK_SIZE)
-
-
 typedef struct {
     njs_vm_t            *vm;
-    njs_opaque_value_t   args[2];
     ngx_str_t            content;
+    const njs_extern_t  *req_proto;
+    const njs_extern_t  *res_proto;
 } ngx_http_js_loc_conf_t;
 
 
 typedef struct {
     njs_vm_t            *vm;
-    njs_opaque_value_t  *args;
+    njs_opaque_value_t   args[2];
 } ngx_http_js_ctx_t;
 
 
@@ -59,12 +43,7 @@ static ngx_int_t ngx_http_js_handler(ngx_http_request_t *r);
 static ngx_int_t ngx_http_js_variable(ngx_http_request_t *r,
     ngx_http_variable_value_t *v, uintptr_t data);
 static ngx_int_t ngx_http_js_init_vm(ngx_http_request_t *r);
-static void ngx_http_js_cleanup_mem_cache_pool(void *data);
-
-static void *ngx_http_js_alloc(void *mem, size_t size);
-static void *ngx_http_js_calloc(void *mem, size_t size);
-static void *ngx_http_js_memalign(void *mem, size_t alignment, size_t size);
-static void ngx_http_js_free(void *mem, void *p);
+static void ngx_http_js_cleanup_vm(void *data);
 
 static njs_ret_t ngx_http_js_ext_get_string(njs_vm_t *vm, njs_value_t *value,
     void *obj, uintptr_t data);
@@ -183,17 +162,6 @@ ngx_module_t  ngx_http_js_module = {
 };
 
 
-static const nxt_mem_proto_t  ngx_http_js_mem_cache_pool_proto = {
-    ngx_http_js_alloc,
-    ngx_http_js_calloc,
-    ngx_http_js_memalign,
-    NULL,
-    ngx_http_js_free,
-    NULL,
-    NULL,
-};
-
-
 static njs_external_t  ngx_http_js_ext_response[] = {
 
     { nxt_string("headers"),
@@ -284,18 +252,6 @@ static njs_external_t  ngx_http_js_ext_response[] = {
 
 static njs_external_t  ngx_http_js_ext_request[] = {
 
-    { nxt_string("response"),
-      NJS_EXTERN_OBJECT,
-      ngx_http_js_ext_response,
-      nxt_nitems(ngx_http_js_ext_response),
-      NULL,
-      NULL,
-      NULL,
-      NULL,
-      NULL,
-      NULL,
-      0 },
-
     { nxt_string("log"),
       NJS_EXTERN_METHOD,
       NULL,
@@ -396,7 +352,7 @@ static njs_external_t  ngx_http_js_ext_request[] = {
 
 static njs_external_t  ngx_http_js_externals[] = {
 
-    { nxt_string("$r"),
+    { nxt_string("request"),
       NJS_EXTERN_OBJECT,
       ngx_http_js_ext_request,
       nxt_nitems(ngx_http_js_ext_request),
@@ -407,6 +363,18 @@ static njs_external_t  ngx_http_js_externals[] = {
       NULL,
       NULL,
       0 },
+
+    { nxt_string("response"),
+      NJS_EXTERN_OBJECT,
+      ngx_http_js_ext_response,
+      nxt_nitems(ngx_http_js_ext_response),
+      NULL,
+      NULL,
+      NULL,
+      NULL,
+      NULL,
+      NULL,
+      0 },
 };
 
 
@@ -520,11 +488,10 @@ ngx_http_js_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v,
 static ngx_int_t
 ngx_http_js_init_vm(ngx_http_request_t *r)
 {
-    void                    **ext;
-    ngx_http_js_ctx_t        *ctx;
-    ngx_pool_cleanup_t       *cln;
-    nxt_mem_cache_pool_t     *mcp;
-    ngx_http_js_loc_conf_t   *jlcf;
+    nxt_int_t                rc;
+    ngx_http_js_ctx_t       *ctx;
+    ngx_pool_cleanup_t      *cln;
+    ngx_http_js_loc_conf_t  *jlcf;
 
     jlcf = ngx_http_get_module_loc_conf(r, ngx_http_js_module);
     if (jlcf->vm == NULL) {
@@ -546,8 +513,8 @@ ngx_http_js_init_vm(ngx_http_request_t *r)
         return NGX_OK;
     }
 
-    mcp = ngx_http_js_create_mem_cache_pool();
-    if (mcp == NULL) {
+    ctx->vm = njs_vm_clone(jlcf->vm, r);
+    if (ctx->vm == NULL) {
         return NGX_ERROR;
     }
 
@@ -556,65 +523,33 @@ ngx_http_js_init_vm(ngx_http_request_t *r)
         return NGX_ERROR;
     }
 
-    cln->handler = ngx_http_js_cleanup_mem_cache_pool;
-    cln->data = mcp;
+    cln->handler = ngx_http_js_cleanup_vm;
+    cln->data = ctx->vm;
 
-    ext = ngx_palloc(r->pool, sizeof(void *));
-    if (ext == NULL) {
+    if (njs_vm_run(ctx->vm) != NJS_OK) {
         return NGX_ERROR;
     }
 
-    *ext = r;
-
-    ctx->vm = njs_vm_clone(jlcf->vm, mcp, ext);
-    if (ctx->vm == NULL) {
+    rc = njs_vm_external_create(ctx->vm, &ctx->args[0], jlcf->req_proto, r);
+    if (rc != NXT_OK) {
         return NGX_ERROR;
     }
 
-    if (njs_vm_run(ctx->vm) != NJS_OK) {
+    rc = njs_vm_external_create(ctx->vm, &ctx->args[1], jlcf->res_proto, r);
+    if (rc != NXT_OK) {
         return NGX_ERROR;
     }
 
-    ctx->args = &jlcf->args[0];
-
     return NGX_OK;
 }
 
 
 static void
-ngx_http_js_cleanup_mem_cache_pool(void *data)
-{
-    nxt_mem_cache_pool_t *mcp = data;
-
-    nxt_mem_cache_pool_destroy(mcp);
-}
-
-
-static void *
-ngx_http_js_alloc(void *mem, size_t size)
+ngx_http_js_cleanup_vm(void *data)
 {
-    return ngx_alloc(size, ngx_cycle->log);
-}
-
+    njs_vm_t *vm = data;
 
-static void *
-ngx_http_js_calloc(void *mem, size_t size)
-{
-    return ngx_calloc(size, ngx_cycle->log);
-}
-
-
-static void *
-ngx_http_js_memalign(void *mem, size_t alignment, size_t size)
-{
-    return ngx_memalign(alignment, size, ngx_cycle->log);
-}
-
-
-static void
-ngx_http_js_free(void *mem, void *p)
-{
-    ngx_free(p);
+    njs_vm_destroy(vm);
 }
 
 
@@ -1229,12 +1164,10 @@ ngx_http_js_include(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
     ngx_fd_t               fd;
     ngx_str_t             *value, file;
     nxt_int_t              rc;
-    nxt_str_t              text, ext;
+    nxt_str_t              text;
     njs_vm_opt_t           options;
-    nxt_lvlhsh_t           externals;
     ngx_file_info_t        fi;
     ngx_pool_cleanup_t    *cln;
-    nxt_mem_cache_pool_t  *mcp;
 
     if (jlcf->vm) {
         return "is duplicate";
@@ -1295,8 +1228,13 @@ ngx_http_js_include(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
 
     end = start + size;
 
-    mcp = ngx_http_js_create_mem_cache_pool();
-    if (mcp == NULL) {
+    ngx_memzero(&options, sizeof(njs_vm_opt_t));
+
+    options.backtrace = 1;
+
+    jlcf->vm = njs_vm_create(&options);
+    if (jlcf->vm == NULL) {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "failed to create JS VM");
         return NGX_CONF_ERROR;
     }
 
@@ -1305,28 +1243,21 @@ ngx_http_js_include(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
         return NGX_CONF_ERROR;
     }
 
-    cln->handler = ngx_http_js_cleanup_mem_cache_pool;
-    cln->data = mcp;
-
-    nxt_lvlhsh_init(&externals);
+    cln->handler = ngx_http_js_cleanup_vm;
+    cln->data = jlcf->vm;
 
-    if (njs_vm_external_add(&externals, mcp, 0, ngx_http_js_externals,
-                            nxt_nitems(ngx_http_js_externals))
-        != NJS_OK)
-    {
-        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "could not add js externals");
+    jlcf->req_proto = njs_vm_external_prototype(jlcf->vm,
+                                                &ngx_http_js_externals[0]);
+    if (jlcf->req_proto == NULL) {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "failed to add request proto");
         return NGX_CONF_ERROR;
     }
 
-    ngx_memzero(&options, sizeof(njs_vm_opt_t));
-
-    options.mcp = mcp;
-    options.backtrace = 1;
-    options.externals_hash = &externals;
-
-    jlcf->vm = njs_vm_create(&options);
-    if (jlcf->vm == NULL) {
-        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "failed to create JS VM");
+    jlcf->res_proto = njs_vm_external_prototype(jlcf->vm,
+                                                &ngx_http_js_externals[1]);
+    if (jlcf->res_proto == NULL) {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                           "failed to add response proto");
         return NGX_CONF_ERROR;
     }
 
@@ -1348,25 +1279,6 @@ ngx_http_js_include(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
         return NGX_CONF_ERROR;
     }
 
-    ext = nxt_string_value("$r");
-
-    if (njs_vm_external(jlcf->vm, NULL, &ext, &jlcf->args[0]) != NJS_OK) {
-        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                           "js external \"%*s\" not found",
-                           ext.length, ext.start);
-        return NGX_CONF_ERROR;
-    }
-
-    ext = nxt_string_value("response");
-
-    rc = njs_vm_external(jlcf->vm, &jlcf->args[0], &ext, &jlcf->args[1]);
-    if (rc != NXT_OK) {
-        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                           "js external \"$r.%*s\" not found",
-                           ext.length, ext.start);
-        return NGX_CONF_ERROR;
-    }
-
     return NGX_CONF_OK;
 }
 
@@ -1443,6 +1355,8 @@ ngx_http_js_create_loc_conf(ngx_conf_t *cf)
      * set by ngx_pcalloc():
      *
      *     conf->vm = NULL;
+     *     conf->req_proto = NULL;
+     *     conf->res_proto = NULL;
      */
 
     return conf;
@@ -1457,8 +1371,8 @@ ngx_http_js_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
 
     if (conf->vm == NULL) {
         conf->vm = prev->vm;
-        conf->args[0] = prev->args[0];
-        conf->args[1] = prev->args[1];
+        conf->req_proto = prev->req_proto;
+        conf->res_proto = prev->res_proto;
     }
 
     return NGX_CONF_OK;
index e8380b4adc24c33a7ea5f64da22bb8ee4c1c7a5a..f11e1459c064e53fd276beb340d240971b7ccc74 100644 (file)
 #include <nxt_string.h>
 #include <nxt_stub.h>
 #include <nxt_array.h>
-#include <nxt_random.h>
-#include <nxt_lvlhsh.h>
-#include <nxt_mem_cache_pool.h>
 
 #include <njscript.h>
 
 
-#define NGX_STREAM_JS_MCP_CLUSTER_SIZE    (2 * ngx_pagesize)
-#define NGX_STREAM_JS_MCP_PAGE_ALIGNMENT  128
-#define NGX_STREAM_JS_MCP_PAGE_SIZE       512
-#define NGX_STREAM_JS_MCP_MIN_CHUNK_SIZE  16
-
-
-#define ngx_stream_js_create_mem_cache_pool()                                 \
-    nxt_mem_cache_pool_create(&ngx_stream_js_mem_cache_pool_proto, NULL, NULL,\
-                              NGX_STREAM_JS_MCP_CLUSTER_SIZE,                 \
-                              NGX_STREAM_JS_MCP_PAGE_ALIGNMENT,               \
-                              NGX_STREAM_JS_MCP_PAGE_SIZE,                    \
-                              NGX_STREAM_JS_MCP_MIN_CHUNK_SIZE)
-
-
 typedef struct {
     njs_vm_t              *vm;
-    njs_opaque_value_t     arg;
     ngx_str_t              access;
     ngx_str_t              preread;
     ngx_str_t              filter;
+    const njs_extern_t    *proto;
 } ngx_stream_js_srv_conf_t;
 
 
 typedef struct {
     njs_vm_t              *vm;
-    njs_opaque_value_t    *arg;
+    njs_opaque_value_t     arg;
     ngx_buf_t             *buf;
     ngx_chain_t           *free;
     ngx_chain_t           *busy;
@@ -65,13 +48,8 @@ static ngx_int_t ngx_stream_js_body_filter(ngx_stream_session_t *s,
     ngx_chain_t *in, ngx_uint_t from_upstream);
 static ngx_int_t ngx_stream_js_variable(ngx_stream_session_t *s,
     ngx_stream_variable_value_t *v, uintptr_t data);
-static void ngx_stream_js_cleanup_mem_cache_pool(void *data);
 static ngx_int_t ngx_stream_js_init_vm(ngx_stream_session_t *s);
-
-static void *ngx_stream_js_alloc(void *mem, size_t size);
-static void *ngx_stream_js_calloc(void *mem, size_t size);
-static void *ngx_stream_js_memalign(void *mem, size_t alignment, size_t size);
-static void ngx_stream_js_free(void *mem, void *p);
+static void ngx_stream_js_cleanup_vm(void *data);
 
 static njs_ret_t ngx_stream_js_ext_get_remote_address(njs_vm_t *vm,
     njs_value_t *value, void *obj, uintptr_t data);
@@ -169,17 +147,6 @@ ngx_module_t  ngx_stream_js_module = {
 };
 
 
-static const nxt_mem_proto_t  ngx_stream_js_mem_cache_pool_proto = {
-    ngx_stream_js_alloc,
-    ngx_stream_js_calloc,
-    ngx_stream_js_memalign,
-    NULL,
-    ngx_stream_js_free,
-    NULL,
-    NULL,
-};
-
-
 static njs_external_t  ngx_stream_js_ext_session[] = {
 
     { nxt_string("remoteAddress"),
@@ -318,7 +285,7 @@ static njs_external_t  ngx_stream_js_ext_session[] = {
 
 static njs_external_t  ngx_stream_js_externals[] = {
 
-    { nxt_string("$s"),
+    { nxt_string("stream"),
       NJS_EXTERN_OBJECT,
       ngx_stream_js_ext_session,
       nxt_nitems(ngx_stream_js_ext_session),
@@ -405,7 +372,7 @@ ngx_stream_js_phase_handler(ngx_stream_session_t *s, ngx_str_t *name)
         return NGX_ERROR;
     }
 
-    if (njs_vm_call(ctx->vm, func, ctx->arg, 1) != NJS_OK) {
+    if (njs_vm_call(ctx->vm, func, &ctx->arg, 1) != NJS_OK) {
         njs_vm_retval_to_ext_string(ctx->vm, &exception);
 
         ngx_log_error(NGX_LOG_ERR, c->log, 0, "js exception: %*s",
@@ -492,7 +459,7 @@ ngx_stream_js_body_filter(ngx_stream_session_t *s, ngx_chain_t *in,
     while (in) {
         ctx->buf = in->buf;
 
-        if (njs_vm_call(ctx->vm, func, ctx->arg, 1) != NJS_OK) {
+        if (njs_vm_call(ctx->vm, func, &ctx->arg, 1) != NJS_OK) {
             njs_vm_retval_to_ext_string(ctx->vm, &exception);
 
             ngx_log_error(NGX_LOG_ERR, c->log, 0, "js exception: %*s",
@@ -590,7 +557,7 @@ ngx_stream_js_variable(ngx_stream_session_t *s, ngx_stream_variable_value_t *v,
         return NGX_OK;
     }
 
-    if (njs_vm_call(ctx->vm, func, ctx->arg, 1) != NJS_OK) {
+    if (njs_vm_call(ctx->vm, func, &ctx->arg, 1) != NJS_OK) {
         njs_vm_retval_to_ext_string(ctx->vm, &exception);
 
         ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
@@ -617,11 +584,10 @@ ngx_stream_js_variable(ngx_stream_session_t *s, ngx_stream_variable_value_t *v,
 static ngx_int_t
 ngx_stream_js_init_vm(ngx_stream_session_t *s)
 {
-    void                      **ext;
-    ngx_pool_cleanup_t         *cln;
-    nxt_mem_cache_pool_t       *mcp;
-    ngx_stream_js_ctx_t        *ctx;
-    ngx_stream_js_srv_conf_t   *jscf;
+    nxt_int_t                  rc;
+    ngx_pool_cleanup_t        *cln;
+    ngx_stream_js_ctx_t       *ctx;
+    ngx_stream_js_srv_conf_t  *jscf;
 
     jscf = ngx_stream_get_module_srv_conf(s, ngx_stream_js_module);
     if (jscf->vm == NULL) {
@@ -643,8 +609,8 @@ ngx_stream_js_init_vm(ngx_stream_session_t *s)
         return NGX_OK;
     }
 
-    mcp = ngx_stream_js_create_mem_cache_pool();
-    if (mcp == NULL) {
+    ctx->vm = njs_vm_clone(jscf->vm, s);
+    if (ctx->vm == NULL) {
         return NGX_ERROR;
     }
 
@@ -653,65 +619,28 @@ ngx_stream_js_init_vm(ngx_stream_session_t *s)
         return NGX_ERROR;
     }
 
-    cln->handler = ngx_stream_js_cleanup_mem_cache_pool;
-    cln->data = mcp;
-
-    ext = ngx_palloc(s->connection->pool, sizeof(void *));
-    if (ext == NULL) {
-        return NGX_ERROR;
-    }
-
-    *ext = s;
+    cln->handler = ngx_stream_js_cleanup_vm;
+    cln->data = ctx->vm;
 
-    ctx->vm = njs_vm_clone(jscf->vm, mcp, ext);
-    if (ctx->vm == NULL) {
+    if (njs_vm_run(ctx->vm) != NJS_OK) {
         return NGX_ERROR;
     }
 
-    if (njs_vm_run(ctx->vm) != NJS_OK) {
+    rc = njs_vm_external_create(ctx->vm, &ctx->arg, jscf->proto, s);
+    if (rc != NXT_OK) {
         return NGX_ERROR;
     }
 
-    ctx->arg = &jscf->arg;
-
     return NGX_OK;
 }
 
 
 static void
-ngx_stream_js_cleanup_mem_cache_pool(void *data)
-{
-    nxt_mem_cache_pool_t *mcp = data;
-
-    nxt_mem_cache_pool_destroy(mcp);
-}
-
-
-static void *
-ngx_stream_js_alloc(void *mem, size_t size)
-{
-    return ngx_alloc(size, ngx_cycle->log);
-}
-
-
-static void *
-ngx_stream_js_calloc(void *mem, size_t size)
+ngx_stream_js_cleanup_vm(void *data)
 {
-    return ngx_calloc(size, ngx_cycle->log);
-}
-
-
-static void *
-ngx_stream_js_memalign(void *mem, size_t alignment, size_t size)
-{
-    return ngx_memalign(alignment, size, ngx_cycle->log);
-}
+    njs_vm_t *vm = data;
 
-
-static void
-ngx_stream_js_free(void *mem, void *p)
-{
-    ngx_free(p);
+    njs_vm_destroy(vm);
 }
 
 
@@ -937,12 +866,10 @@ ngx_stream_js_include(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
     ngx_fd_t               fd;
     ngx_str_t             *value, file;
     nxt_int_t              rc;
-    nxt_str_t              text, ext;
+    nxt_str_t              text;
     njs_vm_opt_t           options;
-    nxt_lvlhsh_t           externals;
     ngx_file_info_t        fi;
     ngx_pool_cleanup_t    *cln;
-    nxt_mem_cache_pool_t  *mcp;
 
     if (jscf->vm) {
         return "is duplicate";
@@ -1003,8 +930,13 @@ ngx_stream_js_include(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
 
     end = start + size;
 
-    mcp = ngx_stream_js_create_mem_cache_pool();
-    if (mcp == NULL) {
+    ngx_memzero(&options, sizeof(njs_vm_opt_t));
+
+    options.backtrace = 1;
+
+    jscf->vm = njs_vm_create(&options);
+    if (jscf->vm == NULL) {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "failed to create JS VM");
         return NGX_CONF_ERROR;
     }
 
@@ -1013,28 +945,14 @@ ngx_stream_js_include(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
         return NGX_CONF_ERROR;
     }
 
-    cln->handler = ngx_stream_js_cleanup_mem_cache_pool;
-    cln->data = mcp;
+    cln->handler = ngx_stream_js_cleanup_vm;
+    cln->data = jscf->vm;
 
-    nxt_lvlhsh_init(&externals);
+    jscf->proto = njs_vm_external_prototype(jscf->vm,
+                                            &ngx_stream_js_externals[0]);
 
-    if (njs_vm_external_add(&externals, mcp, 0, ngx_stream_js_externals,
-                            nxt_nitems(ngx_stream_js_externals))
-        != NJS_OK)
-    {
-        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "could not add js externals");
-        return NGX_CONF_ERROR;
-    }
-
-    ngx_memzero(&options, sizeof(njs_vm_opt_t));
-
-    options.mcp = mcp;
-    options.backtrace = 1;
-    options.externals_hash = &externals;
-
-    jscf->vm = njs_vm_create(&options);
-    if (jscf->vm == NULL) {
-        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "failed to create JS VM");
+    if (jscf->proto == NULL) {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "failed to add stream proto");
         return NGX_CONF_ERROR;
     }
 
@@ -1056,14 +974,6 @@ ngx_stream_js_include(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
         return NGX_CONF_ERROR;
     }
 
-    ext = nxt_string_value("$s");
-
-    if (njs_vm_external(jscf->vm, NULL, &ext, &jscf->arg) != NJS_OK) {
-        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                       "js external \"%*s\" not found", ext.length, ext.start);
-        return NGX_CONF_ERROR;
-    }
-
     return NGX_CONF_OK;
 }
 
@@ -1118,7 +1028,7 @@ ngx_stream_js_create_srv_conf(ngx_conf_t *cf)
      * set by ngx_pcalloc():
      *
      *     conf->vm = NULL;
-     *     conf->arg = NULL;
+     *     conf->proto = NULL;
      *     conf->access = { 0, NULL };
      *     conf->preread = { 0, NULL };
      *     conf->filter = { 0, NULL };
@@ -1136,7 +1046,7 @@ ngx_stream_js_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
 
     if (conf->vm == NULL) {
         conf->vm = prev->vm;
-        conf->arg = prev->arg;
+        conf->proto = prev->proto;
     }
 
     ngx_conf_merge_str_value(conf->access, prev->access, "");
index ee7cc901a2217a3d5cfb370c6e8869e5205f3157..c4bdb1cab39fe948ffa98fd496216ad7dddbdbf0 100644 (file)
--- a/njs/njs.c
+++ b/njs/njs.c
@@ -60,7 +60,7 @@ typedef struct {
 
 
 static nxt_int_t njs_get_options(njs_opts_t *opts, int argc, char **argv);
-static nxt_int_t njs_externals_init(njs_opts_t *opts, njs_vm_opt_t *vm_options);
+static nxt_int_t njs_externals_init(njs_vm_t *vm);
 static nxt_int_t njs_interactive_shell(njs_opts_t *opts,
     njs_vm_opt_t *vm_options);
 static nxt_int_t njs_process_file(njs_opts_t *opts, njs_vm_opt_t *vm_options);
@@ -119,17 +119,15 @@ static njs_external_t  njs_externals[] = {
 };
 
 
-static nxt_lvlhsh_t      njs_externals_hash;
 static njs_completion_t  njs_completion;
 
 
 int
 main(int argc, char **argv)
 {
-    nxt_int_t             ret;
-    njs_opts_t            opts;
-    njs_vm_opt_t          vm_options;
-    nxt_mem_cache_pool_t  *mcp;
+    nxt_int_t     ret;
+    njs_opts_t    opts;
+    njs_vm_opt_t  vm_options;
 
     memset(&opts, 0, sizeof(njs_opts_t));
     opts.interactive = 1;
@@ -144,22 +142,11 @@ main(int argc, char **argv)
         return EXIT_SUCCESS;
     }
 
-    mcp = nxt_mem_cache_pool_create(&njs_vm_mem_cache_pool_proto, NULL,
-                                    NULL, 2 * nxt_pagesize(), 128, 512, 16);
-    if (nxt_slow_path(mcp == NULL)) {
-        return EXIT_FAILURE;
-    }
-
     memset(&vm_options, 0, sizeof(njs_vm_opt_t));
 
-    vm_options.mcp = mcp;
     vm_options.accumulative = 1;
     vm_options.backtrace = 1;
 
-    if (njs_externals_init(&opts, &vm_options) != NXT_OK) {
-        return EXIT_FAILURE;
-    }
-
     if (opts.interactive) {
         ret = njs_interactive_shell(&opts, &vm_options);
 
@@ -218,30 +205,35 @@ njs_get_options(njs_opts_t *opts, int argc, char** argv)
 
 
 static nxt_int_t
-njs_externals_init(njs_opts_t *opts, njs_vm_opt_t *vm_options)
+njs_externals_init(njs_vm_t *vm)
 {
-    void        **ext;
-    nxt_uint_t  i;
+    nxt_uint_t          ret;
+    const njs_extern_t  *proto;
+    njs_opaque_value_t  *value;
 
-    nxt_lvlhsh_init(&njs_externals_hash);
+    static const nxt_str_t name = nxt_string_value("console");
 
-    for (i = 0; i < nxt_nitems(njs_externals); i++) {
-        if (njs_vm_external_add(&njs_externals_hash, vm_options->mcp,
-                                (uintptr_t) i, &njs_externals[i], 1)
-            != NXT_OK)
-        {
-            fprintf(stderr, "could not add external objects\n");
-            return NXT_ERROR;
-        }
+    proto = njs_vm_external_prototype(vm, &njs_externals[0]);
+    if (proto == NULL) {
+        fprintf(stderr, "failed to add console proto\n");
+        return NXT_ERROR;
     }
 
-    ext = nxt_mem_cache_zalloc(vm_options->mcp, sizeof(void *) * i);
-    if (ext == NULL) {
+    value = nxt_mem_cache_zalloc(vm->mem_cache_pool,
+                                 sizeof(njs_opaque_value_t));
+    if (value == NULL) {
         return NXT_ERROR;
     }
 
-    vm_options->external = ext;
-    vm_options->externals_hash = &njs_externals_hash;
+    ret = njs_vm_external_create(vm, value, proto, NULL);
+    if (ret != NXT_OK) {
+        return NXT_ERROR;
+    }
+
+    ret = njs_vm_external_bind(vm, &name, value);
+    if (ret != NXT_OK) {
+        return NXT_ERROR;
+    }
 
     return NXT_OK;
 }
@@ -260,6 +252,10 @@ njs_interactive_shell(njs_opts_t *opts, njs_vm_opt_t *vm_options)
         return NXT_ERROR;
     }
 
+    if (njs_externals_init(vm) != NXT_OK) {
+        return NXT_ERROR;
+    }
+
     if (njs_editline_init(vm) != NXT_OK) {
         fprintf(stderr, "failed to init completions\n");
         return NXT_ERROR;
@@ -393,6 +389,10 @@ njs_process_file(njs_opts_t *opts, njs_vm_opt_t *vm_options)
         goto done;
     }
 
+    if (njs_externals_init(vm) != NXT_OK) {
+        return NXT_ERROR;
+    }
+
     ret = njs_process_script(vm, opts, &script, &out);
     if (ret != NXT_OK) {
         fprintf(stderr, "failed to get retval from VM\n");
@@ -652,10 +652,7 @@ njs_ext_console_help(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs,
     }
 
     printf("\nEmbedded objects:\n");
-    for (i = 0; i < nxt_nitems(njs_externals); i++) {
-        printf("  %.*s\n", (int) njs_externals[i].name.length,
-               njs_externals[i].name.start);
-    }
+    printf("  console\n");
 
     printf("\n");
 
index d04570a9b9b4abe086f4b0581b7e37b3523ca782..314adbcf8c3357e698ce6b84b9f079cd4f716c19 100644 (file)
@@ -513,12 +513,13 @@ njs_builtin_completions(njs_vm_t *vm, size_t *size, nxt_str_t *completions)
     size_t                  n, len;
     nxt_str_t               string;
     nxt_uint_t              i, k;
-    njs_extern_t            *ext_object, *ext_prop;
     njs_object_t            *objects;
     njs_keyword_t           *keyword;
     njs_function_t          *constructors;
     njs_object_prop_t       *prop;
     nxt_lvlhsh_each_t       lhe, lhe_prop;
+    njs_extern_value_t      *ev;
+    const njs_extern_t      *ext_proto, *ext_prop;
     njs_object_prototype_t  *prototypes;
 
     n = 0;
@@ -652,26 +653,27 @@ njs_builtin_completions(njs_vm_t *vm, size_t *size, nxt_str_t *completions)
         }
     }
 
-    nxt_lvlhsh_each_init(&lhe, &njs_extern_hash_proto);
+    nxt_lvlhsh_each_init(&lhe, &njs_extern_value_hash_proto);
 
     for ( ;; ) {
-        ext_object = nxt_lvlhsh_each(&vm->externals_hash, &lhe);
+        ev = nxt_lvlhsh_each(&vm->externals_hash, &lhe);
 
-        if (ext_object == NULL) {
+        if (ev == NULL) {
             break;
         }
 
+        ext_proto = ev->value->external.proto;
+
         nxt_lvlhsh_each_init(&lhe_prop, &njs_extern_hash_proto);
 
         if (completions != NULL) {
-            len = ext_object->name.length + 1;
+            len = ev->name.length + 1;
             compl = nxt_mem_cache_zalloc(vm->mem_cache_pool, len);
             if (compl == NULL) {
                 return NXT_ERROR;
             }
 
-            snprintf(compl, len, "%.*s",
-                     (int) ext_object->name.length, ext_object->name.start);
+            snprintf(compl, len, "%.*s", (int) ev->name.length, ev->name.start);
 
             completions[n].length = len;
             completions[n++].start = (u_char *) compl;
@@ -681,22 +683,22 @@ njs_builtin_completions(njs_vm_t *vm, size_t *size, nxt_str_t *completions)
         }
 
         for ( ;; ) {
-            ext_prop = nxt_lvlhsh_each(&ext_object->hash, &lhe_prop);
+            ext_prop = nxt_lvlhsh_each(&ext_proto->hash, &lhe_prop);
 
             if (ext_prop == NULL) {
                 break;
             }
 
             if (completions != NULL) {
-                len = ext_object->name.length + ext_prop->name.length + 2;
+                len = ev->name.length + ev->name.length + 2;
                 compl = nxt_mem_cache_zalloc(vm->mem_cache_pool, len);
                 if (compl == NULL) {
                     return NXT_ERROR;
                 }
 
-                snprintf(compl, len, "%.*s.%.*s",
-                         (int) ext_object->name.length, ext_object->name.start,
-                         (int) ext_prop->name.length, ext_prop->name.start);
+                snprintf(compl, len, "%.*s.%.*s", (int) ev->name.length,
+                         ev->name.start, (int) ext_prop->name.length,
+                         ext_prop->name.start);
 
                 completions[n].length = len;
                 completions[n++].start = (u_char *) compl;
index 17bffccba26ce6c0b2afb6ade983f3fbd40ea3b9..df2e28bf6be72dc7d45f86c0aa180d231b57b262 100644 (file)
@@ -29,10 +29,8 @@ njs_extern_hash_test(nxt_lvlhsh_query_t *lhq, void *data)
 {
     njs_extern_t  *ext;
 
-    ext = data;
+    ext = (njs_extern_t *) data;
 
-// STUB
-//    if (nxt_strcasestr_eq(&lhq->key, &ext->name)) {
     if (nxt_strstr_eq(&lhq->key, &ext->name)) {
         return NXT_OK;
     }
@@ -41,6 +39,21 @@ njs_extern_hash_test(nxt_lvlhsh_query_t *lhq, void *data)
 }
 
 
+static nxt_int_t
+njs_extern_value_hash_test(nxt_lvlhsh_query_t *lhq, void *data)
+{
+    njs_extern_value_t  *ev;
+
+    ev = (njs_extern_value_t *) data;
+
+    if (nxt_strstr_eq(&lhq->key, &ev->name)) {
+        return NXT_OK;
+    }
+
+    return NXT_DECLINED;
+}
+
+
 const nxt_lvlhsh_proto_t  njs_extern_hash_proto
     nxt_aligned(64) =
 {
@@ -52,71 +65,78 @@ const nxt_lvlhsh_proto_t  njs_extern_hash_proto
 };
 
 
-nxt_int_t
-njs_vm_external_add(nxt_lvlhsh_t *hash, nxt_mem_cache_pool_t *mcp,
-    uintptr_t object, njs_external_t *external, nxt_uint_t n)
+const nxt_lvlhsh_proto_t  njs_extern_value_hash_proto
+    nxt_aligned(64) =
+{
+    NXT_LVLHSH_DEFAULT,
+    NXT_LVLHSH_BATCH_ALLOC,
+    njs_extern_value_hash_test,
+    njs_lvlhsh_alloc,
+    njs_lvlhsh_free,
+};
+
+
+static njs_extern_t *
+njs_vm_external_add(njs_vm_t *vm, nxt_lvlhsh_t *hash, njs_external_t *external,
+    nxt_uint_t n)
 {
     nxt_int_t           ret;
-    njs_extern_t        *ext;
+    njs_extern_t        *ext, *child;
     nxt_lvlhsh_query_t  lhq;
 
     do {
-        ext = nxt_mem_cache_align(mcp, sizeof(njs_value_t),
-                                 sizeof(njs_extern_t));
+        ext = nxt_mem_cache_alloc(vm->mem_cache_pool, sizeof(njs_extern_t));
         if (nxt_slow_path(ext == NULL)) {
-            return NXT_ERROR;
-        }
-
-        ext->name.length = external->name.length;
-        ext->name.start = nxt_mem_cache_alloc(mcp, external->name.length);
-        if (nxt_slow_path(ext->name.start == NULL)) {
-            return NXT_ERROR;
+            return NULL;
         }
 
-        memcpy(ext->name.start, external->name.start, external->name.length);
-
-        ext->value.type = NJS_EXTERNAL;
-        ext->value.data.truth = 1;
-        ext->value.data.u.external = ext;
-
-        if (external->method != NULL) {
-            ext->function = nxt_mem_cache_zalloc(mcp, sizeof(njs_function_t));
-            if (nxt_slow_path(ext->function == NULL)) {
-                return NXT_ERROR;
-            }
-
-            ext->function->native = 1;
-            ext->function->args_offset = 1;
-            ext->function->u.native = external->method;
-        }
+        ext->name = external->name;
 
         nxt_lvlhsh_init(&ext->hash);
+
         ext->type = external->type;
         ext->get = external->get;
         ext->set = external->set;
         ext->find = external->find;
         ext->foreach = external->foreach;
         ext->next = external->next;
-        ext->object = object;
         ext->data = external->data;
 
-        lhq.key_hash = nxt_djb_hash(external->name.start, external->name.length);
-        lhq.key = ext->name;
-        lhq.replace = 0;
-        lhq.value = ext;
-        lhq.pool = mcp;
-        lhq.proto = &njs_extern_hash_proto;
+        if (external->method != NULL) {
+            ext->function = nxt_mem_cache_zalloc(vm->mem_cache_pool,
+                                                 sizeof(njs_function_t));
+            if (nxt_slow_path(ext->function == NULL)) {
+                return NULL;
+            }
+
+            ext->function->native = 1;
+            ext->function->args_offset = 1;
+            ext->function->u.native = external->method;
 
-        ret = nxt_lvlhsh_insert(hash, &lhq);
-        if (nxt_slow_path(ret != NXT_OK)) {
-            return ret;
+        } else {
+            ext->function = NULL;
         }
 
         if (external->properties != NULL) {
-            ret = njs_vm_external_add(&ext->hash, mcp, object,
-                                   external->properties, external->nproperties);
+            child = njs_vm_external_add(vm, &ext->hash, external->properties,
+                                        external->nproperties);
+            if (nxt_slow_path(child == NULL)) {
+                return NULL;
+            }
+        }
+
+        if (hash != NULL) {
+            lhq.key_hash = nxt_djb_hash(external->name.start,
+                                        external->name.length);
+            lhq.key = ext->name;
+            lhq.replace = 0;
+            lhq.value = ext;
+            lhq.pool = vm->mem_cache_pool;
+            lhq.proto = &njs_extern_hash_proto;
+
+            ret = nxt_lvlhsh_insert(hash, &lhq);
             if (nxt_slow_path(ret != NXT_OK)) {
-                return ret;
+                return NULL;
             }
         }
 
@@ -125,62 +145,99 @@ njs_vm_external_add(nxt_lvlhsh_t *hash, nxt_mem_cache_pool_t *mcp,
 
     } while (n != 0);
 
-    return NXT_OK;
+    return ext;
+}
+
+
+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);
 }
 
 
 nxt_int_t
-njs_vm_external(njs_vm_t *vm, njs_opaque_value_t *obj, nxt_str_t *property,
-    njs_opaque_value_t *value)
+njs_vm_external_create(njs_vm_t *vm, njs_opaque_value_t *value,
+    const njs_extern_t *proto,  void *object)
 {
-    uint32_t            (*key_hash)(const void *, size_t);
-    njs_value_t         *object;
-    njs_extern_t        *ext;
-    nxt_lvlhsh_t        hash;
-    nxt_lvlhsh_query_t  lhq;
+    void         *obj;
+    njs_value_t  *ext_val;
 
-    object = (njs_value_t *) obj;
+    if (nxt_slow_path(proto == NULL)) {
+        return NXT_ERROR;
+    }
 
-    key_hash = nxt_djb_hash;
-    hash = vm->externals_hash;
+    obj = nxt_array_add(vm->external_objects, &njs_array_mem_proto,
+                        vm->mem_cache_pool);
+    if (nxt_slow_path(obj == NULL)) {
+        return NXT_ERROR;
+    }
 
-    if (object != NULL) {
-        if (!njs_is_external(object)) {
-            return NXT_ERROR;
-        }
+    memcpy(obj, &object, sizeof(void *));
 
-        ext = object->data.u.external;
-        hash = ext->hash;
+    ext_val = (njs_value_t *) value;
 
-        if (ext->type == NJS_EXTERN_CASELESS_OBJECT) {
-            key_hash = nxt_djb_hash_lowcase;
-        }
+    ext_val->type = NJS_EXTERNAL;
+    ext_val->data.truth = 1;
+    ext_val->external.proto = proto;
+    ext_val->external.index = vm->external_objects->items - 1;
+
+    return NXT_OK;
+}
+
+
+nxt_int_t
+njs_vm_external_bind(njs_vm_t *vm, const nxt_str_t *var_name,
+    njs_opaque_value_t *val)
+{
+    nxt_int_t           ret;
+    njs_value_t         *value;
+    njs_extern_value_t  *ev;
+    nxt_lvlhsh_query_t  lhq;
+
+    value = (njs_value_t *) val;
+
+    if (nxt_slow_path(!njs_is_external(value))) {
+        return NXT_ERROR;
+    }
+
+    ev = nxt_mem_cache_alloc(vm->mem_cache_pool, sizeof(njs_extern_value_t));
+    if (nxt_slow_path(ev == NULL)) {
+        return NXT_ERROR;
     }
 
-    lhq.key_hash = key_hash(property->start, property->length);
-    lhq.key = *property;
-    lhq.proto = &njs_extern_hash_proto;
+    ev->name = *var_name;
+    ev->value = value;
 
-    if (nxt_lvlhsh_find(&hash, &lhq) == NXT_OK) {
-        *value = *(njs_opaque_value_t *) lhq.value;
-        return NXT_OK;
+    lhq.key = *var_name;
+    lhq.key_hash = nxt_djb_hash(lhq.key.start, lhq.key.length);
+    lhq.proto = &njs_extern_value_hash_proto;
+    lhq.value = ev;
+    lhq.replace = 0;
+    lhq.pool = vm->mem_cache_pool;
+
+    ret = nxt_lvlhsh_insert(&vm->externals_hash, &lhq);
+    if (nxt_slow_path(ret != NXT_OK)) {
+        return ret;
     }
 
-    return NXT_ERROR;
+    return NXT_OK;
 }
 
 
-njs_extern_t *
+njs_value_t *
 njs_parser_external(njs_vm_t *vm, njs_parser_t *parser)
 {
     nxt_lvlhsh_query_t  lhq;
+    njs_extern_value_t  *ev;
 
     lhq.key_hash = parser->lexer->key_hash;
     lhq.key = parser->lexer->text;
-    lhq.proto = &njs_extern_hash_proto;
+    lhq.proto = &njs_extern_value_hash_proto;
 
     if (nxt_lvlhsh_find(&vm->externals_hash, &lhq) == NXT_OK) {
-        return lhq.value;
+        ev = (njs_extern_value_t *) lhq.value;
+        return ev->value;
     }
 
     return NULL;
index ea39a574ec16afe432bc8e0d4f97d9d29d5b0a96..2ef45e825ac5fd2a809244b264e87a82ce40ec1e 100644 (file)
@@ -8,9 +8,11 @@
 #define _NJS_EXTERN_H_INCLUDED_
 
 
-struct njs_extern_s {
-    njs_value_t                  value;
+#define njs_extern_object(vm, ext)                                          \
+    (*(void **) nxt_array_item((vm)->external_objects, (ext)->external.index))
+
 
+struct njs_extern_s {
     /* A hash of inclusive njs_extern_t. */
     nxt_lvlhsh_t                 hash;
 
@@ -26,12 +28,18 @@ struct njs_extern_s {
 
     njs_function_t               *function;
 
-    uintptr_t                    object;
     uintptr_t                    data;
 };
 
 
+typedef struct {
+    nxt_str_t               name;
+    njs_value_t             *value;
+} njs_extern_value_t;
+
+
 extern const nxt_lvlhsh_proto_t  njs_extern_hash_proto;
+extern const nxt_lvlhsh_proto_t  njs_extern_value_hash_proto;
 
 
 #endif /* _NJS_EXTERN_H_INCLUDED_ */
index 1cdc6445a8a0aae211f012ab188fb469e5727ba2..5083a3146e74e2af7ba314f7e52eaed75cd09e2b 100644 (file)
@@ -17,6 +17,7 @@
 #include <nxt_djb_hash.h>
 #include <njscript.h>
 #include <njs_vm.h>
+#include <njs_extern.h>
 #include <njs_number.h>
 #include <njs_string.h>
 #include <njs_object.h>
@@ -1807,7 +1808,7 @@ njs_parser_terminal(njs_vm_t *vm, njs_parser_t *parser, njs_token_t token)
 {
     double             num;
     njs_ret_t          ret;
-    njs_extern_t       *ext;
+    njs_value_t        *ext;
     njs_parser_node_t  *node;
 
     if (token == NJS_TOKEN_OPEN_PARENTHESIS) {
@@ -1846,8 +1847,7 @@ njs_parser_terminal(njs_vm_t *vm, njs_parser_t *parser, njs_token_t token)
 
         if (ext != NULL) {
             node->token = NJS_TOKEN_EXTERNAL;
-            node->u.value.type = NJS_EXTERNAL;
-            node->u.value.data.truth = 1;
+            node->u.value = *ext;
             node->index = (njs_index_t) ext;
             break;
         }
index fdbdd2317a82f7957e1c787f2f124cf83732720a..f9fa8f54cab5e514300f6a61e10c246b64a9d733 100644 (file)
@@ -264,7 +264,6 @@ struct njs_parser_node_s {
         njs_value_t                 value;
         njs_vmcode_operation_t      operation;
         njs_parser_node_t           *object;
-        njs_extern_t                *external;
     } u;
 
     njs_index_t                     index;
@@ -359,7 +358,7 @@ nxt_int_t njs_lexer_keywords_init(nxt_mem_cache_pool_t *mcp,
     nxt_lvlhsh_t *hash);
 njs_token_t njs_lexer_keyword(njs_lexer_t *lexer);
 
-njs_extern_t *njs_parser_external(njs_vm_t *vm, njs_parser_t *parser);
+njs_value_t *njs_parser_external(njs_vm_t *vm, njs_parser_t *parser);
 
 njs_parser_node_t *njs_parser(njs_vm_t *vm, njs_parser_t *parser,
     njs_parser_t *prev);
index 7dd1f60e6e9de8d5f5f6ded1a12ab75ffefdf189..bfb35dd128240809e58e875121274a3f558a0ec7 100644 (file)
@@ -519,15 +519,16 @@ njs_ret_t
 njs_vmcode_property_get(njs_vm_t *vm, njs_value_t *object,
     njs_value_t *property)
 {
+    void                  *obj;
     int32_t               index;
     uintptr_t             data;
     njs_ret_t             ret;
-    njs_value_t           *val;
-    njs_extern_t          *ext;
+    njs_value_t           *val, ext_val;
     njs_slice_prop_t      slice;
     njs_string_prop_t     string;
     njs_object_prop_t     *prop;
     const njs_value_t     *retval;
+    const njs_extern_t    *ext_proto;
     njs_property_query_t  pq;
 
     pq.query = NJS_PROPERTY_QUERY_GET;
@@ -615,19 +616,24 @@ njs_vmcode_property_get(njs_vm_t *vm, njs_value_t *object,
         break;
 
     case NJS_EXTERNAL_VALUE:
-        ext = object->data.u.external;
+        ext_proto = object->external.proto;
 
-        ret = nxt_lvlhsh_find(&ext->hash, &pq.lhq);
+        ret = nxt_lvlhsh_find(&ext_proto->hash, &pq.lhq);
 
         if (ret == NXT_OK) {
-            ext = pq.lhq.value;
+            ext_proto = pq.lhq.value;
 
-            if ((ext->type & NJS_EXTERN_OBJECT) != 0) {
-                retval = &ext->value;
+            ext_val.type = NJS_EXTERNAL;
+            ext_val.data.truth = 1;
+            ext_val.external.proto = ext_proto;
+            ext_val.external.index = object->external.index;
+
+            if ((ext_proto->type & NJS_EXTERN_OBJECT) != 0) {
+                retval = &ext_val;
                 break;
             }
 
-            data = ext->data;
+            data = ext_proto->data;
 
         } else {
             data = (uintptr_t) &pq.lhq.key;
@@ -635,13 +641,15 @@ njs_vmcode_property_get(njs_vm_t *vm, njs_value_t *object,
 
         vm->retval = njs_value_void;
 
-        if (ext->get != NULL) {
-            ret = ext->get(vm, &vm->retval, vm->external[ext->object], data);
+        if (ext_proto->get != NULL) {
+            obj = njs_extern_object(vm, object);
+
+            ret = ext_proto->get(vm, &vm->retval, obj, data);
             if (nxt_slow_path(ret != NXT_OK)) {
                 return ret;
             }
 
-            /* The vm->retval is already retained by ext->get(). */
+            /* The vm->retval is already retained by ext_proto->get(). */
         }
 
         return sizeof(njs_vmcode_prop_get_t);
@@ -665,12 +673,13 @@ njs_ret_t
 njs_vmcode_property_set(njs_vm_t *vm, njs_value_t *object,
     njs_value_t *property)
 {
+    void                   *obj;
     uintptr_t              data;
     nxt_str_t              s;
     njs_ret_t              ret;
     njs_value_t            *p, *value;
-    njs_extern_t           *ext;
     njs_object_prop_t      *prop;
+    const njs_extern_t     *ext_proto;
     njs_property_query_t   pq;
     njs_vmcode_prop_set_t  *code;
 
@@ -726,19 +735,19 @@ njs_vmcode_property_set(njs_vm_t *vm, njs_value_t *object,
         return sizeof(njs_vmcode_prop_set_t);
 
     case NJS_EXTERNAL_VALUE:
-        ext = object->data.u.external;
+        ext_proto = object->external.proto;
 
-        ret = nxt_lvlhsh_find(&ext->hash, &pq.lhq);
+        ret = nxt_lvlhsh_find(&ext_proto->hash, &pq.lhq);
 
         if (ret == NXT_OK) {
-            ext = pq.lhq.value;
-            data = ext->data;
+            ext_proto = pq.lhq.value;
+            data = ext_proto->data;
 
         } else {
             data = (uintptr_t) &pq.lhq.key;
         }
 
-        if (ext->set != NULL) {
+        if (ext_proto->set != NULL) {
             ret = njs_vm_value_to_ext_string(vm, &s, value, 0);
             if (nxt_slow_path(ret != NXT_OK)) {
                 return ret;
@@ -746,7 +755,9 @@ njs_vmcode_property_set(njs_vm_t *vm, njs_value_t *object,
 
             /* TODO retain value if it is string. */
 
-            ret = ext->set(vm, vm->external[ext->object], data, &s);
+            obj = njs_extern_object(vm, object);
+
+            ret = ext_proto->set(vm, obj, data, &s);
             if (nxt_slow_path(ret != NXT_OK)) {
                 return ret;
             }
@@ -772,11 +783,12 @@ njs_vmcode_property_set(njs_vm_t *vm, njs_value_t *object,
 njs_ret_t
 njs_vmcode_property_in(njs_vm_t *vm, njs_value_t *object, njs_value_t *property)
 {
+    void                  *obj;
     uintptr_t             data;
     njs_ret_t             ret;
     njs_value_t           *value;
-    njs_extern_t          *ext;
     const njs_value_t     *retval;
+    const njs_extern_t    *ext_proto;
     njs_property_query_t  pq;
 
     retval = &njs_value_false;
@@ -810,9 +822,9 @@ njs_vmcode_property_in(njs_vm_t *vm, njs_value_t *object, njs_value_t *property)
         break;
 
     case NJS_EXTERNAL_VALUE:
-        ext = object->data.u.external;
+        ext_proto = object->external.proto;
 
-        ret = nxt_lvlhsh_find(&ext->hash, &pq.lhq);
+        ret = nxt_lvlhsh_find(&ext_proto->hash, &pq.lhq);
 
         if (ret == NXT_OK) {
             retval = &njs_value_true;
@@ -820,8 +832,10 @@ njs_vmcode_property_in(njs_vm_t *vm, njs_value_t *object, njs_value_t *property)
         } else {
             data = (uintptr_t) &pq.lhq.key;
 
-            if (ext->find != NULL) {
-                ret = ext->find(vm, vm->external[ext->object], data, 0);
+            if (ext_proto->find != NULL) {
+                obj = njs_extern_object(vm, object);
+
+                ret = ext_proto->find(vm, obj, data, 0);
 
                 if (nxt_slow_path(ret == NXT_ERROR)) {
                     return ret;
@@ -852,12 +866,13 @@ njs_ret_t
 njs_vmcode_property_delete(njs_vm_t *vm, njs_value_t *object,
     njs_value_t *property)
 {
+    void                  *obj;
     uintptr_t             data;
     njs_ret_t             ret;
-    njs_value_t           *value;
-    njs_extern_t          *ext;
+    njs_value_t           *value, ext_val;
     const njs_value_t     *retval;
     njs_object_prop_t     *prop;
+    const njs_extern_t    *ext_proto;
     njs_property_query_t  pq;
 
     retval = &njs_value_false;
@@ -896,26 +911,34 @@ njs_vmcode_property_delete(njs_vm_t *vm, njs_value_t *object,
 
     case NJS_EXTERNAL_VALUE:
 
-        ext = object->data.u.external;
+        ext_proto = object->external.proto;
 
-        ret = nxt_lvlhsh_find(&ext->hash, &pq.lhq);
+        ret = nxt_lvlhsh_find(&ext_proto->hash, &pq.lhq);
 
         if (ret == NXT_OK) {
-            ext = pq.lhq.value;
+            ext_proto = pq.lhq.value;
+
+            if ((ext_proto->type & NJS_EXTERN_OBJECT) != 0) {
+
+                ext_val.type = NJS_EXTERNAL;
+                ext_val.data.truth = 1;
+                ext_val.external.proto = ext_proto;
+                ext_val.external.index = object->external.index;
 
-            if ((ext->type & NJS_EXTERN_OBJECT) != 0) {
-                data = (uintptr_t) &ext->value;
+                data = (uintptr_t) &ext_val;
 
             } else {
-                data = ext->data;
+                data = ext_proto->data;
             }
 
         } else {
             data = (uintptr_t) &pq.lhq.key;
         }
 
-        if (ext->find != NULL) {
-            ret = ext->find(vm, vm->external[ext->object], data, 1);
+        if (ext_proto->find != NULL) {
+            obj = njs_extern_object(vm, object);
+
+            ret = ext_proto->find(vm, obj, data, 1);
 
             if (nxt_slow_path(ret == NXT_ERROR)) {
                 return ret;
@@ -958,12 +981,12 @@ static nxt_noinline njs_ret_t
 njs_property_query(njs_vm_t *vm, njs_property_query_t *pq, njs_value_t *object,
     njs_value_t *property)
 {
-    uint32_t        index;
-    uint32_t        (*hash)(const void *, size_t);
-    njs_ret_t       ret;
-    njs_extern_t    *ext;
-    njs_object_t    *obj;
-    njs_function_t  *function;
+    uint32_t            index;
+    uint32_t            (*hash)(const void *, size_t);
+    njs_ret_t           ret;
+    njs_object_t        *obj;
+    njs_function_t      *function;
+    const njs_extern_t  *ext_proto;
 
     hash = nxt_djb_hash;
 
@@ -1031,9 +1054,9 @@ njs_property_query(njs_vm_t *vm, njs_property_query_t *pq, njs_value_t *object,
         break;
 
     case NJS_EXTERNAL:
-        ext = object->data.u.external;
+        ext_proto = object->external.proto;
 
-        if (ext->type == NJS_EXTERN_CASELESS_OBJECT) {
+        if (ext_proto->type == NJS_EXTERN_CASELESS_OBJECT) {
             hash = nxt_djb_hash_lowcase;
         }
 
@@ -1224,9 +1247,10 @@ njs_ret_t
 njs_vmcode_property_foreach(njs_vm_t *vm, njs_value_t *object,
     njs_value_t *invld)
 {
+    void                       *obj;
     njs_ret_t                  ret;
-    njs_extern_t               *ext;
     njs_property_next_t        *next;
+    const njs_extern_t         *ext_proto;
     njs_vmcode_prop_foreach_t  *code;
 
     if (njs_is_object(object)) {
@@ -1246,10 +1270,12 @@ njs_vmcode_property_foreach(njs_vm_t *vm, njs_value_t *object,
         }
 
     } else if (njs_is_external(object)) {
-        ext = object->data.u.external;
+        ext_proto = object->external.proto;
 
-        if (ext->foreach != NULL) {
-            ret = ext->foreach(vm, vm->external[ext->object], &vm->retval);
+        if (ext_proto->foreach != NULL) {
+            obj = njs_extern_object(vm, object);
+
+            ret = ext_proto->foreach(vm, obj, &vm->retval);
             if (nxt_slow_path(ret != NXT_OK)) {
                 return ret;
             }
@@ -1265,13 +1291,14 @@ njs_vmcode_property_foreach(njs_vm_t *vm, njs_value_t *object,
 njs_ret_t
 njs_vmcode_property_next(njs_vm_t *vm, njs_value_t *object, njs_value_t *value)
 {
+    void                    *obj;
     njs_ret_t               ret;
     nxt_uint_t              n;
     njs_value_t             *retval;
     njs_array_t             *array;
-    njs_extern_t            *ext;
     njs_object_prop_t       *prop;
     njs_property_next_t     *next;
+    const njs_extern_t      *ext_proto;
     njs_vmcode_prop_next_t  *code;
 
     code = (njs_vmcode_prop_next_t *) vm->current;
@@ -1307,10 +1334,12 @@ njs_vmcode_property_next(njs_vm_t *vm, njs_value_t *object, njs_value_t *value)
         nxt_mem_cache_free(vm->mem_cache_pool, next);
 
     } else if (njs_is_external(object)) {
-        ext = object->data.u.external;
+        ext_proto = object->external.proto;
+
+        if (ext_proto->next != NULL) {
+            obj = njs_extern_object(vm, object);
 
-        if (ext->next != NULL) {
-            ret = ext->next(vm, retval, vm->external[ext->object], value);
+            ret = ext_proto->next(vm, retval, obj, value);
 
             if (ret == NXT_OK) {
                 return code->offset;
@@ -2313,11 +2342,12 @@ njs_function_new_object(njs_vm_t *vm, njs_value_t *value)
 njs_ret_t
 njs_vmcode_method_frame(njs_vm_t *vm, njs_value_t *object, njs_value_t *name)
 {
+    void                       *obj;
     njs_ret_t                  ret;
     njs_value_t                this, *value;
-    njs_extern_t               *ext;
     njs_object_prop_t          *prop;
     njs_property_query_t       pq;
+    const njs_extern_t         *ext_proto;
     njs_vmcode_method_frame_t  *method;
 
     method = (njs_vmcode_method_frame_t *) vm->current;
@@ -2343,9 +2373,9 @@ njs_vmcode_method_frame(njs_vm_t *vm, njs_value_t *object, njs_value_t *name)
         break;
 
     case NJS_EXTERNAL_VALUE:
-        ext = object->data.u.external;
+        ext_proto = object->external.proto;
 
-        ret = nxt_lvlhsh_find(&ext->hash, &pq.lhq);
+        ret = nxt_lvlhsh_find(&ext_proto->hash, &pq.lhq);
 
         if (nxt_slow_path(ret != NXT_OK)) {
             njs_exception_type_error(vm,
@@ -2355,18 +2385,20 @@ njs_vmcode_method_frame(njs_vm_t *vm, njs_value_t *object, njs_value_t *name)
 
         }
 
-        ext = pq.lhq.value;
+        ext_proto = pq.lhq.value;
 
-        if (nxt_slow_path(ext->type != NJS_EXTERN_METHOD)) {
+        if (nxt_slow_path(ext_proto->type != NJS_EXTERN_METHOD)) {
             njs_exception_type_error(vm,
                           "method '%.*s' of an external object is not callable",
                           (int) pq.lhq.key.length, pq.lhq.key.start);
             return NXT_ERROR;
         }
 
-        this.data.u.data = vm->external[ext->object];
+        obj = njs_extern_object(vm, object);
+
+        this.data.u.data = obj;
 
-        ret = njs_function_native_frame(vm, ext->function, &this, NULL,
+        ret = njs_function_native_frame(vm, ext_proto->function, &this, NULL,
                                         method->nargs, 0, method->code.ctor);
         break;
 
index afcd2826c9d267b78c0220843ab3ae64b3ee8fe0..b87a9021f2d8ad0447045ff752f250051d866114 100644 (file)
@@ -11,6 +11,7 @@
 #include <nxt_trace.h>
 #include <nxt_queue.h>
 #include <nxt_regex.h>
+#include <nxt_random.h>
 
 
 #define NJS_MAX_STACK_SIZE       (16 * 1024 * 1024)
@@ -130,7 +131,6 @@ typedef struct njs_function_lambda_s  njs_function_lambda_t;
 typedef struct njs_regexp_s           njs_regexp_t;
 typedef struct njs_regexp_pattern_s   njs_regexp_pattern_t;
 typedef struct njs_date_s             njs_date_t;
-typedef struct njs_extern_s           njs_extern_t;
 typedef struct njs_frame_s            njs_frame_t;
 typedef struct njs_native_frame_s     njs_native_frame_t;
 typedef struct njs_property_next_s    njs_property_next_t;
@@ -176,7 +176,6 @@ union njs_value_s {
             njs_regexp_t              *regexp;
             njs_date_t                *date;
             njs_getter_t              getter;
-            njs_extern_t              *external;
             njs_value_t               *value;
             njs_property_next_t       *next;
             void                      *data;
@@ -207,6 +206,16 @@ union njs_value_s {
         njs_string_t                  *data;
     } long_string;
 
+    struct {
+        njs_value_type_t              type:8;  /* 5 bits */
+        uint8_t                       truth;
+
+        uint16_t                      _spare;
+
+        uint32_t                      index;
+        const njs_extern_t            *proto;
+    } external;
+
     njs_value_type_t                  type:8;  /* 5 bits */
 };
 
@@ -950,12 +959,16 @@ struct njs_vm_s {
 
     njs_value_t              *scopes[NJS_SCOPES];
 
-    void                     **external;
+    void                     *external;
 
     njs_native_frame_t       *top_frame;
     njs_frame_t              *active_frame;
 
+    nxt_array_t              *external_objects; /* of void * */
+
     nxt_lvlhsh_t             externals_hash;
+    nxt_lvlhsh_t             external_prototypes_hash;
+
     nxt_lvlhsh_t             variables_hash;
     nxt_lvlhsh_t             values_hash;
     nxt_lvlhsh_t             modules_hash;
index 3f059902c2c78c4b2f9c885badf68c009b934d79..b86874c52c200438cd6c203ac5008dcd81cebab9 100644 (file)
@@ -110,14 +110,10 @@ njs_vm_create(njs_vm_opt_t *options)
     nxt_mem_cache_pool_t  *mcp;
     njs_regexp_pattern_t  *pattern;
 
-    mcp = options->mcp;
-
-    if (mcp == NULL) {
-        mcp = nxt_mem_cache_pool_create(&njs_vm_mem_cache_pool_proto, NULL,
-                                        NULL, 2 * nxt_pagesize(), 128, 512, 16);
-        if (nxt_slow_path(mcp == NULL)) {
-            return NULL;
-        }
+    mcp = nxt_mem_cache_pool_create(&njs_vm_mem_cache_pool_proto, NULL,
+                                    NULL, 2 * nxt_pagesize(), 128, 512, 16);
+    if (nxt_slow_path(mcp == NULL)) {
+        return NULL;
     }
 
     vm = nxt_mem_cache_zalign(mcp, sizeof(njs_value_t), sizeof(njs_vm_t));
@@ -164,18 +160,22 @@ njs_vm_create(njs_vm_opt_t *options)
             if (nxt_slow_path(ret != NXT_OK)) {
                 return NULL;
             }
-
-            if (options->externals_hash != NULL) {
-                vm->external = options->external;
-            }
         }
 
         nxt_lvlhsh_init(&vm->values_hash);
 
-        if (options->externals_hash != NULL) {
-            vm->externals_hash = *options->externals_hash;
+        vm->external = options->external;
+
+        vm->external_objects = nxt_array_create(4, sizeof(void *),
+                                                &njs_array_mem_proto,
+                                                vm->mem_cache_pool);
+        if (nxt_slow_path(vm->external_objects == NULL)) {
+            return NULL;
         }
 
+        nxt_lvlhsh_init(&vm->externals_hash);
+        nxt_lvlhsh_init(&vm->external_prototypes_hash);
+
         vm->trace.level = NXT_LEVEL_TRACE;
         vm->trace.size = 2048;
         vm->trace.handler = njs_parser_trace_handler;
@@ -294,9 +294,10 @@ fail:
 
 
 njs_vm_t *
-njs_vm_clone(njs_vm_t *vm, nxt_mem_cache_pool_t *mcp, void **external)
+njs_vm_clone(njs_vm_t *vm, void *external)
 {
     njs_vm_t              *nvm;
+    uint32_t              items;
     nxt_int_t             ret;
     nxt_mem_cache_pool_t  *nmcp;
 
@@ -306,14 +307,10 @@ njs_vm_clone(njs_vm_t *vm, nxt_mem_cache_pool_t *mcp, void **external)
         return NULL;
     }
 
-    nmcp = mcp;
-
-    if (nmcp == NULL) {
-        nmcp = nxt_mem_cache_pool_create(&njs_vm_mem_cache_pool_proto, NULL,
-                                        NULL, 2 * nxt_pagesize(), 128, 512, 16);
-        if (nxt_slow_path(nmcp == NULL)) {
-            return NULL;
-        }
+    nmcp = nxt_mem_cache_pool_create(&njs_vm_mem_cache_pool_proto, NULL,
+                                    NULL, 2 * nxt_pagesize(), 128, 512, 16);
+    if (nxt_slow_path(nmcp == NULL)) {
+        return NULL;
     }
 
     nvm = nxt_mem_cache_zalloc(nmcp, sizeof(njs_vm_t));
@@ -326,9 +323,26 @@ njs_vm_clone(njs_vm_t *vm, nxt_mem_cache_pool_t *mcp, void **external)
         nvm->variables_hash = vm->variables_hash;
         nvm->values_hash = vm->values_hash;
         nvm->modules_hash = vm->modules_hash;
+
         nvm->externals_hash = vm->externals_hash;
+        nvm->external_prototypes_hash = vm->external_prototypes_hash;
+
+        items = vm->external_objects->items;
+        nvm->external_objects = nxt_array_create(items + 4, sizeof(void *),
+                                                 &njs_array_mem_proto,
+                                                 vm->mem_cache_pool);
+        if (nxt_slow_path(vm->external_objects == NULL)) {
+            return NULL;
+        }
+
+        if (items > 0) {
+            memcpy(nvm->external_objects->start, vm->external_objects->start,
+                   items * sizeof(void *));
+            vm->external_objects->items = items;
+        }
 
         nvm->current = vm->current;
+
         nvm->external = external;
 
         nvm->global_scope = vm->global_scope;
@@ -348,9 +362,7 @@ njs_vm_clone(njs_vm_t *vm, nxt_mem_cache_pool_t *mcp, void **external)
 
 fail:
 
-    if (mcp == NULL) {
-        nxt_mem_cache_pool_destroy(nmcp);
-    }
+    nxt_mem_cache_pool_destroy(nmcp);
 
     return NULL;
 }
@@ -523,6 +535,13 @@ njs_vm_retval(njs_vm_t *vm)
 }
 
 
+nxt_noinline void
+njs_vm_retval_set(njs_vm_t *vm, njs_opaque_value_t *value)
+{
+    vm->retval = *(njs_value_t *) value;
+}
+
+
 njs_ret_t njs_vm_retval_to_ext_string(njs_vm_t *vm, nxt_str_t *retval)
 {
     if (vm->top_frame == NULL) {
index f14596143cfb97b7f6e454652f69007703f30bcc..9dd24c92d674ed250ae1b3c78ea426cd8912e122 100644 (file)
@@ -16,6 +16,7 @@ typedef intptr_t                    njs_ret_t;
 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;
 
@@ -70,10 +71,8 @@ struct njs_external_s {
 };
 
 typedef struct {
-    void                            **external;
-    nxt_lvlhsh_t                    *externals_hash;
+    void                            *external;
     njs_vm_shared_t                 *shared;
-    nxt_mem_cache_pool_t            *mcp;
 
     uint8_t                         trailer;         /* 1 bit */
     uint8_t                         accumulative;    /* 1 bit */
@@ -94,27 +93,28 @@ typedef struct {
 #define NJS_DONE                    NXT_DONE
 
 
-NXT_EXPORT nxt_int_t njs_vm_external_add(nxt_lvlhsh_t *hash,
-    nxt_mem_cache_pool_t *mcp, uintptr_t object, njs_external_t *external,
-    nxt_uint_t n);
-NXT_EXPORT nxt_int_t njs_vm_external(njs_vm_t *vm, njs_opaque_value_t *object,
-    nxt_str_t *property, njs_opaque_value_t *value);
-
 NXT_EXPORT njs_vm_t *njs_vm_create(njs_vm_opt_t *options);
 NXT_EXPORT void njs_vm_destroy(njs_vm_t *vm);
 
 NXT_EXPORT nxt_int_t njs_vm_compile(njs_vm_t *vm, u_char **start, u_char *end);
-NXT_EXPORT njs_vm_t *njs_vm_clone(njs_vm_t *vm, nxt_mem_cache_pool_t *mcp,
-    void **external);
+NXT_EXPORT njs_vm_t *njs_vm_clone(njs_vm_t *vm, void *external);
 NXT_EXPORT nxt_int_t njs_vm_call(njs_vm_t *vm, njs_function_t *function,
     njs_opaque_value_t *args, nxt_uint_t nargs);
 NXT_EXPORT nxt_int_t njs_vm_run(njs_vm_t *vm);
 
+NXT_EXPORT const njs_extern_t *njs_vm_external_prototype(njs_vm_t *vm,
+    njs_external_t *external);
+NXT_EXPORT nxt_int_t njs_vm_external_create(njs_vm_t *vm,
+        njs_opaque_value_t *value, const njs_extern_t *proto, void *object);
+NXT_EXPORT nxt_int_t njs_vm_external_bind(njs_vm_t *vm,
+    const nxt_str_t *var_name, njs_opaque_value_t *value);
+
 NXT_EXPORT void njs_disassembler(njs_vm_t *vm);
 NXT_EXPORT nxt_array_t *njs_vm_completions(njs_vm_t *vm, nxt_str_t *expression);
 
 NXT_EXPORT njs_function_t *njs_vm_function(njs_vm_t *vm, nxt_str_t *name);
 NXT_EXPORT njs_value_t *njs_vm_retval(njs_vm_t *vm);
+NXT_EXPORT void njs_vm_retval_set(njs_vm_t *vm, njs_opaque_value_t *value);
 
 NXT_EXPORT u_char * njs_string_alloc(njs_vm_t *vm, njs_value_t *value,
     uint32_t size, uint32_t length);
index 550a7de672355c1c46b0ca080cdedb150a5a27cb..efbf46572398b19af75e3f5e90a1456f1515fb8c 100644 (file)
@@ -11,8 +11,6 @@
 #include <nxt_stub.h>
 #include <nxt_malloc.h>
 #include <nxt_array.h>
-#include <nxt_lvlhsh.h>
-#include <nxt_mem_cache_pool.h>
 #include <njscript.h>
 #include <string.h>
 #include <stdio.h>
 #include <time.h>
 
 
-static void *
-njs_alloc(void *mem, size_t size)
-{
-    return nxt_malloc(size);
-}
-
-
-static void *
-njs_zalloc(void *mem, size_t size)
-{
-    void  *p;
-
-    p = nxt_malloc(size);
-
-    if (p != NULL) {
-        memset(p, 0, size);
-    }
-
-    return p;
-}
-
-
-static void *
-njs_align(void *mem, size_t alignment, size_t size)
-{
-    return nxt_memalign(alignment, size);
-}
-
-
-static void
-njs_free(void *mem, void *p)
-{
-    nxt_free(p);
-}
-
-
-static const nxt_mem_proto_t  njs_mem_cache_pool_proto = {
-    njs_alloc,
-    njs_zalloc,
-    njs_align,
-    NULL,
-    njs_free,
-    NULL,
-    NULL,
-};
-
-
 static nxt_int_t
 njs_unit_test_benchmark(nxt_str_t *script, nxt_str_t *result, const char *msg,
     nxt_uint_t n)
 {
-    u_char                *start;
-    njs_vm_t              *vm, *nvm;
-    uint64_t              us;
-    nxt_int_t             ret;
-    nxt_str_t             s;
-    nxt_uint_t            i;
-    nxt_bool_t            success;
-    njs_vm_opt_t          options;
-    struct rusage         usage;
-    nxt_mem_cache_pool_t  *mcp;
-
-    mcp = nxt_mem_cache_pool_create(&njs_mem_cache_pool_proto, NULL, NULL,
-                                    2 * nxt_pagesize(), 128, 512, 16);
-    if (nxt_slow_path(mcp == NULL)) {
-        return NXT_ERROR;
-    }
+    u_char         *start;
+    njs_vm_t       *vm, *nvm;
+    uint64_t       us;
+    nxt_int_t      ret, rc;
+    nxt_str_t      s;
+    nxt_uint_t     i;
+    nxt_bool_t     success;
+    njs_vm_opt_t   options;
+    struct rusage  usage;
 
     memset(&options, 0, sizeof(njs_vm_opt_t));
 
-    options.mcp = mcp;
+    vm = NULL;
+    nvm = NULL;
+    rc = NXT_ERROR;
 
     vm = njs_vm_create(&options);
     if (vm == NULL) {
-        return NXT_ERROR;
+        printf("njs_vm_create() failed\n");
+        goto done;
     }
 
     start = script->start;
 
     ret = njs_vm_compile(vm, &start, start + script->length);
     if (ret != NXT_OK) {
-        return NXT_ERROR;
+        printf("njs_vm_compile() failed\n");
+        goto done;
     }
 
     for (i = 0; i < n; i++) {
 
-        nvm = njs_vm_clone(vm, NULL, NULL);
+        nvm = njs_vm_clone(vm, NULL);
         if (nvm == NULL) {
-            return NXT_ERROR;
+            printf("njs_vm_clone() failed\n");
+            goto done;
         }
 
         (void) njs_vm_run(nvm);
 
         if (njs_vm_retval_to_ext_string(nvm, &s) != NXT_OK) {
-            return NXT_ERROR;
+            printf("njs_vm_retval_to_ext_string() failed\n");
+            goto done;
         }
 
         success = nxt_strstr_eq(result, &s);
 
         if (!success) {
-            return NXT_ERROR;
+            printf("failed: \"%.*s\" vs \"%.*s\"\n",
+                   (int) result->length, result->start, (int) s.length,
+                   s.start);
+            goto done;
         }
 
         njs_vm_destroy(nvm);
+        nvm = NULL;
     }
 
-    nxt_mem_cache_pool_destroy(mcp);
-
     getrusage(RUSAGE_SELF, &usage);
 
     us = usage.ru_utime.tv_sec * 1000000 + usage.ru_utime.tv_usec
@@ -141,7 +93,19 @@ njs_unit_test_benchmark(nxt_str_t *script, nxt_str_t *result, const char *msg,
                msg, (double) us / n, (int) ((uint64_t) n * 1000000 / us));
     }
 
-    return NXT_OK;
+    rc = NXT_OK;
+
+done:
+
+    if (nvm != NULL) {
+        njs_vm_destroy(nvm);
+    }
+
+    if (vm != NULL) {
+        njs_vm_destroy(vm);
+    }
+
+    return rc;
 }
 
 
index 1b28671a3413978f85e4e2301156ebc867c84d43..537d5ad069790cde5e4af27a3706122f6e81dc11 100644 (file)
@@ -11,8 +11,6 @@
 #include <nxt_stub.h>
 #include <nxt_malloc.h>
 #include <nxt_array.h>
-#include <nxt_lvlhsh.h>
-#include <nxt_mem_cache_pool.h>
 #include <njscript.h>
 #include <string.h>
 #include <stdio.h>
@@ -203,15 +201,9 @@ njs_interactive_test(void)
     nxt_uint_t              i;
     nxt_bool_t              success;
     njs_vm_opt_t            options;
-    nxt_mem_cache_pool_t    *mcp;
     njs_interactive_test_t  *test;
 
-    mcp = nxt_mem_cache_pool_create(&njs_vm_mem_cache_pool_proto, NULL, NULL,
-                                    2 * nxt_pagesize(), 128, 512, 16);
-    if (nxt_slow_path(mcp == NULL)) {
-        return NXT_ERROR;
-    }
-
+    vm = NULL;
     ret = NXT_ERROR;
 
     for (i = 0; i < nxt_nitems(njs_test); i++) {
@@ -223,13 +215,13 @@ njs_interactive_test(void)
 
         memset(&options, 0, sizeof(njs_vm_opt_t));
 
-        options.mcp = mcp;
         options.accumulative = 1;
         options.backtrace = 1;
 
         vm = njs_vm_create(&options);
         if (vm == NULL) {
-            goto fail;
+            printf("njs_vm_create() failed\n");
+            goto done;
         }
 
         start = test->script.start;
@@ -251,11 +243,14 @@ njs_interactive_test(void)
         }
 
         if (njs_vm_retval_to_ext_string(vm, &s) != NXT_OK) {
-            return NXT_ERROR;
+            printf("njs_vm_retval_to_ext_string() failed\n");
+            goto done;
         }
 
         success = nxt_strstr_eq(&test->ret, &s);
         if (success) {
+            njs_vm_destroy(vm);
+            vm = NULL;
             continue;
         }
 
@@ -264,16 +259,18 @@ njs_interactive_test(void)
                (int) test->ret.length, test->ret.start,
                (int) s.length, s.start);
 
-        goto fail;
+        goto done;
     }
 
     ret = NXT_OK;
 
     printf("njs interactive tests passed\n");
 
-fail:
+done:
 
-    nxt_mem_cache_pool_destroy(mcp);
+    if (vm != NULL) {
+        njs_vm_destroy(vm);
+    }
 
     return ret;
 }
index 1742f0d3d2d51a6cc790496ed9053a8a7d205add..c83e3dbfb380f09a680de3357ce79829e4ecd49e 100644 (file)
@@ -14,6 +14,7 @@
 #include <nxt_lvlhsh.h>
 #include <nxt_mem_cache_pool.h>
 #include <njscript.h>
+#include <njs_vm.h>
 #include <string.h>
 #include <stdio.h>
 #include <sys/resource.h>
@@ -3750,6 +3751,12 @@ static njs_unit_test_t  njs_test[] =
     { nxt_string("var a = $r.uri, s = a.fromUTF8(); s.length +' '+ s"),
       nxt_string("3 АБВ") },
 
+    { nxt_string("var a = $r.uri, b = $r2.uri, c = $r3.uri; a+b+c"),
+      nxt_string("АБВαβγabc") },
+
+    { nxt_string("var a = $r.uri; $r.uri = $r2.uri; $r2.uri = a; $r2.uri+$r.uri"),
+      nxt_string("АБВαβγ") },
+
     { nxt_string("var a = $r.uri, s = a.fromUTF8(2); s.length +' '+ s"),
       nxt_string("2 БВ") },
 
@@ -3768,6 +3775,15 @@ static njs_unit_test_t  njs_test[] =
     { nxt_string("$r.uri = $r.uri.substr(2); $r.uri.length +' '+ $r.uri"),
       nxt_string("4 БВ") },
 
+    { nxt_string("'' + $r.props.a + $r2.props.a + $r.props.a"),
+      nxt_string("121") },
+
+    { nxt_string("var p1 = $r.props, p2 = $r2.props; '' + p2.a + p1.a"),
+      nxt_string("21") },
+
+    { nxt_string("var p1 = $r.props, p2 = $r2.props; '' + p1.a + p2.a"),
+      nxt_string("12") },
+
     { nxt_string("var a = $r.host; a +' '+ a.length +' '+ a"),
       nxt_string("АБВГДЕЁЖЗИЙ 22 АБВГДЕЁЖЗИЙ") },
 
@@ -3785,6 +3801,17 @@ static njs_unit_test_t  njs_test[] =
     { nxt_string("$r.some_method('YES')"),
       nxt_string("АБВ") },
 
+    { nxt_string("$r.create('XXX').uri"),
+      nxt_string("XXX") },
+
+    { nxt_string("var sr = $r.create('XXX'); sr.uri = 'YYY'; sr.uri"),
+      nxt_string("YYY") },
+
+    { nxt_string("var sr = $r.create('XXX'), sr2 = $r.create('YYY');"
+                 "sr.uri = 'ZZZ'; "
+                 "sr.uri + sr2.uri"),
+      nxt_string("ZZZYYY") },
+
     { nxt_string("var p; for (p in $r.some_method);"),
       nxt_string("undefined") },
 
@@ -3794,6 +3821,9 @@ static njs_unit_test_t  njs_test[] =
     { nxt_string("'one' in $r"),
       nxt_string("false") },
 
+    { nxt_string("'a' in $r.props"),
+      nxt_string("true") },
+
     { nxt_string("delete $r.uri"),
       nxt_string("false") },
 
@@ -8982,18 +9012,20 @@ static njs_unit_test_t  njs_test[] =
 
 
 typedef struct {
-    nxt_mem_cache_pool_t  *mem_cache_pool;
     nxt_str_t             uri;
-} njs_unit_test_req;
+    uint32_t              a;
+    nxt_mem_cache_pool_t  *mem_cache_pool;
+    const njs_extern_t    *proto;
+} njs_unit_test_req_t;
 
 
 static njs_ret_t
 njs_unit_test_r_get_uri_external(njs_vm_t *vm, njs_value_t *value, void *obj,
     uintptr_t data)
 {
-    njs_unit_test_req  *r;
+    njs_unit_test_req_t  *r;
 
-    r = (njs_unit_test_req *) obj;
+    r = (njs_unit_test_req_t *) obj;
 
     return njs_string_create(vm, value, r->uri.start, r->uri.length, 0);
 }
@@ -9003,15 +9035,32 @@ static njs_ret_t
 njs_unit_test_r_set_uri_external(njs_vm_t *vm, void *obj, uintptr_t data,
     nxt_str_t *value)
 {
-    njs_unit_test_req  *r;
+    njs_unit_test_req_t  *r;
+
+    r = (njs_unit_test_req_t *) obj;
 
-    r = (njs_unit_test_req *) obj;
     r->uri = *value;
 
     return NXT_OK;
 }
 
 
+static njs_ret_t
+njs_unit_test_r_get_a_external(njs_vm_t *vm, njs_value_t *value, void *obj,
+    uintptr_t data)
+{
+    char                 buf[16];
+    size_t               len;
+    njs_unit_test_req_t  *r;
+
+    r = (njs_unit_test_req_t *) obj;
+
+    len = sprintf(buf, "%u", r->a);
+
+    return njs_string_create(vm, value, (u_char *) buf, len, 0);
+}
+
+
 static njs_ret_t
 njs_unit_test_host_external(njs_vm_t *vm, njs_value_t *value, void *obj,
     uintptr_t data)
@@ -9024,27 +9073,24 @@ static njs_ret_t
 njs_unit_test_header_external(njs_vm_t *vm, njs_value_t *value, void *obj,
     uintptr_t data)
 {
-    u_char             *s, *p;
-    uint32_t           size;
-    nxt_str_t          *h;
-    njs_unit_test_req  *r;
+    u_char     *p;
+    uint32_t   size;
+    nxt_str_t  *h;
 
-    r = (njs_unit_test_req *) obj;
     h = (nxt_str_t *) data;
 
     size = 7 + h->length;
 
-    s = nxt_mem_cache_alloc(r->mem_cache_pool, size);
-    if (nxt_slow_path(s == NULL)) {
-        return NXT_ERROR;
+    p = njs_string_alloc(vm, value, size, 0);
+    if (p == NULL) {
+        return NJS_ERROR;
     }
 
-    p = memcpy(s, h->start, h->length);
-    p += h->length;
+    p = nxt_cpymem(p, h->start, h->length);
     *p++ = '|';
     memcpy(p, "АБВ", 6);
 
-    return njs_string_create(vm, value, s, size, 0);
+    return NJS_OK;
 }
 
 
@@ -9082,10 +9128,10 @@ static njs_ret_t
 njs_unit_test_method_external(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs,
     njs_index_t unused)
 {
-    nxt_int_t          ret;
-    nxt_str_t          s;
-    uintptr_t          next;
-    njs_unit_test_req  *r;
+    nxt_int_t            ret;
+    nxt_str_t            s;
+    uintptr_t            next;
+    njs_unit_test_req_t  *r;
 
     next = 0;
 
@@ -9106,6 +9152,70 @@ njs_unit_test_method_external(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs,
 }
 
 
+static njs_ret_t
+njs_unit_test_create_external(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs,
+    njs_index_t unused)
+{
+    nxt_int_t            ret;
+    nxt_str_t            uri;
+    njs_opaque_value_t   *value;
+    njs_unit_test_req_t  *r, *sr;
+
+    if (nargs > 1) {
+        r = njs_value_data(njs_argument(args, 0));
+
+        if (njs_vm_value_to_ext_string(vm, &uri, njs_argument(args, 1), 0)
+            == NJS_ERROR)
+        {
+            return NJS_ERROR;
+        }
+
+        value = nxt_mem_cache_zalloc(r->mem_cache_pool,
+                                     sizeof(njs_opaque_value_t));
+        if (value == NULL) {
+            return NXT_ERROR;
+        }
+
+        sr = nxt_mem_cache_zalloc(r->mem_cache_pool,
+                                  sizeof(njs_unit_test_req_t));
+        if (sr == NULL) {
+            return NXT_ERROR;
+        }
+
+        sr->uri = uri;
+        sr->mem_cache_pool = r->mem_cache_pool;
+        sr->proto = r->proto;
+
+        ret = njs_vm_external_create(vm, value, sr->proto, sr);
+        if (ret != NXT_OK) {
+            return NXT_ERROR;
+        }
+
+        njs_vm_retval_set(vm, value);
+
+        return NXT_OK;
+    }
+
+    return NXT_ERROR;
+}
+
+
+static njs_external_t  njs_unit_test_r_props[] = {
+
+    { nxt_string("a"),
+      NJS_EXTERN_PROPERTY,
+      NULL,
+      0,
+      njs_unit_test_r_get_a_external,
+      NULL,
+      NULL,
+      NULL,
+      NULL,
+      NULL,
+      0 },
+};
+
+
 static njs_external_t  njs_unit_test_r_external[] = {
 
     { nxt_string("uri"),
@@ -9132,6 +9242,18 @@ static njs_external_t  njs_unit_test_r_external[] = {
       NULL,
       0 },
 
+    { nxt_string("props"),
+      NJS_EXTERN_OBJECT,
+      njs_unit_test_r_props,
+      nxt_nitems(njs_unit_test_r_props),
+      NULL,
+      NULL,
+      NULL,
+      NULL,
+      NULL,
+      NULL,
+      0 },
+
     { nxt_string("header"),
       NJS_EXTERN_OBJECT,
       NULL,
@@ -9156,12 +9278,24 @@ static njs_external_t  njs_unit_test_r_external[] = {
       njs_unit_test_method_external,
       0 },
 
+    { nxt_string("create"),
+      NJS_EXTERN_METHOD,
+      NULL,
+      0,
+      NULL,
+      NULL,
+      NULL,
+      NULL,
+      NULL,
+      njs_unit_test_create_external,
+      0 },
+
 };
 
 
 static njs_external_t  nxt_test_external[] = {
 
-    { nxt_string("$r"),
+    { nxt_string("request.proto"),
       NJS_EXTERN_OBJECT,
       njs_unit_test_r_external,
       nxt_nitems(njs_unit_test_r_external),
@@ -9176,77 +9310,81 @@ static njs_external_t  nxt_test_external[] = {
 };
 
 
-static nxt_int_t
-njs_unit_test_externals(nxt_lvlhsh_t *externals, nxt_mem_cache_pool_t *mcp)
-{
-    nxt_lvlhsh_init(externals);
-
-    return njs_vm_external_add(externals, mcp, 0, nxt_test_external,
-                               nxt_nitems(nxt_test_external));
-}
+typedef struct {
+    nxt_str_t            name;
+    njs_unit_test_req_t  request;
+} njs_unit_test_req_t_init_t;
 
 
-static void *
-njs_alloc(void *mem, size_t size)
-{
-    return nxt_malloc(size);
-}
+static const njs_unit_test_req_t_init_t nxt_test_requests[] = {
+    { nxt_string("$r"),  {.uri = nxt_string("АБВ"), .a = 1}},
+    { nxt_string("$r2"), {.uri = nxt_string("αβγ"), .a = 2}},
+    { nxt_string("$r3"), {.uri = nxt_string("abc"), .a = 3}},
+};
 
 
-static void *
-njs_zalloc(void *mem, size_t size)
+static nxt_int_t
+njs_externals_init(njs_vm_t *vm)
 {
-    void  *p;
+    nxt_int_t            ret;
+    nxt_uint_t           i;
+    const njs_extern_t   *proto;
+    njs_opaque_value_t   *values;
+    njs_unit_test_req_t  *requests;
+
+    proto = njs_vm_external_prototype(vm, &nxt_test_external[0]);
+    if (proto == NULL) {
+        printf("njs_vm_external_prototype() failed\n");
+        return NXT_ERROR;
+    }
 
-    p = nxt_malloc(size);
+    values = nxt_mem_cache_zalloc(vm->mem_cache_pool,
+                                  nxt_nitems(nxt_test_requests)
+                                  * sizeof(njs_opaque_value_t));
+    if (values == NULL) {
+        return NXT_ERROR;
+    }
 
-    if (p != NULL) {
-        memset(p, 0, size);
+    requests = nxt_mem_cache_zalloc(vm->mem_cache_pool,
+                                    nxt_nitems(nxt_test_requests)
+                                    * sizeof(njs_unit_test_req_t));
+    if (requests == NULL) {
+        return NXT_ERROR;
     }
 
-    return p;
-}
+    for (i = 0; i < nxt_nitems(nxt_test_requests); i++) {
 
+        requests[i] = nxt_test_requests[i].request;
+        requests[i].mem_cache_pool = vm->mem_cache_pool;
+        requests[i].proto = proto;
 
-static void *
-njs_align(void *mem, size_t alignment, size_t size)
-{
-    return nxt_memalign(alignment, size);
-}
+        ret = njs_vm_external_create(vm, &values[i], proto, &requests[i]);
+        if (ret != NXT_OK) {
+            printf("njs_vm_external_create() failed\n");
+            return NXT_ERROR;
+        }
 
+        ret = njs_vm_external_bind(vm, &nxt_test_requests[i].name, &values[i]);
+        if (ret != NXT_OK) {
+            printf("njs_vm_external_bind() failed\n");
+            return NXT_ERROR;
+        }
+    }
 
-static void
-njs_free(void *mem, void *p)
-{
-    nxt_free(p);
+    return NXT_OK;
 }
 
 
-static const nxt_mem_proto_t  njs_mem_cache_pool_proto = {
-    njs_alloc,
-    njs_zalloc,
-    njs_align,
-    NULL,
-    njs_free,
-    NULL,
-    NULL,
-};
-
-
 static nxt_int_t
 njs_unit_test(nxt_bool_t disassemble)
 {
-    void                  *ext_object;
-    u_char                *start;
-    njs_vm_t              *vm, *nvm;
-    nxt_int_t             ret;
-    nxt_str_t             s;
-    nxt_uint_t            i;
-    nxt_bool_t            success;
-    njs_vm_opt_t          options;
-    nxt_lvlhsh_t          externals;
-    njs_unit_test_req     r;
-    nxt_mem_cache_pool_t  *mcp;
+    u_char        *start;
+    njs_vm_t      *vm, *nvm;
+    nxt_int_t     ret, rc;
+    nxt_str_t     s;
+    nxt_uint_t    i;
+    nxt_bool_t    success;
+    njs_vm_opt_t  options;
 
     /*
      * Chatham Islands NZ-CHAT time zone.
@@ -9255,21 +9393,11 @@ njs_unit_test(nxt_bool_t disassemble)
     (void) putenv((char *) "TZ=Pacific/Chatham");
     tzset();
 
-    mcp = nxt_mem_cache_pool_create(&njs_mem_cache_pool_proto, NULL, NULL,
-                                    2 * nxt_pagesize(), 128, 512, 16);
-    if (nxt_slow_path(mcp == NULL)) {
-        return NXT_ERROR;
-    }
-
-    r.mem_cache_pool = mcp;
-    r.uri.length = 6;
-    r.uri.start = (u_char *) "АБВ";
 
-    ext_object = &r;
+    vm = NULL;
+    nvm = NULL;
 
-    if (njs_unit_test_externals(&externals, mcp) != NXT_OK) {
-        return NXT_ERROR;
-    }
+    rc = NXT_ERROR;
 
     for (i = 0; i < nxt_nitems(njs_test); i++) {
 
@@ -9279,12 +9407,15 @@ njs_unit_test(nxt_bool_t disassemble)
 
         memset(&options, 0, sizeof(njs_vm_opt_t));
 
-        options.mcp = mcp;
-        options.externals_hash = &externals;
-
         vm = njs_vm_create(&options);
         if (vm == NULL) {
-            return NXT_ERROR;
+            printf("njs_vm_create() failed\n");
+            goto done;
+        }
+
+        ret = njs_externals_init(vm);
+        if (ret != NXT_OK) {
+            goto done;
         }
 
         start = njs_test[i].script.start;
@@ -9297,26 +9428,24 @@ njs_unit_test(nxt_bool_t disassemble)
                 fflush(stdout);
             }
 
-            nvm = njs_vm_clone(vm, NULL, &ext_object);
+            nvm = njs_vm_clone(vm, NULL);
             if (nvm == NULL) {
-                return NXT_ERROR;
+                printf("njs_vm_clone() failed\n");
+                goto done;
             }
 
-            r.uri.length = 6;
-            r.uri.start = (u_char *) "АБВ";
-
             ret = njs_vm_run(nvm);
 
             if (njs_vm_retval_to_ext_string(nvm, &s) != NXT_OK) {
-                return NXT_ERROR;
+                printf("njs_vm_retval_to_ext_string() failed\n");
+                goto done;
             }
 
         } else {
             if (njs_vm_retval_to_ext_string(vm, &s) != NXT_OK) {
-                return NXT_ERROR;
+                printf("njs_vm_retval_to_ext_string() failed\n");
+                goto done;
             }
-
-            nvm = NULL;
         }
 
         success = nxt_strstr_eq(&njs_test[i].ret, &s);
@@ -9324,8 +9453,12 @@ njs_unit_test(nxt_bool_t disassemble)
         if (success) {
             if (nvm != NULL) {
                 njs_vm_destroy(nvm);
+                nvm = NULL;
             }
 
+            njs_vm_destroy(vm);
+            vm = NULL;
+
             continue;
         }
 
@@ -9334,12 +9467,24 @@ njs_unit_test(nxt_bool_t disassemble)
                (int) njs_test[i].ret.length, njs_test[i].ret.start,
                (int) s.length, s.start);
 
-        return NXT_ERROR;
+        goto done;
+    }
+
+    rc = NXT_OK;
+
+done:
+
+    if (nvm != NULL) {
+        njs_vm_destroy(nvm);
     }
 
-    nxt_mem_cache_pool_destroy(mcp);
+    if (vm != NULL) {
+        njs_vm_destroy(vm);
+    }
 
-    printf("njs unit tests passed\n");
+    if (rc == NXT_OK) {
+        printf("njs unit tests passed\n");
+    }
 
     return NXT_OK;
 }
index b1c4cdf8f5a8c86f7424e1ac1c6b0f0f340083f4..df64fa9906a28efb26146e257cccce5f38c19d19 100644 (file)
@@ -39,6 +39,10 @@ NXT_EXPORT void *nxt_array_zero_add(nxt_array_t *array,
 NXT_EXPORT void nxt_array_remove(nxt_array_t *array, void *item);
 
 
+#define nxt_array_item(array, i)                                              \
+    ((void *) ((char *) (array)->start + (array)->item_size * (i)))
+
+
 #define nxt_array_last(array)                                                 \
     ((void *)                                                                 \
         ((char *) (array)->start                                              \
index 6794cacb8a357f048c8d237494988e77709e6edd..b0f57473ed3d4e5e0bf3391b5133316f9f8b0624 100644 (file)
@@ -174,7 +174,7 @@ static void *nxt_lvlhsh_bucket_each(nxt_lvlhsh_each_t *lhe);
 
 
 nxt_int_t
-nxt_lvlhsh_find(nxt_lvlhsh_t *lh, nxt_lvlhsh_query_t *lhq)
+nxt_lvlhsh_find(const nxt_lvlhsh_t *lh, nxt_lvlhsh_query_t *lhq)
 {
     void  *slot;
 
@@ -739,7 +739,7 @@ nxt_lvlhsh_bucket_delete(nxt_lvlhsh_query_t *lhq, void **bkt)
 
 
 void *
-nxt_lvlhsh_each(nxt_lvlhsh_t *lh, nxt_lvlhsh_each_t *lhe)
+nxt_lvlhsh_each(const nxt_lvlhsh_t *lh, nxt_lvlhsh_each_t *lhe)
 {
     void  **slot;
 
index cf6552033fa9edcea81d3aa6cd0e4a4064e4ef2a..d5d8e7093eb2a2212d5e8461baee71ee93e923ec 100644 (file)
@@ -126,7 +126,8 @@ struct nxt_lvlhsh_query_s {
  *
  * The required nxt_lvlhsh_query_t fields: key_hash, key, proto.
  */
-NXT_EXPORT nxt_int_t nxt_lvlhsh_find(nxt_lvlhsh_t *lh, nxt_lvlhsh_query_t *lhq);
+NXT_EXPORT nxt_int_t nxt_lvlhsh_find(const nxt_lvlhsh_t *lh,
+    nxt_lvlhsh_query_t *lhq);
 
 /*
  * nxt_lvlhsh_insert() adds a hash element.  If the element already
@@ -179,7 +180,8 @@ typedef struct {
         (lhe)->proto = _proto;                                                \
     } while (0)
 
-NXT_EXPORT void *nxt_lvlhsh_each(nxt_lvlhsh_t *lh, nxt_lvlhsh_each_t *lhe);
+NXT_EXPORT void *nxt_lvlhsh_each(const nxt_lvlhsh_t *lh,
+    nxt_lvlhsh_each_t *lhe);
 
 
 #endif /* _NXT_LVLHSH_H_INCLUDED_ */