[njs] Object.freeze() method.
Dmitry Volyntsev
xeioex at nginx.com
Mon Jun 19 11:49:29 UTC 2017
details: http://hg.nginx.org/njs/rev/824fbb7fcd35
branches:
changeset: 366:824fbb7fcd35
user: Dmitry Volyntsev <xeioex at 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") },
More information about the nginx-devel
mailing list