| /* |
| * Thread support. |
| */ |
| |
| #include "duk_internal.h" |
| |
| DUK_INTERNAL void duk_hthread_terminate(duk_hthread *thr) { |
| DUK_ASSERT(thr != NULL); |
| |
| /* Order of unwinding is important */ |
| |
| duk_hthread_catchstack_unwind(thr, 0); |
| |
| duk_hthread_callstack_unwind(thr, 0); /* side effects, possibly errors */ |
| |
| thr->valstack_bottom = thr->valstack; |
| duk_set_top((duk_context *) thr, 0); /* unwinds valstack, updating refcounts */ |
| |
| thr->state = DUK_HTHREAD_STATE_TERMINATED; |
| |
| /* Here we could remove references to built-ins, but it may not be |
| * worth the effort because built-ins are quite likely to be shared |
| * with another (unterminated) thread, and terminated threads are also |
| * usually garbage collected quite quickly. Also, doing DECREFs |
| * could trigger finalization, which would run on the current thread |
| * and have access to only some of the built-ins. Garbage collection |
| * deals with this correctly already. |
| */ |
| |
| /* XXX: Shrink the stacks to minimize memory usage? May not |
| * be worth the effort because terminated threads are usually |
| * garbage collected quite soon. |
| */ |
| } |
| |
| DUK_INTERNAL duk_activation *duk_hthread_get_current_activation(duk_hthread *thr) { |
| DUK_ASSERT(thr != NULL); |
| |
| if (thr->callstack_top > 0) { |
| return thr->callstack + thr->callstack_top - 1; |
| } else { |
| return NULL; |
| } |
| } |
| |
| #if defined(DUK_USE_DEBUGGER_SUPPORT) |
| DUK_INTERNAL duk_uint_fast32_t duk_hthread_get_act_curr_pc(duk_hthread *thr, duk_activation *act) { |
| duk_instr_t *bcode; |
| |
| DUK_ASSERT(thr != NULL); |
| DUK_ASSERT(act != NULL); |
| DUK_UNREF(thr); |
| |
| /* XXX: store 'bcode' pointer to activation for faster lookup? */ |
| if (act->func && DUK_HOBJECT_IS_COMPILEDFUNCTION(act->func)) { |
| bcode = DUK_HCOMPILEDFUNCTION_GET_CODE_BASE(thr->heap, (duk_hcompiledfunction *) (act->func)); |
| return (duk_uint_fast32_t) (act->curr_pc - bcode); |
| } |
| return 0; |
| } |
| #endif /* DUK_USE_DEBUGGER_SUPPORT */ |
| |
| DUK_INTERNAL duk_uint_fast32_t duk_hthread_get_act_prev_pc(duk_hthread *thr, duk_activation *act) { |
| duk_instr_t *bcode; |
| duk_uint_fast32_t ret; |
| |
| DUK_ASSERT(thr != NULL); |
| DUK_ASSERT(act != NULL); |
| DUK_UNREF(thr); |
| |
| if (act->func && DUK_HOBJECT_IS_COMPILEDFUNCTION(act->func)) { |
| bcode = DUK_HCOMPILEDFUNCTION_GET_CODE_BASE(thr->heap, (duk_hcompiledfunction *) (act->func)); |
| ret = (duk_uint_fast32_t) (act->curr_pc - bcode); |
| if (ret > 0) { |
| ret--; |
| } |
| return ret; |
| } |
| return 0; |
| } |
| |
| /* Write bytecode executor's curr_pc back to topmost activation (if any). */ |
| DUK_INTERNAL void duk_hthread_sync_currpc(duk_hthread *thr) { |
| duk_activation *act; |
| |
| DUK_ASSERT(thr != NULL); |
| |
| if (thr->ptr_curr_pc != NULL) { |
| /* ptr_curr_pc != NULL only when bytecode executor is active. */ |
| DUK_ASSERT(thr->callstack_top > 0); |
| act = thr->callstack + thr->callstack_top - 1; |
| act->curr_pc = *thr->ptr_curr_pc; |
| } |
| } |
| |
| DUK_INTERNAL void duk_hthread_sync_and_null_currpc(duk_hthread *thr) { |
| duk_activation *act; |
| |
| DUK_ASSERT(thr != NULL); |
| |
| if (thr->ptr_curr_pc != NULL) { |
| /* ptr_curr_pc != NULL only when bytecode executor is active. */ |
| DUK_ASSERT(thr->callstack_top > 0); |
| act = thr->callstack + thr->callstack_top - 1; |
| act->curr_pc = *thr->ptr_curr_pc; |
| thr->ptr_curr_pc = NULL; |
| } |
| } |