Github User Fetcher 1.0.0
C Application with Server and GUI
Loading...
Searching...
No Matches
duk_js.h File Reference

Go to the source code of this file.

Macros

#define DUK_CALL_FLAG_IGNORE_RECLIMIT   (1 << 0) /* duk_handle_call_xxx: call ignores C recursion limit (for errhandler calls) */
 
#define DUK_CALL_FLAG_CONSTRUCTOR_CALL   (1 << 1) /* duk_handle_call_xxx: constructor call (i.e. called as 'new Foo()') */
 
#define DUK_CALL_FLAG_IS_RESUME   (1 << 2) /* duk_handle_ecma_call_setup: setup for a resume() */
 
#define DUK_CALL_FLAG_IS_TAILCALL   (1 << 3) /* duk_handle_ecma_call_setup: setup for a tail call */
 
#define DUK_CALL_FLAG_DIRECT_EVAL   (1 << 4) /* call is a direct eval call */
 
#define DUK_EQUALS_FLAG_SAMEVALUE   (1 << 0) /* use SameValue instead of non-strict equality */
 
#define DUK_EQUALS_FLAG_STRICT   (1 << 1) /* use strict equality instead of non-strict equality */
 
#define DUK_COMPARE_FLAG_EVAL_LEFT_FIRST   (1 << 0) /* eval left argument first */
 
#define DUK_COMPARE_FLAG_NEGATE   (1 << 1) /* negate result */
 
#define duk_js_equals(thr, tv_x, tv_y)    duk_js_equals_helper((thr), (tv_x), (tv_y), 0)
 
#define duk_js_strict_equals(tv_x, tv_y)    duk_js_equals_helper(NULL, (tv_x), (tv_y), DUK_EQUALS_FLAG_STRICT)
 
#define duk_js_samevalue(tv_x, tv_y)    duk_js_equals_helper(NULL, (tv_x), (tv_y), DUK_EQUALS_FLAG_SAMEVALUE)
 
#define duk_js_lessthan(thr, tv_x, tv_y)    duk_js_compare_helper((thr), (tv_x), (tv_Y), DUK_COMPARE_FLAG_EVAL_LEFT_FIRST)
 
#define duk_js_greaterthan(thr, tv_x, tv_y)    duk_js_compare_helper((thr), (tv_y), (tv_x), 0)
 
#define duk_js_lessthanorequal(thr, tv_x, tv_y)    duk_js_compare_helper((thr), (tv_y), (tv_x), DUK_COMPARE_FLAG_NEGATE)
 
#define duk_js_greaterthanorequal(thr, tv_x, tv_y)    duk_js_compare_helper((thr), (tv_x), (tv_y), DUK_COMPARE_FLAG_EVAL_LEFT_FIRST | DUK_COMPARE_FLAG_NEGATE)
 

Functions

DUK_INTERNAL_DECL duk_bool_t duk_js_toboolean (duk_tval *tv)
 
DUK_INTERNAL_DECL duk_double_t duk_js_tonumber (duk_hthread *thr, duk_tval *tv)
 
DUK_INTERNAL_DECL duk_double_t duk_js_tointeger_number (duk_double_t x)
 
DUK_INTERNAL_DECL duk_double_t duk_js_tointeger (duk_hthread *thr, duk_tval *tv)
 
DUK_INTERNAL_DECL duk_uint32_t duk_js_touint32 (duk_hthread *thr, duk_tval *tv)
 
DUK_INTERNAL_DECL duk_int32_t duk_js_toint32 (duk_hthread *thr, duk_tval *tv)
 
DUK_INTERNAL_DECL duk_uint16_t duk_js_touint16 (duk_hthread *thr, duk_tval *tv)
 
DUK_INTERNAL_DECL duk_small_int_t duk_js_to_arrayindex_raw_string (const duk_uint8_t *str, duk_uint32_t blen, duk_uarridx_t *out_idx)
 
DUK_INTERNAL_DECL duk_uarridx_t duk_js_to_arrayindex_string_helper (duk_hstring *h)
 
DUK_INTERNAL_DECL duk_bool_t duk_js_equals_helper (duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, duk_small_int_t flags)
 
DUK_INTERNAL_DECL duk_small_int_t duk_js_data_compare (const duk_uint8_t *buf1, const duk_uint8_t *buf2, duk_size_t len1, duk_size_t len2)
 
DUK_INTERNAL_DECL duk_small_int_t duk_js_string_compare (duk_hstring *h1, duk_hstring *h2)
 
DUK_INTERNAL_DECL duk_bool_t duk_js_compare_helper (duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, duk_small_int_t flags)
 
DUK_INTERNAL_DECL duk_bool_t duk_js_instanceof (duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y)
 
DUK_INTERNAL_DECL duk_bool_t duk_js_in (duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y)
 
DUK_INTERNAL_DECL duk_hstringduk_js_typeof (duk_hthread *thr, duk_tval *tv_x)
 
DUK_INTERNAL_DECL duk_bool_t duk_js_getvar_envrec (duk_hthread *thr, duk_hobject *env, duk_hstring *name, duk_bool_t throw_flag)
 
DUK_INTERNAL_DECL duk_bool_t duk_js_getvar_activation (duk_hthread *thr, duk_activation *act, duk_hstring *name, duk_bool_t throw_flag)
 
DUK_INTERNAL_DECL void duk_js_putvar_envrec (duk_hthread *thr, duk_hobject *env, duk_hstring *name, duk_tval *val, duk_bool_t strict)
 
DUK_INTERNAL_DECL void duk_js_putvar_activation (duk_hthread *thr, duk_activation *act, duk_hstring *name, duk_tval *val, duk_bool_t strict)
 
DUK_INTERNAL_DECL duk_bool_t duk_js_delvar_activation (duk_hthread *thr, duk_activation *act, duk_hstring *name)
 
DUK_INTERNAL_DECL duk_bool_t duk_js_declvar_activation (duk_hthread *thr, duk_activation *act, duk_hstring *name, duk_tval *val, duk_small_int_t prop_flags, duk_bool_t is_func_decl)
 
DUK_INTERNAL_DECL void duk_js_init_activation_environment_records_delayed (duk_hthread *thr, duk_activation *act)
 
DUK_INTERNAL_DECL void duk_js_close_environment_record (duk_hthread *thr, duk_hobject *env, duk_hobject *func, duk_size_t regbase)
 
DUK_INTERNAL_DECL duk_hobjectduk_create_activation_environment_record (duk_hthread *thr, duk_hobject *func, duk_size_t idx_bottom)
 
DUK_INTERNAL_DECL void duk_js_push_closure (duk_hthread *thr, duk_hcompiledfunction *fun_temp, duk_hobject *outer_var_env, duk_hobject *outer_lex_env, duk_bool_t add_auto_proto)
 
DUK_INTERNAL_DECL duk_int_t duk_handle_call_protected (duk_hthread *thr, duk_idx_t num_stack_args, duk_small_uint_t call_flags)
 
DUK_INTERNAL_DECL void duk_handle_call_unprotected (duk_hthread *thr, duk_idx_t num_stack_args, duk_small_uint_t call_flags)
 
DUK_INTERNAL_DECL duk_int_t duk_handle_safe_call (duk_hthread *thr, duk_safe_call_function func, duk_idx_t num_stack_args, duk_idx_t num_stack_res)
 
DUK_INTERNAL_DECL duk_bool_t duk_handle_ecma_call_setup (duk_hthread *thr, duk_idx_t num_stack_args, duk_small_uint_t call_flags)
 
DUK_INTERNAL_DECL void duk_js_execute_bytecode (duk_hthread *exec_thr)
 

Macro Definition Documentation

◆ DUK_CALL_FLAG_CONSTRUCTOR_CALL

#define DUK_CALL_FLAG_CONSTRUCTOR_CALL   (1 << 1) /* duk_handle_call_xxx: constructor call (i.e. called as 'new Foo()') */

Definition at line 10 of file duktape-1.5.2/src-separate/duk_js.h.

◆ DUK_CALL_FLAG_DIRECT_EVAL

#define DUK_CALL_FLAG_DIRECT_EVAL   (1 << 4) /* call is a direct eval call */

Definition at line 13 of file duktape-1.5.2/src-separate/duk_js.h.

◆ DUK_CALL_FLAG_IGNORE_RECLIMIT

#define DUK_CALL_FLAG_IGNORE_RECLIMIT   (1 << 0) /* duk_handle_call_xxx: call ignores C recursion limit (for errhandler calls) */

Definition at line 9 of file duktape-1.5.2/src-separate/duk_js.h.

◆ DUK_CALL_FLAG_IS_RESUME

#define DUK_CALL_FLAG_IS_RESUME   (1 << 2) /* duk_handle_ecma_call_setup: setup for a resume() */

Definition at line 11 of file duktape-1.5.2/src-separate/duk_js.h.

◆ DUK_CALL_FLAG_IS_TAILCALL

#define DUK_CALL_FLAG_IS_TAILCALL   (1 << 3) /* duk_handle_ecma_call_setup: setup for a tail call */

Definition at line 12 of file duktape-1.5.2/src-separate/duk_js.h.

◆ DUK_COMPARE_FLAG_EVAL_LEFT_FIRST

#define DUK_COMPARE_FLAG_EVAL_LEFT_FIRST   (1 << 0) /* eval left argument first */

Definition at line 20 of file duktape-1.5.2/src-separate/duk_js.h.

◆ DUK_COMPARE_FLAG_NEGATE

#define DUK_COMPARE_FLAG_NEGATE   (1 << 1) /* negate result */

Definition at line 21 of file duktape-1.5.2/src-separate/duk_js.h.

◆ DUK_EQUALS_FLAG_SAMEVALUE

#define DUK_EQUALS_FLAG_SAMEVALUE   (1 << 0) /* use SameValue instead of non-strict equality */

Definition at line 16 of file duktape-1.5.2/src-separate/duk_js.h.

◆ DUK_EQUALS_FLAG_STRICT

#define DUK_EQUALS_FLAG_STRICT   (1 << 1) /* use strict equality instead of non-strict equality */

Definition at line 17 of file duktape-1.5.2/src-separate/duk_js.h.

◆ duk_js_equals

#define duk_js_equals ( thr,
tv_x,
tv_y )    duk_js_equals_helper((thr), (tv_x), (tv_y), 0)

Definition at line 44 of file duktape-1.5.2/src-separate/duk_js.h.

44#define duk_js_equals(thr,tv_x,tv_y) \
45 duk_js_equals_helper((thr), (tv_x), (tv_y), 0)

◆ duk_js_greaterthan

#define duk_js_greaterthan ( thr,
tv_x,
tv_y )    duk_js_compare_helper((thr), (tv_y), (tv_x), 0)

Definition at line 56 of file duktape-1.5.2/src-separate/duk_js.h.

56#define duk_js_greaterthan(thr,tv_x,tv_y) \
57 duk_js_compare_helper((thr), (tv_y), (tv_x), 0)

◆ duk_js_greaterthanorequal

#define duk_js_greaterthanorequal ( thr,
tv_x,
tv_y )    duk_js_compare_helper((thr), (tv_x), (tv_y), DUK_COMPARE_FLAG_EVAL_LEFT_FIRST | DUK_COMPARE_FLAG_NEGATE)

Definition at line 64 of file duktape-1.5.2/src-separate/duk_js.h.

64#define duk_js_greaterthanorequal(thr,tv_x,tv_y) \
65 duk_js_compare_helper((thr), (tv_x), (tv_y), DUK_COMPARE_FLAG_EVAL_LEFT_FIRST | DUK_COMPARE_FLAG_NEGATE)

◆ duk_js_lessthan

#define duk_js_lessthan ( thr,
tv_x,
tv_y )    duk_js_compare_helper((thr), (tv_x), (tv_Y), DUK_COMPARE_FLAG_EVAL_LEFT_FIRST)

Definition at line 52 of file duktape-1.5.2/src-separate/duk_js.h.

52#define duk_js_lessthan(thr,tv_x,tv_y) \
53 duk_js_compare_helper((thr), (tv_x), (tv_Y), DUK_COMPARE_FLAG_EVAL_LEFT_FIRST)

◆ duk_js_lessthanorequal

#define duk_js_lessthanorequal ( thr,
tv_x,
tv_y )    duk_js_compare_helper((thr), (tv_y), (tv_x), DUK_COMPARE_FLAG_NEGATE)

Definition at line 60 of file duktape-1.5.2/src-separate/duk_js.h.

60#define duk_js_lessthanorequal(thr,tv_x,tv_y) \
61 duk_js_compare_helper((thr), (tv_y), (tv_x), DUK_COMPARE_FLAG_NEGATE)

◆ duk_js_samevalue

#define duk_js_samevalue ( tv_x,
tv_y )    duk_js_equals_helper(NULL, (tv_x), (tv_y), DUK_EQUALS_FLAG_SAMEVALUE)

Definition at line 48 of file duktape-1.5.2/src-separate/duk_js.h.

48#define duk_js_samevalue(tv_x,tv_y) \
49 duk_js_equals_helper(NULL, (tv_x), (tv_y), DUK_EQUALS_FLAG_SAMEVALUE)

◆ duk_js_strict_equals

#define duk_js_strict_equals ( tv_x,
tv_y )    duk_js_equals_helper(NULL, (tv_x), (tv_y), DUK_EQUALS_FLAG_STRICT)

Definition at line 46 of file duktape-1.5.2/src-separate/duk_js.h.

46#define duk_js_strict_equals(tv_x,tv_y) \
47 duk_js_equals_helper(NULL, (tv_x), (tv_y), DUK_EQUALS_FLAG_STRICT)

Function Documentation

◆ duk_create_activation_environment_record()

DUK_INTERNAL_DECL duk_hobject * duk_create_activation_environment_record ( duk_hthread * thr,
duk_hobject * func,
duk_size_t idx_bottom )

Definition at line 71582 of file duktape-1.5.2/src-noline/duktape.c.

71601 {
71602 duk_context *ctx = (duk_context *) thr;
71603 duk_hobject *env;
71604 duk_hobject *parent;
71605 duk_tval *tv;
71606
71607 DUK_ASSERT(thr != NULL);
71608 DUK_ASSERT(func != NULL);
71609
71611 if (tv) {
71614 parent = DUK_TVAL_GET_OBJECT(tv);
71615 } else {
71616 parent = thr->builtins[DUK_BIDX_GLOBAL_ENV];
71617 }
71618
71619 (void) duk_push_object_helper(ctx,
71622 -1); /* no prototype, updated below */
#define DUK_TVAL_GET_OBJECT(tv)
#define DUK_TVAL_IS_OBJECT(tv)
#define DUK_HTHREAD_STRING_INT_LEXENV(thr)
#define DUK_HOBJECT_CLASS_AS_FLAGS(v)
#define DUK_HOBJECT_IS_ENV(h)
DUK_INTERNAL_DECL duk_tval * duk_hobject_find_existing_entry_tval_ptr(duk_heap *heap, duk_hobject *obj, duk_hstring *key)
#define DUK_HOBJECT_CLASS_DECENV
#define DUK_HOBJECT_FLAG_EXTENSIBLE
DUK_INTERNAL_DECL duk_idx_t duk_push_object_helper(duk_context *ctx, duk_uint_t hobject_flags_and_class, duk_small_int_t prototype_bidx)
#define NULL
Definition gmacros.h:924
duk_hobject * builtins[DUK_NUM_BUILTINS]

◆ duk_handle_call_protected()

DUK_INTERNAL_DECL duk_int_t duk_handle_call_protected ( duk_hthread * thr,
duk_idx_t num_stack_args,
duk_small_uint_t call_flags )

Definition at line 55593 of file duktape-1.5.2/src-noline/duktape.c.

55596 :
55597 *
55598 * [ retval ] (DUK_EXEC_SUCCESS)
55599 * [ errobj ] (DUK_EXEC_ERROR (normal error), protected call)
55600 *
55601 * Even when executing a protected call an error may be thrown in rare cases
55602 * such as an insane num_stack_args argument. If there is no catchpoint for
55603 * such errors, the fatal error handler is called.
55604 *
55605 * The error handling path should be error free, even for out-of-memory
55606 * errors, to ensure safe sandboxing. (As of Duktape 1.4.0 this is not
55607 * yet the case, see XXX notes below.)
55608 */
55609
55611 duk_idx_t num_stack_args,
55612 duk_small_uint_t call_flags) {
55613 duk_context *ctx;
55614 duk_size_t entry_valstack_bottom_index;
55615 duk_size_t entry_valstack_end;
55616 duk_size_t entry_callstack_top;
55617 duk_size_t entry_catchstack_top;
55618 duk_int_t entry_call_recursion_depth;
55619 duk_hthread *entry_curr_thread;
55620 duk_uint_fast8_t entry_thread_state;
55621 duk_instr_t **entry_ptr_curr_pc;
55622 duk_jmpbuf *old_jmpbuf_ptr = NULL;
55623 duk_jmpbuf our_jmpbuf;
55624 duk_idx_t idx_func; /* valstack index of 'func' and retval (relative to entry valstack_bottom) */
55625
55626 /* XXX: Multiple tv_func lookups are now avoided by making a local
55627 * copy of tv_func. Another approach would be to compute an offset
55628 * for tv_func from valstack bottom and recomputing the tv_func
55629 * pointer quickly as valstack + offset instead of calling duk_get_tval().
55630 */
55631
55632 ctx = (duk_context *) thr;
55633 DUK_UNREF(ctx);
55634 DUK_ASSERT(thr != NULL);
55636 DUK_ASSERT(num_stack_args >= 0);
55637 /* XXX: currently NULL allocations are not supported; remove if later allowed */
55638 DUK_ASSERT(thr->valstack != NULL);
55639 DUK_ASSERT(thr->callstack != NULL);
55640 DUK_ASSERT(thr->catchstack != NULL);
55641
55642 /* Argument validation and func/args offset. */
55643 idx_func = duk__get_idx_func(thr, num_stack_args);
55644
55645 /* Preliminaries, required by setjmp() handler. Must be careful not
55646 * to throw an unintended error here.
55647 */
55648
55649 entry_valstack_bottom_index = (duk_size_t) (thr->valstack_bottom - thr->valstack);
55650#if defined(DUK_USE_PREFER_SIZE)
55651 entry_valstack_end = (duk_size_t) (thr->valstack_end - thr->valstack);
55652#else
55653 DUK_ASSERT((duk_size_t) (thr->valstack_end - thr->valstack) == thr->valstack_size);
55654 entry_valstack_end = thr->valstack_size;
55655#endif
55656 entry_callstack_top = thr->callstack_top;
55657 entry_catchstack_top = thr->catchstack_top;
55658 entry_call_recursion_depth = thr->heap->call_recursion_depth;
55659 entry_curr_thread = thr->heap->curr_thread; /* Note: may be NULL if first call */
55660 entry_thread_state = thr->state;
55661 entry_ptr_curr_pc = thr->ptr_curr_pc; /* may be NULL */
55662
55663 DUK_DD(DUK_DDPRINT("duk_handle_call_protected: thr=%p, num_stack_args=%ld, "
55664 "call_flags=0x%08lx (ignorerec=%ld, constructor=%ld), "
55665 "valstack_top=%ld, idx_func=%ld, idx_args=%ld, rec_depth=%ld/%ld, "
55666 "entry_valstack_bottom_index=%ld, entry_callstack_top=%ld, entry_catchstack_top=%ld, "
55667 "entry_call_recursion_depth=%ld, entry_curr_thread=%p, entry_thread_state=%ld",
55668 (void *) thr,
55669 (long) num_stack_args,
55670 (unsigned long) call_flags,
55671 (long) ((call_flags & DUK_CALL_FLAG_IGNORE_RECLIMIT) != 0 ? 1 : 0),
55672 (long) ((call_flags & DUK_CALL_FLAG_CONSTRUCTOR_CALL) != 0 ? 1 : 0),
55673 (long) duk_get_top(ctx),
55674 (long) idx_func,
55675 (long) (idx_func + 2),
55676 (long) thr->heap->call_recursion_depth,
55677 (long) thr->heap->call_recursion_limit,
55678 (long) entry_valstack_bottom_index,
55679 (long) entry_callstack_top,
55680 (long) entry_catchstack_top,
55681 (long) entry_call_recursion_depth,
55682 (void *) entry_curr_thread,
55683 (long) entry_thread_state));
55684
55685 old_jmpbuf_ptr = thr->heap->lj.jmpbuf_ptr;
55686 thr->heap->lj.jmpbuf_ptr = &our_jmpbuf;
55687
55688#if defined(DUK_USE_CPP_EXCEPTIONS)
55689 try {
55690#else
55691 DUK_ASSERT(thr->heap->lj.jmpbuf_ptr == &our_jmpbuf);
55692 if (DUK_SETJMP(our_jmpbuf.jb) == 0) {
55693#endif
55694 /* Call handling and success path. Success path exit cleans
55695 * up almost all state.
55696 */
55697 duk__handle_call_inner(thr, num_stack_args, call_flags, idx_func);
55698
55699 /* Success path handles */
55700 DUK_ASSERT(thr->heap->call_recursion_depth == entry_call_recursion_depth);
55701 DUK_ASSERT(thr->ptr_curr_pc == entry_ptr_curr_pc);
55702
55703 /* Longjmp state is kept clean in success path */
55704 DUK_ASSERT(thr->heap->lj.type == DUK_LJ_TYPE_UNKNOWN);
55705 DUK_ASSERT(thr->heap->lj.iserror == 0);
55706 DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value1));
55707 DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value2));
55708
55709 thr->heap->lj.jmpbuf_ptr = old_jmpbuf_ptr;
55710
55711 return DUK_EXEC_SUCCESS;
55712#if defined(DUK_USE_CPP_EXCEPTIONS)
55713 } catch (duk_internal_exception &exc) {
55714#else
55715 } else {
55716#endif
55717 /* Error; error value is in heap->lj.value1. */
55718
55719#if defined(DUK_USE_CPP_EXCEPTIONS)
55720 DUK_UNREF(exc);
55721#endif
55722
55724 entry_valstack_bottom_index,
55725 entry_valstack_end,
55726 entry_catchstack_top,
55727 entry_callstack_top,
55728 entry_call_recursion_depth,
55729 entry_curr_thread,
55730 entry_thread_state,
55731 entry_ptr_curr_pc,
55732 idx_func,
55733 old_jmpbuf_ptr);
55734
55735 /* Longjmp state is cleaned up by error handling */
55736 DUK_ASSERT(thr->heap->lj.type == DUK_LJ_TYPE_UNKNOWN);
55737 DUK_ASSERT(thr->heap->lj.iserror == 0);
55738 DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value1));
55739 DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value2));
55740 return DUK_EXEC_ERROR;
55741 }
55742#if defined(DUK_USE_CPP_EXCEPTIONS)
55743 catch (std::exception &exc) {
55744 const char *what = exc.what();
55745 if (!what) {
55746 what = "unknown";
55747 }
55748 DUK_D(DUK_DPRINT("unexpected c++ std::exception (perhaps thrown by user code)"));
55749 try {
55750 DUK_ERROR_FMT1(thr, DUK_ERR_API_ERROR, "caught invalid c++ std::exception '%s' (perhaps thrown by user code)", what);
55751 } catch (duk_internal_exception exc) {
55752 DUK_D(DUK_DPRINT("caught api error thrown from unexpected c++ std::exception"));
55753 DUK_UNREF(exc);
55755 entry_valstack_bottom_index,
55756 entry_valstack_end,
55757 entry_catchstack_top,
55758 entry_callstack_top,
55759 entry_call_recursion_depth,
55760 entry_curr_thread,
55761 entry_thread_state,
55762 entry_ptr_curr_pc,
55763 idx_func,
55764 old_jmpbuf_ptr);
55765 return DUK_EXEC_ERROR;
55766 }
55767 } catch (...) {
55768 DUK_D(DUK_DPRINT("unexpected c++ exception (perhaps thrown by user code)"));
55769 try {
55770 DUK_ERROR_API(thr, "caught invalid c++ exception (perhaps thrown by user code)");
55771 } catch (duk_internal_exception exc) {
55772 DUK_D(DUK_DPRINT("caught api error thrown from unexpected c++ exception"));
#define free
Definition civetweb.c:1542
unsigned int duk_small_uint_t
duk_uint8_t duk_uint_fast8_t
duk_int_fast32_t duk_int_t
#define DUK_ASSERT_CTX_VALID(ctx)
DUK_LOCAL duk_idx_t duk__get_idx_func(duk_hthread *thr, duk_idx_t num_stack_args)
#define DUK_CALL_FLAG_CONSTRUCTOR_CALL
#define DUK_TVAL_IS_UNDEFINED(tv)
#define DUK_ERROR_API(thr, msg)
DUK_LOCAL void duk__handle_call_inner(duk_hthread *thr, duk_idx_t num_stack_args, duk_small_uint_t call_flags, duk_idx_t idx_func)
DUK_LOCAL void duk__handle_call_error(duk_hthread *thr, duk_size_t entry_valstack_bottom_index, duk_size_t entry_valstack_end, duk_size_t entry_catchstack_top, duk_size_t entry_callstack_top, duk_int_t entry_call_recursion_depth, duk_hthread *entry_curr_thread, duk_uint_fast8_t entry_thread_state, duk_instr_t **entry_ptr_curr_pc, duk_idx_t idx_func, duk_jmpbuf *old_jmpbuf_ptr)
DUK_EXTERNAL duk_idx_t duk_get_top(duk_context *ctx)
duk_uint32_t duk_instr_t
DUK_INTERNAL_DECL duk_int_t duk_handle_call_protected(duk_hthread *thr, duk_idx_t num_stack_args, duk_small_uint_t call_flags)
#define DUK_ERROR_FMT1(thr, err, fmt, arg1)
#define DUK_CALL_FLAG_IGNORE_RECLIMIT
static void fatal(const char *message)
static void error(LoadState *S, const char *why)

◆ duk_handle_call_unprotected()

DUK_INTERNAL_DECL void duk_handle_call_unprotected ( duk_hthread * thr,
duk_idx_t num_stack_args,
duk_small_uint_t call_flags )

Definition at line 55774 of file duktape-1.5.2/src-noline/duktape.c.

◆ duk_handle_ecma_call_setup()

DUK_INTERNAL_DECL duk_bool_t duk_handle_ecma_call_setup ( duk_hthread * thr,
duk_idx_t num_stack_args,
duk_small_uint_t call_flags )

Definition at line 56917 of file duktape-1.5.2/src-noline/duktape.c.

56936 {
56937 duk_context *ctx = (duk_context *) thr;
56938 duk_size_t entry_valstack_bottom_index;
56939 duk_idx_t idx_func; /* valstack index of 'func' and retval (relative to entry valstack_bottom) */
56940 duk_idx_t idx_args; /* valstack index of start of args (arg1) (relative to entry valstack_bottom) */
56941 duk_idx_t nargs; /* # argument registers target function wants (< 0 => never for ecma calls) */
56942 duk_idx_t nregs; /* # total registers target function wants on entry (< 0 => never for ecma calls) */
56943 duk_hobject *func; /* 'func' on stack (borrowed reference) */
56944 duk_tval *tv_func; /* duk_tval ptr for 'func' on stack (borrowed reference) */
56945 duk_activation *act;
56946 duk_hobject *env;
56947 duk_bool_t use_tailcall;
56948 duk_instr_t **entry_ptr_curr_pc;
56949
56950 DUK_ASSERT(thr != NULL);
56951 DUK_ASSERT(ctx != NULL);
56952 DUK_ASSERT(!((call_flags & DUK_CALL_FLAG_IS_RESUME) != 0 && (call_flags & DUK_CALL_FLAG_IS_TAILCALL) != 0));
56953
56954 /* XXX: assume these? */
56955 DUK_ASSERT(thr->valstack != NULL);
56956 DUK_ASSERT(thr->callstack != NULL);
56957 DUK_ASSERT(thr->catchstack != NULL);
56958
56959 /* no need to handle thread state book-keeping here */
56960 DUK_ASSERT((call_flags & DUK_CALL_FLAG_IS_RESUME) != 0 ||
56962 thr->heap->curr_thread == thr));
56963
56964 /* If thr->ptr_curr_pc is set, sync curr_pc to act->pc. Then NULL
56965 * thr->ptr_curr_pc so that it's not accidentally used with an incorrect
56966 * activation when side effects occur. If we end up not making the
56967 * call we must restore the value.
56968 */
56969 entry_ptr_curr_pc = thr->ptr_curr_pc;
56971
56972 /* if a tail call:
56973 * - an Ecmascript activation must be on top of the callstack
56974 * - there cannot be any active catchstack entries
56975 */
56976#if defined(DUK_USE_ASSERTIONS)
56977 if (call_flags & DUK_CALL_FLAG_IS_TAILCALL) {
56978 duk_size_t our_callstack_index;
56979 duk_size_t i;
56980
56981 DUK_ASSERT(thr->callstack_top >= 1);
56982 our_callstack_index = thr->callstack_top - 1;
56983 DUK_ASSERT_DISABLE(our_callstack_index >= 0);
56984 DUK_ASSERT(our_callstack_index < thr->callstack_size);
56985 DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + our_callstack_index) != NULL);
56987
56988 /* No entry in the catchstack which would actually catch a
56989 * throw can refer to the callstack entry being reused.
56990 * There *can* be catchstack entries referring to the current
56991 * callstack entry as long as they don't catch (e.g. label sites).
56992 */
56993
56994 for (i = 0; i < thr->catchstack_top; i++) {
56995 DUK_ASSERT(thr->catchstack[i].callstack_index < our_callstack_index || /* refer to callstack entries below current */
56996 DUK_CAT_GET_TYPE(thr->catchstack + i) == DUK_CAT_TYPE_LABEL); /* or a non-catching entry */
56997 }
56998 }
56999#endif /* DUK_USE_ASSERTIONS */
57000
57001 entry_valstack_bottom_index = (duk_size_t) (thr->valstack_bottom - thr->valstack);
57002 /* XXX: rework */
57003 idx_func = duk_normalize_index(thr, -num_stack_args - 2);
57004 idx_args = idx_func + 2;
57005
57006 DUK_DD(DUK_DDPRINT("handle_ecma_call_setup: thr=%p, "
57007 "num_stack_args=%ld, call_flags=0x%08lx (resume=%ld, tailcall=%ld), "
57008 "idx_func=%ld, idx_args=%ld, entry_valstack_bottom_index=%ld",
57009 (void *) thr,
57010 (long) num_stack_args,
57011 (unsigned long) call_flags,
57012 (long) ((call_flags & DUK_CALL_FLAG_IS_RESUME) != 0 ? 1 : 0),
57013 (long) ((call_flags & DUK_CALL_FLAG_IS_TAILCALL) != 0 ? 1 : 0),
57014 (long) idx_func,
57015 (long) idx_args,
57016 (long) entry_valstack_bottom_index));
57017
57018 if (DUK_UNLIKELY(idx_func < 0 || idx_args < 0)) {
57019 /* XXX: assert? compiler is responsible for this never happening */
57021 }
57022
57023 /*
57024 * Check the function type, handle bound function chains, and prepare
57025 * parameters for the rest of the call handling. Also figure out the
57026 * effective 'this' binding, which replaces the current value at
57027 * idx_func + 1.
57028 *
57029 * If the target function is a 'bound' one, follow the chain of 'bound'
57030 * functions until a non-bound function is found. During this process,
57031 * bound arguments are 'prepended' to existing ones, and the "this"
57032 * binding is overridden. See E5 Section 15.3.4.5.1.
57033 *
57034 * If the final target function cannot be handled by an ecma-to-ecma
57035 * call, return to the caller with a return value indicating this case.
57036 * The bound chain is resolved and the caller can resume with a plain
57037 * function call.
57038 */
57039
57040 func = duk__nonbound_func_lookup(ctx, idx_func, &num_stack_args, &tv_func, call_flags);
57041 if (func == NULL || !DUK_HOBJECT_IS_COMPILEDFUNCTION(func)) {
57042 DUK_DDD(DUK_DDDPRINT("final target is a lightfunc/nativefunc, cannot do ecma-to-ecma call"));
57043 thr->ptr_curr_pc = entry_ptr_curr_pc;
57044 return 0;
57045 }
57046 /* XXX: tv_func is not actually needed */
57047
57048 DUK_ASSERT(func != NULL);
57051
57052 duk__coerce_effective_this_binding(thr, func, idx_func + 1);
57053 DUK_DDD(DUK_DDDPRINT("effective 'this' binding is: %!T",
57054 duk_get_tval(ctx, idx_func + 1)));
57055
57056 nargs = ((duk_hcompiledfunction *) func)->nargs;
57057 nregs = ((duk_hcompiledfunction *) func)->nregs;
57058 DUK_ASSERT(nregs >= nargs);
57059
57060 /* [ ... func this arg1 ... argN ] */
57061
57062 /*
57063 * Preliminary activation record and valstack manipulation.
57064 * The concrete actions depend on whether the we're dealing
57065 * with a tail call (reuse an existing activation), a resume,
57066 * or a normal call.
57067 *
57068 * The basic actions, in varying order, are:
57069 *
57070 * - Check stack size for call handling
57071 * - Grow call stack if necessary (non-tail-calls)
57072 * - Update current activation (idx_retval) if necessary
57073 * (non-tail, non-resume calls)
57074 * - Move start of args (idx_args) to valstack bottom
57075 * (tail calls)
57076 *
57077 * Don't touch valstack_bottom or valstack_top yet so that Duktape API
57078 * calls work normally.
57079 */
57080
57081 /* XXX: some overlapping code; cleanup */
57082 use_tailcall = call_flags & DUK_CALL_FLAG_IS_TAILCALL;
57083#if !defined(DUK_USE_TAILCALL)
57084 DUK_ASSERT(use_tailcall == 0); /* compiler ensures this */
57085#endif
57086 if (use_tailcall) {
57087 /* tailcall cannot be flagged to resume calls, and a
57088 * previous frame must exist
57089 */
57090 DUK_ASSERT(thr->callstack_top >= 1);
57091 DUK_ASSERT((call_flags & DUK_CALL_FLAG_IS_RESUME) == 0);
57092
57093 act = thr->callstack + thr->callstack_top - 1;
57094 if (act->flags & DUK_ACT_FLAG_PREVENT_YIELD) {
57095 /* See: test-bug-tailcall-preventyield-assert.c. */
57096 DUK_DDD(DUK_DDDPRINT("tail call prevented by current activation having DUK_ACT_FLAG_PREVENTYIELD"));
57097 use_tailcall = 0;
57098 } else if (DUK_HOBJECT_HAS_NOTAIL(func)) {
57099 DUK_D(DUK_DPRINT("tail call prevented by function having a notail flag"));
57100 use_tailcall = 0;
57101 }
57102 }
57103
57104 if (use_tailcall) {
57105 duk_tval *tv1, *tv2;
57106 duk_size_t cs_index;
57107 duk_int_t i_stk; /* must be signed for loop structure */
57108 duk_idx_t i_arg;
57109
57110 /*
57111 * Tailcall handling
57112 *
57113 * Although the callstack entry is reused, we need to explicitly unwind
57114 * the current activation (or simulate an unwind). In particular, the
57115 * current activation must be closed, otherwise something like
57116 * test-bug-reduce-judofyr.js results. Also catchstack needs be unwound
57117 * because there may be non-error-catching label entries in valid tail calls.
57118 */
57119
57120 DUK_DDD(DUK_DDDPRINT("is tail call, reusing activation at callstack top, at index %ld",
57121 (long) (thr->callstack_top - 1)));
57122
57123 /* 'act' already set above */
57124
57129
57130 /* Unwind catchstack entries referring to the callstack entry we're reusing */
57131 cs_index = thr->callstack_top - 1;
57132 DUK_ASSERT(thr->catchstack_top <= DUK_INT_MAX); /* catchstack limits */
57133 for (i_stk = (duk_int_t) (thr->catchstack_top - 1); i_stk >= 0; i_stk--) {
57134 duk_catcher *cat = thr->catchstack + i_stk;
57135 if (cat->callstack_index != cs_index) {
57136 /* 'i' is the first entry we'll keep */
57137 break;
57138 }
57139 }
57140 duk_hthread_catchstack_unwind(thr, i_stk + 1);
57141
57142 /* Unwind the topmost callstack entry before reusing it */
57143 DUK_ASSERT(thr->callstack_top > 0);
57144 duk_hthread_callstack_unwind(thr, thr->callstack_top - 1);
57145
57146 /* Then reuse the unwound activation; callstack was not shrunk so there is always space */
57147 thr->callstack_top++;
57148 DUK_ASSERT(thr->callstack_top <= thr->callstack_size);
57149 act = thr->callstack + thr->callstack_top - 1;
57150
57151 /* Start filling in the activation */
57152 act->func = func; /* don't want an intermediate exposed state with func == NULL */
57153#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
57154 act->prev_caller = NULL;
57155#endif
57156 DUK_ASSERT(func != NULL);
57158 /* don't want an intermediate exposed state with invalid pc */
57160#if defined(DUK_USE_DEBUGGER_SUPPORT)
57161 act->prev_line = 0;
57162#endif
57163 DUK_TVAL_SET_OBJECT(&act->tv_func, func); /* borrowed, no refcount */
57164#if defined(DUK_USE_REFERENCE_COUNTING)
57165 DUK_HOBJECT_INCREF(thr, func);
57166 act = thr->callstack + thr->callstack_top - 1; /* side effects (currently none though) */
57167#endif
57168
57169#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
57170#if defined(DUK_USE_TAILCALL)
57171#error incorrect options: tail calls enabled with function caller property
57172#endif
57173 /* XXX: this doesn't actually work properly for tail calls, so
57174 * tail calls are disabled when DUK_USE_NONSTD_FUNC_CALLER_PROPERTY
57175 * is in use.
57176 */
57177 duk__update_func_caller_prop(thr, func);
57178 act = thr->callstack + thr->callstack_top - 1;
57179#endif
57180
57181 act->flags = (DUK_HOBJECT_HAS_STRICT(func) ?
57184
57185 DUK_ASSERT(DUK_ACT_GET_FUNC(act) == func); /* already updated */
57186 DUK_ASSERT(act->var_env == NULL); /* already NULLed (by unwind) */
57187 DUK_ASSERT(act->lex_env == NULL); /* already NULLed (by unwind) */
57188 act->idx_bottom = entry_valstack_bottom_index; /* tail call -> reuse current "frame" */
57189 DUK_ASSERT(nregs >= 0);
57190#if 0 /* topmost activation idx_retval is considered garbage, no need to init */
57191 act->idx_retval = 0;
57192#endif
57193
57194 /*
57195 * Manipulate valstack so that args are on the current bottom and the
57196 * previous caller's 'this' binding (which is the value preceding the
57197 * current bottom) is replaced with the new 'this' binding:
57198 *
57199 * [ ... this_old | (crud) func this_new arg1 ... argN ]
57200 * --> [ ... this_new | arg1 ... argN ]
57201 *
57202 * For tail calling to work properly, the valstack bottom must not grow
57203 * here; otherwise crud would accumulate on the valstack.
57204 */
57205
57206 tv1 = thr->valstack_bottom - 1;
57207 tv2 = thr->valstack_bottom + idx_func + 1;
57208 DUK_ASSERT(tv1 >= thr->valstack && tv1 < thr->valstack_top); /* tv1 is -below- valstack_bottom */
57209 DUK_ASSERT(tv2 >= thr->valstack_bottom && tv2 < thr->valstack_top);
57210 DUK_TVAL_SET_TVAL_UPDREF(thr, tv1, tv2); /* side effects */
57211
57212 for (i_arg = 0; i_arg < idx_args; i_arg++) {
57213 /* XXX: block removal API primitive */
57214 /* Note: 'func' is popped from valstack here, but it is
57215 * already reachable from the activation.
57216 */
57217 duk_remove(ctx, 0);
57218 }
57219 idx_func = 0; DUK_UNREF(idx_func); /* really 'not applicable' anymore, should not be referenced after this */
57220 idx_args = 0;
57221
57222 /* [ ... this_new | arg1 ... argN ] */
57223 } else {
57224 DUK_DDD(DUK_DDDPRINT("not a tail call, pushing a new activation to callstack, to index %ld",
57225 (long) (thr->callstack_top)));
57226
57228
57229 if (call_flags & DUK_CALL_FLAG_IS_RESUME) {
57230 DUK_DDD(DUK_DDDPRINT("is resume -> no update to current activation (may not even exist)"));
57231 } else {
57232 DUK_DDD(DUK_DDDPRINT("update to current activation idx_retval"));
57233 DUK_ASSERT(thr->callstack_top < thr->callstack_size);
57234 DUK_ASSERT(thr->callstack_top >= 1);
57235 act = thr->callstack + thr->callstack_top - 1;
57238 act->idx_retval = entry_valstack_bottom_index + idx_func;
57239 }
57240
57241 DUK_ASSERT(thr->callstack_top < thr->callstack_size);
57242 act = thr->callstack + thr->callstack_top;
57243 thr->callstack_top++;
57244 DUK_ASSERT(thr->callstack_top <= thr->callstack_size);
57245
57249
57250 act->flags = (DUK_HOBJECT_HAS_STRICT(func) ?
57252 0);
57253 act->func = func;
57254 act->var_env = NULL;
57255 act->lex_env = NULL;
57256#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
57257 act->prev_caller = NULL;
57258#endif
57259 DUK_ASSERT(func != NULL);
57262#if defined(DUK_USE_DEBUGGER_SUPPORT)
57263 act->prev_line = 0;
57264#endif
57265 act->idx_bottom = entry_valstack_bottom_index + idx_args;
57266 DUK_ASSERT(nregs >= 0);
57267#if 0 /* topmost activation idx_retval is considered garbage, no need to init */
57268 act->idx_retval = 0;
57269#endif
57270 DUK_TVAL_SET_OBJECT(&act->tv_func, func); /* borrowed, no refcount */
57271
57272 DUK_HOBJECT_INCREF(thr, func); /* act->func */
57273
57274#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
57275 duk__update_func_caller_prop(thr, func);
57276 act = thr->callstack + thr->callstack_top - 1;
57277#endif
57278 }
57279
57280 /* [ ... func this arg1 ... argN ] (not tail call)
57281 * [ this | arg1 ... argN ] (tail call)
57282 *
57283 * idx_args updated to match
57284 */
57285
57286 /*
57287 * Environment record creation and 'arguments' object creation.
57288 * Named function expression name binding is handled by the
57289 * compiler; the compiled function's parent env will contain
57290 * the (immutable) binding already.
57291 *
57292 * Delayed creation (on demand) is handled in duk_js_var.c.
57293 */
57294
57295 /* XXX: unify handling with native call. */
57296
57297 DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(func)); /* bound function chain has already been resolved */
57298
57299 if (!DUK_HOBJECT_HAS_NEWENV(func)) {
57300 /* use existing env (e.g. for non-strict eval); cannot have
57301 * an own 'arguments' object (but can refer to the existing one)
57302 */
57303
57304 duk__handle_oldenv_for_call(thr, func, act);
57305
57306 DUK_ASSERT(act->lex_env != NULL);
57307 DUK_ASSERT(act->var_env != NULL);
57308 goto env_done;
57309 }
57310
57312
57313 if (!DUK_HOBJECT_HAS_CREATEARGS(func)) {
57314 /* no need to create environment record now; leave as NULL */
57315 DUK_ASSERT(act->lex_env == NULL);
57316 DUK_ASSERT(act->var_env == NULL);
57317 goto env_done;
57318 }
57319
57320 /* third arg: absolute index (to entire valstack) of idx_bottom of new activation */
57322 DUK_ASSERT(env != NULL);
57323
57324 /* [ ... arg1 ... argN envobj ] */
57325
57326 /* original input stack before nargs/nregs handling must be
57327 * intact for 'arguments' object
57328 */
57330 duk__handle_createargs_for_call(thr, func, env, num_stack_args);
57331
57332 /* [ ... arg1 ... argN envobj ] */
57333
57334 act = thr->callstack + thr->callstack_top - 1;
57335 act->lex_env = env;
57336 act->var_env = env;
57337 DUK_HOBJECT_INCREF(thr, act->lex_env);
57338 DUK_HOBJECT_INCREF(thr, act->var_env);
57339 duk_pop(ctx);
57340
57341 env_done:
57342 /* [ ... arg1 ... argN ] */
57343
57344 /*
57345 * Setup value stack: clamp to 'nargs', fill up to 'nregs'
57346 */
57347
57349 num_stack_args,
57350 idx_args,
57351 nregs,
57352 nargs,
57353 func);
57354
duk_small_int_t duk_bool_t
#define DUK_ACT_FLAG_TAILCALLED
DUK_INTERNAL_DECL void duk_hthread_callstack_grow(duk_hthread *thr)
#define DUK_ACT_FLAG_PREVENT_YIELD
DUK_LOCAL void duk__coerce_effective_this_binding(duk_hthread *thr, duk_hobject *func, duk_idx_t idx_this)
DUK_LOCAL duk_hobject * duk__nonbound_func_lookup(duk_context *ctx, duk_idx_t idx_func, duk_idx_t *out_num_stack_args, duk_tval **out_tv_func, duk_small_uint_t call_flags)
DUK_EXTERNAL duk_idx_t duk_normalize_index(duk_context *ctx, duk_idx_t index)
#define DUK_HCOMPILEDFUNCTION_GET_CODE_BASE(heap, h)
#define DUK_HOBJECT_HAS_BOUND(h)
#define DUK_CAT_GET_TYPE(c)
DUK_LOCAL void duk__handle_oldenv_for_call(duk_hthread *thr, duk_hobject *func, duk_activation *act)
DUK_LOCAL void duk__adjust_valstack_and_top(duk_hthread *thr, duk_idx_t num_stack_args, duk_idx_t idx_args, duk_idx_t nregs, duk_idx_t nargs, duk_hobject *func)
#define DUK_TVAL_SET_OBJECT(tv, hptr)
DUK_INTERNAL_DECL void duk_hthread_catchstack_unwind(duk_hthread *thr, duk_size_t new_top)
DUK_INTERNAL_DECL duk_hobject * duk_create_activation_environment_record(duk_hthread *thr, duk_hobject *func, duk_size_t idx_bottom)
#define DUK_STR_INVALID_CALL_ARGS
#define DUK_HOBJECT_IS_COMPILEDFUNCTION(h)
#define DUK_HOBJECT_HAS_CREATEARGS(h)
DUK_EXTERNAL void duk_remove(duk_context *ctx, duk_idx_t index)
#define DUK_ASSERT_DISABLE(x)
#define DUK_CALL_FLAG_IS_RESUME
#define DUK_CALL_FLAG_IS_TAILCALL
DUK_INTERNAL_DECL void duk_hthread_callstack_unwind(duk_hthread *thr, duk_size_t new_top)
#define DUK_TVAL_SET_TVAL_UPDREF
#define DUK_HTHREAD_STATE_RUNNING
DUK_INTERNAL_DECL void duk_hthread_sync_and_null_currpc(duk_hthread *thr)
#define DUK_HOBJECT_HAS_NATIVEFUNCTION(h)
DUK_LOCAL void duk__handle_createargs_for_call(duk_hthread *thr, duk_hobject *func, duk_hobject *env, duk_idx_t num_stack_args)
#define DUK_HOBJECT_HAS_NEWENV(h)
#define DUK_HOBJECT_INCREF(thr, h)
#define DUK_ACT_GET_FUNC(act)
DUK_EXTERNAL void duk_pop(duk_context *ctx)
#define DUK_HOBJECT_HAS_STRICT(h)
#define DUK_HOBJECT_HAS_NOTAIL(h)
#define DUK_HOBJECT_HAS_COMPILEDFUNCTION(h)
DUK_INTERNAL_DECL duk_tval * duk_get_tval(duk_context *ctx, duk_idx_t index)

◆ duk_handle_safe_call()

DUK_INTERNAL_DECL duk_int_t duk_handle_safe_call ( duk_hthread * thr,
duk_safe_call_function func,
duk_idx_t num_stack_args,
duk_idx_t num_stack_res )

Definition at line 56499 of file duktape-1.5.2/src-noline/duktape.c.

56519 {
56520 duk_context *ctx = (duk_context *) thr;
56521 duk_size_t entry_valstack_bottom_index;
56522 duk_size_t entry_callstack_top;
56523 duk_size_t entry_catchstack_top;
56524 duk_int_t entry_call_recursion_depth;
56525 duk_hthread *entry_curr_thread;
56526 duk_uint_fast8_t entry_thread_state;
56527 duk_instr_t **entry_ptr_curr_pc;
56528 duk_jmpbuf *old_jmpbuf_ptr = NULL;
56529 duk_jmpbuf our_jmpbuf;
56530 duk_idx_t idx_retbase;
56531 duk_int_t retval;
56532
56533 DUK_ASSERT(thr != NULL);
56534 DUK_ASSERT(ctx != NULL);
56535
56536 /* Note: careful with indices like '-x'; if 'x' is zero, it refers to bottom */
56537 entry_valstack_bottom_index = (duk_size_t) (thr->valstack_bottom - thr->valstack);
56538 entry_callstack_top = thr->callstack_top;
56539 entry_catchstack_top = thr->catchstack_top;
56540 entry_call_recursion_depth = thr->heap->call_recursion_depth;
56541 entry_curr_thread = thr->heap->curr_thread; /* Note: may be NULL if first call */
56542 entry_thread_state = thr->state;
56543 entry_ptr_curr_pc = thr->ptr_curr_pc; /* may be NULL */
56544 idx_retbase = duk_get_top(ctx) - num_stack_args; /* Note: not a valid stack index if num_stack_args == 0 */
56545
56546 /* Note: cannot portably debug print a function pointer, hence 'func' not printed! */
56547 DUK_DD(DUK_DDPRINT("duk_handle_safe_call: thr=%p, num_stack_args=%ld, num_stack_rets=%ld, "
56548 "valstack_top=%ld, idx_retbase=%ld, rec_depth=%ld/%ld, "
56549 "entry_valstack_bottom_index=%ld, entry_callstack_top=%ld, entry_catchstack_top=%ld, "
56550 "entry_call_recursion_depth=%ld, entry_curr_thread=%p, entry_thread_state=%ld",
56551 (void *) thr,
56552 (long) num_stack_args,
56553 (long) num_stack_rets,
56554 (long) duk_get_top(ctx),
56555 (long) idx_retbase,
56556 (long) thr->heap->call_recursion_depth,
56557 (long) thr->heap->call_recursion_limit,
56558 (long) entry_valstack_bottom_index,
56559 (long) entry_callstack_top,
56560 (long) entry_catchstack_top,
56561 (long) entry_call_recursion_depth,
56562 (void *) entry_curr_thread,
56563 (long) entry_thread_state));
56564
56565 if (idx_retbase < 0) {
56566 /* Since stack indices are not reliable, we can't do anything useful
56567 * here. Invoke the existing setjmp catcher, or if it doesn't exist,
56568 * call the fatal error handler.
56569 */
56570
56572 }
56573
56574 /* setjmp catchpoint setup */
56575
56576 old_jmpbuf_ptr = thr->heap->lj.jmpbuf_ptr;
56577 thr->heap->lj.jmpbuf_ptr = &our_jmpbuf;
56578
56579#if defined(DUK_USE_CPP_EXCEPTIONS)
56580 try {
56581#else
56582 DUK_ASSERT(thr->heap->lj.jmpbuf_ptr == &our_jmpbuf);
56583 if (DUK_SETJMP(our_jmpbuf.jb) == 0) {
56584 /* Success path. */
56585#endif
56586 DUK_DDD(DUK_DDDPRINT("safe_call setjmp catchpoint setup complete"));
56587
56589 func,
56590 idx_retbase,
56591 num_stack_rets,
56592 entry_valstack_bottom_index,
56593 entry_callstack_top,
56594 entry_catchstack_top);
56595
56596 /* Longjmp state is kept clean in success path */
56597 DUK_ASSERT(thr->heap->lj.type == DUK_LJ_TYPE_UNKNOWN);
56598 DUK_ASSERT(thr->heap->lj.iserror == 0);
56599 DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value1));
56600 DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value2));
56601
56602 /* Note: either pointer may be NULL (at entry), so don't assert */
56603 thr->heap->lj.jmpbuf_ptr = old_jmpbuf_ptr;
56604
56605 retval = DUK_EXEC_SUCCESS;
56606#if defined(DUK_USE_CPP_EXCEPTIONS)
56607 } catch (duk_internal_exception &exc) {
56608 DUK_UNREF(exc);
56609#else
56610 } else {
56611 /* Error path. */
56612#endif
56614 idx_retbase,
56615 num_stack_rets,
56616 entry_valstack_bottom_index,
56617 entry_callstack_top,
56618 entry_catchstack_top,
56619 old_jmpbuf_ptr);
56620
56621 /* Longjmp state is cleaned up by error handling */
56622 DUK_ASSERT(thr->heap->lj.type == DUK_LJ_TYPE_UNKNOWN);
56623 DUK_ASSERT(thr->heap->lj.iserror == 0);
56624 DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value1));
56625 DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value2));
56626
56627 retval = DUK_EXEC_ERROR;
56628 }
56629#if defined(DUK_USE_CPP_EXCEPTIONS)
56630 catch (std::exception &exc) {
56631 const char *what = exc.what();
56632 if (!what) {
56633 what = "unknown";
56634 }
56635 DUK_D(DUK_DPRINT("unexpected c++ std::exception (perhaps thrown by user code)"));
56636 try {
56637 DUK_ERROR_FMT1(thr, DUK_ERR_API_ERROR, "caught invalid c++ std::exception '%s' (perhaps thrown by user code)", what);
56638 } catch (duk_internal_exception exc) {
56639 DUK_D(DUK_DPRINT("caught api error thrown from unexpected c++ std::exception"));
56640 DUK_UNREF(exc);
56642 idx_retbase,
56643 num_stack_rets,
56644 entry_valstack_bottom_index,
56645 entry_callstack_top,
56646 entry_catchstack_top,
56647 old_jmpbuf_ptr);
56648 retval = DUK_EXEC_ERROR;
56649 }
56650 } catch (...) {
56651 DUK_D(DUK_DPRINT("unexpected c++ exception (perhaps thrown by user code)"));
56652 try {
56653 DUK_ERROR_API(thr, "caught invalid c++ exception (perhaps thrown by user code)");
56654 } catch (duk_internal_exception exc) {
56655 DUK_D(DUK_DPRINT("caught api error thrown from unexpected c++ exception"));
56656 DUK_UNREF(exc);
56658 idx_retbase,
56659 num_stack_rets,
56660 entry_valstack_bottom_index,
56661 entry_callstack_top,
56662 entry_catchstack_top,
56663 old_jmpbuf_ptr);
DUK_LOCAL void duk__handle_safe_call_error(duk_hthread *thr, duk_idx_t idx_retbase, duk_idx_t num_stack_rets, duk_size_t entry_valstack_bottom_index, duk_size_t entry_callstack_top, duk_size_t entry_catchstack_top, duk_jmpbuf *old_jmpbuf_ptr)
DUK_LOCAL void duk__handle_safe_call_inner(duk_hthread *thr, duk_safe_call_function func, duk_idx_t idx_retbase, duk_idx_t num_stack_rets, duk_size_t entry_valstack_bottom_index, duk_size_t entry_callstack_top, duk_size_t entry_catchstack_top)

◆ duk_js_close_environment_record()

DUK_INTERNAL_DECL void duk_js_close_environment_record ( duk_hthread * thr,
duk_hobject * env,
duk_hobject * func,
duk_size_t regbase )

Definition at line 71680 of file duktape-1.5.2/src-noline/duktape.c.

71697 {
71698 duk_context *ctx = (duk_context *) thr;
71700
71701 DUK_ASSERT(thr != NULL);
71702 DUK_ASSERT(env != NULL);
71703 /* func is NULL for lightfuncs */
71704
71706 DUK_DDD(DUK_DDDPRINT("environment record not a declarative record, "
71707 "or already closed: %!iO",
71708 (duk_heaphdr *) env));
71709 return;
71710 }
71711
71712 DUK_DDD(DUK_DDDPRINT("closing environment record: %!iO, func: %!iO, regbase: %ld",
71713 (duk_heaphdr *) env, (duk_heaphdr *) func, (long) regbase));
71714
71715 duk_push_hobject(ctx, env);
71716
71717 /* assertions: env must be closed in the same thread as where it runs */
71718#ifdef DUK_USE_ASSERTIONS
71719 {
71720 /* [... env] */
71721
71723 DUK_ASSERT(duk_is_object(ctx, -1));
71724 DUK_ASSERT(duk_get_hobject(ctx, -1) == (duk_hobject *) func);
71725 }
71726 duk_pop(ctx);
71727
71729 DUK_ASSERT(duk_is_object(ctx, -1));
71730 DUK_ASSERT(duk_get_hobject(ctx, -1) == (duk_hobject *) thr);
71731 }
71732 duk_pop(ctx);
71733
71735 DUK_ASSERT(duk_is_number(ctx, -1));
71736 DUK_ASSERT(duk_get_number(ctx, -1) == (double) regbase);
71737 }
71738 duk_pop(ctx);
71739
71740 /* [... env] */
71741 }
71742#endif
71743
71744 if (func != NULL && DUK_HOBJECT_IS_COMPILEDFUNCTION(func)) {
71745 duk_hobject *varmap;
71746 duk_hstring *key;
71747 duk_tval *tv;
71748 duk_uint_t regnum;
71749
71750 /* XXX: additional conditions when to close variables? we don't want to do it
71751 * unless the environment may have "escaped" (referenced in a function closure).
71752 * With delayed environments, the existence is probably good enough of a check.
71753 */
71754
71755 /* XXX: any way to detect faster whether something needs to be closed?
71756 * We now look up _Callee and then skip the rest.
71757 */
71758
71759 /* Note: we rely on the _Varmap having a bunch of nice properties, like:
71760 * - being compacted and unmodified during this process
71761 * - not containing an array part
71762 * - having correct value types
71763 */
71764
71765 /* [... env] */
71766
71768 DUK_DDD(DUK_DDDPRINT("env has no callee property, nothing to close; re-delete the control properties just in case"));
71769 duk_pop(ctx);
71770 goto skip_varmap;
71771 }
71772
71773 /* [... env callee] */
71774
71776 DUK_DDD(DUK_DDDPRINT("callee has no varmap property, nothing to close; delete the control properties"));
71777 duk_pop_2(ctx);
71778 goto skip_varmap;
71779 }
71780 varmap = duk_require_hobject(ctx, -1);
71781 DUK_ASSERT(varmap != NULL);
71782
71783 DUK_DDD(DUK_DDDPRINT("varmap: %!O", (duk_heaphdr *) varmap));
71784
71785 /* [... env callee varmap] */
71786
71787 DUK_DDD(DUK_DDDPRINT("copying bound register values, %ld bound regs", (long) DUK_HOBJECT_GET_ENEXT(varmap)));
71788
71789 for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(varmap); i++) {
71790 key = DUK_HOBJECT_E_GET_KEY(thr->heap, varmap, i);
71791 DUK_ASSERT(key != NULL); /* assume keys are compacted */
71792
71793 DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, varmap, i)); /* assume plain values */
71794
71795 tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, varmap, i);
71796 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv)); /* assume value is a number */
71797 regnum = (duk_uint_t) DUK_TVAL_GET_NUMBER(tv);
71798 DUK_ASSERT_DISABLE(regnum >= 0); /* unsigned */
71799 DUK_ASSERT(regnum < ((duk_hcompiledfunction *) func)->nregs); /* regnum is sane */
71800 DUK_ASSERT(thr->valstack + regbase + regnum >= thr->valstack);
71801 DUK_ASSERT(thr->valstack + regbase + regnum < thr->valstack_top);
71802
71803 /* XXX: slightly awkward */
71804 duk_push_hstring(ctx, key);
71805 duk_push_tval(ctx, thr->valstack + regbase + regnum);
71806 DUK_DDD(DUK_DDDPRINT("closing identifier '%s' -> reg %ld, value %!T",
71807 (const char *) duk_require_string(ctx, -2),
71808 (long) regnum,
71809 (duk_tval *) duk_get_tval(ctx, -1)));
71810
71811 /* [... env callee varmap key val] */
71812
71813 /* if property already exists, overwrites silently */
71814 duk_xdef_prop(ctx, -5, DUK_PROPDESC_FLAGS_WE); /* writable but not deletable */
71815 }
71816
71817 duk_pop_2(ctx);
71818
71819 /* [... env] */
duk_uint_fast32_t duk_uint_t
duk_uint32_t duk_uint_fast32_t
#define DUK_STRIDX_INT_CALLEE
DUK_EXTERNAL void duk_pop_2(duk_context *ctx)
#define DUK_STRIDX_INT_REGBASE
DUK_INTERNAL_DECL duk_hobject * duk_require_hobject(duk_context *ctx, duk_idx_t index)
#define DUK_TVAL_IS_NUMBER(tv)
DUK_INTERNAL_DECL duk_bool_t duk_get_prop_stridx(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx)
DUK_EXTERNAL duk_double_t duk_get_number(duk_context *ctx, duk_idx_t index)
#define DUK_HOBJECT_GET_ENEXT(h)
#define DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(heap, h, i)
#define DUK_STRIDX_INT_THREAD
#define DUK_HOBJECT_E_GET_KEY(heap, h, i)
#define DUK_PROPDESC_FLAGS_WE
DUK_EXTERNAL duk_bool_t duk_is_number(duk_context *ctx, duk_idx_t index)
DUK_EXTERNAL duk_bool_t duk_is_object(duk_context *ctx, duk_idx_t index)
#define DUK_STRIDX_INT_VARMAP
#define DUK_HOBJECT_E_SLOT_IS_ACCESSOR(heap, h, i)
DUK_INTERNAL_DECL void duk_push_tval(duk_context *ctx, duk_tval *tv)
#define DUK_HOBJECT_IS_DECENV(h)
DUK_INTERNAL_DECL duk_hobject * duk_get_hobject(duk_context *ctx, duk_idx_t index)
DUK_INTERNAL_DECL void duk_push_hobject(duk_context *ctx, duk_hobject *h)
#define DUK_HOBJECT_HAS_ENVRECCLOSED(h)
#define DUK_TVAL_GET_NUMBER(tv)
DUK_INTERNAL_DECL void duk_push_hstring(duk_context *ctx, duk_hstring *h)
DUK_EXTERNAL const char * duk_require_string(duk_context *ctx, duk_idx_t index)
DUK_INTERNAL_DECL void duk_xdef_prop(duk_context *ctx, duk_idx_t obj_index, duk_small_uint_t desc_flags)

◆ duk_js_compare_helper()

DUK_INTERNAL_DECL duk_bool_t duk_js_compare_helper ( duk_hthread * thr,
duk_tval * tv_x,
duk_tval * tv_y,
duk_small_int_t flags )

Definition at line 70571 of file duktape-1.5.2/src-noline/duktape.c.

70574 {
70575 /* Similar to String comparison. */
70576
70577 DUK_ASSERT(h1 != NULL);
70578 DUK_ASSERT(h2 != NULL);
70579 DUK_UNREF(heap);
70580
70581 return duk_js_data_compare((const duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(heap, h1),
70582 (const duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(heap, h2),
70585}
70586#endif
70587
70589 duk_context *ctx = (duk_context *) thr;
70590 duk_double_t d1, d2;
70591 duk_small_int_t c1, c2;
70592 duk_small_int_t s1, s2;
70593 duk_small_int_t rc;
70594 duk_bool_t retval;
70595
70596 /* Fast path for fastints */
70597#if defined(DUK_USE_FASTINT)
70598 if (DUK_TVAL_IS_FASTINT(tv_x) && DUK_TVAL_IS_FASTINT(tv_y)) {
70599 duk_int64_t v1 = DUK_TVAL_GET_FASTINT(tv_x);
70600 duk_int64_t v2 = DUK_TVAL_GET_FASTINT(tv_y);
70601 if (v1 < v2) {
70602 /* 'lt is true' */
70603 retval = 1;
70604 } else {
70605 retval = 0;
70606 }
70607 if (flags & DUK_COMPARE_FLAG_NEGATE) {
70608 retval ^= 1;
70609 }
70610 return retval;
70611 }
70612#endif /* DUK_USE_FASTINT */
70613
70614 /* Fast path for numbers (one of which may be a fastint) */
70615#if 1 /* XXX: make fast paths optional for size minimization? */
70616 if (DUK_TVAL_IS_NUMBER(tv_x) && DUK_TVAL_IS_NUMBER(tv_y)) {
70617 d1 = DUK_TVAL_GET_NUMBER(tv_x);
70618 d2 = DUK_TVAL_GET_NUMBER(tv_y);
70619 c1 = DUK_FPCLASSIFY(d1);
70620 c2 = DUK_FPCLASSIFY(d2);
70621
70622 if (c1 == DUK_FP_NORMAL && c2 == DUK_FP_NORMAL) {
70623 /* XXX: this is a very narrow check, and doesn't cover
70624 * zeroes, subnormals, infinities, which compare normally.
70625 */
70626
70627 if (d1 < d2) {
70628 /* 'lt is true' */
70629 retval = 1;
70630 } else {
70631 retval = 0;
70632 }
70633 if (flags & DUK_COMPARE_FLAG_NEGATE) {
70634 retval ^= 1;
70635 }
70636 return retval;
70637 }
70638 }
70639#endif
70640
70641 /* Slow path */
70642
70643 duk_push_tval(ctx, tv_x);
70644 duk_push_tval(ctx, tv_y);
70645
70649 } else {
70652 }
70653
70654 /* Note: reuse variables */
70655 tv_x = DUK_GET_TVAL_NEGIDX(ctx, -2);
70656 tv_y = DUK_GET_TVAL_NEGIDX(ctx, -1);
70657
70658 if (DUK_TVAL_IS_STRING(tv_x) && DUK_TVAL_IS_STRING(tv_y)) {
70659 duk_hstring *h1 = DUK_TVAL_GET_STRING(tv_x);
70660 duk_hstring *h2 = DUK_TVAL_GET_STRING(tv_y);
70661 DUK_ASSERT(h1 != NULL);
70662 DUK_ASSERT(h2 != NULL);
70663
70664 rc = duk_js_string_compare(h1, h2);
70665 if (rc < 0) {
70666 goto lt_true;
70667 } else {
70668 goto lt_false;
70669 }
70670 } else {
70671 /* Ordering should not matter (E5 Section 11.8.5, step 3.a) but
70672 * preserve it just in case.
70673 */
70674
70676 d1 = duk_to_number(ctx, -2);
70677 d2 = duk_to_number(ctx, -1);
70678 } else {
70679 d2 = duk_to_number(ctx, -1);
70680 d1 = duk_to_number(ctx, -2);
70681 }
70682
70684 s1 = (duk_small_int_t) DUK_SIGNBIT(d1);
70686 s2 = (duk_small_int_t) DUK_SIGNBIT(d2);
70687
70688 if (c1 == DUK_FP_NAN || c2 == DUK_FP_NAN) {
70689 goto lt_undefined;
70690 }
70691
70692 if (c1 == DUK_FP_ZERO && c2 == DUK_FP_ZERO) {
70693 /* For all combinations: +0 < +0, +0 < -0, -0 < +0, -0 < -0,
70694 * steps e, f, and g.
70695 */
70696 goto lt_false;
70697 }
70698
70699 if (d1 == d2) {
70700 goto lt_false;
70701 }
70702
70703 if (c1 == DUK_FP_INFINITE && s1 == 0) {
70704 /* x == +Infinity */
70705 goto lt_false;
70706 }
70707
70708 if (c2 == DUK_FP_INFINITE && s2 == 0) {
70709 /* y == +Infinity */
70710 goto lt_true;
70711 }
70712
70713 if (c2 == DUK_FP_INFINITE && s2 != 0) {
70714 /* y == -Infinity */
70715 goto lt_false;
70716 }
70717
70718 if (c1 == DUK_FP_INFINITE && s1 != 0) {
70719 /* x == -Infinity */
70720 goto lt_true;
70721 }
70722
70723 if (d1 < d2) {
70724 goto lt_true;
70725 }
70726
70727 goto lt_false;
70728 }
70729
70730 lt_undefined:
70731 /* Note: undefined from Section 11.8.5 always results in false
70732 * return (see e.g. Section 11.8.3) - hence special treatment here.
70733 */
70734 retval = 0;
70735 goto cleanup;
70736
70737 lt_true:
70738 if (flags & DUK_COMPARE_FLAG_NEGATE) {
70739 retval = 0;
70740 goto cleanup;
70741 } else {
70742 retval = 1;
70743 goto cleanup;
DUK_EXTERNAL void duk_to_primitive(duk_context *ctx, duk_idx_t index, duk_int_t hint)
#define DUK_COMPARE_FLAG_NEGATE
#define DUK_COMPARE_FLAG_EVAL_LEFT_FIRST
DUK_EXTERNAL duk_double_t duk_to_number(duk_context *ctx, duk_idx_t index)
#define DUK_TVAL_GET_STRING(tv)
#define DUK_TVAL_IS_STRING(tv)
DUK_INTERNAL_DECL duk_small_int_t duk_js_string_compare(duk_hstring *h1, duk_hstring *h2)
DUK_INTERNAL_DECL duk_small_int_t duk_js_data_compare(const duk_uint8_t *buf1, const duk_uint8_t *buf2, duk_size_t len1, duk_size_t len2)
#define DUK_GET_TVAL_NEGIDX(ctx, idx)
#define DUK_HBUFFER_GET_DATA_PTR(heap, x)
DUK_INTERNAL_DECL duk_bool_t duk_js_compare_helper(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, duk_small_int_t flags)
#define DUK_HBUFFER_GET_SIZE(x)

◆ duk_js_data_compare()

DUK_INTERNAL_DECL duk_small_int_t duk_js_data_compare ( const duk_uint8_t * buf1,
const duk_uint8_t * buf2,
duk_size_t len1,
duk_size_t len2 )

Definition at line 70503 of file duktape-1.5.2/src-noline/duktape.c.

70520 {
70521 duk_size_t prefix_len;
70522 duk_small_int_t rc;
70523
70524 prefix_len = (len1 <= len2 ? len1 : len2);
70525
70526 /* DUK_MEMCMP() is guaranteed to return zero (equal) for zero length
70527 * inputs so no zero length check is needed.
70528 */
70529 rc = DUK_MEMCMP((const void *) buf1,
70530 (const void *) buf2,
70531 (size_t) prefix_len);

◆ duk_js_declvar_activation()

DUK_INTERNAL_DECL duk_bool_t duk_js_declvar_activation ( duk_hthread * thr,
duk_activation * act,
duk_hstring * name,
duk_tval * val,
duk_small_int_t prop_flags,
duk_bool_t is_func_decl )

Definition at line 72884 of file duktape-1.5.2/src-noline/duktape.c.

72894 :
72895 fail_not_extensible:
72896 DUK_ERROR_TYPE(thr, "declaration failed");
72897 return 0;
72898}
72899
72902 duk_activation *act,
72904 duk_tval *val,
72905 duk_small_int_t prop_flags,
72906 duk_bool_t is_func_decl) {
72907 duk_hobject *env;
72908 duk_tval tv_val_copy;
72909
72910 /*
72911 * Make a value copy of the input val. This ensures that
72912 * side effects cannot invalidate the pointer.
72913 */
72914
72915 DUK_TVAL_SET_TVAL(&tv_val_copy, val);
72916 val = &tv_val_copy;
72917
#define DUK_TVAL_SET_TVAL(v, x)
DUK_INTERNAL_DECL duk_bool_t duk_js_declvar_activation(duk_hthread *thr, duk_activation *act, duk_hstring *name, duk_tval *val, duk_small_int_t prop_flags, duk_bool_t is_func_decl)
#define DUK_ERROR_TYPE(thr, msg)
const char * name
Definition lsqlite3.c:2154

◆ duk_js_delvar_activation()

DUK_INTERNAL_DECL duk_bool_t duk_js_delvar_activation ( duk_hthread * thr,
duk_activation * act,
duk_hstring * name )

Definition at line 72594 of file duktape-1.5.2/src-noline/duktape.c.

72595 : name=%!O "
72596 "(treated as silent success)",
72597 (duk_heaphdr *) name));
72598 return 1;
72599}

◆ duk_js_equals_helper()

DUK_INTERNAL_DECL duk_bool_t duk_js_equals_helper ( duk_hthread * thr,
duk_tval * tv_x,
duk_tval * tv_y,
duk_small_int_t flags )

Definition at line 70271 of file duktape-1.5.2/src-noline/duktape.c.

70279 {
70280 /* SameValue(NaN, NaN) = true, regardless of NaN sign or extra bits */
70281 return 1;
70282 }
70283 return 0;
70284 }
70285#endif /* DUK_USE_PARANOID_MATH */
70286}
70287
70289 duk_context *ctx = (duk_context *) thr;
70290 duk_tval *tv_tmp;
70291
70292 /* If flags != 0 (strict or SameValue), thr can be NULL. For loose
70293 * equals comparison it must be != NULL.
70294 */
70295 DUK_ASSERT(flags != 0 || thr != NULL);
70296
70297 /*
70298 * Same type?
70299 *
70300 * Note: since number values have no explicit tag in the 8-byte
70301 * representation, need the awkward if + switch.
70302 */
70303
70304#if defined(DUK_USE_FASTINT)
70305 if (DUK_TVAL_IS_FASTINT(tv_x) && DUK_TVAL_IS_FASTINT(tv_y)) {
70306 if (DUK_TVAL_GET_FASTINT(tv_x) == DUK_TVAL_GET_FASTINT(tv_y)) {
70307 return 1;
70308 } else {
70309 return 0;
70310 }
70311 }
70312 else
70313#endif
70314 if (DUK_TVAL_IS_NUMBER(tv_x) && DUK_TVAL_IS_NUMBER(tv_y)) {
70315 /* Catches both doubles and cases where only one argument is a fastint */
70316 if (DUK_UNLIKELY((flags & DUK_EQUALS_FLAG_SAMEVALUE) != 0)) {
70317 /* SameValue */
70319 DUK_TVAL_GET_NUMBER(tv_y));
70320 } else {
70321 /* equals and strict equals */
70323 DUK_TVAL_GET_NUMBER(tv_y));
70324 }
70325 } else if (DUK_TVAL_GET_TAG(tv_x) == DUK_TVAL_GET_TAG(tv_y)) {
70326 switch (DUK_TVAL_GET_TAG(tv_x)) {
70327 case DUK_TAG_UNDEFINED:
70328 case DUK_TAG_NULL: {
70329 return 1;
70330 }
70331 case DUK_TAG_BOOLEAN: {
70332 return DUK_TVAL_GET_BOOLEAN(tv_x) == DUK_TVAL_GET_BOOLEAN(tv_y);
70333 }
70334 case DUK_TAG_POINTER: {
70335 return DUK_TVAL_GET_POINTER(tv_x) == DUK_TVAL_GET_POINTER(tv_y);
70336 }
70337 case DUK_TAG_STRING:
70338 case DUK_TAG_OBJECT: {
70339 /* heap pointer comparison suffices */
70340 return DUK_TVAL_GET_HEAPHDR(tv_x) == DUK_TVAL_GET_HEAPHDR(tv_y);
70341 }
70342 case DUK_TAG_BUFFER: {
70343 if ((flags & (DUK_EQUALS_FLAG_STRICT | DUK_EQUALS_FLAG_SAMEVALUE)) != 0) {
70344 /* heap pointer comparison suffices */
70345 return DUK_TVAL_GET_HEAPHDR(tv_x) == DUK_TVAL_GET_HEAPHDR(tv_y);
70346 } else {
70347 /* non-strict equality for buffers compares contents */
70348 duk_hbuffer *h_x = DUK_TVAL_GET_BUFFER(tv_x);
70349 duk_hbuffer *h_y = DUK_TVAL_GET_BUFFER(tv_y);
70350 duk_size_t len_x = DUK_HBUFFER_GET_SIZE(h_x);
70351 duk_size_t len_y = DUK_HBUFFER_GET_SIZE(h_y);
70352 void *buf_x;
70353 void *buf_y;
70354 if (len_x != len_y) {
70355 return 0;
70356 }
70357 buf_x = (void *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_x);
70358 buf_y = (void *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_y);
70359 /* if len_x == len_y == 0, buf_x and/or buf_y may
70360 * be NULL, but that's OK.
70361 */
70362 DUK_ASSERT(len_x == len_y);
70363 DUK_ASSERT(len_x == 0 || buf_x != NULL);
70364 DUK_ASSERT(len_y == 0 || buf_y != NULL);
70365 return (DUK_MEMCMP((const void *) buf_x, (const void *) buf_y, (size_t) len_x) == 0) ? 1 : 0;
70366 }
70367 }
70368 case DUK_TAG_LIGHTFUNC: {
70369 /* At least 'magic' has a significant impact on function
70370 * identity.
70371 */
70372 duk_small_uint_t lf_flags_x;
70373 duk_small_uint_t lf_flags_y;
70374 duk_c_function func_x;
70375 duk_c_function func_y;
70376
70377 DUK_TVAL_GET_LIGHTFUNC(tv_x, func_x, lf_flags_x);
70378 DUK_TVAL_GET_LIGHTFUNC(tv_y, func_y, lf_flags_y);
70379 return ((func_x == func_y) && (lf_flags_x == lf_flags_y)) ? 1 : 0;
70380 }
70381#if defined(DUK_USE_FASTINT)
70382 case DUK_TAG_FASTINT:
70383#endif
70384 default: {
70390 return 0;
70391 }
70392 }
70393 }
70394
70395 if ((flags & (DUK_EQUALS_FLAG_STRICT | DUK_EQUALS_FLAG_SAMEVALUE)) != 0) {
70396 return 0;
70397 }
70398
70399 DUK_ASSERT(flags == 0); /* non-strict equality from here on */
70400
70401 /*
70402 * Types are different; various cases for non-strict comparison
70403 *
70404 * Since comparison is symmetric, we use a "swap trick" to reduce
70405 * code size.
70406 */
70407
70408 /* Undefined/null are considered equal (e.g. "null == undefined" -> true). */
70409 if ((DUK_TVAL_IS_UNDEFINED(tv_x) && DUK_TVAL_IS_NULL(tv_y)) ||
70410 (DUK_TVAL_IS_NULL(tv_x) && DUK_TVAL_IS_UNDEFINED(tv_y))) {
70411 return 1;
70412 }
70413
70414 /* Number/string-or-buffer -> coerce string to number (e.g. "'1.5' == 1.5" -> true). */
70415 if (DUK_TVAL_IS_NUMBER(tv_x) && (DUK_TVAL_IS_STRING(tv_y) || DUK_TVAL_IS_BUFFER(tv_y))) {
70416 /* the next 'if' is guaranteed to match after swap */
70417 tv_tmp = tv_x;
70418 tv_x = tv_y;
70419 tv_y = tv_tmp;
70420 }
70421 if ((DUK_TVAL_IS_STRING(tv_x) || DUK_TVAL_IS_BUFFER(tv_x)) && DUK_TVAL_IS_NUMBER(tv_y)) {
70422 /* XXX: this is possible without resorting to the value stack */
70423 duk_double_t d1, d2;
70424 d2 = DUK_TVAL_GET_NUMBER(tv_y);
70425 duk_push_tval(ctx, tv_x);
70426 duk_to_string(ctx, -1); /* buffer values are coerced first to string here */
70427 duk_to_number(ctx, -1);
70428 d1 = duk_require_number(ctx, -1);
70429 duk_pop(ctx);
70430 return duk__js_equals_number(d1, d2);
70431 }
70432
70433 /* Buffer/string -> compare contents. */
70434 if (DUK_TVAL_IS_BUFFER(tv_x) && DUK_TVAL_IS_STRING(tv_y)) {
70435 tv_tmp = tv_x;
70436 tv_x = tv_y;
70437 tv_y = tv_tmp;
70438 }
70439 if (DUK_TVAL_IS_STRING(tv_x) && DUK_TVAL_IS_BUFFER(tv_y)) {
70440 duk_hstring *h_x = DUK_TVAL_GET_STRING(tv_x);
70441 duk_hbuffer *h_y = DUK_TVAL_GET_BUFFER(tv_y);
70443 duk_size_t len_y = DUK_HBUFFER_GET_SIZE(h_y);
70444 const void *buf_x;
70445 const void *buf_y;
70446 if (len_x != len_y) {
70447 return 0;
70448 }
70449 buf_x = (const void *) DUK_HSTRING_GET_DATA(h_x);
70450 buf_y = (const void *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_y);
70451 /* if len_x == len_y == 0, buf_x and/or buf_y may
70452 * be NULL, but that's OK.
70453 */
70454 DUK_ASSERT(len_x == len_y);
70455 DUK_ASSERT(len_x == 0 || buf_x != NULL);
70456 DUK_ASSERT(len_y == 0 || buf_y != NULL);
70457 return (DUK_MEMCMP((const void *) buf_x, (const void *) buf_y, (size_t) len_x) == 0) ? 1 : 0;
70458 }
70459
70460 /* Boolean/any -> coerce boolean to number and try again. If boolean is
70461 * compared to a pointer, the final comparison after coercion now always
70462 * yields false (as pointer vs. number compares to false), but this is
70463 * not special cased.
70464 */
70465 if (DUK_TVAL_IS_BOOLEAN(tv_x)) {
70466 tv_tmp = tv_x;
70467 tv_x = tv_y;
70468 tv_y = tv_tmp;
70469 }
70470 if (DUK_TVAL_IS_BOOLEAN(tv_y)) {
70471 /* ToNumber(bool) is +1.0 or 0.0. Tagged boolean value is always 0 or 1. */
70472 duk_bool_t rc;
70473 DUK_ASSERT(DUK_TVAL_GET_BOOLEAN(tv_y) == 0 || DUK_TVAL_GET_BOOLEAN(tv_y) == 1);
70474 duk_push_tval(ctx, tv_x);
70476 rc = duk_js_equals_helper(thr,
70477 DUK_GET_TVAL_NEGIDX(ctx, -2),
70478 DUK_GET_TVAL_NEGIDX(ctx, -1),
70479 0 /*flags:nonstrict*/);
70480 duk_pop_2(ctx);
70481 return rc;
70482 }
70483
70484 /* String-number-buffer/object -> coerce object to primitive (apparently without hint), then try again. */
70485 if ((DUK_TVAL_IS_STRING(tv_x) || DUK_TVAL_IS_NUMBER(tv_x) || DUK_TVAL_IS_BUFFER(tv_x)) &&
70486 DUK_TVAL_IS_OBJECT(tv_y)) {
70487 tv_tmp = tv_x;
70488 tv_x = tv_y;
70489 tv_y = tv_tmp;
70490 }
DUK_LOCAL duk_bool_t duk__js_samevalue_number(duk_double_t x, duk_double_t y)
#define DUK_HSTRING_GET_DATA(x)
DUK_EXTERNAL duk_double_t duk_require_number(duk_context *ctx, duk_idx_t index)
#define DUK_TVAL_IS_NULL(tv)
#define DUK_TVAL_IS_BUFFER(tv)
#define DUK_EQUALS_FLAG_SAMEVALUE
#define DUK_TVAL_GET_BUFFER(tv)
#define DUK_TVAL_GET_TAG(tv)
#define DUK_TVAL_IS_UNUSED(tv)
DUK_EXTERNAL void duk_push_int(duk_context *ctx, duk_int_t val)
#define DUK_HSTRING_GET_BYTELEN(x)
DUK_LOCAL duk_bool_t duk__js_equals_number(duk_double_t x, duk_double_t y)
#define DUK_TVAL_GET_POINTER(tv)
#define DUK_TVAL_GET_LIGHTFUNC(tv, out_fp, out_flags)
#define DUK_TVAL_GET_BOOLEAN(tv)
DUK_EXTERNAL const char * duk_to_string(duk_context *ctx, duk_idx_t index)
DUK_INTERNAL_DECL duk_bool_t duk_js_equals_helper(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, duk_small_int_t flags)
#define DUK_TVAL_GET_HEAPHDR(tv)
#define DUK_EQUALS_FLAG_STRICT
#define DUK_TVAL_IS_BOOLEAN(tv)
duk_ret_t(* duk_c_function)(duk_context *ctx)

◆ duk_js_execute_bytecode()

DUK_INTERNAL_DECL void duk_js_execute_bytecode ( duk_hthread * exec_thr)

Definition at line 67244 of file duktape-1.5.2/src-noline/duktape.c.

67244 {
67245 /* Restart bytecode execution, possibly with a changed thread. */
67246 ;
67247 } else {
67248 /* Rethrow error to calling state. */
67250
67251 /* Longjmp handling has restored jmpbuf_ptr. */
67252 DUK_ASSERT(heap->lj.jmpbuf_ptr == entry_jmpbuf_ptr);
67253
67254 /* Thread may have changed, e.g. YIELD converted to THROW. */
67255 duk_err_longjmp(heap->curr_thread);
67257 }
67258}
67259
67260/* Outer executor with setjmp/longjmp handling. */
67262 /* Entry level info. */
67263 duk_hthread *entry_thread;
67264 duk_size_t entry_callstack_top;
67265 duk_int_t entry_call_recursion_depth;
67266 duk_jmpbuf *entry_jmpbuf_ptr;
67267 duk_jmpbuf our_jmpbuf;
67268 duk_heap *heap;
67269
67270 DUK_ASSERT(exec_thr != NULL);
67271 DUK_ASSERT(exec_thr->heap != NULL);
67272 DUK_ASSERT(exec_thr->heap->curr_thread != NULL);
67274 DUK_ASSERT(exec_thr->callstack_top >= 1); /* at least one activation, ours */
67275 DUK_ASSERT(DUK_ACT_GET_FUNC(exec_thr->callstack + exec_thr->callstack_top - 1) != NULL);
67277
67278 entry_thread = exec_thr;
67279 heap = entry_thread->heap;
67280 entry_callstack_top = entry_thread->callstack_top;
67281 entry_call_recursion_depth = entry_thread->heap->call_recursion_depth;
67282 entry_jmpbuf_ptr = entry_thread->heap->lj.jmpbuf_ptr;
67283
67284 /*
67285 * Note: we currently assume that the setjmp() catchpoint is
67286 * not re-entrant (longjmp() cannot be called more than once
67287 * for a single setjmp()).
67288 *
67289 * See doc/code-issues.rst for notes on variable assignment
67290 * before and after setjmp().
67291 */
67292
67293 for (;;) {
67294 heap->lj.jmpbuf_ptr = &our_jmpbuf;
67295 DUK_ASSERT(heap->lj.jmpbuf_ptr != NULL);
67296
67297#if defined(DUK_USE_CPP_EXCEPTIONS)
67298 try {
67299#else
67300 DUK_ASSERT(heap->lj.jmpbuf_ptr == &our_jmpbuf);
67301 if (DUK_SETJMP(our_jmpbuf.jb) == 0) {
67302#endif
67303 /* Execute bytecode until returned or longjmp(). */
67304 duk__js_execute_bytecode_inner(entry_thread, entry_callstack_top);
67305
67306 /* Successful return: restore jmpbuf and return to caller. */
67307 heap->lj.jmpbuf_ptr = entry_jmpbuf_ptr;
67308
67309 return;
67310#if defined(DUK_USE_CPP_EXCEPTIONS)
67311 } catch (duk_internal_exception &exc) {
67312#else
67313 } else {
67314#endif
67315#if defined(DUK_USE_CPP_EXCEPTIONS)
67316 DUK_UNREF(exc);
67317#endif
67318 DUK_DDD(DUK_DDDPRINT("longjmp caught by bytecode executor"));
67319
67321 entry_thread,
67322 entry_callstack_top,
67323 entry_call_recursion_depth,
67324 entry_jmpbuf_ptr);
67325 }
67326#if defined(DUK_USE_CPP_EXCEPTIONS)
67327 catch (std::exception &exc) {
67328 const char *what = exc.what();
67329 if (!what) {
67330 what = "unknown";
67331 }
67332 DUK_D(DUK_DPRINT("unexpected c++ std::exception (perhaps thrown by user code)"));
67333 try {
67334 DUK_ASSERT(heap->curr_thread != NULL);
67335 DUK_ERROR_FMT1(heap->curr_thread, DUK_ERR_API_ERROR, "caught invalid c++ std::exception '%s' (perhaps thrown by user code)", what);
67336 } catch (duk_internal_exception exc) {
67337 DUK_D(DUK_DPRINT("caught api error thrown from unexpected c++ std::exception"));
67338 DUK_UNREF(exc);
67340 entry_thread,
67341 entry_callstack_top,
67342 entry_call_recursion_depth,
67343 entry_jmpbuf_ptr);
67344 }
67345 } catch (...) {
67346 DUK_D(DUK_DPRINT("unexpected c++ exception (perhaps thrown by user code)"));
67347 try {
DUK_LOCAL_DECL void duk__js_execute_bytecode_inner(duk_hthread *entry_thread, duk_size_t entry_callstack_top)
DUK_INTERNAL void duk_err_longjmp(duk_hthread *thr)
DUK_LOCAL void duk__handle_executor_error(duk_heap *heap, duk_hthread *entry_thread, duk_size_t entry_callstack_top, duk_int_t entry_call_recursion_depth, duk_jmpbuf *entry_jmpbuf_ptr)
#define DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(h)
DUK_INTERNAL_DECL void duk_js_execute_bytecode(duk_hthread *exec_thr)

◆ duk_js_getvar_activation()

DUK_INTERNAL_DECL duk_bool_t duk_js_getvar_activation ( duk_hthread * thr,
duk_activation * act,
duk_hstring * name,
duk_bool_t throw_flag )

Definition at line 72379 of file duktape-1.5.2/src-noline/duktape.c.

◆ duk_js_getvar_envrec()

DUK_INTERNAL_DECL duk_bool_t duk_js_getvar_envrec ( duk_hthread * thr,
duk_hobject * env,
duk_hstring * name,
duk_bool_t throw_flag )

Definition at line 72371 of file duktape-1.5.2/src-noline/duktape.c.

72376 {

◆ duk_js_in()

DUK_INTERNAL_DECL duk_bool_t duk_js_in ( duk_hthread * thr,
duk_tval * tv_x,
duk_tval * tv_y )

Definition at line 70922 of file duktape-1.5.2/src-noline/duktape.c.

70924 :
70925 duk_pop_2(ctx);
70926 return 1;
70927}
70928
70929/*
70930 * in
70931 */
70932
70933/*
70934 * E5 Sections 11.8.7, 8.12.6.
70935 *
70936 * Basically just a property existence check using [[HasProperty]].
70937 */
70938
70940 duk_context *ctx = (duk_context *) thr;
70941 duk_bool_t retval;
70942
70943 /*
70944 * Get the values onto the stack first. It would be possible to cover
70945 * some normal cases without resorting to the value stack (e.g. if
70946 * lval is already a string).
70947 */
70948
70949 /* XXX: The ES5/5.1/6 specifications require that the key in 'key in obj'
70950 * must be string coerced before the internal HasProperty() algorithm is
70951 * invoked. A fast path skipping coercion could be safely implemented for
70952 * numbers (as number-to-string coercion has no side effects). For ES6
70953 * proxy behavior, the trap 'key' argument must be in a string coerced
70954 * form (which is a shame).
DUK_INTERNAL_DECL duk_bool_t duk_js_in(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y)

◆ duk_js_init_activation_environment_records_delayed()

DUK_INTERNAL_DECL void duk_js_init_activation_environment_records_delayed ( duk_hthread * thr,
duk_activation * act )

Definition at line 71625 of file duktape-1.5.2/src-noline/duktape.c.

71629 {
71630 duk_push_hthread(ctx, thr);
71632 duk_push_hobject(ctx, func);
71634 duk_push_size_t(ctx, idx_bottom);
71636 }
71637
71638 return env;
71639}
71640
71643 duk_activation *act) {
71644 duk_context *ctx = (duk_context *) thr;
71645 duk_hobject *func;
71646 duk_hobject *env;
71647
71648 func = DUK_ACT_GET_FUNC(act);
71649 DUK_ASSERT(func != NULL);
71650 DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(func)); /* bound functions are never in act 'func' */
71651
71652 /*
71653 * Delayed initialization only occurs for 'NEWENV' functions.
71654 */
71655
71657 DUK_ASSERT(act->lex_env == NULL);
71658 DUK_ASSERT(act->var_env == NULL);
71659
71661 DUK_ASSERT(env != NULL);
71662
71663 DUK_DDD(DUK_DDDPRINT("created delayed fresh env: %!ipO", (duk_heaphdr *) env));
DUK_INTERNAL_DECL void duk_js_init_activation_environment_records_delayed(duk_hthread *thr, duk_activation *act)
#define duk_xdef_prop_stridx_wec(ctx, obj_index, stridx)
#define duk_push_size_t(ctx, val)
#define duk_push_hthread(ctx, h)

◆ duk_js_instanceof()

DUK_INTERNAL_DECL duk_bool_t duk_js_instanceof ( duk_hthread * thr,
duk_tval * tv_x,
duk_tval * tv_y )

Definition at line 70765 of file duktape-1.5.2/src-noline/duktape.c.

70782 {
70783 duk_context *ctx = (duk_context *) thr;
70784 duk_hobject *func;
70785 duk_hobject *val;
70787 duk_uint_t sanity;
70788
70789 /*
70790 * Get the values onto the stack first. It would be possible to cover
70791 * some normal cases without resorting to the value stack.
70792 *
70793 * The right hand side could be a light function (as they generally
70794 * behave like objects). Light functions never have a 'prototype'
70795 * property so E5.1 Section 15.3.5.3 step 3 always throws a TypeError.
70796 * Using duk_require_hobject() is thus correct (except for error msg).
70797 */
70798
70799 duk_push_tval(ctx, tv_x);
70800 duk_push_tval(ctx, tv_y);
70801 func = duk_require_hobject(ctx, -1);
70802
70803 /*
70804 * For bound objects, [[HasInstance]] just calls the target function
70805 * [[HasInstance]]. If that is again a bound object, repeat until
70806 * we find a non-bound Function object.
70807 */
70808
70809 /* XXX: this bound function resolution also happens elsewhere,
70810 * move into a shared helper.
70811 */
70812
70814 do {
70815 /* check func supports [[HasInstance]] (this is checked for every function
70816 * in the bound chain, including the final one)
70817 */
70818
70819 if (!DUK_HOBJECT_IS_CALLABLE(func)) {
70820 /*
70821 * Note: of native Ecmascript objects, only Function instances
70822 * have a [[HasInstance]] internal property. Custom objects might
70823 * also have it, but not in current implementation.
70824 *
70825 * XXX: add a separate flag, DUK_HOBJECT_FLAG_ALLOW_INSTANCEOF?
70826 */
70827 DUK_ERROR_TYPE(thr, "invalid instanceof rval");
70828 }
70829
70830 if (!DUK_HOBJECT_HAS_BOUND(func)) {
70831 break;
70832 }
70833
70834 /* [ ... lval rval ] */
70835
70836 duk_get_prop_stridx(ctx, -1, DUK_STRIDX_INT_TARGET); /* -> [ ... lval rval new_rval ] */
70837 duk_replace(ctx, -1); /* -> [ ... lval new_rval ] */
70838 func = duk_require_hobject(ctx, -1);
70839
70840 /* func support for [[HasInstance]] checked in the beginning of the loop */
70841 } while (--sanity > 0);
70842
70843 if (sanity == 0) {
70845 }
70846
70847 /*
70848 * 'func' is now a non-bound object which supports [[HasInstance]]
70849 * (which here just means DUK_HOBJECT_FLAG_CALLABLE). Move on
70850 * to execute E5 Section 15.3.5.3.
70851 */
70852
70855
70856 /* [ ... lval rval(func) ] */
70857
70858 /* Handle lightfuncs through object coercion for now. */
70859 /* XXX: direct implementation */
70860 val = duk_get_hobject_or_lfunc_coerce(ctx, -2);
70861 if (!val) {
70862 goto pop_and_false;
70863 }
70864
70865 duk_get_prop_stridx(ctx, -1, DUK_STRIDX_PROTOTYPE); /* -> [ ... lval rval rval.prototype ] */
70866 proto = duk_require_hobject(ctx, -1);
70867 duk_pop(ctx); /* -> [ ... lval rval ] */
70868
70869 DUK_ASSERT(val != NULL);
70870
70871#if defined(DUK_USE_ES6_PROXY)
70872 val = duk_hobject_resolve_proxy_target(thr, val);
70873 DUK_ASSERT(val != NULL);
70874#endif
70875
70877 do {
70878 /*
70879 * Note: prototype chain is followed BEFORE first comparison. This
70880 * means that the instanceof lval is never itself compared to the
70881 * rval.prototype property. This is apparently intentional, see E5
70882 * Section 15.3.5.3, step 4.a.
70883 *
70884 * Also note:
70885 *
70886 * js> (function() {}) instanceof Function
70887 * true
70888 * js> Function instanceof Function
70889 * true
70890 *
70891 * For the latter, h_proto will be Function.prototype, which is the
70892 * built-in Function prototype. Because Function.[[Prototype]] is
70893 * also the built-in Function prototype, the result is true.
70894 */
70895
70896 DUK_ASSERT(val != NULL);
70897 val = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, val);
70898
70899 if (!val) {
70900 goto pop_and_false;
70901 }
70902
70903 DUK_ASSERT(val != NULL);
70904#if defined(DUK_USE_ES6_PROXY)
70905 val = duk_hobject_resolve_proxy_target(thr, val);
70906#endif
70907
70908 if (val == proto) {
70909 goto pop_and_true;
70910 }
const char * proto
Definition civetweb.c:18378
#define DUK_ERROR_RANGE(thr, msg)
#define DUK_HOBJECT_GET_PROTOTYPE(heap, h)
DUK_INTERNAL_DECL duk_hobject * duk_get_hobject_or_lfunc_coerce(duk_context *ctx, duk_idx_t index)
#define DUK_HOBJECT_IS_CALLABLE(h)
DUK_EXTERNAL void duk_replace(duk_context *ctx, duk_idx_t to_index)
DUK_INTERNAL_DECL duk_hobject * duk_hobject_resolve_proxy_target(duk_hthread *thr, duk_hobject *obj)
#define DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY
#define DUK_STRIDX_INT_TARGET
#define DUK_HOBJECT_BOUND_CHAIN_SANITY
#define DUK_STR_BOUND_CHAIN_LIMIT

◆ duk_js_push_closure()

DUK_INTERNAL_DECL void duk_js_push_closure ( duk_hthread * thr,
duk_hcompiledfunction * fun_temp,
duk_hobject * outer_var_env,
duk_hobject * outer_lex_env,
duk_bool_t add_auto_proto )

Definition at line 71214 of file duktape-1.5.2/src-noline/duktape.c.

71215 : if fun_temp has NEWENV, i.e. a new lexical and variable declaration
71216 * is created when the function is called, only outer_lex_env matters
71217 * (outer_var_env is ignored and may or may not be same as outer_lex_env).
71218 */
71219
71220DUK_LOCAL const duk_uint16_t duk__closure_copy_proplist[] = {
71221 /* order: most frequent to least frequent */
71228};
71229
71232 duk_hcompiledfunction *fun_temp,
71233 duk_hobject *outer_var_env,
71234 duk_hobject *outer_lex_env,
71235 duk_bool_t add_auto_proto) {
71236 duk_context *ctx = (duk_context *) thr;
71237 duk_hcompiledfunction *fun_clos;
71239 duk_uint_t len_value;
71240
71241 DUK_ASSERT(fun_temp != NULL);
71245 DUK_ASSERT(outer_var_env != NULL);
71246 DUK_ASSERT(outer_lex_env != NULL);
71247 DUK_UNREF(len_value);
71248
71250 duk_push_hobject(ctx, &fun_temp->obj); /* -> [ ... closure template ] */
71251
71252 fun_clos = (duk_hcompiledfunction *) duk_get_hcompiledfunction(ctx, -2);
71253 DUK_ASSERT(fun_clos != NULL);
71258
71262
71263 /* Note: all references inside 'data' need to get their refcounts
71264 * upped too. This is the case because refcounts are decreased
71265 * through every function referencing 'data' independently.
71266 */
71267
71269 duk__inc_data_inner_refcounts(thr, fun_temp);
71270
71271 fun_clos->nregs = fun_temp->nregs;
71272 fun_clos->nargs = fun_temp->nargs;
71273#if defined(DUK_USE_DEBUGGER_SUPPORT)
71274 fun_clos->start_line = fun_temp->start_line;
71275 fun_clos->end_line = fun_temp->end_line;
71276#endif
71277
71281
71282 /* XXX: could also copy from template, but there's no way to have any
71283 * other value here now (used code has no access to the template).
71284 */
71286
71287 /*
71288 * Init/assert flags, copying them where appropriate. Some flags
71289 * (like NEWENV) are processed separately below.
71290 */
71291
71292 /* XXX: copy flags using a mask */
71293
71295 DUK_HOBJECT_SET_CONSTRUCTABLE(&fun_clos->obj); /* Note: not set in template (has no "prototype") */
71297 DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(&fun_clos->obj));
71301 /* DUK_HOBJECT_FLAG_ARRAY_PART: don't care */
71302 if (DUK_HOBJECT_HAS_STRICT(&fun_temp->obj)) {
71303 DUK_HOBJECT_SET_STRICT(&fun_clos->obj);
71304 }
71305 if (DUK_HOBJECT_HAS_NOTAIL(&fun_temp->obj)) {
71306 DUK_HOBJECT_SET_NOTAIL(&fun_clos->obj);
71307 }
71308 /* DUK_HOBJECT_FLAG_NEWENV: handled below */
71309 if (DUK_HOBJECT_HAS_NAMEBINDING(&fun_temp->obj)) {
71310 /* Although NAMEBINDING is not directly needed for using
71311 * function instances, it's needed by bytecode dump/load
71312 * so copy it too.
71313 */
71314 DUK_HOBJECT_SET_NAMEBINDING(&fun_clos->obj);
71315 }
71316 if (DUK_HOBJECT_HAS_CREATEARGS(&fun_temp->obj)) {
71317 DUK_HOBJECT_SET_CREATEARGS(&fun_clos->obj);
71318 }
71322
71323 /*
71324 * Setup environment record properties based on the template and
71325 * its flags.
71326 *
71327 * If DUK_HOBJECT_HAS_NEWENV(fun_temp) is true, the environment
71328 * records represent identifiers "outside" the function; the
71329 * "inner" environment records are created on demand. Otherwise,
71330 * the environment records are those that will be directly used
71331 * (e.g. for declarations).
71332 *
71333 * _Lexenv is always set; _Varenv defaults to _Lexenv if missing,
71334 * so _Varenv is only set if _Lexenv != _Varenv.
71335 *
71336 * This is relatively complex, see doc/identifier-handling.rst.
71337 */
71338
71339 if (DUK_HOBJECT_HAS_NEWENV(&fun_temp->obj)) {
71340 DUK_HOBJECT_SET_NEWENV(&fun_clos->obj);
71341
71342 if (DUK_HOBJECT_HAS_NAMEBINDING(&fun_temp->obj)) {
71344
71345 /*
71346 * Named function expression, name needs to be bound
71347 * in an intermediate environment record. The "outer"
71348 * lexical/variable environment will thus be:
71349 *
71350 * a) { funcname: <func>, __prototype: outer_lex_env }
71351 * b) { funcname: <func>, __prototype: <globalenv> } (if outer_lex_env missing)
71352 */
71353
71354 DUK_ASSERT(duk_has_prop_stridx(ctx, -1, DUK_STRIDX_NAME)); /* required if NAMEBINDING set */
71355
71356 if (outer_lex_env) {
71357 proto = outer_lex_env;
71358 } else {
71360 }
71361
71362 /* -> [ ... closure template env ] */
71366 proto);
71367
71368 /* It's important that duk_xdef_prop() is a 'raw define' so that any
71369 * properties in an ancestor are never an issue (they should never be
71370 * e.g. non-writable, but just in case).
71371 */
71372 duk_get_prop_stridx(ctx, -2, DUK_STRIDX_NAME); /* -> [ ... closure template env funcname ] */
71373 duk_dup(ctx, -4); /* -> [ ... closure template env funcname closure ] */
71374 duk_xdef_prop(ctx, -3, DUK_PROPDESC_FLAGS_NONE); /* -> [ ... closure template env ] */
71375 /* env[funcname] = closure */
71376
71377 /* [ ... closure template env ] */
71378
71380 /* since closure has NEWENV, never define DUK_STRIDX_INT_VARENV, as it
71381 * will be ignored anyway
71382 */
71383
71384 /* [ ... closure template ] */
71385 } else {
71386 /*
71387 * Other cases (function declaration, anonymous function expression,
71388 * strict direct eval code). The "outer" environment will be whatever
71389 * the caller gave us.
71390 */
71391
71392 duk_push_hobject(ctx, outer_lex_env); /* -> [ ... closure template env ] */
71394 /* since closure has NEWENV, never define DUK_STRIDX_INT_VARENV, as it
71395 * will be ignored anyway
71396 */
71397
71398 /* [ ... closure template ] */
71399 }
71400 } else {
71401 /*
71402 * Function gets no new environment when called. This is the
71403 * case for global code, indirect eval code, and non-strict
71404 * direct eval code. There is no direct correspondence to the
71405 * E5 specification, as global/eval code is not exposed as a
71406 * function.
71407 */
71408
71410
71411 duk_push_hobject(ctx, outer_lex_env); /* -> [ ... closure template env ] */
71413
71414 if (outer_var_env != outer_lex_env) {
71415 duk_push_hobject(ctx, outer_var_env); /* -> [ ... closure template env ] */
71417 }
71418 }
71419#ifdef DUK_USE_DDDPRINT
71422 DUK_DDD(DUK_DDDPRINT("closure varenv -> %!ipT, lexenv -> %!ipT",
71423 (duk_tval *) duk_get_tval(ctx, -2),
71424 (duk_tval *) duk_get_tval(ctx, -1)));
71425 duk_pop_2(ctx);
71426#endif
71427
71428 /*
71429 * Copy some internal properties directly
71430 *
71431 * The properties will be writable and configurable, but not enumerable.
71432 */
71433
71434 /* [ ... closure template ] */
71435
71436 DUK_DDD(DUK_DDDPRINT("copying properties: closure=%!iT, template=%!iT",
71437 (duk_tval *) duk_get_tval(ctx, -2),
71438 (duk_tval *) duk_get_tval(ctx, -1)));
71439
71440 for (i = 0; i < (duk_small_uint_t) (sizeof(duk__closure_copy_proplist) / sizeof(duk_uint16_t)); i++) {
71442 if (duk_get_prop_stridx(ctx, -1, stridx)) {
71443 /* [ ... closure template val ] */
71444 DUK_DDD(DUK_DDDPRINT("copying property, stridx=%ld -> found", (long) stridx));
71446 } else {
71447 DUK_DDD(DUK_DDDPRINT("copying property, stridx=%ld -> not found", (long) stridx));
71448 duk_pop(ctx);
71449 }
71450 }
71451
71452 /*
71453 * "length" maps to number of formals (E5 Section 13.2) for function
71454 * declarations/expressions (non-bound functions). Note that 'nargs'
71455 * is NOT necessarily equal to the number of arguments.
71456 */
71457
71458 /* [ ... closure template ] */
71459
71460 len_value = 0;
71461
71462 /* XXX: use helper for size optimization */
71464 /* [ ... closure template formals ] */
71466 DUK_ASSERT(duk_get_length(ctx, -1) <= DUK_UINT_MAX); /* formal arg limits */
71467 len_value = (duk_uint_t) duk_get_length(ctx, -1);
71468 } else {
71469 /* XXX: what to do if _Formals is not empty but compiler has
71470 * optimized it away -- read length from an explicit property
71471 * then?
71472 */
71473 }
71474 duk_pop(ctx);
71475
71476 duk_push_uint(ctx, len_value); /* [ ... closure template len_value ] */
71478
71479 /*
71480 * "prototype" is, by default, a fresh object with the "constructor"
71481 * property.
71482 *
71483 * Note that this creates a circular reference for every function
71484 * instance (closure) which prevents refcount-based collection of
71485 * function instances.
71486 *
71487 * XXX: Try to avoid creating the default prototype object, because
71488 * many functions are not used as constructors and the default
71489 * prototype is unnecessary. Perhaps it could be created on-demand
71490 * when it is first accessed?
71491 */
71492
71493 /* [ ... closure template ] */
71494
71495 if (add_auto_proto) {
71496 duk_push_object(ctx); /* -> [ ... closure template newobj ] */
71497 duk_dup(ctx, -3); /* -> [ ... closure template newobj closure ] */
71498 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_CONSTRUCTOR, DUK_PROPDESC_FLAGS_WC); /* -> [ ... closure template newobj ] */
71499 duk_compact(ctx, -1); /* compact the prototype */
71500 duk_xdef_prop_stridx(ctx, -3, DUK_STRIDX_PROTOTYPE, DUK_PROPDESC_FLAGS_W); /* -> [ ... closure template ] */
71501 }
71502
71503 /*
71504 * "arguments" and "caller" must be mapped to throwers for strict
71505 * mode and bound functions (E5 Section 15.3.5).
71506 *
71507 * XXX: This is expensive to have for every strict function instance.
71508 * Try to implement as virtual properties or on-demand created properties.
71509 */
71510
71511 /* [ ... closure template ] */
71512
71513 if (DUK_HOBJECT_HAS_STRICT(&fun_clos->obj)) {
71516 } else {
71517#ifdef DUK_USE_NONSTD_FUNC_CALLER_PROPERTY
71518 DUK_DDD(DUK_DDDPRINT("function is non-strict and non-standard 'caller' property in use, add initial 'null' value"));
71519 duk_push_null(ctx);
71521#else
71522 DUK_DDD(DUK_DDDPRINT("function is non-strict and non-standard 'caller' property not used"));
71523#endif
71524 }
71525
71526 /*
71527 * "name" is a non-standard property found in at least V8, Rhino, smjs.
71528 * For Rhino and smjs it is non-writable, non-enumerable, and non-configurable;
71529 * for V8 it is writable, non-enumerable, non-configurable. It is also defined
71530 * for an anonymous function expression in which case the value is an empty string.
71531 * We could also leave name 'undefined' for anonymous functions but that would
71532 * differ from behavior of other engines, so use an empty string.
71533 *
71534 * XXX: make optional? costs something per function.
71535 */
71536
71537 /* [ ... closure template ] */
71538
71539 if (duk_get_prop_stridx(ctx, -1, DUK_STRIDX_NAME)) {
71540 /* [ ... closure template name ] */
71541 DUK_ASSERT(duk_is_string(ctx, -1));
71542 } else {
71543 /* [ ... closure template undefined ] */
71544 duk_pop(ctx);
71546 }
71547 duk_xdef_prop_stridx(ctx, -3, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_NONE); /* -> [ ... closure template ] */
71548
71549 /*
71550 * Compact the closure, in most cases no properties will be added later.
71551 * Also, without this the closures end up having unused property slots
71552 * (e.g. in Duktape 0.9.0, 8 slots would be allocated and only 7 used).
71553 * A better future solution would be to allocate the closure directly
71554 * to correct size (and setup the properties directly without going
71555 * through the API).
71556 */
71557
71558 duk_compact(ctx, -2);
71559
71560 /*
71561 * Some assertions (E5 Section 13.2).
71562 */
71563
71568 DUK_ASSERT(add_auto_proto == 0 || duk_has_prop_stridx(ctx, -2, DUK_STRIDX_PROTOTYPE) != 0);
71569 DUK_ASSERT(duk_has_prop_stridx(ctx, -2, DUK_STRIDX_NAME) != 0); /* non-standard */
71570 DUK_ASSERT(!DUK_HOBJECT_HAS_STRICT(&fun_clos->obj) ||
71571 duk_has_prop_stridx(ctx, -2, DUK_STRIDX_CALLER) != 0);
#define DUK_HCOMPILEDFUNCTION_SET_FUNCS(heap, h, v)
#define DUK_HOBJECT_HAS_EXOTIC_ARRAY(h)
DUK_INTERNAL_DECL duk_idx_t duk_push_object_helper_proto(duk_context *ctx, duk_uint_t hobject_flags_and_class, duk_hobject *proto)
#define DUK_HCOMPILEDFUNCTION_SET_BYTECODE(heap, h, v)
#define DUK_HBUFFER_INCREF(thr, h)
#define DUK_STRIDX_INT_FORMALS
#define DUK_STRIDX_LC_ARGUMENTS
DUK_EXTERNAL void duk_compact(duk_context *ctx, duk_idx_t obj_index)
#define DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(h)
DUK_INTERNAL_DECL void duk_js_push_closure(duk_hthread *thr, duk_hcompiledfunction *fun_temp, duk_hobject *outer_var_env, duk_hobject *outer_lex_env, duk_bool_t add_auto_proto)
DUK_EXTERNAL duk_size_t duk_get_length(duk_context *ctx, duk_idx_t index)
#define DUK_HOBJECT_SET_CREATEARGS(h)
DUK_INTERNAL_DECL duk_bool_t duk_has_prop_stridx(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx)
#define DUK_BIDX_FUNCTION_PROTOTYPE
#define DUK_PROPDESC_FLAGS_NONE
DUK_INTERNAL_DECL void duk_push_hstring_stridx(duk_context *ctx, duk_small_int_t stridx)
#define DUK_HOBJECT_CLASS_FUNCTION
#define DUK_STRIDX_CONSTRUCTOR
#define DUK_HOBJECT_HAS_CONSTRUCTABLE(h)
#define DUK_HCOMPILEDFUNCTION_SET_DATA(heap, h, v)
#define DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, h, p)
DUK_EXTERNAL void duk_push_null(duk_context *ctx)
#define DUK_HOBJECT_SET_NOTAIL(h)
#define DUK_HOBJECT_SET_STRICT(h)
#define DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(h)
#define DUK_STRIDX_INT_LEXENV
DUK_LOCAL const duk_uint16_t duk__closure_copy_proplist[]
DUK_EXTERNAL duk_idx_t duk_push_object(duk_context *ctx)
#define DUK_STRIDX_EMPTY_STRING
DUK_EXTERNAL void duk_dup(duk_context *ctx, duk_idx_t from_index)
DUK_EXTERNAL void duk_push_uint(duk_context *ctx, duk_uint_t val)
#define DUK_HOBJECT_HAS_THREAD(h)
#define DUK_HCOMPILEDFUNCTION_GET_FUNCS(heap, h)
DUK_INTERNAL_DECL duk_hcompiledfunction * duk_get_hcompiledfunction(duk_context *ctx, duk_idx_t index)
#define DUK_HOBJECT_SET_CONSTRUCTABLE(h)
#define DUK_PROPDESC_FLAGS_WC
DUK_LOCAL void duk__inc_data_inner_refcounts(duk_hthread *thr, duk_hcompiledfunction *f)
DUK_INTERNAL_DECL void duk_xdef_prop_stridx_thrower(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx, duk_small_uint_t desc_flags)
#define DUK_STRIDX_INT_VARENV
DUK_INTERNAL_DECL duk_idx_t duk_push_compiledfunction(duk_context *ctx)
#define DUK_STRIDX_INT_PC2LINE
#define DUK_HCOMPILEDFUNCTION_GET_DATA(heap, h)
#define DUK_HOBJECT_SET_NAMEBINDING(h)
#define DUK_HOBJECT_GET_CLASS_NUMBER(h)
DUK_INTERNAL_DECL void duk_xdef_prop_stridx(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx, duk_small_uint_t desc_flags)
DUK_EXTERNAL duk_bool_t duk_is_string(duk_context *ctx, duk_idx_t index)
#define DUK_HOBJECT_HAS_EXTENSIBLE(h)
#define DUK_STRIDX_INT_SOURCE
#define DUK_HCOMPILEDFUNCTION_GET_BYTECODE(heap, h)
#define DUK_HOBJECT_SET_NEWENV(h)
#define DUK_HOBJECT_HAS_NAMEBINDING(h)

◆ duk_js_putvar_activation()

DUK_INTERNAL_DECL void duk_js_putvar_activation ( duk_hthread * thr,
duk_activation * act,
duk_hstring * name,
duk_tval * val,
duk_bool_t strict )

Definition at line 72509 of file duktape-1.5.2/src-noline/duktape.c.

◆ duk_js_putvar_envrec()

DUK_INTERNAL_DECL void duk_js_putvar_envrec ( duk_hthread * thr,
duk_hobject * env,
duk_hstring * name,
duk_tval * val,
duk_bool_t strict )

Definition at line 72500 of file duktape-1.5.2/src-noline/duktape.c.

72500 {
72501 DUK_DDD(DUK_DDDPRINT("identifier binding not found, strict => reference error"));
72502 DUK_ERROR(thr, DUK_ERR_REFERENCE_ERROR, "identifier not defined");
72503 }
72504
72505 DUK_DDD(DUK_DDDPRINT("identifier binding not found, not strict => set to global"));
72506
#define DUK_ERROR(thr, err, msg)
#define DUK_ERR_REFERENCE_ERROR

◆ duk_js_string_compare()

DUK_INTERNAL_DECL duk_small_int_t duk_js_string_compare ( duk_hstring * h1,
duk_hstring * h2 )

Definition at line 70533 of file duktape-1.5.2/src-noline/duktape.c.

70533 {
70534 return -1;
70535 } else if (rc > 0) {
70536 return 1;
70537 }
70538
70539 /* prefix matches, lengths matter now */
70540 if (len1 < len2) {
70541 /* e.g. "x" < "xx" */
70542 return -1;
70543 } else if (len1 > len2) {
70544 return 1;
70545 }
70546
70547 return 0;
70548}
70549
70551 /*
70552 * String comparison (E5 Section 11.8.5, step 4), which
70553 * needs to compare codepoint by codepoint.
70554 *

◆ duk_js_to_arrayindex_raw_string()

DUK_INTERNAL_DECL duk_small_int_t duk_js_to_arrayindex_raw_string ( const duk_uint8_t * str,
duk_uint32_t blen,
duk_uarridx_t * out_idx )

Definition at line 71043 of file duktape-1.5.2/src-noline/duktape.c.

71060 {
71061 duk_uarridx_t res, new_res;
71062
71063 if (blen == 0 || blen > 10) {
71064 goto parse_fail;
71065 }
71066 if (str[0] == (duk_uint8_t) '0' && blen > 1) {
71067 goto parse_fail;
71068 }
71069
71070 /* Accept 32-bit decimal integers, no leading zeroes, signs, etc.
71071 * Leading zeroes are not accepted (zero index "0" is an exception
71072 * handled above).
71073 */
71074
71075 res = 0;
71076 while (blen-- > 0) {
71077 duk_uint8_t c = *str++;
71078 if (c >= (duk_uint8_t) '0' && c <= (duk_uint8_t) '9') {
71079 new_res = res * 10 + (duk_uint32_t) (c - (duk_uint8_t) '0');

◆ duk_js_to_arrayindex_string_helper()

DUK_INTERNAL_DECL duk_uarridx_t duk_js_to_arrayindex_string_helper ( duk_hstring * h)

Definition at line 71082 of file duktape-1.5.2/src-noline/duktape.c.

71085 {
71086 goto parse_fail;
71087 }
71088 }
71089
71090 *out_idx = res;
71091 return 1;
71092
71093 parse_fail:
71094 *out_idx = DUK_HSTRING_NO_ARRAY_INDEX;
71095 return 0;
71096}
#define DUK_HSTRING_NO_ARRAY_INDEX

◆ duk_js_toboolean()

DUK_INTERNAL_DECL duk_bool_t duk_js_toboolean ( duk_tval * tv)

Definition at line 69791 of file duktape-1.5.2/src-noline/duktape.c.

69808 {
69809 switch (DUK_TVAL_GET_TAG(tv)) {
69810 case DUK_TAG_UNDEFINED:
69811 case DUK_TAG_NULL:
69812 return 0;
69813 case DUK_TAG_BOOLEAN:
69814 return DUK_TVAL_GET_BOOLEAN(tv);
69815 case DUK_TAG_STRING: {
69817 DUK_ASSERT(h != NULL);
69818 return (DUK_HSTRING_GET_BYTELEN(h) > 0 ? 1 : 0);
69819 }
69820 case DUK_TAG_OBJECT: {
69821 return 1;
69822 }
69823 case DUK_TAG_BUFFER: {
69824 /* mimic semantics for strings */
69826 DUK_ASSERT(h != NULL);
69827 return (DUK_HBUFFER_GET_SIZE(h) > 0 ? 1 : 0);
69828 }
69829 case DUK_TAG_POINTER: {
69830 void *p = DUK_TVAL_GET_POINTER(tv);
69831 return (p != NULL ? 1 : 0);
69832 }
69833 case DUK_TAG_LIGHTFUNC: {
69834 return 1;
69835 }
69836#if defined(DUK_USE_FASTINT)
69837 case DUK_TAG_FASTINT:
69838 if (DUK_TVAL_GET_FASTINT(tv) != 0) {
69839 return 1;
69840 } else {
69841 return 0;
69842 }
69843#endif

◆ duk_js_toint32()

DUK_INTERNAL_DECL duk_int32_t duk_js_toint32 ( duk_hthread * thr,
duk_tval * tv )

Definition at line 70053 of file duktape-1.5.2/src-noline/duktape.c.

70054 {
70055 x += DUK_DOUBLE_2TO32;
70056 }
70057 /* -> x in [0, 2**32[ */
70058
70059 if (is_toint32) {
70060 if (x >= DUK_DOUBLE_2TO31) {
70061 /* x in [2**31, 2**32[ */
70062
70063 x -= DUK_DOUBLE_2TO32; /* -> x in [-2**31,2**31[ */
70064 }
70065 }
70066
70067 return x;
70068}

◆ duk_js_tointeger()

DUK_INTERNAL_DECL duk_double_t duk_js_tointeger ( duk_hthread * thr,
duk_tval * tv )

Definition at line 70004 of file duktape-1.5.2/src-noline/duktape.c.

70004 {
70005 return 0.0;
70006 } else if (c == DUK_FP_ZERO || c == DUK_FP_INFINITE) {
70007 /* XXX: FP_ZERO check can be removed, the else clause handles it
70008 * correctly (preserving sign).

◆ duk_js_tointeger_number()

DUK_INTERNAL_DECL duk_double_t duk_js_tointeger_number ( duk_double_t x)

Definition at line 69984 of file duktape-1.5.2/src-noline/duktape.c.

69985 : {
69986 /* number */
69989 return DUK_TVAL_GET_DOUBLE(tv);
69990 }
69991 }
69992
69994}
69995
69996/*
69997 * ToInteger() (E5 Section 9.4)
69998 */
69999
70000/* exposed, used by e.g. duk_bi_date.c */
#define DUK_TVAL_IS_DOUBLE(v)
#define DUK_TVAL_GET_DOUBLE(tv)
DUK_INTERNAL_DECL duk_double_t duk_js_tointeger_number(duk_double_t x)

◆ duk_js_tonumber()

DUK_INTERNAL_DECL duk_double_t duk_js_tonumber ( duk_hthread * thr,
duk_tval * tv )

Definition at line 69901 of file duktape-1.5.2/src-noline/duktape.c.

69918 {
69919 duk_context *ctx = (duk_hthread *) thr;
69920
69921 DUK_ASSERT(thr != NULL);
69922 DUK_ASSERT(tv != NULL);
69923
69924 switch (DUK_TVAL_GET_TAG(tv)) {
69925 case DUK_TAG_UNDEFINED: {
69926 /* return a specific NaN (although not strictly necessary) */
69930 return du.d;
69931 }
69932 case DUK_TAG_NULL: {
69933 /* +0.0 */
69934 return 0.0;
69935 }
69936 case DUK_TAG_BOOLEAN: {
69937 if (DUK_TVAL_IS_BOOLEAN_TRUE(tv)) {
69938 return 1.0;
69939 }
69940 return 0.0;
69941 }
69942 case DUK_TAG_STRING: {
69944 duk_push_hstring(ctx, h);
69945 return duk__tonumber_string_raw(thr);
69946 }
69947 case DUK_TAG_OBJECT: {
69948 /* Note: ToPrimitive(object,hint) == [[DefaultValue]](object,hint),
69949 * so use [[DefaultValue]] directly.
69950 */
69951 duk_double_t d;
69952 duk_push_tval(ctx, tv);
69953 duk_to_defaultvalue(ctx, -1, DUK_HINT_NUMBER); /* 'tv' becomes invalid */
69954
69955 /* recursive call for a primitive value (guaranteed not to cause second
69956 * recursion).
69957 */
69958 d = duk_js_tonumber(thr, duk_require_tval(ctx, -1));
69959
69960 duk_pop(ctx);
69961 return d;
69962 }
69963 case DUK_TAG_BUFFER: {
69964 /* Coerce like a string. This makes sense because addition also treats
69965 * buffers like strings.
69966 */
69968 duk_push_hbuffer(ctx, h);
69969 duk_to_string(ctx, -1); /* XXX: expensive, but numconv now expects to see a string */
69970 return duk__tonumber_string_raw(thr);
69971 }
69972 case DUK_TAG_POINTER: {
69973 /* Coerce like boolean */
69974 void *p = DUK_TVAL_GET_POINTER(tv);
69975 return (p != NULL ? 1.0 : 0.0);
69976 }
69977 case DUK_TAG_LIGHTFUNC: {
DUK_LOCAL duk_double_t duk__tonumber_string_raw(duk_hthread *thr)
#define DUK_TVAL_IS_BOOLEAN_TRUE(tv)
DUK_EXTERNAL void duk_to_defaultvalue(duk_context *ctx, duk_idx_t index, duk_int_t hint)
DUK_INTERNAL_DECL duk_tval * duk_require_tval(duk_context *ctx, duk_idx_t index)
DUK_INTERNAL_DECL duk_double_t duk_js_tonumber(duk_hthread *thr, duk_tval *tv)
DUK_INTERNAL_DECL void duk_push_hbuffer(duk_context *ctx, duk_hbuffer *h)
#define DUK_DBLUNION_SET_NAN(u)
#define DUK_DBLUNION_IS_NORMALIZED(u)

◆ duk_js_touint16()

DUK_INTERNAL_DECL duk_uint16_t duk_js_touint16 ( duk_hthread * thr,
duk_tval * tv )

Definition at line 70089 of file duktape-1.5.2/src-noline/duktape.c.

70092 {

◆ duk_js_touint32()

DUK_INTERNAL_DECL duk_uint32_t duk_js_touint32 ( duk_hthread * thr,
duk_tval * tv )

Definition at line 70071 of file duktape-1.5.2/src-noline/duktape.c.

70074 {
70075 return DUK_TVAL_GET_FASTINT_I32(tv);
70076 }
70077#endif
70078
70079 d = duk_js_tonumber(thr, tv); /* invalidates tv */
70082 DUK_ASSERT(d >= -2147483648.0 && d <= 2147483647.0); /* [-0x80000000,0x7fffffff] */
70083 DUK_ASSERT(d == ((duk_double_t) ((duk_int32_t) d))); /* whole, won't clip */
70084 return (duk_int32_t) d;
70085}
70086
70087
DUK_LOCAL duk_double_t duk__toint32_touint32_helper(duk_double_t x, duk_bool_t is_toint32)

◆ duk_js_typeof()

DUK_INTERNAL_DECL duk_hstring * duk_js_typeof ( duk_hthread * thr,
duk_tval * tv_x )

Definition at line 70970 of file duktape-1.5.2/src-noline/duktape.c.

70987 {
70988 duk_small_int_t stridx = 0;
70989
70990 DUK_UNREF(thr);
70991
70992 switch (DUK_TVAL_GET_TAG(tv_x)) {
70993 case DUK_TAG_UNDEFINED: {
70994 stridx = DUK_STRIDX_LC_UNDEFINED;
70995 break;
70996 }
70997 case DUK_TAG_NULL: {
70998 /* Note: not a typo, "object" is returned for a null value */
70999 stridx = DUK_STRIDX_LC_OBJECT;
71000 break;
71001 }
71002 case DUK_TAG_BOOLEAN: {
71003 stridx = DUK_STRIDX_LC_BOOLEAN;
71004 break;
71005 }
71006 case DUK_TAG_POINTER: {
71007 /* implementation specific */
71008 stridx = DUK_STRIDX_LC_POINTER;
71009 break;
71010 }
71011 case DUK_TAG_STRING: {
71012 stridx = DUK_STRIDX_LC_STRING;
71013 break;
71014 }
71015 case DUK_TAG_OBJECT: {
71016 duk_hobject *obj = DUK_TVAL_GET_OBJECT(tv_x);
71017 DUK_ASSERT(obj != NULL);
71018 if (DUK_HOBJECT_IS_CALLABLE(obj)) {
71019 stridx = DUK_STRIDX_LC_FUNCTION;
71020 } else {
71021 stridx = DUK_STRIDX_LC_OBJECT;
71022 }
71023 break;
71024 }
71025 case DUK_TAG_BUFFER: {
71026 /* implementation specific */
71027 stridx = DUK_STRIDX_LC_BUFFER;
71028 break;
71029 }
71030 case DUK_TAG_LIGHTFUNC: {
71031 stridx = DUK_STRIDX_LC_FUNCTION;
#define DUK_STRIDX_LC_POINTER
#define DUK_STRIDX_LC_FUNCTION
#define DUK_STRIDX_LC_UNDEFINED
#define DUK_STRIDX_LC_BOOLEAN