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;
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 },
}
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;
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;
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;
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,
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;
object->__proto__ = &vm->prototypes[NJS_PROTOTYPE_OBJECT].object;
object->type = NJS_OBJECT;
object->shared = 0;
+ object->extensible = 1;
}
return object;
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;
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);
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;
}
+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,
.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),
+ },
};
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;
}
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) {
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;
/* 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 */
};
.args_types = { __VA_ARGS__ }, \
.args_offset = 1, \
.u.native = _function, \
- .object = { .type = NJS_FUNCTION, .shared = 1 }, \
+ .object = { .type = NJS_FUNCTION, \
+ .shared = 1, \
+ .extensible = 1 }, \
} \
} \
}
{ 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") },