]> git.kaiwu.me - njs.git/commitdiff
Moving top-level objects to global object.
authorDmitry Volyntsev <xeioex@nginx.com>
Thu, 31 Oct 2019 15:17:31 +0000 (18:17 +0300)
committerDmitry Volyntsev <xeioex@nginx.com>
Thu, 31 Oct 2019 15:17:31 +0000 (18:17 +0300)
src/njs_builtin.c
src/njs_generator.c
src/njs_lexer.h
src/njs_lexer_keyword.c
src/njs_object_hash.h
src/njs_parser_terminal.c
src/njs_value.h
src/test/njs_unit_test.c
test/njs_expect_test.exp

index 3beda05a3543f5ee5c81753df724b8e30c0520b7..4f0734168793776b636783ce10c6ff71174681e9 100644 (file)
@@ -1042,8 +1042,58 @@ njs_dump_value(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
 }
 
 
+static njs_int_t
+njs_top_level_object(njs_vm_t *vm, njs_object_prop_t *self,
+    njs_value_t *global, njs_value_t *setval, njs_value_t *retval)
+{
+    njs_int_t           ret;
+    njs_object_t        *object;
+    njs_object_prop_t   *prop;
+    njs_lvlhsh_query_t  lhq;
+
+    if (njs_slow_path(setval != NULL)) {
+        *retval = *setval;
+
+    } else {
+        njs_set_object(retval, &vm->shared->objects[self->value.data.magic16]);
+
+        object = njs_object_value_copy(vm, retval);
+        if (njs_slow_path(object == NULL)) {
+            return NJS_ERROR;
+        }
+    }
+
+    prop = njs_object_prop_alloc(vm, &self->name, retval, 1);
+    if (njs_slow_path(prop == NULL)) {
+        return NJS_ERROR;
+    }
+
+    /* GC */
+
+    prop->value = *retval;
+    prop->enumerable = 0;
+
+    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;
+
+    ret = njs_lvlhsh_insert(njs_object_hash(global), &lhq);
+    if (njs_slow_path(ret != NJS_OK)) {
+        njs_internal_error(vm, "lvlhsh insert/replace failed");
+        return NJS_ERROR;
+    }
+
+    return NJS_OK;
+}
+
+
 static const njs_object_prop_t  njs_global_this_object_properties[] =
 {
+    /* Global constants. */
+
     {
         .type = NJS_PROPERTY,
         .name = njs_string("NaN"),
@@ -1062,6 +1112,8 @@ static const njs_object_prop_t  njs_global_this_object_properties[] =
         .value = njs_value(NJS_UNDEFINED, 0, NAN),
     },
 
+    /* Global functions. */
+
     {
         .type = NJS_PROPERTY,
         .name = njs_string("isFinite"),
@@ -1174,6 +1226,44 @@ static const njs_object_prop_t  njs_global_this_object_properties[] =
         .configurable = 1,
     },
 
+    /* Global objects. */
+
+    {
+        .type = NJS_PROPERTY_HANDLER,
+        .name = njs_string("njs"),
+        .value = njs_prop_handler2(njs_top_level_object, NJS_OBJECT_NJS,
+                                   NJS_NJS_HASH),
+        .writable = 1,
+        .configurable = 1,
+    },
+
+    {
+        .type = NJS_PROPERTY_HANDLER,
+        .name = njs_string("process"),
+        .value = njs_prop_handler2(njs_top_level_object, NJS_OBJECT_PROCESS,
+                                   NJS_PROCESS_HASH),
+        .writable = 1,
+        .configurable = 1,
+    },
+
+    {
+        .type = NJS_PROPERTY_HANDLER,
+        .name = njs_string("Math"),
+        .value = njs_prop_handler2(njs_top_level_object, NJS_OBJECT_MATH,
+                                   NJS_MATH_HASH),
+        .writable = 1,
+        .configurable = 1,
+    },
+
+    {
+        .type = NJS_PROPERTY_HANDLER,
+        .name = njs_string("JSON"),
+        .value = njs_prop_handler2(njs_top_level_object, NJS_OBJECT_JSON,
+                                   NJS_JSON_HASH),
+        .writable = 1,
+        .configurable = 1,
+    },
+
 };
 
 
index 41a19c5647e7f0d21b9ae63985d93ebb3c924e23..948bf277e0e0265bd30bc2284e7d4dfb96477115 100644 (file)
@@ -59,8 +59,6 @@ static u_char *njs_generate_reserve(njs_vm_t *vm, njs_generator_t *generator,
     size_t size);
 static njs_int_t njs_generate_name(njs_vm_t *vm, njs_generator_t *generator,
     njs_parser_node_t *node);
-static njs_int_t njs_generate_builtin_object(njs_vm_t *vm,
-    njs_generator_t *generator, njs_parser_node_t *node);
 static njs_int_t njs_generate_variable(njs_vm_t *vm, njs_generator_t *generator,
     njs_parser_node_t *node, njs_reference_type_t type);
 static njs_int_t njs_generate_var_statement(njs_vm_t *vm,
@@ -460,12 +458,6 @@ njs_generate(njs_vm_t *vm, njs_generator_t *generator, njs_parser_node_t *node)
 
         return NJS_OK;
 
-    case NJS_TOKEN_NJS:
-    case NJS_TOKEN_PROCESS:
-    case NJS_TOKEN_MATH:
-    case NJS_TOKEN_JSON:
-        return njs_generate_builtin_object(vm, generator, node);
-
     case NJS_TOKEN_FUNCTION:
         return njs_generate_function_declaration(vm, generator, node);
 
@@ -586,32 +578,6 @@ njs_generate_name(njs_vm_t *vm, njs_generator_t *generator,
 }
 
 
-static njs_int_t
-njs_generate_builtin_object(njs_vm_t *vm, njs_generator_t *generator,
-    njs_parser_node_t *node)
-{
-    njs_index_t               index;
-    njs_vmcode_object_copy_t  *copy;
-
-    index = njs_variable_index(vm, node);
-    if (njs_slow_path(index == NJS_INDEX_NONE)) {
-        return NJS_ERROR;
-    }
-
-    node->index = njs_generate_dest_index(vm, generator, node);
-    if (njs_slow_path(node->index == NJS_INDEX_ERROR)) {
-        return NJS_ERROR;
-    }
-
-    njs_generate_code(generator, njs_vmcode_object_copy_t, copy,
-                      NJS_VMCODE_OBJECT_COPY, 2);
-    copy->retval = node->index;
-    copy->object = index;
-
-    return NJS_OK;
-}
-
-
 static njs_int_t
 njs_generate_variable(njs_vm_t *vm, njs_generator_t *generator,
     njs_parser_node_t *node, njs_reference_type_t type)
index d14e93a19297de00b3e4315525048d3ca2c098ce..1ae6bf52d55cd69e1a51bdd73f787cf34849ce62 100644 (file)
@@ -166,18 +166,11 @@ typedef enum {
     NJS_TOKEN_THROW,
 
     NJS_TOKEN_THIS,
+    NJS_TOKEN_GLOBAL_OBJECT,
     NJS_TOKEN_NON_LOCAL_THIS,
     NJS_TOKEN_ARGUMENTS,
     NJS_TOKEN_EVAL,
 
-#define NJS_TOKEN_FIRST_OBJECT     NJS_TOKEN_GLOBAL_OBJECT
-
-    NJS_TOKEN_GLOBAL_OBJECT,
-    NJS_TOKEN_NJS,
-    NJS_TOKEN_PROCESS,
-    NJS_TOKEN_MATH,
-    NJS_TOKEN_JSON,
-
     NJS_TOKEN_OBJECT_CONSTRUCTOR,
     NJS_TOKEN_ARRAY_CONSTRUCTOR,
     NJS_TOKEN_BOOLEAN_CONSTRUCTOR,
index c7e74c830f73c1288d9b44d248a20fd98cc239df..dbd8902929be664cd67e9191ff404cf037154cc2 100644 (file)
@@ -47,14 +47,6 @@ static const njs_keyword_t  njs_keywords[] = {
     { njs_str("finally"),       NJS_TOKEN_FINALLY, 0 },
     { njs_str("throw"),         NJS_TOKEN_THROW, 0 },
 
-    /* Builtin objects. */
-
-    { njs_str("this"),          NJS_TOKEN_THIS, 0 },
-    { njs_str("njs"),           NJS_TOKEN_NJS, 0 },
-    { njs_str("process"),       NJS_TOKEN_PROCESS, 0 },
-    { njs_str("Math"),          NJS_TOKEN_MATH, 0 },
-    { njs_str("JSON"),          NJS_TOKEN_JSON, 0 },
-
     /* Builtin functions. */
 
     { njs_str("Object"),        NJS_TOKEN_OBJECT_CONSTRUCTOR, 0 },
@@ -82,6 +74,7 @@ static const njs_keyword_t  njs_keywords[] = {
 
     /* Reserved words. */
 
+    { njs_str("this"),          NJS_TOKEN_THIS, 0 },
     { njs_str("arguments"),     NJS_TOKEN_ARGUMENTS, 0 },
     { njs_str("eval"),          NJS_TOKEN_EVAL, 0 },
 
index 9f8fcce75a524827fdaca95ff75fecd7250055d4..34508078d46e3bc7ba133a3fd9602f4609eb02d6 100644 (file)
         'j'), 'o'), 'i'), 'n')
 
 
+#define NJS_JSON_HASH                                                         \
+    njs_djb_hash_add(                                                         \
+    njs_djb_hash_add(                                                         \
+    njs_djb_hash_add(                                                         \
+    njs_djb_hash_add(NJS_DJB_HASH_INIT,                                       \
+        'J'), 'S'), 'O'), 'N')
+
+
 #define NJS_LENGTH_HASH                                                       \
     njs_djb_hash_add(                                                         \
     njs_djb_hash_add(                                                         \
         'n'), 'a'), 'm'), 'e')
 
 
+#define NJS_NJS_HASH                                                          \
+    njs_djb_hash_add(                                                         \
+    njs_djb_hash_add(                                                         \
+    njs_djb_hash_add(NJS_DJB_HASH_INIT,                                       \
+        'n'), 'j'), 's')
+
+
+#define NJS_MATH_HASH                                                         \
+    njs_djb_hash_add(                                                         \
+    njs_djb_hash_add(                                                         \
+    njs_djb_hash_add(                                                         \
+    njs_djb_hash_add(NJS_DJB_HASH_INIT,                                       \
+        'M'), 'a'), 't'), 'h')
+
+
 #define NJS_MESSAGE_HASH                                                      \
     njs_djb_hash_add(                                                         \
     njs_djb_hash_add(                                                         \
         'p'), 'a'), 't'), 'h')
 
 
+#define NJS_PROCESS_HASH                                                      \
+    njs_djb_hash_add(                                                         \
+    njs_djb_hash_add(                                                         \
+    njs_djb_hash_add(                                                         \
+    njs_djb_hash_add(                                                         \
+    njs_djb_hash_add(                                                         \
+    njs_djb_hash_add(                                                         \
+    njs_djb_hash_add(NJS_DJB_HASH_INIT,                                       \
+        'p'), 'r'), 'o'), 'c'), 'e'), 's'), 's')
+
+
 #define NJS_PROTOTYPE_HASH                                                    \
     njs_djb_hash_add(                                                         \
     njs_djb_hash_add(                                                         \
index 24e74a7c94f10b3642e52aef187afb57345a3be6..71dd55dc87db32f34aee71ec9bbbab77c6b86b18 100644 (file)
@@ -11,9 +11,6 @@
 static njs_parser_node_t *njs_parser_reference(njs_vm_t *vm,
     njs_parser_t *parser, njs_token_t token, njs_str_t *name, uint32_t hash,
     uint32_t token_line);
-static njs_int_t njs_parser_builtin(njs_vm_t *vm, njs_parser_t *parser,
-    njs_parser_node_t *node, njs_value_type_t type, njs_str_t *name,
-    uint32_t hash);
 static njs_token_t njs_parser_object(njs_vm_t *vm, njs_parser_t *parser,
     njs_parser_node_t *obj);
 static njs_int_t njs_parser_object_property(njs_vm_t *vm, njs_parser_t *parser,
@@ -259,17 +256,6 @@ njs_parser_reference(njs_vm_t *vm, njs_parser_t *parser, njs_token_t token,
 
         break;
 
-    case NJS_TOKEN_NJS:
-    case NJS_TOKEN_PROCESS:
-    case NJS_TOKEN_MATH:
-    case NJS_TOKEN_JSON:
-        ret = njs_parser_builtin(vm, parser, node, NJS_OBJECT, name, hash);
-        if (njs_slow_path(ret != NJS_OK)) {
-            return NULL;
-        }
-
-        break;
-
     case NJS_TOKEN_OBJECT_CONSTRUCTOR:
         node->index = NJS_INDEX_OBJECT;
         break;
@@ -399,42 +385,6 @@ njs_parser_reference(njs_vm_t *vm, njs_parser_t *parser, njs_token_t token,
 }
 
 
-static njs_int_t
-njs_parser_builtin(njs_vm_t *vm, njs_parser_t *parser, njs_parser_node_t *node,
-    njs_value_type_t type, njs_str_t *name, uint32_t hash)
-{
-    njs_int_t           ret;
-    njs_uint_t          index;
-    njs_variable_t      *var;
-    njs_parser_scope_t  *scope;
-
-    scope = njs_parser_global_scope(vm);
-
-    var = njs_variable_add(vm, scope, name, hash, NJS_VARIABLE_VAR);
-    if (njs_slow_path(var == NULL)) {
-        return NJS_ERROR;
-    }
-
-    /* TODO: once */
-    switch (type) {
-    case NJS_OBJECT:
-        index = node->token - NJS_TOKEN_FIRST_OBJECT;
-        njs_set_object(&var->value, &vm->shared->objects[index]);
-        break;
-
-    default:
-        return NJS_ERROR;
-    }
-
-    ret = njs_variable_reference(vm, scope, node, name, hash, NJS_REFERENCE);
-    if (njs_slow_path(ret != NJS_OK)) {
-        return NJS_ERROR;
-    }
-
-    return NJS_OK;
-}
-
-
 static njs_token_t
 njs_parser_object(njs_vm_t *vm, njs_parser_t *parser, njs_parser_node_t *obj)
 {
index b84d10d67b43ded76f0fe7812b7b81418b706612..edf4c91e3e67e6fe14f32da87fc8426cfb1c6add 100644 (file)
@@ -128,8 +128,8 @@ union njs_value_s {
          */
         uint8_t                       truth;
 
-        uint16_t                      _spare1;
-        uint32_t                      _spare2;
+        uint16_t                      magic16;
+        uint32_t                      magic32;
 
         union {
             double                    number;
@@ -409,6 +409,17 @@ typedef struct {
 }
 
 
+#define njs_prop_handler2(_handler, _magic16, _magic32) {                     \
+    .data = {                                                                 \
+        .type = NJS_INVALID,                                                  \
+        .truth = 1,                                                           \
+        .magic16 = _magic16,                                                  \
+        .magic32 = _magic32,                                                  \
+        .u = { .prop_handler = _handler }                                     \
+    }                                                                         \
+}
+
+
 #define njs_is_null(value)                                                    \
     ((value)->type == NJS_NULL)
 
index 8d1c3966b35d60178f9a5fbfd20560068eadcf8f..d2bfc2f281ebe0044f1dbf8749337a0c24c7f7e3 100644 (file)
@@ -13227,6 +13227,43 @@ static njs_unit_test_t  njs_test[] =
     { njs_str("parseFloat('-5.7e+abc')"),
       njs_str("-5.7") },
 
+    /* Top-level objects. */
+
+    { njs_str("var global = this;"
+              "function isMutableObject(v) {"
+              "    var d = Object.getOwnPropertyDescriptor(global, v);"
+              "    return d.writable && !d.enumerable && d.configurable;"
+              "};"
+              "['njs', 'process', 'Math', 'JSON'].every((v)=>isMutableObject(v))"),
+      njs_str("true") },
+
+    { njs_str("njs === njs"),
+      njs_str("true") },
+
+    { njs_str("this.njs = 1; njs"),
+      njs_str("1") },
+
+    { njs_str("process === process"),
+      njs_str("true") },
+
+    { njs_str("this.process = 1; process"),
+      njs_str("1") },
+
+    { njs_str("Math === Math"),
+      njs_str("true") },
+
+    { njs_str("this.Math = 1; Math"),
+      njs_str("1") },
+
+    { njs_str("JSON === JSON"),
+      njs_str("true") },
+
+    { njs_str("this.JSON = 1; JSON"),
+      njs_str("1") },
+
+    { njs_str("delete this.JSON; JSON"),
+      njs_str("ReferenceError: \"JSON\" is not defined in 1") },
+
     /* JSON.parse() */
 
     { njs_str("JSON.parse('null')"),
index 2587f5664065d0086163293ea2f500a5529fd75a..0559baace666a17ecec0201eae2f398279117c65 100644 (file)
@@ -120,8 +120,8 @@ njs_test {
 
 njs_test {
     {"Ma\t"
-     "Ma\a*th"}
-    {".\t\t"
+     "Ma\a*th."}
+    {"\t\t"
      "Math.abs*Math.atan2"}
 }