[njs] Querying global object when variable cannot be resolved.

Dmitry Volyntsev xeioex at nginx.com
Fri Oct 18 14:00:10 UTC 2019


details:   https://hg.nginx.org/njs/rev/5f192dbb694e
branches:  
changeset: 1188:5f192dbb694e
user:      Dmitry Volyntsev <xeioex at nginx.com>
date:      Fri Oct 18 16:34:50 2019 +0300
description:
Querying global object when variable cannot be resolved.

diffstat:

 src/njs_disassembler.c   |   2 +
 src/njs_generator.c      |  97 ++++++++++++++++++++++++++++++++++-------------
 src/njs_vmcode.c         |  17 ++++++++
 src/njs_vmcode.h         |   1 +
 src/test/njs_unit_test.c |  22 ++++++++++
 5 files changed, 111 insertions(+), 28 deletions(-)

diffs (285 lines):

diff -r 10c10102cad0 -r 5f192dbb694e src/njs_disassembler.c
--- a/src/njs_disassembler.c	Fri Oct 18 16:28:16 2019 +0300
+++ b/src/njs_disassembler.c	Fri Oct 18 16:34:50 2019 +0300
@@ -34,6 +34,8 @@ static njs_code_name_t  code_names[] = {
 
     { NJS_VMCODE_PROPERTY_GET, sizeof(njs_vmcode_prop_get_t),
           njs_str("PROP GET        ") },
+    { NJS_VMCODE_GLOBAL_GET, sizeof(njs_vmcode_prop_get_t),
+          njs_str("GLOBAL GET      ") },
     { NJS_VMCODE_PROPERTY_INIT, sizeof(njs_vmcode_prop_set_t),
           njs_str("PROP INIT       ") },
     { NJS_VMCODE_PROTO_INIT, sizeof(njs_vmcode_prop_set_t),
diff -r 10c10102cad0 -r 5f192dbb694e src/njs_generator.c
--- a/src/njs_generator.c	Fri Oct 18 16:28:16 2019 +0300
+++ b/src/njs_generator.c	Fri Oct 18 16:34:50 2019 +0300
@@ -62,7 +62,7 @@ static njs_int_t njs_generate_name(njs_v
 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_parser_node_t *node, njs_reference_type_t type);
 static njs_int_t njs_generate_var_statement(njs_vm_t *vm,
     njs_generator_t *generator, njs_parser_node_t *node);
 static njs_int_t njs_generate_if_statement(njs_vm_t *vm,
@@ -176,6 +176,8 @@ static njs_int_t njs_generate_node_index
     njs_generator_t *generator, njs_parser_node_t *node);
 static njs_int_t njs_generate_index_release(njs_vm_t *vm,
     njs_generator_t *generator, njs_index_t index);
+static njs_int_t njs_generate_global_reference(njs_vm_t *vm,
+    njs_generator_t *generator, njs_parser_node_t *node, njs_bool_t exception);
 static njs_int_t njs_generate_reference_error(njs_vm_t *vm,
     njs_generator_t *generator, njs_parser_node_t *node);
 
@@ -577,11 +579,8 @@ njs_generate_name(njs_vm_t *vm, njs_gene
     njs_vmcode_object_copy_t  *copy;
 
     var = njs_variable_resolve(vm, node);
-    if (njs_slow_path(var == NULL)) {
-        return njs_generate_reference_error(vm, generator, node);
-    }
-
-    if (var->type == NJS_VARIABLE_FUNCTION) {
+
+    if (var != NULL && var->type == NJS_VARIABLE_FUNCTION) {
 
         node->index = njs_generate_dest_index(vm, generator, node);
         if (njs_slow_path(node->index == NJS_INDEX_ERROR)) {
@@ -596,7 +595,7 @@ njs_generate_name(njs_vm_t *vm, njs_gene
         return NJS_OK;
     }
 
-    return njs_generate_variable(vm, generator, node);
+    return njs_generate_variable(vm, generator, node, NJS_REFERENCE);
 }
 
 
@@ -628,13 +627,22 @@ njs_generate_builtin_object(njs_vm_t *vm
 
 static njs_int_t
 njs_generate_variable(njs_vm_t *vm, njs_generator_t *generator,
-    njs_parser_node_t *node)
+    njs_parser_node_t *node, njs_reference_type_t type)
 {
     njs_index_t  index;
 
     index = njs_variable_index(vm, node);
     if (njs_slow_path(index == NJS_INDEX_NONE)) {
-        return njs_generate_reference_error(vm, generator, node);
+
+        switch (type) {
+        case NJS_DECLARATION:
+            return njs_generate_reference_error(vm, generator, node);
+
+        case NJS_REFERENCE:
+        case NJS_TYPEOF:
+            return njs_generate_global_reference(vm, generator, node,
+                                                 type == NJS_REFERENCE);
+        }
     }
 
     node->index = index;
@@ -1682,7 +1690,7 @@ njs_generate_assignment(njs_vm_t *vm, nj
 
     if (lvalue->token == NJS_TOKEN_NAME) {
 
-        ret = njs_generate_variable(vm, generator, lvalue);
+        ret = njs_generate_variable(vm, generator, lvalue, NJS_DECLARATION);
         if (njs_slow_path(ret != NJS_OK)) {
             return ret;
         }
@@ -1805,7 +1813,7 @@ njs_generate_operation_assignment(njs_vm
 
     if (lvalue->token == NJS_TOKEN_NAME) {
 
-        ret = njs_generate_variable(vm, generator, lvalue);
+        ret = njs_generate_variable(vm, generator, lvalue, NJS_DECLARATION);
         if (njs_slow_path(ret != NJS_OK)) {
             return ret;
         }
@@ -2239,17 +2247,9 @@ njs_generate_typeof_operation(njs_vm_t *
     expr = node->left;
 
     if (expr->token == NJS_TOKEN_NAME) {
-        expr->index = njs_variable_typeof(vm, expr);
-
-        if (expr->u.reference.variable) {
-            ret = njs_generate_variable(vm, generator, expr);
-            if (njs_slow_path(ret != NJS_OK)) {
-                return NJS_ERROR;
-            }
-
-        } else {
-            expr->index = njs_value_index(vm, &njs_value_undefined,
-                                          generator->runtime);
+        ret = njs_generate_variable(vm, generator, expr, NJS_TYPEOF);
+        if (njs_slow_path(ret != NJS_OK)) {
+            return NJS_ERROR;
         }
 
     } else {
@@ -2291,7 +2291,7 @@ njs_generate_inc_dec_operation(njs_vm_t 
 
     if (lvalue->token == NJS_TOKEN_NAME) {
 
-        ret = njs_generate_variable(vm, generator, lvalue);
+        ret = njs_generate_variable(vm, generator, lvalue, NJS_DECLARATION);
         if (njs_slow_path(ret != NJS_OK)) {
             return ret;
         }
@@ -2668,7 +2668,7 @@ njs_generate_function_call(njs_vm_t *vm,
         name = node->left;
 
     } else {
-        ret = njs_generate_variable(vm, generator, node);
+        ret = njs_generate_variable(vm, generator, node, NJS_REFERENCE);
         if (njs_slow_path(ret != NJS_OK)) {
             return ret;
         }
@@ -2676,10 +2676,6 @@ njs_generate_function_call(njs_vm_t *vm,
         name = node;
     }
 
-    if (node->u.reference.not_defined) {
-        return NJS_OK;
-    }
-
     njs_generate_code(generator, njs_vmcode_function_frame_t, func,
                       NJS_VMCODE_FUNCTION_FRAME, 2);
     func_offset = njs_code_offset(generator, func);
@@ -3361,6 +3357,51 @@ njs_generate_index_release(njs_vm_t *vm,
 
 
 static njs_int_t
+njs_generate_global_reference(njs_vm_t *vm, njs_generator_t *generator,
+    njs_parser_node_t *node, njs_bool_t exception)
+{
+    njs_str_t              *name;
+    njs_int_t              ret;
+    njs_index_t            index;
+    njs_value_t            property;
+    njs_vmcode_prop_get_t  *prop_get;
+
+    index = njs_generate_dest_index(vm, generator, node);
+    if (njs_slow_path(index == NJS_INDEX_ERROR)) {
+        return NJS_ERROR;
+    }
+
+    njs_generate_code(generator, njs_vmcode_prop_get_t, prop_get,
+                 exception ? NJS_VMCODE_GLOBAL_GET: NJS_VMCODE_PROPERTY_GET, 3);
+
+    prop_get->value = index;
+    prop_get->object = NJS_INDEX_GLOBAL_OBJECT;
+
+    /* FIXME: cache keys in a hash. */
+
+    name = &node->u.reference.name;
+
+    ret = njs_string_set(vm, &property, name->start, name->length);
+    if (njs_slow_path(ret != NJS_OK)) {
+        return NJS_ERROR;
+    }
+
+    prop_get->property = njs_value_index(vm, &property, generator->runtime);
+    if (njs_slow_path(prop_get->property == NJS_INDEX_NONE)) {
+        return NJS_ERROR;
+    }
+
+    node->index = index;
+
+    if (!exception) {
+        return NJS_OK;
+    }
+
+    return njs_generate_reference_error(vm, generator, node);
+}
+
+
+static njs_int_t
 njs_generate_reference_error(njs_vm_t *vm, njs_generator_t *generator,
     njs_parser_node_t *node)
 {
diff -r 10c10102cad0 -r 5f192dbb694e src/njs_vmcode.c
--- a/src/njs_vmcode.c	Fri Oct 18 16:28:16 2019 +0300
+++ b/src/njs_vmcode.c	Fri Oct 18 16:34:50 2019 +0300
@@ -209,6 +209,23 @@ next:
                 pc += sizeof(njs_vmcode_3addr_t);
                 goto next;
 
+            case NJS_VMCODE_GLOBAL_GET:
+                get = (njs_vmcode_prop_get_t *) pc;
+                retval = njs_vmcode_operand(vm, get->value);
+
+                ret = njs_value_property(vm, value1, value2, retval);
+                if (njs_slow_path(ret == NJS_ERROR)) {
+                    goto error;
+                }
+
+                pc += sizeof(njs_vmcode_prop_get_t);
+
+                if (ret == NJS_OK) {
+                    pc += sizeof(njs_vmcode_reference_error_t);
+                }
+
+                goto next;
+
             /*
              * njs_vmcode_try_return() saves a return value to use it later by
              * njs_vmcode_finally(), and jumps to the nearest try_break block.
diff -r 10c10102cad0 -r 5f192dbb694e src/njs_vmcode.h
--- a/src/njs_vmcode.h	Fri Oct 18 16:28:16 2019 +0300
+++ b/src/njs_vmcode.h	Fri Oct 18 16:34:50 2019 +0300
@@ -72,6 +72,7 @@ typedef uint8_t                         
 #define NJS_VMCODE_DECREMENT            VMCODE1(4)
 #define NJS_VMCODE_POST_DECREMENT       VMCODE1(5)
 #define NJS_VMCODE_TRY_RETURN           VMCODE1(6)
+#define NJS_VMCODE_GLOBAL_GET           VMCODE1(7)
 
 #define NJS_VMCODE_LESS                 VMCODE1(8)
 #define NJS_VMCODE_GREATER              VMCODE1(9)
diff -r 10c10102cad0 -r 5f192dbb694e src/test/njs_unit_test.c
--- a/src/test/njs_unit_test.c	Fri Oct 18 16:28:16 2019 +0300
+++ b/src/test/njs_unit_test.c	Fri Oct 18 16:34:50 2019 +0300
@@ -2694,6 +2694,10 @@ static njs_unit_test_t  njs_test[] =
                  "}; t"),
       njs_str("A") },
 
+    { njs_str("[isNaN, undefined, isFinite]."
+              "map((v)=>{switch(v) { case isNaN: return 1; default: return 0;}})"),
+      njs_str("1,0,0") },
+
     /* continue. */
 
     { njs_str("continue"),
@@ -9319,6 +9323,18 @@ static njs_unit_test_t  njs_test[] =
     { njs_str("this.a = 1; this.a"),
       njs_str("1") },
 
+    { njs_str("this.a = 1; a"),
+      njs_str("1") },
+
+    { njs_str("this.a = 2; this.b = 3; a * b - a"),
+      njs_str("4") },
+
+    { njs_str("this.a = 1; a()"),
+      njs_str("TypeError: number is not a function") },
+
+    { njs_str("this.a = ()=>1; a()"),
+      njs_str("1") },
+
     { njs_str("this.undefined = 42"),
       njs_str("TypeError: Cannot assign to read-only property \"undefined\" of object") },
 
@@ -13084,6 +13100,12 @@ static njs_unit_test_t  njs_test[] =
     { njs_str("isNaN.length"),
       njs_str("1") },
 
+    { njs_str("typeof isNaN"),
+      njs_str("function") },
+
+    { njs_str("typeof isNaN.length"),
+      njs_str("number") },
+
     { njs_str("isNaN()"),
       njs_str("true") },
 


More information about the nginx-devel mailing list