Created
May 22, 2019 16:38
-
-
Save lexborisov/408637860883507da532ba218c5946be to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# HG changeset patch | |
# User Alexander Borisov <alexander.borisov@nginx.com> | |
# Date 1558542019 -10800 | |
# Wed May 22 19:20:19 2019 +0300 | |
# Node ID 6e7a925ef027e85d64d6a707842bcd81b83c8e4a | |
# Parent d49d270ea377c515f45b5af1eb783c737db82a3e | |
Added njs_value_property_set() function. | |
diff -r d49d270ea377 -r 6e7a925ef027 njs/njs_object.h | |
--- a/njs/njs_object.h Wed May 22 15:19:22 2019 +0300 | |
+++ b/njs/njs_object.h Wed May 22 19:20:19 2019 +0300 | |
@@ -86,6 +86,8 @@ njs_array_t *njs_object_own_enumerate(nj | |
njs_object_enum_t kind, nxt_bool_t all); | |
njs_ret_t njs_value_property(njs_vm_t *vm, const njs_value_t *value, | |
const njs_value_t *property, njs_value_t *retval); | |
+njs_ret_t njs_value_property_set(njs_vm_t *vm, njs_value_t *object, | |
+ const njs_value_t *property, njs_value_t *value); | |
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, | |
diff -r d49d270ea377 -r 6e7a925ef027 njs/njs_vm.c | |
--- a/njs/njs_vm.c Wed May 22 15:19:22 2019 +0300 | |
+++ b/njs/njs_vm.c Wed May 22 19:20:19 2019 +0300 | |
@@ -550,112 +550,17 @@ njs_vmcode_property_set(njs_vm_t *vm, nj | |
{ | |
njs_ret_t ret; | |
njs_value_t *value; | |
- njs_object_prop_t *prop; | |
- njs_property_query_t pq; | |
njs_vmcode_prop_set_t *code; | |
- if (njs_is_primitive(object)) { | |
- njs_type_error(vm, "property set on primitive %s type", | |
- njs_type_string(object->type)); | |
- return NXT_ERROR; | |
- } | |
- | |
code = (njs_vmcode_prop_set_t *) vm->current; | |
value = njs_vmcode_operand(vm, code->value); | |
- njs_property_query_init(&pq, NJS_PROPERTY_QUERY_SET, 0); | |
- | |
- ret = njs_property_query(vm, &pq, object, property); | |
- | |
- switch (ret) { | |
- | |
- case NXT_OK: | |
- prop = pq.lhq.value; | |
- | |
- switch (prop->type) { | |
- case NJS_PROPERTY: | |
- break; | |
- | |
- case NJS_PROPERTY_REF: | |
- *prop->value.data.u.value = *value; | |
- 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; | |
- } | |
- | |
- return sizeof(njs_vmcode_prop_set_t); | |
- } | |
- | |
- break; | |
- | |
- default: | |
- njs_internal_error(vm, "unexpected property type \"%s\" " | |
- "while setting", | |
- njs_prop_type_string(prop->type)); | |
- | |
- return NXT_ERROR; | |
- } | |
- | |
- break; | |
- | |
- 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; | |
- } | |
- | |
- break; | |
- | |
- case NJS_TRAP: | |
- case NXT_ERROR: | |
- default: | |
- | |
- return ret; | |
+ ret = njs_value_property_set(vm, object, property, value); | |
+ if (ret == NXT_OK || ret == NXT_DECLINED) { | |
+ return sizeof(njs_vmcode_prop_set_t); | |
} | |
- 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; | |
- } | |
- | |
- prop->value = *value; | |
- | |
- return sizeof(njs_vmcode_prop_set_t); | |
+ return ret; | |
} | |
@@ -3099,6 +3004,121 @@ njs_value_property(njs_vm_t *vm, const n | |
} | |
+/* | |
+ * NXT_OK property has been found and value replaced, | |
+ * NXT_DECLINED property was not found. Created and sets, | |
+ * NJS_TRAP the property trap must be called, | |
+ * NXT_ERROR exception has been thrown. | |
+ */ | |
+njs_ret_t | |
+njs_value_property_set(njs_vm_t *vm, njs_value_t *object, | |
+ const njs_value_t *property, njs_value_t *value) | |
+{ | |
+ njs_ret_t ret; | |
+ njs_object_prop_t *prop; | |
+ njs_property_query_t pq; | |
+ | |
+ if (njs_is_primitive(object)) { | |
+ njs_type_error(vm, "property set on primitive %s type", | |
+ njs_type_string(object->type)); | |
+ return NXT_ERROR; | |
+ } | |
+ | |
+ njs_property_query_init(&pq, NJS_PROPERTY_QUERY_SET, 0); | |
+ | |
+ ret = njs_property_query(vm, &pq, object, property); | |
+ | |
+ switch (ret) { | |
+ | |
+ case NXT_OK: | |
+ prop = pq.lhq.value; | |
+ | |
+ switch (prop->type) { | |
+ case NJS_PROPERTY: | |
+ break; | |
+ | |
+ case NJS_PROPERTY_REF: | |
+ *prop->value.data.u.value = *value; | |
+ return NJS_OK; | |
+ | |
+ 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; | |
+ } | |
+ | |
+ return NJS_OK; | |
+ } | |
+ | |
+ break; | |
+ | |
+ default: | |
+ njs_internal_error(vm, "unexpected property type \"%s\" " | |
+ "while setting", | |
+ njs_prop_type_string(prop->type)); | |
+ | |
+ return NJS_ERROR; | |
+ } | |
+ | |
+ break; | |
+ | |
+ 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 NJS_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 NJS_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 NJS_ERROR; | |
+ } | |
+ | |
+ break; | |
+ | |
+ case NJS_TRAP: | |
+ case NXT_ERROR: | |
+ default: | |
+ 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)); | |
+ return NJS_ERROR; | |
+ } | |
+ | |
+ prop->value = *value; | |
+ | |
+ return NJS_OK; | |
+} | |
+ | |
+ | |
njs_array_t * | |
njs_value_enumerate(njs_vm_t *vm, const njs_value_t *value, | |
njs_object_enum_t kind, nxt_bool_t all) | |
# HG changeset patch | |
# User Alexander Borisov <alexander.borisov@nginx.com> | |
# Date 1558542058 -10800 | |
# Wed May 22 19:20:58 2019 +0300 | |
# Node ID 075a46e1b11a35c3eee1dc09de4d892ce87a72e8 | |
# Parent 6e7a925ef027e85d64d6a707842bcd81b83c8e4a | |
Added generic implementation of Array.prototype.fill(). | |
This closes #72 issue on GitHub. | |
diff -r 6e7a925ef027 -r 075a46e1b11a njs/njs_array.c | |
--- a/njs/njs_array.c Wed May 22 19:20:19 2019 +0300 | |
+++ b/njs/njs_array.c Wed May 22 19:20:58 2019 +0300 | |
@@ -23,6 +23,16 @@ typedef struct { | |
typedef struct { | |
+ union { | |
+ njs_continuation_t cont; | |
+ u_char padding[NJS_CONTINUATION_SIZE]; | |
+ } u; | |
+ | |
+ njs_value_t length; | |
+} njs_array_fill_t; | |
+ | |
+ | |
+typedef struct { | |
njs_continuation_t cont; | |
njs_value_t *values; | |
uint32_t max; | |
@@ -90,6 +100,8 @@ static njs_ret_t njs_array_prototype_to_ | |
static njs_ret_t njs_array_prototype_join_continuation(njs_vm_t *vm, | |
njs_value_t *args, nxt_uint_t nargs, njs_index_t unused); | |
static njs_value_t *njs_array_copy(njs_value_t *dst, njs_value_t *src); | |
+static njs_ret_t njs_array_prototype_fill_continuation(njs_vm_t *vm, | |
+ njs_value_t *args, nxt_uint_t nargs, njs_index_t unused); | |
static njs_ret_t njs_array_prototype_for_each_continuation(njs_vm_t *vm, | |
njs_value_t *args, nxt_uint_t nargs, njs_index_t unused); | |
static njs_ret_t njs_array_prototype_some_continuation(njs_vm_t *vm, | |
@@ -1409,62 +1421,105 @@ static njs_ret_t | |
njs_array_prototype_fill(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, | |
njs_index_t unused) | |
{ | |
- nxt_int_t i, start, end, length; | |
- njs_array_t *array; | |
- const njs_value_t *value; | |
- | |
- vm->retval = args[0]; | |
- | |
- if (!njs_is_array(&args[0])) { | |
- return NXT_OK; | |
+ njs_ret_t ret; | |
+ njs_value_t *this; | |
+ njs_array_fill_t *fill; | |
+ | |
+ static const njs_value_t njs_string_length = njs_string("length"); | |
+ | |
+ this = (njs_value_t *) njs_arg(args, nargs, 0); | |
+ | |
+ if (!njs_is_object(this)) { | |
+ njs_type_error(vm, "\"this\" argument is not object"); | |
+ return NXT_ERROR; | |
} | |
- array = args[0].data.u.array; | |
- length = array->length; | |
- | |
- if (length == 0) { | |
- return NXT_OK; | |
+ if (!njs_is_array(this)) { | |
+ fill = njs_vm_continuation(vm); | |
+ fill->u.cont.function = njs_array_prototype_fill_continuation; | |
+ | |
+ ret = njs_value_property(vm, this, &njs_string_length, &fill->length); | |
+ if (nxt_slow_path(ret == NXT_ERROR || ret == NJS_TRAP)) { | |
+ return ret; | |
+ } | |
} | |
- start = 0; | |
- end = length; | |
- | |
- if (nargs > 2) { | |
- start = args[2].data.u.number; | |
- | |
- if (start > length) { | |
- start = length; | |
- } | |
- | |
- if (start < 0) { | |
- start += length; | |
- | |
- if (start < 0) { | |
- start = 0; | |
- } | |
+ return njs_array_prototype_fill_continuation(vm, args, nargs, unused); | |
+} | |
+ | |
+ | |
+static njs_ret_t | |
+njs_array_prototype_fill_continuation(njs_vm_t *vm, njs_value_t *args, | |
+ nxt_uint_t nargs, njs_index_t unused) | |
+{ | |
+ njs_ret_t ret; | |
+ nxt_int_t i, start, end, length; | |
+ njs_array_t *array = NULL; | |
+ njs_value_t *this, name; | |
+ njs_array_fill_t *fill; | |
+ const njs_value_t *value, *val_start, *val_stop; | |
+ | |
+ this = (njs_value_t *) njs_arg(args, nargs, 0); | |
+ val_start = njs_arg(args, nargs, 2); | |
+ val_stop = njs_arg(args, nargs, 3); | |
+ | |
+ vm->retval = *this; | |
+ | |
+ if (njs_is_array(this)) { | |
+ array = this->data.u.array; | |
+ length = array->length; | |
+ | |
+ } else { | |
+ fill = njs_vm_continuation(vm); | |
+ | |
+ if (nxt_slow_path(!njs_is_primitive(&fill->length))) { | |
+ njs_vm_trap_value(vm, &fill->length); | |
+ return njs_trap(vm, NJS_TRAP_NUMBER_ARG); | |
} | |
- if (nargs > 3) { | |
- end = args[3].data.u.number; | |
- | |
- if (end > length) { | |
- end = length; | |
- } | |
- | |
- if (end < 0) { | |
- end += length; | |
- | |
- if (end < 0) { | |
- end = 0; | |
- } | |
- } | |
- } | |
+ length = njs_primitive_value_to_length(&fill->length); | |
+ } | |
+ | |
+ start = njs_primitive_value_to_number(val_start); | |
+ | |
+ if (start < 0) { | |
+ start = nxt_max((length + start), 0); | |
+ | |
+ } else { | |
+ start = nxt_min(start, length); | |
+ } | |
+ | |
+ if (njs_is_undefined(val_stop)) { | |
+ end = length; | |
+ | |
+ } else { | |
+ end = njs_primitive_value_to_number(val_stop); | |
+ } | |
+ | |
+ if (end < 0) { | |
+ end = nxt_max((length + end), 0); | |
+ | |
+ } else { | |
+ end = nxt_min(end, length); | |
} | |
value = njs_arg(args, nargs, 1); | |
+ if (njs_is_array(this)) { | |
+ for (i = start; i < end; i++) { | |
+ array->start[i] = *value; | |
+ } | |
+ | |
+ return NXT_OK; | |
+ } | |
+ | |
for (i = start; i < end; i++) { | |
- array->start[i] = *value; | |
+ njs_uint32_to_string(&name, i); | |
+ | |
+ ret = njs_value_property_set(vm, this, &name, (njs_value_t *) value); | |
+ if (nxt_slow_path(ret == NXT_ERROR)) { | |
+ return ret; | |
+ } | |
} | |
return NXT_OK; | |
@@ -2392,7 +2447,8 @@ static const njs_object_prop_t njs_arra | |
{ | |
.type = NJS_METHOD, | |
.name = njs_string("fill"), | |
- .value = njs_native_function(njs_array_prototype_fill, 0, | |
+ .value = njs_native_function(njs_array_prototype_fill, | |
+ njs_continuation_size(njs_array_fill_t), | |
NJS_OBJECT_ARG, NJS_SKIP_ARG, NJS_NUMBER_ARG, | |
NJS_NUMBER_ARG), | |
.configurable = 1, | |
diff -r 6e7a925ef027 -r 075a46e1b11a njs/test/njs_unit_test.c | |
--- a/njs/test/njs_unit_test.c Wed May 22 19:20:19 2019 +0300 | |
+++ b/njs/test/njs_unit_test.c Wed May 22 19:20:58 2019 +0300 | |
@@ -3995,6 +3995,15 @@ static njs_unit_test_t njs_test[] = | |
"{ return a + (x === undefined); }, 0)"), | |
nxt_string("3") }, | |
+ { nxt_string("var a = Array.prototype.fill.apply(" | |
+ "Object({length: 40}), [\"a\", 1, 20]); Object.values(a)"), | |
+ nxt_string("a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,40,a,a,a,a") }, | |
+ | |
+ { nxt_string("var a = Array.prototype.fill.apply({length: " | |
+ "{ valueOf: function() { return 40 }}}, [\"a\", 1, 20]);" | |
+ "Object.values(a)"), | |
+ nxt_string("a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,[object Object],a,a,a,a") }, | |
+ | |
{ nxt_string("var a = [];" | |
"a.filter(function(v, i, a) { return v > 1 })"), | |
nxt_string("") }, |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment