details: https://hg.nginx.org/njs/rev/ff591ba3e780 branches: changeset: 979:ff591ba3e780 user: Valentin Bartenev <vb...@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("{}") }, _______________________________________________ nginx-devel mailing list nginx-devel@nginx.org http://mailman.nginx.org/mailman/listinfo/nginx-devel