michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- michael@0: * vim: set ts=8 sts=4 et sw=4 tw=99: michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: /* michael@0: * Header for JavaScript Debugging support - Internal ONLY declarations michael@0: */ michael@0: michael@0: #ifndef jsd_h___ michael@0: #define jsd_h___ michael@0: michael@0: /* michael@0: * NOTE: This is a *private* header file and should only be included by michael@0: * the sources in js/jsd. Defining EXPORT_JSD_API in an outside module michael@0: * using jsd would be bad. michael@0: */ michael@0: #define EXPORT_JSD_API 1 /* if used, must be set before include of jsdebug.h */ michael@0: michael@0: /* michael@0: * These can be controled by the makefile, but this allows a place to set michael@0: * the values always used in the mozilla client, but perhaps done differently michael@0: * in other embeddings. michael@0: */ michael@0: #ifdef MOZILLA_CLIENT michael@0: #define JSD_THREADSAFE 1 michael@0: /* define JSD_HAS_DANGEROUS_THREAD 1 */ michael@0: #define JSD_USE_NSPR_LOCKS 1 michael@0: #endif /* MOZILLA_CLIENT */ michael@0: michael@0: #include "jsapi.h" michael@0: #include "jshash.h" michael@0: #include "jsclist.h" michael@0: #include "jsdebug.h" michael@0: #include "js/OldDebugAPI.h" michael@0: #include "jsd_lock.h" michael@0: michael@0: #include michael@0: #include michael@0: #include michael@0: michael@0: #define JSD_MAJOR_VERSION 1 michael@0: #define JSD_MINOR_VERSION 1 michael@0: michael@0: /***************************************************************************/ michael@0: /* handy macros */ michael@0: #undef CHECK_BIT_FLAG michael@0: #define CHECK_BIT_FLAG(f,b) ((f)&(b)) michael@0: #undef SET_BIT_FLAG michael@0: #define SET_BIT_FLAG(f,b) ((f)|=(b)) michael@0: #undef CLEAR_BIT_FLAG michael@0: #define CLEAR_BIT_FLAG(f,b) ((f)&=(~(b))) michael@0: michael@0: #define JSD_IS_DEBUG_ENABLED(jsdc,jsdscript) \ michael@0: (!(((jsdc->flags & JSD_DEBUG_WHEN_SET) ? 1 : 0) ^ \ michael@0: ((jsdscript->flags & JSD_SCRIPT_DEBUG_BIT) ? 1 : 0))) michael@0: #define JSD_IS_PROFILE_ENABLED(jsdc,jsdscript) \ michael@0: ((jsdc->flags & JSD_COLLECT_PROFILE_DATA) && \ michael@0: (!(((jsdc->flags & JSD_PROFILE_WHEN_SET) ? 1 : 0) ^ \ michael@0: ((jsdscript->flags & JSD_SCRIPT_PROFILE_BIT) ? 1 : 0)))) michael@0: michael@0: michael@0: /***************************************************************************/ michael@0: /* These are not exposed in jsdebug.h - typedef here for consistency */ michael@0: michael@0: typedef struct JSDExecHook JSDExecHook; michael@0: typedef struct JSDAtom JSDAtom; michael@0: typedef struct JSDProfileData JSDProfileData; michael@0: /***************************************************************************/ michael@0: /* Our structures */ michael@0: michael@0: /* michael@0: * XXX What I'm calling a JSDContext is really more of a JSDTaskState. michael@0: */ michael@0: michael@0: struct JSDContext michael@0: { michael@0: JSCList links; /* we are part of a JSCList */ michael@0: bool inited; michael@0: void* data; michael@0: uint32_t flags; michael@0: JSD_ScriptHookProc scriptHook; michael@0: void* scriptHookData; michael@0: JSD_ExecutionHookProc interruptHook; michael@0: void* interruptHookData; michael@0: JSRuntime* jsrt; michael@0: JSD_ErrorReporter errorReporter; michael@0: void* errorReporterData; michael@0: JSCList threadsStates; michael@0: JSD_ExecutionHookProc debugBreakHook; michael@0: void* debugBreakHookData; michael@0: JSD_ExecutionHookProc debuggerHook; michael@0: void* debuggerHookData; michael@0: JSD_ExecutionHookProc throwHook; michael@0: void* throwHookData; michael@0: JSD_CallHookProc functionHook; michael@0: void* functionHookData; michael@0: JSD_CallHookProc toplevelHook; michael@0: void* toplevelHookData; michael@0: JS::Heap glob; michael@0: JSD_UserCallbacks userCallbacks; michael@0: void* user; michael@0: JSCList scripts; michael@0: JSHashTable* scriptsTable; michael@0: JSCList sources; michael@0: JSCList removedSources; michael@0: unsigned sourceAlterCount; michael@0: JSHashTable* atoms; michael@0: JSCList objectsList; michael@0: JSHashTable* objectsTable; michael@0: JSDProfileData* callingFunctionPData; michael@0: int64_t lastReturnTime; michael@0: #ifdef JSD_THREADSAFE michael@0: JSDStaticLock* scriptsLock; michael@0: JSDStaticLock* sourceTextLock; michael@0: JSDStaticLock* objectsLock; michael@0: JSDStaticLock* atomsLock; michael@0: JSDStaticLock* threadStatesLock; michael@0: #endif /* JSD_THREADSAFE */ michael@0: #ifdef JSD_HAS_DANGEROUS_THREAD michael@0: void* dangerousThread; michael@0: #endif /* JSD_HAS_DANGEROUS_THREAD */ michael@0: michael@0: }; michael@0: michael@0: struct JSDScript michael@0: { michael@0: JSCList links; /* we are part of a JSCList */ michael@0: JSDContext* jsdc; /* JSDContext for this jsdscript */ michael@0: JSScript* script; /* script we are wrapping */ michael@0: unsigned lineBase; /* we cache this */ michael@0: unsigned lineExtent; /* we cache this */ michael@0: JSCList hooks; /* JSCList of JSDExecHooks for this script */ michael@0: char* url; michael@0: uint32_t flags; michael@0: void* data; michael@0: michael@0: JSDProfileData *profileData; michael@0: }; michael@0: michael@0: struct JSDProfileData michael@0: { michael@0: JSDProfileData* caller; michael@0: int64_t lastCallStart; michael@0: int64_t runningTime; michael@0: unsigned callCount; michael@0: unsigned recurseDepth; michael@0: unsigned maxRecurseDepth; michael@0: double minExecutionTime; michael@0: double maxExecutionTime; michael@0: double totalExecutionTime; michael@0: double minOwnExecutionTime; michael@0: double maxOwnExecutionTime; michael@0: double totalOwnExecutionTime; michael@0: }; michael@0: michael@0: struct JSDSourceText michael@0: { michael@0: JSCList links; /* we are part of a JSCList */ michael@0: char* url; michael@0: char* text; michael@0: unsigned textLength; michael@0: unsigned textSpace; michael@0: bool dirty; michael@0: JSDSourceStatus status; michael@0: unsigned alterCount; michael@0: bool doingEval; michael@0: }; michael@0: michael@0: struct JSDExecHook michael@0: { michael@0: JSCList links; /* we are part of a JSCList */ michael@0: JSDScript* jsdscript; michael@0: uintptr_t pc; michael@0: JSD_ExecutionHookProc hook; michael@0: void* callerdata; michael@0: }; michael@0: michael@0: #define TS_HAS_DISABLED_FRAME 0x01 michael@0: michael@0: struct JSDThreadState michael@0: { michael@0: JSCList links; /* we are part of a JSCList */ michael@0: JSContext* context; michael@0: void* thread; michael@0: JSCList stack; michael@0: unsigned stackDepth; michael@0: unsigned flags; michael@0: }; michael@0: michael@0: struct JSDStackFrameInfo michael@0: { michael@0: JSCList links; /* we are part of a JSCList */ michael@0: JSDThreadState* jsdthreadstate; michael@0: JSDScript* jsdscript; michael@0: uintptr_t pc; michael@0: bool isConstructing; michael@0: JSAbstractFramePtr frame; michael@0: }; michael@0: michael@0: #define GOT_PROTO ((short) (1 << 0)) michael@0: #define GOT_PROPS ((short) (1 << 1)) michael@0: #define GOT_PARENT ((short) (1 << 2)) michael@0: #define GOT_CTOR ((short) (1 << 3)) michael@0: michael@0: struct JSDValue michael@0: { michael@0: JS::Heap val; michael@0: int nref; michael@0: JSCList props; michael@0: JS::Heap string; michael@0: JS::Heap funName; michael@0: const char* className; michael@0: JSDValue* proto; michael@0: JSDValue* parent; michael@0: JSDValue* ctor; michael@0: unsigned flags; michael@0: }; michael@0: michael@0: struct JSDProperty michael@0: { michael@0: JSCList links; /* we are part of a JSCList */ michael@0: int nref; michael@0: JSDValue* val; michael@0: JSDValue* name; michael@0: JSDValue* alias; michael@0: unsigned flags; michael@0: }; michael@0: michael@0: struct JSDAtom michael@0: { michael@0: char* str; /* must be first element in struct for compare */ michael@0: int refcount; michael@0: }; michael@0: michael@0: struct JSDObject michael@0: { michael@0: JSCList links; /* we are part of a JSCList */ michael@0: JSObject* obj; michael@0: JSDAtom* newURL; michael@0: unsigned newLineno; michael@0: JSDAtom* ctorURL; michael@0: unsigned ctorLineno; michael@0: JSDAtom* ctorName; michael@0: }; michael@0: michael@0: /***************************************************************************/ michael@0: /* Code validation support */ michael@0: michael@0: #ifdef DEBUG michael@0: extern void JSD_ASSERT_VALID_CONTEXT(JSDContext* jsdc); michael@0: extern void JSD_ASSERT_VALID_SCRIPT(JSDScript* jsdscript); michael@0: extern void JSD_ASSERT_VALID_SOURCE_TEXT(JSDSourceText* jsdsrc); michael@0: extern void JSD_ASSERT_VALID_THREAD_STATE(JSDThreadState* jsdthreadstate); michael@0: extern void JSD_ASSERT_VALID_STACK_FRAME(JSDStackFrameInfo* jsdframe); michael@0: extern void JSD_ASSERT_VALID_EXEC_HOOK(JSDExecHook* jsdhook); michael@0: extern void JSD_ASSERT_VALID_VALUE(JSDValue* jsdval); michael@0: extern void JSD_ASSERT_VALID_PROPERTY(JSDProperty* jsdprop); michael@0: extern void JSD_ASSERT_VALID_OBJECT(JSDObject* jsdobj); michael@0: #else michael@0: #define JSD_ASSERT_VALID_CONTEXT(x) ((void)0) michael@0: #define JSD_ASSERT_VALID_SCRIPT(x) ((void)0) michael@0: #define JSD_ASSERT_VALID_SOURCE_TEXT(x) ((void)0) michael@0: #define JSD_ASSERT_VALID_THREAD_STATE(x)((void)0) michael@0: #define JSD_ASSERT_VALID_STACK_FRAME(x) ((void)0) michael@0: #define JSD_ASSERT_VALID_EXEC_HOOK(x) ((void)0) michael@0: #define JSD_ASSERT_VALID_VALUE(x) ((void)0) michael@0: #define JSD_ASSERT_VALID_PROPERTY(x) ((void)0) michael@0: #define JSD_ASSERT_VALID_OBJECT(x) ((void)0) michael@0: #endif michael@0: michael@0: /***************************************************************************/ michael@0: /* higher level functions */ michael@0: michael@0: extern JSDContext* michael@0: jsd_DebuggerOnForUser(JSRuntime* jsrt, michael@0: JSD_UserCallbacks* callbacks, michael@0: void* user, michael@0: JSObject* scopeobj); michael@0: michael@0: extern JSDContext* michael@0: jsd_DebuggerOn(void); michael@0: michael@0: extern void michael@0: jsd_DebuggerOff(JSDContext* jsdc); michael@0: michael@0: extern void michael@0: jsd_DebuggerPause(JSDContext* jsdc, bool forceAllHooksOff); michael@0: michael@0: extern void michael@0: jsd_DebuggerUnpause(JSDContext* jsdc); michael@0: michael@0: extern void michael@0: jsd_SetUserCallbacks(JSRuntime* jsrt, JSD_UserCallbacks* callbacks, void* user); michael@0: michael@0: extern JSDContext* michael@0: jsd_JSDContextForJSContext(JSContext* context); michael@0: michael@0: extern void* michael@0: jsd_SetContextPrivate(JSDContext* jsdc, void *data); michael@0: michael@0: extern void* michael@0: jsd_GetContextPrivate(JSDContext* jsdc); michael@0: michael@0: extern void michael@0: jsd_ClearAllProfileData(JSDContext* jsdc); michael@0: michael@0: extern bool michael@0: jsd_SetErrorReporter(JSDContext* jsdc, michael@0: JSD_ErrorReporter reporter, michael@0: void* callerdata); michael@0: michael@0: extern bool michael@0: jsd_GetErrorReporter(JSDContext* jsdc, michael@0: JSD_ErrorReporter* reporter, michael@0: void** callerdata); michael@0: michael@0: /***************************************************************************/ michael@0: /* Script functions */ michael@0: michael@0: extern bool michael@0: jsd_InitScriptManager(JSDContext *jsdc); michael@0: michael@0: extern void michael@0: jsd_DestroyScriptManager(JSDContext* jsdc); michael@0: michael@0: extern JSDScript* michael@0: jsd_FindJSDScript(JSDContext* jsdc, michael@0: JSScript *script); michael@0: michael@0: extern JSDScript* michael@0: jsd_FindOrCreateJSDScript(JSDContext *jsdc, michael@0: JSContext *cx, michael@0: JSScript *script, michael@0: JSAbstractFramePtr frame); michael@0: michael@0: extern JSDProfileData* michael@0: jsd_GetScriptProfileData(JSDContext* jsdc, JSDScript *script); michael@0: michael@0: extern uint32_t michael@0: jsd_GetScriptFlags(JSDContext *jsdc, JSDScript *script); michael@0: michael@0: extern void michael@0: jsd_SetScriptFlags(JSDContext *jsdc, JSDScript *script, uint32_t flags); michael@0: michael@0: extern unsigned michael@0: jsd_GetScriptCallCount(JSDContext* jsdc, JSDScript *script); michael@0: michael@0: extern unsigned michael@0: jsd_GetScriptMaxRecurseDepth(JSDContext* jsdc, JSDScript *script); michael@0: michael@0: extern double michael@0: jsd_GetScriptMinExecutionTime(JSDContext* jsdc, JSDScript *script); michael@0: michael@0: extern double michael@0: jsd_GetScriptMaxExecutionTime(JSDContext* jsdc, JSDScript *script); michael@0: michael@0: extern double michael@0: jsd_GetScriptTotalExecutionTime(JSDContext* jsdc, JSDScript *script); michael@0: michael@0: extern double michael@0: jsd_GetScriptMinOwnExecutionTime(JSDContext* jsdc, JSDScript *script); michael@0: michael@0: extern double michael@0: jsd_GetScriptMaxOwnExecutionTime(JSDContext* jsdc, JSDScript *script); michael@0: michael@0: extern double michael@0: jsd_GetScriptTotalOwnExecutionTime(JSDContext* jsdc, JSDScript *script); michael@0: michael@0: extern void michael@0: jsd_ClearScriptProfileData(JSDContext* jsdc, JSDScript *script); michael@0: michael@0: extern JSScript * michael@0: jsd_GetJSScript (JSDContext *jsdc, JSDScript *script); michael@0: michael@0: extern JSFunction * michael@0: jsd_GetJSFunction (JSDContext *jsdc, JSDScript *script); michael@0: michael@0: extern JSDScript* michael@0: jsd_IterateScripts(JSDContext* jsdc, JSDScript **iterp); michael@0: michael@0: extern void * michael@0: jsd_SetScriptPrivate (JSDScript *jsdscript, void *data); michael@0: michael@0: extern void * michael@0: jsd_GetScriptPrivate (JSDScript *jsdscript); michael@0: michael@0: extern bool michael@0: jsd_IsActiveScript(JSDContext* jsdc, JSDScript *jsdscript); michael@0: michael@0: extern const char* michael@0: jsd_GetScriptFilename(JSDContext* jsdc, JSDScript *jsdscript); michael@0: michael@0: extern JSString* michael@0: jsd_GetScriptFunctionId(JSDContext* jsdc, JSDScript *jsdscript); michael@0: michael@0: extern unsigned michael@0: jsd_GetScriptBaseLineNumber(JSDContext* jsdc, JSDScript *jsdscript); michael@0: michael@0: extern unsigned michael@0: jsd_GetScriptLineExtent(JSDContext* jsdc, JSDScript *jsdscript); michael@0: michael@0: extern bool michael@0: jsd_SetScriptHook(JSDContext* jsdc, JSD_ScriptHookProc hook, void* callerdata); michael@0: michael@0: extern bool michael@0: jsd_GetScriptHook(JSDContext* jsdc, JSD_ScriptHookProc* hook, void** callerdata); michael@0: michael@0: extern uintptr_t michael@0: jsd_GetClosestPC(JSDContext* jsdc, JSDScript* jsdscript, unsigned line); michael@0: michael@0: extern unsigned michael@0: jsd_GetClosestLine(JSDContext* jsdc, JSDScript* jsdscript, uintptr_t pc); michael@0: michael@0: extern bool michael@0: jsd_GetLinePCs(JSDContext* jsdc, JSDScript* jsdscript, michael@0: unsigned startLine, unsigned maxLines, michael@0: unsigned* count, unsigned** lines, uintptr_t** pcs); michael@0: michael@0: extern void michael@0: jsd_NewScriptHookProc( michael@0: JSContext *cx, michael@0: const char *filename, /* URL this script loads from */ michael@0: unsigned lineno, /* line where this script starts */ michael@0: JSScript *script, michael@0: JSFunction *fun, michael@0: void* callerdata); michael@0: michael@0: extern void michael@0: jsd_DestroyScriptHookProc( michael@0: JSFreeOp *fop, michael@0: JSScript *script, michael@0: void* callerdata); michael@0: michael@0: /* Script execution hook functions */ michael@0: michael@0: extern bool michael@0: jsd_SetExecutionHook(JSDContext* jsdc, michael@0: JSDScript* jsdscript, michael@0: uintptr_t pc, michael@0: JSD_ExecutionHookProc hook, michael@0: void* callerdata); michael@0: michael@0: extern bool michael@0: jsd_ClearExecutionHook(JSDContext* jsdc, michael@0: JSDScript* jsdscript, michael@0: uintptr_t pc); michael@0: michael@0: extern bool michael@0: jsd_ClearAllExecutionHooksForScript(JSDContext* jsdc, JSDScript* jsdscript); michael@0: michael@0: extern bool michael@0: jsd_ClearAllExecutionHooks(JSDContext* jsdc); michael@0: michael@0: extern void michael@0: jsd_ScriptCreated(JSDContext* jsdc, michael@0: JSContext *cx, michael@0: const char *filename, /* URL this script loads from */ michael@0: unsigned lineno, /* line where this script starts */ michael@0: JSScript *script, michael@0: JSFunction *fun); michael@0: michael@0: extern void michael@0: jsd_ScriptDestroyed(JSDContext* jsdc, michael@0: JSFreeOp *fop, michael@0: JSScript *script); michael@0: michael@0: /***************************************************************************/ michael@0: /* Source Text functions */ michael@0: michael@0: extern JSDSourceText* michael@0: jsd_IterateSources(JSDContext* jsdc, JSDSourceText **iterp); michael@0: michael@0: extern JSDSourceText* michael@0: jsd_FindSourceForURL(JSDContext* jsdc, const char* url); michael@0: michael@0: extern const char* michael@0: jsd_GetSourceURL(JSDContext* jsdc, JSDSourceText* jsdsrc); michael@0: michael@0: extern bool michael@0: jsd_GetSourceText(JSDContext* jsdc, JSDSourceText* jsdsrc, michael@0: const char** ppBuf, int* pLen); michael@0: michael@0: extern void michael@0: jsd_ClearSourceText(JSDContext* jsdc, JSDSourceText* jsdsrc); michael@0: michael@0: extern JSDSourceStatus michael@0: jsd_GetSourceStatus(JSDContext* jsdc, JSDSourceText* jsdsrc); michael@0: michael@0: extern bool michael@0: jsd_IsSourceDirty(JSDContext* jsdc, JSDSourceText* jsdsrc); michael@0: michael@0: extern void michael@0: jsd_SetSourceDirty(JSDContext* jsdc, JSDSourceText* jsdsrc, bool dirty); michael@0: michael@0: extern unsigned michael@0: jsd_GetSourceAlterCount(JSDContext* jsdc, JSDSourceText* jsdsrc); michael@0: michael@0: extern unsigned michael@0: jsd_IncrementSourceAlterCount(JSDContext* jsdc, JSDSourceText* jsdsrc); michael@0: michael@0: extern JSDSourceText* michael@0: jsd_NewSourceText(JSDContext* jsdc, const char* url); michael@0: michael@0: extern JSDSourceText* michael@0: jsd_AppendSourceText(JSDContext* jsdc, michael@0: JSDSourceText* jsdsrc, michael@0: const char* text, /* *not* zero terminated */ michael@0: size_t length, michael@0: JSDSourceStatus status); michael@0: michael@0: extern JSDSourceText* michael@0: jsd_AppendUCSourceText(JSDContext* jsdc, michael@0: JSDSourceText* jsdsrc, michael@0: const jschar* text, /* *not* zero terminated */ michael@0: size_t length, michael@0: JSDSourceStatus status); michael@0: michael@0: /* convienence function for adding complete source of url in one call */ michael@0: extern bool michael@0: jsd_AddFullSourceText(JSDContext* jsdc, michael@0: const char* text, /* *not* zero terminated */ michael@0: size_t length, michael@0: const char* url); michael@0: michael@0: extern void michael@0: jsd_DestroyAllSources(JSDContext* jsdc); michael@0: michael@0: extern char* michael@0: jsd_BuildNormalizedURL(const char* url_string); michael@0: michael@0: extern void michael@0: jsd_StartingEvalUsingFilename(JSDContext* jsdc, const char* url); michael@0: michael@0: extern void michael@0: jsd_FinishedEvalUsingFilename(JSDContext* jsdc, const char* url); michael@0: michael@0: /***************************************************************************/ michael@0: /* Interrupt Hook functions */ michael@0: michael@0: extern bool michael@0: jsd_SetInterruptHook(JSDContext* jsdc, michael@0: JSD_ExecutionHookProc hook, michael@0: void* callerdata); michael@0: michael@0: extern bool michael@0: jsd_ClearInterruptHook(JSDContext* jsdc); michael@0: michael@0: extern bool michael@0: jsd_EnableSingleStepInterrupts(JSDContext* jsdc, michael@0: JSDScript* jsdscript, michael@0: bool enable); michael@0: michael@0: extern bool michael@0: jsd_SetDebugBreakHook(JSDContext* jsdc, michael@0: JSD_ExecutionHookProc hook, michael@0: void* callerdata); michael@0: michael@0: extern bool michael@0: jsd_ClearDebugBreakHook(JSDContext* jsdc); michael@0: michael@0: extern bool michael@0: jsd_SetDebuggerHook(JSDContext* jsdc, michael@0: JSD_ExecutionHookProc hook, michael@0: void* callerdata); michael@0: michael@0: extern bool michael@0: jsd_ClearDebuggerHook(JSDContext* jsdc); michael@0: michael@0: extern JSTrapStatus michael@0: jsd_CallExecutionHook(JSDContext* jsdc, michael@0: JSContext* cx, michael@0: unsigned type, michael@0: JSD_ExecutionHookProc hook, michael@0: void* hookData, michael@0: jsval* rval); michael@0: michael@0: extern bool michael@0: jsd_CallCallHook (JSDContext* jsdc, michael@0: JSContext* cx, michael@0: unsigned type, michael@0: JSD_CallHookProc hook, michael@0: void* hookData); michael@0: michael@0: extern bool michael@0: jsd_SetThrowHook(JSDContext* jsdc, michael@0: JSD_ExecutionHookProc hook, michael@0: void* callerdata); michael@0: extern bool michael@0: jsd_ClearThrowHook(JSDContext* jsdc); michael@0: michael@0: extern JSTrapStatus michael@0: jsd_DebuggerHandler(JSContext *cx, JSScript *script, jsbytecode *pc, michael@0: jsval *rval, void *closure); michael@0: michael@0: extern JSTrapStatus michael@0: jsd_ThrowHandler(JSContext *cx, JSScript *script, jsbytecode *pc, michael@0: jsval *rval, void *closure); michael@0: michael@0: extern bool michael@0: jsd_SetFunctionHook(JSDContext* jsdc, michael@0: JSD_CallHookProc hook, michael@0: void* callerdata); michael@0: michael@0: extern bool michael@0: jsd_ClearFunctionHook(JSDContext* jsdc); michael@0: michael@0: extern bool michael@0: jsd_SetTopLevelHook(JSDContext* jsdc, michael@0: JSD_CallHookProc hook, michael@0: void* callerdata); michael@0: michael@0: extern bool michael@0: jsd_ClearTopLevelHook(JSDContext* jsdc); michael@0: michael@0: /***************************************************************************/ michael@0: /* Stack Frame functions */ michael@0: michael@0: extern unsigned michael@0: jsd_GetCountOfStackFrames(JSDContext* jsdc, JSDThreadState* jsdthreadstate); michael@0: michael@0: extern JSDStackFrameInfo* michael@0: jsd_GetStackFrame(JSDContext* jsdc, JSDThreadState* jsdthreadstate); michael@0: michael@0: extern JSContext* michael@0: jsd_GetJSContext(JSDContext* jsdc, JSDThreadState* jsdthreadstate); michael@0: michael@0: extern JSDStackFrameInfo* michael@0: jsd_GetCallingStackFrame(JSDContext* jsdc, michael@0: JSDThreadState* jsdthreadstate, michael@0: JSDStackFrameInfo* jsdframe); michael@0: michael@0: extern JSDScript* michael@0: jsd_GetScriptForStackFrame(JSDContext* jsdc, michael@0: JSDThreadState* jsdthreadstate, michael@0: JSDStackFrameInfo* jsdframe); michael@0: michael@0: extern uintptr_t michael@0: jsd_GetPCForStackFrame(JSDContext* jsdc, michael@0: JSDThreadState* jsdthreadstate, michael@0: JSDStackFrameInfo* jsdframe); michael@0: michael@0: extern JSDValue* michael@0: jsd_GetCallObjectForStackFrame(JSDContext* jsdc, michael@0: JSDThreadState* jsdthreadstate, michael@0: JSDStackFrameInfo* jsdframe); michael@0: michael@0: extern JSDValue* michael@0: jsd_GetScopeChainForStackFrame(JSDContext* jsdc, michael@0: JSDThreadState* jsdthreadstate, michael@0: JSDStackFrameInfo* jsdframe); michael@0: michael@0: extern bool michael@0: jsd_IsStackFrameDebugger(JSDContext* jsdc, michael@0: JSDThreadState* jsdthreadstate, michael@0: JSDStackFrameInfo* jsdframe); michael@0: michael@0: extern bool michael@0: jsd_IsStackFrameConstructing(JSDContext* jsdc, michael@0: JSDThreadState* jsdthreadstate, michael@0: JSDStackFrameInfo* jsdframe); michael@0: michael@0: extern JSDValue* michael@0: jsd_GetThisForStackFrame(JSDContext* jsdc, michael@0: JSDThreadState* jsdthreadstate, michael@0: JSDStackFrameInfo* jsdframe); michael@0: michael@0: extern JSString* michael@0: jsd_GetIdForStackFrame(JSDContext* jsdc, michael@0: JSDThreadState* jsdthreadstate, michael@0: JSDStackFrameInfo* jsdframe); michael@0: michael@0: extern JSDThreadState* michael@0: jsd_NewThreadState(JSDContext* jsdc, JSContext *cx); michael@0: michael@0: extern void michael@0: jsd_DestroyThreadState(JSDContext* jsdc, JSDThreadState* jsdthreadstate); michael@0: michael@0: extern bool michael@0: jsd_EvaluateUCScriptInStackFrame(JSDContext* jsdc, michael@0: JSDThreadState* jsdthreadstate, michael@0: JSDStackFrameInfo* jsdframe, michael@0: const jschar *bytes, unsigned length, michael@0: const char *filename, unsigned lineno, michael@0: bool eatExceptions, JS::MutableHandleValue rval); michael@0: michael@0: extern bool michael@0: jsd_EvaluateScriptInStackFrame(JSDContext* jsdc, michael@0: JSDThreadState* jsdthreadstate, michael@0: JSDStackFrameInfo* jsdframe, michael@0: const char *bytes, unsigned length, michael@0: const char *filename, unsigned lineno, michael@0: bool eatExceptions, JS::MutableHandleValue rval); michael@0: michael@0: extern JSString* michael@0: jsd_ValToStringInStackFrame(JSDContext* jsdc, michael@0: JSDThreadState* jsdthreadstate, michael@0: JSDStackFrameInfo* jsdframe, michael@0: jsval val); michael@0: michael@0: extern bool michael@0: jsd_IsValidThreadState(JSDContext* jsdc, michael@0: JSDThreadState* jsdthreadstate); michael@0: michael@0: extern bool michael@0: jsd_IsValidFrameInThreadState(JSDContext* jsdc, michael@0: JSDThreadState* jsdthreadstate, michael@0: JSDStackFrameInfo* jsdframe); michael@0: michael@0: extern JSDValue* michael@0: jsd_GetException(JSDContext* jsdc, JSDThreadState* jsdthreadstate); michael@0: michael@0: extern bool michael@0: jsd_SetException(JSDContext* jsdc, JSDThreadState* jsdthreadstate, michael@0: JSDValue* jsdval); michael@0: michael@0: /***************************************************************************/ michael@0: /* Locking support */ michael@0: michael@0: /* protos are in js_lock.h for: michael@0: * jsd_CreateLock michael@0: * jsd_Lock michael@0: * jsd_Unlock michael@0: * jsd_IsLocked michael@0: * jsd_CurrentThread michael@0: */ michael@0: michael@0: #ifdef JSD_THREADSAFE michael@0: michael@0: /* the system-wide lock */ michael@0: extern JSDStaticLock* _jsd_global_lock; michael@0: #define JSD_LOCK() \ michael@0: JS_BEGIN_MACRO \ michael@0: if(!_jsd_global_lock) \ michael@0: _jsd_global_lock = jsd_CreateLock(); \ michael@0: MOZ_ASSERT(_jsd_global_lock); \ michael@0: jsd_Lock(_jsd_global_lock); \ michael@0: JS_END_MACRO michael@0: michael@0: #define JSD_UNLOCK() \ michael@0: JS_BEGIN_MACRO \ michael@0: MOZ_ASSERT(_jsd_global_lock); \ michael@0: jsd_Unlock(_jsd_global_lock); \ michael@0: JS_END_MACRO michael@0: michael@0: /* locks for the subsystems of a given context */ michael@0: #define JSD_INIT_LOCKS(jsdc) \ michael@0: ( (nullptr != (jsdc->scriptsLock = jsd_CreateLock())) && \ michael@0: (nullptr != (jsdc->sourceTextLock = jsd_CreateLock())) && \ michael@0: (nullptr != (jsdc->atomsLock = jsd_CreateLock())) && \ michael@0: (nullptr != (jsdc->objectsLock = jsd_CreateLock())) && \ michael@0: (nullptr != (jsdc->threadStatesLock = jsd_CreateLock())) ) michael@0: michael@0: #define JSD_LOCK_SCRIPTS(jsdc) jsd_Lock(jsdc->scriptsLock) michael@0: #define JSD_UNLOCK_SCRIPTS(jsdc) jsd_Unlock(jsdc->scriptsLock) michael@0: michael@0: #define JSD_LOCK_SOURCE_TEXT(jsdc) jsd_Lock(jsdc->sourceTextLock) michael@0: #define JSD_UNLOCK_SOURCE_TEXT(jsdc) jsd_Unlock(jsdc->sourceTextLock) michael@0: michael@0: #define JSD_LOCK_ATOMS(jsdc) jsd_Lock(jsdc->atomsLock) michael@0: #define JSD_UNLOCK_ATOMS(jsdc) jsd_Unlock(jsdc->atomsLock) michael@0: michael@0: #define JSD_LOCK_OBJECTS(jsdc) jsd_Lock(jsdc->objectsLock) michael@0: #define JSD_UNLOCK_OBJECTS(jsdc) jsd_Unlock(jsdc->objectsLock) michael@0: michael@0: #define JSD_LOCK_THREADSTATES(jsdc) jsd_Lock(jsdc->threadStatesLock) michael@0: #define JSD_UNLOCK_THREADSTATES(jsdc) jsd_Unlock(jsdc->threadStatesLock) michael@0: michael@0: #else /* !JSD_THREADSAFE */ michael@0: michael@0: #define JSD_LOCK() ((void)0) michael@0: #define JSD_UNLOCK() ((void)0) michael@0: michael@0: #define JSD_INIT_LOCKS(jsdc) 1 michael@0: michael@0: #define JSD_LOCK_SCRIPTS(jsdc) ((void)0) michael@0: #define JSD_UNLOCK_SCRIPTS(jsdc) ((void)0) michael@0: michael@0: #define JSD_LOCK_SOURCE_TEXT(jsdc) ((void)0) michael@0: #define JSD_UNLOCK_SOURCE_TEXT(jsdc) ((void)0) michael@0: michael@0: #define JSD_LOCK_ATOMS(jsdc) ((void)0) michael@0: #define JSD_UNLOCK_ATOMS(jsdc) ((void)0) michael@0: michael@0: #define JSD_LOCK_OBJECTS(jsdc) ((void)0) michael@0: #define JSD_UNLOCK_OBJECTS(jsdc) ((void)0) michael@0: michael@0: #define JSD_LOCK_THREADSTATES(jsdc) ((void)0) michael@0: #define JSD_UNLOCK_THREADSTATES(jsdc) ((void)0) michael@0: michael@0: #endif /* JSD_THREADSAFE */ michael@0: michael@0: /* NOTE: These are intended for ASSERTs. Thus we supply checks for both michael@0: * LOCKED and UNLOCKED (rather that just LOCKED and !LOCKED) so that in michael@0: * the DEBUG non-Threadsafe case we can have an ASSERT that always succeeds michael@0: * without having to special case things in the code. michael@0: */ michael@0: #if defined(JSD_THREADSAFE) && defined(DEBUG) michael@0: #define JSD_SCRIPTS_LOCKED(jsdc) (jsd_IsLocked(jsdc->scriptsLock)) michael@0: #define JSD_SOURCE_TEXT_LOCKED(jsdc) (jsd_IsLocked(jsdc->sourceTextLock)) michael@0: #define JSD_ATOMS_LOCKED(jsdc) (jsd_IsLocked(jsdc->atomsLock)) michael@0: #define JSD_OBJECTS_LOCKED(jsdc) (jsd_IsLocked(jsdc->objectsLock)) michael@0: #define JSD_THREADSTATES_LOCKED(jsdc) (jsd_IsLocked(jsdc->threadStatesLock)) michael@0: #define JSD_SCRIPTS_UNLOCKED(jsdc) (!jsd_IsLocked(jsdc->scriptsLock)) michael@0: #define JSD_SOURCE_TEXT_UNLOCKED(jsdc) (!jsd_IsLocked(jsdc->sourceTextLock)) michael@0: #define JSD_ATOMS_UNLOCKED(jsdc) (!jsd_IsLocked(jsdc->atomsLock)) michael@0: #define JSD_OBJECTS_UNLOCKED(jsdc) (!jsd_IsLocked(jsdc->objectsLock)) michael@0: #define JSD_THREADSTATES_UNLOCKED(jsdc) (!jsd_IsLocked(jsdc->threadStatesLock)) michael@0: #else michael@0: #define JSD_SCRIPTS_LOCKED(jsdc) 1 michael@0: #define JSD_SOURCE_TEXT_LOCKED(jsdc) 1 michael@0: #define JSD_ATOMS_LOCKED(jsdc) 1 michael@0: #define JSD_OBJECTS_LOCKED(jsdc) 1 michael@0: #define JSD_THREADSTATES_LOCKED(jsdc) 1 michael@0: #define JSD_SCRIPTS_UNLOCKED(jsdc) 1 michael@0: #define JSD_SOURCE_TEXT_UNLOCKED(jsdc) 1 michael@0: #define JSD_ATOMS_UNLOCKED(jsdc) 1 michael@0: #define JSD_OBJECTS_UNLOCKED(jsdc) 1 michael@0: #define JSD_THREADSTATES_UNLOCKED(jsdc) 1 michael@0: #endif /* defined(JSD_THREADSAFE) && defined(DEBUG) */ michael@0: michael@0: /***************************************************************************/ michael@0: /* Threading support */ michael@0: michael@0: #ifdef JSD_THREADSAFE michael@0: michael@0: #define JSD_CURRENT_THREAD() jsd_CurrentThread() michael@0: michael@0: #else /* !JSD_THREADSAFE */ michael@0: michael@0: #define JSD_CURRENT_THREAD() ((void*)0) michael@0: michael@0: #endif /* JSD_THREADSAFE */ michael@0: michael@0: /***************************************************************************/ michael@0: /* Dangerous thread support */ michael@0: michael@0: #ifdef JSD_HAS_DANGEROUS_THREAD michael@0: michael@0: #define JSD_IS_DANGEROUS_THREAD(jsdc) \ michael@0: (JSD_CURRENT_THREAD() == jsdc->dangerousThread) michael@0: michael@0: #else /* !JSD_HAS_DANGEROUS_THREAD */ michael@0: michael@0: #define JSD_IS_DANGEROUS_THREAD(jsdc) 0 michael@0: michael@0: #endif /* JSD_HAS_DANGEROUS_THREAD */ michael@0: michael@0: /***************************************************************************/ michael@0: /* Value and Property Functions */ michael@0: michael@0: extern JSDValue* michael@0: jsd_NewValue(JSDContext* jsdc, jsval val); michael@0: michael@0: extern void michael@0: jsd_DropValue(JSDContext* jsdc, JSDValue* jsdval); michael@0: michael@0: extern jsval michael@0: jsd_GetValueWrappedJSVal(JSDContext* jsdc, JSDValue* jsdval); michael@0: michael@0: extern void michael@0: jsd_RefreshValue(JSDContext* jsdc, JSDValue* jsdval); michael@0: michael@0: /**************************************************/ michael@0: michael@0: extern bool michael@0: jsd_IsValueObject(JSDContext* jsdc, JSDValue* jsdval); michael@0: michael@0: extern bool michael@0: jsd_IsValueNumber(JSDContext* jsdc, JSDValue* jsdval); michael@0: michael@0: extern bool michael@0: jsd_IsValueInt(JSDContext* jsdc, JSDValue* jsdval); michael@0: michael@0: extern bool michael@0: jsd_IsValueDouble(JSDContext* jsdc, JSDValue* jsdval); michael@0: michael@0: extern bool michael@0: jsd_IsValueString(JSDContext* jsdc, JSDValue* jsdval); michael@0: michael@0: extern bool michael@0: jsd_IsValueBoolean(JSDContext* jsdc, JSDValue* jsdval); michael@0: michael@0: extern bool michael@0: jsd_IsValueNull(JSDContext* jsdc, JSDValue* jsdval); michael@0: michael@0: extern bool michael@0: jsd_IsValueVoid(JSDContext* jsdc, JSDValue* jsdval); michael@0: michael@0: extern bool michael@0: jsd_IsValuePrimitive(JSDContext* jsdc, JSDValue* jsdval); michael@0: michael@0: extern bool michael@0: jsd_IsValueFunction(JSDContext* jsdc, JSDValue* jsdval); michael@0: michael@0: extern bool michael@0: jsd_IsValueNative(JSDContext* jsdc, JSDValue* jsdval); michael@0: michael@0: /**************************************************/ michael@0: michael@0: extern bool michael@0: jsd_GetValueBoolean(JSDContext* jsdc, JSDValue* jsdval); michael@0: michael@0: extern int32_t michael@0: jsd_GetValueInt(JSDContext* jsdc, JSDValue* jsdval); michael@0: michael@0: extern double michael@0: jsd_GetValueDouble(JSDContext* jsdc, JSDValue* jsdval); michael@0: michael@0: extern JSString* michael@0: jsd_GetValueString(JSDContext* jsdc, JSDValue* jsdval); michael@0: michael@0: extern JSString* michael@0: jsd_GetValueFunctionId(JSDContext* jsdc, JSDValue* jsdval); michael@0: michael@0: extern JSFunction* michael@0: jsd_GetValueFunction(JSDContext* jsdc, JSDValue* jsdval); michael@0: michael@0: /**************************************************/ michael@0: michael@0: extern unsigned michael@0: jsd_GetCountOfProperties(JSDContext* jsdc, JSDValue* jsdval); michael@0: michael@0: extern JSDProperty* michael@0: jsd_IterateProperties(JSDContext* jsdc, JSDValue* jsdval, JSDProperty **iterp); michael@0: michael@0: extern JSDProperty* michael@0: jsd_GetValueProperty(JSDContext* jsdc, JSDValue* jsdval, JSString* name); michael@0: michael@0: extern JSDValue* michael@0: jsd_GetValuePrototype(JSDContext* jsdc, JSDValue* jsdval); michael@0: michael@0: extern JSDValue* michael@0: jsd_GetValueParent(JSDContext* jsdc, JSDValue* jsdval); michael@0: michael@0: extern JSDValue* michael@0: jsd_GetValueConstructor(JSDContext* jsdc, JSDValue* jsdval); michael@0: michael@0: extern const char* michael@0: jsd_GetValueClassName(JSDContext* jsdc, JSDValue* jsdval); michael@0: michael@0: extern JSDScript* michael@0: jsd_GetScriptForValue(JSDContext* jsdc, JSDValue* jsdval); michael@0: michael@0: /**************************************************/ michael@0: michael@0: extern void michael@0: jsd_DropProperty(JSDContext* jsdc, JSDProperty* jsdprop); michael@0: michael@0: extern JSDValue* michael@0: jsd_GetPropertyName(JSDContext* jsdc, JSDProperty* jsdprop); michael@0: michael@0: extern JSDValue* michael@0: jsd_GetPropertyValue(JSDContext* jsdc, JSDProperty* jsdprop); michael@0: michael@0: extern JSDValue* michael@0: jsd_GetPropertyAlias(JSDContext* jsdc, JSDProperty* jsdprop); michael@0: michael@0: extern unsigned michael@0: jsd_GetPropertyFlags(JSDContext* jsdc, JSDProperty* jsdprop); michael@0: michael@0: /**************************************************/ michael@0: /* Stepping Functions */ michael@0: michael@0: extern void * michael@0: jsd_FunctionCallHook(JSContext *cx, JSAbstractFramePtr frame, bool isConstructing, michael@0: bool before, bool *ok, void *closure); michael@0: michael@0: extern void * michael@0: jsd_TopLevelCallHook(JSContext *cx, JSAbstractFramePtr frame, bool isConstructing, michael@0: bool before, bool *ok, void *closure); michael@0: michael@0: /**************************************************/ michael@0: /* Object Functions */ michael@0: michael@0: extern bool michael@0: jsd_InitObjectManager(JSDContext* jsdc); michael@0: michael@0: extern void michael@0: jsd_DestroyObjectManager(JSDContext* jsdc); michael@0: michael@0: extern void michael@0: jsd_DestroyObjects(JSDContext* jsdc); michael@0: michael@0: extern void michael@0: jsd_Constructing(JSDContext* jsdc, JSContext *cx, JSObject *obj, michael@0: JSAbstractFramePtr frame); michael@0: michael@0: extern JSDObject* michael@0: jsd_IterateObjects(JSDContext* jsdc, JSDObject** iterp); michael@0: michael@0: extern JSObject* michael@0: jsd_GetWrappedObject(JSDContext* jsdc, JSDObject* jsdobj); michael@0: michael@0: extern const char* michael@0: jsd_GetObjectNewURL(JSDContext* jsdc, JSDObject* jsdobj); michael@0: michael@0: extern unsigned michael@0: jsd_GetObjectNewLineNumber(JSDContext* jsdc, JSDObject* jsdobj); michael@0: michael@0: extern const char* michael@0: jsd_GetObjectConstructorURL(JSDContext* jsdc, JSDObject* jsdobj); michael@0: michael@0: extern unsigned michael@0: jsd_GetObjectConstructorLineNumber(JSDContext* jsdc, JSDObject* jsdobj); michael@0: michael@0: extern const char* michael@0: jsd_GetObjectConstructorName(JSDContext* jsdc, JSDObject* jsdobj); michael@0: michael@0: extern JSDObject* michael@0: jsd_GetJSDObjectForJSObject(JSDContext* jsdc, JSObject* jsobj); michael@0: michael@0: extern JSDObject* michael@0: jsd_GetObjectForValue(JSDContext* jsdc, JSDValue* jsdval); michael@0: michael@0: /* michael@0: * returns new refcounted JSDValue michael@0: */ michael@0: extern JSDValue* michael@0: jsd_GetValueForObject(JSDContext* jsdc, JSDObject* jsdobj); michael@0: michael@0: /**************************************************/ michael@0: /* Atom Functions */ michael@0: michael@0: extern bool michael@0: jsd_CreateAtomTable(JSDContext* jsdc); michael@0: michael@0: extern void michael@0: jsd_DestroyAtomTable(JSDContext* jsdc); michael@0: michael@0: extern JSDAtom* michael@0: jsd_AddAtom(JSDContext* jsdc, const char* str); michael@0: michael@0: extern JSDAtom* michael@0: jsd_CloneAtom(JSDContext* jsdc, JSDAtom* atom); michael@0: michael@0: extern void michael@0: jsd_DropAtom(JSDContext* jsdc, JSDAtom* atom); michael@0: michael@0: #define JSD_ATOM_TO_STRING(a) ((const char*)((a)->str)) michael@0: michael@0: struct AutoSaveExceptionState { michael@0: AutoSaveExceptionState(JSContext *cx) : mCx(cx) { michael@0: mState = JS_SaveExceptionState(cx); michael@0: } michael@0: ~AutoSaveExceptionState() { michael@0: JS_RestoreExceptionState(mCx, mState); michael@0: } michael@0: JSContext *mCx; michael@0: JSExceptionState *mState; michael@0: }; michael@0: michael@0: #endif /* jsd_h___ */