/* Array.prototype. */
{
- .type = NJS_NATIVE_GETTER,
+ .type = NJS_PROPERTY_HANDLER,
.name = njs_string("prototype"),
- .value = njs_native_getter(njs_object_prototype_create),
+ .value = njs_prop_handler(njs_object_prototype_create),
},
/* Array.isArray(). */
static njs_ret_t
njs_array_prototype_length(njs_vm_t *vm, njs_value_t *array,
- njs_value_t *retval)
+ njs_value_t *setval, njs_value_t *retval)
{
njs_value_number_set(retval, array->data.u.array->length);
static const njs_object_prop_t njs_array_prototype_properties[] =
{
{
- .type = NJS_NATIVE_GETTER,
+ .type = NJS_PROPERTY_HANDLER,
.name = njs_string("length"),
- .value = njs_native_getter(njs_array_prototype_length),
+ .value = njs_prop_handler(njs_array_prototype_length),
},
{
/* Boolean.prototype. */
{
- .type = NJS_NATIVE_GETTER,
+ .type = NJS_PROPERTY_HANDLER,
.name = njs_string("prototype"),
- .value = njs_native_getter(njs_object_prototype_create),
+ .value = njs_prop_handler(njs_object_prototype_create),
},
};
static const njs_object_prop_t njs_boolean_prototype_properties[] =
{
{
- .type = NJS_NATIVE_GETTER,
+ .type = NJS_PROPERTY_HANDLER,
.name = njs_string("__proto__"),
- .value = njs_native_getter(njs_primitive_prototype_get_proto),
+ .value = njs_prop_handler(njs_primitive_prototype_get_proto),
},
{
};
static const njs_object_prop_t function_prototype_property = {
- .type = NJS_NATIVE_GETTER,
+ .type = NJS_PROPERTY_HANDLER,
.name = njs_string("prototype"),
- .value = njs_native_getter(njs_function_prototype_create),
+ .value = njs_prop_handler(njs_function_prototype_create),
};
ret = njs_object_hash_create(vm, &vm->shared->function_prototype_hash,
/* Date.prototype. */
{
- .type = NJS_NATIVE_GETTER,
+ .type = NJS_PROPERTY_HANDLER,
.name = njs_string("prototype"),
- .value = njs_native_getter(njs_object_prototype_create),
+ .value = njs_prop_handler(njs_object_prototype_create),
},
{
static const njs_object_prop_t njs_date_prototype_properties[] =
{
{
- .type = NJS_NATIVE_GETTER,
+ .type = NJS_PROPERTY_HANDLER,
.name = njs_string("__proto__"),
- .value = njs_native_getter(njs_primitive_prototype_get_proto),
+ .value = njs_prop_handler(njs_primitive_prototype_get_proto),
},
{
/* Error.prototype. */
{
- .type = NJS_NATIVE_GETTER,
+ .type = NJS_PROPERTY_HANDLER,
.name = njs_string("prototype"),
- .value = njs_native_getter(njs_object_prototype_create),
+ .value = njs_prop_handler(njs_object_prototype_create),
},
};
/* EvalError.prototype. */
{
- .type = NJS_NATIVE_GETTER,
+ .type = NJS_PROPERTY_HANDLER,
.name = njs_string("prototype"),
- .value = njs_native_getter(njs_object_prototype_create),
+ .value = njs_prop_handler(njs_object_prototype_create),
},
};
/* InternalError.prototype. */
{
- .type = NJS_NATIVE_GETTER,
+ .type = NJS_PROPERTY_HANDLER,
.name = njs_string("prototype"),
- .value = njs_native_getter(njs_object_prototype_create),
+ .value = njs_prop_handler(njs_object_prototype_create),
},
};
/* RangeError.prototype. */
{
- .type = NJS_NATIVE_GETTER,
+ .type = NJS_PROPERTY_HANDLER,
.name = njs_string("prototype"),
- .value = njs_native_getter(njs_object_prototype_create),
+ .value = njs_prop_handler(njs_object_prototype_create),
},
};
/* ReferenceError.prototype. */
{
- .type = NJS_NATIVE_GETTER,
+ .type = NJS_PROPERTY_HANDLER,
.name = njs_string("prototype"),
- .value = njs_native_getter(njs_object_prototype_create),
+ .value = njs_prop_handler(njs_object_prototype_create),
},
};
/* SyntaxError.prototype. */
{
- .type = NJS_NATIVE_GETTER,
+ .type = NJS_PROPERTY_HANDLER,
.name = njs_string("prototype"),
- .value = njs_native_getter(njs_object_prototype_create),
+ .value = njs_prop_handler(njs_object_prototype_create),
},
};
/* TypeError.prototype. */
{
- .type = NJS_NATIVE_GETTER,
+ .type = NJS_PROPERTY_HANDLER,
.name = njs_string("prototype"),
- .value = njs_native_getter(njs_object_prototype_create),
+ .value = njs_prop_handler(njs_object_prototype_create),
},
};
/* URIError.prototype. */
{
- .type = NJS_NATIVE_GETTER,
+ .type = NJS_PROPERTY_HANDLER,
.name = njs_string("prototype"),
- .value = njs_native_getter(njs_object_prototype_create),
+ .value = njs_prop_handler(njs_object_prototype_create),
},
};
static njs_ret_t
njs_memory_error_prototype_create(njs_vm_t *vm, njs_value_t *value,
- njs_value_t *retval)
+ njs_value_t *setval, njs_value_t *retval)
{
int32_t index;
njs_value_t *proto;
/* MemoryError.prototype. */
{
- .type = NJS_NATIVE_GETTER,
+ .type = NJS_PROPERTY_HANDLER,
.name = njs_string("prototype"),
- .value = njs_native_getter(njs_memory_error_prototype_create),
+ .value = njs_prop_handler(njs_memory_error_prototype_create),
},
};
njs_ret_t
njs_function_prototype_create(njs_vm_t *vm, njs_value_t *value,
- njs_value_t *retval)
+ njs_value_t *setval, njs_value_t *retval)
{
njs_value_t *proto;
/* Function.prototype. */
{
- .type = NJS_NATIVE_GETTER,
+ .type = NJS_PROPERTY_HANDLER,
.name = njs_string("prototype"),
- .value = njs_native_getter(njs_object_prototype_create),
+ .value = njs_prop_handler(njs_object_prototype_create),
},
};
njs_function_t *njs_function_value_copy(njs_vm_t *vm, njs_value_t *value);
njs_native_frame_t *njs_function_frame_alloc(njs_vm_t *vm, size_t size);
njs_ret_t njs_function_prototype_create(njs_vm_t *vm, njs_value_t *value,
- njs_value_t *retval);
+ njs_value_t *setval, njs_value_t *retval);
njs_value_t *njs_function_property_prototype_create(njs_vm_t *vm,
njs_value_t *value);
njs_ret_t njs_function_constructor(njs_vm_t *vm, njs_value_t *args,
},
{
- .type = NJS_NATIVE_GETTER,
+ .type = NJS_PROPERTY_HANDLER,
.name = njs_string("__proto__"),
- .value = njs_native_getter(njs_object_prototype_get_proto),
+ .value = njs_prop_handler(njs_object_prototype_get_proto),
},
{
/* Number.prototype. */
{
- .type = NJS_NATIVE_GETTER,
+ .type = NJS_PROPERTY_HANDLER,
.name = njs_string("prototype"),
- .value = njs_native_getter(njs_object_prototype_create),
+ .value = njs_prop_handler(njs_object_prototype_create),
},
/* ES6. */
static const njs_object_prop_t njs_number_prototype_properties[] =
{
{
- .type = NJS_NATIVE_GETTER,
+ .type = NJS_PROPERTY_HANDLER,
.name = njs_string("__proto__"),
- .value = njs_native_getter(njs_primitive_prototype_get_proto),
+ .value = njs_prop_handler(njs_primitive_prototype_get_proto),
},
{
njs_index_t unused)
{
if (nargs > 1 && njs_is_object(&args[1])) {
- njs_object_prototype_get_proto(vm, &args[1], &vm->retval);
+ njs_object_prototype_get_proto(vm, &args[1], NULL, &vm->retval);
return NXT_OK;
}
njs_ret_t
njs_primitive_prototype_get_proto(njs_vm_t *vm, njs_value_t *value,
- njs_value_t *retval)
+ njs_value_t *setval, njs_value_t *retval)
{
nxt_uint_t index;
njs_object_t *proto;
njs_ret_t
njs_object_prototype_create(njs_vm_t *vm, njs_value_t *value,
- njs_value_t *retval)
+ njs_value_t *setval, njs_value_t *retval)
{
int32_t index;
njs_value_t *proto;
/* Object.prototype. */
{
- .type = NJS_NATIVE_GETTER,
+ .type = NJS_PROPERTY_HANDLER,
.name = njs_string("prototype"),
- .value = njs_native_getter(njs_object_prototype_create),
+ .value = njs_prop_handler(njs_object_prototype_create),
},
/* Object.create(). */
njs_ret_t
njs_object_prototype_get_proto(njs_vm_t *vm, njs_value_t *value,
- njs_value_t *retval)
+ njs_value_t *setval, njs_value_t *retval)
{
njs_object_t *proto;
static njs_ret_t
njs_object_prototype_create_constructor(njs_vm_t *vm, njs_value_t *value,
- njs_value_t *retval)
+ njs_value_t *setval, njs_value_t *retval)
{
int32_t index;
njs_value_t *cons;
static const njs_object_prop_t njs_object_prototype_properties[] =
{
{
- .type = NJS_NATIVE_GETTER,
+ .type = NJS_PROPERTY_HANDLER,
.name = njs_string("__proto__"),
- .value = njs_native_getter(njs_object_prototype_get_proto),
+ .value = njs_prop_handler(njs_object_prototype_get_proto),
},
{
- .type = NJS_NATIVE_GETTER,
+ .type = NJS_PROPERTY_HANDLER,
.name = njs_string("constructor"),
- .value = njs_native_getter(njs_object_prototype_create_constructor),
+ .value = njs_prop_handler(njs_object_prototype_create_constructor),
},
{
NJS_GETTER,
NJS_SETTER,
NJS_METHOD,
- NJS_NATIVE_GETTER,
- NJS_NATIVE_SETTER,
+ NJS_PROPERTY_HANDLER,
NJS_WHITEOUT,
} njs_object_property_type_t;
njs_object_prop_t *njs_object_prop_alloc(njs_vm_t *vm, const njs_value_t *name,
const njs_value_t *value, uint8_t attributes);
njs_ret_t njs_primitive_prototype_get_proto(njs_vm_t *vm, njs_value_t *value,
- njs_value_t *retval);
+ njs_value_t *setval, njs_value_t *retval);
njs_ret_t njs_object_prototype_create(njs_vm_t *vm, njs_value_t *value,
- njs_value_t *retval);
+ njs_value_t *setval, njs_value_t *retval);
njs_value_t *njs_property_prototype_create(njs_vm_t *vm, nxt_lvlhsh_t *hash,
njs_object_t *prototype);
njs_ret_t njs_object_prototype_get_proto(njs_vm_t *vm, njs_value_t *value,
- njs_value_t *retval);
+ njs_value_t *setval, njs_value_t *retval);
njs_value_t *njs_property_constructor_create(njs_vm_t *vm, nxt_lvlhsh_t *hash,
njs_value_t *constructor);
njs_ret_t njs_object_prototype_to_string(njs_vm_t *vm, njs_value_t *args,
static njs_ret_t
njs_regexp_prototype_last_index(njs_vm_t *vm, njs_value_t *value,
- njs_value_t *retval)
+ njs_value_t *setval, njs_value_t *retval)
{
uint32_t index;
njs_regexp_t *regexp;
static njs_ret_t
njs_regexp_prototype_global(njs_vm_t *vm, njs_value_t *value,
- njs_value_t *retval)
+ njs_value_t *setval, njs_value_t *retval)
{
njs_regexp_pattern_t *pattern;
static njs_ret_t
njs_regexp_prototype_ignore_case(njs_vm_t *vm, njs_value_t *value,
- njs_value_t *retval)
+ njs_value_t *setval, njs_value_t *retval)
{
njs_regexp_pattern_t *pattern;
static njs_ret_t
njs_regexp_prototype_multiline(njs_vm_t *vm, njs_value_t *value,
- njs_value_t *retval)
+ njs_value_t *setval, njs_value_t *retval)
{
njs_regexp_pattern_t *pattern;
static njs_ret_t
njs_regexp_prototype_source(njs_vm_t *vm, njs_value_t *value,
- njs_value_t *retval)
+ njs_value_t *setval, njs_value_t *retval)
{
u_char *source;
int32_t length;
/* RegExp.prototype. */
{
- .type = NJS_NATIVE_GETTER,
+ .type = NJS_PROPERTY_HANDLER,
.name = njs_string("prototype"),
- .value = njs_native_getter(njs_object_prototype_create),
+ .value = njs_prop_handler(njs_object_prototype_create),
},
};
static const njs_object_prop_t njs_regexp_prototype_properties[] =
{
{
- .type = NJS_NATIVE_GETTER,
+ .type = NJS_PROPERTY_HANDLER,
.name = njs_string("lastIndex"),
- .value = njs_native_getter(njs_regexp_prototype_last_index),
+ .value = njs_prop_handler(njs_regexp_prototype_last_index),
},
{
- .type = NJS_NATIVE_GETTER,
+ .type = NJS_PROPERTY_HANDLER,
.name = njs_string("global"),
- .value = njs_native_getter(njs_regexp_prototype_global),
+ .value = njs_prop_handler(njs_regexp_prototype_global),
},
{
- .type = NJS_NATIVE_GETTER,
+ .type = NJS_PROPERTY_HANDLER,
.name = njs_string("ignoreCase"),
- .value = njs_native_getter(njs_regexp_prototype_ignore_case),
+ .value = njs_prop_handler(njs_regexp_prototype_ignore_case),
},
{
- .type = NJS_NATIVE_GETTER,
+ .type = NJS_PROPERTY_HANDLER,
.name = njs_string("multiline"),
- .value = njs_native_getter(njs_regexp_prototype_multiline),
+ .value = njs_prop_handler(njs_regexp_prototype_multiline),
},
{
- .type = NJS_NATIVE_GETTER,
+ .type = NJS_PROPERTY_HANDLER,
.name = njs_string("source"),
- .value = njs_native_getter(njs_regexp_prototype_source),
+ .value = njs_prop_handler(njs_regexp_prototype_source),
},
{
/* String.prototype. */
{
- .type = NJS_NATIVE_GETTER,
+ .type = NJS_PROPERTY_HANDLER,
.name = njs_string("prototype"),
- .value = njs_native_getter(njs_object_prototype_create),
+ .value = njs_prop_handler(njs_object_prototype_create),
},
/* String.fromCharCode(). */
static njs_ret_t
njs_string_prototype_length(njs_vm_t *vm, njs_value_t *value,
- njs_value_t *retval)
+ njs_value_t *setval, njs_value_t *retval)
{
size_t size;
uintptr_t length;
static const njs_object_prop_t njs_string_prototype_properties[] =
{
{
- .type = NJS_NATIVE_GETTER,
+ .type = NJS_PROPERTY_HANDLER,
.name = njs_string("__proto__"),
- .value = njs_native_getter(njs_primitive_prototype_get_proto),
+ .value = njs_prop_handler(njs_primitive_prototype_get_proto),
},
{
- .type = NJS_NATIVE_GETTER,
+ .type = NJS_PROPERTY_HANDLER,
.name = njs_string("length"),
- .value = njs_native_getter(njs_string_prototype_length),
+ .value = njs_prop_handler(njs_string_prototype_length),
},
{
typedef struct {
nxt_lvlhsh_query_t lhq;
- /* scratch is used to get the value of an NJS_NATIVE_GETTER property. */
+ /* scratch is used to get the value of an NJS_PROPERTY_HANDLER property. */
njs_object_prop_t scratch;
njs_value_t value;
njs_property_query_t *pq, njs_value_t *object, uint32_t index);
static njs_ret_t njs_object_property_query(njs_vm_t *vm,
njs_property_query_t *pq, njs_value_t *value, njs_object_t *object);
+static njs_ret_t njs_object_query_prop_handler(njs_property_query_t *pq,
+ njs_object_t *object);
static njs_ret_t njs_method_private_copy(njs_vm_t *vm,
njs_property_query_t *pq);
static nxt_noinline njs_ret_t njs_values_equal(const njs_value_t *val1,
case NXT_OK:
prop = pq.lhq.value;
+
+ 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);
+ }
+
break;
case NXT_DECLINED:
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;
+ }
+ }
+
do {
pq->prototype = object;
if (pq->query == NJS_PROPERTY_QUERY_GET) {
prop = pq->lhq.value;
- if (prop->type == NJS_NATIVE_GETTER) {
+ if (prop->type == NJS_PROPERTY_HANDLER) {
pq->scratch = *prop;
prop = &pq->scratch;
- ret = prop->value.data.u.getter(vm, value, &prop->value);
+ ret = prop->value.data.u.prop_handler(vm, value, NULL,
+ &prop->value);
if (nxt_fast_path(ret == NXT_OK)) {
prop->type = NJS_PROPERTY;
}
+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;
+}
+
+
static njs_ret_t
njs_method_private_copy(njs_vm_t *vm, njs_property_query_t *pq)
{
typedef struct njs_parser_s njs_parser_t;
-typedef njs_ret_t (*njs_getter_t) (njs_vm_t *vm, njs_value_t *obj,
- njs_value_t *retval);
+/*
+ * njs_prop_handler_t operates as a property getter and/or setter.
+ * The handler receives NULL setval if it is invoked in GET context and
+ * non-null otherwise.
+ */
+typedef njs_ret_t (*njs_prop_handler_t) (njs_vm_t *vm, njs_value_t *value,
+ njs_value_t *setval, njs_value_t *retval);
typedef njs_ret_t (*njs_function_native_t) (njs_vm_t *vm, njs_value_t *args,
nxt_uint_t nargs, njs_index_t retval);
njs_function_lambda_t *lambda;
njs_regexp_t *regexp;
njs_date_t *date;
- njs_getter_t getter;
+ njs_prop_handler_t prop_handler;
njs_value_t *value;
njs_property_next_t *next;
void *data;
}
-#define njs_native_getter(_getter) { \
+#define njs_prop_handler(_handler) { \
.data = { \
.type = NJS_INVALID, \
.truth = 1, \
- .u = { .getter = _getter } \
+ .u = { .prop_handler = _handler } \
} \
}
{ nxt_string("({}).__proto__ === Object.prototype"),
nxt_string("true") },
+ { nxt_string("({}).__proto__ = 1"),
+ nxt_string("1") },
+
+ { nxt_string("var o = {}; o.__proto__ = 1; o.__proto__"),
+ nxt_string("[object Object]") },
+
{ nxt_string("({}).__proto__.constructor === Object"),
nxt_string("true") },