mirror of https://github.com/svaarala/duktape.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
635 lines
19 KiB
635 lines
19 KiB
/*
|
|
* [[OwnPropertyKeys]]
|
|
*
|
|
* ES2015+ [[OwnPropertyKeys]] ordering guarantees:
|
|
*
|
|
* 1. Array indices in ascending order, i.e. CanonicalNumericIndexStrings
|
|
* representing integers in [0, 0xfffffffe].
|
|
*
|
|
* 2. String keys in insertion order. This includes non-array-index
|
|
* CanonicalNumericIndexStrings, e.g. ToString(0xffffffff), 'NaN',
|
|
* 'Infinity'.
|
|
*
|
|
* 3. Symbol keys in insertion order.
|
|
*
|
|
* Proxy 'ownKeys' trap does not have forced ordering at [[OwnPropertyKeys]]
|
|
* level. Instead, they are sorted in EnumerableOwnPropertyNames() after
|
|
* filtering. Proxy invariants for 'ownKeys' trap are complex and heavy.
|
|
*
|
|
* Object property enumeration which includes inheritance has a separate
|
|
* algorithm, EnumerateObjectProperties:
|
|
* https://tc39.es/ecma262/#sec-enumerate-object-properties
|
|
*/
|
|
|
|
#include "duk_internal.h"
|
|
|
|
/* Append index keys of an array with an items part to output array.
|
|
* Index keys are not (yet) string coerced.
|
|
*/
|
|
DUK_LOCAL duk_uarridx_t duk__prop_ownpropkeys_arrayitems(duk_hthread *thr,
|
|
duk_hobject *obj,
|
|
duk_harray *arr_out,
|
|
duk_uarridx_t idx_out) {
|
|
duk_harray *a = (duk_harray *) obj;
|
|
duk_tval *tv_out;
|
|
duk_tval *tv_out_start;
|
|
duk_tval *tv_base;
|
|
duk_uint32_t i, n;
|
|
|
|
/* Reserve space for maximum result size, actual size may be smaller
|
|
* due to input array gaps.
|
|
*/
|
|
n = DUK_HARRAY_GET_ITEMS_LENGTH(a);
|
|
tv_out_start = duk_harray_append_reserve_items(thr, arr_out, idx_out, n);
|
|
tv_out = tv_out_start;
|
|
DUK_ASSERT(tv_out != NULL || (idx_out == 0 && n == 0));
|
|
|
|
tv_base = DUK_HARRAY_GET_ITEMS(thr->heap, a);
|
|
|
|
/* Array resize is side effect protected so assumptions
|
|
* should still hold.
|
|
*/
|
|
|
|
for (i = 0, n = DUK_HARRAY_GET_ITEMS_LENGTH(a); i < n; i++) {
|
|
duk_tval *tv_val = tv_base + i;
|
|
if (DUK_TVAL_IS_UNUSED(tv_val)) {
|
|
/* Gaps are excluded from result. */
|
|
continue;
|
|
}
|
|
DUK_TVAL_SET_U32(tv_out, (duk_uint32_t) i);
|
|
tv_out++;
|
|
}
|
|
idx_out += (duk_uarridx_t) (tv_out - tv_out_start);
|
|
DUK_HARRAY_SET_LENGTH(arr_out, idx_out);
|
|
|
|
return idx_out;
|
|
}
|
|
|
|
/* Emit index keys without gaps for e.g. a string object. Index keys are
|
|
* not (yet) string coerced.
|
|
*/
|
|
DUK_LOCAL duk_uarridx_t duk__prop_ownpropkeys_append_indices(duk_hthread *thr,
|
|
duk_uint32_t n,
|
|
duk_harray *arr_out,
|
|
duk_uarridx_t idx_out) {
|
|
duk_tval *tv_out;
|
|
duk_tval *tv_out_start;
|
|
duk_uint32_t i;
|
|
|
|
tv_out_start = duk_harray_append_reserve_items(thr, arr_out, idx_out, n);
|
|
tv_out = tv_out_start;
|
|
DUK_ASSERT(tv_out != NULL || (idx_out == 0 && n == 0));
|
|
|
|
for (i = 0; i < n; i++) {
|
|
DUK_TVAL_SET_U32(tv_out, (duk_uint32_t) i);
|
|
tv_out++;
|
|
}
|
|
idx_out += n;
|
|
DUK_HARRAY_SET_LENGTH(arr_out, idx_out);
|
|
|
|
return idx_out;
|
|
}
|
|
|
|
DUK_LOCAL duk_uarridx_t duk__prop_ownpropkeys_bufobj_indices(duk_hthread *thr,
|
|
duk_hobject *obj,
|
|
duk_harray *arr_out,
|
|
duk_uarridx_t idx_out) {
|
|
duk_hbufobj *h = (duk_hbufobj *) obj;
|
|
duk_uarridx_t res;
|
|
duk_uint32_t n;
|
|
|
|
n = (duk_uint32_t) DUK_HBUFOBJ_GET_LOGICAL_LENGTH(h);
|
|
res = duk__prop_ownpropkeys_append_indices(thr, n, arr_out, idx_out);
|
|
/* Side effects are possible, but they cannot alter the length of a
|
|
* typed array so 'n' should still be valid.
|
|
*/
|
|
DUK_ASSERT(DUK_HBUFOBJ_GET_LOGICAL_LENGTH(h) == n);
|
|
return res;
|
|
}
|
|
|
|
DUK_LOCAL duk_uarridx_t duk__prop_ownpropkeys_strobj_indices(duk_hthread *thr,
|
|
duk_hobject *obj,
|
|
duk_harray *arr_out,
|
|
duk_uarridx_t idx_out) {
|
|
duk_hstring *h;
|
|
duk_uarridx_t res;
|
|
duk_uint32_t n;
|
|
|
|
h = duk_hobject_get_internal_value_string(thr->heap, obj);
|
|
DUK_ASSERT(h != NULL);
|
|
if (!h) {
|
|
return idx_out;
|
|
}
|
|
|
|
n = duk_hstring_get_charlen(h);
|
|
res = duk__prop_ownpropkeys_append_indices(thr, n, arr_out, idx_out);
|
|
DUK_ASSERT(duk_hstring_get_charlen(h) == n);
|
|
return res;
|
|
}
|
|
|
|
DUK_LOCAL duk_uarridx_t duk__prop_ownpropkeys_idxprops(duk_hthread *thr,
|
|
duk_hobject *obj,
|
|
duk_harray *arr_out,
|
|
duk_uarridx_t idx_out,
|
|
duk_uint_t ownpropkeys_flags) {
|
|
duk_tval *tv_out_start;
|
|
duk_tval *tv_out;
|
|
duk_uint32_t i, n;
|
|
duk_propvalue *val_base;
|
|
duk_uarridx_t *key_base;
|
|
duk_uint8_t *attr_base;
|
|
|
|
n = obj->i_next;
|
|
tv_out_start = duk_harray_append_reserve_items(thr, arr_out, idx_out, n);
|
|
tv_out = tv_out_start;
|
|
DUK_ASSERT(tv_out != NULL || (idx_out == 0 && n == 0));
|
|
|
|
duk_hobject_get_idxprops_key_attr(thr->heap, obj, &val_base, &key_base, &attr_base);
|
|
|
|
for (i = 0, n = obj->i_next; i < n; i++) {
|
|
duk_uarridx_t idx;
|
|
duk_uint8_t attrs;
|
|
|
|
idx = key_base[i];
|
|
if (idx == DUK_ARRIDX_NONE) {
|
|
continue;
|
|
}
|
|
attrs = attr_base[i];
|
|
if ((ownpropkeys_flags & DUK_OWNPROPKEYS_FLAG_REQUIRE_ENUMERABLE) && (attrs & DUK_PROPDESC_FLAG_ENUMERABLE) == 0) {
|
|
continue;
|
|
}
|
|
|
|
DUK_TVAL_SET_U32(tv_out, (duk_uint32_t) idx);
|
|
tv_out++;
|
|
}
|
|
idx_out += (duk_uarridx_t) (tv_out - tv_out_start);
|
|
DUK_HARRAY_SET_LENGTH(arr_out, idx_out);
|
|
|
|
return idx_out;
|
|
}
|
|
|
|
DUK_LOCAL duk_uarridx_t duk__prop_ownpropkeys_strprops(duk_hthread *thr,
|
|
duk_hobject *obj,
|
|
duk_harray *arr_out,
|
|
duk_uarridx_t idx_out,
|
|
duk_uint_t ownpropkeys_flags,
|
|
duk_bool_t symbol_phase,
|
|
duk_bool_t *out_found_symbols) {
|
|
duk_tval *tv_out_start;
|
|
duk_tval *tv_out;
|
|
duk_uint32_t i, n;
|
|
duk_propvalue *val_base;
|
|
duk_hstring **key_base;
|
|
duk_uint8_t *attr_base;
|
|
duk_bool_t found_symbols = 0;
|
|
|
|
n = duk_hobject_get_enext(obj);
|
|
tv_out_start = duk_harray_append_reserve_items(thr, arr_out, idx_out, n);
|
|
tv_out = tv_out_start;
|
|
DUK_ASSERT(tv_out != NULL || (idx_out == 0 && n == 0));
|
|
|
|
duk_hobject_get_strprops_key_attr(thr->heap, obj, &val_base, &key_base, &attr_base);
|
|
|
|
for (i = 0, n = duk_hobject_get_enext(obj); i < n; i++) {
|
|
duk_hstring *key;
|
|
duk_uint8_t attrs;
|
|
|
|
key = key_base[i];
|
|
if (key == NULL) {
|
|
continue;
|
|
}
|
|
attrs = attr_base[i];
|
|
if ((ownpropkeys_flags & DUK_OWNPROPKEYS_FLAG_REQUIRE_ENUMERABLE) && (attrs & DUK_PROPDESC_FLAG_ENUMERABLE) == 0) {
|
|
continue;
|
|
}
|
|
if (symbol_phase) {
|
|
if (!DUK_HSTRING_HAS_SYMBOL(key) || DUK_HSTRING_HAS_HIDDEN(key)) {
|
|
continue;
|
|
}
|
|
} else {
|
|
if (DUK_HSTRING_HAS_SYMBOL(key)) {
|
|
found_symbols = 1;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
DUK_TVAL_SET_STRING_INCREF(thr, tv_out, key);
|
|
tv_out++;
|
|
}
|
|
idx_out += (duk_uarridx_t) (tv_out - tv_out_start);
|
|
DUK_HARRAY_SET_LENGTH(arr_out, idx_out);
|
|
|
|
*out_found_symbols = found_symbols;
|
|
return idx_out;
|
|
}
|
|
|
|
DUK_LOCAL duk_uarridx_t duk__prop_ownpropkeys_add_length(duk_hthread *thr, duk_uarridx_t idx_out) {
|
|
duk_push_hstring_stridx(thr, DUK_STRIDX_LENGTH);
|
|
duk_xdef_prop_index_wec(thr, -2, idx_out);
|
|
idx_out++;
|
|
|
|
return idx_out;
|
|
}
|
|
|
|
DUK_LOCAL void duk__prop_ownpropkeys_string_coerce(duk_hthread *thr, duk_harray *arr_out) {
|
|
duk_uint32_t i, n;
|
|
|
|
/* Arbitrary side effects are possible here. However, 'arr_out' is
|
|
* not reachable to finalizers etc, so we can safely assume it won't
|
|
* be mutated.
|
|
*/
|
|
for (i = 0, n = DUK_HARRAY_GET_LENGTH(arr_out); i < n; i++) {
|
|
duk_hstring *tmp;
|
|
duk_tval *tv_slot;
|
|
|
|
tv_slot = DUK_HARRAY_GET_ITEMS(thr->heap, arr_out) + i;
|
|
duk_push_tval(thr, tv_slot);
|
|
tmp = duk_to_hstring(thr, -1);
|
|
DUK_ASSERT(tmp != NULL);
|
|
tv_slot = DUK_HARRAY_GET_ITEMS(thr->heap, arr_out) + i;
|
|
DUK_TVAL_SET_STRING(tv_slot, tmp); /* Steal refcount. */
|
|
tv_slot = DUK_GET_TVAL_NEGIDX(thr, -1);
|
|
DUK_TVAL_SET_UNDEFINED(tv_slot);
|
|
thr->valstack_top--;
|
|
}
|
|
}
|
|
|
|
DUK_LOCAL DUK_ALWAYS_INLINE duk_uint32_t duk__prop_ownpropkeys_get_known_u32(duk_tval *tv) {
|
|
duk_uint32_t res;
|
|
|
|
#if defined(DUK_USE_FASTINT)
|
|
DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv));
|
|
res = DUK_TVAL_GET_FASTINT_U32(tv);
|
|
#else
|
|
DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
|
|
res = (duk_uint32_t) DUK_TVAL_GET_DOUBLE(tv);
|
|
#endif
|
|
return res;
|
|
}
|
|
|
|
/* Sort index keys emitted so far. This is needed when index keys
|
|
* come from the index part, and are unordered. Insertion sort for
|
|
* now, should be quicksort or similar to handle large cases.
|
|
*/
|
|
DUK_LOCAL void duk__prop_ownpropkeys_sort_index_keys(duk_hthread *thr, duk_harray *arr_out) {
|
|
duk_uint32_t i, n;
|
|
duk_tval *val_base;
|
|
|
|
DUK_UNREF(thr);
|
|
|
|
n = DUK_HARRAY_GET_LENGTH(arr_out);
|
|
if (n == 0) {
|
|
return;
|
|
}
|
|
val_base = DUK_HARRAY_GET_ITEMS(thr->heap, arr_out);
|
|
for (i = 1; i < n; i++) {
|
|
duk_uint32_t curr_val;
|
|
duk_uint32_t j;
|
|
|
|
curr_val = duk__prop_ownpropkeys_get_known_u32(val_base + i);
|
|
|
|
/* Insert curr_val at index i into sorted subarray [0,i[. */
|
|
j = i;
|
|
for (;;) {
|
|
duk_uint32_t test_val;
|
|
|
|
DUK_ASSERT(j >= 1U);
|
|
j--;
|
|
|
|
test_val = duk__prop_ownpropkeys_get_known_u32(val_base + j);
|
|
if (curr_val >= test_val) { /* Equality not actually possible. */
|
|
j++;
|
|
break;
|
|
}
|
|
if (DUK_UNLIKELY(j == 0U)) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* curr_val belongs at index j. */
|
|
if (j < i) {
|
|
duk_tval *copy_dst;
|
|
duk_tval *copy_src;
|
|
duk_tval *tv_i;
|
|
duk_size_t copy_size;
|
|
duk_tval tv_tmp;
|
|
|
|
/*
|
|
* j i
|
|
* | |
|
|
* v v
|
|
* A B C D F G E ...
|
|
* ===
|
|
*
|
|
* A B C D F F G ...
|
|
* ===
|
|
*
|
|
* A B C D E F G ...
|
|
* =
|
|
*/
|
|
copy_src = val_base + j;
|
|
copy_dst = copy_src + 1;
|
|
copy_size = i - j;
|
|
tv_i = val_base + i;
|
|
DUK_TVAL_SET_TVAL(&tv_tmp, tv_i);
|
|
duk_memmove((void *) copy_dst, (const void *) copy_src, (duk_size_t) (copy_size * sizeof(duk_tval)));
|
|
DUK_TVAL_SET_TVAL(copy_src, &tv_tmp);
|
|
}
|
|
}
|
|
}
|
|
|
|
#if defined(DUK_USE_PROXY_POLICY)
|
|
/* Incorrect approximate implementation for now. */
|
|
DUK_LOCAL void duk__prop_ownpropkeys_proxy_policy(duk_hthread *thr, duk_hobject *obj, duk_uint_t ownpropkeys_flags) {
|
|
duk_hobject *target;
|
|
duk_uarridx_t i, len, out_idx = 0;
|
|
duk_tval *tv_out;
|
|
duk_bool_t target_extensible;
|
|
|
|
DUK_ASSERT(DUK_HOBJECT_GET_HTYPE(obj) == DUK_HTYPE_PROXY);
|
|
|
|
target = duk_proxy_get_target_autothrow(thr, (duk_hproxy *) obj);
|
|
DUK_ASSERT(target != NULL);
|
|
target_extensible = duk_js_isextensible(thr, target);
|
|
DUK_UNREF(target_extensible);
|
|
|
|
if (!duk_is_object(thr, -1)) {
|
|
goto proxy_reject;
|
|
}
|
|
|
|
len = (duk_uarridx_t) duk_get_length(thr, -1);
|
|
tv_out = duk_push_harray_with_size_outptr(thr, len);
|
|
DUK_UNREF(tv_out);
|
|
|
|
for (i = 0; i < len; i++) {
|
|
duk_hstring *h;
|
|
|
|
/* [ obj(stabilized) arr_out(ignored) trap_result res_arr ] */
|
|
(void) duk_get_prop_index(thr, -2, i);
|
|
|
|
h = duk_get_hstring(thr, -1);
|
|
if (DUK_UNLIKELY(h == NULL)) {
|
|
DUK_ERROR_TYPE_PROXY_REJECTED(thr);
|
|
DUK_WO_NORETURN(return;);
|
|
}
|
|
|
|
if (DUK_UNLIKELY(DUK_HSTRING_HAS_SYMBOL(h))) {
|
|
if (!(ownpropkeys_flags & DUK_OWNPROPKEYS_FLAG_INCLUDE_SYMBOL)) {
|
|
DUK_DDD(DUK_DDDPRINT("ignore symbol property: %!T", duk_get_tval(thr, -1)));
|
|
goto skip_key;
|
|
}
|
|
if (DUK_HSTRING_HAS_HIDDEN(h) && !(ownpropkeys_flags & DUK_OWNPROPKEYS_FLAG_INCLUDE_HIDDEN)) {
|
|
DUK_DDD(DUK_DDDPRINT("ignore hidden symbol property: %!T", duk_get_tval(thr, -1)));
|
|
goto skip_key;
|
|
}
|
|
} else {
|
|
if (!(ownpropkeys_flags & DUK_OWNPROPKEYS_FLAG_INCLUDE_STRING)) {
|
|
DUK_DDD(DUK_DDDPRINT("ignore string property: %!T", duk_get_tval(thr, -1)));
|
|
goto skip_key;
|
|
}
|
|
}
|
|
|
|
/* XXX: This is not correct, but approximate for now. */
|
|
if (ownpropkeys_flags & DUK_OWNPROPKEYS_FLAG_REQUIRE_ENUMERABLE) {
|
|
duk_small_int_t attrs = duk_prop_getownattr_obj_strkey(thr, target, h);
|
|
if (attrs >= 0) {
|
|
if (((duk_small_uint_t) attrs & DUK_PROPDESC_FLAG_ENUMERABLE) == 0) {
|
|
DUK_DDD(DUK_DDDPRINT("ignore non-enumerable property: %!T", duk_get_tval(thr, -1)));
|
|
goto skip_key;
|
|
}
|
|
} else {
|
|
DUK_DDD(DUK_DDDPRINT("ignore non-existent property: %!T", duk_get_tval(thr, -1)));
|
|
goto skip_key;
|
|
}
|
|
}
|
|
|
|
/* [ obj trap_result res_arr propname ] */
|
|
duk_xdef_prop_index_wec(thr, -2, out_idx++);
|
|
continue;
|
|
|
|
skip_key:
|
|
duk_pop_known(thr);
|
|
continue;
|
|
}
|
|
|
|
/* Truncate result array, it may be smaller than raw trap result. */
|
|
duk_set_length(thr, -1, out_idx);
|
|
|
|
duk_remove_m2(thr); /* Remove direct trap result. */
|
|
return;
|
|
|
|
proxy_reject:
|
|
DUK_ERROR_TYPE_PROXY_REJECTED(thr);
|
|
}
|
|
#endif
|
|
|
|
DUK_LOCAL duk_small_int_t duk__prop_ownpropkeys_proxy(duk_hthread *thr, duk_hobject *obj, duk_uint_t ownpropkeys_flags) {
|
|
if (duk_proxy_trap_check_nokey(thr, (duk_hproxy *) obj, DUK_STRIDX_OWN_KEYS)) {
|
|
duk_call_method(thr, 1); /* [ ... trap handler target ] -> [ ... result ] */
|
|
|
|
#if defined(DUK_USE_PROXY_POLICY)
|
|
duk__prop_ownpropkeys_proxy_policy(thr, obj, ownpropkeys_flags);
|
|
#else
|
|
DUK_DD(DUK_DDPRINT("proxy policy check for 'ownKeys' trap disabled in configuration"));
|
|
#endif
|
|
|
|
return 1;
|
|
} else {
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
DUK_INTERNAL void duk_prop_ownpropkeys(duk_hthread *thr, duk_hobject *obj, duk_uint_t ownpropkeys_flags) {
|
|
#if defined(DUK_USE_ASSERTIONS)
|
|
duk_idx_t entry_top;
|
|
#endif
|
|
duk_small_uint_t htype;
|
|
duk_uarridx_t idx_out = 0;
|
|
duk_harray *arr_out;
|
|
|
|
DUK_ASSERT(thr != NULL);
|
|
DUK_ASSERT(obj != NULL);
|
|
#if defined(DUK_USE_ASSERTIONS)
|
|
entry_top = duk_get_top(thr);
|
|
#endif
|
|
|
|
/* Stabilize 'obj' in case we need to traverse Proxy targets. Keep
|
|
* the current object in this value stack slot (link to previous
|
|
* objects may be severed by side effects).
|
|
*/
|
|
duk_push_hobject(thr, obj);
|
|
|
|
/* Output is always a duk_harray with a gap-free items part. We can write
|
|
* out items directly, and they implicitly get WEC attributes which is
|
|
* compatible with Reflect.ownKeys() etc.
|
|
*/
|
|
arr_out = duk_push_harray(thr);
|
|
|
|
/* [ ... obj arr_out ] */
|
|
|
|
retry_obj:
|
|
htype = DUK_HOBJECT_GET_HTYPE(obj);
|
|
DUK_ASSERT(DUK_HTYPE_IS_ANY_OBJECT(htype));
|
|
|
|
switch (htype) {
|
|
case DUK_HTYPE_ARRAY:
|
|
case DUK_HTYPE_ARGUMENTS:
|
|
if (DUK_HOBJECT_HAS_ARRAY_ITEMS(obj)) {
|
|
if (ownpropkeys_flags & DUK_OWNPROPKEYS_FLAG_INCLUDE_ARRIDX) {
|
|
idx_out = duk__prop_ownpropkeys_arrayitems(thr, obj, arr_out, idx_out);
|
|
}
|
|
goto skip_index_part;
|
|
}
|
|
break;
|
|
case DUK_HTYPE_STRING_OBJECT:
|
|
if (ownpropkeys_flags & DUK_OWNPROPKEYS_FLAG_INCLUDE_ARRIDX) {
|
|
idx_out = duk__prop_ownpropkeys_strobj_indices(thr, obj, arr_out, idx_out);
|
|
}
|
|
/* Indices >= .length are handled below as ordinary properties. */
|
|
break;
|
|
case DUK_HTYPE_PROXY: {
|
|
duk_small_int_t proxy_rc;
|
|
|
|
if (ownpropkeys_flags & DUK_OWNPROPKEYS_FLAG_NO_PROXY_BEHAVIOR) {
|
|
DUK_DD(DUK_DDPRINT("caller request no proxy behavior for enumerating own property keys, skip proxy check"));
|
|
break;
|
|
}
|
|
|
|
proxy_rc = duk__prop_ownpropkeys_proxy(thr, obj, ownpropkeys_flags);
|
|
if (proxy_rc < 0) {
|
|
/* Not found, continue to Proxy target. */
|
|
duk_hproxy *h = (duk_hproxy *) obj;
|
|
duk_hobject *next;
|
|
|
|
next = duk_proxy_get_target_autothrow(thr, h);
|
|
DUK_ASSERT(next != NULL);
|
|
|
|
/* Replace stabilized object. */
|
|
duk_push_hobject(thr, next);
|
|
duk_replace(thr, -3);
|
|
obj = next;
|
|
|
|
goto retry_obj;
|
|
} else {
|
|
duk_remove_m2(thr); /* [ ... arr_out ] */
|
|
goto success;
|
|
}
|
|
break;
|
|
}
|
|
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
|
|
case DUK_HTYPE_ARRAYBUFFER:
|
|
case DUK_HTYPE_DATAVIEW:
|
|
break;
|
|
case DUK_HTYPE_INT8ARRAY:
|
|
case DUK_HTYPE_UINT8ARRAY:
|
|
case DUK_HTYPE_UINT8CLAMPEDARRAY:
|
|
case DUK_HTYPE_INT16ARRAY:
|
|
case DUK_HTYPE_UINT16ARRAY:
|
|
case DUK_HTYPE_INT32ARRAY:
|
|
case DUK_HTYPE_UINT32ARRAY:
|
|
case DUK_HTYPE_FLOAT32ARRAY:
|
|
case DUK_HTYPE_FLOAT64ARRAY:
|
|
if (ownpropkeys_flags & DUK_OWNPROPKEYS_FLAG_INCLUDE_ARRIDX) {
|
|
duk_hbufobj *h = (duk_hbufobj *) obj;
|
|
if (!DUK_HBUFOBJ_IS_DETACHED(h)) {
|
|
idx_out = duk__prop_ownpropkeys_bufobj_indices(thr, obj, arr_out, idx_out);
|
|
} else {
|
|
/* Detached: don't enumerate at all. */
|
|
}
|
|
}
|
|
goto skip_index_part;
|
|
#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
|
|
default:
|
|
break;
|
|
}
|
|
|
|
/* Index properties from idxprops part. These need to be sorted
|
|
* because they're stored in a hash.
|
|
*/
|
|
if (obj->i_next > 0) {
|
|
DUK_ASSERT(duk_hobject_get_idxprops(thr->heap, obj) != NULL);
|
|
if (ownpropkeys_flags & DUK_OWNPROPKEYS_FLAG_INCLUDE_ARRIDX) {
|
|
idx_out = duk__prop_ownpropkeys_idxprops(thr, obj, arr_out, idx_out, ownpropkeys_flags);
|
|
duk__prop_ownpropkeys_sort_index_keys(thr, arr_out);
|
|
}
|
|
}
|
|
|
|
skip_index_part:
|
|
/* At this point there are sorted index keys in the result. */
|
|
|
|
/* String coerce index keys inserted so far if necessary. */
|
|
if (ownpropkeys_flags & DUK_OWNPROPKEYS_FLAG_STRING_COERCE) {
|
|
duk__prop_ownpropkeys_string_coerce(thr, arr_out);
|
|
}
|
|
|
|
/* Virtual .length property? */
|
|
if ((ownpropkeys_flags & (DUK_OWNPROPKEYS_FLAG_INCLUDE_STRING | DUK_OWNPROPKEYS_FLAG_REQUIRE_ENUMERABLE)) ==
|
|
(DUK_OWNPROPKEYS_FLAG_INCLUDE_STRING)) {
|
|
htype = DUK_HOBJECT_GET_HTYPE(obj);
|
|
DUK_ASSERT(DUK_HTYPE_IS_ANY_OBJECT(htype));
|
|
|
|
switch (htype) {
|
|
case DUK_HTYPE_ARRAY:
|
|
case DUK_HTYPE_STRING_OBJECT:
|
|
#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
|
|
case DUK_HTYPE_INT8ARRAY:
|
|
case DUK_HTYPE_UINT8ARRAY:
|
|
case DUK_HTYPE_UINT8CLAMPEDARRAY:
|
|
case DUK_HTYPE_INT16ARRAY:
|
|
case DUK_HTYPE_UINT16ARRAY:
|
|
case DUK_HTYPE_INT32ARRAY:
|
|
case DUK_HTYPE_UINT32ARRAY:
|
|
case DUK_HTYPE_FLOAT32ARRAY:
|
|
case DUK_HTYPE_FLOAT64ARRAY:
|
|
#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
|
|
idx_out = duk__prop_ownpropkeys_add_length(thr, idx_out);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* At this point there are sorted index keys and maybe a few non-index
|
|
* keys (e.g. 'length') in the result after the index keys.
|
|
*
|
|
* String/Symbol properties in the string property part are in
|
|
* insertion order, but ES2015+ ordering requires that strings
|
|
* come before Symbols. This could be achieved by first inserting
|
|
* the keys and then sorting them.
|
|
*
|
|
* We handle this here with two insertion passes now: first we
|
|
* insert all string properties and also keep track if any
|
|
* Symbols are encountered. If Symbols were found, Symbols are
|
|
* added in the final step if desired.
|
|
*/
|
|
|
|
if (duk_hobject_get_strprops(thr->heap, obj) != NULL && duk_hobject_get_enext(obj) > 0) {
|
|
duk_bool_t found_symbols = 1;
|
|
|
|
if (ownpropkeys_flags & DUK_OWNPROPKEYS_FLAG_INCLUDE_STRING) {
|
|
idx_out = duk__prop_ownpropkeys_strprops(thr,
|
|
obj,
|
|
arr_out,
|
|
idx_out,
|
|
ownpropkeys_flags,
|
|
0 /*symbol phase*/,
|
|
&found_symbols);
|
|
}
|
|
if ((ownpropkeys_flags & DUK_OWNPROPKEYS_FLAG_INCLUDE_SYMBOL) && found_symbols) {
|
|
idx_out = duk__prop_ownpropkeys_strprops(thr,
|
|
obj,
|
|
arr_out,
|
|
idx_out,
|
|
ownpropkeys_flags,
|
|
1 /*symbol phase*/,
|
|
&found_symbols);
|
|
}
|
|
}
|
|
|
|
success:
|
|
DUK_HARRAY_ASSERT_VALID(thr->heap, (duk_harray *) duk_require_hobject(thr, -1));
|
|
|
|
duk_remove_m2(thr); /* Remove stabilized 'obj': [ ... obj arr_out ] -> [ ... arr_out ] */
|
|
|
|
DUK_ASSERT(duk_get_top(thr) == entry_top + 1);
|
|
}
|
|
|