Browse Source

Add duk_debugger_cooperate() API call

pull/156/head
Sami Vaarala 10 years ago
parent
commit
b512503474
  1. 32
      src/duk_api_debug.c
  2. 1
      src/duk_api_public.h.in
  3. 71
      src/duk_debugger.c
  4. 5
      src/duk_debugger.h
  5. 1
      src/duk_heap.h
  6. 6
      src/duk_js_executor.c

32
src/duk_api_debug.c

@ -66,6 +66,7 @@ DUK_EXTERNAL void duk_debugger_attach(duk_context *ctx,
heap->dbg_udata = udata;
/* Start in paused state. */
heap->dbg_processing = 0;
heap->dbg_paused = 1;
heap->dbg_state_dirty = 1;
heap->dbg_step_type = 0;
@ -103,6 +104,32 @@ DUK_EXTERNAL void duk_debugger_detach(duk_context *ctx) {
duk_debug_do_detach(thr->heap);
}
DUK_EXTERNAL void duk_debugger_cooperate(duk_context *ctx) {
duk_hthread *thr;
duk_bool_t processed_messages;
thr = (duk_hthread *) ctx;
DUK_ASSERT(ctx != NULL);
DUK_ASSERT(thr != NULL);
DUK_ASSERT(thr->heap != NULL);
if (!DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) {
return;
}
if (thr->callstack_top > 0 || thr->heap->dbg_processing) {
/* Calling duk_debugger_cooperate() while Duktape is being
* called into is not supported. This is not a 100% check
* but prevents any damage in most cases.
*/
return;
}
thr->heap->dbg_processing = 1;
processed_messages = duk_debug_process_messages(thr, 1 /*no_block*/);
thr->heap->dbg_processing = 0;
DUK_UNREF(processed_messages);
}
#else /* DUK_USE_DEBUGGER_SUPPORT */
DUK_EXTERNAL void duk_debugger_attach(duk_context *ctx,
@ -127,4 +154,9 @@ DUK_EXTERNAL void duk_debugger_detach(duk_context *ctx) {
duk_error(ctx, DUK_ERR_API_ERROR, "no debugger support");
}
DUK_EXTERNAL void duk_debugger_cooperate(duk_context *ctx) {
/* nop */
DUK_UNREF(ctx);
}
#endif /* DUK_USE_DEBUGGER_SUPPORT */

1
src/duk_api_public.h.in

@ -879,6 +879,7 @@ DUK_EXTERNAL_DECL void duk_debugger_attach(duk_context *ctx,
duk_debug_detached_function detached_cb,
void *udata);
DUK_EXTERNAL_DECL void duk_debugger_detach(duk_context *ctx);
DUK_EXTERNAL_DECL void duk_debugger_cooperate(duk_context *ctx);
/*
* C++ name mangling

71
src/duk_debugger.c

@ -41,6 +41,7 @@ DUK_INTERNAL void duk_debug_do_detach(duk_heap *heap) {
}
heap->dbg_detached_cb = NULL;
heap->dbg_udata = NULL;
heap->dbg_processing = 0;
heap->dbg_paused = 0;
heap->dbg_state_dirty = 0;
heap->dbg_step_type = 0;
@ -506,6 +507,14 @@ DUK_INTERNAL void duk_debug_write_byte(duk_hthread *thr, duk_uint8_t x) {
}
}
DUK_INTERNAL void duk_debug_write_unused(duk_hthread *thr) {
duk_debug_write_byte(thr, 0x15);
}
DUK_INTERNAL void duk_debug_write_undefined(duk_hthread *thr) {
duk_debug_write_byte(thr, 0x16);
}
/* Write signed 32-bit integer. */
DUK_INTERNAL void duk_debug_write_int(duk_hthread *thr, duk_int32_t x) {
duk_uint8_t buf[5];
@ -648,10 +657,6 @@ DUK_INTERNAL void duk_debug_write_hobject(duk_hthread *thr, duk_hobject *obj) {
duk_debug_write_bytes(thr, (const duk_uint8_t *) &pu.p, (duk_size_t) sizeof(pu));
}
DUK_INTERNAL void duk_debug_write_unused(duk_hthread *thr) {
duk_debug_write_byte(thr, 0x15);
}
DUK_INTERNAL void duk_debug_write_tval(duk_hthread *thr, duk_tval *tv) {
duk_c_function lf_func;
duk_small_uint_t lf_flags;
@ -791,10 +796,17 @@ DUK_INTERNAL void duk_debug_send_status(duk_hthread *thr) {
duk_context *ctx = (duk_context *) thr;
duk_activation *act;
act = thr->callstack + thr->callstack_top - 1;
duk_debug_write_notify(thr, DUK_DBG_CMD_STATUS);
duk_debug_write_int(thr, thr->heap->dbg_paused);
DUK_ASSERT_DISABLE(thr->callstack_top >= 0); /* unsigned */
if (thr->callstack_top == 0) {
duk_debug_write_undefined(thr);
duk_debug_write_undefined(thr);
duk_debug_write_int(thr, 0);
duk_debug_write_int(thr, 0);
} else {
act = thr->callstack + thr->callstack_top - 1;
duk_push_hobject(ctx, act->func);
duk_get_prop_string(ctx, -1, "fileName");
duk_safe_to_string(ctx, -1);
@ -805,6 +817,8 @@ DUK_INTERNAL void duk_debug_send_status(duk_hthread *thr) {
duk_pop_3(ctx);
duk_debug_write_uint(thr, (duk_uint32_t) duk_debug_curr_line(thr));
duk_debug_write_uint(thr, (duk_uint32_t) act->pc);
}
duk_debug_write_eom(thr);
}
@ -1032,10 +1046,19 @@ DUK_LOCAL void duk__debug_handle_get_var(duk_hthread *thr, duk_heap *heap) {
str = duk_debug_read_hstring(thr); /* push to stack */
DUK_ASSERT(str != NULL);
if (thr->callstack_top > 0) {
rc = duk_js_getvar_activation(thr,
thr->callstack + thr->callstack_top - 1,
str,
0);
} else {
/* No activation, no variable access. Could also pretend
* we're in the global program context and read stuff off
* the global object.
*/
DUK_D(DUK_DPRINT("callstack empty, no activation -> ignore getvar"));
rc = 0;
}
duk_debug_write_reply(thr);
if (rc) {
@ -1044,9 +1067,7 @@ DUK_LOCAL void duk__debug_handle_get_var(duk_hthread *thr, duk_heap *heap) {
duk_pop_2(ctx);
} else {
duk_debug_write_int(thr, 0);
duk_push_unused(thr);
duk_debug_write_tval(thr, duk_require_tval(ctx, -1));
duk_pop(ctx);
duk_debug_write_unused(thr);
}
duk_pop(ctx);
duk_debug_write_eom(thr);
@ -1065,12 +1086,15 @@ DUK_LOCAL void duk__debug_handle_put_var(duk_hthread *thr, duk_heap *heap) {
duk_debug_read_tval(thr); /* push to stack */
tv = duk_require_tval(ctx, -1);
if (thr->callstack_top > 0) {
duk_js_putvar_activation(thr,
thr->callstack + thr->callstack_top - 1,
str,
tv,
0);
} else {
DUK_D(DUK_DPRINT("callstack empty, no activation -> ignore putvar"));
}
duk_pop_2(ctx);
/* XXX: Current putvar implementation doesn't have a success flag,
@ -1188,7 +1212,22 @@ DUK_LOCAL void duk__debug_handle_eval(duk_hthread *thr, duk_heap *heap) {
/* [ ... eval "eval" eval_input ] */
call_flags = DUK_CALL_FLAG_DIRECT_EVAL | DUK_CALL_FLAG_PROTECTED;
call_flags = DUK_CALL_FLAG_PROTECTED;
if (thr->callstack_top >= 1) {
duk_activation *act;
duk_hobject *fun;
act = thr->callstack + thr->callstack_top - 1;
fun = DUK_ACT_GET_FUNC(act);
if (fun && DUK_HOBJECT_IS_COMPILEDFUNCTION(fun)) {
/* Direct eval requires that there's a current
* activation and it is an Ecmascript function.
* When Eval is executed from e.g. cooperate API
* call we'll need to an indirect eval instead.
*/
call_flags |= DUK_CALL_FLAG_DIRECT_EVAL;
}
}
call_ret = duk_handle_call(thr, 1 /*num_stack_args*/, call_flags);
@ -1497,7 +1536,7 @@ DUK_LOCAL void duk__debug_process_message(duk_hthread *thr) {
break;
}
default: {
DUK_D(DUK_DPRINT("invalid initial byte, drop connection"));
DUK_D(DUK_DPRINT("invalid initial byte, drop connection: %d", (int) x));
goto fail;
}
} /* switch initial byte */
@ -1510,7 +1549,7 @@ DUK_LOCAL void duk__debug_process_message(duk_hthread *thr) {
return;
}
DUK_INTERNAL duk_bool_t duk_debug_process_messages(duk_hthread *thr) {
DUK_INTERNAL duk_bool_t duk_debug_process_messages(duk_hthread *thr, duk_bool_t no_block) {
duk_context *ctx = (duk_context *) thr;
#if defined(DUK_USE_ASSERTIONS)
duk_idx_t entry_top;
@ -1534,12 +1573,12 @@ DUK_INTERNAL duk_bool_t duk_debug_process_messages(duk_hthread *thr) {
if (thr->heap->dbg_read_cb == NULL) {
DUK_D(DUK_DPRINT("debug connection broken, stop processing messages"));
break;
} else if (!thr->heap->dbg_paused) {
} else if (!thr->heap->dbg_paused || no_block) {
if (!duk_debug_read_peek(thr)) {
DUK_D(DUK_DPRINT("processing debug message, not paused and peek indicated no data, stop processing"));
DUK_D(DUK_DPRINT("processing debug message, peek indicated no data, stop processing"));
break;
}
DUK_D(DUK_DPRINT("processing debug message, not paused and peek indicated there is data, handle it"));
DUK_D(DUK_DPRINT("processing debug message, peek indicated there is data, handle it"));
} else {
DUK_D(DUK_DPRINT("paused, process debug message, blocking if necessary"));
}

5
src/duk_debugger.h

@ -59,6 +59,8 @@ DUK_INTERNAL_DECL void duk_debug_read_tval(duk_hthread *thr);
DUK_INTERNAL_DECL void duk_debug_write_bytes(duk_hthread *thr, const duk_uint8_t *data, duk_size_t length);
DUK_INTERNAL_DECL void duk_debug_write_byte(duk_hthread *thr, duk_uint8_t x);
DUK_INTERNAL_DECL void duk_debug_write_unused(duk_hthread *thr);
DUK_INTERNAL_DECL void duk_debug_write_undefined(duk_hthread *thr);
DUK_INTERNAL_DECL void duk_debug_write_int(duk_hthread *thr, duk_int32_t x);
DUK_INTERNAL_DECL void duk_debug_write_uint(duk_hthread *thr, duk_uint32_t x);
DUK_INTERNAL_DECL void duk_debug_write_string(duk_hthread *thr, const char *data, duk_size_t length);
@ -69,7 +71,6 @@ DUK_INTERNAL_DECL void duk_debug_write_hbuffer(duk_hthread *thr, duk_hbuffer *h)
DUK_INTERNAL_DECL void duk_debug_write_pointer(duk_hthread *thr, const void *ptr);
DUK_INTERNAL_DECL void duk_debug_write_heapptr(duk_hthread *thr, duk_heaphdr *h);
DUK_INTERNAL_DECL void duk_debug_write_hobject(duk_hthread *thr, duk_hobject *obj);
DUK_INTERNAL_DECL void duk_debug_write_unused(duk_hthread *thr);
DUK_INTERNAL_DECL void duk_debug_write_tval(duk_hthread *thr, duk_tval *tv);
#if 0 /* unused */
@ -83,7 +84,7 @@ DUK_INTERNAL_DECL void duk_debug_write_eom(duk_hthread *thr);
DUK_INTERNAL duk_uint_fast32_t duk_debug_curr_line(duk_hthread *thr);
DUK_INTERNAL void duk_debug_send_status(duk_hthread *thr);
DUK_INTERNAL_DECL duk_bool_t duk_debug_process_messages(duk_hthread *thr);
DUK_INTERNAL_DECL duk_bool_t duk_debug_process_messages(duk_hthread *thr, duk_bool_t no_block);
DUK_INTERNAL_DECL duk_small_int_t duk_debug_add_breakpoint(duk_hthread *thr, duk_hstring *filename, duk_uint32_t line);
DUK_INTERNAL_DECL duk_bool_t duk_debug_remove_breakpoint(duk_hthread *thr, duk_small_uint_t breakpoint_index);

1
src/duk_heap.h

@ -463,6 +463,7 @@ struct duk_heap {
void *dbg_udata;
/* debugger state, only relevant when attached */
duk_bool_t dbg_processing; /* currently processing messages or breakpoints: don't enter message processing recursively (e.g. no breakpoints when processing debugger eval) */
duk_bool_t dbg_paused; /* currently paused: talk with debug client until step/resume */
duk_bool_t dbg_state_dirty; /* resend state next time executor is about to run */
duk_small_uint_t dbg_step_type; /* step type: none, step into, step over, step out */

6
src/duk_js_executor.c

@ -1481,7 +1481,7 @@ DUK_LOCAL void duk__interrupt_handle_debugger(duk_hthread *thr, duk_bool_t *out_
*/
if (process_messages) {
processed_messages = duk_debug_process_messages(thr);
processed_messages = duk_debug_process_messages(thr, 0 /*no_block*/);
}
/* XXX: any case here where we need to re-send status? */
@ -1958,8 +1958,10 @@ DUK_INTERNAL void duk_js_execute_bytecode(duk_hthread *exec_thr) {
bcode = DUK_HCOMPILEDFUNCTION_GET_CODE_BASE(thr->heap, fun);
#if defined(DUK_USE_DEBUGGER_SUPPORT)
if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) {
if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap) && !thr->heap->dbg_processing) {
thr->heap->dbg_processing = 1;
duk__executor_handle_debugger(thr, act, fun);
thr->heap->dbg_processing = 0;
}
#endif /* DUK_USE_DEBUGGER_SUPPORT */

Loading…
Cancel
Save