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: #ifndef JSDSERVICE_H___ michael@0: #define JSDSERVICE_H___ michael@0: michael@0: #include "jsdIDebuggerService.h" michael@0: #include "jsdebug.h" michael@0: #include "nsString.h" michael@0: #include "nsCOMPtr.h" michael@0: #include "nspr.h" michael@0: #include "nsCycleCollectionParticipant.h" michael@0: #include "mozilla/Attributes.h" michael@0: michael@0: // #if defined(DEBUG_rginda_l) michael@0: // # define DEBUG_verbose michael@0: // #endif michael@0: michael@0: struct LiveEphemeral { michael@0: /* link in a chain of live values list */ michael@0: PRCList links; michael@0: jsdIEphemeral *value; michael@0: void *key; michael@0: }; michael@0: michael@0: struct PCMapEntry { michael@0: uint32_t pc, line; michael@0: }; michael@0: michael@0: /******************************************************************************* michael@0: * reflected jsd data structures michael@0: *******************************************************************************/ michael@0: michael@0: class jsdObject MOZ_FINAL : public jsdIObject michael@0: { michael@0: public: michael@0: NS_DECL_THREADSAFE_ISUPPORTS michael@0: NS_DECL_JSDIOBJECT michael@0: michael@0: /* you'll normally use use FromPtr() instead of directly constructing one */ michael@0: jsdObject (JSDContext *aCx, JSDObject *aObject) : michael@0: mCx(aCx), mObject(aObject) michael@0: { michael@0: } michael@0: michael@0: static jsdIObject *FromPtr (JSDContext *aCx, michael@0: JSDObject *aObject) michael@0: { michael@0: if (!aObject) michael@0: return nullptr; michael@0: michael@0: jsdIObject *rv = new jsdObject (aCx, aObject); michael@0: NS_IF_ADDREF(rv); michael@0: return rv; michael@0: } michael@0: michael@0: private: michael@0: jsdObject(); /* no implementation */ michael@0: jsdObject(const jsdObject&); /* no implementation */ michael@0: michael@0: JSDContext *mCx; michael@0: JSDObject *mObject; michael@0: }; michael@0: michael@0: michael@0: class jsdProperty : public jsdIProperty michael@0: { michael@0: public: michael@0: NS_DECL_THREADSAFE_ISUPPORTS michael@0: NS_DECL_JSDIPROPERTY michael@0: NS_DECL_JSDIEPHEMERAL michael@0: michael@0: jsdProperty (JSDContext *aCx, JSDProperty *aProperty); michael@0: virtual ~jsdProperty (); michael@0: michael@0: static jsdIProperty *FromPtr (JSDContext *aCx, michael@0: JSDProperty *aProperty) michael@0: { michael@0: if (!aProperty) michael@0: return nullptr; michael@0: michael@0: jsdIProperty *rv = new jsdProperty (aCx, aProperty); michael@0: NS_IF_ADDREF(rv); michael@0: return rv; michael@0: } michael@0: michael@0: static void InvalidateAll(); michael@0: michael@0: private: michael@0: jsdProperty(); /* no implementation */ michael@0: jsdProperty(const jsdProperty&); /* no implementation */ michael@0: michael@0: bool mValid; michael@0: LiveEphemeral mLiveListEntry; michael@0: JSDContext *mCx; michael@0: JSDProperty *mProperty; michael@0: }; michael@0: michael@0: class jsdScript : public jsdIScript michael@0: { michael@0: public: michael@0: NS_DECL_THREADSAFE_ISUPPORTS michael@0: NS_DECL_JSDISCRIPT michael@0: NS_DECL_JSDIEPHEMERAL michael@0: michael@0: /* you'll normally use use FromPtr() instead of directly constructing one */ michael@0: jsdScript (JSDContext *aCx, JSDScript *aScript); michael@0: virtual ~jsdScript(); michael@0: michael@0: static jsdIScript *FromPtr (JSDContext *aCx, JSDScript *aScript) michael@0: { michael@0: if (!aScript) michael@0: return nullptr; michael@0: michael@0: void *data = JSD_GetScriptPrivate (aScript); michael@0: jsdIScript *rv; michael@0: michael@0: if (data) { michael@0: rv = static_cast(data); michael@0: } else { michael@0: rv = new jsdScript (aCx, aScript); michael@0: NS_IF_ADDREF(rv); /* addref for the SetScriptPrivate, released in michael@0: * Invalidate() */ michael@0: JSD_SetScriptPrivate (aScript, static_cast(rv)); michael@0: } michael@0: michael@0: NS_IF_ADDREF(rv); /* addref for return value */ michael@0: return rv; michael@0: } michael@0: michael@0: static void InvalidateAll(); michael@0: michael@0: private: michael@0: static uint32_t LastTag; michael@0: michael@0: jsdScript(); /* no implementation */ michael@0: jsdScript (const jsdScript&); /* no implementation */ michael@0: PCMapEntry* CreatePPLineMap(); michael@0: uint32_t PPPcToLine(uint32_t aPC); michael@0: uint32_t PPLineToPc(uint32_t aLine); michael@0: michael@0: bool mValid; michael@0: uint32_t mTag; michael@0: JSDContext *mCx; michael@0: JSDScript *mScript; michael@0: nsCString *mFileName; michael@0: nsCString *mFunctionName; michael@0: uint32_t mBaseLineNumber, mLineExtent; michael@0: PCMapEntry *mPPLineMap; michael@0: uint32_t mPCMapSize; michael@0: uintptr_t mFirstPC; michael@0: }; michael@0: michael@0: uint32_t jsdScript::LastTag = 0; michael@0: michael@0: class jsdContext : public jsdIContext michael@0: { michael@0: public: michael@0: NS_DECL_THREADSAFE_ISUPPORTS michael@0: NS_DECL_JSDICONTEXT michael@0: NS_DECL_JSDIEPHEMERAL michael@0: michael@0: jsdContext (JSDContext *aJSDCx, JSContext *aJSCx, nsISupports *aISCx); michael@0: virtual ~jsdContext(); michael@0: michael@0: static void InvalidateAll(); michael@0: static jsdIContext *FromPtr (JSDContext *aJSDCx, JSContext *aJSCx); michael@0: private: michael@0: static uint32_t LastTag; michael@0: michael@0: jsdContext (); /* no implementation */ michael@0: jsdContext (const jsdContext&); /* no implementation */ michael@0: michael@0: bool mValid; michael@0: // The API exposed by JSD here is problematic, because it allows for per- michael@0: // JSContext script disabling, which no longer exists in the platform. michael@0: // The only consumer here in practice is Firebug, which makes sure to re- michael@0: // enable any disabled script before navigation. But if some other consumer michael@0: // were to disable script, navigate, and try to re-enable it, we'd end up michael@0: // with an unmatched UnblockScript call, which violates platform invariants. michael@0: // So we make a half-hearted attempt to detect this by storing the Window ID michael@0: // of the scope for which we disabled script. michael@0: uint64_t mScriptDisabledForWindowWithID; michael@0: bool IsScriptEnabled() { return !mScriptDisabledForWindowWithID; } michael@0: LiveEphemeral mLiveListEntry; michael@0: uint32_t mTag; michael@0: JSDContext *mJSDCx; michael@0: JSContext *mJSCx; michael@0: nsCOMPtr mISCx; michael@0: }; michael@0: michael@0: uint32_t jsdContext::LastTag = 0; michael@0: michael@0: class jsdStackFrame : public jsdIStackFrame michael@0: { michael@0: public: michael@0: NS_DECL_THREADSAFE_ISUPPORTS michael@0: NS_DECL_JSDISTACKFRAME michael@0: NS_DECL_JSDIEPHEMERAL michael@0: michael@0: /* you'll normally use use FromPtr() instead of directly constructing one */ michael@0: jsdStackFrame (JSDContext *aCx, JSDThreadState *aThreadState, michael@0: JSDStackFrameInfo *aStackFrameInfo); michael@0: virtual ~jsdStackFrame(); michael@0: michael@0: static void InvalidateAll(); michael@0: static jsdIStackFrame* FromPtr (JSDContext *aCx, michael@0: JSDThreadState *aThreadState, michael@0: JSDStackFrameInfo *aStackFrameInfo); michael@0: michael@0: private: michael@0: jsdStackFrame(); /* no implementation */ michael@0: jsdStackFrame(const jsdStackFrame&); /* no implementation */ michael@0: michael@0: bool mValid; michael@0: LiveEphemeral mLiveListEntry; michael@0: JSDContext *mCx; michael@0: JSDThreadState *mThreadState; michael@0: JSDStackFrameInfo *mStackFrameInfo; michael@0: }; michael@0: michael@0: class jsdValue : public jsdIValue michael@0: { michael@0: public: michael@0: NS_DECL_THREADSAFE_ISUPPORTS michael@0: NS_DECL_JSDIVALUE michael@0: NS_DECL_JSDIEPHEMERAL michael@0: michael@0: /* you'll normally use use FromPtr() instead of directly constructing one */ michael@0: jsdValue (JSDContext *aCx, JSDValue *aValue); michael@0: virtual ~jsdValue(); michael@0: michael@0: static jsdIValue *FromPtr (JSDContext *aCx, JSDValue *aValue); michael@0: static void InvalidateAll(); michael@0: michael@0: private: michael@0: jsdValue(); /* no implementation */ michael@0: jsdValue (const jsdScript&); /* no implementation */ michael@0: michael@0: bool mValid; michael@0: LiveEphemeral mLiveListEntry; michael@0: JSDContext *mCx; michael@0: JSDValue *mValue; michael@0: }; michael@0: michael@0: /****************************************************************************** michael@0: * debugger service michael@0: ******************************************************************************/ michael@0: michael@0: class jsdService : public jsdIDebuggerService michael@0: { michael@0: public: michael@0: NS_DECL_CYCLE_COLLECTING_ISUPPORTS michael@0: NS_DECL_JSDIDEBUGGERSERVICE michael@0: michael@0: NS_DECL_CYCLE_COLLECTION_CLASS(jsdService) michael@0: michael@0: jsdService() : mOn(false), mPauseLevel(0), michael@0: mNestedLoopLevel(0), mCx(0), mRuntime(0), mErrorHook(0), michael@0: mBreakpointHook(0), mDebugHook(0), mDebuggerHook(0), michael@0: mInterruptHook(0), mScriptHook(0), mThrowHook(0), michael@0: mTopLevelHook(0), mFunctionHook(0), michael@0: mWarnedAboutDeprecation(false), michael@0: mDeprecationAcknowledged(false) michael@0: { michael@0: } michael@0: michael@0: virtual ~jsdService(); michael@0: michael@0: static jsdService *GetService (); michael@0: michael@0: bool CheckInterruptHook() { return !!mInterruptHook; } michael@0: michael@0: nsresult DoPause(uint32_t *_rval, bool internalCall); michael@0: nsresult DoUnPause(uint32_t *_rval, bool internalCall); michael@0: michael@0: private: michael@0: bool mOn; michael@0: uint32_t mPauseLevel; michael@0: uint32_t mNestedLoopLevel; michael@0: JSDContext *mCx; michael@0: JSRuntime *mRuntime; michael@0: michael@0: nsCOMPtr mErrorHook; michael@0: nsCOMPtr mBreakpointHook; michael@0: nsCOMPtr mDebugHook; michael@0: nsCOMPtr mDebuggerHook; michael@0: nsCOMPtr mInterruptHook; michael@0: nsCOMPtr mScriptHook; michael@0: nsCOMPtr mThrowHook; michael@0: nsCOMPtr mTopLevelHook; michael@0: nsCOMPtr mFunctionHook; michael@0: nsCOMPtr mActivationCallback; michael@0: michael@0: // True if we have ever printed a warning about JSD being deprecated. michael@0: // We only ever print the warning once. michael@0: bool mWarnedAboutDeprecation; michael@0: michael@0: // True if the next call to asyncOn should not produce a warning, michael@0: // because the consumer called jsdIDebuggerService::acknowledgeDeprecation. michael@0: bool mDeprecationAcknowledged; michael@0: }; michael@0: michael@0: #endif /* JSDSERVICE_H___ */ michael@0: michael@0: michael@0: /* graveyard */ michael@0: michael@0: #if 0 michael@0: michael@0: class jsdContext : public jsdIContext michael@0: { michael@0: public: michael@0: NS_DECL_THREADSAFE_ISUPPORTS michael@0: NS_DECL_JSDICONTEXT michael@0: michael@0: /* you'll normally use use FromPtr() instead of directly constructing one */ michael@0: jsdContext (JSDContext *aCx) : mCx(aCx) michael@0: { michael@0: printf ("++++++ jsdContext\n"); michael@0: } michael@0: michael@0: static jsdIContext *FromPtr (JSDContext *aCx) michael@0: { michael@0: if (!aCx) michael@0: return nullptr; michael@0: michael@0: void *data = JSD_GetContextPrivate (aCx); michael@0: jsdIContext *rv; michael@0: michael@0: if (data) { michael@0: rv = static_cast(data); michael@0: } else { michael@0: rv = new jsdContext (aCx); michael@0: NS_IF_ADDREF(rv); // addref for the SetContextPrivate michael@0: JSD_SetContextPrivate (aCx, static_cast(rv)); michael@0: } michael@0: michael@0: NS_IF_ADDREF(rv); // addref for the return value michael@0: return rv; michael@0: } michael@0: michael@0: virtual ~jsdContext() { printf ("------ ~jsdContext\n"); } michael@0: private: michael@0: jsdContext(); /* no implementation */ michael@0: jsdContext(const jsdContext&); /* no implementation */ michael@0: michael@0: JSDContext *mCx; michael@0: }; michael@0: michael@0: class jsdThreadState : public jsdIThreadState michael@0: { michael@0: public: michael@0: NS_DECL_THREADSAFE_ISUPPORTS michael@0: NS_DECL_JSDITHREADSTATE michael@0: michael@0: /* you'll normally use use FromPtr() instead of directly constructing one */ michael@0: jsdThreadState (JSDContext *aCx, JSDThreadState *aThreadState) : michael@0: mCx(aCx), mThreadState(aThreadState) michael@0: { michael@0: } michael@0: michael@0: /* XXX These things are only valid for a short period of time, they reflect michael@0: * state in the js engine that will go away after stepping past wherever michael@0: * we were stopped at when this was created. We could keep a list of every michael@0: * instance of this we've created, and "invalidate" them before we let the michael@0: * engine continue. The next time we need a threadstate, we can search the michael@0: * list to find an invalidated one, and just reuse it. michael@0: */ michael@0: static jsdIThreadState *FromPtr (JSDContext *aCx, michael@0: JSDThreadState *aThreadState) michael@0: { michael@0: if (!aThreadState) michael@0: return nullptr; michael@0: michael@0: jsdIThreadState *rv = new jsdThreadState (aCx, aThreadState); michael@0: NS_IF_ADDREF(rv); michael@0: return rv; michael@0: } michael@0: michael@0: private: michael@0: jsdThreadState(); /* no implementation */ michael@0: jsdThreadState(const jsdThreadState&); /* no implementation */ michael@0: michael@0: JSDContext *mCx; michael@0: JSDThreadState *mThreadState; michael@0: }; michael@0: michael@0: #endif