Skip to content

Instantly share code, notes, and snippets.

@lexborisov
Created May 22, 2019 16:38
Show Gist options
  • Save lexborisov/408637860883507da532ba218c5946be to your computer and use it in GitHub Desktop.
Save lexborisov/408637860883507da532ba218c5946be to your computer and use it in GitHub Desktop.
# 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