details: https://hg.nginx.org/njs/rev/7d2d28095c42 branches: changeset: 907:7d2d28095c42 user: Alexander Borisov <alexander.bori...@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]") }, _______________________________________________ nginx-devel mailing list nginx-devel@nginx.org http://mailman.nginx.org/mailman/listinfo/nginx-devel