DiagObjectModel.cpp 171 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404
  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. #include "RuntimeDebugPch.h"
  6. // Parser includes
  7. #include "CharClassifier.h"
  8. // TODO: clean up the need of these regex related header here just for GroupInfo needed in JavascriptRegExpConstructor
  9. #include "RegexCommon.h"
  10. // Runtime includes
  11. #include "Library/ObjectPrototypeObject.h"
  12. #include "Library/JavascriptNumberObject.h"
  13. #include "Library/BoundFunction.h"
  14. #include "Library/JavascriptRegExpConstructor.h"
  15. #include "Library/SameValueComparer.h"
  16. #include "Library/MapOrSetDataList.h"
  17. #include "Library/JavascriptPromise.h"
  18. #include "Library/JavascriptProxy.h"
  19. #include "Library/JavascriptMap.h"
  20. #include "Library/JavascriptSet.h"
  21. #include "Library/JavascriptWeakMap.h"
  22. #include "Library/JavascriptWeakSet.h"
  23. #include "Library/ArgumentsObject.h"
  24. #include "Types/DynamicObjectPropertyEnumerator.h"
  25. #include "Types/JavascriptStaticEnumerator.h"
  26. #include "Library/ForInObjectEnumerator.h"
  27. #include "Library/ES5Array.h"
  28. #include "Library/SimdLib.h"
  29. namespace Js
  30. {
  31. #define RETURN_VALUE_MAX_NAME 255
  32. #define PENDING_MUTATION_VALUE_MAX_NAME 255
  33. ArenaAllocator *GetArenaFromContext(ScriptContext *scriptContext)
  34. {
  35. Assert(scriptContext);
  36. return scriptContext->GetThreadContext()->GetDebugManager()->GetDiagnosticArena()->Arena();
  37. }
  38. template <class T>
  39. WeakArenaReference<IDiagObjectModelWalkerBase>* CreateAWalker(ScriptContext * scriptContext, Var instance, Var originalInstance)
  40. {
  41. ReferencedArenaAdapter* pRefArena = scriptContext->GetThreadContext()->GetDebugManager()->GetDiagnosticArena();
  42. if (pRefArena)
  43. {
  44. IDiagObjectModelWalkerBase* pOMWalker = Anew(pRefArena->Arena(), T, scriptContext, instance, originalInstance);
  45. return HeapNew(WeakArenaReference<IDiagObjectModelWalkerBase>,pRefArena, pOMWalker);
  46. }
  47. return nullptr;
  48. }
  49. //-----------------------
  50. // ResolvedObject
  51. WeakArenaReference<IDiagObjectModelDisplay>* ResolvedObject::GetObjectDisplay()
  52. {
  53. AssertMsg(typeId != TypeIds_HostDispatch, "Bad usage of ResolvedObject::GetObjectDisplay");
  54. IDiagObjectModelDisplay* pOMDisplay = (this->objectDisplay != nullptr) ? this->objectDisplay : CreateDisplay();
  55. Assert(pOMDisplay);
  56. return HeapNew(WeakArenaReference<IDiagObjectModelDisplay>, scriptContext->GetThreadContext()->GetDebugManager()->GetDiagnosticArena(), pOMDisplay);
  57. }
  58. IDiagObjectModelDisplay * ResolvedObject::CreateDisplay()
  59. {
  60. IDiagObjectModelDisplay* pOMDisplay = nullptr;
  61. ReferencedArenaAdapter* pRefArena = scriptContext->GetThreadContext()->GetDebugManager()->GetDiagnosticArena();
  62. if (Js::TypedArrayBase::Is(obj))
  63. {
  64. pOMDisplay = Anew(pRefArena->Arena(), RecyclableTypedArrayDisplay, this);
  65. }
  66. else if (Js::ES5Array::Is(obj))
  67. {
  68. pOMDisplay = Anew(pRefArena->Arena(), RecyclableES5ArrayDisplay, this);
  69. }
  70. else if (Js::JavascriptArray::Is(obj))
  71. {
  72. // DisableJIT-TODO: Review- is this correct?
  73. #if ENABLE_COPYONACCESS_ARRAY
  74. // Make sure any NativeIntArrays are converted
  75. Js::JavascriptLibrary::CheckAndConvertCopyOnAccessNativeIntArray<Var>(obj);
  76. #endif
  77. pOMDisplay = Anew(pRefArena->Arena(), RecyclableArrayDisplay, this);
  78. }
  79. #ifdef ENABLE_SIMDJS
  80. else if (Js::JavascriptSIMDInt32x4::Is(obj))
  81. {
  82. pOMDisplay = Anew(pRefArena->Arena(), RecyclableSimdInt32x4ObjectDisplay, this);
  83. }
  84. else if (Js::JavascriptSIMDFloat32x4::Is(obj))
  85. {
  86. pOMDisplay = Anew(pRefArena->Arena(), RecyclableSimdFloat32x4ObjectDisplay, this);
  87. }
  88. else if (Js::JavascriptSIMDInt8x16::Is(obj))
  89. {
  90. pOMDisplay = Anew(pRefArena->Arena(), RecyclableSimdInt8x16ObjectDisplay, this);
  91. }
  92. else if (Js::JavascriptSIMDInt16x8::Is(obj))
  93. {
  94. pOMDisplay = Anew(pRefArena->Arena(), RecyclableSimdInt16x8ObjectDisplay, this);
  95. }
  96. else if (Js::JavascriptSIMDBool32x4::Is(obj))
  97. {
  98. pOMDisplay = Anew(pRefArena->Arena(), RecyclableSimdBool32x4ObjectDisplay, this);
  99. }
  100. else if (Js::JavascriptSIMDBool8x16::Is(obj))
  101. {
  102. pOMDisplay = Anew(pRefArena->Arena(), RecyclableSimdBool8x16ObjectDisplay, this);
  103. }
  104. else if (Js::JavascriptSIMDBool16x8::Is(obj))
  105. {
  106. pOMDisplay = Anew(pRefArena->Arena(), RecyclableSimdBool16x8ObjectDisplay, this);
  107. }
  108. else if (Js::JavascriptSIMDUint32x4::Is(obj))
  109. {
  110. pOMDisplay = Anew(pRefArena->Arena(), RecyclableSimdUint32x4ObjectDisplay, this);
  111. }
  112. else if (Js::JavascriptSIMDUint8x16::Is(obj))
  113. {
  114. pOMDisplay = Anew(pRefArena->Arena(), RecyclableSimdUint8x16ObjectDisplay, this);
  115. }
  116. else if (Js::JavascriptSIMDUint16x8::Is(obj))
  117. {
  118. pOMDisplay = Anew(pRefArena->Arena(), RecyclableSimdUint16x8ObjectDisplay, this);
  119. }
  120. #endif
  121. else
  122. {
  123. pOMDisplay = Anew(pRefArena->Arena(), RecyclableObjectDisplay, this);
  124. }
  125. if (this->isConst || this->propId == Js::PropertyIds::_super || this->propId == Js::PropertyIds::_superConstructor)
  126. {
  127. pOMDisplay->SetDefaultTypeAttribute(DBGPROP_ATTRIB_VALUE_READONLY);
  128. }
  129. return pOMDisplay;
  130. }
  131. bool ResolvedObject::IsInDeadZone() const
  132. {
  133. Assert(scriptContext);
  134. return this->obj == scriptContext->GetLibrary()->GetDebuggerDeadZoneBlockVariableString();
  135. }
  136. //-----------------------
  137. // LocalsDisplay
  138. LocalsDisplay::LocalsDisplay(DiagStackFrame* _frame)
  139. : pFrame(_frame)
  140. {
  141. }
  142. LPCWSTR LocalsDisplay::Name()
  143. {
  144. return _u("Locals");
  145. }
  146. LPCWSTR LocalsDisplay::Type()
  147. {
  148. return _u("");
  149. }
  150. LPCWSTR LocalsDisplay::Value(int radix)
  151. {
  152. return _u("Locals");
  153. }
  154. BOOL LocalsDisplay::HasChildren()
  155. {
  156. Js::JavascriptFunction* func = pFrame->GetJavascriptFunction();
  157. FunctionBody* function = func->GetFunctionBody();
  158. return function && function->GetLocalsCount() != 0;
  159. }
  160. DBGPROP_ATTRIB_FLAGS LocalsDisplay::GetTypeAttribute()
  161. {
  162. return DBGPROP_ATTRIB_NO_ATTRIB;
  163. }
  164. BOOL LocalsDisplay::Set(Var updateObject)
  165. {
  166. // This is the hidden root object for Locals it doesn't get updated.
  167. return FALSE;
  168. }
  169. WeakArenaReference<IDiagObjectModelWalkerBase>* LocalsDisplay::CreateWalker()
  170. {
  171. ReferencedArenaAdapter* pRefArena = pFrame->GetScriptContext()->GetThreadContext()->GetDebugManager()->GetDiagnosticArena();
  172. if (pRefArena)
  173. {
  174. IDiagObjectModelWalkerBase * pOMWalker = nullptr;
  175. IGNORE_STACKWALK_EXCEPTION(scriptContext);
  176. pOMWalker = Anew(pRefArena->Arena(), LocalsWalker, pFrame, FrameWalkerFlags::FW_MakeGroups);
  177. return HeapNew(WeakArenaReference<IDiagObjectModelWalkerBase>,pRefArena, pOMWalker);
  178. }
  179. return nullptr;
  180. }
  181. // Variables on the scope or in current function.
  182. /*static*/
  183. BOOL VariableWalkerBase::GetExceptionObject(int &index, DiagStackFrame* frame, ResolvedObject* pResolvedObject)
  184. {
  185. Assert(pResolvedObject);
  186. Assert(pResolvedObject->scriptContext);
  187. Assert(frame);
  188. Assert(index >= 0);
  189. if (HasExceptionObject(frame))
  190. {
  191. if (index == 0)
  192. {
  193. pResolvedObject->name = _u("{exception}");
  194. pResolvedObject->typeId = TypeIds_Error;
  195. pResolvedObject->address = nullptr;
  196. pResolvedObject->obj = pResolvedObject->scriptContext->GetDebugContext()->GetProbeContainer()->GetExceptionObject();
  197. if (pResolvedObject->obj == nullptr)
  198. {
  199. Assert(false);
  200. pResolvedObject->obj = pResolvedObject->scriptContext->GetLibrary()->GetUndefined();
  201. }
  202. return TRUE;
  203. }
  204. // Adjust the index
  205. index -= 1;
  206. }
  207. return FALSE;
  208. }
  209. /*static*/
  210. bool VariableWalkerBase::HasExceptionObject(DiagStackFrame* frame)
  211. {
  212. Assert(frame);
  213. Assert(frame->GetScriptContext());
  214. return frame->GetScriptContext()->GetDebugContext()->GetProbeContainer()->GetExceptionObject() != nullptr;
  215. }
  216. /*static*/
  217. void VariableWalkerBase::GetReturnedValueResolvedObject(ReturnedValue * returnValue, DiagStackFrame* frame, ResolvedObject* pResolvedObject)
  218. {
  219. DBGPROP_ATTRIB_FLAGS defaultAttributes = DBGPROP_ATTRIB_VALUE_IS_RETURN_VALUE | DBGPROP_ATTRIB_VALUE_IS_FAKE;
  220. WCHAR * finalName = AnewArray(GetArenaFromContext(pResolvedObject->scriptContext), WCHAR, RETURN_VALUE_MAX_NAME);
  221. if (returnValue->isValueOfReturnStatement)
  222. {
  223. swprintf_s(finalName, RETURN_VALUE_MAX_NAME, _u("[Return value]"));
  224. pResolvedObject->obj = frame->GetRegValue(Js::FunctionBody::ReturnValueRegSlot);
  225. pResolvedObject->address = Anew(frame->GetArena(), LocalObjectAddressForRegSlot, frame, Js::FunctionBody::ReturnValueRegSlot, pResolvedObject->obj);
  226. }
  227. else
  228. {
  229. if (returnValue->calledFunction->IsScriptFunction())
  230. {
  231. swprintf_s(finalName, RETURN_VALUE_MAX_NAME, _u("[%s returned]"), returnValue->calledFunction->GetFunctionBody()->GetDisplayName());
  232. }
  233. else
  234. {
  235. Js::JavascriptString *builtInName = ParseFunctionName(returnValue->calledFunction->GetDisplayName(), pResolvedObject->scriptContext);
  236. swprintf_s(finalName, RETURN_VALUE_MAX_NAME, _u("[%s returned]"), builtInName->GetSz());
  237. }
  238. pResolvedObject->obj = returnValue->returnedValue;
  239. defaultAttributes |= DBGPROP_ATTRIB_VALUE_READONLY;
  240. pResolvedObject->address = nullptr;
  241. }
  242. Assert(pResolvedObject->obj != nullptr);
  243. pResolvedObject->name = finalName;
  244. pResolvedObject->typeId = TypeIds_Object;
  245. pResolvedObject->objectDisplay = pResolvedObject->CreateDisplay();
  246. pResolvedObject->objectDisplay->SetDefaultTypeAttribute(defaultAttributes);
  247. }
  248. // The debugger uses the functionNameId field instead of the "name" property to get the name of the funtion. The functionNameId field is overloaded and may contain the display name if
  249. // toString() has been called on the function object. For built-in or external functions the display name can be something like "function Echo() { native code }". We will try to parse the
  250. // function name out of the display name so the user will see just the function name e.g. "Echo" instead of the full display name in debugger.
  251. JavascriptString * VariableWalkerBase::ParseFunctionName(JavascriptString* displayName, ScriptContext* scriptContext)
  252. {
  253. Assert(displayName);
  254. const char16 * displayNameBuffer = displayName->GetString();
  255. const charcount_t displayNameBufferLength = displayName->GetLength();
  256. const charcount_t funcStringLength = _countof(JS_DISPLAY_STRING_FUNCTION_HEADER) - 1; // discount the ending null character in string literal
  257. const charcount_t templateStringLength = funcStringLength + _countof(JS_DISPLAY_STRING_FUNCTION_BODY) - 1; // discount the ending null character in string literal
  258. // If the string doesn't meet our expected format; return the original string.
  259. if (displayNameBufferLength <= templateStringLength || (wmemcmp(displayNameBuffer, JS_DISPLAY_STRING_FUNCTION_HEADER, funcStringLength) != 0))
  260. {
  261. return displayName;
  262. }
  263. // Look for the left parenthesis, if we don't find one; return the original string.
  264. const char16* parenChar = wcschr(displayNameBuffer, '(');
  265. if (parenChar == nullptr)
  266. {
  267. return displayName;
  268. }
  269. charcount_t actualFunctionNameLength = displayNameBufferLength - templateStringLength;
  270. uint byteLengthForCopy = sizeof(char16) * actualFunctionNameLength;
  271. char16 * actualFunctionNameBuffer = AnewArray(GetArenaFromContext(scriptContext), char16, actualFunctionNameLength + 1); // The last character will be the null character.
  272. if (actualFunctionNameBuffer == nullptr)
  273. {
  274. return displayName;
  275. }
  276. js_memcpy_s(actualFunctionNameBuffer, byteLengthForCopy, displayNameBuffer + funcStringLength, byteLengthForCopy);
  277. actualFunctionNameBuffer[actualFunctionNameLength] = _u('\0');
  278. JavascriptString * actualFunctionName = JavascriptString::NewWithArenaSz(actualFunctionNameBuffer, scriptContext);
  279. if (actualFunctionName == nullptr)
  280. {
  281. return displayName;
  282. }
  283. return actualFunctionName;
  284. }
  285. /*static*/
  286. BOOL VariableWalkerBase::GetReturnedValue(int &index, DiagStackFrame* frame, ResolvedObject* pResolvedObject)
  287. {
  288. Assert(pResolvedObject);
  289. Assert(pResolvedObject->scriptContext);
  290. Assert(frame);
  291. Assert(index >= 0);
  292. ReturnedValueList *returnedValueList = frame->GetScriptContext()->GetDebugContext()->GetProbeContainer()->GetReturnedValueList();
  293. if (returnedValueList != nullptr && returnedValueList->Count() > 0 && frame->IsTopFrame())
  294. {
  295. if (index < returnedValueList->Count())
  296. {
  297. ReturnedValue * returnValue = returnedValueList->Item(index);
  298. VariableWalkerBase::GetReturnedValueResolvedObject(returnValue, frame, pResolvedObject);
  299. return TRUE;
  300. }
  301. // Adjust the index
  302. index -= returnedValueList->Count();
  303. }
  304. return FALSE;
  305. }
  306. /*static*/
  307. int VariableWalkerBase::GetReturnedValueCount(DiagStackFrame* frame)
  308. {
  309. Assert(frame);
  310. Assert(frame->GetScriptContext());
  311. ReturnedValueList *returnedValueList = frame->GetScriptContext()->GetDebugContext()->GetProbeContainer()->GetReturnedValueList();
  312. return returnedValueList != nullptr && frame->IsTopFrame() ? returnedValueList->Count() : 0;
  313. }
  314. #ifdef ENABLE_MUTATION_BREAKPOINT
  315. BOOL VariableWalkerBase::GetBreakMutationBreakpointValue(int &index, DiagStackFrame* frame, ResolvedObject* pResolvedObject)
  316. {
  317. Assert(pResolvedObject);
  318. Assert(pResolvedObject->scriptContext);
  319. Assert(frame);
  320. Assert(index >= 0);
  321. Js::MutationBreakpoint *mutationBreakpoint = frame->GetScriptContext()->GetDebugContext()->GetProbeContainer()->GetDebugManager()->GetActiveMutationBreakpoint();
  322. if (mutationBreakpoint != nullptr)
  323. {
  324. if (index == 0)
  325. {
  326. pResolvedObject->name = _u("[Pending Mutation]");
  327. pResolvedObject->typeId = TypeIds_Object;
  328. pResolvedObject->address = nullptr;
  329. pResolvedObject->obj = mutationBreakpoint->GetMutationObjectVar();
  330. ReferencedArenaAdapter* pRefArena = pResolvedObject->scriptContext->GetThreadContext()->GetDebugManager()->GetDiagnosticArena();
  331. pResolvedObject->objectDisplay = Anew(pRefArena->Arena(), PendingMutationBreakpointDisplay, pResolvedObject, mutationBreakpoint->GetBreakMutationType());
  332. pResolvedObject->objectDisplay->SetDefaultTypeAttribute(DBGPROP_ATTRIB_VALUE_PENDING_MUTATION | DBGPROP_ATTRIB_VALUE_READONLY | DBGPROP_ATTRIB_VALUE_IS_FAKE);
  333. return TRUE;
  334. }
  335. index -= 1; // Adjust the index
  336. }
  337. return FALSE;
  338. }
  339. uint VariableWalkerBase::GetBreakMutationBreakpointsCount(DiagStackFrame* frame)
  340. {
  341. Assert(frame);
  342. Assert(frame->GetScriptContext());
  343. return frame->GetScriptContext()->GetDebugContext()->GetProbeContainer()->GetDebugManager()->GetActiveMutationBreakpoint() != nullptr ? 1 : 0;
  344. }
  345. #endif
  346. BOOL VariableWalkerBase::Get(int i, ResolvedObject* pResolvedObject)
  347. {
  348. AssertMsg(pResolvedObject, "Bad usage of VariableWalkerBase::Get");
  349. Assert(pFrame);
  350. pResolvedObject->scriptContext = pFrame->GetScriptContext();
  351. if (i < 0)
  352. {
  353. return FALSE;
  354. }
  355. if (GetMemberCount() > i)
  356. {
  357. pResolvedObject->propId = pMembersList->Item(i)->propId;
  358. Assert(pResolvedObject->propId != Js::Constants::NoProperty);
  359. Assert(!Js::IsInternalPropertyId(pResolvedObject->propId));
  360. if (pResolvedObject->propId == Js::PropertyIds::_super || pResolvedObject->propId == Js::PropertyIds::_superConstructor)
  361. {
  362. pResolvedObject->name = _u("super");
  363. }
  364. else
  365. {
  366. const Js::PropertyRecord* propertyRecord = pResolvedObject->scriptContext->GetPropertyName(pResolvedObject->propId);
  367. pResolvedObject->name = propertyRecord->GetBuffer();
  368. }
  369. pResolvedObject->obj = GetVarObjectAt(i);
  370. Assert(pResolvedObject->obj);
  371. pResolvedObject->typeId = JavascriptOperators::GetTypeId(pResolvedObject->obj);
  372. pResolvedObject->address = GetObjectAddress(i);
  373. pResolvedObject->isConst = IsConstAt(i);
  374. pResolvedObject->objectDisplay = nullptr;
  375. return TRUE;
  376. }
  377. return FALSE;
  378. }
  379. Var VariableWalkerBase::GetVarObjectAt(int index)
  380. {
  381. Assert(index < pMembersList->Count());
  382. return pMembersList->Item(index)->aVar;
  383. }
  384. bool VariableWalkerBase::IsConstAt(int index)
  385. {
  386. Assert(index < pMembersList->Count());
  387. DebuggerPropertyDisplayInfo* displayInfo = pMembersList->Item(index);
  388. // Dead zone variables are also displayed as read only.
  389. return displayInfo->IsConst() || displayInfo->IsInDeadZone();
  390. }
  391. uint32 VariableWalkerBase::GetChildrenCount()
  392. {
  393. PopulateMembers();
  394. return GetMemberCount();
  395. }
  396. BOOL VariableWalkerBase::GetGroupObject(ResolvedObject* pResolvedObject)
  397. {
  398. if (!IsInGroup()) return FALSE;
  399. Assert(pResolvedObject);
  400. // This is fake [Methods] object.
  401. pResolvedObject->name = groupType == UIGroupType_Scope ? _u("[Scope]") : _u("[Globals]");
  402. pResolvedObject->obj = Js::RecyclableObject::FromVar(instance);
  403. pResolvedObject->typeId = TypeIds_Function;
  404. pResolvedObject->address = nullptr; // Scope object should not be editable
  405. ArenaAllocator *arena = GetArenaFromContext(pResolvedObject->scriptContext);
  406. Assert(arena);
  407. if (groupType == UIGroupType_Scope)
  408. {
  409. pResolvedObject->objectDisplay = Anew(arena, ScopeVariablesGroupDisplay, this, pResolvedObject);
  410. }
  411. else
  412. {
  413. pResolvedObject->objectDisplay = Anew(arena, GlobalsScopeVariablesGroupDisplay, this, pResolvedObject);
  414. }
  415. return TRUE;
  416. }
  417. IDiagObjectAddress *VariableWalkerBase::FindPropertyAddress(PropertyId propId, bool& isConst)
  418. {
  419. PopulateMembers();
  420. if (pMembersList)
  421. {
  422. for (int i = 0; i < pMembersList->Count(); i++)
  423. {
  424. DebuggerPropertyDisplayInfo *pair = pMembersList->Item(i);
  425. Assert(pair);
  426. if (pair->propId == propId)
  427. {
  428. isConst = pair->IsConst();
  429. return GetObjectAddress(i);
  430. }
  431. }
  432. }
  433. return nullptr;
  434. }
  435. // Determines if the given property is valid for display in the locals window.
  436. // Cases in which the property is valid are:
  437. // 1. It is not represented by an internal property.
  438. // 2. It is a var property.
  439. // 3. It is a let/const property in scope and is not in a dead zone (assuming isInDeadZone is nullptr).
  440. // (Determines if the given property is currently in block scope and not in a dead zone.)
  441. bool VariableWalkerBase::IsPropertyValid(PropertyId propertyId, RegSlot location, bool *isPropertyInDebuggerScope, bool* isConst, bool* isInDeadZone) const
  442. {
  443. Assert(isPropertyInDebuggerScope);
  444. Assert(isConst);
  445. *isPropertyInDebuggerScope = false;
  446. // Default to writable (for the case of vars and internal properties).
  447. *isConst = false;
  448. if (!allowLexicalThis && (propertyId == Js::PropertyIds::_this || propertyId == Js::PropertyIds::_newTarget))
  449. {
  450. return false;
  451. }
  452. if (!allowSuperReference && (propertyId == Js::PropertyIds::_super || propertyId == Js::PropertyIds::_superConstructor))
  453. {
  454. return false;
  455. }
  456. if (Js::IsInternalPropertyId(propertyId))
  457. {
  458. return false;
  459. }
  460. Assert(pFrame);
  461. Js::FunctionBody *pFBody = pFrame->GetJavascriptFunction()->GetFunctionBody();
  462. if (pFBody && pFBody->GetScopeObjectChain())
  463. {
  464. int offset = GetAdjustedByteCodeOffset();
  465. if (pFBody->GetScopeObjectChain()->TryGetDebuggerScopePropertyInfo(
  466. propertyId,
  467. location,
  468. offset,
  469. isPropertyInDebuggerScope,
  470. isConst,
  471. isInDeadZone))
  472. {
  473. return true;
  474. }
  475. }
  476. // If the register was not found in any scopes, then it's a var and should be in scope.
  477. return !*isPropertyInDebuggerScope;
  478. }
  479. int VariableWalkerBase::GetAdjustedByteCodeOffset() const
  480. {
  481. return LocalsWalker::GetAdjustedByteCodeOffset(pFrame);
  482. }
  483. DebuggerScope * VariableWalkerBase::GetScopeWhenHaltAtFormals()
  484. {
  485. if (IsWalkerForCurrentFrame())
  486. {
  487. return LocalsWalker::GetScopeWhenHaltAtFormals(pFrame);
  488. }
  489. return nullptr;
  490. }
  491. bool VariableWalkerBase::IsInParamScope(DebuggerScope* scope, DiagStackFrame* pFrame)
  492. {
  493. return scope != nullptr && scope->GetEnd() > LocalsWalker::GetAdjustedByteCodeOffset(pFrame);
  494. }
  495. // Allocates and returns a property display info.
  496. DebuggerPropertyDisplayInfo* VariableWalkerBase::AllocateNewPropertyDisplayInfo(PropertyId propertyId, Var value, bool isConst, bool isInDeadZone)
  497. {
  498. Assert(pFrame);
  499. Assert(value);
  500. Assert(isInDeadZone || !pFrame->GetScriptContext()->IsUndeclBlockVar(value));
  501. DWORD flags = DebuggerPropertyDisplayInfoFlags_None;
  502. flags |= isConst ? DebuggerPropertyDisplayInfoFlags_Const : 0;
  503. flags |= isInDeadZone ? DebuggerPropertyDisplayInfoFlags_InDeadZone : 0;
  504. ArenaAllocator *arena = pFrame->GetArena();
  505. if (isInDeadZone)
  506. {
  507. value = pFrame->GetScriptContext()->GetLibrary()->GetDebuggerDeadZoneBlockVariableString();
  508. }
  509. return Anew(arena, DebuggerPropertyDisplayInfo, propertyId, value, flags);
  510. }
  511. /// Slot array
  512. void SlotArrayVariablesWalker::PopulateMembers()
  513. {
  514. if (pMembersList == nullptr && instance != nullptr)
  515. {
  516. ArenaAllocator *arena = pFrame->GetArena();
  517. ScopeSlots slotArray = GetSlotArray();
  518. if (slotArray.IsFunctionScopeSlotArray())
  519. {
  520. DebuggerScope *formalScope = GetScopeWhenHaltAtFormals();
  521. bool isInParamScope = IsInParamScope(formalScope, pFrame);
  522. Js::FunctionBody *pFBody = slotArray.GetFunctionInfo()->GetFunctionBody();
  523. if (this->groupType & UIGroupType_Param)
  524. {
  525. Assert(formalScope != nullptr && pFBody->paramScopeSlotArraySize > 0);
  526. uint slotArrayCount = pFBody->paramScopeSlotArraySize;
  527. pMembersList = JsUtil::List<DebuggerPropertyDisplayInfo *, ArenaAllocator>::New(arena, slotArrayCount);
  528. for (uint32 i = 0; i < slotArrayCount; i++)
  529. {
  530. Js::DebuggerScopeProperty scopeProperty = formalScope->scopeProperties->Item(i);
  531. Var value = slotArray.Get(i);
  532. bool isInDeadZone = pFrame->GetScriptContext()->IsUndeclBlockVar(value);
  533. DebuggerPropertyDisplayInfo *pair = AllocateNewPropertyDisplayInfo(
  534. scopeProperty.propId,
  535. value,
  536. false/*isConst*/,
  537. isInDeadZone);
  538. Assert(pair != nullptr);
  539. pMembersList->Add(pair);
  540. }
  541. }
  542. else if (pFBody->GetPropertyIdsForScopeSlotArray() != nullptr)
  543. {
  544. uint slotArrayCount = static_cast<uint>(slotArray.GetCount());
  545. pMembersList = JsUtil::List<DebuggerPropertyDisplayInfo *, ArenaAllocator>::New(arena, slotArrayCount);
  546. for (uint32 i = 0; i < slotArrayCount; i++)
  547. {
  548. Js::PropertyId propertyId = pFBody->GetPropertyIdsForScopeSlotArray()[i];
  549. bool isConst = false;
  550. bool isPropertyInDebuggerScope = false;
  551. bool isInDeadZone = false;
  552. if (propertyId != Js::Constants::NoProperty && IsPropertyValid(propertyId, i, &isPropertyInDebuggerScope, &isConst, &isInDeadZone))
  553. {
  554. if (!isInParamScope || formalScope->HasProperty(propertyId))
  555. {
  556. Var value = slotArray.Get(i);
  557. if (pFrame->GetScriptContext()->IsUndeclBlockVar(value))
  558. {
  559. isInDeadZone = true;
  560. }
  561. DebuggerPropertyDisplayInfo *pair = AllocateNewPropertyDisplayInfo(
  562. propertyId,
  563. value,
  564. isConst,
  565. isInDeadZone);
  566. Assert(pair != nullptr);
  567. pMembersList->Add(pair);
  568. }
  569. }
  570. }
  571. }
  572. }
  573. else
  574. {
  575. DebuggerScope* debuggerScope = slotArray.GetDebuggerScope();
  576. AssertMsg(debuggerScope, "Slot array debugger scope is missing but should be created.");
  577. pMembersList = JsUtil::List<DebuggerPropertyDisplayInfo *, ArenaAllocator>::New(arena);
  578. if (debuggerScope->HasProperties())
  579. {
  580. debuggerScope->scopeProperties->Map([&] (int i, Js::DebuggerScopeProperty& scopeProperty)
  581. {
  582. Var value = slotArray.Get(scopeProperty.location);
  583. bool isConst = scopeProperty.IsConst();
  584. bool isInDeadZone = false;
  585. if (pFrame->GetScriptContext()->IsUndeclBlockVar(value))
  586. {
  587. isInDeadZone = true;
  588. }
  589. DebuggerPropertyDisplayInfo *pair = AllocateNewPropertyDisplayInfo(
  590. scopeProperty.propId,
  591. value,
  592. isConst,
  593. isInDeadZone);
  594. Assert(pair != nullptr);
  595. pMembersList->Add(pair);
  596. });
  597. }
  598. }
  599. }
  600. }
  601. IDiagObjectAddress * SlotArrayVariablesWalker::GetObjectAddress(int index)
  602. {
  603. Assert(index < pMembersList->Count());
  604. ScopeSlots slotArray = GetSlotArray();
  605. return Anew(pFrame->GetArena(), LocalObjectAddressForSlot, slotArray, index, pMembersList->Item(index)->aVar);
  606. }
  607. // Regslot
  608. void RegSlotVariablesWalker::PopulateMembers()
  609. {
  610. if (pMembersList == nullptr)
  611. {
  612. Js::FunctionBody *pFBody = pFrame->GetJavascriptFunction()->GetFunctionBody();
  613. ArenaAllocator *arena = pFrame->GetArena();
  614. PropertyIdOnRegSlotsContainer *propIdContainer = pFBody->GetPropertyIdOnRegSlotsContainer();
  615. DebuggerScope *formalScope = GetScopeWhenHaltAtFormals();
  616. // this container can be nullptr if there is no locals in current function.
  617. if (propIdContainer != nullptr)
  618. {
  619. RegSlot limit = propIdContainer->formalsUpperBound == Js::Constants::NoRegister ? Js::Constants::NoRegister : pFBody->MapRegSlot(propIdContainer->formalsUpperBound);
  620. pMembersList = JsUtil::List<DebuggerPropertyDisplayInfo *, ArenaAllocator>::New(arena);
  621. for (uint i = 0; i < propIdContainer->length; i++)
  622. {
  623. Js::PropertyId propertyId;
  624. RegSlot reg;
  625. propIdContainer->FetchItemAt(i, pFBody, &propertyId, &reg);
  626. bool shouldInsert = false;
  627. bool isConst = false;
  628. bool isInDeadZone = false;
  629. if (this->debuggerScope)
  630. {
  631. DebuggerScopeProperty debuggerScopeProperty;
  632. if (this->debuggerScope->TryGetValidProperty(propertyId, reg, GetAdjustedByteCodeOffset(), &debuggerScopeProperty, &isInDeadZone))
  633. {
  634. isConst = debuggerScopeProperty.IsConst();
  635. shouldInsert = true;
  636. }
  637. }
  638. else
  639. {
  640. bool isPropertyInDebuggerScope = false;
  641. shouldInsert = IsPropertyValid(propertyId, reg, &isPropertyInDebuggerScope, &isConst, &isInDeadZone) && !isPropertyInDebuggerScope;
  642. }
  643. if (shouldInsert)
  644. {
  645. if (IsInParamScope(formalScope, pFrame))
  646. {
  647. if (limit != Js::Constants::NoRegister)
  648. {
  649. shouldInsert = reg <= limit;
  650. }
  651. else
  652. {
  653. shouldInsert = formalScope->HasProperty(propertyId);
  654. }
  655. }
  656. else if (!pFBody->IsParamAndBodyScopeMerged() && formalScope->HasProperty(propertyId))
  657. {
  658. DebuggerScopeProperty prop;
  659. prop.flags = DebuggerScopePropertyFlags_None;
  660. prop.propId = 0;
  661. formalScope->TryGetProperty(propertyId, reg, &prop);
  662. if (prop.flags & DebuggerScopePropertyFlags_HasDuplicateInBody)
  663. {
  664. shouldInsert = false;
  665. }
  666. }
  667. }
  668. if (shouldInsert)
  669. {
  670. Var value = pFrame->GetRegValue(reg);
  671. // If the user didn't supply an arguments object, a fake one will
  672. // be created when evaluating LocalsWalker::ShouldInsertFakeArguments().
  673. if (!(propertyId == PropertyIds::arguments && value == nullptr))
  674. {
  675. if (pFrame->GetScriptContext()->IsUndeclBlockVar(value))
  676. {
  677. isInDeadZone = true;
  678. }
  679. DebuggerPropertyDisplayInfo *info = AllocateNewPropertyDisplayInfo(
  680. propertyId,
  681. (Var)reg,
  682. isConst,
  683. isInDeadZone);
  684. Assert(info != nullptr);
  685. pMembersList->Add(info);
  686. }
  687. }
  688. }
  689. }
  690. }
  691. }
  692. Var RegSlotVariablesWalker::GetVarObjectAndRegAt(int index, RegSlot* reg /*= nullptr*/)
  693. {
  694. Assert(index < pMembersList->Count());
  695. Var returnedVar = nullptr;
  696. RegSlot returnedReg = Js::Constants::NoRegister;
  697. DebuggerPropertyDisplayInfo* displayInfo = pMembersList->Item(index);
  698. if (displayInfo->IsInDeadZone())
  699. {
  700. // The uninitialized string is already set in the var for the dead zone display.
  701. Assert(JavascriptString::Is(displayInfo->aVar));
  702. returnedVar = displayInfo->aVar;
  703. }
  704. else
  705. {
  706. returnedReg = ::Math::PointerCastToIntegral<RegSlot>(displayInfo->aVar);
  707. returnedVar = pFrame->GetRegValue(returnedReg);
  708. }
  709. if (reg != nullptr)
  710. {
  711. *reg = returnedReg;
  712. }
  713. AssertMsg(returnedVar, "Var should be replaced with the dead zone string object.");
  714. return returnedVar;
  715. }
  716. Var RegSlotVariablesWalker::GetVarObjectAt(int index)
  717. {
  718. return GetVarObjectAndRegAt(index);
  719. }
  720. IDiagObjectAddress * RegSlotVariablesWalker::GetObjectAddress(int index)
  721. {
  722. RegSlot reg = Js::Constants::NoRegister;
  723. Var obj = GetVarObjectAndRegAt(index, &reg);
  724. return Anew(pFrame->GetArena(), LocalObjectAddressForRegSlot, pFrame, reg, obj);
  725. }
  726. // For an activation object.
  727. void ObjectVariablesWalker::PopulateMembers()
  728. {
  729. if (pMembersList == nullptr && instance != nullptr)
  730. {
  731. ScriptContext * scriptContext = pFrame->GetScriptContext();
  732. ArenaAllocator *arena = GetArenaFromContext(scriptContext);
  733. Assert(Js::RecyclableObject::Is(instance));
  734. Js::RecyclableObject* object = Js::RecyclableObject::FromVar(instance);
  735. Assert(JavascriptOperators::IsObject(object));
  736. int count = object->GetPropertyCount();
  737. pMembersList = JsUtil::List<DebuggerPropertyDisplayInfo *, ArenaAllocator>::New(arena, count);
  738. AddObjectProperties(count, object);
  739. }
  740. }
  741. void ObjectVariablesWalker::AddObjectProperties(int count, Js::RecyclableObject* object)
  742. {
  743. ScriptContext * scriptContext = pFrame->GetScriptContext();
  744. DebuggerScope *formalScope = LocalsWalker::GetScopeWhenHaltAtFormals(pFrame);
  745. // For the scopes and locals only enumerable properties will be shown.
  746. for (int i = 0; i < count; i++)
  747. {
  748. Js::PropertyId propertyId = object->GetPropertyId((PropertyIndex)i);
  749. bool isConst = false;
  750. bool isPropertyInDebuggerScope = false;
  751. bool isInDeadZone = false;
  752. if (propertyId != Js::Constants::NoProperty
  753. && IsPropertyValid(propertyId, Js::Constants::NoRegister, &isPropertyInDebuggerScope, &isConst, &isInDeadZone)
  754. && object->IsEnumerable(propertyId))
  755. {
  756. Var itemObj = RecyclableObjectWalker::GetObject(object, object, propertyId, scriptContext);
  757. if (itemObj == nullptr)
  758. {
  759. itemObj = scriptContext->GetLibrary()->GetUndefined();
  760. }
  761. if (IsInParamScope(formalScope, pFrame) && pFrame->GetScriptContext()->IsUndeclBlockVar(itemObj))
  762. {
  763. itemObj = scriptContext->GetLibrary()->GetUndefined();
  764. }
  765. AssertMsg(!RootObjectBase::Is(object) || !isConst, "root object shouldn't produce const properties through IsPropertyValid");
  766. DebuggerPropertyDisplayInfo *info = AllocateNewPropertyDisplayInfo(
  767. propertyId,
  768. itemObj,
  769. isConst,
  770. isInDeadZone);
  771. Assert(info);
  772. pMembersList->Add(info);
  773. }
  774. }
  775. }
  776. IDiagObjectAddress * ObjectVariablesWalker::GetObjectAddress(int index)
  777. {
  778. Assert(index < pMembersList->Count());
  779. DebuggerPropertyDisplayInfo* info = pMembersList->Item(index);
  780. return Anew(pFrame->GetArena(), RecyclableObjectAddress, instance, info->propId, info->aVar, info->IsInDeadZone() ? TRUE : FALSE);
  781. }
  782. // For root access on the Global object (adds let/const variables before properties)
  783. void RootObjectVariablesWalker::PopulateMembers()
  784. {
  785. if (pMembersList == nullptr && instance != nullptr)
  786. {
  787. ScriptContext * scriptContext = pFrame->GetScriptContext();
  788. ArenaAllocator *arena = GetArenaFromContext(scriptContext);
  789. Assert(Js::RootObjectBase::Is(instance));
  790. Js::RootObjectBase* object = Js::RootObjectBase::FromVar(instance);
  791. int count = object->GetPropertyCount();
  792. pMembersList = JsUtil::List<DebuggerPropertyDisplayInfo *, ArenaAllocator>::New(arena, count);
  793. // Add let/const globals first so that they take precedence over the global properties. Then
  794. // VariableWalkerBase::FindPropertyAddress will correctly find let/const globals that shadow
  795. // global properties of the same name.
  796. object->MapLetConstGlobals([&](const PropertyRecord* propertyRecord, Var value, bool isConst) {
  797. if (!scriptContext->IsUndeclBlockVar(value))
  798. {
  799. // Let/const are always enumerable and valid
  800. DebuggerPropertyDisplayInfo *info = AllocateNewPropertyDisplayInfo(propertyRecord->GetPropertyId(), value, isConst, false /*isInDeadZone*/);
  801. pMembersList->Add(info);
  802. }
  803. });
  804. AddObjectProperties(count, object);
  805. }
  806. }
  807. // DiagScopeVariablesWalker
  808. DiagScopeVariablesWalker::DiagScopeVariablesWalker(DiagStackFrame* _pFrame, Var _instance, IDiagObjectModelWalkerBase* innerWalker)
  809. : VariableWalkerBase(_pFrame, _instance, UIGroupType_InnerScope, /* allowLexicalThis */ false)
  810. {
  811. ScriptContext * scriptContext = _pFrame->GetScriptContext();
  812. ArenaAllocator *arena = GetArenaFromContext(scriptContext);
  813. pDiagScopeObjects = JsUtil::List<IDiagObjectModelWalkerBase *, ArenaAllocator>::New(arena);
  814. pDiagScopeObjects->Add(innerWalker);
  815. diagScopeVarCount = innerWalker->GetChildrenCount();
  816. scopeIsInitialized = true;
  817. }
  818. uint32 DiagScopeVariablesWalker::GetChildrenCount()
  819. {
  820. if (scopeIsInitialized)
  821. {
  822. return diagScopeVarCount;
  823. }
  824. Assert(pFrame);
  825. Js::FunctionBody *pFBody = pFrame->GetJavascriptFunction()->GetFunctionBody();
  826. if (pFBody->GetScopeObjectChain())
  827. {
  828. int bytecodeOffset = GetAdjustedByteCodeOffset();
  829. ScriptContext * scriptContext = pFrame->GetScriptContext();
  830. ArenaAllocator *arena = GetArenaFromContext(scriptContext);
  831. pDiagScopeObjects = JsUtil::List<IDiagObjectModelWalkerBase *, ArenaAllocator>::New(arena);
  832. // Look for catch/with/block scopes which encompass current offset (skip block scopes as
  833. // they are only used for lookup within the RegSlotVariablesWalker).
  834. // Go the reverse way so that we find the innermost scope first;
  835. Js::ScopeObjectChain * pScopeObjectChain = pFBody->GetScopeObjectChain();
  836. for (int i = pScopeObjectChain->pScopeChain->Count() - 1 ; i >= 0; i--)
  837. {
  838. Js::DebuggerScope *debuggerScope = pScopeObjectChain->pScopeChain->Item(i);
  839. bool isScopeInRange = debuggerScope->IsOffsetInScope(bytecodeOffset);
  840. if (isScopeInRange
  841. && !debuggerScope->IsParamScope()
  842. && (debuggerScope->IsOwnScope() || (debuggerScope->scopeType == DiagBlockScopeDirect && debuggerScope->HasProperties())))
  843. {
  844. switch (debuggerScope->scopeType)
  845. {
  846. case DiagWithScope:
  847. {
  848. if (enumWithScopeAlso)
  849. {
  850. RecyclableObjectWalker* recylableObjectWalker = Anew(arena, RecyclableObjectWalker, scriptContext,
  851. (Var)pFrame->GetRegValue(debuggerScope->GetLocation(), true));
  852. pDiagScopeObjects->Add(recylableObjectWalker);
  853. diagScopeVarCount += recylableObjectWalker->GetChildrenCount();
  854. }
  855. }
  856. break;
  857. case DiagCatchScopeDirect:
  858. case DiagCatchScopeInObject:
  859. {
  860. CatchScopeWalker* catchScopeWalker = Anew(arena, CatchScopeWalker, pFrame, debuggerScope);
  861. pDiagScopeObjects->Add(catchScopeWalker);
  862. diagScopeVarCount += catchScopeWalker->GetChildrenCount();
  863. }
  864. break;
  865. case DiagCatchScopeInSlot:
  866. case DiagBlockScopeInSlot:
  867. {
  868. SlotArrayVariablesWalker* blockScopeWalker = Anew(arena, SlotArrayVariablesWalker, pFrame,
  869. (Var)pFrame->GetInnerScopeFromRegSlot(debuggerScope->GetLocation()), UIGroupType_InnerScope, /* allowLexicalThis */ false);
  870. pDiagScopeObjects->Add(blockScopeWalker);
  871. diagScopeVarCount += blockScopeWalker->GetChildrenCount();
  872. }
  873. break;
  874. case DiagBlockScopeDirect:
  875. {
  876. RegSlotVariablesWalker *pObjWalker = Anew(arena, RegSlotVariablesWalker, pFrame, debuggerScope, UIGroupType_InnerScope);
  877. pDiagScopeObjects->Add(pObjWalker);
  878. diagScopeVarCount += pObjWalker->GetChildrenCount();
  879. }
  880. break;
  881. case DiagBlockScopeInObject:
  882. {
  883. ObjectVariablesWalker* objectVariablesWalker = Anew(arena, ObjectVariablesWalker, pFrame, pFrame->GetInnerScopeFromRegSlot(debuggerScope->GetLocation()), UIGroupType_InnerScope, /* allowLexicalThis */ false);
  884. pDiagScopeObjects->Add(objectVariablesWalker);
  885. diagScopeVarCount += objectVariablesWalker->GetChildrenCount();
  886. }
  887. break;
  888. default:
  889. Assert(false);
  890. }
  891. }
  892. }
  893. }
  894. scopeIsInitialized = true;
  895. return diagScopeVarCount;
  896. }
  897. BOOL DiagScopeVariablesWalker::Get(int i, ResolvedObject* pResolvedObject)
  898. {
  899. if (i >= 0 && i < (int)diagScopeVarCount)
  900. {
  901. for (int j = 0; j < pDiagScopeObjects->Count(); j++)
  902. {
  903. IDiagObjectModelWalkerBase *pObjWalker = pDiagScopeObjects->Item(j);
  904. if (i < (int)pObjWalker->GetChildrenCount())
  905. {
  906. return pObjWalker->Get(i, pResolvedObject);
  907. }
  908. i -= (int)pObjWalker->GetChildrenCount();
  909. Assert(i >=0);
  910. }
  911. }
  912. return FALSE;
  913. }
  914. IDiagObjectAddress * DiagScopeVariablesWalker::FindPropertyAddress(PropertyId propId, bool& isConst)
  915. {
  916. IDiagObjectAddress * address = nullptr;
  917. // Ensure that children are fetched.
  918. GetChildrenCount();
  919. if (pDiagScopeObjects)
  920. {
  921. for (int j = 0; j < pDiagScopeObjects->Count(); j++)
  922. {
  923. IDiagObjectModelWalkerBase *pObjWalker = pDiagScopeObjects->Item(j);
  924. Assert(pObjWalker);
  925. address = pObjWalker->FindPropertyAddress(propId, isConst);
  926. if (address != nullptr)
  927. {
  928. break;
  929. }
  930. }
  931. }
  932. return address;
  933. }
  934. // Locals walker
  935. LocalsWalker::LocalsWalker(DiagStackFrame* _frame, DWORD _frameWalkerFlags)
  936. : pFrame(_frame), frameWalkerFlags(_frameWalkerFlags), pVarWalkers(nullptr), totalLocalsCount(0), hasUserNotDefinedArguments(false)
  937. {
  938. Js::FunctionBody *pFBody = pFrame->GetJavascriptFunction()->GetFunctionBody();
  939. if (pFBody && !pFBody->GetUtf8SourceInfo()->GetIsLibraryCode())
  940. {
  941. // Allocate the container of all walkers.
  942. ArenaAllocator *arena = pFrame->GetArena();
  943. pVarWalkers = JsUtil::List<VariableWalkerBase *, ArenaAllocator>::New(arena);
  944. // Top most function will have one of these regslot, slotarray or activation object.
  945. FrameDisplay * pDisplay = pFrame->GetFrameDisplay();
  946. uint scopeCount = (uint)(pDisplay ? pDisplay->GetLength() : 0);
  947. uint nextStartIndex = 0;
  948. // Add the catch/with/block expression scope objects.
  949. if (pFBody->GetScopeObjectChain())
  950. {
  951. pVarWalkers->Add(Anew(arena, DiagScopeVariablesWalker, pFrame, nullptr, !!(frameWalkerFlags & FrameWalkerFlags::FW_EnumWithScopeAlso)));
  952. }
  953. // In the eval function, we will not show global items directly, instead they should go as a group node.
  954. bool shouldAddGlobalItemsDirectly = pFBody->GetIsGlobalFunc() && !pFBody->IsEval();
  955. bool dontAddGlobalsDirectly = (frameWalkerFlags & FrameWalkerFlags::FW_DontAddGlobalsDirectly) == FrameWalkerFlags::FW_DontAddGlobalsDirectly;
  956. if (shouldAddGlobalItemsDirectly && !dontAddGlobalsDirectly)
  957. {
  958. // Global properties will be enumerated using RootObjectVariablesWalker
  959. pVarWalkers->Add(Anew(arena, RootObjectVariablesWalker, pFrame, pFrame->GetRootObject(), UIGroupType_None));
  960. }
  961. DebuggerScope *formalScope = GetScopeWhenHaltAtFormals(pFrame);
  962. DWORD localsType = GetCurrentFramesLocalsType(pFrame);
  963. // If we are in the formal scope of a split scoped function then we can skip checking the body scope
  964. if (!VariableWalkerBase::IsInParamScope(formalScope, pFrame) || pFBody->IsParamAndBodyScopeMerged())
  965. {
  966. VariableWalkerBase *pVarWalker = nullptr;
  967. // More than one localsType can occur in the scope
  968. if (localsType & FramesLocalType::LocalType_InObject)
  969. {
  970. Assert(scopeCount > 0);
  971. pVarWalker = Anew(arena, ObjectVariablesWalker, pFrame, pDisplay->GetItem(nextStartIndex), UIGroupType_None, !!(frameWalkerFlags & FrameWalkerFlags::FW_AllowLexicalThis), !!(frameWalkerFlags & FrameWalkerFlags::FW_AllowSuperReference));
  972. nextStartIndex++;
  973. }
  974. else if (localsType & FramesLocalType::LocalType_InSlot)
  975. {
  976. Assert(scopeCount > 0);
  977. pVarWalker = Anew(arena, SlotArrayVariablesWalker, pFrame, (Js::Var *)pDisplay->GetItem(nextStartIndex), UIGroupType_None, !!(frameWalkerFlags & FrameWalkerFlags::FW_AllowLexicalThis), !!(frameWalkerFlags & FrameWalkerFlags::FW_AllowSuperReference));
  978. nextStartIndex++;
  979. }
  980. else if (scopeCount > 0 && pFBody->GetFrameDisplayRegister() != 0 && pFBody->IsParamAndBodyScopeMerged())
  981. {
  982. Assert((Var)pDisplay->GetItem(0) == pFrame->GetScriptContext()->GetLibrary()->GetNull());
  983. nextStartIndex++;
  984. }
  985. if (pVarWalker)
  986. {
  987. pVarWalkers->Add(pVarWalker);
  988. }
  989. }
  990. // If we are halted at formal place, and param and body scopes are splitted we need to make use of formal debugger scope to to determine the locals type.
  991. if (formalScope != nullptr && !pFBody->IsParamAndBodyScopeMerged())
  992. {
  993. if (pFBody->GetPropertyIdOnRegSlotsContainer() && pFBody->GetPropertyIdOnRegSlotsContainer()->formalsUpperBound != Js::Constants::NoRegister)
  994. {
  995. localsType |= FramesLocalType::LocalType_Reg;
  996. }
  997. Assert(scopeCount > 0);
  998. if (formalScope->scopeType == Js::DiagParamScopeInObject)
  999. {
  1000. // Need to add the param scope frame display as a separate walker as the ObjectVariablesWalker directly uses the socpe object to retrieve properties
  1001. pVarWalkers->Add(Anew(arena, ObjectVariablesWalker, pFrame, pDisplay->GetItem(nextStartIndex), UIGroupType_Param, !!(frameWalkerFlags & FrameWalkerFlags::FW_AllowLexicalThis), !!(frameWalkerFlags & FrameWalkerFlags::FW_AllowSuperReference)));
  1002. }
  1003. else
  1004. {
  1005. pVarWalkers->Add(Anew(arena, SlotArrayVariablesWalker, pFrame, (Js::Var *)pDisplay->GetItem(nextStartIndex), UIGroupType_Param, !!(frameWalkerFlags & FrameWalkerFlags::FW_AllowLexicalThis), !!(frameWalkerFlags & FrameWalkerFlags::FW_AllowSuperReference)));
  1006. }
  1007. nextStartIndex++;
  1008. }
  1009. if (localsType & FramesLocalType::LocalType_Reg)
  1010. {
  1011. pVarWalkers->Add(Anew(arena, RegSlotVariablesWalker, pFrame, nullptr /*not debugger scope*/, UIGroupType_None, !!(frameWalkerFlags & FrameWalkerFlags::FW_AllowSuperReference)));
  1012. }
  1013. const Js::Var nullVar = pFrame->GetScriptContext()->GetLibrary()->GetNull();
  1014. for (uint i = nextStartIndex; i < (uint)scopeCount; i++)
  1015. {
  1016. Var currentScopeObject = pDisplay->GetItem(i);
  1017. if (currentScopeObject != nullptr && currentScopeObject != nullVar) // Skip nullptr (dummy scope)
  1018. {
  1019. ScopeType scopeType = FrameDisplay::GetScopeType(currentScopeObject);
  1020. switch(scopeType)
  1021. {
  1022. case ScopeType_ActivationObject:
  1023. pVarWalkers->Add(Anew(arena, ObjectVariablesWalker, pFrame, currentScopeObject, UIGroupType_Scope, !!(frameWalkerFlags & FrameWalkerFlags::FW_AllowLexicalThis), !!(frameWalkerFlags & FrameWalkerFlags::FW_AllowSuperReference)));
  1024. break;
  1025. case ScopeType_SlotArray:
  1026. pVarWalkers->Add(Anew(arena, SlotArrayVariablesWalker, pFrame, currentScopeObject, UIGroupType_Scope, !!(frameWalkerFlags & FrameWalkerFlags::FW_AllowLexicalThis), !!(frameWalkerFlags & FrameWalkerFlags::FW_AllowSuperReference)));
  1027. break;
  1028. case ScopeType_WithScope:
  1029. if( (frameWalkerFlags & FrameWalkerFlags::FW_EnumWithScopeAlso) == FrameWalkerFlags::FW_EnumWithScopeAlso)
  1030. {
  1031. RecyclableObjectWalker* withScopeWalker = Anew(arena, RecyclableObjectWalker, pFrame->GetScriptContext(), currentScopeObject);
  1032. pVarWalkers->Add(Anew(arena, DiagScopeVariablesWalker, pFrame, currentScopeObject, withScopeWalker));
  1033. }
  1034. break;
  1035. default:
  1036. Assert(false);
  1037. }
  1038. }
  1039. }
  1040. // No need to add global properties if this is a global function, as it is already done above.
  1041. if (!shouldAddGlobalItemsDirectly && !dontAddGlobalsDirectly)
  1042. {
  1043. pVarWalkers->Add(Anew(arena, RootObjectVariablesWalker, pFrame, pFrame->GetRootObject(), UIGroupType_Globals));
  1044. }
  1045. }
  1046. }
  1047. BOOL LocalsWalker::CreateArgumentsObject(ResolvedObject* pResolvedObject)
  1048. {
  1049. Assert(pResolvedObject);
  1050. Assert(pResolvedObject->scriptContext);
  1051. Assert(hasUserNotDefinedArguments);
  1052. pResolvedObject->name = _u("arguments");
  1053. pResolvedObject->propId = Js::PropertyIds::arguments;
  1054. pResolvedObject->typeId = TypeIds_Arguments;
  1055. Js::FunctionBody *pFBody = pFrame->GetJavascriptFunction()->GetFunctionBody();
  1056. Assert(pFBody);
  1057. pResolvedObject->obj = pFrame->GetArgumentsObject();
  1058. if (pResolvedObject->obj == nullptr)
  1059. {
  1060. pResolvedObject->obj = pFrame->CreateHeapArguments();
  1061. Assert(pResolvedObject->obj);
  1062. pResolvedObject->objectDisplay = Anew(pFrame->GetArena(), RecyclableArgumentsObjectDisplay, pResolvedObject, this);
  1063. ExpandArgumentsObject(pResolvedObject->objectDisplay);
  1064. }
  1065. pResolvedObject->address = Anew(GetArenaFromContext(pResolvedObject->scriptContext),
  1066. RecyclableObjectAddress,
  1067. pResolvedObject->scriptContext->GetGlobalObject(),
  1068. Js::PropertyIds::arguments,
  1069. pResolvedObject->obj,
  1070. false /*isInDeadZone*/);
  1071. return TRUE;
  1072. }
  1073. BOOL LocalsWalker::Get(int i, ResolvedObject* pResolvedObject)
  1074. {
  1075. if (i >= (int)totalLocalsCount)
  1076. {
  1077. return FALSE;
  1078. }
  1079. pResolvedObject->scriptContext = pFrame->GetScriptContext();
  1080. if (VariableWalkerBase::GetExceptionObject(i, pFrame, pResolvedObject))
  1081. {
  1082. return TRUE;
  1083. }
  1084. #ifdef ENABLE_MUTATION_BREAKPOINT
  1085. // Pending mutation display should be before any return value
  1086. if (VariableWalkerBase::GetBreakMutationBreakpointValue(i, pFrame, pResolvedObject))
  1087. {
  1088. return TRUE;
  1089. }
  1090. #endif
  1091. if (VariableWalkerBase::GetReturnedValue(i, pFrame, pResolvedObject))
  1092. {
  1093. return TRUE;
  1094. }
  1095. if (hasUserNotDefinedArguments)
  1096. {
  1097. if (i == 0)
  1098. {
  1099. return CreateArgumentsObject(pResolvedObject);
  1100. }
  1101. i--;
  1102. }
  1103. if (!pVarWalkers || pVarWalkers->Count() == 0)
  1104. {
  1105. return FALSE;
  1106. }
  1107. // In the case of not making groups, all variables will be arranged
  1108. // as one int32 list in the locals window.
  1109. if (!ShouldMakeGroups())
  1110. {
  1111. for (int j = 0; j < pVarWalkers->Count(); j++)
  1112. {
  1113. int count = pVarWalkers->Item(j)->GetChildrenCount();
  1114. if (i < count)
  1115. {
  1116. return pVarWalkers->Item(j)->Get(i, pResolvedObject);
  1117. }
  1118. i-= count;
  1119. }
  1120. Assert(FALSE);
  1121. return FALSE;
  1122. }
  1123. int startScopeIndex = 0;
  1124. // Need to determine what range of local variables we're in for the requested index.
  1125. // Non-grouped local variables are organized with reg slot coming first, then followed by
  1126. // scope slot/activation object variables. Catch and with variables follow next
  1127. // and group variables are stored last which come from upper scopes that
  1128. // are accessed in this function (those passed down as part of a closure).
  1129. // Note that all/any/none of these walkers may be present.
  1130. // Example variable layout:
  1131. // [0-2] - Reg slot vars.
  1132. // [3-4] - Scope slot array vars.
  1133. // [5-8] - Global vars (stored on the global object as properties).
  1134. for (int j = 0; j < pVarWalkers->Count(); ++j)
  1135. {
  1136. VariableWalkerBase *variableWalker = pVarWalkers->Item(j);
  1137. if (!variableWalker->IsInGroup())
  1138. {
  1139. int count = variableWalker->GetChildrenCount();
  1140. if (i < count)
  1141. {
  1142. return variableWalker->Get(i, pResolvedObject);
  1143. }
  1144. i-= count;
  1145. startScopeIndex++;
  1146. }
  1147. else
  1148. {
  1149. // We've finished with all walkers for the current locals level so
  1150. // break out in order to handle the groups.
  1151. break;
  1152. }
  1153. }
  1154. // Handle groups.
  1155. Assert((i + startScopeIndex) < pVarWalkers->Count());
  1156. VariableWalkerBase *variableWalker = pVarWalkers->Item(i + startScopeIndex);
  1157. return variableWalker->GetGroupObject(pResolvedObject);
  1158. }
  1159. bool LocalsWalker::ShouldInsertFakeArguments()
  1160. {
  1161. JavascriptFunction* func = pFrame->GetJavascriptFunction();
  1162. if (func->IsScriptFunction()
  1163. && !func->GetFunctionBody()->GetUtf8SourceInfo()->GetIsLibraryCode()
  1164. && !func->GetFunctionBody()->GetIsGlobalFunc())
  1165. {
  1166. bool isConst = false;
  1167. hasUserNotDefinedArguments = (nullptr == FindPropertyAddress(PropertyIds::arguments, false /*walkers on the current frame*/, isConst));
  1168. }
  1169. return hasUserNotDefinedArguments;
  1170. }
  1171. uint32 LocalsWalker::GetChildrenCount()
  1172. {
  1173. if (totalLocalsCount == 0)
  1174. {
  1175. if (pVarWalkers)
  1176. {
  1177. int groupWalkersStartIndex = 0;
  1178. for (int i = 0; i < pVarWalkers->Count(); i++)
  1179. {
  1180. VariableWalkerBase* variableWalker = pVarWalkers->Item(i);
  1181. // In the case of making groups, we want to include any variables that aren't
  1182. // part of a group as part of the local variable count.
  1183. if (!ShouldMakeGroups() || !variableWalker->IsInGroup())
  1184. {
  1185. ++groupWalkersStartIndex;
  1186. totalLocalsCount += variableWalker->GetChildrenCount();
  1187. }
  1188. }
  1189. // Add on the number of groups to display in locals
  1190. // (group walkers come after function local walkers).
  1191. totalLocalsCount += (pVarWalkers->Count() - groupWalkersStartIndex);
  1192. }
  1193. if (VariableWalkerBase::HasExceptionObject(pFrame))
  1194. {
  1195. totalLocalsCount++;
  1196. }
  1197. #ifdef ENABLE_MUTATION_BREAKPOINT
  1198. totalLocalsCount += VariableWalkerBase::GetBreakMutationBreakpointsCount(pFrame);
  1199. #endif
  1200. totalLocalsCount += VariableWalkerBase::GetReturnedValueCount(pFrame);
  1201. // Check if needed to add fake arguments.
  1202. if (ShouldInsertFakeArguments())
  1203. {
  1204. // In this case we need to create arguments object explicitly.
  1205. totalLocalsCount++;
  1206. }
  1207. }
  1208. return totalLocalsCount;
  1209. }
  1210. uint32 LocalsWalker::GetLocalVariablesCount()
  1211. {
  1212. uint32 localsCount = 0;
  1213. if (pVarWalkers)
  1214. {
  1215. for (int i = 0; i < pVarWalkers->Count(); i++)
  1216. {
  1217. VariableWalkerBase* variableWalker = pVarWalkers->Item(i);
  1218. // In the case of making groups, we want to include any variables that aren't
  1219. // part of a group as part of the local variable count.
  1220. if (!ShouldMakeGroups() || !variableWalker->IsInGroup())
  1221. {
  1222. localsCount += variableWalker->GetChildrenCount();
  1223. }
  1224. }
  1225. }
  1226. return localsCount;
  1227. }
  1228. BOOL LocalsWalker::GetLocal(int i, ResolvedObject* pResolvedObject)
  1229. {
  1230. if (!pVarWalkers || pVarWalkers->Count() == 0)
  1231. {
  1232. return FALSE;
  1233. }
  1234. for (int j = 0; j < pVarWalkers->Count(); ++j)
  1235. {
  1236. VariableWalkerBase *variableWalker = pVarWalkers->Item(j);
  1237. if (!ShouldMakeGroups() || !variableWalker->IsInGroup())
  1238. {
  1239. int count = variableWalker->GetChildrenCount();
  1240. if (i < count)
  1241. {
  1242. return variableWalker->Get(i, pResolvedObject);
  1243. }
  1244. i -= count;
  1245. }
  1246. else
  1247. {
  1248. // We've finished with all walkers for the current locals level so
  1249. // break out in order to handle the groups.
  1250. break;
  1251. }
  1252. }
  1253. return FALSE;
  1254. }
  1255. BOOL LocalsWalker::GetGroupObject(Js::UIGroupType uiGroupType, int i, ResolvedObject* pResolvedObject)
  1256. {
  1257. if (pVarWalkers)
  1258. {
  1259. int scopeCount = 0;
  1260. for (int j = 0; j < pVarWalkers->Count(); j++)
  1261. {
  1262. VariableWalkerBase* variableWalker = pVarWalkers->Item(j);
  1263. if (variableWalker->groupType == uiGroupType)
  1264. {
  1265. scopeCount++;
  1266. if (i < scopeCount)
  1267. {
  1268. return variableWalker->GetGroupObject(pResolvedObject);
  1269. }
  1270. }
  1271. }
  1272. }
  1273. return FALSE;
  1274. }
  1275. BOOL LocalsWalker::GetScopeObject(int i, ResolvedObject* pResolvedObject)
  1276. {
  1277. return this->GetGroupObject(Js::UIGroupType::UIGroupType_Scope, i, pResolvedObject);
  1278. }
  1279. BOOL LocalsWalker::GetGlobalsObject(ResolvedObject* pResolvedObject)
  1280. {
  1281. int i = 0;
  1282. return this->GetGroupObject(Js::UIGroupType::UIGroupType_Globals, i, pResolvedObject);
  1283. }
  1284. /*static*/
  1285. DebuggerScope * LocalsWalker::GetScopeWhenHaltAtFormals(DiagStackFrame* frame)
  1286. {
  1287. Js::ScopeObjectChain * scopeObjectChain = frame->GetJavascriptFunction()->GetFunctionBody()->GetScopeObjectChain();
  1288. if (scopeObjectChain != nullptr && scopeObjectChain->pScopeChain != nullptr)
  1289. {
  1290. for (int i = 0; i < scopeObjectChain->pScopeChain->Count(); i++)
  1291. {
  1292. Js::DebuggerScope * scope = scopeObjectChain->pScopeChain->Item(i);
  1293. if (scope->IsParamScope())
  1294. {
  1295. return scope;
  1296. }
  1297. }
  1298. }
  1299. return nullptr;
  1300. }
  1301. // Gets an adjusted offset for the current bytecode location based on which stack frame we're in.
  1302. // If we're in the top frame (leaf node), then the byte code offset should remain as is, to reflect
  1303. // the current position of the instruction pointer. If we're not in the top frame, we need to subtract
  1304. // 1 as the byte code location will be placed at the next statement to be executed at the top frame.
  1305. // In the case of block scoping, this is an inaccurate location for viewing variables since the next
  1306. // statement could be beyond the current block scope. For inspection, we want to remain in the
  1307. // current block that the function was called from.
  1308. // An example is this:
  1309. // function foo() { ... } // Frame 0 (with breakpoint inside)
  1310. // function bar() { // Frame 1
  1311. // {
  1312. // let a = 0;
  1313. // foo(); // <-- Inspecting here, foo is already evaluated.
  1314. // }
  1315. // foo(); // <-- Byte code offset is now here, so we need to -1 to get back in the block scope.
  1316. int LocalsWalker::GetAdjustedByteCodeOffset(DiagStackFrame* frame)
  1317. {
  1318. int offset = frame->GetByteCodeOffset();
  1319. if (!frame->IsTopFrame() && frame->IsInterpreterFrame())
  1320. {
  1321. // Native frames are already adjusted so just need to adjust interpreted
  1322. // frames that are not the top frame.
  1323. --offset;
  1324. }
  1325. return offset;
  1326. }
  1327. /*static*/
  1328. DWORD LocalsWalker::GetCurrentFramesLocalsType(DiagStackFrame* frame)
  1329. {
  1330. Assert(frame);
  1331. FunctionBody *pFBody = frame->GetJavascriptFunction()->GetFunctionBody();
  1332. Assert(pFBody);
  1333. DWORD localType = FramesLocalType::LocalType_None;
  1334. if (pFBody->GetFrameDisplayRegister() != 0)
  1335. {
  1336. if (pFBody->GetObjectRegister() != 0)
  1337. {
  1338. // current scope is activation object
  1339. localType = FramesLocalType::LocalType_InObject;
  1340. }
  1341. else
  1342. {
  1343. if (pFBody->scopeSlotArraySize > 0)
  1344. {
  1345. localType = FramesLocalType::LocalType_InSlot;
  1346. }
  1347. }
  1348. }
  1349. if (pFBody->GetPropertyIdOnRegSlotsContainer() && pFBody->GetPropertyIdOnRegSlotsContainer()->length > 0)
  1350. {
  1351. localType |= FramesLocalType::LocalType_Reg;
  1352. }
  1353. return localType;
  1354. }
  1355. IDiagObjectAddress * LocalsWalker::FindPropertyAddress(PropertyId propId, bool& isConst)
  1356. {
  1357. return FindPropertyAddress(propId, true, isConst);
  1358. }
  1359. IDiagObjectAddress * LocalsWalker::FindPropertyAddress(PropertyId propId, bool enumerateGroups, bool& isConst)
  1360. {
  1361. isConst = false;
  1362. if (propId == PropertyIds::arguments && hasUserNotDefinedArguments)
  1363. {
  1364. ResolvedObject resolveObject;
  1365. resolveObject.scriptContext = pFrame->GetScriptContext();
  1366. if (CreateArgumentsObject(&resolveObject))
  1367. {
  1368. return resolveObject.address;
  1369. }
  1370. }
  1371. if (pVarWalkers)
  1372. {
  1373. for (int i = 0; i < pVarWalkers->Count(); i++)
  1374. {
  1375. VariableWalkerBase *pVarWalker = pVarWalkers->Item(i);
  1376. if (!enumerateGroups && !pVarWalker->IsWalkerForCurrentFrame())
  1377. {
  1378. continue;
  1379. }
  1380. IDiagObjectAddress *address = pVarWalkers->Item(i)->FindPropertyAddress(propId, isConst);
  1381. if (address != nullptr)
  1382. {
  1383. return address;
  1384. }
  1385. }
  1386. }
  1387. return nullptr;
  1388. }
  1389. void LocalsWalker::ExpandArgumentsObject(IDiagObjectModelDisplay * argumentsDisplay)
  1390. {
  1391. Assert(argumentsDisplay != nullptr);
  1392. WeakArenaReference<Js::IDiagObjectModelWalkerBase>* argumentsObjectWalkerRef = argumentsDisplay->CreateWalker();
  1393. Assert(argumentsObjectWalkerRef != nullptr);
  1394. IDiagObjectModelWalkerBase * walker = argumentsObjectWalkerRef->GetStrongReference();
  1395. int count = (int)walker->GetChildrenCount();
  1396. Js::ResolvedObject tempResolvedObj;
  1397. for (int i = 0; i < count; i++)
  1398. {
  1399. walker->Get(i, &tempResolvedObj);
  1400. }
  1401. argumentsObjectWalkerRef->ReleaseStrongReference();
  1402. HeapDelete(argumentsObjectWalkerRef);
  1403. }
  1404. //--------------------------
  1405. // LocalObjectAddressForSlot
  1406. LocalObjectAddressForSlot::LocalObjectAddressForSlot(ScopeSlots _pSlotArray, int _slotIndex, Js::Var _value)
  1407. : slotArray(_pSlotArray),
  1408. slotIndex(_slotIndex),
  1409. value(_value)
  1410. {
  1411. }
  1412. BOOL LocalObjectAddressForSlot::Set(Var updateObject)
  1413. {
  1414. if (IsInDeadZone())
  1415. {
  1416. AssertMsg(FALSE, "Should not be able to set the value of a slot in a dead zone.");
  1417. return FALSE;
  1418. }
  1419. slotArray.Set(slotIndex, updateObject);
  1420. return TRUE;
  1421. }
  1422. Var LocalObjectAddressForSlot::GetValue(BOOL fUpdated)
  1423. {
  1424. if (!fUpdated || IsInDeadZone())
  1425. {
  1426. #if DBG
  1427. if (IsInDeadZone())
  1428. {
  1429. // If we're in a dead zone, the value will be the
  1430. // [Uninitialized block variable] string.
  1431. Assert(JavascriptString::Is(value));
  1432. }
  1433. #endif // DBG
  1434. return value;
  1435. }
  1436. return slotArray.Get(slotIndex);
  1437. }
  1438. BOOL LocalObjectAddressForSlot::IsInDeadZone() const
  1439. {
  1440. Var value = slotArray.Get(slotIndex);
  1441. if (!RecyclableObject::Is(value))
  1442. {
  1443. return FALSE;
  1444. }
  1445. RecyclableObject* obj = RecyclableObject::FromVar(value);
  1446. ScriptContext* scriptContext = obj->GetScriptContext();
  1447. return scriptContext->IsUndeclBlockVar(obj) ? TRUE : FALSE;
  1448. }
  1449. //--------------------------
  1450. // LocalObjectAddressForSlot
  1451. LocalObjectAddressForRegSlot::LocalObjectAddressForRegSlot(DiagStackFrame* _pFrame, RegSlot _regSlot, Js::Var _value)
  1452. : pFrame(_pFrame),
  1453. regSlot(_regSlot),
  1454. value(_value)
  1455. {
  1456. }
  1457. BOOL LocalObjectAddressForRegSlot::IsInDeadZone() const
  1458. {
  1459. return regSlot == Js::Constants::NoRegister;
  1460. }
  1461. BOOL LocalObjectAddressForRegSlot::Set(Var updateObject)
  1462. {
  1463. Assert(pFrame);
  1464. if (IsInDeadZone())
  1465. {
  1466. AssertMsg(FALSE, "Should not be able to set the value of a register in a dead zone.");
  1467. return FALSE;
  1468. }
  1469. pFrame->SetRegValue(regSlot, updateObject);
  1470. return TRUE;
  1471. }
  1472. Var LocalObjectAddressForRegSlot::GetValue(BOOL fUpdated)
  1473. {
  1474. if (!fUpdated || IsInDeadZone())
  1475. {
  1476. #if DBG
  1477. if (IsInDeadZone())
  1478. {
  1479. // If we're in a dead zone, the value will be the
  1480. // [Uninitialized block variable] string.
  1481. Assert(JavascriptString::Is(value));
  1482. }
  1483. #endif // DBG
  1484. return value;
  1485. }
  1486. Assert(pFrame);
  1487. return pFrame->GetRegValue(regSlot);
  1488. }
  1489. //
  1490. // CatchScopeWalker
  1491. BOOL CatchScopeWalker::Get(int i, ResolvedObject* pResolvedObject)
  1492. {
  1493. Assert(pResolvedObject);
  1494. Assert(pFrame);
  1495. pResolvedObject->scriptContext = pFrame->GetScriptContext();
  1496. Assert(i < (int)GetChildrenCount());
  1497. Js::DebuggerScopeProperty scopeProperty = debuggerScope->scopeProperties->Item(i);
  1498. pResolvedObject->propId = scopeProperty.propId;
  1499. const Js::PropertyRecord* propertyRecord = pResolvedObject->scriptContext->GetPropertyName(pResolvedObject->propId);
  1500. // TODO: If this is a symbol-keyed property, we should indicate that in the name - "Symbol (description)"
  1501. pResolvedObject->name = propertyRecord->GetBuffer();
  1502. FetchValueAndAddress(scopeProperty, &pResolvedObject->obj, &pResolvedObject->address);
  1503. Assert(pResolvedObject->obj);
  1504. pResolvedObject->typeId = JavascriptOperators::GetTypeId(pResolvedObject->obj);
  1505. pResolvedObject->objectDisplay = Anew(pFrame->GetArena(), RecyclableObjectDisplay, pResolvedObject);
  1506. return TRUE;
  1507. }
  1508. uint32 CatchScopeWalker::GetChildrenCount()
  1509. {
  1510. return debuggerScope->scopeProperties->Count();
  1511. }
  1512. void CatchScopeWalker::FetchValueAndAddress(DebuggerScopeProperty &scopeProperty, _Out_opt_ Var *pValue, _Out_opt_ IDiagObjectAddress ** ppAddress)
  1513. {
  1514. Assert(pValue != nullptr || ppAddress != nullptr);
  1515. ArenaAllocator* arena = pFrame->GetArena();
  1516. Var outValue;
  1517. IDiagObjectAddress * pAddress = nullptr;
  1518. ScriptContext* scriptContext = pFrame->GetScriptContext();
  1519. if (debuggerScope->scopeType == Js::DiagCatchScopeInObject)
  1520. {
  1521. Var obj = pFrame->GetInnerScopeFromRegSlot(debuggerScope->GetLocation());
  1522. Assert(RecyclableObject::Is(obj));
  1523. outValue = RecyclableObjectWalker::GetObject(RecyclableObject::FromVar(obj), RecyclableObject::FromVar(obj), scopeProperty.propId, scriptContext);
  1524. bool isInDeadZone = scriptContext->IsUndeclBlockVar(outValue);
  1525. if (isInDeadZone)
  1526. {
  1527. outValue = scriptContext->GetLibrary()->GetDebuggerDeadZoneBlockVariableString();
  1528. }
  1529. pAddress = Anew(arena, RecyclableObjectAddress, obj, scopeProperty.propId, outValue, isInDeadZone);
  1530. }
  1531. else
  1532. {
  1533. outValue = pFrame->GetRegValue(scopeProperty.location);
  1534. bool isInDeadZone = scriptContext->IsUndeclBlockVar(outValue);
  1535. if (isInDeadZone)
  1536. {
  1537. outValue = scriptContext->GetLibrary()->GetDebuggerDeadZoneBlockVariableString();
  1538. }
  1539. pAddress = Anew(arena, LocalObjectAddressForRegSlot, pFrame, scopeProperty.location, outValue);
  1540. }
  1541. if (pValue)
  1542. {
  1543. *pValue = outValue;
  1544. }
  1545. if (ppAddress)
  1546. {
  1547. *ppAddress = pAddress;
  1548. }
  1549. }
  1550. IDiagObjectAddress *CatchScopeWalker::FindPropertyAddress(PropertyId _propId, bool& isConst)
  1551. {
  1552. isConst = false;
  1553. IDiagObjectAddress * address = nullptr;
  1554. auto properties = debuggerScope->scopeProperties;
  1555. for (int i = 0; i < properties->Count(); i++)
  1556. {
  1557. if (properties->Item(i).propId == _propId)
  1558. {
  1559. FetchValueAndAddress(properties->Item(i), nullptr, &address);
  1560. break;
  1561. }
  1562. }
  1563. return address;
  1564. }
  1565. //--------------------------
  1566. // RecyclableObjectAddress
  1567. RecyclableObjectAddress::RecyclableObjectAddress(Var _parentObj, Js::PropertyId _propId, Js::Var _value, BOOL _isInDeadZone)
  1568. : parentObj(_parentObj),
  1569. propId(_propId),
  1570. value(_value),
  1571. isInDeadZone(_isInDeadZone)
  1572. {
  1573. parentObj = ((RecyclableObject*)parentObj)->GetThisObjectOrUnWrap();
  1574. }
  1575. BOOL RecyclableObjectAddress::IsInDeadZone() const
  1576. {
  1577. return isInDeadZone;
  1578. }
  1579. BOOL RecyclableObjectAddress::Set(Var updateObject)
  1580. {
  1581. if (Js::RecyclableObject::Is(parentObj))
  1582. {
  1583. Js::RecyclableObject* obj = Js::RecyclableObject::FromVar(parentObj);
  1584. ScriptContext* requestContext = obj->GetScriptContext(); //TODO: real requestContext
  1585. return Js::JavascriptOperators::SetProperty(obj, obj, propId, updateObject, requestContext);
  1586. }
  1587. return FALSE;
  1588. }
  1589. BOOL RecyclableObjectAddress::IsWritable()
  1590. {
  1591. if (Js::RecyclableObject::Is(parentObj))
  1592. {
  1593. Js::RecyclableObject* obj = Js::RecyclableObject::FromVar(parentObj);
  1594. return obj->IsWritable(propId);
  1595. }
  1596. return TRUE;
  1597. }
  1598. Var RecyclableObjectAddress::GetValue(BOOL fUpdated)
  1599. {
  1600. if (!fUpdated)
  1601. {
  1602. return value;
  1603. }
  1604. if (Js::RecyclableObject::Is(parentObj))
  1605. {
  1606. Js::RecyclableObject* obj = Js::RecyclableObject::FromVar(parentObj);
  1607. ScriptContext* requestContext = obj->GetScriptContext();
  1608. Var objValue = nullptr;
  1609. #if ENABLE_TTD
  1610. bool suppressGetterForTTDebug = requestContext->GetThreadContext()->IsRuntimeInTTDMode() && requestContext->GetThreadContext()->TTDLog->ShouldDoGetterInvocationSupression();
  1611. TTD::TTModeStackAutoPopper suppressModeAutoPopper(requestContext->GetThreadContext()->TTDLog);
  1612. if(suppressGetterForTTDebug)
  1613. {
  1614. suppressModeAutoPopper.PushModeAndSetToAutoPop(TTD::TTDMode::DebuggerSuppressGetter);
  1615. }
  1616. #endif
  1617. if (Js::JavascriptOperators::GetProperty(obj, propId, &objValue, requestContext))
  1618. {
  1619. return objValue;
  1620. }
  1621. }
  1622. return nullptr;
  1623. }
  1624. //--------------------------
  1625. // RecyclableObjectDisplay
  1626. RecyclableObjectDisplay::RecyclableObjectDisplay(ResolvedObject* resolvedObject, DBGPROP_ATTRIB_FLAGS defaultAttributes)
  1627. : scriptContext(resolvedObject->scriptContext),
  1628. instance(resolvedObject->obj),
  1629. originalInstance(resolvedObject->originalObj != nullptr ? resolvedObject->originalObj : resolvedObject->obj), // If we don't have it set it means originalInstance should point to object itself
  1630. name(resolvedObject->name),
  1631. pObjAddress(resolvedObject->address),
  1632. defaultAttributes(defaultAttributes),
  1633. propertyId(resolvedObject->propId)
  1634. {
  1635. }
  1636. bool RecyclableObjectDisplay::IsLiteralProperty() const
  1637. {
  1638. Assert(this->scriptContext);
  1639. if (this->propertyId != Constants::NoProperty)
  1640. {
  1641. Js::PropertyRecord const * propertyRecord = this->scriptContext->GetThreadContext()->GetPropertyName(this->propertyId);
  1642. const WCHAR* startOfPropertyName = propertyRecord->GetBuffer();
  1643. const WCHAR* endOfIdentifier = this->scriptContext->GetCharClassifier()->SkipIdentifier((LPCOLESTR)propertyRecord->GetBuffer());
  1644. return (charcount_t)(endOfIdentifier - startOfPropertyName) == propertyRecord->GetLength();
  1645. }
  1646. else
  1647. {
  1648. return true;
  1649. }
  1650. }
  1651. bool RecyclableObjectDisplay::IsSymbolProperty()
  1652. {
  1653. Assert(this->scriptContext);
  1654. if (this->propertyId != Constants::NoProperty)
  1655. {
  1656. Js::PropertyRecord const * propertyRecord = this->scriptContext->GetThreadContext()->GetPropertyName(this->propertyId);
  1657. return propertyRecord->IsSymbol();
  1658. }
  1659. return false;
  1660. }
  1661. LPCWSTR RecyclableObjectDisplay::Name()
  1662. {
  1663. return name;
  1664. }
  1665. LPCWSTR RecyclableObjectDisplay::Type()
  1666. {
  1667. LPCWSTR typeStr;
  1668. if(Js::TaggedInt::Is(instance) || Js::JavascriptNumber::Is(instance))
  1669. {
  1670. typeStr = _u("Number");
  1671. }
  1672. else
  1673. {
  1674. Js::RecyclableObject* obj = Js::RecyclableObject::FromVar(instance);
  1675. StringBuilder<ArenaAllocator>* builder = scriptContext->GetThreadContext()->GetDebugManager()->pCurrentInterpreterLocation->stringBuilder;
  1676. builder->Reset();
  1677. // For the RecyclableObject try to find out the constructor, which will be shown as type for the object.
  1678. // This case is to handle the user defined function, built in objects have dedicated classes to handle.
  1679. Var value = nullptr;
  1680. TypeId typeId = obj->GetTypeId();
  1681. if (typeId == TypeIds_Object && GetPropertyWithScriptEnter(obj, obj, PropertyIds::constructor, &value, scriptContext))
  1682. {
  1683. builder->AppendCppLiteral(_u("Object"));
  1684. if (Js::JavascriptFunction::Is(value))
  1685. {
  1686. Js::JavascriptFunction *pfunction = Js::JavascriptFunction::FromVar(value);
  1687. // For an odd chance that the constructor wasn't called to create the object.
  1688. Js::ParseableFunctionInfo *pFuncBody = pfunction->GetFunctionProxy() != nullptr ? pfunction->GetFunctionProxy()->EnsureDeserialized() : nullptr;
  1689. if (pFuncBody)
  1690. {
  1691. const char16* pDisplayName = pFuncBody->GetDisplayName();
  1692. if (pDisplayName)
  1693. {
  1694. builder->AppendCppLiteral(_u(", ("));
  1695. builder->AppendSz(pDisplayName);
  1696. builder->Append(_u(')'));
  1697. }
  1698. }
  1699. }
  1700. typeStr = builder->Detach();
  1701. }
  1702. else if (obj->GetDiagTypeString(builder, scriptContext))
  1703. {
  1704. typeStr = builder->Detach();
  1705. }
  1706. else
  1707. {
  1708. typeStr = _u("Undefined");
  1709. }
  1710. }
  1711. return typeStr;
  1712. }
  1713. Var RecyclableObjectDisplay::GetVarValue(BOOL fUpdated)
  1714. {
  1715. if (pObjAddress)
  1716. {
  1717. return pObjAddress->GetValue(fUpdated);
  1718. }
  1719. return instance;
  1720. }
  1721. LPCWSTR RecyclableObjectDisplay::Value(int radix)
  1722. {
  1723. LPCWSTR valueStr = _u("");
  1724. if(Js::TaggedInt::Is(instance)
  1725. || Js::JavascriptNumber::Is(instance)
  1726. || Js::JavascriptNumberObject::Is(instance)
  1727. || Js::JavascriptOperators::GetTypeId(instance) == TypeIds_Int64Number
  1728. || Js::JavascriptOperators::GetTypeId(instance) == TypeIds_UInt64Number)
  1729. {
  1730. double value;
  1731. if (Js::TaggedInt::Is(instance))
  1732. {
  1733. value = TaggedInt::ToDouble(instance);
  1734. }
  1735. else if (Js::JavascriptNumber::Is(instance))
  1736. {
  1737. value = Js::JavascriptNumber::GetValue(instance);
  1738. }
  1739. else if (Js::JavascriptOperators::GetTypeId(instance) == TypeIds_Int64Number)
  1740. {
  1741. value = (double)JavascriptInt64Number::FromVar(instance)->GetValue();
  1742. }
  1743. else if (Js::JavascriptOperators::GetTypeId(instance) == TypeIds_UInt64Number)
  1744. {
  1745. value = (double)JavascriptUInt64Number::FromVar(instance)->GetValue();
  1746. }
  1747. else
  1748. {
  1749. Js::JavascriptNumberObject* numobj = Js::JavascriptNumberObject::FromVar(instance);
  1750. value = numobj->GetValue();
  1751. }
  1752. // For fractional values, radix is ignored.
  1753. int32 l = (int32)value;
  1754. bool isZero = JavascriptNumber::IsZero(value - (double)l);
  1755. if (radix == 10 || !isZero)
  1756. {
  1757. if (Js::JavascriptNumber::IsNegZero(value))
  1758. {
  1759. // In debugger, we wanted to show negative zero explicitly
  1760. valueStr = _u("-0");
  1761. }
  1762. else
  1763. {
  1764. valueStr = Js::JavascriptNumber::ToStringRadix10(value, scriptContext)->GetSz();
  1765. }
  1766. }
  1767. else if (radix >= 2 && radix <= 36)
  1768. {
  1769. if (radix == 16)
  1770. {
  1771. if (value < 0)
  1772. {
  1773. // On the tools side we show unsigned value.
  1774. uint32 ul = static_cast<uint32>(static_cast<int32>(value)); // ARM: casting negative value to uint32 gives 0
  1775. value = (double)ul;
  1776. }
  1777. valueStr = Js::JavascriptString::Concat(scriptContext->GetLibrary()->CreateStringFromCppLiteral(_u("0x")),
  1778. Js::JavascriptNumber::ToStringRadixHelper(value, radix, scriptContext))->GetSz();
  1779. }
  1780. else
  1781. {
  1782. valueStr = Js::JavascriptNumber::ToStringRadixHelper(value, radix, scriptContext)->GetSz();
  1783. }
  1784. }
  1785. }
  1786. else
  1787. {
  1788. Js::RecyclableObject* obj = Js::RecyclableObject::FromVar(instance);
  1789. StringBuilder<ArenaAllocator>* builder = scriptContext->GetThreadContext()->GetDebugManager()->pCurrentInterpreterLocation->stringBuilder;
  1790. builder->Reset();
  1791. if (obj->GetDiagValueString(builder, scriptContext))
  1792. {
  1793. valueStr = builder->Detach();
  1794. }
  1795. else
  1796. {
  1797. valueStr = _u("undefined");
  1798. }
  1799. }
  1800. return valueStr;
  1801. }
  1802. BOOL RecyclableObjectDisplay::HasChildren()
  1803. {
  1804. if (Js::RecyclableObject::Is(instance))
  1805. {
  1806. Js::RecyclableObject* object = Js::RecyclableObject::FromVar(instance);
  1807. if (JavascriptOperators::IsObject(object))
  1808. {
  1809. if (JavascriptOperators::GetTypeId(object) == TypeIds_HostDispatch)
  1810. {
  1811. return TRUE;
  1812. }
  1813. try
  1814. {
  1815. auto funcPtr = [&]()
  1816. {
  1817. IGNORE_STACKWALK_EXCEPTION(scriptContext);
  1818. if (object->CanHaveInterceptors())
  1819. {
  1820. Js::ForInObjectEnumerator enumerator(object, object->GetScriptContext(), /* enumSymbols */ true);
  1821. Js::PropertyId propertyId;
  1822. if (enumerator.MoveAndGetNext(propertyId))
  1823. {
  1824. enumerator.Clear();
  1825. return TRUE;
  1826. }
  1827. }
  1828. else if (object->GetPropertyCount() > 0 || (JavascriptOperators::GetTypeId(object->GetPrototype()) != TypeIds_Null))
  1829. {
  1830. return TRUE;
  1831. }
  1832. return FALSE;
  1833. };
  1834. BOOL autoFuncReturn = FALSE;
  1835. if (!scriptContext->GetThreadContext()->IsScriptActive())
  1836. {
  1837. BEGIN_JS_RUNTIME_CALL_EX(scriptContext, false)
  1838. {
  1839. autoFuncReturn = funcPtr();
  1840. }
  1841. END_JS_RUNTIME_CALL(scriptContext);
  1842. }
  1843. else
  1844. {
  1845. autoFuncReturn = funcPtr();
  1846. }
  1847. if (autoFuncReturn == TRUE)
  1848. {
  1849. return TRUE;
  1850. }
  1851. }
  1852. catch (const JavascriptException& err)
  1853. {
  1854. // The For in enumerator can throw an exception and we will use the error object as a child in that case.
  1855. Var error = err.GetAndClear()->GetThrownObject(scriptContext);
  1856. if (error != nullptr && Js::JavascriptError::Is(error))
  1857. {
  1858. return TRUE;
  1859. }
  1860. return FALSE;
  1861. }
  1862. }
  1863. }
  1864. return FALSE;
  1865. }
  1866. BOOL RecyclableObjectDisplay::Set(Var updateObject)
  1867. {
  1868. if (pObjAddress)
  1869. {
  1870. return pObjAddress->Set(updateObject);
  1871. }
  1872. return FALSE;
  1873. }
  1874. DBGPROP_ATTRIB_FLAGS RecyclableObjectDisplay::GetTypeAttribute()
  1875. {
  1876. DBGPROP_ATTRIB_FLAGS flag = defaultAttributes;
  1877. if (Js::RecyclableObject::Is(instance))
  1878. {
  1879. if (instance == scriptContext->GetLibrary()->GetDebuggerDeadZoneBlockVariableString())
  1880. {
  1881. flag |= DBGPROP_ATTRIB_VALUE_IS_INVALID;
  1882. }
  1883. else if (JavascriptOperators::GetTypeId(instance) == TypeIds_Function)
  1884. {
  1885. flag |= DBGPROP_ATTRIB_VALUE_IS_METHOD;
  1886. }
  1887. else if (JavascriptOperators::GetTypeId(instance) == TypeIds_String
  1888. || JavascriptOperators::GetTypeId(instance) == TypeIds_StringObject)
  1889. {
  1890. flag |= DBGPROP_ATTRIB_VALUE_IS_RAW_STRING;
  1891. }
  1892. }
  1893. auto checkWriteableFunction = [&]()
  1894. {
  1895. if (pObjAddress && !pObjAddress->IsWritable())
  1896. {
  1897. flag |= DBGPROP_ATTRIB_VALUE_READONLY;
  1898. }
  1899. };
  1900. if (!scriptContext->GetThreadContext()->IsScriptActive())
  1901. {
  1902. BEGIN_JS_RUNTIME_CALL_EX(scriptContext, false);
  1903. {
  1904. IGNORE_STACKWALK_EXCEPTION(scriptContext);
  1905. checkWriteableFunction();
  1906. }
  1907. END_JS_RUNTIME_CALL(scriptContext);
  1908. }
  1909. else
  1910. {
  1911. checkWriteableFunction();
  1912. }
  1913. // TODO : need to identify Events explicitly for fastDOM
  1914. return flag;
  1915. }
  1916. /* static */
  1917. BOOL RecyclableObjectDisplay::GetPropertyWithScriptEnter(RecyclableObject* originalInstance, RecyclableObject* instance, PropertyId propertyId, Var* value, ScriptContext* scriptContext)
  1918. {
  1919. BOOL retValue = FALSE;
  1920. #if ENABLE_TTD
  1921. bool suppressGetterForTTDebug = scriptContext->GetThreadContext()->IsRuntimeInTTDMode() && scriptContext->GetThreadContext()->TTDLog->ShouldDoGetterInvocationSupression();
  1922. TTD::TTModeStackAutoPopper suppressModeAutoPopper(scriptContext->GetThreadContext()->TTDLog);
  1923. if(suppressGetterForTTDebug)
  1924. {
  1925. suppressModeAutoPopper.PushModeAndSetToAutoPop(TTD::TTDMode::DebuggerSuppressGetter);
  1926. }
  1927. #endif
  1928. if(!scriptContext->GetThreadContext()->IsScriptActive())
  1929. {
  1930. BEGIN_JS_RUNTIME_CALL_EX(scriptContext, false)
  1931. {
  1932. IGNORE_STACKWALK_EXCEPTION(scriptContext);
  1933. retValue = Js::JavascriptOperators::GetProperty(originalInstance, instance, propertyId, value, scriptContext);
  1934. }
  1935. END_JS_RUNTIME_CALL(scriptContext);
  1936. }
  1937. else
  1938. {
  1939. retValue = Js::JavascriptOperators::GetProperty(originalInstance, instance, propertyId, value, scriptContext);
  1940. }
  1941. return retValue;
  1942. }
  1943. WeakArenaReference<IDiagObjectModelWalkerBase>* RecyclableObjectDisplay::CreateWalker()
  1944. {
  1945. return CreateAWalker<RecyclableObjectWalker>(scriptContext, instance, originalInstance);
  1946. }
  1947. StringBuilder<ArenaAllocator>* RecyclableObjectDisplay::GetStringBuilder()
  1948. {
  1949. return scriptContext->GetThreadContext()->GetDebugManager()->pCurrentInterpreterLocation->stringBuilder;
  1950. }
  1951. PropertyId RecyclableObjectDisplay::GetPropertyId() const
  1952. {
  1953. return this->propertyId;
  1954. }
  1955. // ------------------------------------
  1956. // RecyclableObjectWalker
  1957. RecyclableObjectWalker::RecyclableObjectWalker(ScriptContext* _scriptContext, Var _slot)
  1958. : scriptContext(_scriptContext),
  1959. instance(_slot),
  1960. originalInstance(_slot),
  1961. pMembersList(nullptr),
  1962. innerArrayObjectWalker(nullptr),
  1963. fakeGroupObjectWalkerList(nullptr)
  1964. {
  1965. }
  1966. RecyclableObjectWalker::RecyclableObjectWalker(ScriptContext* _scriptContext, Var _slot, Var _originalInstance)
  1967. : scriptContext(_scriptContext),
  1968. instance(_slot),
  1969. originalInstance(_originalInstance),
  1970. pMembersList(nullptr),
  1971. innerArrayObjectWalker(nullptr),
  1972. fakeGroupObjectWalkerList(nullptr)
  1973. {
  1974. }
  1975. BOOL RecyclableObjectWalker::Get(int index, ResolvedObject* pResolvedObject)
  1976. {
  1977. AssertMsg(pResolvedObject, "Bad usage of RecyclableObjectWalker::Get");
  1978. int fakeObjCount = fakeGroupObjectWalkerList ? fakeGroupObjectWalkerList->Count() : 0;
  1979. int arrayItemCount = innerArrayObjectWalker ? innerArrayObjectWalker->GetChildrenCount() : 0;
  1980. if (index < 0 || !pMembersList || index >= (pMembersList->Count() + arrayItemCount + fakeObjCount))
  1981. {
  1982. return FALSE;
  1983. }
  1984. int nonArrayElementCount = Js::RecyclableObject::Is(instance) ? pMembersList->Count() : 0;
  1985. // First the virtual groups
  1986. if (index < fakeObjCount)
  1987. {
  1988. Assert(fakeGroupObjectWalkerList);
  1989. return fakeGroupObjectWalkerList->Item(index)->GetGroupObject(pResolvedObject);
  1990. }
  1991. index -= fakeObjCount;
  1992. if (index < nonArrayElementCount)
  1993. {
  1994. Assert(Js::RecyclableObject::Is(instance));
  1995. pResolvedObject->propId = pMembersList->Item(index)->propId;
  1996. if (pResolvedObject->propId == Js::Constants::NoProperty || Js::IsInternalPropertyId(pResolvedObject->propId))
  1997. {
  1998. Assert(FALSE);
  1999. return FALSE;
  2000. }
  2001. Js::DebuggerPropertyDisplayInfo* displayInfo = pMembersList->Item(index);
  2002. const Js::PropertyRecord* propertyRecord = scriptContext->GetPropertyName(pResolvedObject->propId);
  2003. pResolvedObject->name = propertyRecord->GetBuffer();
  2004. pResolvedObject->obj = displayInfo->aVar;
  2005. Assert(pResolvedObject->obj);
  2006. pResolvedObject->scriptContext = scriptContext;
  2007. pResolvedObject->typeId = JavascriptOperators::GetTypeId(pResolvedObject->obj);
  2008. pResolvedObject->address = Anew(GetArenaFromContext(scriptContext),
  2009. RecyclableObjectAddress,
  2010. instance,
  2011. pResolvedObject->propId,
  2012. pResolvedObject->obj,
  2013. displayInfo->IsInDeadZone() ? TRUE : FALSE);
  2014. pResolvedObject->isConst = displayInfo->IsConst();
  2015. return TRUE;
  2016. }
  2017. index -= nonArrayElementCount;
  2018. if (index < arrayItemCount)
  2019. {
  2020. Assert(innerArrayObjectWalker);
  2021. return innerArrayObjectWalker->Get(index, pResolvedObject);
  2022. }
  2023. Assert(false);
  2024. return FALSE;
  2025. }
  2026. void RecyclableObjectWalker::EnsureFakeGroupObjectWalkerList()
  2027. {
  2028. if (fakeGroupObjectWalkerList == nullptr)
  2029. {
  2030. ArenaAllocator *arena = GetArenaFromContext(scriptContext);
  2031. fakeGroupObjectWalkerList = JsUtil::List<IDiagObjectModelWalkerBase *, ArenaAllocator>::New(arena);
  2032. }
  2033. }
  2034. IDiagObjectAddress *RecyclableObjectWalker::FindPropertyAddress(PropertyId propertyId, bool& isConst)
  2035. {
  2036. GetChildrenCount(); // Ensure to populate members
  2037. if (pMembersList != nullptr)
  2038. {
  2039. for (int i = 0; i < pMembersList->Count(); i++)
  2040. {
  2041. DebuggerPropertyDisplayInfo *pair = pMembersList->Item(i);
  2042. Assert(pair);
  2043. if (pair->propId == propertyId)
  2044. {
  2045. isConst = pair->IsConst();
  2046. return Anew(GetArenaFromContext(scriptContext),
  2047. RecyclableObjectAddress,
  2048. instance,
  2049. propertyId,
  2050. pair->aVar,
  2051. pair->IsInDeadZone() ? TRUE : FALSE);
  2052. }
  2053. }
  2054. }
  2055. // Following is for "with object" scope lookup. We may have members in [Methods] group or prototype chain that need to
  2056. // be exposed to expression evaluation.
  2057. if (fakeGroupObjectWalkerList != nullptr)
  2058. {
  2059. // WARNING: Following depends on [Methods] group being before [prototype] group. We need to check local [Methods] group
  2060. // first for local properties before going to prototype chain.
  2061. for (int i = 0; i < fakeGroupObjectWalkerList->Count(); i++)
  2062. {
  2063. IDiagObjectAddress* address = fakeGroupObjectWalkerList->Item(i)->FindPropertyAddress(propertyId, isConst);
  2064. if (address != nullptr)
  2065. {
  2066. return address;
  2067. }
  2068. }
  2069. }
  2070. return nullptr;
  2071. }
  2072. uint32 RecyclableObjectWalker::GetChildrenCount()
  2073. {
  2074. if (pMembersList == nullptr)
  2075. {
  2076. ArenaAllocator *arena = GetArenaFromContext(scriptContext);
  2077. pMembersList = JsUtil::List<DebuggerPropertyDisplayInfo *, ArenaAllocator>::New(arena);
  2078. RecyclableMethodsGroupWalker *pMethodsGroupWalker = nullptr;
  2079. if (Js::RecyclableObject::Is(instance))
  2080. {
  2081. Js::RecyclableObject* object = Js::RecyclableObject::FromVar(instance);
  2082. // If we are walking a prototype, we'll use its instance for property names enumeration, but originalInstance to get values
  2083. Js::RecyclableObject* originalObject = (originalInstance != nullptr) ? Js::RecyclableObject::FromVar(originalInstance) : object;
  2084. const Js::TypeId typeId = JavascriptOperators::GetTypeId(instance);
  2085. if (JavascriptOperators::IsObject(object))
  2086. {
  2087. if (object->CanHaveInterceptors() || JavascriptOperators::GetTypeId(object) == TypeIds_Proxy)
  2088. {
  2089. try
  2090. {
  2091. ScriptContext * objectContext = object->GetScriptContext();
  2092. JavascriptStaticEnumerator enumerator;
  2093. if (object->GetEnumerator(&enumerator, EnumeratorFlags::EnumNonEnumerable | EnumeratorFlags::EnumSymbols, objectContext))
  2094. {
  2095. Js::PropertyId propertyId;
  2096. JavascriptString * obj;
  2097. while ((obj = enumerator.MoveAndGetNext(propertyId)) != nullptr)
  2098. {
  2099. if (propertyId == Constants::NoProperty)
  2100. {
  2101. if (VirtualTableInfo<Js::PropertyString>::HasVirtualTable(obj))
  2102. {
  2103. // If we have a property string, it is assumed that the propertyId is being
  2104. // kept alive with the object
  2105. PropertyString * propertyString = (PropertyString *)obj;
  2106. propertyId = propertyString->GetPropertyRecord()->GetPropertyId();
  2107. }
  2108. else
  2109. {
  2110. const PropertyRecord* propertyRecord;
  2111. objectContext->GetOrAddPropertyRecord(obj, &propertyRecord);
  2112. propertyId = propertyRecord->GetPropertyId();
  2113. }
  2114. }
  2115. // MoveAndGetNext shouldn't return an internal property id
  2116. Assert(!Js::IsInternalPropertyId(propertyId));
  2117. uint32 indexVal;
  2118. Var varValue;
  2119. if (objectContext->IsNumericPropertyId(propertyId, &indexVal) && object->GetItem(object, indexVal, &varValue, objectContext))
  2120. {
  2121. InsertItem(propertyId, false /*isConst*/, false /*isUnscoped*/, varValue, &pMethodsGroupWalker, true /*shouldPinProperty*/);
  2122. }
  2123. else
  2124. {
  2125. InsertItem(originalObject, object, propertyId, false /*isConst*/, false /*isUnscoped*/, &pMethodsGroupWalker, true /*shouldPinProperty*/);
  2126. }
  2127. }
  2128. }
  2129. }
  2130. catch (const JavascriptException& err)
  2131. {
  2132. Var error = err.GetAndClear()->GetThrownObject(scriptContext);
  2133. if (error != nullptr && Js::JavascriptError::Is(error))
  2134. {
  2135. Js::PropertyId propertyId = scriptContext->GetOrAddPropertyIdTracked(_u("{error}"));
  2136. InsertItem(propertyId, false /*isConst*/, false /*isUnscoped*/, error, &pMethodsGroupWalker);
  2137. }
  2138. }
  2139. if (typeId == TypeIds_Proxy)
  2140. {
  2141. // Provide [Proxy] group object
  2142. EnsureFakeGroupObjectWalkerList();
  2143. JavascriptProxy* proxy = JavascriptProxy::FromVar(object);
  2144. RecyclableProxyObjectWalker* proxyWalker = Anew(arena, RecyclableProxyObjectWalker, scriptContext, proxy);
  2145. fakeGroupObjectWalkerList->Add(proxyWalker);
  2146. }
  2147. // If current object has internal proto object then provide [prototype] group object.
  2148. if (JavascriptOperators::GetTypeId(object->GetPrototype()) != TypeIds_Null)
  2149. {
  2150. // Has [prototype] object.
  2151. EnsureFakeGroupObjectWalkerList();
  2152. RecyclableProtoObjectWalker *pProtoWalker = Anew(arena, RecyclableProtoObjectWalker, scriptContext, instance, (originalInstance == nullptr) ? instance : originalInstance);
  2153. fakeGroupObjectWalkerList->Add(pProtoWalker);
  2154. }
  2155. }
  2156. else
  2157. {
  2158. RecyclableObject* wrapperObject = nullptr;
  2159. if (JavascriptOperators::GetTypeId(object) == TypeIds_WithScopeObject)
  2160. {
  2161. wrapperObject = object;
  2162. object = object->GetThisObjectOrUnWrap();
  2163. }
  2164. int count = object->GetPropertyCount();
  2165. for (int i = 0; i < count; i++)
  2166. {
  2167. Js::PropertyId propertyId = object->GetPropertyId((PropertyIndex)i);
  2168. bool isUnscoped = false;
  2169. if (wrapperObject && JavascriptOperators::IsPropertyUnscopable(object, propertyId))
  2170. {
  2171. isUnscoped = true;
  2172. }
  2173. if (propertyId != Js::Constants::NoProperty && !Js::IsInternalPropertyId(propertyId))
  2174. {
  2175. InsertItem(originalObject, object, propertyId, false /*isConst*/, isUnscoped, &pMethodsGroupWalker);
  2176. }
  2177. }
  2178. if (CONFIG_FLAG(EnumerateSpecialPropertiesInDebugger))
  2179. {
  2180. count = object->GetSpecialPropertyCount();
  2181. PropertyId const * specialPropertyIds = object->GetSpecialPropertyIds();
  2182. for (int i = 0; i < count; i++)
  2183. {
  2184. Js::PropertyId propertyId = specialPropertyIds[i];
  2185. bool isUnscoped = false;
  2186. if (wrapperObject && JavascriptOperators::IsPropertyUnscopable(object, propertyId))
  2187. {
  2188. isUnscoped = true;
  2189. }
  2190. if (propertyId != Js::Constants::NoProperty)
  2191. {
  2192. bool isConst = true;
  2193. if (propertyId == PropertyIds::length && Js::JavascriptArray::Is(object))
  2194. {
  2195. // For JavascriptArrays, we allow resetting the length special property.
  2196. isConst = false;
  2197. }
  2198. auto containsPredicate = [&](Js::DebuggerPropertyDisplayInfo* info) { return info->propId == propertyId; };
  2199. if (Js::BoundFunction::Is(object)
  2200. && this->pMembersList->Any(containsPredicate))
  2201. {
  2202. // Bound functions can already contain their special properties,
  2203. // so we need to check for that (caller and arguments). This occurs
  2204. // when JavascriptFunction::EntryBind() is called. Arguments can similarly
  2205. // already display caller in compat mode 8.
  2206. continue;
  2207. }
  2208. AssertMsg(!this->pMembersList->Any(containsPredicate), "Special property already on the object, no need to insert.");
  2209. InsertItem(originalObject, object, propertyId, isConst, isUnscoped, &pMethodsGroupWalker);
  2210. }
  2211. }
  2212. if (Js::JavascriptFunction::Is(object))
  2213. {
  2214. // We need to special-case RegExp constructor here because it has some special properties (above) and some
  2215. // special enumerable properties which should all show up in the debugger.
  2216. JavascriptRegExpConstructor* regExp = scriptContext->GetLibrary()->GetRegExpConstructor();
  2217. if (regExp == object)
  2218. {
  2219. bool isUnscoped = false;
  2220. bool isConst = true;
  2221. count = regExp->GetSpecialEnumerablePropertyCount();
  2222. PropertyId const * specialEnumerablePropertyIds = regExp->GetSpecialEnumerablePropertyIds();
  2223. for (int i = 0; i < count; i++)
  2224. {
  2225. Js::PropertyId propertyId = specialEnumerablePropertyIds[i];
  2226. InsertItem(originalObject, object, propertyId, isConst, isUnscoped, &pMethodsGroupWalker);
  2227. }
  2228. }
  2229. else if (Js::JavascriptFunction::FromVar(object)->IsScriptFunction() || Js::JavascriptFunction::FromVar(object)->IsBoundFunction())
  2230. {
  2231. // Adding special property length for the ScriptFunction, like it is done in JavascriptFunction::GetSpecialNonEnumerablePropertyName
  2232. InsertItem(originalObject, object, PropertyIds::length, true/*not editable*/, false /*isUnscoped*/, &pMethodsGroupWalker);
  2233. }
  2234. }
  2235. }
  2236. // If current object has internal proto object then provide [prototype] group object.
  2237. if (JavascriptOperators::GetTypeId(object->GetPrototype()) != TypeIds_Null)
  2238. {
  2239. // Has [prototype] object.
  2240. EnsureFakeGroupObjectWalkerList();
  2241. RecyclableProtoObjectWalker *pProtoWalker = Anew(arena, RecyclableProtoObjectWalker, scriptContext, instance, originalInstance);
  2242. fakeGroupObjectWalkerList->Add(pProtoWalker);
  2243. }
  2244. }
  2245. // If the object contains array indices.
  2246. if (typeId == TypeIds_Arguments)
  2247. {
  2248. // Create ArgumentsArray walker for an arguments object
  2249. Js::ArgumentsObject * argObj = static_cast<Js::ArgumentsObject*>(instance);
  2250. Assert(argObj);
  2251. if (argObj->GetNumberOfArguments() > 0 || argObj->HasNonEmptyObjectArray())
  2252. {
  2253. innerArrayObjectWalker = Anew(arena, RecyclableArgumentsArrayWalker, scriptContext, (Var)instance, originalInstance);
  2254. }
  2255. }
  2256. else if (typeId == TypeIds_Map)
  2257. {
  2258. // Provide [Map] group object.
  2259. EnsureFakeGroupObjectWalkerList();
  2260. JavascriptMap* map = JavascriptMap::FromVar(object);
  2261. RecyclableMapObjectWalker *pMapWalker = Anew(arena, RecyclableMapObjectWalker, scriptContext, map);
  2262. fakeGroupObjectWalkerList->Add(pMapWalker);
  2263. }
  2264. else if (typeId == TypeIds_Set)
  2265. {
  2266. // Provide [Set] group object.
  2267. EnsureFakeGroupObjectWalkerList();
  2268. JavascriptSet* set = JavascriptSet::FromVar(object);
  2269. RecyclableSetObjectWalker *pSetWalker = Anew(arena, RecyclableSetObjectWalker, scriptContext, set);
  2270. fakeGroupObjectWalkerList->Add(pSetWalker);
  2271. }
  2272. else if (typeId == TypeIds_WeakMap)
  2273. {
  2274. // Provide [WeakMap] group object.
  2275. EnsureFakeGroupObjectWalkerList();
  2276. JavascriptWeakMap* weakMap = JavascriptWeakMap::FromVar(object);
  2277. RecyclableWeakMapObjectWalker *pWeakMapWalker = Anew(arena, RecyclableWeakMapObjectWalker, scriptContext, weakMap);
  2278. fakeGroupObjectWalkerList->Add(pWeakMapWalker);
  2279. }
  2280. else if (typeId == TypeIds_WeakSet)
  2281. {
  2282. // Provide [WeakSet] group object.
  2283. EnsureFakeGroupObjectWalkerList();
  2284. JavascriptWeakSet* weakSet = JavascriptWeakSet::FromVar(object);
  2285. RecyclableWeakSetObjectWalker *pWeakSetWalker = Anew(arena, RecyclableWeakSetObjectWalker, scriptContext, weakSet);
  2286. fakeGroupObjectWalkerList->Add(pWeakSetWalker);
  2287. }
  2288. else if (typeId == TypeIds_Promise)
  2289. {
  2290. // Provide [Promise] group object.
  2291. EnsureFakeGroupObjectWalkerList();
  2292. JavascriptPromise* promise = JavascriptPromise::FromVar(object);
  2293. RecyclablePromiseObjectWalker *pPromiseWalker = Anew(arena, RecyclablePromiseObjectWalker, scriptContext, promise);
  2294. fakeGroupObjectWalkerList->Add(pPromiseWalker);
  2295. }
  2296. else if (Js::DynamicType::Is(typeId))
  2297. {
  2298. DynamicObject *const dynamicObject = Js::DynamicObject::FromVar(instance);
  2299. if (dynamicObject->HasNonEmptyObjectArray())
  2300. {
  2301. ArrayObject* objectArray = dynamicObject->GetObjectArray();
  2302. if (Js::ES5Array::Is(objectArray))
  2303. {
  2304. innerArrayObjectWalker = Anew(arena, RecyclableES5ArrayWalker, scriptContext, objectArray, originalInstance);
  2305. }
  2306. else if (Js::JavascriptArray::Is(objectArray))
  2307. {
  2308. innerArrayObjectWalker = Anew(arena, RecyclableArrayWalker, scriptContext, objectArray, originalInstance);
  2309. }
  2310. else
  2311. {
  2312. innerArrayObjectWalker = Anew(arena, RecyclableTypedArrayWalker, scriptContext, objectArray, originalInstance);
  2313. }
  2314. innerArrayObjectWalker->SetOnlyWalkOwnProperties(true);
  2315. }
  2316. }
  2317. }
  2318. }
  2319. // Sort the members of the methods group
  2320. if (pMethodsGroupWalker)
  2321. {
  2322. pMethodsGroupWalker->Sort();
  2323. }
  2324. // Sort current pMembersList.
  2325. HostDebugContext* hostDebugContext = scriptContext->GetDebugContext()->GetHostDebugContext();
  2326. if (hostDebugContext != nullptr)
  2327. {
  2328. hostDebugContext->SortMembersList(pMembersList, scriptContext);
  2329. }
  2330. }
  2331. uint32 childrenCount =
  2332. pMembersList->Count()
  2333. + (innerArrayObjectWalker ? innerArrayObjectWalker->GetChildrenCount() : 0)
  2334. + (fakeGroupObjectWalkerList ? fakeGroupObjectWalkerList->Count() : 0);
  2335. return childrenCount;
  2336. }
  2337. void RecyclableObjectWalker::InsertItem(
  2338. Js::RecyclableObject *pOriginalObject,
  2339. Js::RecyclableObject *pObject,
  2340. PropertyId propertyId,
  2341. bool isReadOnly,
  2342. bool isUnscoped,
  2343. Js::RecyclableMethodsGroupWalker **ppMethodsGroupWalker,
  2344. bool shouldPinProperty /* = false*/)
  2345. {
  2346. Assert(pOriginalObject);
  2347. Assert(pObject);
  2348. Assert(propertyId);
  2349. Assert(ppMethodsGroupWalker);
  2350. if (propertyId != PropertyIds::__proto__)
  2351. {
  2352. InsertItem(propertyId, isReadOnly, isUnscoped, RecyclableObjectWalker::GetObject(pOriginalObject, pObject, propertyId, scriptContext), ppMethodsGroupWalker, shouldPinProperty);
  2353. }
  2354. else // Since __proto__ defined as a Getter we should always evaluate it against object itself instead of walking prototype chain
  2355. {
  2356. InsertItem(propertyId, isReadOnly, isUnscoped, RecyclableObjectWalker::GetObject(pObject, pObject, propertyId, scriptContext), ppMethodsGroupWalker, shouldPinProperty);
  2357. }
  2358. }
  2359. void RecyclableObjectWalker::InsertItem(
  2360. PropertyId propertyId,
  2361. bool isConst,
  2362. bool isUnscoped,
  2363. Var itemObj,
  2364. Js:: RecyclableMethodsGroupWalker **ppMethodsGroupWalker,
  2365. bool shouldPinProperty /* = false*/)
  2366. {
  2367. Assert(propertyId);
  2368. Assert(ppMethodsGroupWalker);
  2369. if (itemObj == nullptr)
  2370. {
  2371. itemObj = scriptContext->GetLibrary()->GetUndefined();
  2372. }
  2373. if (shouldPinProperty)
  2374. {
  2375. const Js::PropertyRecord * propertyRecord = scriptContext->GetPropertyName(propertyId);
  2376. if (propertyRecord)
  2377. {
  2378. // Pin this record so that it will not go away till we are done with this break.
  2379. scriptContext->GetDebugContext()->GetProbeContainer()->PinPropertyRecord(propertyRecord);
  2380. }
  2381. }
  2382. ArenaAllocator *arena = GetArenaFromContext(scriptContext);
  2383. if (JavascriptOperators::GetTypeId(itemObj) == TypeIds_Function)
  2384. {
  2385. if (scriptContext->GetThreadContext()->GetDebugManager()->IsLocalsDisplayFlagsSet(Js::DebugManager::LocalsDisplayFlags::LocalsDisplayFlags_NoGroupMethods))
  2386. {
  2387. DebuggerPropertyDisplayInfo *info = Anew(arena, DebuggerPropertyDisplayInfo, propertyId, itemObj, DebuggerPropertyDisplayInfoFlags_Const);
  2388. pMembersList->Add(info);
  2389. }
  2390. else
  2391. {
  2392. EnsureFakeGroupObjectWalkerList();
  2393. if (*ppMethodsGroupWalker == nullptr)
  2394. {
  2395. *ppMethodsGroupWalker = Anew(arena, RecyclableMethodsGroupWalker, scriptContext, instance);
  2396. fakeGroupObjectWalkerList->Add(*ppMethodsGroupWalker);
  2397. }
  2398. (*ppMethodsGroupWalker)->AddItem(propertyId, itemObj);
  2399. }
  2400. }
  2401. else
  2402. {
  2403. DWORD flags = DebuggerPropertyDisplayInfoFlags_None;
  2404. flags |= isConst ? DebuggerPropertyDisplayInfoFlags_Const : 0;
  2405. flags |= isUnscoped ? DebuggerPropertyDisplayInfoFlags_Unscope : 0;
  2406. DebuggerPropertyDisplayInfo *info = Anew(arena, DebuggerPropertyDisplayInfo, propertyId, itemObj, flags);
  2407. pMembersList->Add(info);
  2408. }
  2409. }
  2410. /*static*/
  2411. Var RecyclableObjectWalker::GetObject(RecyclableObject* originalInstance, RecyclableObject* instance, PropertyId propertyId, ScriptContext* scriptContext)
  2412. {
  2413. Assert(instance);
  2414. Assert(!Js::IsInternalPropertyId(propertyId));
  2415. Var obj = nullptr;
  2416. try
  2417. {
  2418. if (!RecyclableObjectDisplay::GetPropertyWithScriptEnter(originalInstance, instance, propertyId, &obj, scriptContext))
  2419. {
  2420. return instance->GetScriptContext()->GetMissingPropertyResult();
  2421. }
  2422. }
  2423. catch(const JavascriptException& err)
  2424. {
  2425. Var error = err.GetAndClear()->GetThrownObject(instance->GetScriptContext());
  2426. if (error != nullptr && Js::JavascriptError::Is(error))
  2427. {
  2428. obj = error;
  2429. }
  2430. }
  2431. return obj;
  2432. }
  2433. //--------------------------
  2434. // RecyclableArrayAddress
  2435. RecyclableArrayAddress::RecyclableArrayAddress(Var _parentArray, unsigned int _index)
  2436. : parentArray(_parentArray),
  2437. index(_index)
  2438. {
  2439. }
  2440. BOOL RecyclableArrayAddress::Set(Var updateObject)
  2441. {
  2442. if (Js::JavascriptArray::Is(parentArray))
  2443. {
  2444. Js::JavascriptArray* jsArray = Js::JavascriptArray::FromVar(parentArray);
  2445. return jsArray->SetItem(index, updateObject, PropertyOperation_None);
  2446. }
  2447. return FALSE;
  2448. }
  2449. //--------------------------
  2450. // RecyclableArrayDisplay
  2451. RecyclableArrayDisplay::RecyclableArrayDisplay(ResolvedObject* resolvedObject)
  2452. : RecyclableObjectDisplay(resolvedObject)
  2453. {
  2454. }
  2455. BOOL RecyclableArrayDisplay::HasChildrenInternal(Js::JavascriptArray* arrayObj)
  2456. {
  2457. Assert(arrayObj);
  2458. if (JavascriptOperators::GetTypeId(arrayObj->GetPrototype()) != TypeIds_Null)
  2459. {
  2460. return TRUE;
  2461. }
  2462. uint32 index = arrayObj->GetNextIndex(Js::JavascriptArray::InvalidIndex);
  2463. return index != Js::JavascriptArray::InvalidIndex && index < arrayObj->GetLength();
  2464. }
  2465. BOOL RecyclableArrayDisplay::HasChildren()
  2466. {
  2467. if (Js::JavascriptArray::Is(instance))
  2468. {
  2469. Js::JavascriptArray* arrayObj = Js::JavascriptArray::FromVar(instance);
  2470. if (HasChildrenInternal(arrayObj))
  2471. {
  2472. return TRUE;
  2473. }
  2474. }
  2475. return RecyclableObjectDisplay::HasChildren();
  2476. }
  2477. WeakArenaReference<IDiagObjectModelWalkerBase>* RecyclableArrayDisplay::CreateWalker()
  2478. {
  2479. return CreateAWalker<RecyclableArrayWalker>(scriptContext, instance, originalInstance);
  2480. }
  2481. //--------------------------
  2482. // RecyclableArrayWalker
  2483. uint32 RecyclableArrayWalker::GetItemCount(Js::JavascriptArray* arrayObj)
  2484. {
  2485. if (pAbsoluteIndexList == nullptr)
  2486. {
  2487. Assert(arrayObj);
  2488. pAbsoluteIndexList = JsUtil::List<uint32, ArenaAllocator>::New(GetArenaFromContext(scriptContext));
  2489. Assert(pAbsoluteIndexList);
  2490. uint32 dataIndex = Js::JavascriptArray::InvalidIndex;
  2491. uint32 descriptorIndex = Js::JavascriptArray::InvalidIndex;
  2492. uint32 absIndex = Js::JavascriptArray::InvalidIndex;
  2493. do
  2494. {
  2495. if (absIndex == dataIndex)
  2496. {
  2497. dataIndex = arrayObj->GetNextIndex(dataIndex);
  2498. }
  2499. if (absIndex == descriptorIndex)
  2500. {
  2501. descriptorIndex = GetNextDescriptor(descriptorIndex);
  2502. }
  2503. absIndex = min(dataIndex, descriptorIndex);
  2504. if (absIndex == Js::JavascriptArray::InvalidIndex || absIndex >= arrayObj->GetLength())
  2505. {
  2506. break;
  2507. }
  2508. pAbsoluteIndexList->Add(absIndex);
  2509. } while (absIndex < arrayObj->GetLength());
  2510. }
  2511. return (uint32)pAbsoluteIndexList->Count();
  2512. }
  2513. BOOL RecyclableArrayWalker::FetchItemAtIndex(Js::JavascriptArray* arrayObj, uint32 index, Var * value)
  2514. {
  2515. Assert(arrayObj);
  2516. Assert(value);
  2517. return arrayObj->DirectGetItemAt(index, value);
  2518. }
  2519. Var RecyclableArrayWalker::FetchItemAt(Js::JavascriptArray* arrayObj, uint32 index)
  2520. {
  2521. Assert(arrayObj);
  2522. return arrayObj->DirectGetItem(index);
  2523. }
  2524. LPCWSTR RecyclableArrayWalker::GetIndexName(uint32 index, StringBuilder<ArenaAllocator>* stringBuilder)
  2525. {
  2526. stringBuilder->Append(_u('['));
  2527. if (stringBuilder->AppendUint64(index) != 0)
  2528. {
  2529. return _u("[.]");
  2530. }
  2531. stringBuilder->Append(_u(']'));
  2532. return stringBuilder->Detach();
  2533. }
  2534. RecyclableArrayWalker::RecyclableArrayWalker(ScriptContext* scriptContext, Var instance, Var originalInstance)
  2535. : indexedItemCount(0),
  2536. pAbsoluteIndexList(nullptr),
  2537. fOnlyOwnProperties(false),
  2538. RecyclableObjectWalker(scriptContext,instance,originalInstance)
  2539. {
  2540. }
  2541. BOOL RecyclableArrayWalker::GetResolvedObject(Js::JavascriptArray* arrayObj, int index, ResolvedObject* pResolvedObject, uint32 * pabsIndex)
  2542. {
  2543. Assert(arrayObj);
  2544. Assert(pResolvedObject);
  2545. Assert(pAbsoluteIndexList);
  2546. Assert(pAbsoluteIndexList->Count() > index);
  2547. // translate i'th Item to the correct array index and return
  2548. uint32 absIndex = pAbsoluteIndexList->Item(index);
  2549. pResolvedObject->obj = FetchItemAt(arrayObj, absIndex);
  2550. pResolvedObject->scriptContext = scriptContext;
  2551. pResolvedObject->typeId = JavascriptOperators::GetTypeId(pResolvedObject->obj);
  2552. pResolvedObject->address = nullptr;
  2553. StringBuilder<ArenaAllocator>* builder = GetBuilder();
  2554. Assert(builder);
  2555. builder->Reset();
  2556. pResolvedObject->name = GetIndexName(absIndex, builder);
  2557. if (pabsIndex)
  2558. {
  2559. *pabsIndex = absIndex;
  2560. }
  2561. return TRUE;
  2562. }
  2563. BOOL RecyclableArrayWalker::Get(int i, ResolvedObject* pResolvedObject)
  2564. {
  2565. AssertMsg(pResolvedObject, "Bad usage of RecyclableArrayWalker::Get");
  2566. if (Js::JavascriptArray::Is(instance) || Js::ES5Array::Is(instance))
  2567. {
  2568. Js::JavascriptArray* arrayObj = GetArrayObject();
  2569. int nonArrayElementCount = (!fOnlyOwnProperties ? RecyclableObjectWalker::GetChildrenCount() : 0);
  2570. if (i < nonArrayElementCount)
  2571. {
  2572. return RecyclableObjectWalker::Get(i, pResolvedObject);
  2573. }
  2574. else
  2575. {
  2576. i -= nonArrayElementCount;
  2577. uint32 absIndex; // Absolute index
  2578. GetResolvedObject(arrayObj, i, pResolvedObject, &absIndex);
  2579. pResolvedObject->address = Anew(GetArenaFromContext(scriptContext),
  2580. RecyclableArrayAddress,
  2581. instance,
  2582. absIndex);
  2583. return TRUE;
  2584. }
  2585. }
  2586. return FALSE;
  2587. }
  2588. Js::JavascriptArray* RecyclableArrayWalker::GetArrayObject()
  2589. {
  2590. Assert(Js::JavascriptArray::Is(instance) || Js::ES5Array::Is(instance));
  2591. return Js::ES5Array::Is(instance) ?
  2592. static_cast<Js::JavascriptArray *>(RecyclableObject::FromVar(instance)) :
  2593. Js::JavascriptArray::FromVar(instance);
  2594. }
  2595. uint32 RecyclableArrayWalker::GetChildrenCount()
  2596. {
  2597. if (Js::JavascriptArray::Is(instance) || Js::ES5Array::Is(instance))
  2598. {
  2599. uint32 count = (!fOnlyOwnProperties ? RecyclableObjectWalker::GetChildrenCount() : 0);
  2600. Js::JavascriptArray* arrayObj = GetArrayObject();
  2601. return GetItemCount(arrayObj) + count;
  2602. }
  2603. return 0;
  2604. }
  2605. StringBuilder<ArenaAllocator>* RecyclableArrayWalker::GetBuilder()
  2606. {
  2607. return scriptContext->GetThreadContext()->GetDebugManager()->pCurrentInterpreterLocation->stringBuilder;
  2608. }
  2609. //--------------------------
  2610. // RecyclableArgumentsArrayAddress
  2611. RecyclableArgumentsArrayAddress::RecyclableArgumentsArrayAddress(Var _parentArray, unsigned int _index)
  2612. : parentArray(_parentArray),
  2613. index(_index)
  2614. {
  2615. }
  2616. BOOL RecyclableArgumentsArrayAddress::Set(Var updateObject)
  2617. {
  2618. if (Js::ArgumentsObject::Is(parentArray))
  2619. {
  2620. Js::ArgumentsObject* argObj = static_cast<Js::ArgumentsObject*>(parentArray);
  2621. return argObj->SetItem(index, updateObject, PropertyOperation_None);
  2622. }
  2623. return FALSE;
  2624. }
  2625. //--------------------------
  2626. // RecyclableArgumentsObjectDisplay
  2627. RecyclableArgumentsObjectDisplay::RecyclableArgumentsObjectDisplay(ResolvedObject* resolvedObject, LocalsWalker *localsWalker)
  2628. : RecyclableObjectDisplay(resolvedObject), pLocalsWalker(localsWalker)
  2629. {
  2630. }
  2631. BOOL RecyclableArgumentsObjectDisplay::HasChildren()
  2632. {
  2633. // It must have children otherwise object itself was not created in first place.
  2634. return TRUE;
  2635. }
  2636. WeakArenaReference<IDiagObjectModelWalkerBase>* RecyclableArgumentsObjectDisplay::CreateWalker()
  2637. {
  2638. ReferencedArenaAdapter* pRefArena = scriptContext->GetThreadContext()->GetDebugManager()->GetDiagnosticArena();
  2639. if (pRefArena)
  2640. {
  2641. IDiagObjectModelWalkerBase* pOMWalker = Anew(pRefArena->Arena(), RecyclableArgumentsObjectWalker, scriptContext, instance, pLocalsWalker);
  2642. return HeapNew(WeakArenaReference<IDiagObjectModelWalkerBase>,pRefArena, pOMWalker);
  2643. }
  2644. return nullptr;
  2645. }
  2646. //--------------------------
  2647. // RecyclableArgumentsObjectWalker
  2648. RecyclableArgumentsObjectWalker::RecyclableArgumentsObjectWalker(ScriptContext* pContext, Var _instance, LocalsWalker * localsWalker)
  2649. : RecyclableObjectWalker(pContext, _instance), pLocalsWalker(localsWalker)
  2650. {
  2651. }
  2652. uint32 RecyclableArgumentsObjectWalker::GetChildrenCount()
  2653. {
  2654. if (innerArrayObjectWalker == nullptr)
  2655. {
  2656. uint32 count = RecyclableObjectWalker::GetChildrenCount();
  2657. if (innerArrayObjectWalker != nullptr)
  2658. {
  2659. RecyclableArgumentsArrayWalker *pWalker = static_cast<RecyclableArgumentsArrayWalker *> (innerArrayObjectWalker);
  2660. pWalker->FetchFormalsAddress(pLocalsWalker);
  2661. }
  2662. return count;
  2663. }
  2664. return RecyclableObjectWalker::GetChildrenCount();
  2665. }
  2666. //--------------------------
  2667. // RecyclableArgumentsArrayWalker
  2668. RecyclableArgumentsArrayWalker::RecyclableArgumentsArrayWalker(ScriptContext* _scriptContext, Var _instance, Var _originalInstance)
  2669. : RecyclableArrayWalker(_scriptContext, _instance, _originalInstance), pFormalsList(nullptr)
  2670. {
  2671. }
  2672. uint32 RecyclableArgumentsArrayWalker::GetChildrenCount()
  2673. {
  2674. if (pMembersList == nullptr)
  2675. {
  2676. Assert(Js::ArgumentsObject::Is(instance));
  2677. Js::ArgumentsObject * argObj = static_cast<Js::ArgumentsObject*>(instance);
  2678. pMembersList = JsUtil::List<DebuggerPropertyDisplayInfo *, ArenaAllocator>::New(GetArenaFromContext(scriptContext));
  2679. Assert(pMembersList);
  2680. uint32 totalCount = argObj->GetNumberOfArguments();
  2681. Js::ArrayObject * objectArray = argObj->GetObjectArray();
  2682. if (objectArray != nullptr && objectArray->GetLength() > totalCount)
  2683. {
  2684. totalCount = objectArray->GetLength();
  2685. }
  2686. for (uint32 index = 0; index < totalCount; index++)
  2687. {
  2688. Var itemObj;
  2689. if (argObj->GetItem(argObj, index, &itemObj, scriptContext))
  2690. {
  2691. DebuggerPropertyDisplayInfo *info = Anew(GetArenaFromContext(scriptContext), DebuggerPropertyDisplayInfo, index, itemObj, DebuggerPropertyDisplayInfoFlags_None);
  2692. Assert(info);
  2693. pMembersList->Add(info);
  2694. }
  2695. }
  2696. }
  2697. return pMembersList ? pMembersList->Count() : 0;
  2698. }
  2699. void RecyclableArgumentsArrayWalker::FetchFormalsAddress(LocalsWalker * localsWalker)
  2700. {
  2701. Assert(localsWalker);
  2702. Assert(localsWalker->pFrame);
  2703. Js::FunctionBody *pFBody = localsWalker->pFrame->GetJavascriptFunction()->GetFunctionBody();
  2704. Assert(pFBody);
  2705. PropertyIdOnRegSlotsContainer * container = pFBody->GetPropertyIdOnRegSlotsContainer();
  2706. if (container && container->propertyIdsForFormalArgs)
  2707. {
  2708. for (uint32 i = 0; i < container->propertyIdsForFormalArgs->count; i++)
  2709. {
  2710. if (container->propertyIdsForFormalArgs->elements[i] != Js::Constants::NoRegister)
  2711. {
  2712. bool isConst = false;
  2713. IDiagObjectAddress * address = localsWalker->FindPropertyAddress(container->propertyIdsForFormalArgs->elements[i], false, isConst);
  2714. if (address)
  2715. {
  2716. if (pFormalsList == nullptr)
  2717. {
  2718. pFormalsList = JsUtil::List<IDiagObjectAddress *, ArenaAllocator>::New(GetArenaFromContext(scriptContext));
  2719. }
  2720. pFormalsList->Add(address);
  2721. }
  2722. }
  2723. }
  2724. }
  2725. }
  2726. BOOL RecyclableArgumentsArrayWalker::Get(int i, ResolvedObject* pResolvedObject)
  2727. {
  2728. AssertMsg(pResolvedObject, "Bad usage of RecyclableArgumentsArrayWalker::Get");
  2729. Assert(i >= 0);
  2730. Assert(Js::ArgumentsObject::Is(instance));
  2731. if (pMembersList && i < pMembersList->Count())
  2732. {
  2733. Assert(pMembersList->Item(i) != nullptr);
  2734. pResolvedObject->address = nullptr;
  2735. if (pFormalsList && i < pFormalsList->Count())
  2736. {
  2737. pResolvedObject->address = pFormalsList->Item(i);
  2738. pResolvedObject->obj = pResolvedObject->address->GetValue(FALSE);
  2739. if (pResolvedObject->obj == nullptr)
  2740. {
  2741. // Temp workaround till the arguments (In jit code) work is ready.
  2742. Assert(Js::Configuration::Global.EnableJitInDebugMode());
  2743. pResolvedObject->obj = pMembersList->Item(i)->aVar;
  2744. }
  2745. else if (pResolvedObject->obj != pMembersList->Item(i)->aVar)
  2746. {
  2747. // We set the formals value in the object itself, so that expression evaluation can reflect them correctly
  2748. Js::HeapArgumentsObject* argObj = static_cast<Js::HeapArgumentsObject*>(instance);
  2749. JavascriptOperators::SetItem(instance, argObj, (uint32)pMembersList->Item(i)->propId, pResolvedObject->obj, scriptContext, PropertyOperation_None);
  2750. }
  2751. }
  2752. else
  2753. {
  2754. pResolvedObject->obj = pMembersList->Item(i)->aVar;
  2755. }
  2756. Assert(pResolvedObject->obj);
  2757. pResolvedObject->scriptContext = scriptContext;
  2758. pResolvedObject->typeId = JavascriptOperators::GetTypeId(pResolvedObject->obj);
  2759. StringBuilder<ArenaAllocator>* builder = GetBuilder();
  2760. Assert(builder);
  2761. builder->Reset();
  2762. pResolvedObject->name = GetIndexName(pMembersList->Item(i)->propId, builder);
  2763. if (pResolvedObject->typeId != TypeIds_HostDispatch && pResolvedObject->address == nullptr)
  2764. {
  2765. pResolvedObject->address = Anew(GetArenaFromContext(scriptContext),
  2766. RecyclableArgumentsArrayAddress,
  2767. instance,
  2768. pMembersList->Item(i)->propId);
  2769. }
  2770. return TRUE;
  2771. }
  2772. return FALSE;
  2773. }
  2774. //--------------------------
  2775. // RecyclableTypedArrayAddress
  2776. RecyclableTypedArrayAddress::RecyclableTypedArrayAddress(Var _parentArray, unsigned int _index)
  2777. : RecyclableArrayAddress(_parentArray, _index)
  2778. {
  2779. }
  2780. BOOL RecyclableTypedArrayAddress::Set(Var updateObject)
  2781. {
  2782. if (Js::TypedArrayBase::Is(parentArray))
  2783. {
  2784. Js::TypedArrayBase* typedArrayObj = Js::TypedArrayBase::FromVar(parentArray);
  2785. return typedArrayObj->SetItem(index, updateObject, PropertyOperation_None);
  2786. }
  2787. return FALSE;
  2788. }
  2789. //--------------------------
  2790. // RecyclableTypedArrayDisplay
  2791. RecyclableTypedArrayDisplay::RecyclableTypedArrayDisplay(ResolvedObject* resolvedObject)
  2792. : RecyclableObjectDisplay(resolvedObject)
  2793. {
  2794. }
  2795. BOOL RecyclableTypedArrayDisplay::HasChildren()
  2796. {
  2797. if (Js::TypedArrayBase::Is(instance))
  2798. {
  2799. Js::TypedArrayBase* typedArrayObj = Js::TypedArrayBase::FromVar(instance);
  2800. if (typedArrayObj->GetLength() > 0)
  2801. {
  2802. return TRUE;
  2803. }
  2804. }
  2805. return RecyclableObjectDisplay::HasChildren();
  2806. }
  2807. WeakArenaReference<IDiagObjectModelWalkerBase>* RecyclableTypedArrayDisplay::CreateWalker()
  2808. {
  2809. return CreateAWalker<RecyclableTypedArrayWalker>(scriptContext, instance, originalInstance);
  2810. }
  2811. //--------------------------
  2812. // RecyclableTypedArrayWalker
  2813. RecyclableTypedArrayWalker::RecyclableTypedArrayWalker(ScriptContext* _scriptContext, Var _instance, Var _originalInstance)
  2814. : RecyclableArrayWalker(_scriptContext, _instance, _originalInstance)
  2815. {
  2816. }
  2817. uint32 RecyclableTypedArrayWalker::GetChildrenCount()
  2818. {
  2819. if (!indexedItemCount)
  2820. {
  2821. Assert(Js::TypedArrayBase::Is(instance));
  2822. Js::TypedArrayBase * typedArrayObj = Js::TypedArrayBase::FromVar(instance);
  2823. indexedItemCount = typedArrayObj->GetLength() + (!fOnlyOwnProperties ? RecyclableObjectWalker::GetChildrenCount() : 0);
  2824. }
  2825. return indexedItemCount;
  2826. }
  2827. BOOL RecyclableTypedArrayWalker::Get(int i, ResolvedObject* pResolvedObject)
  2828. {
  2829. AssertMsg(pResolvedObject, "Bad usage of RecyclableTypedArrayWalker::Get");
  2830. Assert(Js::TypedArrayBase::Is(instance));
  2831. Js::TypedArrayBase * typedArrayObj = Js::TypedArrayBase::FromVar(instance);
  2832. int nonArrayElementCount = (!fOnlyOwnProperties ? RecyclableObjectWalker::GetChildrenCount() : 0);
  2833. if (i < nonArrayElementCount)
  2834. {
  2835. return RecyclableObjectWalker::Get(i, pResolvedObject);
  2836. }
  2837. else
  2838. {
  2839. i -= nonArrayElementCount;
  2840. pResolvedObject->scriptContext = scriptContext;
  2841. pResolvedObject->obj = typedArrayObj->DirectGetItem(i);
  2842. pResolvedObject->typeId = JavascriptOperators::GetTypeId(pResolvedObject->obj);
  2843. StringBuilder<ArenaAllocator>* builder = GetBuilder();
  2844. Assert(builder);
  2845. builder->Reset();
  2846. pResolvedObject->name = GetIndexName(i, builder);
  2847. Assert(pResolvedObject->typeId != TypeIds_HostDispatch);
  2848. pResolvedObject->address = Anew(GetArenaFromContext(scriptContext),
  2849. RecyclableTypedArrayAddress,
  2850. instance,
  2851. i);
  2852. }
  2853. return TRUE;
  2854. }
  2855. //--------------------------
  2856. // RecyclableES5ArrayAddress
  2857. RecyclableES5ArrayAddress::RecyclableES5ArrayAddress(Var _parentArray, unsigned int _index)
  2858. : RecyclableArrayAddress(_parentArray, _index)
  2859. {
  2860. }
  2861. BOOL RecyclableES5ArrayAddress::Set(Var updateObject)
  2862. {
  2863. if (Js::ES5Array::Is(parentArray))
  2864. {
  2865. Js::ES5Array* arrayObj = Js::ES5Array::FromVar(parentArray);
  2866. return arrayObj->SetItem(index, updateObject, PropertyOperation_None);
  2867. }
  2868. return FALSE;
  2869. }
  2870. //--------------------------
  2871. // RecyclableES5ArrayDisplay
  2872. RecyclableES5ArrayDisplay::RecyclableES5ArrayDisplay(ResolvedObject* resolvedObject)
  2873. : RecyclableArrayDisplay(resolvedObject)
  2874. {
  2875. }
  2876. BOOL RecyclableES5ArrayDisplay::HasChildren()
  2877. {
  2878. if (Js::ES5Array::Is(instance))
  2879. {
  2880. Js::JavascriptArray* arrayObj = static_cast<Js::JavascriptArray *>(RecyclableObject::FromVar(instance));
  2881. if (HasChildrenInternal(arrayObj))
  2882. {
  2883. return TRUE;
  2884. }
  2885. }
  2886. return RecyclableObjectDisplay::HasChildren();
  2887. }
  2888. WeakArenaReference<IDiagObjectModelWalkerBase>* RecyclableES5ArrayDisplay::CreateWalker()
  2889. {
  2890. return CreateAWalker<RecyclableES5ArrayWalker>(scriptContext, instance, originalInstance);
  2891. }
  2892. //--------------------------
  2893. // RecyclableES5ArrayWalker
  2894. RecyclableES5ArrayWalker::RecyclableES5ArrayWalker(ScriptContext* _scriptContext, Var _instance, Var _originalInstance)
  2895. : RecyclableArrayWalker(_scriptContext, _instance, _originalInstance)
  2896. {
  2897. }
  2898. uint32 RecyclableES5ArrayWalker::GetNextDescriptor(uint32 currentDescriptor)
  2899. {
  2900. Js::ES5Array *es5Array = static_cast<Js::ES5Array *>(RecyclableObject::FromVar(instance));
  2901. IndexPropertyDescriptor* descriptor = nullptr;
  2902. void * descriptorValidationToken = nullptr;
  2903. return es5Array->GetNextDescriptor(currentDescriptor, &descriptor, &descriptorValidationToken);
  2904. }
  2905. BOOL RecyclableES5ArrayWalker::FetchItemAtIndex(Js::JavascriptArray* arrayObj, uint32 index, Var *value)
  2906. {
  2907. Assert(arrayObj);
  2908. Assert(value);
  2909. return arrayObj->GetItem(arrayObj, index, value, scriptContext);
  2910. }
  2911. Var RecyclableES5ArrayWalker::FetchItemAt(Js::JavascriptArray* arrayObj, uint32 index)
  2912. {
  2913. Assert(arrayObj);
  2914. Var value = nullptr;
  2915. if (FetchItemAtIndex(arrayObj, index, &value))
  2916. {
  2917. return value;
  2918. }
  2919. return nullptr;
  2920. }
  2921. //--------------------------
  2922. // RecyclableProtoObjectWalker
  2923. RecyclableProtoObjectWalker::RecyclableProtoObjectWalker(ScriptContext* pContext, Var instance, Var originalInstance)
  2924. : RecyclableObjectWalker(pContext, instance)
  2925. {
  2926. this->originalInstance = originalInstance;
  2927. }
  2928. BOOL RecyclableProtoObjectWalker::GetGroupObject(ResolvedObject* pResolvedObject)
  2929. {
  2930. Assert(pResolvedObject);
  2931. DBGPROP_ATTRIB_FLAGS defaultAttributes = DBGPROP_ATTRIB_NO_ATTRIB;
  2932. if (scriptContext->GetLibrary()->GetObjectPrototypeObject()->is__proto__Enabled())
  2933. {
  2934. pResolvedObject->name = _u("__proto__");
  2935. pResolvedObject->propId = PropertyIds::__proto__;
  2936. }
  2937. else
  2938. {
  2939. pResolvedObject->name = _u("[prototype]");
  2940. pResolvedObject->propId = Constants::NoProperty; // This property will not be editable.
  2941. defaultAttributes = DBGPROP_ATTRIB_VALUE_IS_FAKE;
  2942. }
  2943. RecyclableObject *obj = Js::RecyclableObject::FromVar(instance);
  2944. Assert(obj->GetPrototype() != nullptr);
  2945. //withscopeObjects prototype is null
  2946. Assert(obj->GetPrototype()->GetTypeId() != TypeIds_Null || (obj->GetPrototype()->GetTypeId() == TypeIds_Null && obj->GetTypeId() == TypeIds_WithScopeObject));
  2947. pResolvedObject->obj = obj->GetPrototype();
  2948. pResolvedObject->originalObj = (originalInstance != nullptr) ? Js::RecyclableObject::FromVar(originalInstance) : pResolvedObject->obj;
  2949. pResolvedObject->scriptContext = scriptContext;
  2950. pResolvedObject->typeId = JavascriptOperators::GetTypeId(pResolvedObject->obj);
  2951. ArenaAllocator * arena = GetArenaFromContext(scriptContext);
  2952. pResolvedObject->objectDisplay = pResolvedObject->CreateDisplay();
  2953. pResolvedObject->objectDisplay->SetDefaultTypeAttribute(defaultAttributes);
  2954. pResolvedObject->address = Anew(arena,
  2955. RecyclableProtoObjectAddress,
  2956. instance,
  2957. PropertyIds::prototype,
  2958. pResolvedObject->obj);
  2959. return TRUE;
  2960. }
  2961. IDiagObjectAddress* RecyclableProtoObjectWalker::FindPropertyAddress(PropertyId propId, bool& isConst)
  2962. {
  2963. ResolvedObject resolvedProto;
  2964. GetGroupObject(&resolvedProto);
  2965. struct AutoCleanup
  2966. {
  2967. WeakArenaReference<Js::IDiagObjectModelWalkerBase> * walkerRef;
  2968. IDiagObjectModelWalkerBase * walker;
  2969. AutoCleanup() : walkerRef(nullptr), walker(nullptr) {};
  2970. ~AutoCleanup()
  2971. {
  2972. if (walker)
  2973. {
  2974. walkerRef->ReleaseStrongReference();
  2975. }
  2976. if (walkerRef)
  2977. {
  2978. HeapDelete(walkerRef);
  2979. }
  2980. }
  2981. } autoCleanup;
  2982. Assert(resolvedProto.objectDisplay);
  2983. autoCleanup.walkerRef = resolvedProto.objectDisplay->CreateWalker();
  2984. autoCleanup.walker = autoCleanup.walkerRef->GetStrongReference();
  2985. return autoCleanup.walker ? autoCleanup.walker->FindPropertyAddress(propId, isConst) : nullptr;
  2986. }
  2987. //--------------------------
  2988. // RecyclableProtoObjectAddress
  2989. RecyclableProtoObjectAddress::RecyclableProtoObjectAddress(Var _parentObj, Js::PropertyId _propId, Js::Var _value)
  2990. : RecyclableObjectAddress(_parentObj, _propId, _value, false /*isInDeadZone*/)
  2991. {
  2992. }
  2993. //--------------------------
  2994. // RecyclableCollectionObjectWalker
  2995. template <typename TData> const char16* RecyclableCollectionObjectWalker<TData>::Name() { static_assert(false, _u("Must use specialization")); }
  2996. template <> const char16* RecyclableCollectionObjectWalker<JavascriptMap>::Name() { return _u("[Map]"); }
  2997. template <> const char16* RecyclableCollectionObjectWalker<JavascriptSet>::Name() { return _u("[Set]"); }
  2998. template <> const char16* RecyclableCollectionObjectWalker<JavascriptWeakMap>::Name() { return _u("[WeakMap]"); }
  2999. template <> const char16* RecyclableCollectionObjectWalker<JavascriptWeakSet>::Name() { return _u("[WeakSet]"); }
  3000. template <typename TData>
  3001. BOOL RecyclableCollectionObjectWalker<TData>::GetGroupObject(ResolvedObject* pResolvedObject)
  3002. {
  3003. pResolvedObject->name = Name();
  3004. pResolvedObject->propId = Constants::NoProperty;
  3005. pResolvedObject->obj = instance;
  3006. pResolvedObject->scriptContext = scriptContext;
  3007. pResolvedObject->typeId = JavascriptOperators::GetTypeId(pResolvedObject->obj);
  3008. pResolvedObject->address = nullptr;
  3009. typedef RecyclableCollectionObjectDisplay<TData> RecyclableDataObjectDisplay;
  3010. pResolvedObject->objectDisplay = Anew(GetArenaFromContext(scriptContext), RecyclableDataObjectDisplay, scriptContext, pResolvedObject->name, this);
  3011. return TRUE;
  3012. }
  3013. template <typename TData>
  3014. BOOL RecyclableCollectionObjectWalker<TData>::Get(int i, ResolvedObject* pResolvedObject)
  3015. {
  3016. auto builder = scriptContext->GetThreadContext()->GetDebugManager()->pCurrentInterpreterLocation->stringBuilder;
  3017. builder->Reset();
  3018. builder->AppendUint64(i);
  3019. pResolvedObject->name = builder->Detach();
  3020. pResolvedObject->propId = Constants::NoProperty;
  3021. pResolvedObject->obj = instance;
  3022. pResolvedObject->scriptContext = scriptContext;
  3023. pResolvedObject->typeId = JavascriptOperators::GetTypeId(pResolvedObject->obj);
  3024. pResolvedObject->address = nullptr;
  3025. pResolvedObject->objectDisplay = CreateTDataDisplay(pResolvedObject, i);
  3026. return TRUE;
  3027. }
  3028. template <typename TData>
  3029. IDiagObjectModelDisplay* RecyclableCollectionObjectWalker<TData>::CreateTDataDisplay(ResolvedObject* resolvedObject, int i)
  3030. {
  3031. Var key = propertyList->Item(i).key;
  3032. Var value = propertyList->Item(i).value;
  3033. return Anew(GetArenaFromContext(scriptContext), RecyclableKeyValueDisplay, resolvedObject->scriptContext, key, value, resolvedObject->name);
  3034. }
  3035. template <>
  3036. IDiagObjectModelDisplay* RecyclableCollectionObjectWalker<JavascriptSet>::CreateTDataDisplay(ResolvedObject* resolvedObject, int i)
  3037. {
  3038. resolvedObject->obj = propertyList->Item(i).value;
  3039. IDiagObjectModelDisplay* display = resolvedObject->CreateDisplay();
  3040. display->SetDefaultTypeAttribute(DBGPROP_ATTRIB_VALUE_READONLY | DBGPROP_ATTRIB_VALUE_IS_FAKE);
  3041. return display;
  3042. }
  3043. template <>
  3044. IDiagObjectModelDisplay* RecyclableCollectionObjectWalker<JavascriptWeakSet>::CreateTDataDisplay(ResolvedObject* resolvedObject, int i)
  3045. {
  3046. resolvedObject->obj = propertyList->Item(i).value;
  3047. IDiagObjectModelDisplay* display = resolvedObject->CreateDisplay();
  3048. display->SetDefaultTypeAttribute(DBGPROP_ATTRIB_VALUE_READONLY | DBGPROP_ATTRIB_VALUE_IS_FAKE);
  3049. return display;
  3050. }
  3051. template <typename TData>
  3052. uint32 RecyclableCollectionObjectWalker<TData>::GetChildrenCount()
  3053. {
  3054. TData* data = TData::FromVar(instance);
  3055. if (data->Size() > 0 && propertyList == nullptr)
  3056. {
  3057. propertyList = JsUtil::List<RecyclableCollectionObjectWalkerPropertyData<TData>, ArenaAllocator>::New(GetArenaFromContext(scriptContext));
  3058. GetChildren();
  3059. }
  3060. return data->Size();
  3061. }
  3062. template <>
  3063. void RecyclableCollectionObjectWalker<JavascriptMap>::GetChildren()
  3064. {
  3065. JavascriptMap* data = JavascriptMap::FromVar(instance);
  3066. auto iterator = data->GetIterator();
  3067. while (iterator.Next())
  3068. {
  3069. Var key = iterator.Current().Key();
  3070. Var value = iterator.Current().Value();
  3071. propertyList->Add(RecyclableCollectionObjectWalkerPropertyData<JavascriptMap>(key, value));
  3072. }
  3073. }
  3074. template <>
  3075. void RecyclableCollectionObjectWalker<JavascriptSet>::GetChildren()
  3076. {
  3077. JavascriptSet* data = JavascriptSet::FromVar(instance);
  3078. auto iterator = data->GetIterator();
  3079. while (iterator.Next())
  3080. {
  3081. Var value = iterator.Current();
  3082. propertyList->Add(RecyclableCollectionObjectWalkerPropertyData<JavascriptSet>(value));
  3083. }
  3084. }
  3085. template <>
  3086. void RecyclableCollectionObjectWalker<JavascriptWeakMap>::GetChildren()
  3087. {
  3088. JavascriptWeakMap* data = JavascriptWeakMap::FromVar(instance);
  3089. data->Map([&](Var key, Var value)
  3090. {
  3091. propertyList->Add(RecyclableCollectionObjectWalkerPropertyData<JavascriptWeakMap>(key, value));
  3092. });
  3093. }
  3094. template <>
  3095. void RecyclableCollectionObjectWalker<JavascriptWeakSet>::GetChildren()
  3096. {
  3097. JavascriptWeakSet* data = JavascriptWeakSet::FromVar(instance);
  3098. data->Map([&](Var value)
  3099. {
  3100. propertyList->Add(RecyclableCollectionObjectWalkerPropertyData<JavascriptWeakSet>(value));
  3101. });
  3102. }
  3103. //--------------------------
  3104. // RecyclableCollectionObjectDisplay
  3105. template <typename TData>
  3106. LPCWSTR RecyclableCollectionObjectDisplay<TData>::Value(int radix)
  3107. {
  3108. StringBuilder<ArenaAllocator>* builder = scriptContext->GetThreadContext()->GetDebugManager()->pCurrentInterpreterLocation->stringBuilder;
  3109. builder->Reset();
  3110. builder->AppendCppLiteral(_u("size = "));
  3111. builder->AppendUint64(walker->GetChildrenCount());
  3112. return builder->Detach();
  3113. }
  3114. template <typename TData>
  3115. WeakArenaReference<IDiagObjectModelWalkerBase>* RecyclableCollectionObjectDisplay<TData>::CreateWalker()
  3116. {
  3117. if (walker)
  3118. {
  3119. ReferencedArenaAdapter* pRefArena = scriptContext->GetThreadContext()->GetDebugManager()->GetDiagnosticArena();
  3120. if (pRefArena)
  3121. {
  3122. return HeapNew(WeakArenaReference<IDiagObjectModelWalkerBase>, pRefArena, walker);
  3123. }
  3124. }
  3125. return nullptr;
  3126. }
  3127. //--------------------------
  3128. // RecyclableKeyValueDisplay
  3129. WeakArenaReference<IDiagObjectModelWalkerBase>* RecyclableKeyValueDisplay::CreateWalker()
  3130. {
  3131. ReferencedArenaAdapter* pRefArena = scriptContext->GetThreadContext()->GetDebugManager()->GetDiagnosticArena();
  3132. if (pRefArena)
  3133. {
  3134. IDiagObjectModelWalkerBase* pOMWalker = Anew(pRefArena->Arena(), RecyclableKeyValueWalker, scriptContext, key, value);
  3135. return HeapNew(WeakArenaReference<IDiagObjectModelWalkerBase>, pRefArena, pOMWalker);
  3136. }
  3137. return nullptr;
  3138. }
  3139. LPCWSTR RecyclableKeyValueDisplay::Value(int radix)
  3140. {
  3141. ResolvedObject ro;
  3142. ro.scriptContext = scriptContext;
  3143. ro.obj = key;
  3144. RecyclableObjectDisplay keyDisplay(&ro);
  3145. ro.obj = value;
  3146. RecyclableObjectDisplay valueDisplay(&ro);
  3147. // Note, RecyclableObjectDisplay::Value(int) uses the shared string builder
  3148. // so we cannot call it while building our string below. Call both before hand.
  3149. const char16* keyValue = keyDisplay.Value(radix);
  3150. const char16* valueValue = valueDisplay.Value(radix);
  3151. StringBuilder<ArenaAllocator>* builder = scriptContext->GetThreadContext()->GetDebugManager()->pCurrentInterpreterLocation->stringBuilder;
  3152. builder->Reset();
  3153. builder->Append('[');
  3154. builder->AppendSz(keyValue);
  3155. builder->AppendCppLiteral(_u(", "));
  3156. builder->AppendSz(valueValue);
  3157. builder->Append(']');
  3158. return builder->Detach();
  3159. }
  3160. //--------------------------
  3161. // RecyclableKeyValueWalker
  3162. BOOL RecyclableKeyValueWalker::Get(int i, ResolvedObject* pResolvedObject)
  3163. {
  3164. if (i == 0)
  3165. {
  3166. pResolvedObject->name = _u("key");
  3167. pResolvedObject->obj = key;
  3168. }
  3169. else if (i == 1)
  3170. {
  3171. pResolvedObject->name = _u("value");
  3172. pResolvedObject->obj = value;
  3173. }
  3174. else
  3175. {
  3176. Assert(false);
  3177. return FALSE;
  3178. }
  3179. pResolvedObject->propId = Constants::NoProperty;
  3180. pResolvedObject->scriptContext = scriptContext;
  3181. pResolvedObject->typeId = JavascriptOperators::GetTypeId(pResolvedObject->obj);
  3182. pResolvedObject->objectDisplay = pResolvedObject->CreateDisplay();
  3183. pResolvedObject->objectDisplay->SetDefaultTypeAttribute(DBGPROP_ATTRIB_VALUE_READONLY | DBGPROP_ATTRIB_VALUE_IS_FAKE);
  3184. pResolvedObject->address = nullptr;
  3185. return TRUE;
  3186. }
  3187. //--------------------------
  3188. // RecyclableProxyObjectDisplay
  3189. RecyclableProxyObjectDisplay::RecyclableProxyObjectDisplay(ResolvedObject* resolvedObject)
  3190. : RecyclableObjectDisplay(resolvedObject)
  3191. {
  3192. }
  3193. WeakArenaReference<IDiagObjectModelWalkerBase>* RecyclableProxyObjectDisplay::CreateWalker()
  3194. {
  3195. ReferencedArenaAdapter* pRefArena = scriptContext->GetThreadContext()->GetDebugManager()->GetDiagnosticArena();
  3196. if (pRefArena)
  3197. {
  3198. IDiagObjectModelWalkerBase* pOMWalker = Anew(pRefArena->Arena(), RecyclableProxyObjectWalker, scriptContext, instance);
  3199. return HeapNew(WeakArenaReference<IDiagObjectModelWalkerBase>, pRefArena, pOMWalker);
  3200. }
  3201. return nullptr;
  3202. }
  3203. //--------------------------
  3204. // RecyclableProxyObjectWalker
  3205. RecyclableProxyObjectWalker::RecyclableProxyObjectWalker(ScriptContext* pContext, Var _instance)
  3206. : RecyclableObjectWalker(pContext, _instance)
  3207. {
  3208. }
  3209. BOOL RecyclableProxyObjectWalker::GetGroupObject(ResolvedObject* pResolvedObject)
  3210. {
  3211. pResolvedObject->name = _u("[Proxy]");
  3212. pResolvedObject->propId = Constants::NoProperty;
  3213. pResolvedObject->obj = instance;
  3214. pResolvedObject->scriptContext = scriptContext;
  3215. pResolvedObject->typeId = JavascriptOperators::GetTypeId(pResolvedObject->obj);
  3216. pResolvedObject->address = nullptr;
  3217. pResolvedObject->objectDisplay = Anew(GetArenaFromContext(scriptContext), RecyclableProxyObjectDisplay, pResolvedObject);
  3218. pResolvedObject->objectDisplay->SetDefaultTypeAttribute(DBGPROP_ATTRIB_VALUE_READONLY | DBGPROP_ATTRIB_VALUE_IS_FAKE);
  3219. return TRUE;
  3220. }
  3221. BOOL RecyclableProxyObjectWalker::Get(int i, ResolvedObject* pResolvedObject)
  3222. {
  3223. JavascriptProxy* proxy = JavascriptProxy::FromVar(instance);
  3224. if (proxy->GetTarget() == nullptr || proxy->GetHandler() == nullptr)
  3225. {
  3226. return FALSE;
  3227. }
  3228. if (i == 0)
  3229. {
  3230. pResolvedObject->name = _u("[target]");
  3231. pResolvedObject->obj = proxy->GetTarget();
  3232. }
  3233. else if (i == 1)
  3234. {
  3235. pResolvedObject->name = _u("[handler]");
  3236. pResolvedObject->obj = proxy->GetHandler();
  3237. }
  3238. else
  3239. {
  3240. Assert(false);
  3241. return FALSE;
  3242. }
  3243. pResolvedObject->propId = Constants::NoProperty;
  3244. pResolvedObject->scriptContext = scriptContext;
  3245. pResolvedObject->typeId = JavascriptOperators::GetTypeId(pResolvedObject->obj);
  3246. pResolvedObject->objectDisplay = pResolvedObject->CreateDisplay();
  3247. pResolvedObject->objectDisplay->SetDefaultTypeAttribute(DBGPROP_ATTRIB_VALUE_READONLY | DBGPROP_ATTRIB_VALUE_IS_FAKE);
  3248. pResolvedObject->address = Anew(GetArenaFromContext(pResolvedObject->scriptContext),
  3249. RecyclableObjectAddress,
  3250. pResolvedObject->scriptContext->GetGlobalObject(),
  3251. Js::PropertyIds::Proxy,
  3252. pResolvedObject->obj,
  3253. false /*isInDeadZone*/);
  3254. return TRUE;
  3255. }
  3256. //--------------------------
  3257. // RecyclablePromiseObjectDisplay
  3258. RecyclablePromiseObjectDisplay::RecyclablePromiseObjectDisplay(ResolvedObject* resolvedObject)
  3259. : RecyclableObjectDisplay(resolvedObject)
  3260. {
  3261. }
  3262. WeakArenaReference<IDiagObjectModelWalkerBase>* RecyclablePromiseObjectDisplay::CreateWalker()
  3263. {
  3264. ReferencedArenaAdapter* pRefArena = scriptContext->GetThreadContext()->GetDebugManager()->GetDiagnosticArena();
  3265. if (pRefArena)
  3266. {
  3267. IDiagObjectModelWalkerBase* pOMWalker = Anew(pRefArena->Arena(), RecyclablePromiseObjectWalker, scriptContext, instance);
  3268. return HeapNew(WeakArenaReference<IDiagObjectModelWalkerBase>, pRefArena, pOMWalker);
  3269. }
  3270. return nullptr;
  3271. }
  3272. //--------------------------
  3273. // RecyclablePromiseObjectWalker
  3274. RecyclablePromiseObjectWalker::RecyclablePromiseObjectWalker(ScriptContext* pContext, Var _instance)
  3275. : RecyclableObjectWalker(pContext, _instance)
  3276. {
  3277. }
  3278. BOOL RecyclablePromiseObjectWalker::GetGroupObject(ResolvedObject* pResolvedObject)
  3279. {
  3280. pResolvedObject->name = _u("[Promise]");
  3281. pResolvedObject->propId = Constants::NoProperty;
  3282. pResolvedObject->obj = instance;
  3283. pResolvedObject->scriptContext = scriptContext;
  3284. pResolvedObject->typeId = JavascriptOperators::GetTypeId(pResolvedObject->obj);
  3285. pResolvedObject->address = nullptr;
  3286. pResolvedObject->objectDisplay = Anew(GetArenaFromContext(scriptContext), RecyclablePromiseObjectDisplay, pResolvedObject);
  3287. pResolvedObject->objectDisplay->SetDefaultTypeAttribute(DBGPROP_ATTRIB_VALUE_READONLY | DBGPROP_ATTRIB_VALUE_IS_FAKE);
  3288. return TRUE;
  3289. }
  3290. BOOL RecyclablePromiseObjectWalker::Get(int i, ResolvedObject* pResolvedObject)
  3291. {
  3292. JavascriptPromise* promise = JavascriptPromise::FromVar(instance);
  3293. if (i == 0)
  3294. {
  3295. pResolvedObject->name = _u("[status]");
  3296. switch (promise->GetStatus())
  3297. {
  3298. case JavascriptPromise::PromiseStatusCode_Undefined:
  3299. pResolvedObject->obj = scriptContext->GetLibrary()->GetUndefinedDisplayString();
  3300. break;
  3301. case JavascriptPromise::PromiseStatusCode_Unresolved:
  3302. pResolvedObject->obj = scriptContext->GetLibrary()->CreateStringFromCppLiteral(_u("pending"));
  3303. case JavascriptPromise::PromiseStatusCode_HasResolution:
  3304. pResolvedObject->obj = scriptContext->GetLibrary()->CreateStringFromCppLiteral(_u("resolved"));
  3305. break;
  3306. case JavascriptPromise::PromiseStatusCode_HasRejection:
  3307. pResolvedObject->obj = scriptContext->GetLibrary()->CreateStringFromCppLiteral(_u("rejected"));
  3308. break;
  3309. default:
  3310. AssertMsg(false, "New PromiseStatusCode not handled in debugger");
  3311. pResolvedObject->obj = scriptContext->GetLibrary()->GetUndefinedDisplayString();
  3312. break;
  3313. }
  3314. }
  3315. else if (i == 1)
  3316. {
  3317. pResolvedObject->name = _u("[value]");
  3318. Var result = promise->GetResult();
  3319. pResolvedObject->obj = result != nullptr ? result : scriptContext->GetLibrary()->GetUndefinedDisplayString();
  3320. }
  3321. else
  3322. {
  3323. Assert(false);
  3324. return FALSE;
  3325. }
  3326. pResolvedObject->propId = Constants::NoProperty;
  3327. pResolvedObject->scriptContext = scriptContext;
  3328. pResolvedObject->typeId = JavascriptOperators::GetTypeId(pResolvedObject->obj);
  3329. pResolvedObject->objectDisplay = pResolvedObject->CreateDisplay();
  3330. pResolvedObject->objectDisplay->SetDefaultTypeAttribute(DBGPROP_ATTRIB_VALUE_READONLY | DBGPROP_ATTRIB_VALUE_IS_FAKE);
  3331. pResolvedObject->address = nullptr;
  3332. return TRUE;
  3333. }
  3334. // ---------------------------
  3335. // RecyclableMethodsGroupWalker
  3336. RecyclableMethodsGroupWalker::RecyclableMethodsGroupWalker(ScriptContext* scriptContext, Var instance)
  3337. : RecyclableObjectWalker(scriptContext,instance)
  3338. {
  3339. }
  3340. void RecyclableMethodsGroupWalker::AddItem(Js::PropertyId propertyId, Var obj)
  3341. {
  3342. if (pMembersList == nullptr)
  3343. {
  3344. pMembersList = JsUtil::List<DebuggerPropertyDisplayInfo *, ArenaAllocator>::New(GetArenaFromContext(scriptContext));
  3345. }
  3346. Assert(pMembersList);
  3347. DebuggerPropertyDisplayInfo *info = Anew(GetArenaFromContext(scriptContext), DebuggerPropertyDisplayInfo, propertyId, obj, DebuggerPropertyDisplayInfoFlags_Const);
  3348. Assert(info);
  3349. pMembersList->Add(info);
  3350. }
  3351. uint32 RecyclableMethodsGroupWalker::GetChildrenCount()
  3352. {
  3353. return pMembersList ? pMembersList->Count() : 0;
  3354. }
  3355. BOOL RecyclableMethodsGroupWalker::Get(int i, ResolvedObject* pResolvedObject)
  3356. {
  3357. AssertMsg(pResolvedObject, "Bad usage of RecyclableMethodsGroupWalker::Get");
  3358. return RecyclableObjectWalker::Get(i, pResolvedObject);
  3359. }
  3360. BOOL RecyclableMethodsGroupWalker::GetGroupObject(ResolvedObject* pResolvedObject)
  3361. {
  3362. Assert(pResolvedObject);
  3363. // This is fake [Methods] object.
  3364. pResolvedObject->name = _u("[Methods]");
  3365. pResolvedObject->obj = Js::RecyclableObject::FromVar(instance);
  3366. pResolvedObject->scriptContext = scriptContext;
  3367. pResolvedObject->typeId = JavascriptOperators::GetTypeId(pResolvedObject->obj);
  3368. pResolvedObject->address = nullptr; // Methods object will not be editable
  3369. pResolvedObject->objectDisplay = Anew(GetArenaFromContext(scriptContext), RecyclableMethodsGroupDisplay, this, pResolvedObject);
  3370. return TRUE;
  3371. }
  3372. void RecyclableMethodsGroupWalker::Sort()
  3373. {
  3374. HostDebugContext* hostDebugContext = this->scriptContext->GetDebugContext()->GetHostDebugContext();
  3375. if (hostDebugContext != nullptr)
  3376. {
  3377. hostDebugContext->SortMembersList(pMembersList, scriptContext);
  3378. }
  3379. }
  3380. RecyclableMethodsGroupDisplay::RecyclableMethodsGroupDisplay(RecyclableMethodsGroupWalker *_methodGroupWalker, ResolvedObject* resolvedObject)
  3381. : methodGroupWalker(_methodGroupWalker),
  3382. RecyclableObjectDisplay(resolvedObject)
  3383. {
  3384. }
  3385. LPCWSTR RecyclableMethodsGroupDisplay::Type()
  3386. {
  3387. return _u("");
  3388. }
  3389. LPCWSTR RecyclableMethodsGroupDisplay::Value(int radix)
  3390. {
  3391. return _u("{...}");
  3392. }
  3393. BOOL RecyclableMethodsGroupDisplay::HasChildren()
  3394. {
  3395. return methodGroupWalker ? TRUE : FALSE;
  3396. }
  3397. DBGPROP_ATTRIB_FLAGS RecyclableMethodsGroupDisplay::GetTypeAttribute()
  3398. {
  3399. return DBGPROP_ATTRIB_VALUE_READONLY | DBGPROP_ATTRIB_VALUE_IS_FAKE | DBGPROP_ATTRIB_VALUE_IS_METHOD | DBGPROP_ATTRIB_VALUE_IS_EXPANDABLE;
  3400. }
  3401. WeakArenaReference<IDiagObjectModelWalkerBase>* RecyclableMethodsGroupDisplay::CreateWalker()
  3402. {
  3403. if (methodGroupWalker)
  3404. {
  3405. ReferencedArenaAdapter* pRefArena = scriptContext->GetThreadContext()->GetDebugManager()->GetDiagnosticArena();
  3406. if (pRefArena)
  3407. {
  3408. return HeapNew(WeakArenaReference<IDiagObjectModelWalkerBase>, pRefArena, methodGroupWalker);
  3409. }
  3410. }
  3411. return nullptr;
  3412. }
  3413. ScopeVariablesGroupDisplay::ScopeVariablesGroupDisplay(VariableWalkerBase *walker, ResolvedObject* resolvedObject)
  3414. : scopeGroupWalker(walker),
  3415. RecyclableObjectDisplay(resolvedObject)
  3416. {
  3417. }
  3418. LPCWSTR ScopeVariablesGroupDisplay::Type()
  3419. {
  3420. return _u("");
  3421. }
  3422. LPCWSTR ScopeVariablesGroupDisplay::Value(int radix)
  3423. {
  3424. if (ActivationObject::Is(instance))
  3425. {
  3426. // The scope is defined by the activation object.
  3427. Js::RecyclableObject *object = Js::RecyclableObject::FromVar(instance);
  3428. try
  3429. {
  3430. // Trying to find out the JavascriptFunction from the scope.
  3431. Var value = nullptr;
  3432. if (object->GetTypeId() == TypeIds_ActivationObject && GetPropertyWithScriptEnter(object, object, PropertyIds::arguments, &value, scriptContext))
  3433. {
  3434. if (Js::RecyclableObject::Is(value))
  3435. {
  3436. Js::RecyclableObject *argObject = Js::RecyclableObject::FromVar(value);
  3437. Var calleeFunc = nullptr;
  3438. if (GetPropertyWithScriptEnter(argObject, argObject, PropertyIds::callee, &calleeFunc, scriptContext) && Js::JavascriptFunction::Is(calleeFunc))
  3439. {
  3440. Js::JavascriptFunction *calleeFunction = Js::JavascriptFunction::FromVar(calleeFunc);
  3441. Js::FunctionBody *pFuncBody = calleeFunction->GetFunctionBody();
  3442. if (pFuncBody)
  3443. {
  3444. const char16* pDisplayName = pFuncBody->GetDisplayName();
  3445. if (pDisplayName)
  3446. {
  3447. StringBuilder<ArenaAllocator>* builder = GetStringBuilder();
  3448. builder->Reset();
  3449. builder->AppendSz(pDisplayName);
  3450. return builder->Detach();
  3451. }
  3452. }
  3453. }
  3454. }
  3455. }
  3456. }
  3457. catch(const JavascriptException& err)
  3458. {
  3459. err.GetAndClear(); // discard exception object
  3460. }
  3461. return _u("");
  3462. }
  3463. else
  3464. {
  3465. // The scope is defined by a slot array object so grab the function body out to get the function name.
  3466. ScopeSlots slotArray = ScopeSlots(reinterpret_cast<Var*>(instance));
  3467. if(slotArray.IsFunctionScopeSlotArray())
  3468. {
  3469. Js::FunctionBody *functionBody = slotArray.GetFunctionInfo()->GetFunctionBody();
  3470. return functionBody->GetDisplayName();
  3471. }
  3472. else
  3473. {
  3474. // handling for block/catch scope
  3475. return _u("");
  3476. }
  3477. }
  3478. }
  3479. BOOL ScopeVariablesGroupDisplay::HasChildren()
  3480. {
  3481. return scopeGroupWalker ? TRUE : FALSE;
  3482. }
  3483. DBGPROP_ATTRIB_FLAGS ScopeVariablesGroupDisplay::GetTypeAttribute()
  3484. {
  3485. return DBGPROP_ATTRIB_VALUE_READONLY | DBGPROP_ATTRIB_VALUE_IS_FAKE | DBGPROP_ATTRIB_VALUE_IS_EXPANDABLE;
  3486. }
  3487. WeakArenaReference<IDiagObjectModelWalkerBase>* ScopeVariablesGroupDisplay::CreateWalker()
  3488. {
  3489. if (scopeGroupWalker)
  3490. {
  3491. ReferencedArenaAdapter* pRefArena = scriptContext->GetThreadContext()->GetDebugManager()->GetDiagnosticArena();
  3492. if (pRefArena)
  3493. {
  3494. return HeapNew(WeakArenaReference<IDiagObjectModelWalkerBase>, pRefArena, scopeGroupWalker);
  3495. }
  3496. }
  3497. return nullptr;
  3498. }
  3499. GlobalsScopeVariablesGroupDisplay::GlobalsScopeVariablesGroupDisplay(VariableWalkerBase *walker, ResolvedObject* resolvedObject)
  3500. : globalsGroupWalker(walker),
  3501. RecyclableObjectDisplay(resolvedObject)
  3502. {
  3503. }
  3504. LPCWSTR GlobalsScopeVariablesGroupDisplay::Type()
  3505. {
  3506. return _u("");
  3507. }
  3508. LPCWSTR GlobalsScopeVariablesGroupDisplay::Value(int radix)
  3509. {
  3510. return _u("");
  3511. }
  3512. BOOL GlobalsScopeVariablesGroupDisplay::HasChildren()
  3513. {
  3514. return globalsGroupWalker ? globalsGroupWalker->GetChildrenCount() > 0 : FALSE;
  3515. }
  3516. DBGPROP_ATTRIB_FLAGS GlobalsScopeVariablesGroupDisplay::GetTypeAttribute()
  3517. {
  3518. return DBGPROP_ATTRIB_VALUE_READONLY | DBGPROP_ATTRIB_VALUE_IS_FAKE | (HasChildren() ? DBGPROP_ATTRIB_VALUE_IS_EXPANDABLE : 0);
  3519. }
  3520. WeakArenaReference<IDiagObjectModelWalkerBase>* GlobalsScopeVariablesGroupDisplay::CreateWalker()
  3521. {
  3522. if (globalsGroupWalker)
  3523. {
  3524. ReferencedArenaAdapter* pRefArena = scriptContext->GetThreadContext()->GetDebugManager()->GetDiagnosticArena();
  3525. if (pRefArena)
  3526. {
  3527. return HeapNew(WeakArenaReference<IDiagObjectModelWalkerBase>, pRefArena, globalsGroupWalker);
  3528. }
  3529. }
  3530. return nullptr;
  3531. }
  3532. #ifdef ENABLE_MUTATION_BREAKPOINT
  3533. PendingMutationBreakpointDisplay::PendingMutationBreakpointDisplay(ResolvedObject* resolvedObject, MutationType _mutationType)
  3534. : RecyclableObjectDisplay(resolvedObject), mutationType(_mutationType)
  3535. {
  3536. AssertMsg(_mutationType > MutationTypeNone && _mutationType < MutationTypeAll, "Invalid mutationType value passed to PendingMutationBreakpointDisplay");
  3537. }
  3538. WeakArenaReference<IDiagObjectModelWalkerBase>* PendingMutationBreakpointDisplay::CreateWalker()
  3539. {
  3540. ReferencedArenaAdapter* pRefArena = scriptContext->GetThreadContext()->GetDebugManager()->GetDiagnosticArena();
  3541. if (pRefArena)
  3542. {
  3543. IDiagObjectModelWalkerBase* pOMWalker = Anew(pRefArena->Arena(), PendingMutationBreakpointWalker, scriptContext, instance, this->mutationType);
  3544. return HeapNew(WeakArenaReference<IDiagObjectModelWalkerBase>, pRefArena, pOMWalker);
  3545. }
  3546. return nullptr;
  3547. }
  3548. uint32 PendingMutationBreakpointWalker::GetChildrenCount()
  3549. {
  3550. switch (this->mutationType)
  3551. {
  3552. case MutationTypeUpdate:
  3553. return 3;
  3554. case MutationTypeDelete:
  3555. case MutationTypeAdd:
  3556. return 2;
  3557. default:
  3558. AssertMsg(false, "Invalid mutationType");
  3559. return 0;
  3560. }
  3561. }
  3562. PendingMutationBreakpointWalker::PendingMutationBreakpointWalker(ScriptContext* pContext, Var _instance, MutationType mutationType)
  3563. : RecyclableObjectWalker(pContext, _instance)
  3564. {
  3565. this->mutationType = mutationType;
  3566. }
  3567. BOOL PendingMutationBreakpointWalker::Get(int i, ResolvedObject* pResolvedObject)
  3568. {
  3569. Js::MutationBreakpoint *mutationBreakpoint = scriptContext->GetDebugContext()->GetProbeContainer()->GetDebugManager()->GetActiveMutationBreakpoint();
  3570. Assert(mutationBreakpoint);
  3571. if (mutationBreakpoint != nullptr)
  3572. {
  3573. if (i == 0)
  3574. {
  3575. // <Property Name> [Adding] : New Value
  3576. // <Property Name> [Changing] : Old Value
  3577. // <Property Name> [Deleting] : Old Value
  3578. WCHAR * displayName = AnewArray(GetArenaFromContext(scriptContext), WCHAR, PENDING_MUTATION_VALUE_MAX_NAME);
  3579. swprintf_s(displayName, PENDING_MUTATION_VALUE_MAX_NAME, _u("%s [%s]"), mutationBreakpoint->GetBreakPropertyName(), Js::MutationBreakpoint::GetBreakMutationTypeName(mutationType));
  3580. pResolvedObject->name = displayName;
  3581. if (mutationType == MutationTypeUpdate || mutationType == MutationTypeDelete)
  3582. {
  3583. // Old/Current value
  3584. PropertyId breakPId = mutationBreakpoint->GetBreakPropertyId();
  3585. pResolvedObject->propId = breakPId;
  3586. pResolvedObject->obj = JavascriptOperators::OP_GetProperty(mutationBreakpoint->GetMutationObjectVar(), breakPId, scriptContext);
  3587. }
  3588. else
  3589. {
  3590. // New Value
  3591. pResolvedObject->obj = mutationBreakpoint->GetBreakNewValueVar();
  3592. pResolvedObject->propId = Constants::NoProperty;
  3593. }
  3594. }
  3595. else if ((i == 1) && (mutationType == MutationTypeUpdate))
  3596. {
  3597. pResolvedObject->name = _u("[New Value]");
  3598. pResolvedObject->obj = mutationBreakpoint->GetBreakNewValueVar();
  3599. pResolvedObject->propId = Constants::NoProperty;
  3600. }
  3601. else if (((i == 1) && (mutationType != MutationTypeUpdate)) || (i == 2))
  3602. {
  3603. WCHAR * displayName = AnewArray(GetArenaFromContext(scriptContext), WCHAR, PENDING_MUTATION_VALUE_MAX_NAME);
  3604. swprintf_s(displayName, PENDING_MUTATION_VALUE_MAX_NAME, _u("[Property container %s]"), mutationBreakpoint->GetParentPropertyName());
  3605. pResolvedObject->name = displayName;
  3606. pResolvedObject->obj = mutationBreakpoint->GetMutationObjectVar();
  3607. pResolvedObject->propId = mutationBreakpoint->GetParentPropertyId();
  3608. }
  3609. else
  3610. {
  3611. Assert(false);
  3612. return FALSE;
  3613. }
  3614. pResolvedObject->scriptContext = scriptContext;
  3615. pResolvedObject->typeId = JavascriptOperators::GetTypeId(pResolvedObject->obj);
  3616. pResolvedObject->objectDisplay = pResolvedObject->CreateDisplay();
  3617. pResolvedObject->objectDisplay->SetDefaultTypeAttribute(DBGPROP_ATTRIB_VALUE_READONLY | DBGPROP_ATTRIB_VALUE_IS_FAKE);
  3618. pResolvedObject->address = nullptr; // TODO: (SaAgarwa) Currently Pending mutation values are not editable, will do as part of another WI
  3619. return TRUE;
  3620. }
  3621. return FALSE;
  3622. }
  3623. #endif
  3624. #ifdef ENABLE_SIMDJS
  3625. //--------------------------
  3626. // RecyclableSimdObjectWalker
  3627. template <typename simdType, uint elementCount>
  3628. BOOL RecyclableSimdObjectWalker<simdType, elementCount>::Get(int i, ResolvedObject* pResolvedObject)
  3629. {
  3630. Assert(elementCount == 4 || elementCount == 8 || elementCount == 16); // SIMD types such as int32x4, int8x16, int16x8
  3631. Assert(i >= 0 && i <= elementCount);
  3632. simdType* simd = simdType::FromVar(instance);
  3633. SIMDValue value = simd->GetValue();
  3634. WCHAR* indexName = AnewArray(GetArenaFromContext(scriptContext), WCHAR, SIMD_INDEX_VALUE_MAX);
  3635. Assert(indexName);
  3636. swprintf_s(indexName, SIMD_INDEX_VALUE_MAX, _u("[%d]"), i);
  3637. pResolvedObject->name = indexName;
  3638. TypeId simdTypeId = JavascriptOperators::GetTypeId(instance);
  3639. switch (simdTypeId)
  3640. {
  3641. case TypeIds_SIMDInt32x4:
  3642. pResolvedObject->obj = JavascriptNumber::ToVarWithCheck(value.i32[i], scriptContext);
  3643. break;
  3644. case TypeIds_SIMDFloat32x4:
  3645. pResolvedObject->obj = JavascriptNumber::ToVarWithCheck(value.f32[i], scriptContext);
  3646. break;
  3647. case TypeIds_SIMDInt8x16:
  3648. pResolvedObject->obj = JavascriptNumber::ToVarWithCheck(value.i8[i], scriptContext);
  3649. break;
  3650. case TypeIds_SIMDInt16x8:
  3651. pResolvedObject->obj = JavascriptNumber::ToVarWithCheck(value.i16[i], scriptContext);
  3652. break;
  3653. case TypeIds_SIMDBool32x4:
  3654. pResolvedObject->obj = JavascriptBoolean::ToVar(value.i32[i], scriptContext);
  3655. break;
  3656. case TypeIds_SIMDBool8x16:
  3657. pResolvedObject->obj = JavascriptBoolean::ToVar(value.i8[i], scriptContext);
  3658. break;
  3659. case TypeIds_SIMDBool16x8:
  3660. pResolvedObject->obj = JavascriptBoolean::ToVar(value.i16[i], scriptContext);
  3661. break;
  3662. case TypeIds_SIMDUint32x4:
  3663. pResolvedObject->obj = JavascriptNumber::ToVarWithCheck(value.u32[i], scriptContext);
  3664. break;
  3665. case TypeIds_SIMDUint8x16:
  3666. pResolvedObject->obj = JavascriptNumber::ToVarWithCheck(value.u8[i], scriptContext);
  3667. break;
  3668. case TypeIds_SIMDUint16x8:
  3669. pResolvedObject->obj = JavascriptNumber::ToVarWithCheck(value.u16[i], scriptContext);
  3670. break;
  3671. default:
  3672. AssertMsg(false, "Unexpected SIMD typeId");
  3673. return FALSE;
  3674. }
  3675. pResolvedObject->propId = Constants::NoProperty;
  3676. pResolvedObject->scriptContext = scriptContext;
  3677. pResolvedObject->typeId = simdTypeId;
  3678. pResolvedObject->objectDisplay = pResolvedObject->CreateDisplay();
  3679. pResolvedObject->objectDisplay->SetDefaultTypeAttribute(DBGPROP_ATTRIB_VALUE_READONLY | DBGPROP_ATTRIB_VALUE_IS_FAKE);
  3680. pResolvedObject->address = nullptr;
  3681. return TRUE;
  3682. }
  3683. //--------------------------
  3684. // RecyclableSimdObjectDisplay
  3685. template <typename simdType, typename simdWalker>
  3686. LPCWSTR RecyclableSimdObjectDisplay<simdType, simdWalker>::Type()
  3687. {
  3688. TypeId simdTypeId = JavascriptOperators::GetTypeId(instance);
  3689. switch (simdTypeId)
  3690. {
  3691. case TypeIds_SIMDInt32x4:
  3692. return _u("SIMD.Int32x4");
  3693. case TypeIds_SIMDFloat32x4:
  3694. return _u("SIMD.Float32x4");
  3695. case TypeIds_SIMDInt8x16:
  3696. return _u("SIMD.Int8x16");
  3697. case TypeIds_SIMDInt16x8:
  3698. return _u("SIMD.Int16x8");
  3699. case TypeIds_SIMDBool32x4:
  3700. return _u("SIMD.Bool32x4");
  3701. case TypeIds_SIMDBool8x16:
  3702. return _u("SIMD.Bool8x16");
  3703. case TypeIds_SIMDBool16x8:
  3704. return _u("SIMD.Bool16x8");
  3705. case TypeIds_SIMDUint32x4:
  3706. return _u("SIMD.Uint32x4");
  3707. case TypeIds_SIMDUint8x16:
  3708. return _u("SIMD.Uint8x16");
  3709. case TypeIds_SIMDUint16x8:
  3710. return _u("SIMD.Uint16x8");
  3711. default:
  3712. AssertMsg(false, "Unexpected SIMD typeId");
  3713. return nullptr;
  3714. }
  3715. }
  3716. template <typename simdType, typename simdWalker>
  3717. LPCWSTR RecyclableSimdObjectDisplay<simdType, simdWalker>::Value(int radix)
  3718. {
  3719. StringBuilder<ArenaAllocator>* builder = GetStringBuilder();
  3720. builder->Reset();
  3721. simdType* simd = simdType::FromVar(instance);
  3722. SIMDValue value = simd->GetValue();
  3723. char16* stringBuffer = AnewArray(GetArenaFromContext(scriptContext), char16, SIMD_STRING_BUFFER_MAX);
  3724. simdType::ToStringBuffer(value, stringBuffer, SIMD_STRING_BUFFER_MAX, scriptContext);
  3725. builder->AppendSz(stringBuffer);
  3726. return builder->Detach();
  3727. }
  3728. template <typename simdType, typename simdWalker>
  3729. WeakArenaReference<IDiagObjectModelWalkerBase>* RecyclableSimdObjectDisplay<simdType, simdWalker>::CreateWalker()
  3730. {
  3731. ReferencedArenaAdapter* pRefArena = scriptContext->GetThreadContext()->GetDebugManager()->GetDiagnosticArena();
  3732. if (pRefArena)
  3733. {
  3734. IDiagObjectModelWalkerBase* pOMWalker = Anew(pRefArena->Arena(), simdWalker, scriptContext, instance);
  3735. return HeapNew(WeakArenaReference<IDiagObjectModelWalkerBase>, pRefArena, pOMWalker);
  3736. }
  3737. return nullptr;
  3738. }
  3739. #endif // #ifdef ENABLE_SIMDJS
  3740. }