[njs] Walking over prototypes chain during iteration over an object.
Alexander Borisov
alexander.borisov at nginx.com
Thu Apr 18 16:10:17 UTC 2019
details: https://hg.nginx.org/njs/rev/7d2d28095c42
branches:
changeset: 907:7d2d28095c42
user: Alexander Borisov <alexander.borisov at nginx.com>
date: Wed Apr 17 18:00:56 2019 +0300
description:
Walking over prototypes chain during iteration over an object.
This closes #33 issue on Github.
diffstat:
njs/njs_vm.c | 93 ++++++++++++++++++-----------------------------
njs/test/njs_unit_test.c | 56 ++++++++++++++++++++++++++++
2 files changed, 91 insertions(+), 58 deletions(-)
diffs (209 lines):
diff -r 519785f57b81 -r 7d2d28095c42 njs/njs_vm.c
--- a/njs/njs_vm.c Wed Apr 17 17:27:14 2019 +0300
+++ b/njs/njs_vm.c Wed Apr 17 18:00:56 2019 +0300
@@ -10,8 +10,8 @@
struct njs_property_next_s {
- int32_t index;
- nxt_lvlhsh_each_t lhe;
+ uint32_t index;
+ njs_array_t *array;
};
@@ -764,23 +764,7 @@ njs_vmcode_property_foreach(njs_vm_t *vm
const njs_extern_t *ext_proto;
njs_vmcode_prop_foreach_t *code;
- if (njs_is_object(object)) {
- next = nxt_mp_alloc(vm->mem_pool, sizeof(njs_property_next_t));
- if (nxt_slow_path(next == NULL)) {
- njs_memory_error(vm);
- return NXT_ERROR;
- }
-
- vm->retval.data.u.next = next;
-
- nxt_lvlhsh_each_init(&next->lhe, &njs_object_hash_proto);
- next->index = -1;
-
- if (njs_is_array(object) && object->data.u.array->length != 0) {
- next->index = 0;
- }
-
- } else if (njs_is_external(object)) {
+ if (njs_is_external(object)) {
ext_proto = object->external.proto;
if (ext_proto->foreach != NULL) {
@@ -791,8 +775,27 @@ njs_vmcode_property_foreach(njs_vm_t *vm
return ret;
}
}
+
+ goto done;
}
+ next = nxt_mp_alloc(vm->mem_pool, sizeof(njs_property_next_t));
+ if (nxt_slow_path(next == NULL)) {
+ njs_memory_error(vm);
+ return NXT_ERROR;
+ }
+
+ next->index = 0;
+ next->array = njs_value_enumerate(vm, object, NJS_ENUM_KEYS, 0);
+ if (nxt_slow_path(next->array == NULL)) {
+ njs_memory_error(vm);
+ return NXT_ERROR;
+ }
+
+ vm->retval.data.u.next = next;
+
+done:
+
code = (njs_vmcode_prop_foreach_t *) vm->current;
return code->offset;
@@ -804,10 +807,7 @@ njs_vmcode_property_next(njs_vm_t *vm, n
{
void *obj;
njs_ret_t ret;
- nxt_uint_t n;
njs_value_t *retval;
- njs_array_t *array;
- njs_object_prop_t *prop;
njs_property_next_t *next;
const njs_extern_t *ext_proto;
njs_vmcode_prop_next_t *code;
@@ -815,42 +815,7 @@ njs_vmcode_property_next(njs_vm_t *vm, n
code = (njs_vmcode_prop_next_t *) vm->current;
retval = njs_vmcode_operand(vm, code->retval);
- if (njs_is_object(object)) {
- next = value->data.u.next;
-
- if (next->index >= 0) {
- array = object->data.u.array;
-
- while ((uint32_t) next->index < array->length) {
- n = next->index++;
-
- if (njs_is_valid(&array->start[n])) {
- njs_uint32_to_string(retval, n);
-
- return code->offset;
- }
- }
-
- next->index = -1;
- }
-
- for ( ;; ) {
- prop = nxt_lvlhsh_each(&object->data.u.object->hash, &next->lhe);
-
- if (prop == NULL) {
- break;
- }
-
- if (prop->type != NJS_WHITEOUT && prop->enumerable) {
- *retval = prop->name;
-
- return code->offset;
- }
- }
-
- nxt_mp_free(vm->mem_pool, next);
-
- } else if (njs_is_external(object)) {
+ if (njs_is_external(object)) {
ext_proto = object->external.proto;
if (ext_proto->next != NULL) {
@@ -868,8 +833,20 @@ njs_vmcode_property_next(njs_vm_t *vm, n
/* ret == NJS_DONE. */
}
+
+ return sizeof(njs_vmcode_prop_next_t);
}
+ next = value->data.u.next;
+
+ if (next->index < next->array->length) {
+ *retval = next->array->data[ next->index++ ];
+
+ return code->offset;
+ }
+
+ nxt_mp_free(vm->mem_pool, next);
+
return sizeof(njs_vmcode_prop_next_t);
}
diff -r 519785f57b81 -r 7d2d28095c42 njs/test/njs_unit_test.c
--- a/njs/test/njs_unit_test.c Wed Apr 17 17:27:14 2019 +0300
+++ b/njs/test/njs_unit_test.c Wed Apr 17 18:00:56 2019 +0300
@@ -7819,6 +7819,62 @@ static njs_unit_test_t njs_test[] =
{ nxt_string("Object.prototype.__proto__.f()"),
nxt_string("TypeError: cannot get property \"f\" of undefined") },
+ { nxt_string("var obj = Object.create(null); obj.one = 1;"
+ "var res = [];"
+ "for (var val in obj) res.push(val); res"),
+ nxt_string("one") },
+
+ { nxt_string("var o1 = Object.create(null); o1.one = 1;"
+ "var o2 = Object.create(o1); o2.two = 2;"
+ "var o3 = Object.create(o2); o3.three = 3;"
+ "var res = [];"
+ "for (var val in o3) res.push(val); res"),
+ nxt_string("three,two,one") },
+
+ { nxt_string("var o1 = Object.create(null); o1.one = 1;"
+ "var o2 = Object.create(o1);"
+ "var o3 = Object.create(o2); o3.three = 3;"
+ "var res = [];"
+ "for (var val in o3) res.push(val); res"),
+ nxt_string("three,one") },
+
+ { nxt_string("var o1 = Object.create(null); o1.one = 1;"
+ "var o2 = Object.create(o1);"
+ "var o3 = Object.create(o2);"
+ "var res = [];"
+ "for (var val in o3) res.push(val); res"),
+ nxt_string("one") },
+
+ { nxt_string("var o1 = Object.create(null); o1.one = 1;"
+ "var o2 = Object.create(o1); o2.two = 2;"
+ "var o3 = Object.create(o2); o3.three = 3;"
+ "o3.two = -2; o3.one = -1;"
+ "var res = [];"
+ "for (var val in o3) res.push(val); res"),
+ nxt_string("three,two,one") },
+
+ { nxt_string("var a = []; for(var p in 'abc') a.push(p); a"),
+ nxt_string("0,1,2") },
+
+ { nxt_string("var a = []; for(var p in Object('abc')) a.push(p); a"),
+ nxt_string("0,1,2") },
+
+ { nxt_string("var o = Object('abc'); var x = Object.create(o);"
+ "x.a = 1; x.b = 2;"
+ "var a = []; for(var p in x) a.push(p); a"),
+ nxt_string("a,b,0,1,2") },
+
+#if 0
+ /* TODO: No properties implementation for array type
+ * (enumerable, writable, configurable).
+ */
+
+ { nxt_string("var o = Object("abc"); var x = Object.create(o);"
+ "x['sd'] = 44; x[1] = 8; x[55] = 8;"
+ "Object.keys(x)"),
+ nxt_string("55,sd") },
+#endif
+
{ nxt_string("Object.prototype.toString.call(Object.prototype)"),
nxt_string("[object Object]") },
More information about the nginx-devel
mailing list