]> git.kaiwu.me - njs.git/commitdiff
Fixed complex assignments.
authorDmitry Volyntsev <xeioex@nginx.com>
Fri, 16 Sep 2022 03:20:11 +0000 (20:20 -0700)
committerDmitry Volyntsev <xeioex@nginx.com>
Fri, 16 Sep 2022 03:20:11 +0000 (20:20 -0700)
A new instruction is introduced NJS_VMCODE_TO_PROPERTY_KEY to ensure
that property key is evaluated only once.

src/njs_disassembler.c
src/njs_generator.c
src/njs_value.c
src/njs_vmcode.c
src/njs_vmcode.h
src/test/njs_unit_test.c

index d4c748484ab40d97d13ed0dc9bdab958fa974538..68fd234e12672067b11a0e5be2d3d98c52f29112 100644 (file)
@@ -74,6 +74,8 @@ static njs_code_name_t  code_names[] = {
           njs_str("VOID            ") },
     { NJS_VMCODE_TYPEOF, sizeof(njs_vmcode_2addr_t),
           njs_str("TYPEOF          ") },
+    { NJS_VMCODE_TO_PROPERTY_KEY, sizeof(njs_vmcode_3addr_t),
+          njs_str("TO PROPERTY KEY ") },
 
     { NJS_VMCODE_UNARY_PLUS, sizeof(njs_vmcode_2addr_t),
           njs_str("PLUS            ") },
index 8cc7ee0ac2160dee848ad9c613ea64cd18319685..74c4635d3581e8178a33b93eee54fbeeed8a1969 100644 (file)
@@ -3016,9 +3016,10 @@ static njs_int_t
 njs_generate_operation_assignment_prop(njs_vm_t *vm, njs_generator_t *generator,
     njs_parser_node_t *node)
 {
-    njs_index_t            index, src;
+    njs_index_t            index, src, prop_index;
     njs_parser_node_t      *lvalue, *object, *property;
     njs_vmcode_move_t      *move;
+    njs_vmcode_3addr_t     *to_property_key;
     njs_vmcode_prop_get_t  *prop_get;
 
     lvalue = node->left;
@@ -3053,6 +3054,18 @@ njs_generate_operation_assignment_prop(njs_vm_t *vm, njs_generator_t *generator,
         }
     }
 
+    prop_index = njs_generate_node_temp_index_get(vm, generator, node);
+    if (njs_slow_path(prop_index == NJS_INDEX_ERROR)) {
+        return NJS_ERROR;
+    }
+
+    njs_generate_code(generator, njs_vmcode_3addr_t, to_property_key,
+                      NJS_VMCODE_TO_PROPERTY_KEY, 2, property);
+
+    to_property_key->src2 = object->index;
+    to_property_key->src1 = property->index;
+    to_property_key->dst = prop_index;
+
     index = njs_generate_node_temp_index_get(vm, generator, node);
     if (njs_slow_path(index == NJS_INDEX_ERROR)) {
         return NJS_ERROR;
@@ -3062,13 +3075,14 @@ njs_generate_operation_assignment_prop(njs_vm_t *vm, njs_generator_t *generator,
                       NJS_VMCODE_PROPERTY_GET, 3, property);
     prop_get->value = index;
     prop_get->object = object->index;
-    prop_get->property = property->index;
+    prop_get->property = prop_index;
 
     njs_generator_next(generator, njs_generate, node->right);
 
     return njs_generator_after(vm, generator,
                                njs_queue_first(&generator->stack), node,
-                               njs_generate_operation_assignment_end, NULL, 0);
+                               njs_generate_operation_assignment_end,
+                               &prop_index, sizeof(njs_index_t));
 }
 
 
@@ -3077,6 +3091,7 @@ njs_generate_operation_assignment_end(njs_vm_t *vm, njs_generator_t *generator,
     njs_parser_node_t *node)
 {
     njs_int_t              ret;
+    njs_index_t            prop_index;
     njs_parser_node_t      *lvalue, *expr;
     njs_vmcode_3addr_t     *code;
     njs_vmcode_prop_set_t  *prop_set;
@@ -3084,6 +3099,8 @@ njs_generate_operation_assignment_end(njs_vm_t *vm, njs_generator_t *generator,
     lvalue = node->left;
     expr = node->right;
 
+    prop_index = *((njs_index_t *) generator->context);
+
     njs_generate_code(generator, njs_vmcode_3addr_t, code,
                       node->u.operation, 3, expr);
     code->dst = node->index;
@@ -3094,7 +3111,7 @@ njs_generate_operation_assignment_end(njs_vm_t *vm, njs_generator_t *generator,
                       NJS_VMCODE_PROPERTY_SET, 3, expr);
     prop_set->value = node->index;
     prop_set->object = lvalue->left->index;
-    prop_set->property = lvalue->right->index;
+    prop_set->property = prop_index;
 
     ret = njs_generate_children_indexes_release(vm, generator, lvalue);
     if (njs_slow_path(ret != NJS_OK)) {
@@ -3677,9 +3694,9 @@ njs_generate_inc_dec_operation_prop(njs_vm_t *vm, njs_generator_t *generator,
 {
     njs_int_t              ret;
     njs_bool_t             post;
-    njs_index_t            index, dest_index;
+    njs_index_t            index, dest_index, prop_index;
     njs_parser_node_t      *lvalue;
-    njs_vmcode_3addr_t     *code;
+    njs_vmcode_3addr_t     *code, *to_property_key;
     njs_vmcode_prop_get_t  *prop_get;
     njs_vmcode_prop_set_t  *prop_set;
 
@@ -3701,6 +3718,18 @@ njs_generate_inc_dec_operation_prop(njs_vm_t *vm, njs_generator_t *generator,
 
 found:
 
+    prop_index = njs_generate_temp_index_get(vm, generator, node);
+    if (njs_slow_path(prop_index == NJS_INDEX_ERROR)) {
+        return NJS_ERROR;
+    }
+
+    njs_generate_code(generator, njs_vmcode_3addr_t, to_property_key,
+                      NJS_VMCODE_TO_PROPERTY_KEY, 2, node);
+
+    to_property_key->src2 = lvalue->left->index;
+    to_property_key->src1 = lvalue->right->index;
+    to_property_key->dst = prop_index;
+
     post = *((njs_bool_t *) generator->context);
 
     index = post ? njs_generate_temp_index_get(vm, generator, node)
@@ -3714,7 +3743,7 @@ found:
                       NJS_VMCODE_PROPERTY_GET, 3, node);
     prop_get->value = index;
     prop_get->object = lvalue->left->index;
-    prop_get->property = lvalue->right->index;
+    prop_get->property = prop_index;
 
     njs_generate_code(generator, njs_vmcode_3addr_t, code,
                       node->u.operation, 3, node);
@@ -3726,7 +3755,7 @@ found:
                       NJS_VMCODE_PROPERTY_SET, 3, node);
     prop_set->value = index;
     prop_set->object = lvalue->left->index;
-    prop_set->property = lvalue->right->index;
+    prop_set->property = prop_index;
 
     if (post) {
         ret = njs_generate_index_release(vm, generator, index);
index 7e8597f307d6bfb75fc78a64375b9c24cd7909a8..6a401bfbc061b47725edd2993f56528bc0b11e1c 100644 (file)
@@ -586,12 +586,14 @@ njs_property_query(njs_vm_t *vm, njs_property_query_t *pq, njs_value_t *value,
 
         if (njs_fast_path(ret == NJS_OK)) {
             njs_string_get(&pq->key, &pq->lhq.key);
-            njs_type_error(vm, "cannot get property \"%V\" of undefined",
-                           &pq->lhq.key);
+            njs_type_error(vm, "cannot get property \"%V\" of %s",
+                           &pq->lhq.key, njs_is_null(value) ? "null"
+                                                            : "undefined");
             return NJS_ERROR;
         }
 
-        njs_type_error(vm, "cannot get property \"unknown\" of undefined");
+        njs_type_error(vm, "cannot get property \"unknown\" of %s",
+                       njs_is_null(value) ? "null" : "undefined");
 
         return NJS_ERROR;
     }
index e0785f0b68824cadf032a04f98e6f91ed52a407c..bcef3097d1f0e778e346c054e90ab058c7b63568 100644 (file)
@@ -883,9 +883,26 @@ next:
             case NJS_VMCODE_ARGUMENTS:
                 ret = njs_vmcode_arguments(vm, pc);
                 if (njs_slow_path(ret == NJS_ERROR)) {
+                }
+
+                break;
+
+            case NJS_VMCODE_TO_PROPERTY_KEY:
+                njs_vmcode_operand(vm, (njs_index_t) value2, retval);
+                njs_vmcode_operand(vm, vmcode->operand3, value2);
+
+                if (njs_slow_path(njs_is_null_or_undefined(value2))) {
+                    (void) njs_throw_cannot_property(vm, value2, value1,
+                                                     "get");
+                    goto error;
+                }
+
+                ret = njs_value_to_string(vm, retval, value1);
+                if (njs_fast_path(ret == NJS_ERROR)) {
                     goto error;
                 }
 
+                ret = sizeof(njs_vmcode_3addr_t);
                 break;
 
             case NJS_VMCODE_PROTO_INIT:
index a88799d2a1b189d58d4d6acb73d8857fcdbe3f5b..4cc5e00136fa79d4f6d3eb8d656d6aa59ee7983a 100644 (file)
@@ -49,6 +49,7 @@ enum {
     NJS_VMCODE_THIS,
     NJS_VMCODE_ARGUMENTS,
     NJS_VMCODE_PROTO_INIT,
+    NJS_VMCODE_TO_PROPERTY_KEY,
     NJS_VMCODE_IMPORT,
 
     NJS_VMCODE_AWAIT,
index 2f9e1b3cc40d24540310c03ea7d6ebc53c5d33f1..1306f3d1a439ce37789427aa4ec0e83d5e1bf4fb 100644 (file)
@@ -3651,7 +3651,7 @@ static njs_unit_test_t  njs_test[] =
       njs_str("TypeError: cannot get property \"b\" of undefined") },
 
     { njs_str("var a = null; a.b++; a.b"),
-      njs_str("TypeError: cannot get property \"b\" of undefined") },
+      njs_str("TypeError: cannot get property \"b\" of null") },
 
     { njs_str("var a = true; a.b++; a.b"),
       njs_str("TypeError: property set on primitive boolean type") },
@@ -4423,6 +4423,9 @@ static njs_unit_test_t  njs_test[] =
     { njs_str("var o = null; o[{toString:()=>{throw 'OOps'}}] = 1"),
       njs_str("TypeError: cannot set property \"[object Object]\" of null") },
 
+    { njs_str("var o = null; o[{toString:()=>{throw 'OOps'}}] += 1"),
+      njs_str("TypeError: cannot get property \"[object Object]\" of null") },
+
     /**/
 
     { njs_str("Array.isArray()"),
@@ -12281,7 +12284,7 @@ static njs_unit_test_t  njs_test[] =
       njs_str("TypeError: Cyclic __proto__ value") },
 
     { njs_str("Object.prototype.__proto__.f()"),
-      njs_str("TypeError: cannot get property \"f\" of undefined") },
+      njs_str("TypeError: cannot get property \"f\" of null") },
 
     { njs_str("var obj = Object.create(null); obj.one = 1;"
                  "var res = [];"