| //------------------------------------------------------------------------------------------------------- |
| // Copyright (C) Microsoft. All rights reserved. |
| // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. |
| //------------------------------------------------------------------------------------------------------- |
| #pragma once |
| namespace Js |
| { |
| #ifdef ENABLE_MUTATION_BREAKPOINT |
| class MutationBreakpoint; |
| #endif |
| |
| class DebugManager; |
| struct Probe; |
| struct DebuggerPropertyDisplayInfo; |
| typedef JsUtil::List<Probe*, ArenaAllocator> ProbeList; |
| class DiagStackFrame; |
| typedef JsUtil::Stack<DiagStackFrame*> DiagStack; |
| typedef WeakArenaReference<DiagStack> WeakDiagStack; |
| struct InterpreterHaltState; |
| |
| // This class contains the probes and list of function bodies. |
| // The object of this class is maintained by ScriptContext. |
| class ProbeContainer |
| { |
| friend class RecyclableObjectDisplay; |
| friend class RecyclableArrayWalker; |
| |
| private: |
| ProbeList* diagProbeList; |
| ProbeList* pendingProbeList; |
| |
| ScriptContext* pScriptContext; |
| DebugManager *debugManager; |
| |
| // Stack for a current scriptcontext |
| DiagStack* framePointers; |
| |
| HaltCallback* haltCallbackProbe; |
| DebuggerOptionsCallback* debuggerOptionsCallback; |
| |
| // Refer to the callback which is responsible for making async break |
| HaltCallback* pAsyncHaltCallback; |
| |
| Var jsExceptionObject; |
| |
| // Used for synchronizing with ProbeManager |
| uint32 debugSessionNumber; |
| |
| uint32 tmpRegCount; // Mentions the temp register count for the current statement (this will be used to determine if SetNextStatement can be applied) |
| |
| // Used when SetNextStatement is applied. |
| int bytecodeOffset; |
| bool IsNextStatementChanged; |
| |
| // Used when the throw is internal and engine does not want to be broken at exception. |
| bool isThrowInternal; |
| |
| // This variable will be set true when we don't want to check for debug script engine being initialized. |
| bool forceBypassDebugEngine; |
| |
| bool isPrimaryBrokenToDebuggerContext; |
| |
| JsUtil::List<DWORD_PTR, ArenaAllocator> *registeredFuncContextList; |
| JsUtil::List<const Js::PropertyRecord*> *pinnedPropertyRecords; |
| |
| void UpdateFramePointers(bool fMatchWithCurrentScriptContext, DWORD_PTR dispatchHaltFrameAddress = 0); |
| bool InitializeLocation(InterpreterHaltState* pHaltState, bool fMatchWithCurrentScriptContext = true); |
| void DestroyLocation(); |
| |
| bool GetNextUserStatementOffsetHelper( |
| Js::FunctionBody* functionBody, int currentOffset, FunctionBody::StatementAdjustmentType adjType, int* nextStatementOffset); |
| |
| #ifdef ENABLE_MUTATION_BREAKPOINT |
| void InitMutationBreakpointListIfNeeded(); |
| void ClearMutationBreakpoints(); |
| void RemoveMutationBreakpointListIfNeeded(); |
| #endif |
| static bool FetchTmpRegCount(Js::FunctionBody * functionBody, Js::ByteCodeReader * reader, int atOffset, uint32 *pTmpRegCount, Js::OpCode *pOp); |
| public: |
| |
| bool isForcedToEnterScriptStart; |
| |
| ProbeContainer(); |
| ~ProbeContainer(); |
| |
| void StartRecordingCall(); |
| void EndRecordingCall(Js::Var returnValue, Js::JavascriptFunction * function); |
| ReturnedValueList* GetReturnedValueList() const; |
| void ResetReturnedValueList(); |
| |
| void Initialize(ScriptContext* pScriptContext); |
| void Close(); |
| |
| WeakDiagStack* GetFramePointers(DWORD_PTR dispatchHaltFrameAddress = 0); |
| |
| // A break engine responsible for breaking at iniline statement and error statement. |
| void InitializeInlineBreakEngine(HaltCallback* pProbe); |
| void InitializeDebuggerScriptOptionCallback(DebuggerOptionsCallback* debuggerOptionsCallback); |
| |
| void UninstallInlineBreakpointProbe(HaltCallback* pProbe); |
| void UninstallDebuggerScriptOptionCallback(); |
| |
| void AddProbe(Probe* pProbe); |
| void RemoveProbe(Probe* pProbe); |
| |
| template<class TMapFunction> |
| void MapProbes(TMapFunction map) |
| { |
| this->diagProbeList->Map(map); |
| } |
| |
| template<class TMapFunction> |
| void MapProbesUntil(TMapFunction map) |
| { |
| this->diagProbeList->MapUntil(map); |
| } |
| |
| void RemoveAllProbes(); |
| |
| bool CanDispatchHalt(InterpreterHaltState* pHaltState); |
| |
| // When on breakpoint hit |
| void DispatchProbeHandlers(InterpreterHaltState* pHaltState); |
| |
| // When on step in, step out and step over |
| void DispatchStepHandler(InterpreterHaltState* pHaltState, OpCode* pOriginalOpcode); |
| |
| // When on break-all |
| void DispatchAsyncBreak(InterpreterHaltState* pHaltState); |
| |
| // When executing 'debugger' statement |
| void DispatchInlineBreakpoint(InterpreterHaltState* pHaltState); |
| |
| // When encountered and exception |
| bool DispatchExceptionBreakpoint(InterpreterHaltState* pHaltState); |
| |
| // When on mutation breakpoint hit |
| void DispatchMutationBreakpoint(InterpreterHaltState* pHaltState); |
| |
| void UpdateStep(bool fDuringSetupDebugApp = false); |
| void DeactivateStep(); |
| |
| bool GetNextUserStatementOffsetForSetNext(Js::FunctionBody* functionBody, int currentOffset, int* nextStatementOffset); |
| bool GetNextUserStatementOffsetForAdvance(Js::FunctionBody* functionBody, ByteCodeReader* reader, int currentOffset, int* nextStatementOffset); |
| bool AdvanceToNextUserStatement(Js::FunctionBody* functionBody, ByteCodeReader* reader); |
| |
| void SetNextStatementAt(int bytecodeOffset); |
| bool IsSetNextStatementCalled() const { return IsNextStatementChanged; } |
| int GetByteCodeOffset() const { Assert(IsNextStatementChanged); return bytecodeOffset; } |
| |
| void AsyncActivate(HaltCallback* haltCallback); |
| void AsyncDeactivate(); |
| bool IsAsyncActivate() const; |
| |
| void PrepDiagForEnterScript(); |
| |
| void RegisterContextToDiag(DWORD_PTR context, ArenaAllocator *alloc); |
| bool IsContextRegistered(DWORD_PTR context); |
| FunctionBody * GetGlobalFunc(ScriptContext* scriptContext, DWORD_PTR secondaryHostSourceContext); |
| |
| Var GetExceptionObject() { return jsExceptionObject; } |
| |
| bool HasAllowedForException(__in JavascriptExceptionObject* exceptionObject); |
| |
| void SetThrowIsInternal(bool set) { isThrowInternal = set; } |
| |
| bool IsExceptionReportingEnabled(); |
| bool IsFirstChanceExceptionEnabled(); |
| bool IsNonUserCodeSupportEnabled(); |
| bool IsLibraryStackFrameSupportEnabled(); |
| |
| void SetCurrentTmpRegCount(uint32 set) { tmpRegCount = set; } |
| uint32 GetCurrentTmpRegCount() const { return tmpRegCount; } |
| void PinPropertyRecord(const Js::PropertyRecord *propertyRecord); |
| |
| bool IsPrimaryBrokenToDebuggerContext() const { return isPrimaryBrokenToDebuggerContext; } |
| void SetIsPrimaryBrokenToDebuggerContext(bool set) { isPrimaryBrokenToDebuggerContext = set; } |
| |
| DebugManager *GetDebugManager() const { return this->debugManager; } |
| |
| #ifdef ENABLE_MUTATION_BREAKPOINT |
| typedef JsUtil::List<RecyclerWeakReference<Js::MutationBreakpoint>*, Recycler, false, Js::WeakRefFreeListedRemovePolicy> MutationBreakpointList; |
| RecyclerRootPtr<MutationBreakpointList> mutationBreakpointList; |
| bool HasMutationBreakpoints(); |
| void InsertMutationBreakpoint(MutationBreakpoint *mutationBreakpoint); |
| #endif |
| static bool IsTmpRegCountIncreased(Js::FunctionBody* functionBody, ByteCodeReader* reader, int currentOffset, int nextStmOffset, bool restoreOffset); |
| }; |
| } // namespace Js. |