Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- # HG changeset patch
- # User Dmitry Volyntsev <xeioex@nginx.com>
- # Date 1536859188 -10800
- # Thu Sep 13 20:19:48 2018 +0300
- # Node ID ebc9a6f65579c68976a54f88bdeff1248e1d0be8
- # Parent c4f9a49486979285b6b508109d4988b4bc30d35d
- Fixed Array.prototype.length setter.
- diff --git a/njs/njs_array.c b/njs/njs_array.c
- --- a/njs/njs_array.c
- +++ b/njs/njs_array.c
- @@ -377,7 +377,7 @@ njs_array_prototype_length(njs_vm_t *vm,
- njs_value_t *setval, njs_value_t *retval)
- {
- double num;
- - int32_t size;
- + int64_t size;
- uint32_t length;
- njs_ret_t ret;
- njs_value_t *val;
- @@ -399,7 +399,7 @@ njs_array_prototype_length(njs_vm_t *vm,
- return NJS_ERROR;
- }
- - size = (int32_t) (length - array->length);
- + size = (int64_t) length - array->length;
- if (size > 0) {
- ret = njs_array_expand(vm, array, 0, size);
- diff --git a/njs/test/njs_unit_test.c b/njs/test/njs_unit_test.c
- --- a/njs/test/njs_unit_test.c
- +++ b/njs/test/njs_unit_test.c
- @@ -2790,9 +2790,15 @@ static njs_unit_test_t njs_test[] =
- { nxt_string("[].length = {}"),
- nxt_string("RangeError: Invalid array length") },
- + { nxt_string("[].length = 2**32 - 1"),
- + nxt_string("MemoryError") },
- +
- { nxt_string("[].length = 2**32"),
- nxt_string("RangeError: Invalid array length") },
- + { nxt_string("[].length = 2**32 + 1"),
- + nxt_string("RangeError: Invalid array length") },
- +
- { nxt_string("[].length = -1"),
- nxt_string("RangeError: Invalid array length") },
- # HG changeset patch
- # User Dmitry Volyntsev <xeioex@nginx.com>
- # Date 1536859188 -10800
- # Thu Sep 13 20:19:48 2018 +0300
- # Node ID 84d4d83acd928ca222143dbba3ad48c985027262
- # Parent ebc9a6f65579c68976a54f88bdeff1248e1d0be8
- Fixed njs_array_alloc() for length > 2**31.
- diff --git a/njs/njs_array.c b/njs/njs_array.c
- --- a/njs/njs_array.c
- +++ b/njs/njs_array.c
- @@ -117,7 +117,7 @@ njs_array_alloc(njs_vm_t *vm, uint32_t l
- goto memory_error;
- }
- - size = length + spare;
- + size = (size_t) length + spare;
- if (nxt_slow_path(size * sizeof(njs_value_t) < size)) {
- goto memory_error;
- # HG changeset patch
- # User Dmitry Volyntsev <xeioex@nginx.com>
- # Date 1536859189 -10800
- # Thu Sep 13 20:19:49 2018 +0300
- # Node ID 7baa55f6e48df106e5226bea86949a64804b93d0
- # Parent 84d4d83acd928ca222143dbba3ad48c985027262
- Fixed njs_string_slice().
- dst retval argument was ignored.
- diff --git a/njs/njs_string.c b/njs/njs_string.c
- --- a/njs/njs_string.c
- +++ b/njs/njs_string.c
- @@ -1288,7 +1288,7 @@ njs_string_slice_args(njs_slice_prop_t *
- nxt_noinline njs_ret_t
- njs_string_slice(njs_vm_t *vm, njs_value_t *dst,
- - const njs_string_prop_t *string, njs_slice_prop_t *slice)
- + const njs_string_prop_t *string, const njs_slice_prop_t *slice)
- {
- size_t size, n, length;
- const u_char *p, *start, *end;
- @@ -1325,10 +1325,10 @@ njs_string_slice(njs_vm_t *vm, njs_value
- }
- if (nxt_fast_path(size != 0)) {
- - return njs_string_new(vm, &vm->retval, start, size, length);
- + return njs_string_new(vm, dst, start, size, length);
- }
- - vm->retval = njs_string_empty;
- + *dst = njs_string_empty;
- return NXT_OK;
- }
- diff --git a/njs/njs_string.h b/njs/njs_string.h
- --- a/njs/njs_string.h
- +++ b/njs/njs_string.h
- @@ -146,7 +146,7 @@ njs_ret_t njs_string_constructor(njs_vm_
- nxt_bool_t njs_string_eq(const njs_value_t *val1, const njs_value_t *val2);
- nxt_int_t njs_string_cmp(const njs_value_t *val1, const njs_value_t *val2);
- njs_ret_t njs_string_slice(njs_vm_t *vm, njs_value_t *dst,
- - const njs_string_prop_t *string, njs_slice_prop_t *slice);
- + const njs_string_prop_t *string, const njs_slice_prop_t *slice);
- const u_char *njs_string_offset(const u_char *start, const u_char *end,
- size_t index);
- nxt_noinline uint32_t njs_string_index(njs_string_prop_t *string,
- # HG changeset patch
- # User Dmitry Volyntsev <xeioex@nginx.com>
- # Date 1536860013 -10800
- # Thu Sep 13 20:33:33 2018 +0300
- # Node ID ffe3b161805980547f16f3ff1142fc55f3f628ca
- # Parent 7baa55f6e48df106e5226bea86949a64804b93d0
- Object property quering is refactored.
- njs_property_query() only returns property descriptors and
- does not try to invoke PROPERTY_HANDLER for
- AccessorDescriptors.
- njs_property_query_t.own can be used to query for an object's
- OwnProperty.
- njs_value_property() is introduced which corresponds to [[Get]]
- method from specification.
- This fixes #32 issue on Github.
- diff --git a/njs/njs_object.c b/njs/njs_object.c
- --- a/njs/njs_object.c
- +++ b/njs/njs_object.c
- @@ -246,13 +246,15 @@ njs_object_property(njs_vm_t *vm, const
- njs_ret_t
- njs_property_query(njs_vm_t *vm, njs_property_query_t *pq, njs_value_t *object,
- - njs_value_t *property)
- + const njs_value_t *property)
- {
- uint32_t index;
- uint32_t (*hash)(const void *, size_t);
- njs_ret_t ret;
- + njs_array_t *array;
- njs_object_t *obj;
- njs_function_t *function;
- + njs_object_prop_t *prop;
- const njs_extern_t *ext_proto;
- hash = nxt_djb_hash;
- @@ -285,6 +287,34 @@ njs_property_query(njs_vm_t *vm, njs_pro
- if (nxt_fast_path(index < NJS_ARRAY_MAX_LENGTH)) {
- return njs_array_property_query(vm, pq, object, index);
- +
- + } else if (pq->query == NJS_PROPERTY_QUERY_GET) {
- +
- + /* FIXME: length should be a DataProperty */
- +
- + njs_primitive_value_to_string(vm, &pq->value, property);
- + njs_string_get(&pq->value, &pq->lhq.key);
- +
- + if (nxt_slow_path(pq->lhq.key.length == 6
- + && memcmp(pq->lhq.key.start, "length", 6)
- + == 0))
- + {
- + prop = &pq->scratch;
- +
- + prop->name = (njs_value_t) njs_string("length");
- +
- + array = object->data.u.array;
- + njs_value_number_set(&prop->value, array->length);
- +
- + prop->type = NJS_PROPERTY;
- + prop->configurable = 0;
- + prop->enumerable = 0;
- + prop->writable = 1;
- +
- + pq->lhq.value = prop;
- +
- + return NXT_OK;
- + }
- }
- } else {
- @@ -381,6 +411,7 @@ njs_object_property_query(njs_vm_t *vm,
- njs_value_t *value, njs_object_t *object)
- {
- njs_ret_t ret;
- + njs_object_t *proto;
- njs_object_prop_t *prop;
- pq->lhq.proto = &njs_object_hash_proto;
- @@ -392,70 +423,49 @@ njs_object_property_query(njs_vm_t *vm,
- }
- }
- + proto = object;
- +
- do {
- - pq->prototype = object;
- + pq->prototype = proto;
- - ret = nxt_lvlhsh_find(&object->hash, &pq->lhq);
- + /* length and other shared properties should be Own property */
- - if (ret == NXT_OK) {
- - prop = pq->lhq.value;
- + if (nxt_fast_path(!pq->own || proto == object)) {
- + ret = nxt_lvlhsh_find(&proto->hash, &pq->lhq);
- - if (prop->type != NJS_WHITEOUT) {
- + if (ret == NXT_OK) {
- + prop = pq->lhq.value;
- pq->shared = 0;
- - return ret;
- + return (prop->type != NJS_WHITEOUT) ? ret : NXT_DECLINED;
- }
- -
- - goto next;
- }
- if (pq->query > NJS_PROPERTY_QUERY_IN) {
- - /* NXT_DECLINED */
- - return ret;
- + return NXT_DECLINED;
- }
- - ret = nxt_lvlhsh_find(&object->shared_hash, &pq->lhq);
- + ret = nxt_lvlhsh_find(&proto->shared_hash, &pq->lhq);
- if (ret == NXT_OK) {
- pq->shared = 1;
- - if (pq->query == NJS_PROPERTY_QUERY_GET) {
- - prop = pq->lhq.value;
- -
- - if (prop->type == NJS_PROPERTY_HANDLER) {
- - pq->scratch = *prop;
- - prop = &pq->scratch;
- - ret = prop->value.data.u.prop_handler(vm, value, NULL,
- - &prop->value);
- -
- - if (nxt_fast_path(ret == NXT_OK)) {
- - prop->type = NJS_PROPERTY;
- - pq->lhq.value = prop;
- - }
- - }
- - }
- -
- return ret;
- }
- if (pq->query > NJS_PROPERTY_QUERY_IN) {
- - /* NXT_DECLINED */
- - return ret;
- + return NXT_DECLINED;
- }
- - next:
- + proto = proto->__proto__;
- - object = object->__proto__;
- -
- - } while (object != NULL);
- + } while (proto != NULL);
- if (njs_is_string(value)) {
- return NJS_STRING_VALUE;
- }
- - /* NXT_DECLINED */
- -
- - return ret;
- + return NXT_DECLINED;
- }
- @@ -1037,12 +1047,9 @@ njs_object_get_own_property_descriptor(n
- lhq.proto = &njs_object_hash_proto;
- if (prop == NULL) {
- - pq.query = NJS_PROPERTY_QUERY_GET;
- - pq.lhq.key.length = 0;
- - pq.lhq.key.start = NULL;
- + njs_property_query_init(&pq, NJS_PROPERTY_QUERY_GET, 1);
- - ret = njs_property_query(vm, &pq, (njs_value_t *) value,
- - (njs_value_t *) property);
- + ret = njs_property_query(vm, &pq, (njs_value_t *) value, property);
- if (ret != NXT_OK) {
- vm->retval = njs_value_void;
- @@ -1050,6 +1057,16 @@ njs_object_get_own_property_descriptor(n
- }
- prop = pq.lhq.value;
- +
- + if (prop->type == NJS_PROPERTY_HANDLER) {
- + pq.scratch = *prop;
- + prop = &pq.scratch;
- + ret = prop->value.data.u.prop_handler(vm, (njs_value_t *) value,
- + NULL, &prop->value);
- + if (nxt_slow_path(ret != NXT_OK)) {
- + return ret;
- + }
- + }
- }
- descriptor = njs_object_alloc(vm);
- diff --git a/njs/njs_object.h b/njs/njs_object.h
- --- a/njs/njs_object.h
- +++ b/njs/njs_object.h
- @@ -51,9 +51,17 @@ typedef struct {
- njs_object_t *prototype;
- uint8_t query;
- uint8_t shared;
- + uint8_t own;
- } njs_property_query_t;
- +#define njs_property_query_init(pq, _query, _own) \
- + do { \
- + (pq)->lhq.key.length = 0; \
- + (pq)->query = _query; \
- + (pq)->own = _own; \
- + } while (0)
- +
- struct njs_object_init_s {
- nxt_str_t name;
- @@ -67,10 +75,12 @@ njs_object_t *njs_object_value_copy(njs_
- njs_object_t *njs_object_value_alloc(njs_vm_t *vm, const njs_value_t *value,
- nxt_uint_t type);
- njs_array_t *njs_object_keys_array(njs_vm_t *vm, const njs_value_t *object);
- +njs_ret_t njs_value_property(njs_vm_t *vm, njs_value_t *value,
- + const njs_value_t *property, njs_value_t *retval);
- njs_object_prop_t *njs_object_property(njs_vm_t *vm, const njs_object_t *obj,
- nxt_lvlhsh_query_t *lhq);
- njs_ret_t njs_property_query(njs_vm_t *vm, njs_property_query_t *pq,
- - njs_value_t *object, njs_value_t *property);
- + njs_value_t *object, const njs_value_t *property);
- nxt_int_t njs_object_hash_create(njs_vm_t *vm, nxt_lvlhsh_t *hash,
- const njs_object_prop_t *prop, nxt_uint_t n);
- njs_ret_t njs_object_constructor(njs_vm_t *vm, njs_value_t *args,
- diff --git a/njs/njs_vm.c b/njs/njs_vm.c
- --- a/njs/njs_vm.c
- +++ b/njs/njs_vm.c
- @@ -476,147 +476,13 @@ njs_ret_t
- njs_vmcode_property_get(njs_vm_t *vm, njs_value_t *object,
- njs_value_t *property)
- {
- - void *obj;
- - int32_t index;
- - uintptr_t data;
- - njs_ret_t ret;
- - njs_value_t *val, ext_val;
- - njs_slice_prop_t slice;
- - njs_string_prop_t string;
- - njs_object_prop_t *prop;
- - const njs_value_t *retval;
- - const njs_extern_t *ext_proto;
- - njs_property_query_t pq;
- -
- - pq.query = NJS_PROPERTY_QUERY_GET;
- -
- - ret = njs_property_query(vm, &pq, object, property);
- -
- - retval = &njs_value_void;
- -
- - switch (ret) {
- -
- - case NXT_OK:
- - prop = pq.lhq.value;
- -
- - switch (prop->type) {
- -
- - case NJS_METHOD:
- - if (pq.shared) {
- - ret = njs_method_private_copy(vm, &pq);
- -
- - if (nxt_slow_path(ret != NXT_OK)) {
- - return ret;
- - }
- -
- - prop = pq.lhq.value;
- - }
- -
- - /* Fall through. */
- -
- - case NJS_PROPERTY:
- - retval = &prop->value;
- - break;
- -
- - default:
- - nxt_thread_log_alert("invalid property get type:%d", prop->type);
- -
- - return NXT_ERROR;
- - }
- -
- - break;
- -
- - case NXT_DECLINED:
- - case NJS_PRIMITIVE_VALUE:
- - break;
- -
- - case NJS_STRING_VALUE:
- -
- - /* string[n]. */
- -
- - index = (int32_t) njs_value_to_index(property);
- -
- - if (nxt_fast_path(index >= 0)) {
- - slice.start = index;
- - slice.length = 1;
- - slice.string_length = njs_string_prop(&string, object);
- -
- - if (slice.start < slice.string_length) {
- - /*
- - * A single codepoint string fits in vm->retval
- - * so the function cannot fail.
- - */
- - (void) njs_string_slice(vm, &vm->retval, &string, &slice);
- -
- - return sizeof(njs_vmcode_prop_get_t);
- - }
- - }
- -
- - break;
- -
- - case NJS_ARRAY_VALUE:
- - val = pq.lhq.value;
- -
- - if (njs_is_valid(val)) {
- - retval = val;
- - }
- -
- - break;
- -
- - case NJS_EXTERNAL_VALUE:
- - ext_proto = object->external.proto;
- -
- - ret = nxt_lvlhsh_find(&ext_proto->hash, &pq.lhq);
- -
- - if (ret == NXT_OK) {
- - ext_proto = pq.lhq.value;
- -
- - ext_val.type = NJS_EXTERNAL;
- - ext_val.data.truth = 1;
- - ext_val.external.proto = ext_proto;
- - ext_val.external.index = object->external.index;
- -
- - if ((ext_proto->type & NJS_EXTERN_OBJECT) != 0) {
- - retval = &ext_val;
- - break;
- - }
- -
- - data = ext_proto->data;
- -
- - } else {
- - data = (uintptr_t) &pq.lhq.key;
- - }
- -
- - vm->retval = njs_value_void;
- -
- - if (ext_proto->get != NULL) {
- - obj = njs_extern_object(vm, object);
- -
- - ret = ext_proto->get(vm, &vm->retval, obj, data);
- - if (nxt_slow_path(ret != NXT_OK)) {
- - return ret;
- - }
- -
- - /* The vm->retval is already retained by ext_proto->get(). */
- - }
- -
- - if (ext_proto->type == NJS_EXTERN_METHOD) {
- - vm->retval.data.u.function = ext_proto->function;
- - vm->retval.type = NJS_FUNCTION;
- - vm->retval.data.truth = 1;
- - }
- -
- - return sizeof(njs_vmcode_prop_get_t);
- -
- - case NJS_TRAP:
- - case NXT_ERROR:
- - default:
- -
- + njs_ret_t ret;
- +
- + ret = njs_value_property(vm, object, property, &vm->retval);
- + if (ret == NXT_ERROR || ret == NJS_TRAP) {
- return ret;
- }
- - vm->retval = *retval;
- -
- /* GC: njs_retain(retval) */
- return sizeof(njs_vmcode_prop_get_t);
- @@ -646,8 +512,7 @@ njs_vmcode_property_set(njs_vm_t *vm, nj
- code = (njs_vmcode_prop_set_t *) vm->current;
- value = njs_vmcode_operand(vm, code->value);
- - pq.lhq.key.length = 0;
- - pq.query = NJS_PROPERTY_QUERY_SET;
- + njs_property_query_init(&pq, NJS_PROPERTY_QUERY_SET, 0);
- ret = njs_property_query(vm, &pq, object, property);
- @@ -767,7 +632,7 @@ njs_vmcode_property_in(njs_vm_t *vm, njs
- retval = &njs_value_false;
- - pq.query = NJS_PROPERTY_QUERY_IN;
- + njs_property_query_init(&pq, NJS_PROPERTY_QUERY_IN, 0);
- ret = njs_property_query(vm, &pq, object, property);
- @@ -851,8 +716,7 @@ njs_vmcode_property_delete(njs_vm_t *vm,
- retval = &njs_value_false;
- - pq.lhq.key.length = 0;
- - pq.query = NJS_PROPERTY_QUERY_DELETE;
- + njs_property_query_init(&pq, NJS_PROPERTY_QUERY_DELETE, 0);
- ret = njs_property_query(vm, &pq, object, property);
- @@ -1097,12 +961,10 @@ njs_ret_t
- njs_vmcode_instance_of(njs_vm_t *vm, njs_value_t *object,
- njs_value_t *constructor)
- {
- - nxt_int_t ret;
- - njs_value_t *value;
- - njs_object_t *prototype, *proto;
- - njs_object_prop_t *prop;
- - const njs_value_t *retval;
- - njs_property_query_t pq;
- + nxt_int_t ret;
- + njs_value_t *value, val;
- + njs_object_t *prototype, *proto;
- + const njs_value_t *retval;
- static njs_value_t prototype_string = njs_string("prototype");
- @@ -1114,13 +976,10 @@ njs_vmcode_instance_of(njs_vm_t *vm, njs
- retval = &njs_value_false;
- if (njs_is_object(object)) {
- - pq.query = NJS_PROPERTY_QUERY_GET;
- -
- - ret = njs_property_query(vm, &pq, constructor, &prototype_string);
- + ret = njs_value_property(vm, constructor, &prototype_string, &val);
- if (nxt_fast_path(ret == NXT_OK)) {
- - prop = pq.lhq.value;
- - value = &prop->value;
- + value = &val;
- /* TODO: test prop->value is object. */
- @@ -2123,9 +1982,7 @@ njs_vmcode_method_frame(njs_vm_t *vm, nj
- method = (njs_vmcode_method_frame_t *) vm->current;
- - pq.lhq.key.length = 0;
- - pq.lhq.key.start = NULL;
- - pq.query = NJS_PROPERTY_QUERY_GET;
- + njs_property_query_init(&pq, NJS_PROPERTY_QUERY_GET, 0);
- ret = njs_property_query(vm, &pq, object, name);
- @@ -2134,6 +1991,16 @@ njs_vmcode_method_frame(njs_vm_t *vm, nj
- case NXT_OK:
- prop = pq.lhq.value;
- + if (prop->type == NJS_PROPERTY_HANDLER) {
- + pq.scratch = *prop;
- + prop = &pq.scratch;
- + ret = prop->value.data.u.prop_handler(vm, object, NULL,
- + &prop->value);
- + if (nxt_slow_path(ret != NXT_OK)) {
- + return ret;
- + }
- + }
- +
- ret = njs_function_frame_create(vm, &prop->value, object, method->nargs,
- method->code.ctor);
- break;
- @@ -3159,6 +3026,45 @@ njs_vmcode_string_argument(njs_vm_t *vm,
- }
- +static njs_ret_t
- +njs_vmcode_restart(njs_vm_t *vm, njs_value_t *invld1, njs_value_t *invld2)
- +{
- + u_char *restart;
- + njs_ret_t ret;
- + njs_value_t *retval, *value1;
- + njs_native_frame_t *frame;
- + njs_vmcode_generic_t *vmcode;
- +
- + frame = vm->top_frame;
- + restart = frame->trap_restart;
- + frame->trap_restart = NULL;
- + vm->current = restart;
- + vmcode = (njs_vmcode_generic_t *) restart;
- +
- + value1 = &frame->trap_values[0];
- +
- + if (frame->trap_reference) {
- + value1 = value1->data.u.value;
- + }
- +
- + ret = vmcode->code.operation(vm, value1, &frame->trap_values[1]);
- +
- + if (nxt_slow_path(ret == NJS_TRAP)) {
- + /* Trap handlers are not reentrant. */
- + njs_internal_error(vm, "trap inside restart instruction");
- + return NXT_ERROR;
- + }
- +
- + retval = njs_vmcode_operand(vm, vmcode->operand1);
- +
- + //njs_release(vm, retval);
- +
- + *retval = vm->retval;
- +
- + return ret;
- +}
- +
- +
- /*
- * A hint value is 0 for numbers and 1 for strings. The value chooses
- * method calls order specified by ECMAScript 5.1: "valueOf", "toString"
- @@ -3257,42 +3163,165 @@ njs_primitive_value(njs_vm_t *vm, njs_va
- }
- -static njs_ret_t
- -njs_vmcode_restart(njs_vm_t *vm, njs_value_t *invld1, njs_value_t *invld2)
- +/*
- + * ES5.1, 8.12.3: [[Get]].
- + * NXT_OK property has been found in object,
- + * retval will contain the property's value
- + *
- + * NXT_DECLINED property was not found in object,
- + * NJS_TRAP the property trap must be called,
- + * NXT_ERROR exception has been thrown.
- + * retval will contain undefined
- + */
- +njs_ret_t
- +njs_value_property(njs_vm_t *vm, njs_value_t *value,
- + const njs_value_t *property, njs_value_t *retval)
- {
- - u_char *restart;
- + void *obj;
- + int32_t index;
- + uintptr_t data;
- njs_ret_t ret;
- - njs_value_t *retval, *value1;
- - njs_native_frame_t *frame;
- - njs_vmcode_generic_t *vmcode;
- -
- - frame = vm->top_frame;
- - restart = frame->trap_restart;
- - frame->trap_restart = NULL;
- - vm->current = restart;
- - vmcode = (njs_vmcode_generic_t *) restart;
- -
- - value1 = &frame->trap_values[0];
- -
- - if (frame->trap_reference) {
- - value1 = value1->data.u.value;
- + njs_value_t *val, ext_val;
- + njs_slice_prop_t slice;
- + njs_string_prop_t string;
- + njs_object_prop_t *prop;
- + const njs_extern_t *ext_proto;
- + njs_property_query_t pq;
- +
- + *retval = njs_value_void;
- +
- + njs_property_query_init(&pq, NJS_PROPERTY_QUERY_GET, 0);
- +
- + ret = njs_property_query(vm, &pq, value, property);
- +
- + switch (ret) {
- +
- + case NXT_OK:
- + prop = pq.lhq.value;
- +
- + switch (prop->type) {
- +
- + case NJS_METHOD:
- + if (pq.shared) {
- + ret = njs_method_private_copy(vm, &pq);
- +
- + if (nxt_slow_path(ret != NXT_OK)) {
- + return ret;
- + }
- +
- + prop = pq.lhq.value;
- + }
- +
- + /* Fall through. */
- +
- + case NJS_PROPERTY:
- + *retval = prop->value;
- + break;
- +
- + case NJS_PROPERTY_HANDLER:
- + pq.scratch = *prop;
- + prop = &pq.scratch;
- + ret = prop->value.data.u.prop_handler(vm, value, NULL,
- + &prop->value);
- +
- + if (nxt_fast_path(ret == NXT_OK)) {
- + *retval = prop->value;
- + }
- +
- + break;
- +
- + default:
- + njs_internal_error(vm, "invalid property get type:%d", prop->type);
- +
- + return NXT_ERROR;
- + }
- +
- + break;
- +
- + case NXT_DECLINED:
- + case NJS_PRIMITIVE_VALUE:
- + break;
- +
- + case NJS_STRING_VALUE:
- +
- + /* string[n]. */
- +
- + index = (int32_t) njs_value_to_index(property);
- +
- + if (nxt_fast_path(index >= 0)) {
- + slice.start = index;
- + slice.length = 1;
- + slice.string_length = njs_string_prop(&string, value);
- +
- + if (slice.start < slice.string_length) {
- + /*
- + * A single codepoint string fits in retval
- + * so the function cannot fail.
- + */
- + (void) njs_string_slice(vm, retval, &string, &slice);
- + }
- + }
- +
- + break;
- +
- + case NJS_ARRAY_VALUE:
- + val = pq.lhq.value;
- +
- + if (njs_is_valid(val)) {
- + *retval = *val;
- + }
- +
- + break;
- +
- + case NJS_EXTERNAL_VALUE:
- + ext_proto = value->external.proto;
- +
- + ret = nxt_lvlhsh_find(&ext_proto->hash, &pq.lhq);
- +
- + if (ret == NXT_OK) {
- + ext_proto = pq.lhq.value;
- +
- + ext_val.type = NJS_EXTERNAL;
- + ext_val.data.truth = 1;
- + ext_val.external.proto = ext_proto;
- + ext_val.external.index = value->external.index;
- +
- + if ((ext_proto->type & NJS_EXTERN_OBJECT) != 0) {
- + *retval = ext_val;
- + break;
- + }
- +
- + data = ext_proto->data;
- +
- + } else {
- + data = (uintptr_t) &pq.lhq.key;
- + }
- +
- + if (ext_proto->get != NULL) {
- + obj = njs_extern_object(vm, value);
- +
- + ret = ext_proto->get(vm, retval, obj, data);
- + if (nxt_slow_path(ret != NXT_OK)) {
- + return ret;
- + }
- + }
- +
- + if (ext_proto->type == NJS_EXTERN_METHOD) {
- + retval->data.u.function = ext_proto->function;
- + retval->type = NJS_FUNCTION;
- + retval->data.truth = 1;
- + }
- +
- + break;
- +
- + case NJS_TRAP:
- + case NXT_ERROR:
- + default:
- +
- + return ret;
- }
- - ret = vmcode->code.operation(vm, value1, &frame->trap_values[1]);
- -
- - if (nxt_slow_path(ret == NJS_TRAP)) {
- - /* Trap handlers are not reentrant. */
- - njs_internal_error(vm, "trap inside restart instruction");
- - return NXT_ERROR;
- - }
- -
- - retval = njs_vmcode_operand(vm, vmcode->operand1);
- -
- - //njs_release(vm, retval);
- -
- - *retval = vm->retval;
- -
- - return ret;
- + return (ret == NXT_OK) ? NXT_OK : NXT_DECLINED;
- }
- diff --git a/njs/test/njs_unit_test.c b/njs/test/njs_unit_test.c
- --- a/njs/test/njs_unit_test.c
- +++ b/njs/test/njs_unit_test.c
- @@ -7001,9 +7001,18 @@ static njs_unit_test_t njs_test[] =
- { nxt_string("Object.getOwnPropertyDescriptor([3,4], 1).value"),
- nxt_string("4") },
- + { nxt_string("Object.getOwnPropertyDescriptor(Object.create({a:1}), 'a')"),
- + nxt_string("undefined") },
- +
- { nxt_string("Object.getOwnPropertyDescriptor([], 'length').value"),
- nxt_string("0") },
- + { nxt_string("Object.getOwnPropertyDescriptor(Array.of, 'length').value"),
- + nxt_string("0") },
- +
- + { nxt_string("JSON.stringify(Object.getOwnPropertyDescriptor(new String('abc'), 'length'))"),
- + nxt_string("{\"value\":3,\"configurable\":false,\"enumerable\":false,\"writable\":false}") },
- +
- { nxt_string("JSON.stringify(Object.getOwnPropertyDescriptor([3,4], 'length'))"),
- nxt_string("{\"value\":2,\"configurable\":false,\"enumerable\":false,\"writable\":true}") },
- # HG changeset patch
- # User Dmitry Volyntsev <xeioex@nginx.com>
- # Date 1536860015 -10800
- # Thu Sep 13 20:33:35 2018 +0300
- # Node ID b9a1326c940d11f303c3d6328dcd1557d20d507f
- # Parent ffe3b161805980547f16f3ff1142fc55f3f628ca
- Fixed delete operator.
- # HG changeset patch
- # User Dmitry Volyntsev <xeioex@nginx.com>
- # Date 1536860015 -10800
- # Thu Sep 13 20:33:35 2018 +0300
- # Node ID b85d3a6cf1eafd0f6d8b43d61f8e6421282a55ef
- # Parent b9a1326c940d11f303c3d6328dcd1557d20d507f
- Added njs_primitive_value_to_number().
- diff --git a/njs/njs_number.c b/njs/njs_number.c
- --- a/njs/njs_number.c
- +++ b/njs/njs_number.c
- @@ -64,6 +64,24 @@ njs_value_to_index(const njs_value_t *va
- double
- +njs_primitive_value_to_number(const njs_value_t *value)
- +{
- + if (nxt_fast_path(njs_is_numeric(value))) {
- + return value->data.u.number;
- + }
- +
- + return njs_string_to_number(value, 1);
- +}
- +
- +
- +uint32_t
- +njs_primitive_value_to_uint32(const njs_value_t *value)
- +{
- + return njs_number_to_integer(njs_primitive_value_to_number(value));
- +}
- +
- +
- +double
- njs_number_dec_parse(const u_char **start, const u_char *end)
- {
- return nxt_strtod(start, end);
- diff --git a/njs/njs_number.h b/njs/njs_number.h
- --- a/njs/njs_number.h
- +++ b/njs/njs_number.h
- @@ -13,6 +13,8 @@
- uint32_t njs_value_to_index(const njs_value_t *value);
- +double njs_primitive_value_to_number(const njs_value_t *value);
- +uint32_t njs_primitive_value_to_uint32(const njs_value_t *value);
- double njs_number_dec_parse(const u_char **start, const u_char *end);
- uint64_t njs_number_oct_parse(const u_char **start, const u_char *end);
- uint64_t njs_number_bin_parse(const u_char **start, const u_char *end);
- # HG changeset patch
- # User Dmitry Volyntsev <xeioex@nginx.com>
- # Date 1536860016 -10800
- # Thu Sep 13 20:33:36 2018 +0300
- # Node ID b87565896b6efc8ac59da011665ed1acbc23a1e6
- # Parent b85d3a6cf1eafd0f6d8b43d61f8e6421282a55ef
- Fixed String.slice() for undefined arguments.
- diff --git a/njs/njs_string.c b/njs/njs_string.c
- --- a/njs/njs_string.c
- +++ b/njs/njs_string.c
- @@ -1239,45 +1239,43 @@ njs_string_slice_args(njs_slice_prop_t *
- ssize_t start, end, length;
- length = slice->string_length;
- - start = 0;
- -
- - if (nargs > 1) {
- - start = args[1].data.u.number;
- +
- + start = njs_arg(args, nargs, 1)->data.u.number;
- +
- + if (start < 0) {
- + start += length;
- if (start < 0) {
- - start += length;
- -
- - if (start < 0) {
- - start = 0;
- - }
- + start = 0;
- }
- -
- - if (start >= length) {
- - start = 0;
- - length = 0;
- + }
- +
- + if (start >= length) {
- + start = 0;
- + length = 0;
- +
- + } else {
- + if (!njs_is_void(njs_arg(args, nargs, 2))) {
- + end = njs_arg(args, nargs, 2)->data.u.number;
- } else {
- end = length;
- -
- - if (nargs > 2) {
- - end = args[2].data.u.number;
- -
- - if (end < 0) {
- - end += length;
- - }
- + }
- +
- + if (end < 0) {
- + end += length;
- + }
- +
- + if (length >= end) {
- + length = end - start;
- +
- + if (length < 0) {
- + start = 0;
- + length = 0;
- }
- - if (length >= end) {
- - length = end - start;
- -
- - if (length < 0) {
- - start = 0;
- - length = 0;
- - }
- -
- - } else {
- - length -= start;
- - }
- + } else {
- + length -= start;
- }
- }
- diff --git a/njs/test/njs_unit_test.c b/njs/test/njs_unit_test.c
- --- a/njs/test/njs_unit_test.c
- +++ b/njs/test/njs_unit_test.c
- @@ -3800,6 +3800,18 @@ static njs_unit_test_t njs_test[] =
- { nxt_string("'abcdefgh'.slice(3)"),
- nxt_string("defgh") },
- + { nxt_string("'abcdefgh'.slice(undefined, undefined)"),
- + nxt_string("abcdefgh") },
- +
- + { nxt_string("'abcdefgh'.slice(undefined)"),
- + nxt_string("abcdefgh") },
- +
- + { nxt_string("'abcdefgh'.slice(undefined, 1)"),
- + nxt_string("a") },
- +
- + { nxt_string("'abcdefgh'.slice(3, undefined)"),
- + nxt_string("defgh") },
- +
- { nxt_string("'abcde'.slice(50)"),
- nxt_string("") },
- # HG changeset patch
- # User Dmitry Volyntsev <xeioex@nginx.com>
- # Date 1536860016 -10800
- # Thu Sep 13 20:33:36 2018 +0300
- # Node ID 96e1d261f0b2c36a797c139b4fb689fe535d0ea8
- # Parent b87565896b6efc8ac59da011665ed1acbc23a1e6
- Added njs_string_slice_string_prop().
- diff --git a/njs/njs_string.c b/njs/njs_string.c
- --- a/njs/njs_string.c
- +++ b/njs/njs_string.c
- @@ -1284,46 +1284,60 @@ njs_string_slice_args(njs_slice_prop_t *
- }
- +nxt_noinline void
- +njs_string_slice_string_prop(njs_string_prop_t *dst,
- + const njs_string_prop_t *string, const njs_slice_prop_t *slice)
- +{
- + size_t size, n, length;
- + const u_char *p, *start, *end;
- +
- + length = slice->length;
- + start = string->start;
- +
- + if (string->size == slice->string_length) {
- + /* Byte or ASCII string. */
- + start += slice->start;
- + size = slice->length;
- +
- + if (string->length == 0) {
- + /* Byte string. */
- + length = 0;
- + }
- +
- + } else {
- + /* UTF-8 string. */
- + end = start + string->size;
- + start = njs_string_offset(start, end, slice->start);
- +
- + /* Evaluate size of the slice in bytes and ajdust length. */
- + p = start;
- + n = length;
- +
- + do {
- + p = nxt_utf8_next(p, end);
- + n--;
- + } while (n != 0 && p < end);
- +
- + size = p - start;
- + length -= n;
- + }
- +
- + dst->start = (u_char *) start;
- + dst->length = length;
- + dst->size = size;
- +}
- +
- +
- nxt_noinline njs_ret_t
- njs_string_slice(njs_vm_t *vm, njs_value_t *dst,
- const njs_string_prop_t *string, const njs_slice_prop_t *slice)
- {
- - size_t size, n, length;
- - const u_char *p, *start, *end;
- -
- - length = slice->length;
- - start = string->start;
- -
- - if (string->size == slice->string_length) {
- - /* Byte or ASCII string. */
- - start += slice->start;
- - size = slice->length;
- -
- - if (string->length == 0) {
- - /* Byte string. */
- - length = 0;
- - }
- -
- - } else {
- - /* UTF-8 string. */
- - end = start + string->size;
- - start = njs_string_offset(start, end, slice->start);
- -
- - /* Evaluate size of the slice in bytes and ajdust length. */
- - p = start;
- - n = length;
- -
- - do {
- - p = nxt_utf8_next(p, end);
- - n--;
- - } while (n != 0 && p < end);
- -
- - size = p - start;
- - length -= n;
- - }
- -
- - if (nxt_fast_path(size != 0)) {
- - return njs_string_new(vm, dst, start, size, length);
- + njs_string_prop_t prop;
- +
- + njs_string_slice_string_prop(&prop, string, slice);
- +
- + if (nxt_fast_path(prop.size != 0)) {
- + return njs_string_new(vm, dst, prop.start, prop.size, prop.length);
- }
- *dst = njs_string_empty;
- diff --git a/njs/njs_string.h b/njs/njs_string.h
- --- a/njs/njs_string.h
- +++ b/njs/njs_string.h
- @@ -145,6 +145,8 @@ njs_ret_t njs_string_constructor(njs_vm_
- nxt_uint_t nargs, njs_index_t unused);
- nxt_bool_t njs_string_eq(const njs_value_t *val1, const njs_value_t *val2);
- nxt_int_t njs_string_cmp(const njs_value_t *val1, const njs_value_t *val2);
- +nxt_noinline void njs_string_slice_string_prop(njs_string_prop_t *dst,
- + const njs_string_prop_t *string, const njs_slice_prop_t *slice);
- njs_ret_t njs_string_slice(njs_vm_t *vm, njs_value_t *dst,
- const njs_string_prop_t *string, const njs_slice_prop_t *slice);
- const u_char *njs_string_offset(const u_char *start, const u_char *end,
- # HG changeset patch
- # User Dmitry Volyntsev <xeioex@nginx.com>
- # Date 1536860017 -10800
- # Thu Sep 13 20:33:37 2018 +0300
- # Node ID 0b601d903078774410f9c44ee3554c7e9b7db6ee
- # Parent 96e1d261f0b2c36a797c139b4fb689fe535d0ea8
- Hanling non-array values properly in Array.prototype.slice.
- diff --git a/njs/njs_array.c b/njs/njs_array.c
- --- a/njs/njs_array.c
- +++ b/njs/njs_array.c
- @@ -9,6 +9,19 @@
- typedef struct {
- + union {
- + njs_continuation_t cont;
- + u_char padding[NJS_CONTINUATION_SIZE];
- + } u;
- + /*
- + * This retval value must be aligned so the continuation is padded
- + * to aligned size.
- + */
- + njs_value_t length;
- +} njs_array_slice_t;
- +
- +
- +typedef struct {
- njs_continuation_t cont;
- njs_value_t *values;
- uint32_t max;
- @@ -67,6 +80,8 @@ typedef struct {
- } njs_array_sort_t;
- +static njs_ret_t njs_array_prototype_slice_continuation(njs_vm_t *vm,
- + njs_value_t *args, nxt_uint_t nargs, njs_index_t unused);
- static njs_ret_t njs_array_prototype_to_string_continuation(njs_vm_t *vm,
- njs_value_t *args, nxt_uint_t nargs, njs_index_t retval);
- static njs_ret_t njs_array_prototype_join_continuation(njs_vm_t *vm,
- @@ -434,55 +449,87 @@ static njs_ret_t
- njs_array_prototype_slice(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs,
- njs_index_t unused)
- {
- - int32_t start, end, length;
- - uint32_t n;
- - njs_array_t *array;
- - njs_value_t *value;
- + njs_ret_t ret;
- + njs_array_slice_t *slice;
- +
- + static const njs_value_t njs_string_length = njs_string("length");
- +
- + slice = njs_vm_continuation(vm);
- + slice->u.cont.function = njs_array_prototype_slice_continuation;
- +
- + ret = njs_value_property(vm, &args[0], &njs_string_length, &slice->length);
- + if (nxt_slow_path(ret == NXT_ERROR || ret == NJS_TRAP)) {
- + return ret;
- + }
- +
- + return njs_array_prototype_slice_continuation(vm, args, nargs, unused);
- +}
- +
- +
- +static njs_ret_t
- +njs_array_prototype_slice_continuation(njs_vm_t *vm, njs_value_t *args,
- + nxt_uint_t nargs, njs_index_t unused)
- +{
- + size_t size;
- + u_char *dst;
- + int32_t start, end;
- + int64_t length;
- + uint32_t n;
- + njs_ret_t ret;
- + njs_array_t *array;
- + njs_value_t *value, name, retval, *this;
- + const u_char *src, *last;
- + njs_slice_prop_t string_slice;
- + njs_array_slice_t *slice;
- + njs_string_prop_t string;
- start = 0;
- - length = 0;
- -
- - if (njs_is_array(&args[0])) {
- - length = args[0].data.u.array->length;
- -
- - if (nargs > 1) {
- - start = args[1].data.u.number;
- -
- - if (start < 0) {
- - start += length;
- -
- - if (start < 0) {
- - start = 0;
- - }
- - }
- -
- - if (start >= length) {
- +
- + slice = njs_vm_continuation(vm);
- +
- + if (nxt_slow_path(!njs_is_primitive(&slice->length))) {
- + njs_vm_trap_value(vm, &slice->length);
- + return njs_trap(vm, NJS_TRAP_NUMBER_ARG);
- + }
- +
- + length = njs_primitive_value_to_uint32(&slice->length);
- +
- + start = njs_arg(args, nargs, 1)->data.u.number;
- +
- + if (start < 0) {
- + start += length;
- +
- + if (start < 0) {
- + start = 0;
- + }
- + }
- +
- + if (start >= length) {
- + start = 0;
- + length = 0;
- +
- + } else {
- + if (!njs_is_void(njs_arg(args, nargs, 2))) {
- + end = njs_arg(args, nargs, 2)->data.u.number;
- +
- + } else {
- + end = length;
- + }
- +
- + if (end < 0) {
- + end += length;
- + }
- +
- + if (length >= end) {
- + length = end - start;
- +
- + if (length < 0) {
- start = 0;
- length = 0;
- -
- - } else {
- - end = length;
- -
- - if (nargs > 2) {
- - end = args[2].data.u.number;
- -
- - if (end < 0) {
- - end += length;
- - }
- - }
- -
- - if (length >= end) {
- - length = end - start;
- -
- - if (length < 0) {
- - start = 0;
- - length = 0;
- - }
- -
- - } else {
- - length -= start;
- - }
- }
- +
- + } else {
- + length -= start;
- }
- }
- @@ -496,14 +543,56 @@ njs_array_prototype_slice(njs_vm_t *vm,
- vm->retval.data.truth = 1;
- if (length != 0) {
- - value = args[0].data.u.array->start;
- n = 0;
- -
- - do {
- - /* GC: retain long string and object in values[start]. */
- - array->start[n++] = value[start++];
- - length--;
- - } while (length != 0);
- + this = &args[0];
- +
- + if (nxt_fast_path(njs_is_array(this))) {
- + value = this->data.u.array->start;
- +
- + do {
- + /* GC: retain long string and object in values[start]. */
- + array->start[n++] = value[start++];
- + length--;
- + } while (length != 0);
- +
- + } else if (njs_is_string(this) || this->type == NJS_OBJECT_STRING) {
- +
- + if (this->type == NJS_OBJECT_STRING) {
- + this = &this->data.u.object_value->value;
- + }
- +
- + string_slice.start = start;
- + string_slice.length = length;
- + string_slice.string_length = njs_string_prop(&string, this);
- +
- + njs_string_slice_string_prop(&string, &string, &string_slice);
- +
- + src = string.start;
- + last = src + string.size;
- +
- + do {
- + value = &array->start[n++];
- + dst = njs_string_short_start(value);
- + dst = nxt_utf8_copy(dst, &src, last);
- + size = dst - njs_string_short_start(value);
- + njs_string_short_set(value, size, (size == 1) ? 0 : 1);
- +
- + length--;
- + } while (length != 0);
- +
- +
- + } else if (njs_is_object(this)) {
- +
- + do {
- + njs_uint32_to_string(&name, start++);
- +
- + ret = njs_value_property(vm, this, &name, &retval);
- +
- + array->start[n++] = (ret == NXT_OK) ? retval
- + : njs_value_invalid;
- + length--;
- + } while (length != 0);
- + }
- }
- return NXT_OK;
- @@ -2101,7 +2190,8 @@ static const njs_object_prop_t njs_arra
- {
- .type = NJS_METHOD,
- .name = njs_string("slice"),
- - .value = njs_native_function(njs_array_prototype_slice, 0,
- + .value = njs_native_function(njs_array_prototype_slice,
- + njs_continuation_size(njs_array_slice_t),
- NJS_OBJECT_ARG, NJS_INTEGER_ARG, NJS_INTEGER_ARG),
- },
- diff --git a/njs/njs_object_hash.h b/njs/njs_object_hash.h
- --- a/njs/njs_object_hash.h
- +++ b/njs/njs_object_hash.h
- @@ -108,6 +108,16 @@
- 'j'), 'o'), 'i'), 'n')
- +#define NJS_LENGTH_HASH \
- + nxt_djb_hash_add( \
- + nxt_djb_hash_add( \
- + nxt_djb_hash_add( \
- + nxt_djb_hash_add( \
- + nxt_djb_hash_add( \
- + nxt_djb_hash_add(NXT_DJB_HASH_INIT, \
- + 'l'), 'e'), 'n'), 'g'), 't'), 'h')
- +
- +
- #define NJS_NAME_HASH \
- nxt_djb_hash_add( \
- nxt_djb_hash_add( \
- diff --git a/njs/test/njs_unit_test.c b/njs/test/njs_unit_test.c
- --- a/njs/test/njs_unit_test.c
- +++ b/njs/test/njs_unit_test.c
- @@ -2981,12 +2981,93 @@ static njs_unit_test_t njs_test[] =
- { nxt_string("Array.prototype.slice(1,2)"),
- nxt_string("") },
- + { nxt_string("Array.prototype.slice.call(undefined)"),
- + nxt_string("TypeError: cannot convert void to object") },
- +
- + { nxt_string("Array.prototype.slice.call(1)"),
- + nxt_string("") },
- +
- + { nxt_string("Array.prototype.slice.call(false)"),
- + nxt_string("") },
- +
- + { nxt_string("Array.prototype.slice.call({'0':'a', '1':'b', length:1})"),
- + nxt_string("a") },
- +
- + { nxt_string("Array.prototype.slice.call({'0':'a', '1':'b', length:2})"),
- + nxt_string("a,b") },
- +
- + { nxt_string("Array.prototype.slice.call({'0':'a', '1':'b', length:4})"),
- + nxt_string("a,b,,") },
- +
- + { nxt_string("Array.prototype.slice.call({'0':'a', '1':'b', length:2}, 1)"),
- + nxt_string("b") },
- +
- + { nxt_string("Array.prototype.slice.call({'0':'a', '1':'b', length:2}, 1, 2)"),
- + nxt_string("b") },
- +
- + { nxt_string("Array.prototype.slice.call({length:'2'})"),
- + nxt_string(",") },
- +
- + { nxt_string("njs.dump(Array.prototype.slice.call({length: 3, 1: undefined }))"),
- + nxt_string("[<empty>,undefined,<empty>]") },
- +
- + { nxt_string("Array.prototype.slice.call({length:new Number(3)})"),
- + nxt_string(",,") },
- +
- + { nxt_string("Array.prototype.slice.call({length: { valueOf: function() { return 2; } }})"),
- + nxt_string(",") },
- +
- + { nxt_string("Array.prototype.slice.call({ length: Object.create(null) })"),
- + nxt_string("TypeError: Cannot convert object to primitive value") },
- +
- + { nxt_string("Array.prototype.slice.call({length:-1})"),
- + nxt_string("MemoryError") },
- +
- + { nxt_string("Array.prototype.slice.call('αβZγ')"),
- + nxt_string("α,β,Z,γ") },
- +
- + { nxt_string("Array.prototype.slice.call('αβZγ', 1)"),
- + nxt_string("β,Z,γ") },
- +
- + { nxt_string("Array.prototype.slice.call('αβZγ', 2)"),
- + nxt_string("Z,γ") },
- +
- + { nxt_string("Array.prototype.slice.call('αβZγ', 3)"),
- + nxt_string("γ") },
- +
- + { nxt_string("Array.prototype.slice.call('αβZγ', 4)"),
- + nxt_string("") },
- +
- + { nxt_string("Array.prototype.slice.call('αβZγ', 0, 1)"),
- + nxt_string("α") },
- +
- + { nxt_string("Array.prototype.slice.call('αβZγ', 1, 2)"),
- + nxt_string("β") },
- +
- + { nxt_string("Array.prototype.slice.call('αβZγ').length"),
- + nxt_string("4") },
- +
- + { nxt_string("Array.prototype.slice.call('αβZγ')[1].length"),
- + nxt_string("1") },
- +
- + { nxt_string("Array.prototype.slice.call(new String('αβZγ'))"),
- + nxt_string("α,β,Z,γ") },
- +
- { nxt_string("Array.prototype.pop()"),
- nxt_string("undefined") },
- { nxt_string("Array.prototype.shift()"),
- nxt_string("undefined") },
- + { nxt_string("[0,1].slice()"),
- + nxt_string("0,1") },
- +
- + { nxt_string("[0,1].slice(undefined)"),
- + nxt_string("0,1") },
- +
- + { nxt_string("[0,1].slice(undefined, undefined)"),
- + nxt_string("0,1") },
- +
- { nxt_string("[0,1,2,3,4].slice(1,4)"),
- nxt_string("1,2,3") },
- @@ -9442,6 +9523,9 @@ static njs_unit_test_t njs_test[] =
- { nxt_string("njs.dump({a:1, b:[1,,2,{c:new Boolean(1)}]})"),
- nxt_string("{a:1,b:[1,<empty>,2,{c:[Boolean: true]}]}") },
- + { nxt_string("njs.dump(Array.prototype.slice.call({'1':'b', length:2}))"),
- + nxt_string("[<empty>,'b']") },
- +
- { nxt_string("njs.dump($r.props)"),
- nxt_string("{a:{type:\"property\",props:[\"getter\"]},b:{type:\"property\",props:[\"getter\"]}}") },
- # HG changeset patch
- # User Dmitry Volyntsev <xeioex@nginx.com>
- # Date 1536860117 -10800
- # Thu Sep 13 20:35:17 2018 +0300
- # Node ID fb2b4c6ac8b022a4530428ad744e9297a342906a
- # Parent 0b601d903078774410f9c44ee3554c7e9b7db6ee
- Added arguments object.
- This closes #19 issue on Github.
- diff --git a/njs/njs_disassembler.c b/njs/njs_disassembler.c
- --- a/njs/njs_disassembler.c
- +++ b/njs/njs_disassembler.c
- @@ -24,6 +24,8 @@ static njs_code_name_t code_names[] = {
- nxt_string("OBJECT ") },
- { njs_vmcode_function, sizeof(njs_vmcode_function_t),
- nxt_string("FUNCTION ") },
- + { njs_vmcode_arguments, sizeof(njs_vmcode_arguments_t),
- + nxt_string("ARGUMENTS ") },
- { njs_vmcode_regexp, sizeof(njs_vmcode_regexp_t),
- nxt_string("REGEXP ") },
- { njs_vmcode_object_copy, sizeof(njs_vmcode_object_copy_t),
- diff --git a/njs/njs_function.c b/njs/njs_function.c
- --- a/njs/njs_function.c
- +++ b/njs/njs_function.c
- @@ -8,6 +8,8 @@
- #include <string.h>
- +static njs_ret_t njs_function_arguments_thrower(njs_vm_t *vm,
- + njs_value_t *value, njs_value_t *setval, njs_value_t *retval);
- static njs_ret_t njs_function_activate(njs_vm_t *vm, njs_function_t *function,
- njs_value_t *this, njs_value_t *args, nxt_uint_t nargs, njs_index_t retval);
- @@ -95,6 +97,137 @@ njs_function_value_copy(njs_vm_t *vm, nj
- }
- +/*
- + * ES5.1, 10.6: CreateArgumentsObject.
- + */
- +njs_ret_t
- +njs_function_arguments_object_init(njs_vm_t *vm, njs_native_frame_t *frame)
- +{
- + nxt_int_t ret;
- + nxt_uint_t nargs, n;
- + njs_value_t val, *value;
- + njs_object_t *obj;
- + njs_object_prop_t *prop;
- + nxt_lvlhsh_query_t lhq;
- +
- + static const njs_value_t njs_string_length = njs_string("length");
- + static const njs_value_t njs_string_callee = njs_string("callee");
- + static const njs_value_t njs_string_caller = njs_string("caller");
- +
- + obj = njs_object_alloc(vm);
- + if (nxt_slow_path(obj == NULL)) {
- + return NXT_ERROR;
- + }
- +
- + nargs = frame->nargs;
- +
- + value = &val;
- + njs_value_number_set(value, nargs);
- +
- + prop = njs_object_prop_alloc(vm, &njs_string_length, value, 1);
- + if (nxt_slow_path(prop == NULL)) {
- + return NXT_ERROR;
- + }
- +
- + prop->enumerable = 0;
- +
- + lhq.value = prop;
- + lhq.key_hash = NJS_LENGTH_HASH;
- + njs_string_get(&prop->name, &lhq.key);
- +
- + lhq.replace = 0;
- + lhq.pool = vm->mem_cache_pool;
- + lhq.proto = &njs_object_hash_proto;
- +
- + ret = nxt_lvlhsh_insert(&obj->hash, &lhq);
- +
- + if (nxt_slow_path(ret != NXT_OK)) {
- + njs_internal_error(vm, "lvlhsh insert failed");
- + return NXT_ERROR;
- + }
- +
- + prop = njs_object_prop_handler_alloc(vm, &njs_string_callee,
- + njs_function_arguments_thrower, 0);
- + if (nxt_slow_path(prop == NULL)) {
- + return NXT_ERROR;
- + }
- +
- + lhq.value = prop;
- + njs_string_get(&prop->name, &lhq.key);
- + lhq.key_hash = nxt_djb_hash(lhq.key.start, lhq.key.length);
- +
- + lhq.replace = 0;
- + lhq.pool = vm->mem_cache_pool;
- + lhq.proto = &njs_object_hash_proto;
- +
- + ret = nxt_lvlhsh_insert(&obj->hash, &lhq);
- +
- + if (nxt_slow_path(ret != NXT_OK)) {
- + njs_internal_error(vm, "lvlhsh insert failed");
- + return NXT_ERROR;
- + }
- +
- + prop = njs_object_prop_handler_alloc(vm, &njs_string_caller,
- + njs_function_arguments_thrower, 0);
- + if (nxt_slow_path(prop == NULL)) {
- + return NXT_ERROR;
- + }
- +
- + lhq.value = prop;
- + njs_string_get(&prop->name, &lhq.key);
- + lhq.key_hash = nxt_djb_hash(lhq.key.start, lhq.key.length);
- +
- + lhq.replace = 0;
- + lhq.pool = vm->mem_cache_pool;
- + lhq.proto = &njs_object_hash_proto;
- +
- + ret = nxt_lvlhsh_insert(&obj->hash, &lhq);
- +
- + if (nxt_slow_path(ret != NXT_OK)) {
- + njs_internal_error(vm, "lvlhsh insert failed");
- + return NXT_ERROR;
- + }
- +
- + for (n = 0; n < nargs; n++) {
- + njs_uint32_to_string(&val, n);
- +
- + prop = njs_object_prop_alloc(vm, &val, &frame->arguments[n + 1], 1);
- + if (nxt_slow_path(prop == NULL)) {
- + return NXT_ERROR;
- + }
- +
- + lhq.value = prop;
- + njs_string_get(&prop->name, &lhq.key);
- + lhq.key_hash = nxt_djb_hash(lhq.key.start, lhq.key.length);
- +
- + lhq.replace = 0;
- + lhq.pool = vm->mem_cache_pool;
- + lhq.proto = &njs_object_hash_proto;
- +
- + ret = nxt_lvlhsh_insert(&obj->hash, &lhq);
- +
- + if (nxt_slow_path(ret != NXT_OK)) {
- + njs_internal_error(vm, "lvlhsh insert failed");
- + return NXT_ERROR;
- + }
- +
- + }
- +
- + frame->arguments_object = obj;
- +
- + return NXT_OK;
- +}
- +
- +
- +static njs_ret_t
- +njs_function_arguments_thrower(njs_vm_t *vm, njs_value_t *value,
- + njs_value_t *setval, njs_value_t *retval)
- +{
- + njs_type_error(vm, "'caller', 'callee' properties may not be accessed");
- + return NXT_ERROR;
- +}
- +
- +
- njs_ret_t
- njs_function_native_frame(njs_vm_t *vm, njs_function_t *function,
- const njs_value_t *this, njs_value_t *args, nxt_uint_t nargs,
- @@ -315,6 +448,7 @@ nxt_noinline njs_ret_t
- njs_function_call(njs_vm_t *vm, njs_index_t retval, size_t advance)
- {
- size_t size;
- + njs_ret_t ret;
- nxt_uint_t n, nesting;
- njs_frame_t *frame;
- njs_value_t *value;
- @@ -393,6 +527,13 @@ njs_function_call(njs_vm_t *vm, njs_inde
- vm->scopes[NJS_SCOPE_CLOSURE + n] = &closure->u.values;
- }
- + if (lambda->arguments_object) {
- + ret = njs_function_arguments_object_init(vm, &frame->native);
- + if (nxt_slow_path(ret != NXT_OK)) {
- + return NXT_ERROR;
- + }
- + }
- +
- vm->active_frame = frame;
- return NJS_APPLIED;
- diff --git a/njs/njs_function.h b/njs/njs_function.h
- --- a/njs/njs_function.h
- +++ b/njs/njs_function.h
- @@ -30,6 +30,8 @@ struct njs_function_lambda_s {
- /* Function internal block closures levels. */
- uint8_t block_closures; /* 4 bits */
- + uint8_t arguments_object;/* 1 bit */
- +
- /* Initial values of local scope. */
- njs_value_t *local_scope;
- @@ -102,7 +104,9 @@ struct njs_native_frame_s {
- njs_function_t *function;
- njs_native_frame_t *previous;
- +
- njs_value_t *arguments;
- + njs_object_t *arguments_object;
- njs_exception_t exception;
- @@ -147,6 +151,8 @@ struct njs_frame_s {
- njs_function_t *njs_function_alloc(njs_vm_t *vm);
- 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_arguments_object_init(njs_vm_t *vm,
- + njs_native_frame_t *frame);
- njs_ret_t njs_function_prototype_create(njs_vm_t *vm, njs_value_t *value,
- njs_value_t *setval, njs_value_t *retval);
- njs_value_t *njs_function_property_prototype_create(njs_vm_t *vm,
- diff --git a/njs/njs_generator.c b/njs/njs_generator.c
- --- a/njs/njs_generator.c
- +++ b/njs/njs_generator.c
- @@ -14,6 +14,8 @@ static nxt_int_t njs_generate_name(njs_v
- njs_parser_node_t *node);
- static nxt_int_t njs_generate_builtin_object(njs_vm_t *vm, njs_parser_t *parser,
- njs_parser_node_t *node);
- +static nxt_int_t njs_generate_arguments_object(njs_vm_t *vm,
- + njs_parser_t *parser, njs_parser_node_t *node);
- static nxt_int_t njs_generate_variable(njs_vm_t *vm, njs_parser_t *parser,
- njs_parser_node_t *node);
- static nxt_int_t njs_generate_var_statement(njs_vm_t *vm, njs_parser_t *parser,
- @@ -308,6 +310,9 @@ njs_generator(njs_vm_t *vm, njs_parser_t
- case NJS_TOKEN_CLEAR_TIMEOUT:
- return njs_generate_builtin_object(vm, parser, node);
- + case NJS_TOKEN_ARGUMENTS:
- + return njs_generate_arguments_object(vm, parser, node);
- +
- case NJS_TOKEN_FUNCTION:
- return njs_generate_function_declaration(vm, parser, node);
- @@ -396,6 +401,29 @@ njs_generate_builtin_object(njs_vm_t *vm
- static nxt_int_t
- +njs_generate_arguments_object(njs_vm_t *vm, njs_parser_t *parser,
- + njs_parser_node_t *node)
- +{
- + njs_vmcode_arguments_t *gen;
- +
- + parser->arguments_object = 1;
- +
- + node->index = njs_generator_object_dest_index(vm, parser, node);
- + if (nxt_slow_path(node->index == NJS_INDEX_ERROR)) {
- + return NXT_ERROR;
- + }
- +
- + njs_generate_code(parser, njs_vmcode_arguments_t, gen);
- + gen->code.operation = njs_vmcode_arguments;
- + gen->code.operands = NJS_VMCODE_1OPERAND;
- + gen->code.retval = NJS_VMCODE_RETVAL;
- + gen->retval = node->index;
- +
- + return NXT_OK;
- +}
- +
- +
- +static nxt_int_t
- njs_generate_variable(njs_vm_t *vm, njs_parser_t *parser,
- njs_parser_node_t *node)
- {
- @@ -2010,6 +2038,7 @@ njs_generate_function_scope(njs_vm_t *vm
- parser->code_size += node->scope->argument_closures
- * sizeof(njs_vmcode_move_t);
- + parser->arguments_object = 0;
- ret = njs_generate_scope(vm, parser, node);
- if (nxt_fast_path(ret == NXT_OK)) {
- @@ -2023,6 +2052,7 @@ njs_generate_function_scope(njs_vm_t *vm
- lambda->nesting = node->scope->nesting;
- lambda->closure_size = size;
- + lambda->arguments_object = parser->arguments_object;
- lambda->local_size = parser->scope_size;
- lambda->local_scope = parser->local_scope;
- diff --git a/njs/njs_lexer_keyword.c b/njs/njs_lexer_keyword.c
- --- a/njs/njs_lexer_keyword.c
- +++ b/njs/njs_lexer_keyword.c
- @@ -53,6 +53,7 @@ static const njs_keyword_t njs_keywords
- /* Builtin objects. */
- { nxt_string("this"), NJS_TOKEN_THIS, 0 },
- + { nxt_string("arguments"), NJS_TOKEN_ARGUMENTS, 0 },
- { nxt_string("njs"), NJS_TOKEN_NJS, 0 },
- { nxt_string("Math"), NJS_TOKEN_MATH, 0 },
- { nxt_string("JSON"), NJS_TOKEN_JSON, 0 },
- diff --git a/njs/njs_object.c b/njs/njs_object.c
- --- a/njs/njs_object.c
- +++ b/njs/njs_object.c
- @@ -203,6 +203,36 @@ njs_object_prop_alloc(njs_vm_t *vm, cons
- nxt_noinline njs_object_prop_t *
- +njs_object_prop_handler_alloc(njs_vm_t *vm, const njs_value_t *name,
- + njs_prop_handler_t handler, uint8_t attributes)
- +{
- + njs_object_prop_t *prop;
- +
- + prop = nxt_mem_cache_align(vm->mem_cache_pool, sizeof(njs_value_t),
- + sizeof(njs_object_prop_t));
- +
- + if (nxt_fast_path(prop != NULL)) {
- + /* GC: retain. */
- + njs_set_invalid(&prop->value);
- + prop->value.data.u.prop_handler = handler;
- +
- + /* GC: retain. */
- + prop->name = *name;
- +
- + prop->type = NJS_PROPERTY_HANDLER;
- + prop->enumerable = attributes;
- + prop->writable = attributes;
- + prop->configurable = attributes;
- + return prop;
- + }
- +
- + njs_memory_error(vm);
- +
- + return NULL;
- +}
- +
- +
- +nxt_noinline njs_object_prop_t *
- njs_object_property(njs_vm_t *vm, const njs_object_t *object,
- nxt_lvlhsh_query_t *lhq)
- {
- diff --git a/njs/njs_object.h b/njs/njs_object.h
- --- a/njs/njs_object.h
- +++ b/njs/njs_object.h
- @@ -87,6 +87,8 @@ njs_ret_t njs_object_constructor(njs_vm_
- nxt_uint_t nargs, njs_index_t unused);
- 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);
- +nxt_noinline njs_object_prop_t *njs_object_prop_handler_alloc(njs_vm_t *vm,
- + const njs_value_t *name, njs_prop_handler_t handler, uint8_t attributes);
- njs_ret_t njs_primitive_prototype_get_proto(njs_vm_t *vm, njs_value_t *value,
- njs_value_t *setval, njs_value_t *retval);
- njs_ret_t njs_object_prototype_create(njs_vm_t *vm, njs_value_t *value,
- diff --git a/njs/njs_parser.c b/njs/njs_parser.c
- --- a/njs/njs_parser.c
- +++ b/njs/njs_parser.c
- @@ -455,6 +455,13 @@ njs_parser_function_declaration(njs_vm_t
- }
- if (token != NJS_TOKEN_NAME) {
- + if (token == NJS_TOKEN_ARGUMENTS || token == NJS_TOKEN_EVAL) {
- + njs_parser_syntax_error(vm, parser, "Identifier \"%.*s\" "
- + "is forbidden in function declaration",
- + (int) parser->lexer->text.length,
- + parser->lexer->text.start);
- + }
- +
- return NJS_TOKEN_ILLEGAL;
- }
- @@ -821,6 +828,13 @@ njs_parser_var_statement(njs_vm_t *vm, n
- }
- if (token != NJS_TOKEN_NAME) {
- + if (token == NJS_TOKEN_ARGUMENTS || token == NJS_TOKEN_EVAL) {
- + njs_parser_syntax_error(vm, parser, "Identifier \"%.*s\" "
- + "is forbidden in var declaration",
- + (int) parser->lexer->text.length,
- + parser->lexer->text.start);
- + }
- +
- return NJS_TOKEN_ILLEGAL;
- }
- @@ -1306,6 +1320,13 @@ njs_parser_for_var_statement(njs_vm_t *v
- }
- if (token != NJS_TOKEN_NAME) {
- + if (token == NJS_TOKEN_ARGUMENTS || token == NJS_TOKEN_EVAL) {
- + njs_parser_syntax_error(vm, parser, "Identifier \"%.*s\" "
- + "is forbidden in for-in var declaration",
- + (int) parser->lexer->text.length,
- + parser->lexer->text.start);
- + }
- +
- return NJS_TOKEN_ILLEGAL;
- }
- @@ -1973,6 +1994,24 @@ njs_parser_terminal(njs_vm_t *vm, njs_pa
- case NJS_TOKEN_JSON:
- return njs_parser_builtin_object(vm, parser, node);
- + case NJS_TOKEN_ARGUMENTS:
- + nxt_thread_log_debug("JS: arguments");
- +
- + if (parser->scope->type <= NJS_SCOPE_GLOBAL) {
- + njs_parser_syntax_error(vm, parser, "\"%.*s\" object "
- + "in global scope",
- + (int) parser->lexer->text.length,
- + parser->lexer->text.start);
- +
- + return NJS_TOKEN_ILLEGAL;
- + }
- +
- + node->token = NJS_TOKEN_ARGUMENTS;
- +
- + parser->code_size += sizeof(njs_vmcode_arguments_t);
- +
- + break;
- +
- case NJS_TOKEN_OBJECT_CONSTRUCTOR:
- node->index = NJS_INDEX_OBJECT;
- break;
- diff --git a/njs/njs_parser.h b/njs/njs_parser.h
- --- a/njs/njs_parser.h
- +++ b/njs/njs_parser.h
- @@ -161,6 +161,7 @@ typedef enum {
- NJS_TOKEN_THROW,
- NJS_TOKEN_THIS,
- + NJS_TOKEN_ARGUMENTS,
- #define NJS_TOKEN_FIRST_OBJECT NJS_TOKEN_GLOBAL_THIS
- @@ -346,6 +347,8 @@ struct njs_parser_s {
- u_char *code_end;
- njs_parser_t *parent;
- +
- + nxt_uint_t arguments_object;
- };
- diff --git a/njs/njs_parser_expression.c b/njs/njs_parser_expression.c
- --- a/njs/njs_parser_expression.c
- +++ b/njs/njs_parser_expression.c
- @@ -414,8 +414,19 @@ njs_parser_assignment_expression(njs_vm_
- }
- if (!njs_parser_is_lvalue(parser->node)) {
- - njs_parser_ref_error(vm, parser,
- - "Invalid left-hand side in assignment");
- + token = parser->node->token;
- +
- + if (token == NJS_TOKEN_ARGUMENTS || token == NJS_TOKEN_EVAL) {
- + njs_parser_syntax_error(vm, parser, "Identifier \"%s\" "
- + "is forbidden as left-hand in assignment",
- + (token == NJS_TOKEN_EVAL) ? "eval"
- + : "arguments");
- +
- + } else {
- + njs_parser_ref_error(vm, parser,
- + "Invalid left-hand side in assignment");
- + }
- +
- return NJS_TOKEN_ILLEGAL;
- }
- diff --git a/njs/njs_vm.c b/njs/njs_vm.c
- --- a/njs/njs_vm.c
- +++ b/njs/njs_vm.c
- @@ -415,6 +415,29 @@ njs_vmcode_function(njs_vm_t *vm, njs_va
- njs_ret_t
- +njs_vmcode_arguments(njs_vm_t *vm, njs_value_t *invld1, njs_value_t *invld2)
- +{
- + njs_ret_t ret;
- + njs_frame_t *frame;
- +
- + frame = (njs_frame_t *) vm->active_frame;
- +
- + if (frame->native.arguments_object == NULL) {
- + ret = njs_function_arguments_object_init(vm, &frame->native);
- + if (nxt_slow_path(ret != NXT_OK)) {
- + return NXT_ERROR;
- + }
- + }
- +
- + vm->retval.data.u.object = frame->native.arguments_object;
- + vm->retval.type = NJS_OBJECT;
- + vm->retval.data.truth = 1;
- +
- + return sizeof(njs_vmcode_arguments_t);
- +}
- +
- +
- +njs_ret_t
- njs_vmcode_regexp(njs_vm_t *vm, njs_value_t *invld1, njs_value_t *invld2)
- {
- njs_regexp_t *regexp;
- diff --git a/njs/njs_vm.h b/njs/njs_vm.h
- --- a/njs/njs_vm.h
- +++ b/njs/njs_vm.h
- @@ -644,6 +644,12 @@ typedef struct {
- typedef struct {
- njs_vmcode_t code;
- njs_index_t retval;
- +} njs_vmcode_arguments_t;
- +
- +
- +typedef struct {
- + njs_vmcode_t code;
- + njs_index_t retval;
- uintptr_t length;
- } njs_vmcode_array_t;
- @@ -1112,6 +1118,8 @@ njs_ret_t njs_vmcode_array(njs_vm_t *vm,
- njs_value_t *inlvd2);
- njs_ret_t njs_vmcode_function(njs_vm_t *vm, njs_value_t *inlvd1,
- njs_value_t *invld2);
- +njs_ret_t njs_vmcode_arguments(njs_vm_t *vm, njs_value_t *inlvd1,
- + njs_value_t *invld2);
- njs_ret_t njs_vmcode_regexp(njs_vm_t *vm, njs_value_t *inlvd1,
- njs_value_t *invld2);
- njs_ret_t njs_vmcode_object_copy(njs_vm_t *vm, njs_value_t *value,
- diff --git a/njs/test/njs_unit_test.c b/njs/test/njs_unit_test.c
- --- a/njs/test/njs_unit_test.c
- +++ b/njs/test/njs_unit_test.c
- @@ -5574,6 +5574,77 @@ static njs_unit_test_t njs_test[] =
- "var b = a(); b(2)"),
- nxt_string("3") },
- + /* arguments object. */
- +
- + { nxt_string("var arguments"),
- + nxt_string("SyntaxError: Identifier \"arguments\" is forbidden in var declaration in 1") },
- +
- + { nxt_string("for (var arguments in []) {}"),
- + nxt_string("SyntaxError: Identifier \"arguments\" is forbidden in for-in var declaration in 1") },
- +
- + { nxt_string("function arguments(){}"),
- + nxt_string("SyntaxError: Identifier \"arguments\" is forbidden in function declaration in 1") },
- +
- + { nxt_string("(function () {arguments = [];})"),
- + nxt_string("SyntaxError: Identifier \"arguments\" is forbidden as left-hand in assignment in 1") },
- +
- + { nxt_string("(function(){return arguments[0];})(1,2,3)"),
- + nxt_string("1") },
- +
- + { nxt_string("(function(){return arguments[2];})(1,2,3)"),
- + nxt_string("3") },
- +
- + { nxt_string("(function(){return arguments[3];})(1,2,3)"),
- + nxt_string("undefined") },
- +
- + { nxt_string("(function(a,b,c){return a;})(1,2,3)"),
- + nxt_string("1") },
- +
- + { nxt_string("(function(a,b,c){arguments[0] = 4; return a;})(1,2,3)"),
- + nxt_string("1") },
- +
- + { nxt_string("(function(a,b,c){a = 4; return arguments[0];})(1,2,3)"),
- + nxt_string("1") },
- +
- + { nxt_string("function check(v) {if (v == false) {throw TypeError('Too few arguments')}}; "
- + "function f() {check(arguments.length > 1); return 1}; f()"),
- + nxt_string("TypeError: Too few arguments") },
- +
- + { nxt_string("function check(v) {if (v == false) {throw TypeError('Too few arguments')}}; "
- + "function f() {check(arguments.length > 1); return 1}; f(1,2)"),
- + nxt_string("1") },
- +
- + { nxt_string("(function(a,b){delete arguments[0]; return arguments[0]})(1,1)"),
- + nxt_string("undefined") },
- +
- + { nxt_string("(function(){return arguments.length;})()"),
- + nxt_string("0") },
- +
- + { nxt_string("(function(){return arguments.length;})(1,2,3)"),
- + nxt_string("3") },
- +
- + { nxt_string("(function(){arguments.length = 1; return arguments.length;})(1,2,3)"),
- + nxt_string("1") },
- +
- + { nxt_string("(function(){return arguments.callee;})()"),
- + nxt_string("TypeError: 'caller', 'callee' properties may not be accessed") },
- +
- + { nxt_string("(function(){return arguments.caller;})()"),
- + nxt_string("TypeError: 'caller', 'callee' properties may not be accessed") },
- +
- + { nxt_string("(function(){return arguments.callee;})()"),
- + nxt_string("TypeError: 'caller', 'callee' properties may not be accessed") },
- +
- + { nxt_string("function sum() { var args = Array.prototype.slice.call(arguments); "
- + "return args.reduce(function(prev, curr) {return prev + curr})};"
- + "[sum(1), sum(1,2), sum(1,2,3), sum(1,2,3,4)]"),
- + nxt_string("1,3,6,10") },
- +
- + { nxt_string("function concat(sep) { var args = Array.prototype.slice.call(arguments, 1); "
- + "return args.join(sep)};"
- + "[concat('.',1,2,3), concat('+',1,2,3,4)]"),
- + nxt_string("1.2.3,1+2+3+4") },
- +
- /* Scopes. */
- { nxt_string("function f(x) { a = x } var a; f(5); a"),
Add Comment
Please, Sign In to add comment