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.
281 lines
8.1 KiB
281 lines
8.1 KiB
/*
|
|
* Misc support functions
|
|
*/
|
|
|
|
#include "duk_internal.h"
|
|
|
|
DUK_INTERNAL duk_bool_t duk_hobject_prototype_chain_contains(duk_hthread *thr,
|
|
duk_hobject *h,
|
|
duk_hobject *p,
|
|
duk_bool_t ignore_loop) {
|
|
duk_uint_t sanity;
|
|
|
|
DUK_ASSERT(thr != NULL);
|
|
|
|
/* False if the object is NULL or the prototype 'p' is NULL.
|
|
* In particular, false if both are NULL (don't compare equal).
|
|
*/
|
|
if (h == NULL || p == NULL) {
|
|
return 0;
|
|
}
|
|
|
|
sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY;
|
|
do {
|
|
if (h == p) {
|
|
return 1;
|
|
}
|
|
|
|
if (DUK_UNLIKELY(--sanity == 0)) {
|
|
if (ignore_loop) {
|
|
break;
|
|
} else {
|
|
DUK_ERROR_RANGE_PROTO_SANITY(thr);
|
|
DUK_WO_NORETURN(return 0;);
|
|
}
|
|
}
|
|
h = duk_hobject_get_proto_raw(thr->heap, h);
|
|
} while (h);
|
|
|
|
return 0;
|
|
}
|
|
|
|
DUK_INTERNAL duk_hobject *duk_hobject_get_proto_raw(duk_heap *heap, duk_hobject *h) {
|
|
DUK_UNREF(heap);
|
|
DUK_ASSERT(h != NULL);
|
|
return DUK_HOBJECT_GET_PROTOTYPE(heap, h);
|
|
}
|
|
|
|
DUK_INTERNAL void duk_hobject_set_proto_raw_updref(duk_hthread *thr, duk_hobject *h, duk_hobject *p) {
|
|
#if defined(DUK_USE_REFERENCE_COUNTING)
|
|
duk_hobject *tmp;
|
|
|
|
DUK_ASSERT(h);
|
|
tmp = duk_hobject_get_proto_raw(thr->heap, h);
|
|
DUK_HOBJECT_SET_PROTOTYPE(thr->heap, h, p);
|
|
DUK_HOBJECT_INCREF_ALLOWNULL(thr, p); /* avoid problems if p == h->prototype */
|
|
DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp);
|
|
#else
|
|
DUK_ASSERT(h);
|
|
DUK_UNREF(thr);
|
|
DUK_HOBJECT_SET_PROTOTYPE(thr->heap, h, p);
|
|
#endif
|
|
}
|
|
|
|
DUK_INTERNAL void duk_hobject_get_props_key_attr(duk_heap *heap,
|
|
duk_hobject *obj,
|
|
duk_propvalue **out_val_base,
|
|
duk_hstring ***out_key_base,
|
|
duk_uint8_t **out_attr_base) {
|
|
duk_propvalue *val_base;
|
|
duk_hstring **key_base;
|
|
duk_uint8_t *attr_base;
|
|
|
|
val_base = duk_hobject_get_props(heap, obj);
|
|
key_base = (duk_hstring **) (void *) (val_base + duk_hobject_get_esize(obj));
|
|
attr_base = (duk_uint8_t *) (void *) (key_base + duk_hobject_get_esize(obj));
|
|
|
|
*out_val_base = val_base;
|
|
*out_key_base = key_base;
|
|
*out_attr_base = attr_base;
|
|
}
|
|
|
|
DUK_INTERNAL duk_propvalue *duk_hobject_get_props(duk_heap *heap, duk_hobject *obj) {
|
|
#if defined(DUK_USE_HEAPPTR16)
|
|
return (duk_propvalue *) DUK_USE_HEAPPTR_DEC16(thr->heap->heap_udata, obj->hdr.h_extra16);
|
|
#else
|
|
return (duk_propvalue *) (void *) obj->props;
|
|
#endif
|
|
}
|
|
|
|
DUK_INTERNAL duk_uint32_t duk_hobject_get_esize(duk_hobject *h) {
|
|
DUK_ASSERT(h != NULL);
|
|
return DUK_HOBJECT_GET_ESIZE(h);
|
|
}
|
|
|
|
DUK_INTERNAL duk_uint32_t duk_hobject_get_enext(duk_hobject *h) {
|
|
DUK_ASSERT(h != NULL);
|
|
return DUK_HOBJECT_GET_ENEXT(h);
|
|
}
|
|
|
|
DUK_INTERNAL duk_size_t duk_hobject_get_ebytes(duk_hobject *h) {
|
|
DUK_ASSERT(h != NULL);
|
|
return DUK_HOBJECT_P_COMPUTE_SIZE(DUK_HOBJECT_GET_ESIZE(h));
|
|
}
|
|
|
|
DUK_INTERNAL duk_uint32_t duk_hobject_get_isize(duk_hobject *h) {
|
|
DUK_ASSERT(h != NULL);
|
|
return h->i_size;
|
|
}
|
|
|
|
DUK_INTERNAL duk_uint32_t duk_hobject_get_inext(duk_hobject *h) {
|
|
DUK_ASSERT(h != NULL);
|
|
return h->i_next;
|
|
}
|
|
|
|
DUK_INTERNAL duk_size_t duk_hobject_get_ibytes(duk_hobject *h) {
|
|
DUK_ASSERT(h != NULL);
|
|
return sizeof(duk_propvalue) * (h->i_size);
|
|
}
|
|
|
|
DUK_INTERNAL duk_uint32_t duk_hobject_get_hsize(duk_heap *heap, duk_hobject *h) {
|
|
duk_uint32_t *hash;
|
|
|
|
DUK_ASSERT(h != NULL);
|
|
DUK_UNREF(heap);
|
|
#if defined(DUK_USE_HOBJECT_HASH_PART)
|
|
hash = DUK_HOBJECT_GET_HASH(heap, h);
|
|
if (hash != NULL) {
|
|
return hash[0];
|
|
} else {
|
|
return 0;
|
|
}
|
|
#else
|
|
DUK_UNREF(hash);
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
DUK_INTERNAL_DECL size_t duk_hobject_get_hbytes(duk_heap *heap, duk_hobject *h) {
|
|
duk_uint32_t *hash;
|
|
|
|
DUK_ASSERT(h != NULL);
|
|
DUK_UNREF(heap);
|
|
#if defined(DUK_USE_HOBJECT_HASH_PART)
|
|
hash = DUK_HOBJECT_GET_HASH(heap, h);
|
|
if (hash != NULL) {
|
|
DUK_ASSERT(hash[0] + 1U >= hash[0]);
|
|
return (hash[0] + 1U) * sizeof(duk_uint32_t);
|
|
} else {
|
|
return 0;
|
|
}
|
|
#else
|
|
DUK_UNREF(hash);
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
DUK_INTERNAL duk_uint32_t duk_harray_get_active_items_length(duk_harray *a) {
|
|
/* For now use items_length as is. Could use 'length' for arrays
|
|
* at least.
|
|
*/
|
|
DUK_ASSERT(a != NULL);
|
|
return DUK_HARRAY_GET_ITEMS_LENGTH(a);
|
|
}
|
|
|
|
DUK_INTERNAL duk_uint32_t duk_hobject_get_asize(duk_hobject *h) {
|
|
DUK_ASSERT(h != NULL);
|
|
if (DUK_HOBJECT_HAS_ARRAY_ITEMS(h)) {
|
|
DUK_ASSERT(DUK_HOBJECT_IS_HARRAY(h));
|
|
return DUK_HARRAY_GET_ITEMS_LENGTH((duk_harray *) h);
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
DUK_INTERNAL duk_size_t duk_hobject_get_abytes(duk_hobject *h) {
|
|
DUK_ASSERT(h != NULL);
|
|
if (DUK_HOBJECT_HAS_ARRAY_ITEMS(h)) {
|
|
DUK_ASSERT(DUK_HOBJECT_IS_HARRAY(h));
|
|
return sizeof(duk_tval) * (duk_size_t) DUK_HARRAY_GET_ITEMS_LENGTH((duk_harray *) h);
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
DUK_INTERNAL duk_uint32_t duk_hobject_compute_uarridx_hash(duk_uarridx_t idx) {
|
|
return (duk_uint32_t) (idx * 3);
|
|
}
|
|
|
|
/*
|
|
* Object.isSealed() and Object.isFrozen() (E5 Sections 15.2.3.11, 15.2.3.13)
|
|
*
|
|
* Since the algorithms are similar, a helper provides both functions.
|
|
* Freezing is essentially sealing + making plain properties non-writable.
|
|
*/
|
|
|
|
DUK_INTERNAL duk_bool_t duk_hobject_object_is_sealed_frozen_helper(duk_hthread *thr, duk_hobject *obj, duk_bool_t is_frozen) {
|
|
duk_uint_t ownpropkeys_flags;
|
|
duk_uarridx_t i, len;
|
|
|
|
DUK_ASSERT(thr != NULL);
|
|
DUK_ASSERT(thr->heap != NULL);
|
|
DUK_ASSERT(obj != NULL);
|
|
|
|
DUK_ASSERT_VALSTACK_SPACE(thr, DUK_HOBJECT_PROP_VALSTACK_SPACE);
|
|
|
|
if (duk_js_isextensible(thr, obj)) {
|
|
return 0;
|
|
}
|
|
|
|
/* Don't coerce keys, don't require enumerable. */
|
|
ownpropkeys_flags =
|
|
DUK_OWNPROPKEYS_FLAG_INCLUDE_ARRIDX | DUK_OWNPROPKEYS_FLAG_INCLUDE_STRING | DUK_OWNPROPKEYS_FLAG_INCLUDE_SYMBOL;
|
|
duk_prop_ownpropkeys(thr, obj, ownpropkeys_flags);
|
|
DUK_ASSERT(duk_is_array(thr, -1));
|
|
|
|
len = (duk_uarridx_t) duk_get_length(thr, -1);
|
|
for (i = 0; i < len; i++) {
|
|
duk_small_int_t attrs;
|
|
|
|
(void) duk_get_prop_index(thr, -1, i);
|
|
attrs = duk_prop_getowndesc_obj_tvkey(thr, obj, DUK_GET_TVAL_NEGIDX(thr, -1));
|
|
duk_prop_pop_propdesc(thr, attrs);
|
|
duk_pop_unsafe(thr);
|
|
if (attrs >= 0) {
|
|
if (attrs & DUK_PROPDESC_FLAG_CONFIGURABLE) {
|
|
return 0;
|
|
}
|
|
if (is_frozen && (attrs & DUK_PROPDESC_FLAG_WRITABLE)) {
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
duk_pop_unsafe(thr);
|
|
return 1;
|
|
}
|
|
|
|
DUK_INTERNAL void duk_hobject_start_critical(duk_hthread *thr,
|
|
duk_small_uint_t *prev_ms_base_flags,
|
|
duk_small_uint_t flags_to_set,
|
|
duk_bool_t *prev_error_not_allowed) {
|
|
/* Call sites triggering property table resizes, such as [[Set]],
|
|
* assume no side effects due to the resize. If this were not the
|
|
* case, call sites would run into various difficulties like checking
|
|
* that a write is allowed, but a side effect actually preventing the
|
|
* write leading to inconsistent behavior.
|
|
*
|
|
* It would be nice to relax these protections as much as possible
|
|
* because we'd like the property table resize to succeed if at all
|
|
* possible. For example compaction only really needs to be prevented
|
|
* for the object being operated on.
|
|
*/
|
|
|
|
#if defined(DUK_USE_ASSERTIONS)
|
|
/* Whole path must be error throw free, but we may be called from
|
|
* within error handling so can't assert for error_not_allowed == 0.
|
|
*/
|
|
*prev_error_not_allowed = thr->heap->error_not_allowed;
|
|
thr->heap->error_not_allowed = 1;
|
|
#else
|
|
DUK_UNREF(prev_error_not_allowed);
|
|
#endif
|
|
*prev_ms_base_flags = thr->heap->ms_base_flags;
|
|
thr->heap->ms_base_flags |= flags_to_set;
|
|
thr->heap->pf_prevent_count++; /* Avoid finalizers. */
|
|
DUK_ASSERT(thr->heap->pf_prevent_count != 0); /* Wrap. */
|
|
}
|
|
|
|
DUK_INTERNAL void duk_hobject_end_critical(duk_hthread *thr,
|
|
duk_small_uint_t *prev_ms_base_flags,
|
|
duk_bool_t *prev_error_not_allowed) {
|
|
DUK_ASSERT(thr->heap->pf_prevent_count > 0);
|
|
thr->heap->pf_prevent_count--;
|
|
thr->heap->ms_base_flags = *prev_ms_base_flags;
|
|
#if defined(DUK_USE_ASSERTIONS)
|
|
DUK_ASSERT(thr->heap->error_not_allowed == 1);
|
|
thr->heap->error_not_allowed = *prev_error_not_allowed;
|
|
#else
|
|
DUK_UNREF(prev_error_not_allowed);
|
|
#endif
|
|
}
|
|
|