From: Dmitry Volyntsev Date: Wed, 7 Jun 2017 14:57:40 +0000 (+0300) Subject: Object.defineProperty() method. X-Git-Tag: 0.1.11~23 X-Git-Url: http://www.kaiwu.me/postgresql/commit/?a=commitdiff_plain;h=cc2586a22651d903c83dd3dadf62cc1b61753440;p=njs.git Object.defineProperty() method. --- diff --git a/njs/njs_object.c b/njs/njs_object.c index 265bf88b..d2f1c382 100644 --- a/njs/njs_object.c +++ b/njs/njs_object.c @@ -412,6 +412,109 @@ njs_object_keys(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, } +static njs_ret_t +njs_object_define_property(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, + njs_index_t unused) +{ + nxt_int_t ret; + nxt_str_t key; + njs_value_t *name; + njs_object_t *object, *descriptor; + njs_object_prop_t *prop, *pr; + nxt_lvlhsh_query_t lhq, pq; + + if (nargs < 4 || !njs_is_object(&args[1]) || !njs_is_object(&args[3])) { + vm->exception = &njs_exception_type_error; + return NXT_ERROR; + } + + object = args[1].data.u.object; + name = &args[2]; + descriptor = args[3].data.u.object; + + if (name->short_string.size != NJS_STRING_LONG) { + key.start = name->short_string.start; + key.length = name->short_string.length; + + } else { + key.start = name->data.u.string->start; + key.length = name->data.string_size; + } + + lhq.key = key; + lhq.key_hash = nxt_djb_hash(key.start, key.length); + lhq.proto = &njs_object_hash_proto; + + ret = nxt_lvlhsh_find(&object->hash, &lhq); + + if (ret != NXT_OK) { + prop = njs_object_prop_alloc(vm, name); + + if (nxt_slow_path(prop == NULL)) { + return NXT_ERROR; + } + + prop->configurable = 0; + prop->enumerable = 0; + prop->writable = 0; + + lhq.value = prop; + + } else { + prop = lhq.value; + } + + pq.key = nxt_string_value("value"); + pq.key_hash = NJS_VALUE_HASH; + pq.proto = &njs_object_hash_proto; + + pr = njs_object_property(vm, descriptor, &pq); + + if (pr != NULL) { + prop->value = pr->value; + } + + pq.key = nxt_string_value("configurable"); + pq.key_hash = NJS_CONFIGURABLE_HASH; + + pr = njs_object_property(vm, descriptor, &pq); + + if (pr != NULL) { + prop->configurable = pr->value.data.truth; + } + + pq.key = nxt_string_value("enumerable"); + pq.key_hash = NJS_ENUMERABLE_HASH; + + pr = njs_object_property(vm, descriptor, &pq); + + if (pr != NULL) { + prop->enumerable = pr->value.data.truth; + } + + pq.key = nxt_string_value("writable"); + pq.key_hash = NJS_WRITABABLE_HASH; + + pr = njs_object_property(vm, descriptor, &pq); + + if (pr != NULL) { + prop->writable = pr->value.data.truth; + } + + lhq.replace = 0; + lhq.pool = vm->mem_cache_pool; + + ret = nxt_lvlhsh_insert(&object->hash, &lhq); + if (nxt_slow_path(ret != NXT_OK)) { + return NXT_ERROR; + } + + vm->retval = args[1]; + + return NXT_OK; +} + + /* * The __proto__ property of booleans, numbers and strings primitives, * of objects created by Boolean(), Number(), and String() constructors, @@ -558,6 +661,15 @@ static const njs_object_prop_t njs_object_constructor_properties[] = .value = njs_native_function(njs_object_keys, 0, NJS_SKIP_ARG, NJS_OBJECT_ARG), }, + + /* Object.defineProperty(). */ + { + .type = NJS_METHOD, + .name = njs_string("defineProperty"), + .value = njs_native_function(njs_object_define_property, 0, + NJS_SKIP_ARG, NJS_OBJECT_ARG, + NJS_STRING_ARG, NJS_OBJECT_ARG), + }, }; diff --git a/njs/njs_object_hash.h b/njs/njs_object_hash.h index 0f25e1d8..3a9edd01 100644 --- a/njs/njs_object_hash.h +++ b/njs/njs_object_hash.h @@ -8,6 +8,22 @@ #define _NJS_OBJECT_HASH_H_INCLUDED_ +#define NJS_CONFIGURABLE_HASH \ + nxt_djb_hash_add( \ + nxt_djb_hash_add( \ + nxt_djb_hash_add( \ + nxt_djb_hash_add( \ + nxt_djb_hash_add( \ + nxt_djb_hash_add( \ + nxt_djb_hash_add( \ + nxt_djb_hash_add( \ + nxt_djb_hash_add( \ + nxt_djb_hash_add( \ + nxt_djb_hash_add( \ + nxt_djb_hash_add(NXT_DJB_HASH_INIT, \ + 'c'), 'o'), 'n'), 'f'), 'i'), 'g'), 'u'), 'r'), 'a'), 'b'), 'l'), 'e') + + #define NJS_CONSTRUCTOR_HASH \ nxt_djb_hash_add( \ nxt_djb_hash_add( \ @@ -23,6 +39,20 @@ 'c'), 'o'), 'n'), 's'), 't'), 'r'), 'u'), 'c'), 't'), 'o'), 'r') +#define NJS_ENUMERABLE_HASH \ + nxt_djb_hash_add( \ + nxt_djb_hash_add( \ + nxt_djb_hash_add( \ + nxt_djb_hash_add( \ + nxt_djb_hash_add( \ + nxt_djb_hash_add( \ + nxt_djb_hash_add( \ + nxt_djb_hash_add( \ + nxt_djb_hash_add( \ + nxt_djb_hash_add(NXT_DJB_HASH_INIT, \ + 'e'), 'n'), 'u'), 'm'), 'e'), 'r'), 'a'), 'b'), 'l'), 'e') + + #define NJS_INDEX_HASH \ nxt_djb_hash_add( \ nxt_djb_hash_add( \ @@ -74,6 +104,15 @@ 't'), 'o'), 'S'), 't'), 'r'), 'i'), 'n'), 'g') +#define NJS_VALUE_HASH \ + nxt_djb_hash_add( \ + nxt_djb_hash_add( \ + nxt_djb_hash_add( \ + nxt_djb_hash_add( \ + nxt_djb_hash_add(NXT_DJB_HASH_INIT, \ + 'v'), 'a'), 'l'), 'u'), 'e') + + #define NJS_VALUE_OF_HASH \ nxt_djb_hash_add( \ nxt_djb_hash_add( \ @@ -100,4 +139,16 @@ 't'), 'o'), 'I'), 'S'), 'O'), 'S'), 't'), 'r'), 'i'), 'n'), 'g') +#define NJS_WRITABABLE_HASH \ + nxt_djb_hash_add( \ + nxt_djb_hash_add( \ + nxt_djb_hash_add( \ + nxt_djb_hash_add( \ + nxt_djb_hash_add( \ + nxt_djb_hash_add( \ + nxt_djb_hash_add( \ + nxt_djb_hash_add(NXT_DJB_HASH_INIT, \ + 'w'), 'r'), 'i'), 't'), 'a'), 'b'), 'l'), 'e') + + #endif /* _NJS_OBJECT_HASH_H_INCLUDED_ */ diff --git a/njs/njs_vm.c b/njs/njs_vm.c index 4d4746cd..5b3dcd5a 100644 --- a/njs/njs_vm.c +++ b/njs/njs_vm.c @@ -746,7 +746,9 @@ njs_vmcode_property_set(njs_vm_t *vm, njs_value_t *object, return ret; } - prop->value = *value; + if (prop->writable) { + prop->value = *value; + } return sizeof(njs_vmcode_prop_set_t); } diff --git a/njs/test/njs_unit_test.c b/njs/test/njs_unit_test.c index cd8288c6..97a82a9c 100644 --- a/njs/test/njs_unit_test.c +++ b/njs/test/njs_unit_test.c @@ -5874,6 +5874,64 @@ static njs_unit_test_t njs_test[] = { nxt_string("Object.keys(1)"), nxt_string("TypeError") }, + { nxt_string("var o = {}; Object.defineProperty(o, 'a', {}); o.a"), + nxt_string("undefined") }, + + { nxt_string("Object.defineProperty({}, 'a', {value:1})"), + nxt_string("[object Object]") }, + + { nxt_string("var o = {}; Object.defineProperty(o, 'a', {value:1}); o.a"), + nxt_string("1") }, + + { nxt_string("var o = {a:1, c:2}; Object.defineProperty(o, 'b', {});" + "Object.keys(o)"), + nxt_string("a,c") }, + + { nxt_string("var o = {a:1, c:2};" + "Object.defineProperty(o, 'b', {enumerable:false});" + "Object.keys(o)"), + nxt_string("a,c") }, + + { nxt_string("var o = {a:1, c:3};" + "Object.defineProperty(o, 'b', {enumerable:true});" + "Object.keys(o)"), + nxt_string("a,c,b") }, + + { nxt_string("var o = {}; Object.defineProperty(o, 'a', {}); o.a = 1; o.a"), + nxt_string("undefined") }, + + { nxt_string("var o = {}; Object.defineProperty(o, 'a', {writable:false});" + "o.a = 1; o.a"), + nxt_string("undefined") }, + + { nxt_string("var o = {}; Object.defineProperty(o, 'a', {writable:true});" + "o.a = 1; o.a"), + nxt_string("1") }, + + { nxt_string("var o = {};" + "Object.defineProperty(o, 'a', {value:1}); delete o.a; o.a"), + nxt_string("1") }, + + { nxt_string("var o = {};" + "Object.defineProperty(o, 'a', {value:1, configurable:true});" + "delete o.a; o.a"), + nxt_string("undefined") }, + + { nxt_string("var o = {};" + "Object.defineProperty(o, 'a', {value:1, configurable:false});" + "delete o.a; o.a"), + nxt_string("1") }, + + { nxt_string("var o = {};" + "Object.defineProperty(o, 'a', Object.create({value:2})); o.a"), + nxt_string("2") }, + + { nxt_string("var o = {}; Object.defineProperty()"), + nxt_string("TypeError") }, + + { nxt_string("var o = {}; Object.defineProperty(o)"), + nxt_string("TypeError") }, + { nxt_string("var d = new Date(''); d +' '+ d.getTime()"), nxt_string("Invalid Date NaN") },