diff --git a/mozilla/js/jsd/idl/jsdIDebuggerService.idl b/mozilla/js/jsd/idl/jsdIDebuggerService.idl index b193f92dd76..81c2a78e3d2 100644 --- a/mozilla/js/jsd/idl/jsdIDebuggerService.idl +++ b/mozilla/js/jsd/idl/jsdIDebuggerService.idl @@ -160,12 +160,47 @@ interface jsdIDebuggerService : nsISupports * When this flag is set the internal call hook will collect profile data. */ const unsigned long COLLECT_PROFILE_DATA = 0x08; + /** + * When this flag is set, stack frames that are disabled for debugging + * will not appear in the call stack chain. + */ + const unsigned long HIDE_DISABLED_FRAMES = 0x10; + /** + * When this flag is set, the debugger will only check the + * JSD_SCRIPT_DEBUG_BIT on the top (most recent) stack frame. This + * makes it possible to stop in an enabled frame which was called from + * a stack that contains a disabled frame. + * + * When this flag is *not* set, any stack that contains a disabled frame + * will not be debugged (the execution hook will not be invoked.) + * + * This only applies when the reason for calling the hook would have + * been TYPE_INTERRUPTED or TYPE_THROW. TYPE_BREAKPOINT, + * TYPE_DEBUG_REQUESTED, and TYPE_DEBUGGER_KEYWORD always stop, regardless + * of this setting, as long as the top frame is not disabled. + * + * If HIDE_DISABLED_FRAMES is set, this is effectively set as well. + */ + const unsigned long MASK_TOP_FRAME_ONLY = 0x20; /** * Debugger service flags. */ attribute unsigned long flags; + /** + * Major version number of implementation. + */ + readonly attribute unsigned long implementationMajor; + /** + * Minor version number of implementation. + */ + readonly attribute unsigned long implementationMinor; + /** + * Free form string identifier for implementation. + */ + readonly attribute string implementationString; + /** * |true| if the debugger should register an app-start observer in order * to begin collecting debug information when mozilla is launched. diff --git a/mozilla/js/jsd/jsd.h b/mozilla/js/jsd/jsd.h index cd905a53974..d98940e044c 100644 --- a/mozilla/js/jsd/jsd.h +++ b/mozilla/js/jsd/jsd.h @@ -237,6 +237,8 @@ struct JSDExecHook void* callerdata; }; +#define TS_HAS_DISABLED_FRAME 0x01 + struct JSDThreadState { JSCList links; /* we are part of a JSCList */ @@ -244,6 +246,7 @@ struct JSDThreadState void* thread; JSCList stack; uintN stackDepth; + uintN flags; }; struct JSDStackFrameInfo diff --git a/mozilla/js/jsd/jsd_hook.c b/mozilla/js/jsd/jsd_hook.c index 0dbda2e1c05..0f62f8f7fbe 100644 --- a/mozilla/js/jsd/jsd_hook.c +++ b/mozilla/js/jsd/jsd_hook.c @@ -164,8 +164,19 @@ jsd_CallExecutionHook(JSDContext* jsdc, if(hook && NULL != (jsdthreadstate = jsd_NewThreadState(jsdc,cx))) { - hookanswer = hook(jsdc, jsdthreadstate, type, hookData, rval); - jsd_DestroyThreadState(jsdc, jsdthreadstate); + if ((type != JSD_HOOK_THROW && type != JSD_HOOK_INTERRUPTED) || + jsdc->flags & JSD_MASK_TOP_FRAME_ONLY || + !(jsdthreadstate->flags & TS_HAS_DISABLED_FRAME)) + { + /* + * if it's not a throw and it's not an interrupt, + * or we're only masking the top frame, + * or there are no disabled frames in this stack, + * then call out. + */ + hookanswer = hook(jsdc, jsdthreadstate, type, hookData, rval); + jsd_DestroyThreadState(jsdc, jsdthreadstate); + } } switch(hookanswer) diff --git a/mozilla/js/jsd/jsd_stak.c b/mozilla/js/jsd/jsd_stak.c index 0cab71c0c1d..5f4ee19b771 100644 --- a/mozilla/js/jsd/jsd_stak.c +++ b/mozilla/js/jsd/jsd_stak.c @@ -70,8 +70,14 @@ _addNewFrame(JSDContext* jsdc, JSD_LOCK_SCRIPTS(jsdc); jsdscript = jsd_FindJSDScript(jsdc, script); JSD_UNLOCK_SCRIPTS(jsdc); - if (!jsdscript || !JSD_IS_DEBUG_ENABLED(jsdc, jsdscript)) + if (!jsdscript || (jsdc->flags & JSD_HIDE_DISABLED_FRAMES && + !JSD_IS_DEBUG_ENABLED(jsdc, jsdscript))) + { return NULL; + } + + if (!JSD_IS_DEBUG_ENABLED(jsdc, jsdscript)) + jsdthreadstate->flags |= TS_HAS_DISABLED_FRAME; } jsdframe = (JSDStackFrameInfo*) calloc(1, sizeof(JSDStackFrameInfo)); @@ -128,26 +134,31 @@ jsd_NewThreadState(JSDContext* jsdc, JSContext *cx ) ((jsdc->flags & JSD_INCLUDE_NATIVE_FRAMES) || !JS_IsNativeFrame(cx, fp))) { - - if (!_addNewFrame( jsdc, jsdthreadstate, script, pc, fp ) && - jsdthreadstate->stackDepth == 0) + JSDStackFrameInfo *frame; + + frame = _addNewFrame( jsdc, jsdthreadstate, script, pc, fp ); + + if (jsdthreadstate->stackDepth == 0 && !frame) || + (jsdthreadstate->stackDepth == 1 && frame && + !JSD_IS_DEBUG_ENABLED(jsdc, frame->jsdscript))) { /* - * if we failed to create the first frame, fail the entire - * thread state. + * if we failed to create the first frame, or the top frame + * is not enabled for debugging, fail the entire thread state. */ - break; + JS_INIT_CLIST(&jsdthreadstate->links); + jsd_DestroyThreadState(jsdc, jsdthreadstate); + return NULL; } } } - - /* if there is no stack, then this threadstate can not be constructed */ - if( 0 == jsdthreadstate->stackDepth ) + + if (jsdthreadstate->stackDepth == 0) { free(jsdthreadstate); return NULL; } - + JSD_LOCK_THREADSTATES(jsdc); JS_APPEND_LINK(&jsdthreadstate->links, &jsdc->threadsStates); JSD_UNLOCK_THREADSTATES(jsdc); diff --git a/mozilla/js/jsd/jsd_xpc.cpp b/mozilla/js/jsd/jsd_xpc.cpp index 50874bfdee9..6976ed22d4c 100644 --- a/mozilla/js/jsd/jsd_xpc.cpp +++ b/mozilla/js/jsd/jsd_xpc.cpp @@ -95,6 +95,9 @@ {0xad, 0x26, 0x11, 0x3f, 0x2c, 0x02, 0xd0, 0xfe} \ } +#define JSDS_MAJOR_VERSION 1 +#define JSDS_MINOR_VERSION 1 + #define NS_CATMAN_CTRID "@mozilla.org/categorymanager;1" #define NS_JSRT_CTRID "@mozilla.org/js/xpc/RuntimeService;1" @@ -107,8 +110,9 @@ jsds_GCCallbackProc (JSContext *cx, JSGCStatus status); /******************************************************************************* * global vars - *******************************************************************************/ + ******************************************************************************/ +const char implementationString[] = "Mozilla JavaScript Debugger Service"; static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID); static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID); @@ -2370,6 +2374,29 @@ jsdService::SetFlags (PRUint32 flags) return NS_OK; } +NS_IMETHODIMP +jsdService::GetImplementationString(char **_rval) +{ + *_rval = PL_strdup(implementationString); + if (!*_rval) + return NS_ERROR_OUT_OF_MEMORY; + return NS_OK; +} + +NS_IMETHODIMP +jsdService::GetImplementationMajor(PRUint32 *_rval) +{ + *_rval = JSDS_MAJOR_VERSION; + return NS_OK; +} + +NS_IMETHODIMP +jsdService::GetImplementationMinor(PRUint32 *_rval) +{ + *_rval = JSDS_MINOR_VERSION; + return NS_OK; +} + NS_IMETHODIMP jsdService::GetIsOn (PRBool *_rval) { diff --git a/mozilla/js/jsd/jsdebug.h b/mozilla/js/jsd/jsdebug.h index 70417666446..bdc5e7000c0 100644 --- a/mozilla/js/jsd/jsdebug.h +++ b/mozilla/js/jsd/jsdebug.h @@ -208,6 +208,28 @@ JSD_ClearAllProfileData(JSDContext* jsdc); * When this flag is set the internal call hook will collect profile data. */ #define JSD_COLLECT_PROFILE_DATA 0x08 +/* +* When this flag is set, stack frames that are disabled for debugging +* will not appear in the call stack chain. +*/ +#define JSD_HIDE_DISABLED_FRAMES 0x10 +/* +* When this flag is set, the debugger will only check the +* JSD_SCRIPT_DEBUG_BIT on the top (most recent) stack frame. This +* makes it possible to stop in an enabled frame which was called from +* a stack that contains a disabled frame. +* +* When this flag is *not* set, any stack that contains a disabled frame +* will not be debugged (the execution hook will not be invoked.) +* +* This only applies when the reason for calling the hook would have +* been JSD_HOOK_INTERRUPTED or JSD_HOOK_THROW. JSD_HOOK_BREAKPOINT, +* JSD_HOOK_DEBUG_REQUESTED, and JSD_HOOK_DEBUGGER_KEYWORD always stop, +* regardless of this setting, as long as the top frame is not disabled. +* +* If JSD_HIDE_DISABLED_FRAMES is set, this is effectively set as well. +*/ +#define JSD_MASK_TOP_FRAME_ONLY 0x20 extern JSD_PUBLIC_API(void) JSD_SetContextFlags (JSDContext* jsdc, uint32 flags);