njs_str("PROP GET ") },
{ NJS_VMCODE_PROPERTY_INIT, sizeof(njs_vmcode_prop_set_t),
njs_str("PROP INIT ") },
+ { NJS_VMCODE_PROTO_INIT, sizeof(njs_vmcode_prop_set_t),
+ njs_str("PROTO INIT ") },
{ NJS_VMCODE_PROPERTY_SET, sizeof(njs_vmcode_prop_set_t),
njs_str("PROP SET ") },
{ NJS_VMCODE_PROPERTY_IN, sizeof(njs_vmcode_3addr_t),
return ret;
}
- if (lvalue->token == NJS_TOKEN_PROPERTY_INIT) {
+ switch (lvalue->token) {
+ case NJS_TOKEN_PROPERTY_INIT:
njs_generate_code(generator, njs_vmcode_prop_set_t, prop_set,
NJS_VMCODE_PROPERTY_INIT, 3);
- } else {
+ break;
+
+ case NJS_TOKEN_PROTO_INIT:
+ njs_generate_code(generator, njs_vmcode_prop_set_t, prop_set,
+ NJS_VMCODE_PROTO_INIT, 3);
+ break;
+
+ default:
+ /* NJS_VMCODE_PROPERTY_SET */
njs_generate_code(generator, njs_vmcode_prop_set_t, prop_set,
NJS_VMCODE_PROPERTY_SET, 3);
}
NJS_TOKEN_PROPERTY_DELETE,
NJS_TOKEN_PROPERTY_GETTER,
NJS_TOKEN_PROPERTY_SETTER,
+ NJS_TOKEN_PROTO_INIT,
NJS_TOKEN_ARRAY,
#define _NJS_OBJECT_HASH_H_INCLUDED_
+#define NJS___PROTO___HASH \
+ njs_djb_hash_add( \
+ njs_djb_hash_add( \
+ njs_djb_hash_add( \
+ njs_djb_hash_add( \
+ njs_djb_hash_add( \
+ njs_djb_hash_add( \
+ njs_djb_hash_add( \
+ njs_djb_hash_add( \
+ njs_djb_hash_add(NJS_DJB_HASH_INIT, \
+ '_'), '_'), 'p'), 'r'), 'o'), 't'), 'o'), '_'), '_')
+
+
#define NJS_ARGV_HASH \
njs_djb_hash_add( \
njs_djb_hash_add( \
njs_parser_node_t *obj);
static njs_int_t njs_parser_object_property(njs_vm_t *vm, njs_parser_t *parser,
njs_parser_node_t *parent, njs_parser_node_t *property,
- njs_parser_node_t *value);
+ njs_parser_node_t *value, njs_bool_t proto_init);
static njs_int_t njs_parser_property_accessor(njs_vm_t *vm,
njs_parser_t *parser, njs_parser_node_t *parent,
njs_parser_node_t *property, njs_parser_node_t *value,
njs_parser_object(njs_vm_t *vm, njs_parser_t *parser, njs_parser_node_t *obj)
{
uint32_t hash, token_line;
- njs_int_t ret;
+ njs_int_t ret, __proto__;
njs_str_t name;
+ njs_bool_t computed, proto_init;
njs_token_t token, accessor;
njs_lexer_t *lexer;
njs_parser_node_t *object, *property, *expression;
njs_function_lambda_t *lambda;
+ const njs_str_t proto_string = njs_str("__proto__");
+
lexer = parser->lexer;
/* GCC and Clang complain about uninitialized values. */
hash = 0;
token_line = 0;
+ __proto__ = 0;
property = NULL;
object = njs_parser_node_new(vm, parser, NJS_TOKEN_OBJECT_VALUE);
}
accessor = 0;
+ computed = 0;
+ proto_init = 0;
njs_memzero(&name, sizeof(njs_str_t));
if (token == NJS_TOKEN_NAME || lexer->keyword) {
token = njs_parser_match(vm, parser, token,
NJS_TOKEN_CLOSE_BRACKET);
+
+ computed = 1;
+
break;
case NJS_TOKEN_NUMBER:
break;
case NJS_TOKEN_COLON:
+ if (!computed) {
+ if (njs_is_string(&property->u.value)) {
+ njs_string_get(&property->u.value, &name);
+ }
+
+ if (njs_slow_path(njs_strstr_eq(&name, &proto_string))) {
+ if (++__proto__ > 1) {
+ njs_parser_syntax_error(vm, parser,
+ "Duplicate __proto__ fields are not allowed "
+ "in object literals");
+ return NJS_TOKEN_ILLEGAL;
+ }
+
+ proto_init = 1;
+ }
+ }
+
token = njs_parser_token(vm, parser);
if (njs_slow_path(token <= NJS_TOKEN_ILLEGAL)) {
return token;
}
ret = njs_parser_object_property(vm, parser, obj, property,
- expression);
+ expression, proto_init);
if (njs_slow_path(ret != NJS_OK)) {
return NJS_TOKEN_ERROR;
}
static njs_int_t
njs_parser_object_property(njs_vm_t *vm, njs_parser_t *parser,
njs_parser_node_t *parent, njs_parser_node_t *property,
- njs_parser_node_t *value)
+ njs_parser_node_t *value, njs_bool_t proto_init)
{
+ njs_token_t token;
njs_parser_node_t *stmt, *assign, *object, *propref;
object = njs_parser_node_new(vm, parser, NJS_TOKEN_OBJECT_VALUE);
object->u.object = parent;
- propref = njs_parser_node_new(vm, parser, NJS_TOKEN_PROPERTY_INIT);
+ token = proto_init ? NJS_TOKEN_PROTO_INIT : NJS_TOKEN_PROPERTY_INIT;
+
+ propref = njs_parser_node_new(vm, parser, token);
if (njs_slow_path(propref == NULL)) {
return NJS_ERROR;
}
njs_set_number(&number->u.value, array->u.length);
- ret = njs_parser_object_property(vm, parser, array, number, value);
+ ret = njs_parser_object_property(vm, parser, array, number, value, 0);
if (njs_slow_path(ret != NJS_OK)) {
return NJS_ERROR;
}
static njs_jump_off_t njs_vmcode_object_copy(njs_vm_t *vm, njs_value_t *value,
njs_value_t *invld);
-static njs_jump_off_t njs_vmcode_property_init(njs_vm_t *vm,
- njs_value_t *value, njs_value_t *key, njs_value_t *retval);
+static njs_jump_off_t njs_vmcode_property_init(njs_vm_t *vm, njs_value_t *value,
+ njs_value_t *key, njs_value_t *retval);
+static njs_jump_off_t njs_vmcode_proto_init(njs_vm_t *vm, njs_value_t *value,
+ njs_value_t *key, njs_value_t *retval);
static njs_jump_off_t njs_vmcode_property_in(njs_vm_t *vm,
njs_value_t *value, njs_value_t *key);
static njs_jump_off_t njs_vmcode_property_delete(njs_vm_t *vm,
break;
+ case NJS_VMCODE_PROTO_INIT:
+ set = (njs_vmcode_prop_set_t *) pc;
+ retval = njs_vmcode_operand(vm, set->value);
+ ret = njs_vmcode_proto_init(vm, value1, value2, retval);
+ if (njs_slow_path(ret == NJS_ERROR)) {
+ goto error;
+ }
+
+ break;
+
case NJS_VMCODE_TRY_START:
ret = njs_vmcode_try_start(vm, value1, value2, pc);
if (njs_slow_path(ret == NJS_ERROR)) {
uint32_t index, size;
njs_array_t *array;
njs_value_t *val, name;
- njs_object_t *obj;
njs_jump_off_t ret;
njs_object_prop_t *prop;
njs_lvlhsh_query_t lhq;
lhq.proto = &njs_object_hash_proto;
lhq.pool = vm->mem_pool;
- obj = njs_object(value);
-
- if (obj->__proto__ != NULL) {
- /* obj->__proto__ can be NULL after __proto__: null assignment */
- ret = njs_lvlhsh_find(&obj->__proto__->shared_hash, &lhq);
- if (ret == NJS_OK) {
- prop = lhq.value;
-
- if (prop->type == NJS_PROPERTY_HANDLER) {
- ret = prop->value.data.u.prop_handler(vm, value, init,
- &vm->retval);
- if (njs_slow_path(ret == NJS_ERROR)) {
- return ret;
- }
-
- if (ret == NJS_OK) {
- break;
- }
-
- /* NJS_DECLINED */
- }
- }
- }
-
prop = njs_object_prop_alloc(vm, &name, init, 1);
if (njs_slow_path(prop == NULL)) {
return NJS_ERROR;
lhq.value = prop;
lhq.replace = 1;
- ret = njs_lvlhsh_insert(&obj->hash, &lhq);
+ ret = njs_lvlhsh_insert(njs_object_hash(value), &lhq);
if (njs_slow_path(ret != NJS_OK)) {
njs_internal_error(vm, "lvlhsh insert/replace failed");
return NJS_ERROR;
}
+static njs_jump_off_t
+njs_vmcode_proto_init(njs_vm_t *vm, njs_value_t *value, njs_value_t *unused,
+ njs_value_t *init)
+{
+ njs_object_t *obj;
+ njs_jump_off_t ret;
+ njs_object_prop_t *prop;
+ njs_lvlhsh_query_t lhq;
+
+ lhq.key = njs_str_value("__proto__");
+ lhq.key_hash = NJS___PROTO___HASH;
+ lhq.proto = &njs_object_hash_proto;
+ lhq.pool = vm->mem_pool;
+
+ obj = njs_object(value);
+
+ ret = njs_lvlhsh_find(&obj->__proto__->shared_hash, &lhq);
+ if (njs_slow_path(ret != NJS_OK)) {
+ goto fail;
+ }
+
+ prop = lhq.value;
+
+ if (prop->type != NJS_PROPERTY_HANDLER) {
+ goto fail;
+ }
+
+ ret = prop->value.data.u.prop_handler(vm, value, init, &vm->retval);
+ if (njs_slow_path(ret != NJS_OK)) {
+ goto fail;
+ }
+
+ return sizeof(njs_vmcode_prop_set_t);
+
+fail:
+
+ njs_internal_error(vm, "\"__proto__\" init failed");
+ return NJS_ERROR;
+}
+
+
static njs_jump_off_t
njs_vmcode_property_in(njs_vm_t *vm, njs_value_t *value, njs_value_t *key)
{
#define NJS_VMCODE_PROPERTY_NEXT VMCODE0(16)
#define NJS_VMCODE_THIS VMCODE0(17)
#define NJS_VMCODE_ARGUMENTS VMCODE0(18)
+#define NJS_VMCODE_PROTO_INIT VMCODE0(19)
#define NJS_VMCODE_TRY_START VMCODE0(32)
#define NJS_VMCODE_THROW VMCODE0(33)
{ njs_str("var o = {__proto__: Array.prototype, length:3}; o.fill('a')[2]"),
njs_str("a") },
+ { njs_str("({__proto__:null, __proto__: null})"),
+ njs_str("SyntaxError: Duplicate __proto__ fields are not allowed in object literals in 1") },
+
+ { njs_str("({__proto__:null, '__proto__': null})"),
+ njs_str("SyntaxError: Duplicate __proto__ fields are not allowed in object literals in 1") },
+
+ { njs_str("({__proto__:null, '\\x5f_proto__': null})"),
+ njs_str("SyntaxError: Duplicate __proto__ fields are not allowed in object literals in 1") },
+
+ { njs_str("var __proto__ = 'a'; ({__proto__}).__proto__"),
+ njs_str("a") },
+
+ { njs_str("var __proto__ = 'a'; ({__proto__, '__proto__':'b'}).__proto__"),
+ njs_str("a") },
+
+ { njs_str("var __proto__ = 'a'; ({__proto__:null, __proto__}).__proto__"),
+ njs_str("a") },
+
+ { njs_str("({__proto__:null, ['__proto__']:'a'}).__proto__"),
+ njs_str("a") },
+
+ { njs_str("({__proto__() { return 123; }}).__proto__()"),
+ njs_str("123") },
+
+ { njs_str("({['__prot' + 'o__']: 123}).__proto__"),
+ njs_str("123") },
+
{ njs_str("({}).__proto__.constructor === Object"),
njs_str("true") },