[njs] Fixed setting of object properties.
Valentin Bartenev
vbart at nginx.com
Thu May 23 12:54:47 UTC 2019
details: https://hg.nginx.org/njs/rev/ff591ba3e780
branches:
changeset: 979:ff591ba3e780
user: Valentin Bartenev <vbart at nginx.com>
date: Thu May 23 15:05:50 2019 +0300
description:
Fixed setting of object properties.
Now writability of prototype properties is properly taken into account.
diffstat:
njs/njs_disassembler.c | 2 +
njs/njs_generator.c | 12 +-
njs/njs_lexer.h | 1 +
njs/njs_object.c | 48 ++-------
njs/njs_object.h | 2 +
njs/njs_parser_terminal.c | 2 +-
njs/njs_vm.c | 240 +++++++++++++++++++++++++++++++++++----------
njs/njs_vm.h | 2 +
njs/test/njs_unit_test.c | 70 +++++++++++--
9 files changed, 269 insertions(+), 110 deletions(-)
diffs (697 lines):
diff -r 88c5787352b2 -r ff591ba3e780 njs/njs_disassembler.c
--- a/njs/njs_disassembler.c Wed May 22 21:01:39 2019 +0300
+++ b/njs/njs_disassembler.c Thu May 23 15:05:50 2019 +0300
@@ -36,6 +36,8 @@ static njs_code_name_t code_names[] = {
{ njs_vmcode_property_get, sizeof(njs_vmcode_prop_get_t),
nxt_string("PROPERTY GET ") },
+ { njs_vmcode_property_init, sizeof(njs_vmcode_prop_set_t),
+ nxt_string("PROPERTY INIT ") },
{ njs_vmcode_property_set, sizeof(njs_vmcode_prop_set_t),
nxt_string("PROPERTY SET ") },
{ njs_vmcode_property_in, sizeof(njs_vmcode_3addr_t),
diff -r 88c5787352b2 -r ff591ba3e780 njs/njs_generator.c
--- a/njs/njs_generator.c Wed May 22 21:01:39 2019 +0300
+++ b/njs/njs_generator.c Thu May 23 15:05:50 2019 +0300
@@ -1682,7 +1682,7 @@ njs_generate_assignment(njs_vm_t *vm, nj
return NXT_OK;
}
- /* lvalue->token == NJS_TOKEN_PROPERTY */
+ /* lvalue->token == NJS_TOKEN_PROPERTY(_INIT) */
/* Object. */
@@ -1735,8 +1735,14 @@ njs_generate_assignment(njs_vm_t *vm, nj
return ret;
}
- njs_generate_code(generator, njs_vmcode_prop_set_t, prop_set,
- njs_vmcode_property_set, 3, 0);
+ if (lvalue->token == NJS_TOKEN_PROPERTY_INIT) {
+ njs_generate_code(generator, njs_vmcode_prop_set_t, prop_set,
+ njs_vmcode_property_init, 3, 0);
+ } else {
+ njs_generate_code(generator, njs_vmcode_prop_set_t, prop_set,
+ njs_vmcode_property_set, 3, 0);
+ }
+
prop_set->value = expr->index;
prop_set->object = object->index;
prop_set->property = property->index;
diff -r 88c5787352b2 -r ff591ba3e780 njs/njs_lexer.h
--- a/njs/njs_lexer.h Wed May 22 21:01:39 2019 +0300
+++ b/njs/njs_lexer.h Thu May 23 15:05:50 2019 +0300
@@ -123,6 +123,7 @@ typedef enum {
NJS_TOKEN_OBJECT,
NJS_TOKEN_OBJECT_VALUE,
NJS_TOKEN_PROPERTY,
+ NJS_TOKEN_PROPERTY_INIT,
NJS_TOKEN_PROPERTY_DELETE,
NJS_TOKEN_ARRAY,
diff -r 88c5787352b2 -r ff591ba3e780 njs/njs_object.c
--- a/njs/njs_object.c Wed May 22 21:01:39 2019 +0300
+++ b/njs/njs_object.c Thu May 23 15:05:50 2019 +0300
@@ -22,8 +22,6 @@ static njs_ret_t njs_external_property_s
njs_value_t *setval, njs_value_t *retval);
static njs_ret_t njs_external_property_delete(njs_vm_t *vm, njs_value_t *value,
njs_value_t *setval, njs_value_t *retval);
-static njs_ret_t njs_object_query_prop_handler(njs_property_query_t *pq,
- njs_object_t *object);
static njs_ret_t njs_define_property(njs_vm_t *vm, njs_value_t *object,
const njs_value_t *name, const njs_object_t *descriptor);
@@ -379,6 +377,7 @@ njs_property_query(njs_vm_t *vm, njs_pro
pq->lhq.key_hash = hash(pq->lhq.key.start, pq->lhq.key.length);
if (obj == NULL) {
+ pq->own = 1;
return njs_external_property_query(vm, pq, object);
}
@@ -395,6 +394,7 @@ njs_object_property_query(njs_vm_t *vm,
{
uint32_t index;
njs_ret_t ret;
+ nxt_bool_t own;
njs_array_t *array;
njs_object_t *proto;
njs_object_prop_t *prop;
@@ -402,12 +402,8 @@ njs_object_property_query(njs_vm_t *vm,
pq->lhq.proto = &njs_object_hash_proto;
- if (pq->query == NJS_PROPERTY_QUERY_SET) {
- ret = njs_object_query_prop_handler(pq, object);
- if (ret == NXT_OK) {
- return ret;
- }
- }
+ own = pq->own;
+ pq->own = 1;
proto = object;
@@ -450,6 +446,10 @@ njs_object_property_query(njs_vm_t *vm,
return ret;
}
+ if (pq->own) {
+ pq->own_whiteout = prop;
+ }
+
} else {
ret = nxt_lvlhsh_find(&proto->shared_hash, &pq->lhq);
@@ -460,10 +460,11 @@ njs_object_property_query(njs_vm_t *vm,
}
}
- if (pq->own || pq->query > NJS_PROPERTY_QUERY_GET) {
+ if (own) {
return NXT_DECLINED;
}
+ pq->own = 0;
proto = proto->__proto__;
} while (proto != NULL);
@@ -706,33 +707,6 @@ njs_external_property_delete(njs_vm_t *v
}
-static njs_ret_t
-njs_object_query_prop_handler(njs_property_query_t *pq, njs_object_t *object)
-{
- njs_ret_t ret;
- njs_object_prop_t *prop;
-
- do {
- pq->prototype = object;
-
- ret = nxt_lvlhsh_find(&object->shared_hash, &pq->lhq);
-
- if (ret == NXT_OK) {
- prop = pq->lhq.value;
-
- if (prop->type == NJS_PROPERTY_HANDLER) {
- return NXT_OK;
- }
- }
-
- object = object->__proto__;
-
- } while (object != NULL);
-
- return NXT_DECLINED;
-}
-
-
njs_ret_t
njs_method_private_copy(njs_vm_t *vm, njs_property_query_t *pq)
{
@@ -1862,7 +1836,7 @@ njs_define_property(njs_vm_t *vm, njs_va
pq.lhq.key_hash = nxt_djb_hash(pq.lhq.key.start, pq.lhq.key.length);
pq.lhq.proto = &njs_object_hash_proto;
- njs_property_query_init(&pq, NJS_PROPERTY_QUERY_SET, 0);
+ njs_property_query_init(&pq, NJS_PROPERTY_QUERY_SET, 1);
ret = njs_property_query(vm, &pq, object, name);
diff -r 88c5787352b2 -r ff591ba3e780 njs/njs_object.h
--- a/njs/njs_object.h Wed May 22 21:01:39 2019 +0300
+++ b/njs/njs_object.h Thu May 23 15:05:50 2019 +0300
@@ -53,6 +53,7 @@ typedef struct {
njs_value_t value;
njs_object_t *prototype;
+ njs_object_prop_t *own_whiteout;
uint8_t query;
uint8_t shared;
uint8_t own;
@@ -63,6 +64,7 @@ typedef struct {
do { \
(pq)->lhq.key.length = 0; \
(pq)->lhq.value = NULL; \
+ (pq)->own_whiteout = NULL; \
(pq)->query = _query; \
(pq)->shared = 0; \
(pq)->own = _own; \
diff -r 88c5787352b2 -r ff591ba3e780 njs/njs_parser_terminal.c
--- a/njs/njs_parser_terminal.c Wed May 22 21:01:39 2019 +0300
+++ b/njs/njs_parser_terminal.c Thu May 23 15:05:50 2019 +0300
@@ -599,7 +599,7 @@ njs_parser_object_property(njs_vm_t *vm,
object->u.object = parent;
- propref = njs_parser_node_new(vm, parser, NJS_TOKEN_PROPERTY);
+ propref = njs_parser_node_new(vm, parser, NJS_TOKEN_PROPERTY_INIT);
if (nxt_slow_path(propref == NULL)) {
return NXT_ERROR;
}
diff -r 88c5787352b2 -r ff591ba3e780 njs/njs_vm.c
--- a/njs/njs_vm.c Wed May 22 21:01:39 2019 +0300
+++ b/njs/njs_vm.c Thu May 23 15:05:50 2019 +0300
@@ -545,12 +545,122 @@ njs_vmcode_property_get(njs_vm_t *vm, nj
njs_ret_t
+njs_vmcode_property_init(njs_vm_t *vm, njs_value_t *object,
+ njs_value_t *property)
+{
+ uint32_t index, size;
+ njs_ret_t ret;
+ njs_array_t *array;
+ njs_value_t *init, *value, name;
+ njs_object_t *obj;
+ njs_object_prop_t *prop;
+ nxt_lvlhsh_query_t lhq;
+ njs_vmcode_prop_set_t *code;
+
+ code = (njs_vmcode_prop_set_t *) vm->current;
+ init = njs_vmcode_operand(vm, code->value);
+
+ switch (object->type) {
+ case NJS_ARRAY:
+ index = njs_value_to_index(property);
+ if (nxt_slow_path(index == NJS_ARRAY_INVALID_INDEX)) {
+ njs_internal_error(vm,
+ "invalid index while property initialization");
+ return NXT_ERROR;
+ }
+
+ array = object->data.u.array;
+
+ if (index >= array->length) {
+ size = index - array->length;
+
+ ret = njs_array_expand(vm, array, 0, size + 1);
+ if (nxt_slow_path(ret != NXT_OK)) {
+ return ret;
+ }
+
+ value = &array->start[array->length];
+
+ while (size != 0) {
+ njs_set_invalid(value);
+ value++;
+ size--;
+ }
+
+ array->length = index + 1;
+ }
+
+ /* GC: retain. */
+ array->start[index] = *init;
+
+ break;
+
+ case NJS_OBJECT:
+ ret = njs_primitive_value_to_string(vm, &name, property);
+ if (nxt_slow_path(ret != NXT_OK)) {
+ njs_internal_error(vm, "failed conversion of type \"%s\" "
+ "to string while property initialization",
+ njs_type_string(property->type));
+ return NXT_ERROR;
+ }
+
+ njs_string_get(&name, &lhq.key);
+ lhq.key_hash = nxt_djb_hash(lhq.key.start, lhq.key.length);
+ lhq.proto = &njs_object_hash_proto;
+ lhq.pool = vm->mem_pool;
+
+ obj = object->data.u.object;
+
+ ret = nxt_lvlhsh_find(&obj->__proto__->shared_hash, &lhq);
+ if (ret == NXT_OK) {
+ prop = lhq.value;
+
+ if (prop->type == NJS_PROPERTY_HANDLER) {
+ ret = prop->value.data.u.prop_handler(vm, object, init,
+ &vm->retval);
+ if (nxt_slow_path(ret != NXT_OK)) {
+ return ret;
+ }
+
+ break;
+ }
+ }
+
+ prop = njs_object_prop_alloc(vm, &name, init, 1);
+ if (nxt_slow_path(prop == NULL)) {
+ return NXT_ERROR;
+ }
+
+ lhq.value = prop;
+ lhq.replace = 1;
+
+ ret = nxt_lvlhsh_insert(&obj->hash, &lhq);
+ if (nxt_slow_path(ret != NXT_OK)) {
+ njs_internal_error(vm, "lvlhsh insert/replace failed");
+ return NXT_ERROR;
+ }
+
+ break;
+
+ default:
+ njs_internal_error(vm, "unexpected object type \"%s\" "
+ "while property initialization",
+ njs_type_string(object->type));
+
+ return NXT_ERROR;
+ }
+
+ return sizeof(njs_vmcode_prop_set_t);
+}
+
+
+njs_ret_t
njs_vmcode_property_set(njs_vm_t *vm, njs_value_t *object,
njs_value_t *property)
{
njs_ret_t ret;
njs_value_t *value;
- njs_object_prop_t *prop;
+ njs_object_prop_t *prop, *shared;
njs_property_query_t pq;
njs_vmcode_prop_set_t *code;
@@ -563,6 +673,8 @@ njs_vmcode_property_set(njs_vm_t *vm, nj
code = (njs_vmcode_prop_set_t *) vm->current;
value = njs_vmcode_operand(vm, code->value);
+ shared = NULL;
+
njs_property_query_init(&pq, NJS_PROPERTY_QUERY_SET, 0);
ret = njs_property_query(vm, &pq, object, property);
@@ -572,70 +684,62 @@ njs_vmcode_property_set(njs_vm_t *vm, nj
case NXT_OK:
prop = pq.lhq.value;
- switch (prop->type) {
- case NJS_PROPERTY:
- break;
-
- case NJS_PROPERTY_REF:
- *prop->value.data.u.value = *value;
+ if (nxt_slow_path(!prop->writable)) {
+ njs_type_error(vm,
+ "Cannot assign to read-only property \"%V\" of %s",
+ &pq.lhq.key, njs_type_string(object->type));
+ return NXT_ERROR;
+ }
+
+ if (prop->type == NJS_PROPERTY_HANDLER) {
+ ret = prop->value.data.u.prop_handler(vm, object, value,
+ &vm->retval);
+ if (nxt_slow_path(ret != NXT_OK)) {
+ return ret;
+ }
+
return sizeof(njs_vmcode_prop_set_t);
-
- case NJS_PROPERTY_HANDLER:
- if (prop->writable) {
- ret = prop->value.data.u.prop_handler(vm, object, value,
- &vm->retval);
- if (nxt_slow_path(ret != NXT_OK)) {
- return ret;
+ }
+
+ if (pq.own) {
+ switch (prop->type) {
+ case NJS_PROPERTY:
+ case NJS_METHOD:
+ if (nxt_slow_path(pq.shared)) {
+ shared = prop;
+ break;
}
+ goto found;
+
+ case NJS_PROPERTY_REF:
+ *prop->value.data.u.value = *value;
return sizeof(njs_vmcode_prop_set_t);
+
+ default:
+ njs_internal_error(vm, "unexpected property type \"%s\" "
+ "while setting",
+ njs_prop_type_string(prop->type));
+
+ return NXT_ERROR;
}
break;
-
- default:
- njs_internal_error(vm, "unexpected property type \"%s\" "
- "while setting",
- njs_prop_type_string(prop->type));
-
- return NXT_ERROR;
}
- break;
+ /* Fall through. */
case NXT_DECLINED:
- if (nxt_slow_path(!object->data.u.object->extensible)) {
- njs_type_error(vm, "Cannot add property \"%V\", "
- "object is not extensible", &pq.lhq.key);
- return NXT_ERROR;
- }
-
- if (nxt_slow_path(pq.lhq.value != NULL)) {
- prop = pq.lhq.value;
-
- if (nxt_slow_path(prop->type == NJS_WHITEOUT)) {
- /* Previously deleted property. */
- prop->type = NJS_PROPERTY;
- prop->enumerable = 1;
- prop->configurable = 1;
- prop->writable = 1;
- break;
- }
- }
-
- prop = njs_object_prop_alloc(vm, &pq.value, &njs_value_undefined, 1);
- if (nxt_slow_path(prop == NULL)) {
- return NXT_ERROR;
- }
-
- pq.lhq.replace = 0;
- pq.lhq.value = prop;
- pq.lhq.pool = vm->mem_pool;
-
- ret = nxt_lvlhsh_insert(&object->data.u.object->hash, &pq.lhq);
- if (nxt_slow_path(ret != NXT_OK)) {
- njs_internal_error(vm, "lvlhsh insert failed");
- return NXT_ERROR;
+ if (nxt_slow_path(pq.own_whiteout != NULL)) {
+ /* Previously deleted property. */
+ prop = pq.own_whiteout;
+
+ prop->type = NJS_PROPERTY;
+ prop->enumerable = 1;
+ prop->configurable = 1;
+ prop->writable = 1;
+
+ goto found;
}
break;
@@ -647,12 +751,34 @@ njs_vmcode_property_set(njs_vm_t *vm, nj
return ret;
}
- if (nxt_slow_path(!prop->writable)) {
- njs_type_error(vm, "Cannot assign to read-only property \"%V\" of %s",
- &pq.lhq.key, njs_type_string(object->type));
+ if (nxt_slow_path(!object->data.u.object->extensible)) {
+ njs_type_error(vm, "Cannot add property \"%V\", "
+ "object is not extensible", &pq.lhq.key);
+ return NXT_ERROR;
+ }
+
+ prop = njs_object_prop_alloc(vm, &pq.value, &njs_value_undefined, 1);
+ if (nxt_slow_path(prop == NULL)) {
return NXT_ERROR;
}
+ if (nxt_slow_path(shared != NULL)) {
+ prop->enumerable = shared->enumerable;
+ prop->configurable = shared->configurable;
+ }
+
+ pq.lhq.replace = 0;
+ pq.lhq.value = prop;
+ pq.lhq.pool = vm->mem_pool;
+
+ ret = nxt_lvlhsh_insert(&object->data.u.object->hash, &pq.lhq);
+ if (nxt_slow_path(ret != NXT_OK)) {
+ njs_internal_error(vm, "lvlhsh insert failed");
+ return NXT_ERROR;
+ }
+
+found:
+
prop->value = *value;
return sizeof(njs_vmcode_prop_set_t);
diff -r 88c5787352b2 -r ff591ba3e780 njs/njs_vm.h
--- a/njs/njs_vm.h Wed May 22 21:01:39 2019 +0300
+++ b/njs/njs_vm.h Thu May 23 15:05:50 2019 +0300
@@ -1194,6 +1194,8 @@ njs_ret_t njs_vmcode_object_copy(njs_vm_
njs_ret_t njs_vmcode_property_get(njs_vm_t *vm, njs_value_t *object,
njs_value_t *property);
+njs_ret_t njs_vmcode_property_init(njs_vm_t *vm, njs_value_t *object,
+ njs_value_t *property);
njs_ret_t njs_vmcode_property_set(njs_vm_t *vm, njs_value_t *object,
njs_value_t *property);
njs_ret_t njs_vmcode_property_in(njs_vm_t *vm, njs_value_t *property,
diff -r 88c5787352b2 -r ff591ba3e780 njs/test/njs_unit_test.c
--- a/njs/test/njs_unit_test.c Wed May 22 21:01:39 2019 +0300
+++ b/njs/test/njs_unit_test.c Thu May 23 15:05:50 2019 +0300
@@ -3408,6 +3408,10 @@ static njs_unit_test_t njs_test[] =
{ nxt_string("Object.create(['α','β'])[false]"),
nxt_string("undefined") },
+ { nxt_string("var a = ['abc']; var o = Object.create(a); o[0] = 32;"
+ "[a,o[0]]"),
+ nxt_string("abc,32") },
+
/* Array.length setter */
{ nxt_string("[].length = {}"),
@@ -3481,6 +3485,7 @@ static njs_unit_test_t njs_test[] =
{ nxt_string("var a = []; a.concat([])"),
nxt_string("") },
+#if 0 /* Most built-in methods and properties must be writable. */
{ nxt_string("var s = { toString: function() { return 'S' } };"
"var v = { toString: 8, valueOf: function() { return 'V' } };"
"var o = [9]; o.join = function() { return 'O' };"
@@ -3495,7 +3500,6 @@ static njs_unit_test_t njs_test[] =
/* Array.toString(). */
-# if 0
{ nxt_string("var a = [1,2,3]; a.join = 'NO';"
"Object.prototype.toString = function () { return 'A' }; a"),
nxt_string("[object Array]") },
@@ -6162,9 +6166,11 @@ static njs_unit_test_t njs_test[] =
"(function(){(function(){(function(){})})})})})})})"),
nxt_string("SyntaxError: The maximum function nesting level is \"5\" in 1") },
+#if 0 /* Most built-in methods and properties must be writable. */
{ nxt_string("Function.prototype.toString = function () {return 'X'};"
"eval"),
nxt_string("X") },
+#endif
{ nxt_string("var o = {f:function(x){ return x**2}}; o.f\n(2)"),
nxt_string("4") },
@@ -7128,6 +7134,9 @@ static njs_unit_test_t njs_test[] =
{ nxt_string("var f = (a,b) => 0; f.length"),
nxt_string("2") },
+ { nxt_string("var o = Object.create(f => 1); o.length = 3"),
+ nxt_string("TypeError: Cannot assign to read-only property \"length\" of object") },
+
/* Scopes. */
{ nxt_string("function f(x) { a = x } var a; f(5); a"),
@@ -7420,6 +7429,7 @@ static njs_unit_test_t njs_test[] =
{ nxt_string("Error('e')"),
nxt_string("Error: e") },
+#if 0 /* Most built-in methods and properties must be writable. */
{ nxt_string("var e = Error('e'); e.name = 'E'; e"),
nxt_string("E: e") },
@@ -7431,6 +7441,7 @@ static njs_unit_test_t njs_test[] =
{ nxt_string("var e = Error(); e.name = ''; e.message = 'e'; e"),
nxt_string("e") },
+#endif
{ nxt_string("Error('e').name + ': ' + Error('e').message"),
nxt_string("Error: e") },
@@ -7504,6 +7515,7 @@ static njs_unit_test_t njs_test[] =
{ nxt_string("URIError('e').name + ': ' + URIError('e').message"),
nxt_string("URIError: e") },
+#if 0 /* Most built-in methods and properties must be writable. */
{ nxt_string("var e = EvalError('e'); e.name = 'E'; e"),
nxt_string("E: e") },
@@ -7529,6 +7541,7 @@ static njs_unit_test_t njs_test[] =
{ nxt_string("var e = MemoryError('e'); e.name = 'E'"),
nxt_string("TypeError: Cannot add property \"name\", object is not extensible") },
+#endif
{ nxt_string("EvalError.prototype.name"),
nxt_string("EvalError") },
@@ -8279,17 +8292,6 @@ static njs_unit_test_t njs_test[] =
"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]") },
@@ -8405,11 +8407,21 @@ static njs_unit_test_t njs_test[] =
{ nxt_string("Array.prototype.length"),
nxt_string("0") },
+ { nxt_string("Array.prototype.length = 3, Array.prototype"),
+ nxt_string(",,") },
+
+ { nxt_string("var o = Object.create(Array.prototype);"
+ "Object.defineProperty(o, 'length', {value: 3});"
+ "[Array.prototype, Array.prototype.length, o.length]"),
+ nxt_string(",0,3") },
+
{ nxt_string("Array.constructor === Function"),
nxt_string("true") },
+#if 0 /* Most built-in methods and properties must be writable. */
{ nxt_string("var a = []; a.join = 'OK'; a"),
nxt_string("[object Array]") },
+#endif
{ nxt_string("[].__proto__ === Array.prototype"),
nxt_string("true") },
@@ -8751,6 +8763,9 @@ static njs_unit_test_t njs_test[] =
{ nxt_string("var s = new String('αβ'); s[1] = 'b'"),
nxt_string("TypeError: Cannot assign to read-only property \"1\" of object string") },
+ { nxt_string("var o = Object.create(new String('αβ')); o[1] = 'a'"),
+ nxt_string("TypeError: Cannot assign to read-only property \"1\" of object") },
+
{ nxt_string("var s = new String('αβ'); s[4] = 'ab'; s[4]"),
nxt_string("ab") },
@@ -8828,6 +8843,9 @@ static njs_unit_test_t njs_test[] =
{ nxt_string("'test'.constructor.prototype === String.prototype"),
nxt_string("true") },
+ { nxt_string("var o = Object.create(String.prototype); o.length = 1"),
+ nxt_string("TypeError: Cannot assign to read-only property \"length\" of object") },
+
{ nxt_string("Function.name"),
nxt_string("Function") },
@@ -9127,6 +9145,30 @@ static njs_unit_test_t njs_test[] =
"o.a = 1; o.a"),
nxt_string("1") },
+ { nxt_string("Object.defineProperty(Object.prototype, 'a', {writable:false});"
+ "var o = {a: 1}; [o.a++, o.a]"),
+ nxt_string("1,2") },
+
+ { nxt_string("var o = {};"
+ "Object.defineProperty(Object.prototype, 'a', {writable:false});"
+ "o.a = 1"),
+ nxt_string("TypeError: Cannot assign to read-only property \"a\" of object") },
+
+ { nxt_string("var o = {};"
+ "Object.defineProperty(Object.prototype, 'a', {writable:true});"
+ "o.a = 1; o.a"),
+ nxt_string("1") },
+
+ { nxt_string("var p = Object.create(Function);"
+ "Object.defineProperty(p, 'length', {writable: true});"
+ "p.length = 32; p.length"),
+ nxt_string("32") },
+
+ { nxt_string("var p = Object.create(Math.abs);"
+ "Object.defineProperty(p, 'length', {writable: true});"
+ "p.length = 23; p.length"),
+ nxt_string("23") },
+
{ nxt_string("var o = {};"
"Object.defineProperty(o, 'a', {value:1}); delete o.a"),
nxt_string("TypeError: Cannot delete property \"a\" of object") },
@@ -9418,6 +9460,7 @@ static njs_unit_test_t njs_test[] =
{ nxt_string("Object.create(Math).hasOwnProperty('abs')"),
nxt_string("false") },
+#if 0 /* Most built-in methods and properties must be writable. */
{ nxt_string("var m = Object.create(Math); m.abs = 3;"
"[m.hasOwnProperty('abs'), m.abs]"),
nxt_string("true,3") },
@@ -9425,6 +9468,7 @@ static njs_unit_test_t njs_test[] =
{ nxt_string("var m = Object.create(Math); m.abs = Math.floor;"
"[m.hasOwnProperty('abs'), delete m.abs, m.abs(-1)]"),
nxt_string("true,true,1") },
+#endif
{ nxt_string("Object.getOwnPropertyDescriptor({a:1}, 'a').value"),
nxt_string("1") },
@@ -11840,8 +11884,10 @@ static njs_unit_test_t njs_test[] =
{ nxt_string("JSON.stringify(URIError('e'))"),
nxt_string("{}") },
+#if 0 /* Most built-in methods and properties must be writable. */
{ nxt_string("var e = URIError('e'); e.name = 'E'; JSON.stringify(e)"),
nxt_string("{\"name\":\"E\"}") },
+#endif
{ nxt_string("var e = URIError('e'); e.message = 'E'; JSON.stringify(e)"),
nxt_string("{}") },
More information about the nginx-devel
mailing list