//------------------------------------------------------------------------------------------------------- // 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 ProbeList; class DiagStackFrame; typedef JsUtil::Stack DiagStack; typedef WeakArenaReference 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 *registeredFuncContextList; JsUtil::List *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 void MapProbes(TMapFunction map) { this->diagProbeList->Map(map); } template 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); // When DOM mutation breakpoint hit void DispatchDOMMutationBreakpoint(); 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*, Recycler, false, Js::WeakRefFreeListedRemovePolicy> MutationBreakpointList; RecyclerRootPtr mutationBreakpointList; bool HasMutationBreakpoints(); void InsertMutationBreakpoint(MutationBreakpoint *mutationBreakpoint); #endif static bool IsTmpRegCountIncreased(Js::FunctionBody* functionBody, ByteCodeReader* reader, int currentOffset, int nextStmOffset, bool restoreOffset); }; } // namespace Js.