DUK_EXTERNAL void duk_call(duk_context *ctx, duk_idx_t nargs) { duk_hthread *thr = (duk_hthread *) ctx; duk_small_uint_t call_flags; duk_idx_t idx_func; DUK_ASSERT_CTX_VALID(ctx); DUK_ASSERT(thr != NULL); idx_func = duk_get_top(ctx) - nargs - 1; if (idx_func < 0 || nargs < 0) { /* note that we can't reliably pop anything here */ DUK_ERROR_TYPE_INVALID_ARGS(thr); } /* XXX: awkward; we assume there is space for this, overwrite * directly instead? */ duk_push_undefined(ctx); duk_insert(ctx, idx_func + 1); call_flags = 0; /* not protected, respect reclimit, not constructor */ duk_handle_call_unprotected(thr, /* thread */ nargs, /* num_stack_args */ call_flags); /* call_flags */ }
DUK_EXTERNAL duk_bool_t duk_put_prop(duk_context *ctx, duk_idx_t obj_index) { duk_hthread *thr = (duk_hthread *) ctx; duk_tval *tv_obj; duk_tval *tv_key; duk_tval *tv_val; duk_small_int_t throw_flag; duk_bool_t rc; DUK_ASSERT_CTX_VALID(ctx); /* Note: copying tv_obj and tv_key to locals to shield against a valstack * resize is not necessary for a property put right now (putprop protects * against it internally). */ tv_obj = duk_require_tval(ctx, obj_index); tv_key = duk_require_tval(ctx, -2); tv_val = duk_require_tval(ctx, -1); throw_flag = duk_is_strict_call(ctx); rc = duk_hobject_putprop(thr, tv_obj, tv_key, tv_val, throw_flag); DUK_ASSERT(rc == 0 || rc == 1); duk_pop_2(ctx); /* remove key and value */ return rc; /* 1 if property found, 0 otherwise */ }
DUK_EXTERNAL duk_int_t duk_get_magic(duk_context *ctx, duk_idx_t idx) { duk_hthread *thr = (duk_hthread *) ctx; duk_tval *tv; duk_hobject *h; DUK_ASSERT_CTX_VALID(ctx); tv = duk_require_tval(ctx, idx); if (DUK_TVAL_IS_OBJECT(tv)) { h = DUK_TVAL_GET_OBJECT(tv); DUK_ASSERT(h != NULL); if (!DUK_HOBJECT_HAS_NATFUNC(h)) { goto type_error; } return (duk_int_t) ((duk_hnatfunc *) h)->magic; } else if (DUK_TVAL_IS_LIGHTFUNC(tv)) { duk_small_uint_t lf_flags = DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv); return (duk_int_t) DUK_LFUNC_FLAGS_GET_MAGIC(lf_flags); } /* fall through */ type_error: DUK_ERROR_TYPE(thr, DUK_STR_UNEXPECTED_TYPE); return 0; }
DUK_EXTERNAL void duk_log_va(duk_context *ctx, duk_int_t level, const char *fmt, va_list ap) { /* stridx_logfunc[] must be static to allow initializer with old compilers like BCC */ static const duk_uint16_t stridx_logfunc[6] = { DUK_STRIDX_LC_TRACE, DUK_STRIDX_LC_DEBUG, DUK_STRIDX_LC_INFO, DUK_STRIDX_LC_WARN, DUK_STRIDX_LC_ERROR, DUK_STRIDX_LC_FATAL }; DUK_ASSERT_CTX_VALID(ctx); if (level < 0) { level = 0; } else if (level > (int) (sizeof(stridx_logfunc) / sizeof(duk_uint16_t)) - 1) { level = (int) (sizeof(stridx_logfunc) / sizeof(duk_uint16_t)) - 1; } duk_push_hobject_bidx(ctx, DUK_BIDX_LOGGER_CONSTRUCTOR); duk_get_prop_stridx(ctx, -1, DUK_STRIDX_CLOG); duk_get_prop_stridx(ctx, -1, stridx_logfunc[level]); duk_dup(ctx, -2); /* [ ... Logger clog logfunc clog ] */ duk_push_vsprintf(ctx, fmt, ap); /* [ ... Logger clog logfunc clog(=this) msg ] */ duk_call_method(ctx, 1 /*nargs*/); /* [ ... Logger clog res ] */ duk_pop_3(ctx); }
DUK_EXTERNAL duk_int_t duk_get_current_magic(duk_context *ctx) { duk_hthread *thr = (duk_hthread *) ctx; duk_activation *act; duk_hobject *func; DUK_ASSERT_CTX_VALID(ctx); DUK_ASSERT(thr != NULL); DUK_ASSERT_DISABLE(thr->callstack_top >= 0); act = duk_hthread_get_current_activation(thr); if (act) { func = DUK_ACT_GET_FUNC(act); if (!func) { duk_tval *tv = &act->tv_func; duk_small_uint_t lf_flags; lf_flags = DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv); return (duk_int_t) DUK_LFUNC_FLAGS_GET_MAGIC(lf_flags); } DUK_ASSERT(func != NULL); if (DUK_HOBJECT_IS_NATFUNC(func)) { duk_hnatfunc *nf = (duk_hnatfunc *) func; return (duk_int_t) nf->magic; } } return 0; }
/* Prepare value stack for a method call through an object property. * May currently throw an error e.g. when getting the property. */ DUK_LOCAL void duk__call_prop_prep_stack(duk_context *ctx, duk_idx_t normalized_obj_idx, duk_idx_t nargs) { DUK_ASSERT_CTX_VALID(ctx); DUK_DDD(DUK_DDDPRINT("duk__call_prop_prep_stack, normalized_obj_idx=%ld, nargs=%ld, stacktop=%ld", (long) normalized_obj_idx, (long) nargs, (long) duk_get_top(ctx))); /* [... key arg1 ... argN] */ /* duplicate key */ duk_dup(ctx, -nargs - 1); /* Note: -nargs alone would fail for nargs == 0, this is OK */ duk_get_prop(ctx, normalized_obj_idx); DUK_DDD(DUK_DDDPRINT("func: %!T", (duk_tval *) duk_get_tval(ctx, -1))); /* [... key arg1 ... argN func] */ duk_replace(ctx, -nargs - 2); /* [... func arg1 ... argN] */ duk_dup(ctx, normalized_obj_idx); duk_insert(ctx, -nargs - 1); /* [... func this arg1 ... argN] */ }
DUK_EXTERNAL duk_bool_t duk_next(duk_context *ctx, duk_idx_t enum_index, duk_bool_t get_value) { DUK_ASSERT_CTX_VALID(ctx); duk_require_hobject(ctx, enum_index); duk_dup(ctx, enum_index); return duk_hobject_enumerator_next(ctx, get_value); }
DUK_EXTERNAL duk_bool_t duk_get_prop_index(duk_context *ctx, duk_idx_t obj_index, duk_uarridx_t arr_index) { DUK_ASSERT_CTX_VALID(ctx); obj_index = duk_require_normalize_index(ctx, obj_index); duk_push_uarridx(ctx, arr_index); return duk_get_prop(ctx, obj_index); }
DUK_EXTERNAL void *duk_alloc_raw(duk_context *ctx, duk_size_t size) { duk_hthread *thr = (duk_hthread *) ctx; DUK_ASSERT_CTX_VALID(ctx); return DUK_ALLOC_RAW(thr->heap, size); }
DUK_EXTERNAL void duk_free(duk_context *ctx, void *ptr) { duk_hthread *thr = (duk_hthread *) ctx; DUK_ASSERT_CTX_VALID(ctx); DUK_FREE(thr->heap, ptr); }
DUK_EXTERNAL void duk_enum(duk_context *ctx, duk_idx_t obj_index, duk_uint_t enum_flags) { DUK_ASSERT_CTX_VALID(ctx); duk_dup(ctx, obj_index); duk_require_hobject_or_lfunc_coerce(ctx, -1); duk_hobject_enumerator_create(ctx, enum_flags); /* [target] -> [enum] */ }
DUK_EXTERNAL duk_bool_t duk_put_prop_index(duk_context *ctx, duk_idx_t obj_index, duk_uarridx_t arr_index) { DUK_ASSERT_CTX_VALID(ctx); obj_index = duk_require_normalize_index(ctx, obj_index); duk_push_uarridx(ctx, arr_index); duk_swap_top(ctx, -2); /* [val key] -> [key val] */ return duk_put_prop(ctx, obj_index); }
DUK_EXTERNAL duk_bool_t duk_get_prop_string(duk_context *ctx, duk_idx_t obj_index, const char *key) { DUK_ASSERT_CTX_VALID(ctx); DUK_ASSERT(key != NULL); obj_index = duk_require_normalize_index(ctx, obj_index); duk_push_string(ctx, key); return duk_get_prop(ctx, obj_index); }
DUK_EXTERNAL void duk_set_magic(duk_context *ctx, duk_idx_t idx, duk_int_t magic) { duk_hnatfunc *nf; DUK_ASSERT_CTX_VALID(ctx); nf = duk_require_hnatfunc(ctx, idx); DUK_ASSERT(nf != NULL); nf->magic = (duk_int16_t) magic; }
DUK_EXTERNAL void duk_log(duk_context *ctx, duk_int_t level, const char *fmt, ...) { va_list ap; DUK_ASSERT_CTX_VALID(ctx); va_start(ap, fmt); duk_log_va(ctx, level, fmt, ap); va_end(ap); }
DUK_INTERNAL duk_bool_t duk_get_prop_stridx(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx) { duk_hthread *thr = (duk_hthread *) ctx; DUK_ASSERT_CTX_VALID(ctx); DUK_ASSERT_DISABLE(stridx >= 0); DUK_ASSERT(stridx < DUK_HEAP_NUM_STRINGS); obj_index = duk_require_normalize_index(ctx, obj_index); duk_push_hstring(ctx, DUK_HTHREAD_GET_STRING(thr, stridx)); return duk_get_prop(ctx, obj_index); }
DUK_INTERNAL void duk_xdef_prop_index(duk_context *ctx, duk_idx_t obj_index, duk_uarridx_t arr_index, duk_small_uint_t desc_flags) { duk_hthread *thr = (duk_hthread *) ctx; duk_hobject *obj; DUK_ASSERT_CTX_VALID(ctx); obj = duk_require_hobject(ctx, obj_index); DUK_ASSERT(obj != NULL); duk_hobject_define_property_internal_arridx(thr, obj, arr_index, desc_flags); /* value popped by call */ }
DUK_EXTERNAL void duk_compact(duk_context *ctx, duk_idx_t obj_index) { duk_hthread *thr = (duk_hthread *) ctx; duk_hobject *obj; DUK_ASSERT_CTX_VALID(ctx); obj = duk_get_hobject(ctx, obj_index); if (obj) { /* Note: this may fail, caller should protect the call if necessary */ duk_hobject_compact_props(thr, obj); } }
DUK_EXTERNAL duk_bool_t duk_is_constructor_call(duk_context *ctx) { duk_hthread *thr = (duk_hthread *) ctx; duk_activation *act; DUK_ASSERT_CTX_VALID(ctx); DUK_ASSERT(thr != NULL); DUK_ASSERT_DISABLE(thr->callstack_top >= 0); act = duk_hthread_get_current_activation(thr); DUK_ASSERT(act != NULL); /* because callstack_top > 0 */ return ((act->flags & DUK_ACT_FLAG_CONSTRUCT) != 0 ? 1 : 0); }
DUK_EXTERNAL duk_bool_t duk_is_constructor_call(duk_context *ctx) { duk_hthread *thr = (duk_hthread *) ctx; duk_activation *act; DUK_ASSERT_CTX_VALID(ctx); DUK_ASSERT(thr != NULL); act = thr->callstack_curr; if (act != NULL) { return ((act->flags & DUK_ACT_FLAG_CONSTRUCT) != 0 ? 1 : 0); } return 0; }
DUK_EXTERNAL void duk_put_number_list(duk_context *ctx, duk_idx_t obj_index, const duk_number_list_entry *numbers) { const duk_number_list_entry *ent = numbers; DUK_ASSERT_CTX_VALID(ctx); obj_index = duk_require_normalize_index(ctx, obj_index); if (ent != NULL) { while (ent->key != NULL) { duk_push_number(ctx, ent->value); duk_put_prop_string(ctx, obj_index, ent->key); ent++; } } }
DUK_EXTERNAL duk_bool_t duk_get_global_string(duk_context *ctx, const char *key) { duk_hthread *thr = (duk_hthread *) ctx; duk_bool_t ret; DUK_ASSERT_CTX_VALID(ctx); DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL); /* XXX: direct implementation */ duk_push_hobject(ctx, thr->builtins[DUK_BIDX_GLOBAL]); ret = duk_get_prop_string(ctx, -1, key); duk_remove(ctx, -2); return ret; }
DUK_EXTERNAL void duk_put_function_list(duk_context *ctx, duk_idx_t obj_index, const duk_function_list_entry *funcs) { const duk_function_list_entry *ent = funcs; DUK_ASSERT_CTX_VALID(ctx); obj_index = duk_require_normalize_index(ctx, obj_index); if (ent != NULL) { while (ent->key != NULL) { duk_push_c_function(ctx, ent->value, ent->nargs); duk_put_prop_string(ctx, obj_index, ent->key); ent++; } } }
DUK_LOCAL void duk__concat_and_join_helper(duk_hthread *thr, duk_idx_t count_in, duk_bool_t is_join) { duk_uint_t count; duk_uint_t i; duk_size_t idx; duk_size_t len; duk_hstring *h; duk_uint8_t *buf; DUK_ASSERT_CTX_VALID(thr); if (DUK_UNLIKELY(count_in <= 0)) { if (count_in < 0) { DUK_ERROR_RANGE_INVALID_COUNT(thr); DUK_WO_NORETURN(return;); }
DUK_EXTERNAL void duk_get_memory_functions(duk_context *ctx, duk_memory_functions *out_funcs) { duk_hthread *thr = (duk_hthread *) ctx; duk_heap *heap; DUK_ASSERT_CTX_VALID(ctx); DUK_ASSERT(out_funcs != NULL); DUK_ASSERT(thr != NULL); DUK_ASSERT(thr->heap != NULL); heap = thr->heap; out_funcs->alloc_func = heap->alloc_func; out_funcs->realloc_func = heap->realloc_func; out_funcs->free_func = heap->free_func; out_funcs->udata = heap->heap_udata; }
DUK_EXTERNAL void duk_call_prop(duk_context *ctx, duk_idx_t obj_idx, duk_idx_t nargs) { /* * XXX: if duk_handle_call() took values through indices, this could be * made much more sensible. However, duk_handle_call() needs to fudge * the 'this' and 'func' values to handle bound function chains, which * is now done "in-place", so this is not a trivial change. */ DUK_ASSERT_CTX_VALID(ctx); obj_idx = duk_require_normalize_index(ctx, obj_idx); /* make absolute */ duk__call_prop_prep_stack(ctx, obj_idx, nargs); duk_call_method(ctx, nargs); }
DUK_INTERNAL duk_bool_t duk_get_prop_stridx_boolean(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx, duk_bool_t *out_has_prop) { duk_bool_t rc; DUK_ASSERT_CTX_VALID(ctx); DUK_ASSERT_DISABLE(stridx >= 0); DUK_ASSERT(stridx < DUK_HEAP_NUM_STRINGS); rc = duk_get_prop_stridx(ctx, obj_index, stridx); if (out_has_prop) { *out_has_prop = rc; } rc = duk_to_boolean(ctx, -1); DUK_ASSERT(rc == 0 || rc == 1); duk_pop(ctx); return rc; }
DUK_EXTERNAL duk_int_t duk_pnew(duk_context *ctx, duk_idx_t nargs) { duk_int_t rc; DUK_ASSERT_CTX_VALID(ctx); /* For now, just use duk_safe_call() to wrap duk_new(). We can't * simply use a protected duk_handle_call() because there's post * processing which might throw. It should be possible to ensure * the post processing never throws (except in internal errors and * out of memory etc which are always allowed) and then remove this * wrapper. */ rc = duk_safe_call(ctx, duk__pnew_helper, (void *) &nargs /*udata*/, nargs + 1 /*nargs*/, 1 /*nrets*/); return rc; }
DUK_LOCAL duk_ret_t duk__pcall_prop_raw(duk_context *ctx, void *udata) { duk_idx_t obj_idx; duk_idx_t nargs; duk__pcall_prop_args *args; DUK_ASSERT_CTX_VALID(ctx); DUK_ASSERT(udata != NULL); args = (duk__pcall_prop_args *) udata; obj_idx = args->obj_idx; nargs = args->nargs; obj_idx = duk_require_normalize_index(ctx, obj_idx); /* make absolute */ duk__call_prop_prep_stack(ctx, obj_idx, nargs); duk_call_method(ctx, nargs); return 1; }
/* Define own property without inheritance looks and such. This differs from * [[DefineOwnProperty]] because special behaviors (like Array 'length') are * not invoked by this method. The caller must be careful to invoke any such * behaviors if necessary. */ DUK_INTERNAL void duk_xdef_prop(duk_context *ctx, duk_idx_t obj_index, duk_small_uint_t desc_flags) { duk_hthread *thr = (duk_hthread *) ctx; duk_hobject *obj; duk_hstring *key; DUK_ASSERT_CTX_VALID(ctx); obj = duk_require_hobject(ctx, obj_index); DUK_ASSERT(obj != NULL); key = duk_to_hstring(ctx, -2); DUK_ASSERT(key != NULL); DUK_ASSERT(duk_require_tval(ctx, -1) != NULL); duk_hobject_define_property_internal(thr, obj, key, desc_flags); duk_pop(ctx); /* pop key */ }