5 #include "duk_internal.h"
8 * Helper to walk the thread chain and see if there is an active error
9 * catcher. Protected calls or finally blocks aren't considered catching.
12 #if defined(DUK_USE_DEBUGGER_SUPPORT) && \
13 (defined(DUK_USE_DEBUGGER_THROW_NOTIFY) || defined(DUK_USE_DEBUGGER_PAUSE_UNCAUGHT))
14 DUK_LOCAL duk_bool_t
duk__have_active_catcher(duk_hthread
*thr
) {
16 * XXX: As noted above, a protected API call won't be counted as a
17 * catcher. This is usually convenient, e.g. in the case of a top-
18 * level duk_pcall(), but may not always be desirable. Perhaps add an
19 * argument to treat them as catchers?
24 DUK_ASSERT(thr
!= NULL
);
27 for (i
= 0; i
< thr
->catchstack_top
; i
++) {
28 duk_catcher
*cat
= thr
->catchstack
+ i
;
29 if (DUK_CAT_HAS_CATCH_ENABLED(cat
)) {
30 return 1; /* all we need to know */
37 #endif /* DUK_USE_DEBUGGER_SUPPORT && (DUK_USE_DEBUGGER_THROW_NOTIFY || DUK_USE_DEBUGGER_PAUSE_UNCAUGHT) */
40 * Get prototype object for an integer error code.
43 DUK_INTERNAL duk_hobject
*duk_error_prototype_from_code(duk_hthread
*thr
, duk_errcode_t code
) {
45 case DUK_ERR_EVAL_ERROR
:
46 return thr
->builtins
[DUK_BIDX_EVAL_ERROR_PROTOTYPE
];
47 case DUK_ERR_RANGE_ERROR
:
48 return thr
->builtins
[DUK_BIDX_RANGE_ERROR_PROTOTYPE
];
49 case DUK_ERR_REFERENCE_ERROR
:
50 return thr
->builtins
[DUK_BIDX_REFERENCE_ERROR_PROTOTYPE
];
51 case DUK_ERR_SYNTAX_ERROR
:
52 return thr
->builtins
[DUK_BIDX_SYNTAX_ERROR_PROTOTYPE
];
53 case DUK_ERR_TYPE_ERROR
:
54 return thr
->builtins
[DUK_BIDX_TYPE_ERROR_PROTOTYPE
];
55 case DUK_ERR_URI_ERROR
:
56 return thr
->builtins
[DUK_BIDX_URI_ERROR_PROTOTYPE
];
58 /* XXX: more specific error classes? */
59 case DUK_ERR_UNIMPLEMENTED_ERROR
:
60 case DUK_ERR_INTERNAL_ERROR
:
61 case DUK_ERR_ALLOC_ERROR
:
62 case DUK_ERR_ASSERTION_ERROR
:
63 case DUK_ERR_API_ERROR
:
66 return thr
->builtins
[DUK_BIDX_ERROR_PROTOTYPE
];
71 * Exposed helper for setting up heap longjmp state.
74 DUK_INTERNAL
void duk_err_setup_heap_ljstate(duk_hthread
*thr
, duk_small_int_t lj_type
) {
75 #if defined(DUK_USE_DEBUGGER_SUPPORT)
76 /* If something is thrown with the debugger attached and nobody will
77 * catch it, execution is paused before the longjmp, turning over
78 * control to the debug client. This allows local state to be examined
79 * before the stack is unwound. Errors are not intercepted when debug
80 * message loop is active (e.g. for Eval).
83 /* XXX: Allow customizing the pause and notify behavior at runtime
84 * using debugger runtime flags. For now the behavior is fixed using
87 #if defined(DUK_USE_DEBUGGER_THROW_NOTIFY) || defined(DUK_USE_DEBUGGER_PAUSE_UNCAUGHT)
88 if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr
->heap
) &&
89 !thr
->heap
->dbg_processing
&&
90 lj_type
== DUK_LJ_TYPE_THROW
) {
91 duk_context
*ctx
= (duk_context
*) thr
;
95 /* Don't intercept a DoubleError, we may have caused the initial double
96 * fault and attempting to intercept it will cause us to be called
97 * recursively and exhaust the C stack.
99 h_obj
= duk_get_hobject(ctx
, -1);
100 if (h_obj
== thr
->builtins
[DUK_BIDX_DOUBLE_ERROR
]) {
101 DUK_D(DUK_DPRINT("built-in DoubleError instance thrown, not intercepting"));
102 goto skip_throw_intercept
;
105 DUK_D(DUK_DPRINT("throw with debugger attached, report to client"));
107 fatal
= !duk__have_active_catcher(thr
);
109 #if defined(DUK_USE_DEBUGGER_THROW_NOTIFY)
110 /* Report it to the debug client */
111 duk_debug_send_throw(thr
, fatal
);
114 #if defined(DUK_USE_DEBUGGER_PAUSE_UNCAUGHT)
116 DUK_D(DUK_DPRINT("throw will be fatal, halt before longjmp"));
117 duk_debug_halt_execution(thr
, 1 /*use_prev_pc*/);
122 skip_throw_intercept
:
123 #endif /* DUK_USE_DEBUGGER_THROW_NOTIFY || DUK_USE_DEBUGGER_PAUSE_UNCAUGHT */
124 #endif /* DUK_USE_DEBUGGER_SUPPORT */
126 thr
->heap
->lj
.type
= lj_type
;
128 DUK_ASSERT(thr
->valstack_top
> thr
->valstack
);
129 DUK_TVAL_SET_TVAL_UPDREF(thr
, &thr
->heap
->lj
.value1
, thr
->valstack_top
- 1); /* side effects */
131 duk_pop((duk_context
*) thr
);