From: Alexander Borisov Date: Wed, 17 Apr 2019 15:00:56 +0000 (+0300) Subject: Walking over prototypes chain during iteration over an object. X-Git-Tag: 0.3.2~66 X-Git-Url: http://www.kaiwu.me/postgresql/commit/?a=commitdiff_plain;h=bfb52c89e11fe451ee73c2cd8d0809556df074f0;p=njs.git Walking over prototypes chain during iteration over an object. This closes #33 issue on Github. --- diff --git a/njs/njs_vm.c b/njs/njs_vm.c index a10ca42e..90e83f4a 100644 --- a/njs/njs_vm.c +++ b/njs/njs_vm.c @@ -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, njs_value_t *object, 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, njs_value_t *object, 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, njs_value_t *object, njs_value_t *value) { 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, njs_value_t *object, njs_value_t *value) 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, njs_value_t *object, njs_value_t *value) /* 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 --git a/njs/test/njs_unit_test.c b/njs/test/njs_unit_test.c index 03684749..abf06d7d 100644 --- a/njs/test/njs_unit_test.c +++ b/njs/test/njs_unit_test.c @@ -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]") },