DUK_EXTERNAL duk_int_t duk_pcall(duk_context *ctx, duk_idx_t nargs) { duk_hthread *thr = (duk_hthread *) ctx; duk_small_uint_t call_flags; duk_idx_t idx_func; duk_int_t rc; DUK_ASSERT_CTX_VALID(ctx); DUK_ASSERT(thr != NULL); idx_func = duk_get_top(ctx) - nargs - 1; /* must work for nargs <= 0 */ if (idx_func < 0 || nargs < 0) { /* We can't reliably pop anything here because the stack input * shape is incorrect. So we throw an error; if the caller has * no catch point for this, a fatal error will occur. Another * alternative would be to just return an error. But then the * stack would be in an unknown state which might cause some * very hard to diagnose problems later on. Also note that even * if we did not throw an error here, the underlying call handler * might STILL throw an out-of-memory error or some other internal * fatal error. */ DUK_ERROR_TYPE_INVALID_ARGS(thr); return DUK_EXEC_ERROR; /* unreachable */ } /* awkward; we assume there is space for this */ duk_push_undefined(ctx); duk_insert(ctx, idx_func + 1); call_flags = 0; /* respect reclimit, not constructor */ rc = duk_handle_call_protected(thr, /* thread */ nargs, /* num_stack_args */ call_flags); /* call_flags */ return rc; }
DUK_EXTERNAL duk_int_t duk_pcall_method(duk_context *ctx, duk_idx_t nargs) { duk_hthread *thr = (duk_hthread *) ctx; duk_small_uint_t call_flags; duk_idx_t idx_func; duk_int_t rc; DUK_ASSERT_CTX_VALID(ctx); DUK_ASSERT(thr != NULL); idx_func = duk_get_top(ctx) - nargs - 2; /* must work for nargs <= 0 */ if (idx_func < 0 || nargs < 0) { /* See comments in duk_pcall(). */ DUK_ERROR_TYPE_INVALID_ARGS(thr); return DUK_EXEC_ERROR; /* unreachable */ } call_flags = 0; /* respect reclimit, not constructor */ rc = duk_handle_call_protected(thr, /* thread */ nargs, /* num_stack_args */ call_flags); /* call_flags */ return rc; }
DUK_LOCAL void duk__err_augment_user(duk_hthread *thr, duk_small_uint_t stridx_cb) { duk_context *ctx = (duk_context *) thr; duk_tval *tv_hnd; duk_small_uint_t call_flags; duk_int_t rc; DUK_ASSERT(thr != NULL); DUK_ASSERT(thr->heap != NULL); DUK_ASSERT_DISABLE(stridx_cb >= 0); /* unsigned */ DUK_ASSERT(stridx_cb < DUK_HEAP_NUM_STRINGS); if (DUK_HEAP_HAS_ERRHANDLER_RUNNING(thr->heap)) { DUK_DD(DUK_DDPRINT("recursive call to error handler, ignore")); return; } /* * Check whether or not we have an error handler. * * We must be careful of not triggering an error when looking up the * property. For instance, if the property is a getter, we don't want * to call it, only plain values are allowed. The value, if it exists, * is not checked. If the value is not a function, a TypeError happens * when it is called and that error replaces the original one. */ DUK_ASSERT_VALSTACK_SPACE(thr, 4); /* 3 entries actually needed below */ /* [ ... errval ] */ if (thr->builtins[DUK_BIDX_DUKTAPE] == NULL) { /* When creating built-ins, some of the built-ins may not be set * and we want to tolerate that when throwing errors. */ DUK_DD(DUK_DDPRINT("error occurred when DUK_BIDX_DUKTAPE is NULL, ignoring")); return; } tv_hnd = duk_hobject_find_existing_entry_tval_ptr(thr->heap, thr->builtins[DUK_BIDX_DUKTAPE], DUK_HTHREAD_GET_STRING(thr, stridx_cb)); if (tv_hnd == NULL) { DUK_DD(DUK_DDPRINT("error handler does not exist or is not a plain value: %!T", (duk_tval *) tv_hnd)); return; } DUK_DDD(DUK_DDDPRINT("error handler dump (callability not checked): %!T", (duk_tval *) tv_hnd)); duk_push_tval(ctx, tv_hnd); /* [ ... errval errhandler ] */ duk_insert(ctx, -2); /* -> [ ... errhandler errval ] */ duk_push_undefined(ctx); duk_insert(ctx, -2); /* -> [ ... errhandler undefined(= this) errval ] */ /* [ ... errhandler undefined errval ] */ /* * DUK_CALL_FLAG_IGNORE_RECLIMIT causes duk_handle_call() to ignore C * recursion depth limit (and won't increase it either). This is * dangerous, but useful because it allows the error handler to run * even if the original error is caused by C recursion depth limit. * * The heap level DUK_HEAP_FLAG_ERRHANDLER_RUNNING is set for the * duration of the error handler and cleared afterwards. This flag * prevents the error handler from running recursively. The flag is * heap level so that the flag properly controls even coroutines * launched by an error handler. Since the flag is heap level, it is * critical to restore it correctly. * * We ignore errors now: a success return and an error value both * replace the original error value. (This would be easy to change.) */ DUK_ASSERT(!DUK_HEAP_HAS_ERRHANDLER_RUNNING(thr->heap)); /* since no recursive error handler calls */ DUK_HEAP_SET_ERRHANDLER_RUNNING(thr->heap); call_flags = DUK_CALL_FLAG_IGNORE_RECLIMIT; /* ignore reclimit, not constructor */ rc = duk_handle_call_protected(thr, 1, /* num args */ call_flags); /* call_flags */ DUK_UNREF(rc); /* no need to check now: both success and error are OK */ DUK_ASSERT(DUK_HEAP_HAS_ERRHANDLER_RUNNING(thr->heap)); DUK_HEAP_CLEAR_ERRHANDLER_RUNNING(thr->heap); /* [ ... errval ] */ }