DiagObjectModel.cpp 163 KB

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