blob: 22728819ba57a6a7dc7ae0abb4d5e16e1d37fc15 [file]
//-------------------------------------------------------------------------------------------------------
// 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.