DiagObjectModel.h 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft. All rights reserved.
  3. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  4. //-------------------------------------------------------------------------------------------------------
  5. #pragma once
  6. namespace Js
  7. {
  8. class IDiagObjectAddress;
  9. class IDiagObjectModelDisplay;
  10. class RecyclableMethodsGroupWalker;
  11. class RecyclableObjectWalker;
  12. class RecyclableArrayWalker;
  13. // Concrete type for manipulating JS Vars
  14. struct ResolvedObject
  15. {
  16. ResolvedObject() : propId(Js::Constants::NoProperty), scriptContext(nullptr), address(nullptr),
  17. objectDisplay(nullptr), obj(nullptr), originalObj(nullptr), isConst(false), name(nullptr)
  18. {}
  19. PropertyId propId;
  20. ScriptContext *scriptContext;
  21. IDiagObjectAddress *address;
  22. IDiagObjectModelDisplay *objectDisplay;
  23. Var obj;
  24. Var originalObj;
  25. LPCWSTR name;
  26. TypeId typeId;
  27. bool isConst;
  28. WeakArenaReference<IDiagObjectModelDisplay>* GetObjectDisplay();
  29. IDiagObjectModelDisplay * CreateDisplay();
  30. bool IsInDeadZone() const;
  31. };
  32. // interfaces for manipulating DataTypes
  33. // Allow setting the value across different parent data types
  34. class IDiagObjectAddress
  35. {
  36. public:
  37. virtual BOOL Set(Var updateObject) = 0;
  38. virtual BOOL IsWritable() { return !IsInDeadZone(); }
  39. virtual Var GetValue(BOOL fUpdated) { return nullptr; }
  40. virtual BOOL IsInDeadZone() const { return FALSE; };
  41. };
  42. class IDiagObjectModelWalkerBase
  43. {
  44. public:
  45. // Get the child at i'th position.
  46. virtual BOOL Get(int i, ResolvedObject* pResolvedObject) = 0;
  47. // Returns number of children for the current diag object.
  48. virtual uint32 GetChildrenCount() = 0;
  49. virtual BOOL GetGroupObject(ResolvedObject* pResolvedObject) = 0;
  50. virtual IDiagObjectAddress *FindPropertyAddress(PropertyId propId, bool& isConst) { return nullptr;}
  51. };
  52. enum DiagObjectModelDisplayType
  53. {
  54. DiagObjectModelDisplayType_LocalsDisplay,
  55. DiagObjectModelDisplayType_RecyclableObjectDisplay,
  56. DiagObjectModelDisplayType_RecyclableCollectionObjectDisplay,
  57. DiagObjectModelDisplayType_RecyclableKeyValueDisplay,
  58. DiagObjectModelDisplayType_RecyclableSimdDisplay,
  59. };
  60. // Allow getting information across different data types
  61. class IDiagObjectModelDisplay
  62. {
  63. public:
  64. virtual LPCWSTR Name() = 0;
  65. virtual LPCWSTR Type() = 0;
  66. virtual LPCWSTR Value(int radix) = 0;
  67. virtual BOOL HasChildren() = 0;
  68. virtual BOOL Set(Var updateObject) = 0;
  69. virtual DBGPROP_ATTRIB_FLAGS GetTypeAttribute() = 0;
  70. virtual BOOL SetDefaultTypeAttribute(DBGPROP_ATTRIB_FLAGS attributes) { return FALSE; };
  71. virtual WeakArenaReference<IDiagObjectModelWalkerBase>* CreateWalker() = 0;
  72. virtual BOOL IsLocalsAsRoot() { return FALSE; }
  73. virtual Var GetVarValue(BOOL fUpdated) { return nullptr; }
  74. virtual IDiagObjectAddress * GetDiagAddress() { return nullptr; }
  75. virtual DiagObjectModelDisplayType GetType() = 0;
  76. virtual bool IsFake() { return (this->GetTypeAttribute() & DBGPROP_ATTRIB_VALUE_IS_FAKE) == DBGPROP_ATTRIB_VALUE_IS_FAKE; }
  77. virtual bool IsLiteralProperty() const = 0;
  78. virtual bool IsSymbolProperty() { return false; }
  79. virtual ~IDiagObjectModelDisplay() { /* Dummy */ }
  80. };
  81. //
  82. // There are three distinct types of classes defined in order to inspect a variable on watch/locals window.
  83. // If someone has to change or provide the support for custom types/objects (such as PixelArray etc) be displayed on the debugger, they need to aware
  84. // of few things which are mentioned below.
  85. // <...>Display (eg RecyclableArrayDisplay), mentions how current variable is given to debugger, and tells what walker (enumerator) to be chosen
  86. // in order to walk to children of the current variable.
  87. // <...>Walker (eg RecyclableArrayWalker), mentions logic of walk thru content of the current variable (the object generally acts like an enumerator). Let say for an array, it has logic to go thru each
  88. // indices and populate values.
  89. // <...>Address (eg RecyclableArrayAddress), associated with each child and will be used to updating that item. The object if this will be consumed by "<...>Walker"
  90. // object when it walks thru each children of the current variable.
  91. // In order to support the custom objects, above classes should be used (or derived) to get started.
  92. //
  93. enum DebuggerPropertyDisplayInfoFlags
  94. {
  95. DebuggerPropertyDisplayInfoFlags_None = 0x0,
  96. DebuggerPropertyDisplayInfoFlags_Const = 0x1,
  97. DebuggerPropertyDisplayInfoFlags_InDeadZone = 0x2,
  98. DebuggerPropertyDisplayInfoFlags_Unscope = 0x4,
  99. };
  100. struct DebuggerPropertyDisplayInfo
  101. {
  102. PropertyId propId;
  103. Var aVar;
  104. DWORD flags; // DebuggerPropertyDisplayInfoFlags.
  105. DebuggerPropertyDisplayInfo(PropertyId _propId, Var _aVar, DWORD _flags) : propId(_propId), aVar(_aVar), flags(_flags)
  106. {}
  107. bool IsUnscoped() const { return (flags & DebuggerPropertyDisplayInfoFlags_Unscope) != 0; }
  108. bool IsConst() const { return (flags & DebuggerPropertyDisplayInfoFlags_Const) != 0; }
  109. bool IsInDeadZone() const { return (flags & DebuggerPropertyDisplayInfoFlags_InDeadZone) != 0; }
  110. };
  111. enum UIGroupType
  112. {
  113. UIGroupType_None,
  114. UIGroupType_InnerScope, // variables under the innerscope (such as Block/Catch)
  115. UIGroupType_Scope,
  116. UIGroupType_Globals,
  117. UIGroupType_Param
  118. };
  119. enum FramesLocalType
  120. {
  121. LocalType_None = 0x0,
  122. LocalType_Reg = 0x1,
  123. LocalType_InSlot = 0x2,
  124. LocalType_InObject = 0x4,
  125. };
  126. enum FrameWalkerFlags
  127. {
  128. FW_None = 0x0,
  129. FW_MakeGroups = 0x1, // Make groups such as [Scope], [Globals] etc.
  130. FW_EnumWithScopeAlso = 0x2, // While walking include the with scope as well.
  131. FW_AllowLexicalThis = 0x4, // Do not filter out Js::PropertyIds::_this
  132. FW_AllowSuperReference = 0x8, // Allow walking of Js::PropertyIds::_super and Js::PropertyIds::_superConstructor
  133. FW_DontAddGlobalsDirectly = 0x10, // Do not add global object directly.
  134. };
  135. class VariableWalkerBase : public IDiagObjectModelWalkerBase
  136. {
  137. public:
  138. DiagStackFrame* pFrame;
  139. Var instance;
  140. JsUtil::List<DebuggerPropertyDisplayInfo*, ArenaAllocator> *pMembersList;
  141. UIGroupType groupType;
  142. private:
  143. bool allowLexicalThis;
  144. bool allowSuperReference;
  145. public :
  146. VariableWalkerBase(DiagStackFrame* _pFrame, Var _instance, UIGroupType _groupType, bool allowLexicalThis, bool allowSuperReference = false)
  147. : pFrame(_pFrame), instance(_instance), pMembersList(nullptr), groupType(_groupType), allowLexicalThis(allowLexicalThis), allowSuperReference(allowSuperReference)
  148. {
  149. }
  150. // Defined virtual function, should be extended by type of variable scope.
  151. virtual void PopulateMembers() { };
  152. virtual IDiagObjectAddress * GetObjectAddress(int index) { return nullptr; }
  153. virtual Var GetVarObjectAt(int index);
  154. virtual bool IsConstAt(int index);
  155. /// IDiagObjectModelWalkerBase
  156. virtual BOOL Get(int i, ResolvedObject* pResolvedObject) override;
  157. virtual uint32 GetChildrenCount() override;
  158. virtual BOOL GetGroupObject(ResolvedObject* pResolvedObject) override sealed;
  159. virtual IDiagObjectAddress *FindPropertyAddress(PropertyId propId, bool& isConst) override;
  160. static BOOL GetExceptionObject(int &index, DiagStackFrame* frame, ResolvedObject* pResolvedObject);
  161. static bool HasExceptionObject(DiagStackFrame* frame);
  162. static BOOL GetReturnedValue(int &index, DiagStackFrame* frame, ResolvedObject* pResolvedObject);
  163. static int GetReturnedValueCount(DiagStackFrame* frame);
  164. static void GetReturnedValueResolvedObject(ReturnedValue * returnValue, DiagStackFrame* frame, ResolvedObject* pResolvedObject);
  165. #ifdef ENABLE_MUTATION_BREAKPOINT
  166. static BOOL GetBreakMutationBreakpointValue(int &index, DiagStackFrame* frame, ResolvedObject* pResolvedObject);
  167. static uint GetBreakMutationBreakpointsCount(DiagStackFrame* frame);
  168. #endif
  169. bool IsInGroup() const { return (groupType != UIGroupType::UIGroupType_None && groupType != UIGroupType::UIGroupType_Param && groupType != UIGroupType::UIGroupType_InnerScope); }
  170. bool IsWalkerForCurrentFrame() const { return groupType == UIGroupType::UIGroupType_None || groupType == UIGroupType_Param; }
  171. DebuggerScope * GetScopeWhenHaltAtFormals();
  172. static bool IsInParamScope(DebuggerScope* scope, DiagStackFrame* pFrame);
  173. int GetAdjustedByteCodeOffset() const;
  174. DebuggerPropertyDisplayInfo* AllocateNewPropertyDisplayInfo(PropertyId propertyId, Var value, bool isConst, bool isInDeadZone);
  175. protected:
  176. int GetMemberCount() { return pMembersList ? pMembersList->Count() : 0; }
  177. bool IsPropertyValid(PropertyId propertyId, RegSlot location, bool *isPropertyInDebuggerScope, bool* isConst, bool* isInDeadZone) const;
  178. private:
  179. static const char16 * ParseFunctionName(const char16* displayNameBuffer, const charcount_t displayNameBufferLength, ScriptContext* scriptContext);
  180. };
  181. class RegSlotVariablesWalker : public VariableWalkerBase
  182. {
  183. // This will be pointing to the inner debugger scope (block/catch)
  184. DebuggerScope* debuggerScope;
  185. public:
  186. RegSlotVariablesWalker(DiagStackFrame* _pFrame, DebuggerScope *_debuggerScope, UIGroupType _groupType, bool allowSuperReference = false)
  187. : VariableWalkerBase(_pFrame, nullptr, _groupType, /* allowLexicalThis */ false, allowSuperReference), debuggerScope(_debuggerScope)
  188. {
  189. }
  190. virtual void PopulateMembers() override;
  191. virtual IDiagObjectAddress * GetObjectAddress(int index) override;
  192. virtual Var GetVarObjectAt(int index) override;
  193. private:
  194. bool IsRegisterValid(PropertyId propertyId, RegSlot registerSlot) const;
  195. bool IsRegisterInScope(PropertyId propertyId, RegSlot registerSlot) const;
  196. Var GetVarObjectAndRegAt(int index, RegSlot* reg = nullptr);
  197. };
  198. class SlotArrayVariablesWalker : public VariableWalkerBase
  199. {
  200. public:
  201. SlotArrayVariablesWalker(DiagStackFrame* _pFrame, Var _instance, UIGroupType _groupType, bool allowLexicalThis, bool allowSuperReference = false) : VariableWalkerBase(_pFrame, _instance, _groupType, allowLexicalThis, allowSuperReference) {}
  202. virtual void PopulateMembers() override;
  203. virtual IDiagObjectAddress * GetObjectAddress(int index) override;
  204. ScopeSlots GetSlotArray()
  205. {
  206. Field(Var) *slotArray = (Field(Var) *) instance;
  207. Assert(slotArray != nullptr);
  208. return ScopeSlots(slotArray);
  209. }
  210. };
  211. class ObjectVariablesWalker : public VariableWalkerBase
  212. {
  213. public:
  214. ObjectVariablesWalker(DiagStackFrame* _pFrame, Var _instance, UIGroupType _groupType, bool allowLexicalThis, bool allowSuperReference = false) : VariableWalkerBase(_pFrame, _instance, _groupType, allowLexicalThis, allowSuperReference) {}
  215. virtual void PopulateMembers() override;
  216. virtual IDiagObjectAddress * GetObjectAddress(int index) override;
  217. protected:
  218. void AddObjectProperties(int count, Js::RecyclableObject* object);
  219. };
  220. class RootObjectVariablesWalker : public ObjectVariablesWalker
  221. {
  222. public:
  223. RootObjectVariablesWalker(DiagStackFrame* _pFrame, Var _instance, UIGroupType _groupType) : ObjectVariablesWalker(_pFrame, _instance, _groupType, /* allowLexicalThis */ false) {}
  224. virtual void PopulateMembers() override;
  225. };
  226. class DiagScopeVariablesWalker sealed : public VariableWalkerBase
  227. {
  228. public:
  229. // Represent catch/with scope objects, (ie. the representation for the diagnostics purposes.)
  230. JsUtil::List<IDiagObjectModelWalkerBase*, ArenaAllocator> *pDiagScopeObjects;
  231. uint32 diagScopeVarCount;
  232. bool scopeIsInitialized;
  233. bool enumWithScopeAlso;
  234. public:
  235. DiagScopeVariablesWalker(DiagStackFrame* _pFrame, Var _instance, bool _enumWithScopeAlso)
  236. : VariableWalkerBase(_pFrame, _instance, UIGroupType_InnerScope, /* allowLexicalThis */ false), pDiagScopeObjects(nullptr), diagScopeVarCount(0), scopeIsInitialized(false), enumWithScopeAlso(_enumWithScopeAlso)
  237. {}
  238. DiagScopeVariablesWalker(DiagStackFrame* _pFrame, Var _instance, IDiagObjectModelWalkerBase* innerWalker);
  239. virtual BOOL Get(int i, ResolvedObject* pResolvedObject) override;
  240. virtual uint32 GetChildrenCount() override;
  241. virtual IDiagObjectAddress *FindPropertyAddress(PropertyId propId, bool& isConst) override;
  242. };
  243. // Display of variable on the locals window
  244. // Also responsible for walking on the current frame and build up chain of scopes.
  245. class LocalsWalker sealed : public IDiagObjectModelWalkerBase
  246. {
  247. friend class RecyclableArgumentsArrayWalker;
  248. DiagStackFrame* pFrame;
  249. JsUtil::List<VariableWalkerBase *, ArenaAllocator> * pVarWalkers; // This includes, current frame, all scopes and globals for a current frame
  250. uint totalLocalsCount;
  251. DWORD frameWalkerFlags;
  252. // true, if user has not defined the 'arguments' in the script, this is used for displaying a fake arguments object and display in the locals window.
  253. bool hasUserNotDefinedArguments;
  254. public:
  255. LocalsWalker(DiagStackFrame* _frame, DWORD _frameWalkerFlags);
  256. virtual BOOL Get(int i, ResolvedObject* pResolvedObject) override;
  257. virtual uint32 GetChildrenCount() override;
  258. virtual uint32 GetLocalVariablesCount();
  259. BOOL GetLocal(int i, ResolvedObject* pResolvedObject);
  260. BOOL GetScopeObject(int i, ResolvedObject* pResolvedObject);
  261. BOOL GetGlobalsObject(ResolvedObject* pResolvedObject);
  262. virtual BOOL GetGroupObject(ResolvedObject* pResolvedObject) {return FALSE; }
  263. static DWORD GetCurrentFramesLocalsType(DiagStackFrame* frame);
  264. static DebuggerScope * GetScopeWhenHaltAtFormals(DiagStackFrame* frame);
  265. static int GetAdjustedByteCodeOffset(DiagStackFrame* frame);
  266. IDiagObjectAddress * FindPropertyAddress(PropertyId propId, bool& isConst) override;
  267. // enumerateGroups will be true for the when fetching from a variable from the expression evaluation.
  268. IDiagObjectAddress * FindPropertyAddress(PropertyId propId, bool enumerateGroups, bool& isConst);
  269. template <typename FnProcessResolvedObject>
  270. DynamicObject* CreateAndPopulateActivationObject(ScriptContext* scriptContext, FnProcessResolvedObject processResolvedObjectFn)
  271. {
  272. Assert(scriptContext);
  273. Js::DynamicObject* activeScopeObject = nullptr;
  274. uint32 count = this->GetChildrenCount();
  275. if (count > 0)
  276. {
  277. activeScopeObject = scriptContext->GetLibrary()->CreateActivationObject();
  278. for (uint32 i = 0; i < count; i++)
  279. {
  280. Js::ResolvedObject resolveObject;
  281. if (this->Get(i, &resolveObject) && resolveObject.propId != Js::Constants::NoProperty)
  282. {
  283. if (!activeScopeObject->HasOwnProperty(resolveObject.propId))
  284. {
  285. OUTPUT_TRACE(Js::ConsoleScopePhase, _u("Adding '%s' property to activeScopeObject\n"), resolveObject.scriptContext->GetPropertyName(resolveObject.propId)->GetBuffer());
  286. if (resolveObject.IsInDeadZone())
  287. {
  288. PropertyOperationFlags flags = static_cast<PropertyOperationFlags>(PropertyOperation_SpecialValue | PropertyOperation_AllowUndecl);
  289. PropertyAttributes attributes = resolveObject.isConst ? PropertyConstDefaults : PropertyLetDefaults;
  290. resolveObject.obj = scriptContext->GetLibrary()->GetUndeclBlockVar();
  291. activeScopeObject->SetPropertyWithAttributes(
  292. resolveObject.propId,
  293. resolveObject.obj,
  294. attributes, nullptr, flags);
  295. }
  296. else
  297. {
  298. activeScopeObject->SetPropertyWithAttributes(
  299. resolveObject.propId,
  300. JavascriptOperators::BoxStackInstance(resolveObject.obj, scriptContext, /* allowStackFunction */ false, /* deepCopy */ false), //The value escapes, box if necessary.
  301. resolveObject.isConst ? PropertyConstDefaults : PropertyDynamicTypeDefaults,
  302. nullptr);
  303. }
  304. processResolvedObjectFn(resolveObject);
  305. }
  306. }
  307. }
  308. }
  309. return activeScopeObject;
  310. }
  311. BOOL CreateArgumentsObject(ResolvedObject* pResolvedObject);
  312. bool HasUserNotDefinedArguments() const { return hasUserNotDefinedArguments; }
  313. private:
  314. bool ShouldMakeGroups() const { return frameWalkerFlags & FW_MakeGroups; }
  315. bool ShouldInsertFakeArguments();
  316. void ExpandArgumentsObject(IDiagObjectModelDisplay * argumentsDisplay);
  317. BOOL GetGroupObject(Js::UIGroupType uiGroupType, int i, ResolvedObject* pResolvedObject);
  318. };
  319. class LocalsDisplay : public IDiagObjectModelDisplay
  320. {
  321. DiagStackFrame* pFrame;
  322. public:
  323. LocalsDisplay(DiagStackFrame* _frame);
  324. virtual LPCWSTR Name() override;
  325. virtual LPCWSTR Type() override;
  326. virtual LPCWSTR Value(int radix) override;
  327. virtual BOOL HasChildren() override;
  328. virtual BOOL Set(Var updateObject) override;
  329. virtual DBGPROP_ATTRIB_FLAGS GetTypeAttribute() override;
  330. virtual WeakArenaReference<IDiagObjectModelWalkerBase>* CreateWalker() override;
  331. virtual BOOL IsLocalsAsRoot() { return TRUE; }
  332. virtual DiagObjectModelDisplayType GetType() { return DiagObjectModelDisplayType_LocalsDisplay; }
  333. virtual bool IsLiteralProperty() const { return false; }
  334. };
  335. //
  336. // The locals var's addresses.
  337. // A representation of an address when this Var is taken from the slot array.
  338. class LocalObjectAddressForSlot : public IDiagObjectAddress
  339. {
  340. ScopeSlots slotArray;
  341. int slotIndex;
  342. Var value;
  343. public:
  344. LocalObjectAddressForSlot(ScopeSlots _pSlotArray, int _slotIndex, Js::Var _value);
  345. virtual BOOL Set(Var updateObject) override;
  346. virtual Var GetValue(BOOL fUpdated);
  347. virtual BOOL IsInDeadZone() const;
  348. };
  349. // A representation of an address when this Var is taken from the direct regslot.
  350. class LocalObjectAddressForRegSlot : public IDiagObjectAddress
  351. {
  352. DiagStackFrame* pFrame;
  353. RegSlot regSlot;
  354. Var value;
  355. public:
  356. LocalObjectAddressForRegSlot(DiagStackFrame* _pFrame, RegSlot _regSlot, Js::Var _value);
  357. virtual BOOL Set(Var updateObject) override;
  358. virtual Var GetValue(BOOL fUpdated);
  359. BOOL IsInDeadZone() const;
  360. };
  361. class CatchScopeWalker sealed : public IDiagObjectModelWalkerBase
  362. {
  363. DiagStackFrame* pFrame;
  364. DebuggerScope * debuggerScope;
  365. public :
  366. CatchScopeWalker(DiagStackFrame* _pFrame, DebuggerScope* _debuggerScope)
  367. : pFrame(_pFrame), debuggerScope(_debuggerScope)
  368. {
  369. }
  370. /// IDiagObjectModelWalkerBase
  371. virtual BOOL Get(int i, ResolvedObject* pResolvedObject) override;
  372. virtual uint32 GetChildrenCount() override;
  373. virtual BOOL GetGroupObject(ResolvedObject* pResolvedObject) override { return FALSE; }
  374. virtual IDiagObjectAddress *FindPropertyAddress(PropertyId propId, bool& isConst) override;
  375. private:
  376. void FetchValueAndAddress(DebuggerScopeProperty &scopeProperty, _Out_opt_ Var *pValue, _Out_opt_ IDiagObjectAddress ** ppAddress);
  377. };
  378. // Concrete Classes for Objects
  379. class RecyclableObjectWalker : public IDiagObjectModelWalkerBase
  380. {
  381. protected:
  382. ScriptContext* scriptContext;
  383. Var instance;
  384. Var originalInstance; // Remember original instance for prototype walk, because evaluating getters in CallGetter() if __proto__ instance is passed does not work
  385. JsUtil::List<DebuggerPropertyDisplayInfo *, ArenaAllocator> * pMembersList;
  386. RecyclableArrayWalker * innerArrayObjectWalker; // Will be used for array indices on the object
  387. JsUtil::List<IDiagObjectModelWalkerBase *, ArenaAllocator> * fakeGroupObjectWalkerList; // such as [prototype], [Methods] etc.
  388. void InsertItem(Js::RecyclableObject *pOriginalObject, Js::RecyclableObject *pObject, PropertyId propertyId, bool isConst, bool isUnscoped, Js::RecyclableMethodsGroupWalker **ppMethodsGrouptWalker, bool shouldPinProperty = false);
  389. void InsertItem(PropertyId propertyId, bool isConst, bool isUnscoped, Var itemObj, Js::RecyclableMethodsGroupWalker **ppMethodsGrouptWalker, bool shouldPinProperty = false);
  390. void EnsureFakeGroupObjectWalkerList();
  391. public:
  392. RecyclableObjectWalker(ScriptContext* pContext, Var slot);
  393. RecyclableObjectWalker(ScriptContext* pContext, Var slot, Var originalInstance);
  394. virtual BOOL Get(int i, ResolvedObject* pResolvedObject) override;
  395. virtual uint32 GetChildrenCount() override;
  396. virtual BOOL GetGroupObject(ResolvedObject* pResolvedObject) { return FALSE; };
  397. virtual IDiagObjectAddress *FindPropertyAddress(PropertyId propertyId, bool& isConst) override;
  398. static Var GetObject(RecyclableObject* originalInstance, RecyclableObject* instance, PropertyId propertyId, ScriptContext* scriptContext);
  399. };
  400. class RecyclableObjectAddress : public IDiagObjectAddress
  401. {
  402. Var parentObj;
  403. Js::PropertyId propId;
  404. Js::Var value;
  405. BOOL isInDeadZone;
  406. public:
  407. RecyclableObjectAddress(Var parentObj, Js::PropertyId _propId, Js::Var _value, BOOL _isInDeadZone);
  408. virtual BOOL Set(Var updateObject) override;
  409. virtual BOOL IsWritable() override;
  410. virtual Var GetValue(BOOL fUpdated);
  411. BOOL IsInDeadZone() const;
  412. };
  413. class RecyclableObjectDisplay : public IDiagObjectModelDisplay
  414. {
  415. protected:
  416. ScriptContext* scriptContext;
  417. Var instance;
  418. Var originalInstance;
  419. LPCWSTR name;
  420. IDiagObjectAddress* pObjAddress;
  421. DBGPROP_ATTRIB_FLAGS defaultAttributes;
  422. PropertyId propertyId;
  423. public:
  424. RecyclableObjectDisplay(ResolvedObject* resolvedObject, DBGPROP_ATTRIB_FLAGS defaultAttributes = DBGPROP_ATTRIB_NO_ATTRIB);
  425. virtual LPCWSTR Name() override;
  426. virtual LPCWSTR Type() override;
  427. virtual LPCWSTR Value(int radix) override;
  428. virtual BOOL HasChildren() override;
  429. virtual BOOL Set(Var updateObject) override;
  430. virtual BOOL SetDefaultTypeAttribute(DBGPROP_ATTRIB_FLAGS attributes) override { defaultAttributes = attributes; return TRUE; };
  431. virtual DBGPROP_ATTRIB_FLAGS GetTypeAttribute() override;
  432. virtual WeakArenaReference<IDiagObjectModelWalkerBase>* CreateWalker() override;
  433. virtual Var GetVarValue(BOOL fUpdated) override;
  434. virtual IDiagObjectAddress * GetDiagAddress() override { return pObjAddress; }
  435. virtual DiagObjectModelDisplayType GetType() { return DiagObjectModelDisplayType_RecyclableObjectDisplay; }
  436. virtual bool IsLiteralProperty() const;
  437. virtual bool IsSymbolProperty() override;
  438. static BOOL GetPropertyWithScriptEnter(RecyclableObject* originalInstance, RecyclableObject* instance, PropertyId propertyId, Var* value, ScriptContext* scriptContext);
  439. StringBuilder<ArenaAllocator>* GetStringBuilder();
  440. PropertyId GetPropertyId() const;
  441. };
  442. // Concrete classes for Arrays
  443. class RecyclableArrayAddress : public IDiagObjectAddress
  444. {
  445. protected:
  446. Var parentArray;
  447. unsigned int index;
  448. public:
  449. RecyclableArrayAddress(Var parentArray, unsigned int index);
  450. virtual BOOL Set(Var updateObject) override;
  451. };
  452. class RecyclableArrayDisplay : public RecyclableObjectDisplay
  453. {
  454. protected:
  455. BOOL HasChildrenInternal(Js::JavascriptArray* arrayObj);
  456. public:
  457. RecyclableArrayDisplay(ResolvedObject* resolvedObject);
  458. virtual BOOL HasChildren() override;
  459. virtual WeakArenaReference<IDiagObjectModelWalkerBase>* CreateWalker() override;
  460. };
  461. class RecyclableArrayWalker : public RecyclableObjectWalker
  462. {
  463. protected:
  464. uint32 indexedItemCount;
  465. JsUtil::List<uint32, ArenaAllocator> * pAbsoluteIndexList;
  466. // Just populate the indexes only.
  467. bool fOnlyOwnProperties;
  468. uint32 GetItemCount(Js::JavascriptArray* arrayObj);
  469. // ES5Array will extend this.
  470. virtual uint32 GetNextDescriptor(uint32 currentDescriptor) { return Js::JavascriptArray::InvalidIndex; }
  471. LPCWSTR GetIndexName(uint32 index, StringBuilder<ArenaAllocator>* stringBuilder);
  472. Js::JavascriptArray* GetArrayObject();
  473. public:
  474. RecyclableArrayWalker(ScriptContext* pContext, Var slot, Var originalInstance);
  475. void SetOnlyWalkOwnProperties(bool set) { fOnlyOwnProperties = set; }
  476. virtual BOOL Get(int i, ResolvedObject* pResolvedObject) override;
  477. virtual uint32 GetChildrenCount() override;
  478. virtual BOOL FetchItemAtIndex(Js::JavascriptArray* arrayObj, uint32 index, Var *value);
  479. virtual Var FetchItemAt(Js::JavascriptArray* arrayObj, uint32 index);
  480. virtual BOOL GetResolvedObject(Js::JavascriptArray* arrayObj, int index, ResolvedObject* pResolvedObject, uint32 * pabsIndex) sealed;
  481. StringBuilder<ArenaAllocator>* GetBuilder();
  482. };
  483. // Concrete classes for Arguments object
  484. //
  485. class RecyclableArgumentsObjectDisplay : public RecyclableObjectDisplay
  486. {
  487. LocalsWalker *pLocalsWalker;
  488. public:
  489. RecyclableArgumentsObjectDisplay(ResolvedObject* resolvedObject, LocalsWalker *localsWalker);
  490. virtual BOOL HasChildren() override;
  491. virtual WeakArenaReference<IDiagObjectModelWalkerBase>* CreateWalker() override;
  492. };
  493. class RecyclableArgumentsObjectWalker : public RecyclableObjectWalker
  494. {
  495. LocalsWalker *pLocalsWalker;
  496. public:
  497. RecyclableArgumentsObjectWalker(ScriptContext* pContext, Var instance, LocalsWalker * localsWalker);
  498. virtual uint32 GetChildrenCount() override;
  499. };
  500. class RecyclableArgumentsArrayAddress : public IDiagObjectAddress
  501. {
  502. Var parentArray;
  503. unsigned int index;
  504. public:
  505. RecyclableArgumentsArrayAddress(Var parentArray, unsigned int index);
  506. virtual BOOL Set(Var updateObject) override;
  507. };
  508. class RecyclableArgumentsArrayWalker : public RecyclableArrayWalker
  509. {
  510. JsUtil::List<IDiagObjectAddress *, ArenaAllocator> * pFormalsList;
  511. public:
  512. RecyclableArgumentsArrayWalker(ScriptContext* pContext, Var slot, Var originalInstance);
  513. virtual BOOL Get(int i, ResolvedObject* pResolvedObject) override;
  514. virtual uint32 GetChildrenCount() override;
  515. void FetchFormalsAddress (LocalsWalker * localsWalker);
  516. };
  517. // Concrete classes for Typed array objects
  518. //
  519. class RecyclableTypedArrayAddress : public RecyclableArrayAddress
  520. {
  521. public:
  522. RecyclableTypedArrayAddress(Var parentArray, unsigned int index);
  523. virtual BOOL Set(Var updateObject) override;
  524. };
  525. class RecyclableTypedArrayDisplay : public RecyclableObjectDisplay
  526. {
  527. public:
  528. RecyclableTypedArrayDisplay(ResolvedObject* resolvedObject);
  529. virtual BOOL HasChildren() override;
  530. virtual WeakArenaReference<IDiagObjectModelWalkerBase>* CreateWalker() override;
  531. };
  532. class RecyclableTypedArrayWalker : public RecyclableArrayWalker
  533. {
  534. public:
  535. RecyclableTypedArrayWalker(ScriptContext* pContext, Var slot, Var originalInstance);
  536. virtual BOOL Get(int i, ResolvedObject* pResolvedObject) override;
  537. virtual uint32 GetChildrenCount() override;
  538. };
  539. // Concrete classes for Pixel array objects
  540. //
  541. class RecyclablePixelArrayAddress : public RecyclableArrayAddress
  542. {
  543. public:
  544. RecyclablePixelArrayAddress(Var parentArray, unsigned int index);
  545. virtual BOOL Set(Var updateObject) override;
  546. };
  547. class RecyclablePixelArrayDisplay : public RecyclableObjectDisplay
  548. {
  549. public:
  550. RecyclablePixelArrayDisplay(ResolvedObject* resolvedObject);
  551. virtual BOOL HasChildren() override;
  552. virtual WeakArenaReference<IDiagObjectModelWalkerBase>* CreateWalker() override;
  553. };
  554. class RecyclablePixelArrayWalker : public RecyclableArrayWalker
  555. {
  556. public:
  557. RecyclablePixelArrayWalker(ScriptContext* pContext, Var slot, Var originalInstance);
  558. virtual BOOL Get(int i, ResolvedObject* pResolvedObject) override;
  559. virtual uint32 GetChildrenCount() override;
  560. };
  561. // Concrete classes for ES5 array objects
  562. //
  563. class RecyclableES5ArrayAddress : public RecyclableArrayAddress
  564. {
  565. public:
  566. RecyclableES5ArrayAddress(Var parentArray, unsigned int index);
  567. virtual BOOL Set(Var updateObject) override;
  568. };
  569. class RecyclableES5ArrayDisplay : public RecyclableArrayDisplay
  570. {
  571. public:
  572. RecyclableES5ArrayDisplay(ResolvedObject* resolvedObject);
  573. virtual BOOL HasChildren() override;
  574. virtual WeakArenaReference<IDiagObjectModelWalkerBase>* CreateWalker() override;
  575. };
  576. class RecyclableES5ArrayWalker sealed : public RecyclableArrayWalker
  577. {
  578. public:
  579. RecyclableES5ArrayWalker(ScriptContext* pContext, Var slot, Var originalInstance);
  580. virtual uint32 GetNextDescriptor(uint32 currentDescriptor) override;
  581. virtual BOOL FetchItemAtIndex(Js::JavascriptArray* arrayObj, uint32 index, Var *value) override;
  582. virtual Var FetchItemAt(Js::JavascriptArray* arrayObj, uint32 index) override;
  583. };
  584. // Concrete classes for Proto group object
  585. //
  586. class RecyclableProtoObjectWalker : public RecyclableObjectWalker
  587. {
  588. public:
  589. RecyclableProtoObjectWalker(ScriptContext* pContext, Var slot, Var originalInstance);
  590. virtual BOOL GetGroupObject(ResolvedObject* pResolvedObject) override;
  591. virtual IDiagObjectAddress *FindPropertyAddress(PropertyId propId, bool& isConst) override;
  592. };
  593. class RecyclableProtoObjectAddress : public RecyclableObjectAddress
  594. {
  595. public:
  596. RecyclableProtoObjectAddress(Var _parentObj, Js::PropertyId _propId, Js::Var _value);
  597. };
  598. // Concrete classes for Map, Set, and WeakMap group objects
  599. //
  600. template <typename TData>
  601. struct RecyclableCollectionObjectWalkerPropertyData
  602. {
  603. RecyclableCollectionObjectWalkerPropertyData():key(nullptr), value(nullptr) { }
  604. RecyclableCollectionObjectWalkerPropertyData(Var key, Var value):key(key), value(value) { }
  605. Var key;
  606. Var value;
  607. };
  608. template<>
  609. struct RecyclableCollectionObjectWalkerPropertyData<JavascriptSet>
  610. {
  611. RecyclableCollectionObjectWalkerPropertyData():value(nullptr) { }
  612. RecyclableCollectionObjectWalkerPropertyData(Var value):value(value) { }
  613. Var value;
  614. };
  615. template<>
  616. struct RecyclableCollectionObjectWalkerPropertyData<JavascriptWeakSet>
  617. {
  618. RecyclableCollectionObjectWalkerPropertyData():value(nullptr) { }
  619. RecyclableCollectionObjectWalkerPropertyData(Var value):value(value) { }
  620. Var value;
  621. };
  622. template <typename TData>
  623. class RecyclableCollectionObjectWalker : public IDiagObjectModelWalkerBase
  624. {
  625. ScriptContext* scriptContext;
  626. Var instance;
  627. JsUtil::List<RecyclableCollectionObjectWalkerPropertyData<TData>, ArenaAllocator>* propertyList;
  628. const char16* Name();
  629. IDiagObjectModelDisplay* CreateTDataDisplay(ResolvedObject* resolvedObject, int i);
  630. void GetChildren();
  631. public:
  632. RecyclableCollectionObjectWalker(ScriptContext* scriptContext, Var instance):scriptContext(scriptContext), instance(instance), propertyList(nullptr) { }
  633. virtual BOOL GetGroupObject(ResolvedObject* pResolvedObject) override;
  634. virtual BOOL Get(int i, ResolvedObject* pResolvedObject) override;
  635. virtual uint32 GetChildrenCount() override;
  636. };
  637. typedef RecyclableCollectionObjectWalker<JavascriptMap> RecyclableMapObjectWalker;
  638. typedef RecyclableCollectionObjectWalker<JavascriptSet> RecyclableSetObjectWalker;
  639. typedef RecyclableCollectionObjectWalker<JavascriptWeakMap> RecyclableWeakMapObjectWalker;
  640. typedef RecyclableCollectionObjectWalker<JavascriptWeakSet> RecyclableWeakSetObjectWalker;
  641. template <typename TData>
  642. class RecyclableCollectionObjectDisplay : public IDiagObjectModelDisplay
  643. {
  644. ScriptContext* scriptContext;
  645. const char16* name;
  646. RecyclableCollectionObjectWalker<TData>* walker;
  647. public:
  648. RecyclableCollectionObjectDisplay(ScriptContext* scriptContext, const char16* name, RecyclableCollectionObjectWalker<TData>* walker) : scriptContext(scriptContext), name(name), walker(walker) { }
  649. virtual LPCWSTR Name() override { return name; }
  650. virtual LPCWSTR Type() override { return _u(""); }
  651. virtual LPCWSTR Value(int radix) override;
  652. virtual BOOL HasChildren() override { return walker->GetChildrenCount() > 0; }
  653. virtual BOOL Set(Var updateObject) override { return FALSE; }
  654. virtual BOOL SetDefaultTypeAttribute(DBGPROP_ATTRIB_FLAGS attributes) override { return FALSE; }
  655. virtual DBGPROP_ATTRIB_FLAGS GetTypeAttribute() override { return DBGPROP_ATTRIB_VALUE_READONLY | DBGPROP_ATTRIB_VALUE_IS_FAKE | (HasChildren() ? DBGPROP_ATTRIB_VALUE_IS_EXPANDABLE : 0); }
  656. virtual WeakArenaReference<IDiagObjectModelWalkerBase>* CreateWalker() override;
  657. virtual Var GetVarValue(BOOL fUpdated) override { return nullptr; }
  658. virtual IDiagObjectAddress * GetDiagAddress() override { return nullptr; }
  659. virtual DiagObjectModelDisplayType GetType() { return DiagObjectModelDisplayType_RecyclableCollectionObjectDisplay; }
  660. virtual bool IsLiteralProperty() const { return false; }
  661. };
  662. class RecyclableKeyValueDisplay : public IDiagObjectModelDisplay
  663. {
  664. ScriptContext* scriptContext;
  665. Var key;
  666. Var value;
  667. const char16* name;
  668. public:
  669. RecyclableKeyValueDisplay(ScriptContext* scriptContext, Var key, Var value, const char16* name) : scriptContext(scriptContext), key(key), value(value), name(name) { }
  670. virtual LPCWSTR Name() override { return name; }
  671. virtual LPCWSTR Type() override { return _u(""); }
  672. virtual LPCWSTR Value(int radix) override;
  673. virtual BOOL HasChildren() override { return TRUE; }
  674. virtual BOOL Set(Var updateObject) override { return FALSE; }
  675. virtual DBGPROP_ATTRIB_FLAGS GetTypeAttribute() override { return DBGPROP_ATTRIB_VALUE_IS_EXPANDABLE | DBGPROP_ATTRIB_VALUE_IS_FAKE | DBGPROP_ATTRIB_VALUE_READONLY; }
  676. virtual WeakArenaReference<IDiagObjectModelWalkerBase>* CreateWalker() override;
  677. virtual DiagObjectModelDisplayType GetType() { return DiagObjectModelDisplayType_RecyclableKeyValueDisplay; }
  678. virtual bool IsLiteralProperty() const { return false; }
  679. };
  680. class RecyclableKeyValueWalker : public IDiagObjectModelWalkerBase
  681. {
  682. ScriptContext* scriptContext;
  683. Var key;
  684. Var value;
  685. public:
  686. RecyclableKeyValueWalker(ScriptContext* scriptContext, Var key, Var value):scriptContext(scriptContext), key(key), value(value) { }
  687. virtual BOOL Get(int i, ResolvedObject* pResolvedObject) override;
  688. // Children count is 2 for 'key' and 'value'
  689. virtual uint32 GetChildrenCount() override { return 2; }
  690. virtual BOOL GetGroupObject(ResolvedObject* pResolvedObject) override { return FALSE; }
  691. };
  692. class RecyclableProxyObjectDisplay : public RecyclableObjectDisplay
  693. {
  694. public:
  695. RecyclableProxyObjectDisplay(ResolvedObject* resolvedObject);
  696. virtual BOOL HasChildren() override { return TRUE; }
  697. virtual WeakArenaReference<IDiagObjectModelWalkerBase>* CreateWalker() override;
  698. };
  699. class RecyclableProxyObjectWalker : public RecyclableObjectWalker
  700. {
  701. public:
  702. RecyclableProxyObjectWalker(ScriptContext* pContext, Var instance);
  703. virtual BOOL Get(int i, ResolvedObject* pResolvedObject) override;
  704. // Children count is 2 for '[target]' and '[handler]'
  705. virtual uint32 GetChildrenCount() override { return 2; }
  706. virtual BOOL GetGroupObject(ResolvedObject* pResolvedObject) override;
  707. };
  708. class RecyclablePromiseObjectDisplay : public RecyclableObjectDisplay
  709. {
  710. public:
  711. RecyclablePromiseObjectDisplay(ResolvedObject* resolvedObject);
  712. virtual BOOL HasChildren() override { return TRUE; }
  713. virtual WeakArenaReference<IDiagObjectModelWalkerBase>* CreateWalker() override;
  714. };
  715. class RecyclablePromiseObjectWalker : public RecyclableObjectWalker
  716. {
  717. public:
  718. RecyclablePromiseObjectWalker(ScriptContext* pContext, Var instance);
  719. virtual BOOL Get(int i, ResolvedObject* pResolvedObject) override;
  720. // Children count is 2 for '[status]' and '[value]'
  721. virtual uint32 GetChildrenCount() override { return 2; }
  722. virtual BOOL GetGroupObject(ResolvedObject* pResolvedObject) override;
  723. };
  724. // Concrete classes for Methods group object
  725. //
  726. class RecyclableMethodsGroupWalker : public RecyclableObjectWalker
  727. {
  728. public:
  729. RecyclableMethodsGroupWalker(ScriptContext* pContext, Var slot);
  730. void AddItem(Js::PropertyId propertyId, Var obj);
  731. virtual BOOL Get(int i, ResolvedObject* pResolvedObject) override;
  732. virtual uint32 GetChildrenCount() override;
  733. virtual BOOL GetGroupObject(ResolvedObject* pResolvedObject) override;
  734. void Sort();
  735. };
  736. class RecyclableMethodsGroupDisplay : public RecyclableObjectDisplay
  737. {
  738. public:
  739. RecyclableMethodsGroupWalker *methodGroupWalker;
  740. RecyclableMethodsGroupDisplay(RecyclableMethodsGroupWalker *_methodGroupWalker, ResolvedObject* resolvedObject);
  741. virtual LPCWSTR Type() override;
  742. virtual LPCWSTR Value(int radix) override;
  743. virtual BOOL HasChildren() override;
  744. virtual DBGPROP_ATTRIB_FLAGS GetTypeAttribute() override;
  745. virtual WeakArenaReference<IDiagObjectModelWalkerBase>* CreateWalker() override;
  746. };
  747. // Concrete classes for Scope group object
  748. //
  749. class ScopeVariablesGroupDisplay : public RecyclableObjectDisplay
  750. {
  751. public:
  752. VariableWalkerBase *scopeGroupWalker;
  753. ScopeVariablesGroupDisplay(VariableWalkerBase *walker, ResolvedObject* resolvedObject);
  754. virtual LPCWSTR Type() override;
  755. virtual LPCWSTR Value(int radix) override;
  756. virtual BOOL HasChildren() override;
  757. virtual DBGPROP_ATTRIB_FLAGS GetTypeAttribute() override;
  758. virtual WeakArenaReference<IDiagObjectModelWalkerBase>* CreateWalker() override;
  759. };
  760. // Concrete classes for Globals group object
  761. //
  762. class GlobalsScopeVariablesGroupDisplay sealed : public RecyclableObjectDisplay
  763. {
  764. public:
  765. VariableWalkerBase *globalsGroupWalker;
  766. GlobalsScopeVariablesGroupDisplay(VariableWalkerBase *walker, ResolvedObject* resolvedObject);
  767. virtual LPCWSTR Type() override;
  768. virtual LPCWSTR Value(int radix) override;
  769. virtual BOOL HasChildren() override;
  770. virtual DBGPROP_ATTRIB_FLAGS GetTypeAttribute() override;
  771. virtual WeakArenaReference<IDiagObjectModelWalkerBase>* CreateWalker() override;
  772. };
  773. #ifdef ENABLE_MUTATION_BREAKPOINT
  774. // For Pending Mutation breakpoint
  775. class PendingMutationBreakpointDisplay : public RecyclableObjectDisplay
  776. {
  777. MutationType mutationType;
  778. public:
  779. PendingMutationBreakpointDisplay(ResolvedObject* resolvedObject, MutationType mutationType);
  780. virtual LPCWSTR Value(int radix) override { return _u(""); }
  781. virtual BOOL HasChildren() override { return TRUE; }
  782. virtual WeakArenaReference<IDiagObjectModelWalkerBase>* CreateWalker() override;
  783. };
  784. class PendingMutationBreakpointWalker : public RecyclableObjectWalker
  785. {
  786. MutationType mutationType;
  787. public:
  788. PendingMutationBreakpointWalker(ScriptContext* pContext, Var instance, MutationType mutationType);
  789. virtual BOOL Get(int i, ResolvedObject* pResolvedObject) override;
  790. virtual uint32 GetChildrenCount() override;
  791. };
  792. #endif
  793. }