details: http://hg.nginx.org/njs/rev/824fbb7fcd35 branches: changeset: 366:824fbb7fcd35 user: Dmitry Volyntsev <xei...@nginx.com> date: Mon Jun 19 14:39:56 2017 +0300 description: Object.freeze() method.
diffstat: njs/njs_array.c | 3 +- njs/njs_builtin.c | 2 + njs/njs_date.c | 1 + njs/njs_function.c | 2 + njs/njs_object.c | 58 +++++++++++++++++++++++++++++ njs/njs_regexp.c | 1 + njs/njs_vm.c | 5 ++ njs/njs_vm.h | 7 ++- njs/test/njs_unit_test.c | 93 ++++++++++++++++++++++++++++++++++++++++++++++++ 9 files changed, 169 insertions(+), 3 deletions(-) diffs (332 lines): diff -r 7ed74a2e4c50 -r 824fbb7fcd35 njs/njs_array.c --- a/njs/njs_array.c Wed Jun 14 17:58:10 2017 +0300 +++ b/njs/njs_array.c Mon Jun 19 14:39:56 2017 +0300 @@ -149,6 +149,7 @@ njs_array_alloc(njs_vm_t *vm, uint32_t l array->object.__proto__ = &vm->prototypes[NJS_PROTOTYPE_ARRAY].object; array->object.type = NJS_ARRAY; array->object.shared = 0; + array->object.extensible = 1; array->size = size; array->length = length; @@ -1941,7 +1942,7 @@ njs_array_string_sort(njs_vm_t *vm, njs_ static const njs_function_t njs_array_string_sort_function = { - .object.shared = 1, + .object = { .type = NJS_FUNCTION, .shared = 1, .extensible = 1 }, .native = 1, .continuation_size = NJS_CONTINUATION_SIZE, .args_types = { NJS_SKIP_ARG, NJS_STRING_ARG, NJS_STRING_ARG }, diff -r 7ed74a2e4c50 -r 824fbb7fcd35 njs/njs_builtin.c --- a/njs/njs_builtin.c Wed Jun 14 17:58:10 2017 +0300 +++ b/njs/njs_builtin.c Mon Jun 19 14:39:56 2017 +0300 @@ -206,6 +206,7 @@ njs_builtin_objects_create(njs_vm_t *vm) } functions[i].object.shared = 1; + functions[i].object.extensible = 1; functions[i].native = 1; functions[i].args_offset = 1; functions[i].u.native = native_functions[i].native; @@ -236,6 +237,7 @@ njs_builtin_objects_create(njs_vm_t *vm) for (i = NJS_CONSTRUCTOR_OBJECT; i < NJS_CONSTRUCTOR_MAX; i++) { constructors[i].object.shared = 0; + constructors[i].object.extensible = 1; constructors[i].native = 1; constructors[i].ctor = 1; constructors[i].args_offset = 1; diff -r 7ed74a2e4c50 -r 824fbb7fcd35 njs/njs_date.c --- a/njs/njs_date.c Wed Jun 14 17:58:10 2017 +0300 +++ b/njs/njs_date.c Mon Jun 19 14:39:56 2017 +0300 @@ -154,6 +154,7 @@ njs_date_constructor(njs_vm_t *vm, njs_v nxt_lvlhsh_init(&date->object.shared_hash); date->object.type = NJS_DATE; date->object.shared = 0; + date->object.extensible = 1; date->object.__proto__ = &vm->prototypes[NJS_PROTOTYPE_DATE].object; date->time = time; diff -r 7ed74a2e4c50 -r 824fbb7fcd35 njs/njs_function.c --- a/njs/njs_function.c Wed Jun 14 17:58:10 2017 +0300 +++ b/njs/njs_function.c Mon Jun 19 14:39:56 2017 +0300 @@ -44,6 +44,7 @@ njs_function_alloc(njs_vm_t *vm) function->object.shared_hash = vm->shared->function_prototype_hash; function->object.type = NJS_FUNCTION; function->object.shared = 1; + function->object.extensible = 1; function->args_offset = 1; function->u.lambda = nxt_mem_cache_zalloc(vm->mem_cache_pool, @@ -635,6 +636,7 @@ njs_function_prototype_bind(njs_vm_t *vm function->object.__proto__ = &vm->prototypes[NJS_PROTOTYPE_FUNCTION].object; function->object.shared = 0; + function->object.extensible = 1; if (nargs == 1) { args = (njs_value_t *) &njs_value_void; diff -r 7ed74a2e4c50 -r 824fbb7fcd35 njs/njs_object.c --- a/njs/njs_object.c Wed Jun 14 17:58:10 2017 +0300 +++ b/njs/njs_object.c Mon Jun 19 14:39:56 2017 +0300 @@ -43,6 +43,7 @@ njs_object_alloc(njs_vm_t *vm) object->__proto__ = &vm->prototypes[NJS_PROTOTYPE_OBJECT].object; object->type = NJS_OBJECT; object->shared = 0; + object->extensible = 1; } return object; @@ -86,6 +87,7 @@ njs_object_value_alloc(njs_vm_t *vm, con nxt_lvlhsh_init(&ov->object.shared_hash); ov->object.type = njs_object_value_type(type); ov->object.shared = 0; + ov->object.extensible = 1; index = njs_primitive_prototype_index(type); ov->object.__proto__ = &vm->prototypes[index].object; @@ -416,6 +418,11 @@ njs_object_define_property(njs_vm_t *vm, return NXT_ERROR; } + if (!args[1].data.u.object->extensible) { + vm->exception = &njs_exception_type_error; + return NXT_ERROR; + } + ret = njs_define_property(vm, args[1].data.u.object, &args[2], args[3].data.u.object); @@ -444,6 +451,11 @@ njs_object_define_properties(njs_vm_t *v return NXT_ERROR; } + if (!args[1].data.u.object->extensible) { + vm->exception = &njs_exception_type_error; + return NXT_ERROR; + } + nxt_lvlhsh_each_init(&lhe, &njs_object_hash_proto); object = args[1].data.u.object; @@ -704,6 +716,44 @@ njs_object_get_prototype_of(njs_vm_t *vm } +static njs_ret_t +njs_object_freeze(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, + njs_index_t unused) +{ + nxt_lvlhsh_t *hash; + njs_object_t *object; + njs_object_prop_t *prop; + nxt_lvlhsh_each_t lhe; + + if (nargs < 2 || !njs_is_object(&args[1])) { + vm->exception = &njs_exception_type_error; + return NXT_ERROR; + } + + object = args[1].data.u.object; + object->extensible = 0; + + nxt_lvlhsh_each_init(&lhe, &njs_object_hash_proto); + + hash = &object->hash; + + for ( ;; ) { + prop = nxt_lvlhsh_each(hash, &lhe); + + if (prop == NULL) { + break; + } + + prop->writable = 0; + prop->configurable = 0; + } + + 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, @@ -881,6 +931,14 @@ static const njs_object_prop_t njs_obje .value = njs_native_function(njs_object_get_prototype_of, 0, NJS_SKIP_ARG, NJS_OBJECT_ARG), }, + + /* Object.freeze(). */ + { + .type = NJS_METHOD, + .name = njs_string("freeze"), + .value = njs_native_function(njs_object_freeze, 0, + NJS_SKIP_ARG, NJS_OBJECT_ARG), + }, }; diff -r 7ed74a2e4c50 -r 824fbb7fcd35 njs/njs_regexp.c --- a/njs/njs_regexp.c Wed Jun 14 17:58:10 2017 +0300 +++ b/njs/njs_regexp.c Mon Jun 19 14:39:56 2017 +0300 @@ -469,6 +469,7 @@ njs_regexp_alloc(njs_vm_t *vm, njs_regex regexp->object.__proto__ = &vm->prototypes[NJS_PROTOTYPE_REGEXP].object; regexp->object.type = NJS_REGEXP; regexp->object.shared = 0; + regexp->object.extensible = 1; regexp->last_index = 0; regexp->pattern = pattern; } diff -r 7ed74a2e4c50 -r 824fbb7fcd35 njs/njs_vm.c --- a/njs/njs_vm.c Wed Jun 14 17:58:10 2017 +0300 +++ b/njs/njs_vm.c Mon Jun 19 14:39:56 2017 +0300 @@ -425,6 +425,7 @@ njs_vmcode_function(njs_vm_t *vm, njs_va function->u.lambda = lambda; function->object.shared_hash = vm->shared->function_prototype_hash; function->object.__proto__ = &vm->prototypes[NJS_PROTOTYPE_FUNCTION].object; + function->object.extensible = 1; function->args_offset = 1; if (nesting != 0) { @@ -683,6 +684,10 @@ njs_vmcode_property_set(njs_vm_t *vm, nj break; case NXT_DECLINED: + if (!object->data.u.object->extensible) { + return sizeof(njs_vmcode_prop_set_t); + } + prop = njs_object_prop_alloc(vm, &pq.value, &njs_value_void, 1); if (nxt_slow_path(prop == NULL)) { return NXT_ERROR; diff -r 7ed74a2e4c50 -r 824fbb7fcd35 njs/njs_vm.h --- a/njs/njs_vm.h Wed Jun 14 17:58:10 2017 +0300 +++ b/njs/njs_vm.h Mon Jun 19 14:39:56 2017 +0300 @@ -208,7 +208,8 @@ struct njs_object_s { /* The type is used in constructor prototypes. */ njs_value_type_t type:8; - uint8_t shared; /* 1 bit */ + uint8_t shared; /* 1 bit */ + uint8_t extensible; /* 1 bit */ }; @@ -339,7 +340,9 @@ typedef union { .args_types = { __VA_ARGS__ }, \ .args_offset = 1, \ .u.native = _function, \ - .object = { .type = NJS_FUNCTION, .shared = 1 }, \ + .object = { .type = NJS_FUNCTION, \ + .shared = 1, \ + .extensible = 1 }, \ } \ } \ } diff -r 7ed74a2e4c50 -r 824fbb7fcd35 njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Wed Jun 14 17:58:10 2017 +0300 +++ b/njs/test/njs_unit_test.c Mon Jun 19 14:39:56 2017 +0300 @@ -6071,6 +6071,99 @@ static njs_unit_test_t njs_test[] = { nxt_string("Object.getOwnPropertyDescriptor(1, '0')"), nxt_string("TypeError") }, + { nxt_string("Object.defineProperty(Object.freeze({}), 'b', {})"), + nxt_string("TypeError") }, + + { nxt_string("Object.defineProperties(Object.freeze({}), {b:{}})"), + nxt_string("TypeError") }, + + { nxt_string("var o = Object.freeze({a:1}); o.a = 2; o.a"), + nxt_string("1") }, + + { nxt_string("var o = Object.freeze({a:1}); delete o.a; o.a"), + nxt_string("1") }, + + { nxt_string("var o = Object.freeze({a:1}); o.b = 1; o.b"), + nxt_string("undefined") }, + + { nxt_string("var o = Object.freeze(Object.create({a:1})); o.a = 2; o.a"), + nxt_string("1") }, + + { nxt_string("var o = Object.freeze({a:{b:1}}); o.a.b = 2; o.a.b"), + nxt_string("2") }, + + { nxt_string("Object.defineProperty([1,2], 'a', {value:1}).a"), + nxt_string("1") }, + + { nxt_string("var a = Object.freeze([1,2]);" + "Object.defineProperty(a, 'a', {value:1}).a"), + nxt_string("TypeError") }, + + { nxt_string("var a = [1,2]; a.a = 1; Object.freeze(a);" + "delete a.a; a.a"), + nxt_string("1") }, + + { nxt_string("var a = [1,2]; a.a = 1; Object.freeze(a);" + "a.a = 2; a.a"), + nxt_string("1") }, + + { nxt_string("var a = Object.freeze([1,2]); a.a = 1; a.a"), + nxt_string("undefined") }, + + { nxt_string("Object.defineProperty(function() {}, 'a', {value:1}).a"), + nxt_string("1") }, + + { nxt_string("var f = Object.freeze(function() {});" + "Object.defineProperty(f, 'a', {value:1}).a"), + nxt_string("TypeError") }, + + { nxt_string("var f = function() {}; f.a = 1; Object.freeze(f);" + "delete f.a; f.a"), + nxt_string("1") }, + + { nxt_string("var f = function() {}; f.a = 1; Object.freeze(f);" + "f.a = 2; f.a"), + nxt_string("1") }, + + { nxt_string("var f = Object.freeze(function() {}); f.a = 1; f.a"), + nxt_string("undefined") }, + + { nxt_string("Object.defineProperty(new Date(''), 'a', {value:1}).a"), + nxt_string("1") }, + + { nxt_string("var d = Object.freeze(new Date(''));" + "Object.defineProperty(d, 'a', {value:1}).a"), + nxt_string("TypeError") }, + + { nxt_string("var d = new Date(''); d.a = 1; Object.freeze(d);" + "delete d.a; d.a"), + nxt_string("1") }, + + { nxt_string("var d = new Date(''); d.a = 1; Object.freeze(d);" + "d.a = 2; d.a"), + nxt_string("1") }, + + { nxt_string("var d = Object.freeze(new Date('')); d.a = 1; d.a"), + nxt_string("undefined") }, + + { nxt_string("Object.defineProperty(new RegExp(''), 'a', {value:1}).a"), + nxt_string("1") }, + + { nxt_string("var r = Object.freeze(new RegExp(''));" + "Object.defineProperty(r, 'a', {value:1}).a"), + nxt_string("TypeError") }, + + { nxt_string("var r = new RegExp(''); r.a = 1; Object.freeze(r);" + "delete r.a; r.a"), + nxt_string("1") }, + + { nxt_string("var r = new RegExp(''); r.a = 1; Object.freeze(r);" + "r.a = 2; r.a"), + nxt_string("1") }, + + { nxt_string("var r = Object.freeze(new RegExp('')); r.a = 1; r.a"), + nxt_string("undefined") }, + { nxt_string("var d = new Date(''); d +' '+ d.getTime()"), nxt_string("Invalid Date NaN") }, _______________________________________________ nginx-devel mailing list nginx-devel@nginx.org http://mailman.nginx.org/mailman/listinfo/nginx-devel