static void duk__call_errhandler(duk_hthread *thr) { int call_flags; int rc; DUK_ASSERT(thr != NULL); DUK_ASSERT(thr->heap != NULL); if (!thr->heap->lj.errhandler) { DUK_DDDPRINT("no errhandler, return"); return; } /* FIXME: assert/require for valstack space */ /* [ ... errval ] */ DUK_DDDPRINT("errhandler is %p", (void *) thr->heap->lj.errhandler); DUK_DDDPRINT("errhandler dump: %!O", (duk_heaphdr *) thr->heap->lj.errhandler); duk_push_hobject((duk_context *) thr, thr->heap->lj.errhandler); duk_insert((duk_context *) thr, -2); /* -> [ ... errhandler errval ] */ duk_push_undefined((duk_context *) thr); duk_insert((duk_context *) thr, -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 an errhandler to run even * if the original error is caused by C recursion depth limit. Because * errhandler is NULL in the errhandler call, the errhandler call * can't cause the same situation to occur again. * * We ignore errors now: a success return and an error value both * replace the original error value. (This would be easy to change.) */ call_flags = DUK_CALL_FLAG_PROTECTED | DUK_CALL_FLAG_IGNORE_RECLIMIT; /* protected, ignore reclimit, not constructor */ rc = duk_handle_call(thr, 1, /* num args */ call_flags, /* call_flags */ NULL); /* errhandler */ DUK_UNREF(rc); /* no need to check now: both success and error are OK */ /* [ ... errval ] */ }
static 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->builtins[DUK_BIDX_DUKTAPE], thr->strs[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_PROTECTED | DUK_CALL_FLAG_IGNORE_RECLIMIT; /* protected, ignore reclimit, not constructor */ rc = duk_handle_call(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 ] */ }