FunctionBody.h 151 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft. All rights reserved.
  3. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  4. //-------------------------------------------------------------------------------------------------------
  5. #pragma once
  6. #include "AuxPtrs.h"
  7. #include "CompactCounters.h"
  8. struct CodeGenWorkItem;
  9. class SourceContextInfo;
  10. class FunctionBailOutRecord;
  11. struct DeferredFunctionStub;
  12. #ifdef DYNAMIC_PROFILE_MUTATOR
  13. class DynamicProfileMutator;
  14. class DynamicProfileMutatorImpl;
  15. #endif
  16. #define MAX_FUNCTION_BODY_DEBUG_STRING_SIZE 42 //11*3+8+1
  17. namespace Js
  18. {
  19. #pragma region Class Forward Declarations
  20. class ByteCodeBufferReader;
  21. class ByteCodeBufferBuilder;
  22. class ByteCodeCache;
  23. class ScopeInfo;
  24. class SmallSpanSequence;
  25. struct StatementLocation;
  26. class SmallSpanSequenceIter;
  27. struct StatementData;
  28. struct PropertyIdOnRegSlotsContainer;
  29. struct InlineCache;
  30. struct PolymorphicInlineCache;
  31. struct IsInstInlineCache;
  32. class ScopeObjectChain;
  33. class EntryPointInfo;
  34. class FunctionProxy;
  35. class ParseableFunctionInfo;
  36. class FunctionBody;
  37. class DebuggerScopeProperty;
  38. class DebuggerScope;
  39. class FunctionEntryPointInfo;
  40. #ifndef TEMP_DISABLE_ASMJS
  41. class AsmJsFunctionInfo;
  42. class AmsJsModuleInfo;
  43. #endif
  44. class ArrayBuffer;
  45. class FunctionCodeGenRuntimeData;
  46. #pragma endregion
  47. typedef JsUtil::BaseDictionary<Js::PropertyId, const Js::PropertyRecord*, RecyclerNonLeafAllocator, PowerOf2SizePolicy, DefaultComparer, JsUtil::SimpleDictionaryEntry> PropertyRecordList;
  48. typedef JsUtil::BaseHashSet<void*, Recycler, PowerOf2SizePolicy> TypeRefSet;
  49. // Definition of scopes such as With, Catch and Block which will be used further in the debugger for additional look-ups.
  50. enum DiagExtraScopesType
  51. {
  52. DiagUnknownScope, // Unknown scope set when deserializing bytecode and the scope is not yet known.
  53. DiagWithScope, // With scope.
  54. DiagCatchScopeDirect, // Catch scope in regslot
  55. DiagCatchScopeInSlot, // Catch scope in slot array
  56. DiagCatchScopeInObject, // Catch scope in scope object
  57. DiagBlockScopeDirect, // Block scope in regslot
  58. DiagBlockScopeInSlot, // Block scope in slot array
  59. DiagBlockScopeInObject, // Block scope in activation object
  60. DiagBlockScopeRangeEnd, // Used to end a block scope range.
  61. DiagParamScope, // The scope represents symbols at formals
  62. };
  63. class PropertyGuard
  64. {
  65. friend class PropertyGuardValidator;
  66. private:
  67. intptr_t value;
  68. public:
  69. static PropertyGuard* New(Recycler* recycler) { return RecyclerNewLeaf(recycler, Js::PropertyGuard); }
  70. PropertyGuard() : value(1) {}
  71. PropertyGuard(intptr_t value) : value(value) { Assert(this->value != 0); }
  72. inline static size_t const GetSizeOfValue() { return sizeof(((PropertyGuard*)0)->value); }
  73. inline static size_t const GetOffsetOfValue() { return offsetof(PropertyGuard, value); }
  74. intptr_t GetValue() const { return this->value; }
  75. bool IsValid() { return this->value != 0; }
  76. void SetValue(intptr_t value) { Assert(value != 0); this->value = value; }
  77. intptr_t const* GetAddressOfValue() { return &this->value; }
  78. void Invalidate() { this->value = 0; }
  79. };
  80. class PropertyGuardValidator
  81. {
  82. // Required by EquivalentTypeGuard::SetType.
  83. CompileAssert(offsetof(PropertyGuard, value) == 0);
  84. CompileAssert(offsetof(ConstructorCache, guard.value) == offsetof(PropertyGuard, value));
  85. };
  86. class JitIndexedPropertyGuard : public Js::PropertyGuard
  87. {
  88. private:
  89. int index;
  90. public:
  91. JitIndexedPropertyGuard(intptr_t value, int index):
  92. Js::PropertyGuard(value), index(index) {}
  93. int GetIndex() const { return this->index; }
  94. };
  95. class JitTypePropertyGuard : public Js::JitIndexedPropertyGuard
  96. {
  97. public:
  98. JitTypePropertyGuard(Js::Type* type, int index):
  99. JitIndexedPropertyGuard(reinterpret_cast<intptr_t>(type), index) {}
  100. Js::Type* GetType() const { return reinterpret_cast<Js::Type*>(this->GetValue()); }
  101. };
  102. struct TypeGuardTransferEntry
  103. {
  104. PropertyId propertyId;
  105. JitIndexedPropertyGuard* guards[0];
  106. TypeGuardTransferEntry(): propertyId(Js::Constants::NoProperty) {}
  107. };
  108. class FakePropertyGuardWeakReference: public RecyclerWeakReference<Js::PropertyGuard>
  109. {
  110. public:
  111. static FakePropertyGuardWeakReference* New(Recycler* recycler, Js::PropertyGuard* guard)
  112. {
  113. Assert(guard != nullptr);
  114. return RecyclerNewLeaf(recycler, Js::FakePropertyGuardWeakReference, guard);
  115. }
  116. FakePropertyGuardWeakReference(const Js::PropertyGuard* guard)
  117. {
  118. this->strongRef = (char*)guard;
  119. this->strongRefHeapBlock = &CollectedRecyclerWeakRefHeapBlock::Instance;
  120. }
  121. void Zero()
  122. {
  123. Assert(this->strongRef != nullptr);
  124. this->strongRef = nullptr;
  125. }
  126. };
  127. struct CtorCacheGuardTransferEntry
  128. {
  129. PropertyId propertyId;
  130. ConstructorCache* caches[0];
  131. CtorCacheGuardTransferEntry(): propertyId(Js::Constants::NoProperty) {}
  132. };
  133. #define EQUIVALENT_TYPE_CACHE_SIZE (8)
  134. struct EquivalentTypeCache
  135. {
  136. Js::Type* types[EQUIVALENT_TYPE_CACHE_SIZE];
  137. PropertyGuard *guard;
  138. TypeEquivalenceRecord record;
  139. uint nextEvictionVictim;
  140. bool isLoadedFromProto;
  141. bool hasFixedValue;
  142. EquivalentTypeCache(): nextEvictionVictim(EQUIVALENT_TYPE_CACHE_SIZE) {}
  143. bool ClearUnusedTypes(Recycler *recycler);
  144. void SetGuard(PropertyGuard *theGuard) { this->guard = theGuard; }
  145. void SetIsLoadedFromProto() { this->isLoadedFromProto = true; }
  146. bool IsLoadedFromProto() const { return this->isLoadedFromProto; }
  147. void SetHasFixedValue() { this->hasFixedValue = true; }
  148. bool HasFixedValue() const { return this->hasFixedValue; }
  149. };
  150. class JitEquivalentTypeGuard : public JitIndexedPropertyGuard
  151. {
  152. // This pointer is allocated from background thread first, and then transferred to recycler,
  153. // so as to keep the cached types alive.
  154. EquivalentTypeCache* cache;
  155. uint32 objTypeSpecFldId;
  156. public:
  157. JitEquivalentTypeGuard(Type* type, int index, uint32 objTypeSpecFldId):
  158. JitIndexedPropertyGuard(reinterpret_cast<intptr_t>(type), index), cache(nullptr), objTypeSpecFldId(objTypeSpecFldId) {}
  159. Js::Type* GetType() const { return reinterpret_cast<Js::Type*>(this->GetValue()); }
  160. void SetType(const Js::Type* type)
  161. {
  162. this->SetValue(reinterpret_cast<intptr_t>(type));
  163. }
  164. uint32 GetObjTypeSpecFldId() const
  165. {
  166. return this->objTypeSpecFldId;
  167. }
  168. Js::EquivalentTypeCache* GetCache() const
  169. {
  170. return this->cache;
  171. }
  172. void SetCache(Js::EquivalentTypeCache* cache)
  173. {
  174. this->cache = cache;
  175. }
  176. };
  177. #pragma region Inline Cache Info class declarations
  178. class PolymorphicCacheUtilizationArray
  179. {
  180. private:
  181. byte *utilArray;
  182. public:
  183. PolymorphicCacheUtilizationArray()
  184. : utilArray(nullptr)
  185. {
  186. }
  187. void EnsureUtilArray(Recycler * const recycler, Js::FunctionBody * functionBody);
  188. void SetUtil(Js::FunctionBody* functionBody, uint index, byte util);
  189. byte GetUtil(Js::FunctionBody* functionBody, uint index);
  190. };
  191. class PolymorphicInlineCacheInfo sealed
  192. {
  193. private:
  194. InlineCachePointerArray<PolymorphicInlineCache> polymorphicInlineCaches;
  195. PolymorphicCacheUtilizationArray polymorphicCacheUtilizationArray;
  196. FunctionBody * functionBody;
  197. public:
  198. PolymorphicInlineCacheInfo(FunctionBody * functionBody)
  199. : functionBody(functionBody)
  200. {
  201. }
  202. InlineCachePointerArray<PolymorphicInlineCache> * GetPolymorphicInlineCaches() { return &polymorphicInlineCaches; }
  203. PolymorphicCacheUtilizationArray * GetUtilArray() { return &polymorphicCacheUtilizationArray; }
  204. FunctionBody * GetFunctionBody() { return functionBody; }
  205. };
  206. class EntryPointPolymorphicInlineCacheInfo sealed
  207. {
  208. private:
  209. PolymorphicInlineCacheInfo selfInfo;
  210. SListBase<PolymorphicInlineCacheInfo*> inlineeInfo;
  211. static void SetPolymorphicInlineCache(PolymorphicInlineCacheInfo * polymorphicInlineCacheInfo, FunctionBody * functionBody, uint index, PolymorphicInlineCache * polymorphicInlineCache, byte polyCacheUtil);
  212. public:
  213. EntryPointPolymorphicInlineCacheInfo(FunctionBody * functionBody)
  214. : selfInfo(functionBody)
  215. {
  216. }
  217. PolymorphicInlineCacheInfo * GetSelfInfo() { return &selfInfo; }
  218. PolymorphicInlineCacheInfo * EnsureInlineeInfo(Recycler * recycler, FunctionBody * inlineeFunctionBody);
  219. PolymorphicInlineCacheInfo * GetInlineeInfo(FunctionBody * inlineeFunctionBody);
  220. void SetPolymorphicInlineCache(FunctionBody * functionBody, uint index, PolymorphicInlineCache * polymorphicInlineCache, bool isInlinee, byte polyCacheUtil);
  221. template <class Fn>
  222. void MapInlinees(Fn fn)
  223. {
  224. SListBase<PolymorphicInlineCacheInfo*>::Iterator iter(&inlineeInfo);
  225. while (iter.Next())
  226. {
  227. fn(iter.Data());
  228. }
  229. }
  230. };
  231. #pragma endregion
  232. #ifdef FIELD_ACCESS_STATS
  233. struct FieldAccessStats
  234. {
  235. uint totalInlineCacheCount;
  236. uint noInfoInlineCacheCount;
  237. uint monoInlineCacheCount;
  238. uint emptyMonoInlineCacheCount;
  239. uint polyInlineCacheCount;
  240. uint nullPolyInlineCacheCount;
  241. uint emptyPolyInlineCacheCount;
  242. uint ignoredPolyInlineCacheCount;
  243. uint highUtilPolyInlineCacheCount;
  244. uint lowUtilPolyInlineCacheCount;
  245. uint equivPolyInlineCacheCount;
  246. uint nonEquivPolyInlineCacheCount;
  247. uint disabledPolyInlineCacheCount;
  248. uint clonedMonoInlineCacheCount;
  249. uint clonedPolyInlineCacheCount;
  250. FieldAccessStats() :
  251. totalInlineCacheCount(0), noInfoInlineCacheCount(0), monoInlineCacheCount(0), emptyMonoInlineCacheCount(0),
  252. polyInlineCacheCount(0), nullPolyInlineCacheCount(0), emptyPolyInlineCacheCount(0), ignoredPolyInlineCacheCount(0),
  253. highUtilPolyInlineCacheCount(0), lowUtilPolyInlineCacheCount(0),
  254. equivPolyInlineCacheCount(0), nonEquivPolyInlineCacheCount(0), disabledPolyInlineCacheCount(0),
  255. clonedMonoInlineCacheCount(0), clonedPolyInlineCacheCount(0) {}
  256. void Add(FieldAccessStats* other);
  257. };
  258. typedef FieldAccessStats* FieldAccessStatsPtr;
  259. #else
  260. typedef void* FieldAccessStatsPtr;
  261. #endif
  262. #pragma region Entry point class declarations
  263. class ProxyEntryPointInfo: public ExpirableObject
  264. {
  265. public:
  266. // These are public because we don't manage them nor their consistency;
  267. // the user of this class does.
  268. void * address;
  269. ProxyEntryPointInfo(void* address, ThreadContext* context = nullptr):
  270. ExpirableObject(context),
  271. address(address)
  272. {
  273. }
  274. static DWORD GetAddressOffset() { return offsetof(ProxyEntryPointInfo, address); }
  275. virtual void Expire()
  276. {
  277. AssertMsg(false, "Expire called on object that doesn't support expiration");
  278. }
  279. virtual void EnterExpirableCollectMode()
  280. {
  281. AssertMsg(false, "EnterExpirableCollectMode called on object that doesn't support expiration");
  282. }
  283. virtual bool IsFunctionEntryPointInfo() const { return false; }
  284. };
  285. // Not thread safe.
  286. // Note that instances of this class are read from and written to from the
  287. // main and JIT threads.
  288. class EntryPointInfo : public ProxyEntryPointInfo
  289. {
  290. private:
  291. enum State : BYTE
  292. {
  293. NotScheduled, // code gen has not been scheduled
  294. CodeGenPending, // code gen job has been scheduled
  295. CodeGenQueued, // code gen has been queued and all the code gen data has been gathered.
  296. CodeGenRecorded, // backend completed, but job still pending
  297. CodeGenDone, // code gen job successfully completed
  298. JITCapReached, // workitem created but JIT cap reached
  299. PendingCleanup, // workitem needs to be cleaned up but couldn't for some reason- it'll be cleaned up at the next opportunity
  300. CleanedUp // the entry point has been cleaned up
  301. };
  302. #if ENABLE_NATIVE_CODEGEN
  303. class JitTransferData
  304. {
  305. friend EntryPointInfo;
  306. private:
  307. TypeRefSet* jitTimeTypeRefs;
  308. void** runtimeTypeRefs;
  309. int runtimeTypeRefCount;
  310. int propertyGuardCount;
  311. // This is a dynamically sized array of dynamically sized TypeGuardTransferEntries. It's heap allocated by the JIT
  312. // thread and lives until entry point is installed, at which point it is explicitly freed.
  313. TypeGuardTransferEntry* propertyGuardsByPropertyId;
  314. size_t propertyGuardsByPropertyIdPlusSize;
  315. // This is a dynamically sized array of dynamically sized CtorCacheGuardTransferEntry. It's heap allocated by the JIT
  316. // thread and lives until entry point is installed, at which point it is explicitly freed.
  317. CtorCacheGuardTransferEntry* ctorCacheGuardsByPropertyId;
  318. size_t ctorCacheGuardsByPropertyIdPlusSize;
  319. int equivalentTypeGuardCount;
  320. int lazyBailoutPropertyCount;
  321. // This is a dynamically sized array of JitEquivalentTypeGuards. It's heap allocated by the JIT thread and lives
  322. // until entry point is installed, at which point it is explicitly freed. We need it during installation so as to
  323. // swap the cache associated with each guard from the heap to the recycler (so the types in the cache are kept alive).
  324. JitEquivalentTypeGuard** equivalentTypeGuards;
  325. Js::PropertyId* lazyBailoutProperties;
  326. NativeCodeData* data;
  327. bool falseReferencePreventionBit;
  328. bool isReady;
  329. public:
  330. JitTransferData():
  331. jitTimeTypeRefs(nullptr), runtimeTypeRefCount(0), runtimeTypeRefs(nullptr),
  332. propertyGuardCount(0), propertyGuardsByPropertyId(nullptr), propertyGuardsByPropertyIdPlusSize(0),
  333. ctorCacheGuardsByPropertyId(nullptr), ctorCacheGuardsByPropertyIdPlusSize(0),
  334. equivalentTypeGuardCount(0), equivalentTypeGuards(nullptr), data(nullptr),
  335. falseReferencePreventionBit(true), isReady(false), lazyBailoutProperties(nullptr), lazyBailoutPropertyCount(0){}
  336. void AddJitTimeTypeRef(void* typeRef, Recycler* recycler);
  337. int GetRuntimeTypeRefCount() { return this->runtimeTypeRefCount; }
  338. void** GetRuntimeTypeRefs() { return this->runtimeTypeRefs; }
  339. void SetRuntimeTypeRefs(void** runtimeTypeRefs, int count) { this->runtimeTypeRefs = runtimeTypeRefs; this->runtimeTypeRefCount = count; }
  340. JitEquivalentTypeGuard** GetEquivalentTypeGuards() const { return this->equivalentTypeGuards; }
  341. void SetEquivalentTypeGuards(JitEquivalentTypeGuard** guards, int count)
  342. {
  343. this->equivalentTypeGuardCount = count;
  344. this->equivalentTypeGuards = guards;
  345. }
  346. void SetLazyBailoutProperties(Js::PropertyId* properties, int count)
  347. {
  348. this->lazyBailoutProperties = properties;
  349. this->lazyBailoutPropertyCount = count;
  350. }
  351. bool GetIsReady() { return this->isReady; }
  352. void SetIsReady() { this->isReady = true; }
  353. private:
  354. void EnsureJitTimeTypeRefs(Recycler* recycler);
  355. };
  356. NativeCodeData * data;
  357. CodeGenNumberChunk * numberChunks;
  358. SmallSpanSequence *nativeThrowSpanSequence;
  359. typedef JsUtil::BaseHashSet<RecyclerWeakReference<FunctionBody>*, Recycler, PowerOf2SizePolicy> WeakFuncRefSet;
  360. WeakFuncRefSet *weakFuncRefSet;
  361. // Need to keep strong references to the guards here so they don't get collected while the entry point is alive.
  362. typedef JsUtil::BaseDictionary<Js::PropertyId, PropertyGuard*, Recycler, PowerOf2SizePolicy> SharedPropertyGuardDictionary;
  363. SharedPropertyGuardDictionary* sharedPropertyGuards;
  364. typedef JsUtil::List<LazyBailOutRecord, HeapAllocator> BailOutRecordMap;
  365. BailOutRecordMap* bailoutRecordMap;
  366. // This array holds fake weak references to type property guards. We need it to zero out the weak references when the
  367. // entry point is finalized and the guards are about to be freed. Otherwise, if one of the guards was to be invalidated
  368. // from the thread context, we would AV trying to access freed memory. Note that the guards themselves are allocated by
  369. // NativeCodeData::Allocator and are kept alive by the data field. The weak references are recycler allocated, and so
  370. // the array must be recycler allocated also, so that the recycler doesn't collect the weak references.
  371. FakePropertyGuardWeakReference** propertyGuardWeakRefs;
  372. EquivalentTypeCache* equivalentTypeCaches;
  373. EntryPointInfo ** registeredEquivalentTypeCacheRef;
  374. int propertyGuardCount;
  375. int equivalentTypeCacheCount;
  376. #endif
  377. CodeGenWorkItem * workItem;
  378. void * nativeAddress;
  379. ptrdiff_t codeSize;
  380. bool isAsmJsFunction; // true if entrypoint is for asmjs function
  381. uintptr_t mModuleAddress; //asm Module address
  382. #ifdef FIELD_ACCESS_STATS
  383. FieldAccessStatsPtr fieldAccessStats;
  384. #endif
  385. protected:
  386. JavascriptLibrary* library;
  387. #if ENABLE_NATIVE_CODEGEN
  388. typedef JsUtil::List<NativeOffsetInlineeFramePair, HeapAllocator> InlineeFrameMap;
  389. InlineeFrameMap* inlineeFrameMap;
  390. #endif
  391. #if ENABLE_DEBUG_STACK_BACK_TRACE
  392. StackBackTrace* cleanupStack;
  393. #endif
  394. public:
  395. enum CleanupReason
  396. {
  397. NotCleanedUp,
  398. CodeGenFailedOOM,
  399. CodeGenFailedStackOverflow,
  400. CodeGenFailedAborted,
  401. CodeGenFailedExceedJITLimit,
  402. CodeGenFailedUnknown,
  403. NativeCodeInstallFailure,
  404. CleanUpForFinalize
  405. };
  406. uint frameHeight;
  407. private:
  408. #if ENABLE_NATIVE_CODEGEN
  409. typedef SListCounted<ConstructorCache*, Recycler> ConstructorCacheList;
  410. ConstructorCacheList* constructorCaches;
  411. EntryPointPolymorphicInlineCacheInfo * polymorphicInlineCacheInfo;
  412. // This field holds any recycler allocated references that must be kept alive until
  413. // we install the entry point. It is freed at that point, so anything that must survive
  414. // until the EntryPointInfo itself goes away, must be copied somewhere else.
  415. JitTransferData* jitTransferData;
  416. // If we pin types this array contains strong references to types, otherwise it holds weak references.
  417. void **runtimeTypeRefs;
  418. uint32 pendingPolymorphicCacheState;
  419. #endif
  420. State state; // Single state member so users can query state w/o a lock
  421. #if ENABLE_DEBUG_CONFIG_OPTIONS
  422. CleanupReason cleanupReason;
  423. #endif
  424. BYTE pendingInlinerVersion;
  425. bool isLoopBody;
  426. bool hasJittedStackClosure;
  427. #if ENABLE_NATIVE_CODEGEN
  428. ImplicitCallFlags pendingImplicitCallFlags;
  429. #endif
  430. public:
  431. virtual void Finalize(bool isShutdown) override;
  432. virtual bool IsFunctionEntryPointInfo() const override { return true; }
  433. protected:
  434. EntryPointInfo(void* address, JavascriptLibrary* library, void* validationCookie, ThreadContext* context = nullptr, bool isLoopBody = false) :
  435. ProxyEntryPointInfo(address, context),
  436. #if ENABLE_NATIVE_CODEGEN
  437. nativeThrowSpanSequence(nullptr), workItem(nullptr), weakFuncRefSet(nullptr),
  438. jitTransferData(nullptr), sharedPropertyGuards(nullptr), propertyGuardCount(0), propertyGuardWeakRefs(nullptr),
  439. equivalentTypeCacheCount(0), equivalentTypeCaches(nullptr), constructorCaches(nullptr), state(NotScheduled), data(nullptr),
  440. numberChunks(nullptr), polymorphicInlineCacheInfo(nullptr), runtimeTypeRefs(nullptr),
  441. isLoopBody(isLoopBody), hasJittedStackClosure(false), registeredEquivalentTypeCacheRef(nullptr), bailoutRecordMap(nullptr),
  442. #endif
  443. library(library), codeSize(0), nativeAddress(nullptr), isAsmJsFunction(false), validationCookie(validationCookie)
  444. #if ENABLE_DEBUG_STACK_BACK_TRACE
  445. , cleanupStack(nullptr)
  446. #endif
  447. #if ENABLE_DEBUG_CONFIG_OPTIONS
  448. , cleanupReason(NotCleanedUp)
  449. #endif
  450. #if DBG_DUMP | defined(VTUNE_PROFILING)
  451. , nativeOffsetMaps(&HeapAllocator::Instance)
  452. #endif
  453. #ifdef FIELD_ACCESS_STATS
  454. , fieldAccessStats(nullptr)
  455. #endif
  456. {}
  457. virtual void ReleasePendingWorkItem() {};
  458. virtual void OnCleanup(bool isShutdown) = 0;
  459. #ifdef PERF_COUNTERS
  460. virtual void OnRecorded() = 0;
  461. #endif
  462. private:
  463. State GetState() const
  464. {
  465. Assert(this->state >= NotScheduled && this->state <= CleanedUp);
  466. return this->state;
  467. }
  468. public:
  469. ScriptContext* GetScriptContext();
  470. virtual FunctionBody *GetFunctionBody() const = 0;
  471. #if ENABLE_NATIVE_CODEGEN
  472. EntryPointPolymorphicInlineCacheInfo * EnsurePolymorphicInlineCacheInfo(Recycler * recycler, FunctionBody * functionBody);
  473. EntryPointPolymorphicInlineCacheInfo * GetPolymorphicInlineCacheInfo() { return polymorphicInlineCacheInfo; }
  474. JitTransferData* GetJitTransferData() { return this->jitTransferData; }
  475. JitTransferData* EnsureJitTransferData(Recycler* recycler);
  476. #ifdef FIELD_ACCESS_STATS
  477. FieldAccessStats* GetFieldAccessStats() { return this->fieldAccessStats; }
  478. FieldAccessStats* EnsureFieldAccessStats(Recycler* recycler);
  479. #endif
  480. void PinTypeRefs(ScriptContext* scriptContext);
  481. void InstallGuards(ScriptContext* scriptContext);
  482. #endif
  483. void Cleanup(bool isShutdown, bool captureCleanupStack);
  484. #if ENABLE_DEBUG_STACK_BACK_TRACE
  485. void CaptureCleanupStackTrace();
  486. #endif
  487. bool IsNotScheduled() const
  488. {
  489. return this->GetState() == NotScheduled;
  490. }
  491. bool IsCodeGenPending() const
  492. {
  493. return this->GetState() == CodeGenPending;
  494. }
  495. bool IsNativeCode() const
  496. {
  497. #if ENABLE_NATIVE_CODEGEN
  498. return this->GetState() == CodeGenRecorded ||
  499. this->GetState() == CodeGenDone;
  500. #else
  501. return false;
  502. #endif
  503. }
  504. bool IsCodeGenDone() const
  505. {
  506. #if ENABLE_NATIVE_CODEGEN
  507. return this->GetState() == CodeGenDone;
  508. #else
  509. return false;
  510. #endif
  511. }
  512. bool IsCodeGenQueued() const
  513. {
  514. #if ENABLE_NATIVE_CODEGEN
  515. return this->GetState() == CodeGenQueued;
  516. #else
  517. return false;
  518. #endif
  519. }
  520. bool IsJITCapReached() const
  521. {
  522. #if ENABLE_NATIVE_CODEGEN
  523. return this->GetState() == JITCapReached;
  524. #else
  525. return false;
  526. #endif
  527. }
  528. bool IsCleanedUp() const
  529. {
  530. return this->GetState() == CleanedUp;
  531. }
  532. bool IsPendingCleanup() const
  533. {
  534. return this->GetState() == PendingCleanup;
  535. }
  536. void SetPendingCleanup()
  537. {
  538. this->state = PendingCleanup;
  539. }
  540. #if ENABLE_DEBUG_CONFIG_OPTIONS
  541. void SetCleanupReason(CleanupReason reason)
  542. {
  543. this->cleanupReason = reason;
  544. }
  545. #endif
  546. bool IsLoopBody() const
  547. {
  548. return this->isLoopBody;
  549. }
  550. #if ENABLE_NATIVE_CODEGEN
  551. bool HasJittedStackClosure() const
  552. {
  553. return this->hasJittedStackClosure;
  554. }
  555. void SetHasJittedStackClosure()
  556. {
  557. this->hasJittedStackClosure = true;
  558. }
  559. #endif
  560. #ifndef TEMP_DISABLE_ASMJS
  561. void SetModuleAddress(uintptr_t moduleAddress)
  562. {
  563. Assert(this->GetIsAsmJSFunction());
  564. Assert(moduleAddress);
  565. mModuleAddress = moduleAddress;
  566. }
  567. uintptr_t GetModuleAddress()const
  568. {
  569. Assert(this->GetIsAsmJSFunction());
  570. Assert(mModuleAddress); // module address should not be null
  571. return mModuleAddress;
  572. }
  573. #endif
  574. void Reset(bool resetStateToNotScheduled = true);
  575. #if ENABLE_NATIVE_CODEGEN
  576. void SetCodeGenPending(CodeGenWorkItem * workItem)
  577. {
  578. Assert(this->GetState() == NotScheduled || this->GetState() == CleanedUp);
  579. Assert(workItem != nullptr);
  580. this->workItem = workItem;
  581. this->state = CodeGenPending;
  582. }
  583. void SetCodeGenPending()
  584. {
  585. Assert(this->GetState() == CodeGenQueued);
  586. this->state = CodeGenPending;
  587. }
  588. void SetCodeGenQueued()
  589. {
  590. Assert(this->GetState() == CodeGenPending);
  591. this->state = CodeGenQueued;
  592. }
  593. void RevertToNotScheduled()
  594. {
  595. Assert(this->GetState() == CodeGenPending);
  596. Assert(this->workItem != nullptr);
  597. this->workItem = nullptr;
  598. this->state = NotScheduled;
  599. }
  600. void SetCodeGenPendingWithStackAllocatedWorkItem()
  601. {
  602. Assert(this->GetState() == NotScheduled || this->GetState() == CleanedUp);
  603. this->workItem = nullptr;
  604. this->state = CodeGenPending;
  605. }
  606. void SetCodeGenRecorded(void * nativeAddress, ptrdiff_t codeSize,
  607. NativeCodeData * data, NativeCodeData * transferData, CodeGenNumberChunk * numberChunks)
  608. {
  609. Assert(this->GetState() == CodeGenQueued);
  610. Assert(nativeAddress != nullptr);
  611. Assert(codeSize > 0);
  612. Assert(this->jitTransferData != nullptr || transferData == nullptr);
  613. this->nativeAddress = (void *)nativeAddress;
  614. this->codeSize = codeSize;
  615. this->data = data;
  616. if (transferData != nullptr)
  617. {
  618. this->jitTransferData->data = transferData;
  619. }
  620. this->numberChunks = numberChunks;
  621. this->state = CodeGenRecorded;
  622. #ifdef PERF_COUNTERS
  623. this->OnRecorded();
  624. #endif
  625. }
  626. void SetCodeGenDone()
  627. {
  628. Assert(this->GetState() == CodeGenRecorded);
  629. this->state = CodeGenDone;
  630. this->workItem = nullptr;
  631. }
  632. void SetJITCapReached()
  633. {
  634. Assert(this->GetState() == CodeGenQueued);
  635. this->state = JITCapReached;
  636. this->workItem = nullptr;
  637. }
  638. SmallSpanSequence* GetNativeThrowSpanSequence() const
  639. {
  640. Assert(this->GetState() != NotScheduled);
  641. Assert(this->GetState() != CleanedUp);
  642. return nativeThrowSpanSequence;
  643. }
  644. void SetNativeThrowSpanSequence(SmallSpanSequence* seq)
  645. {
  646. Assert(this->GetState() == CodeGenQueued);
  647. Assert(this->nativeThrowSpanSequence == nullptr);
  648. nativeThrowSpanSequence = seq;
  649. }
  650. bool IsInNativeAddressRange(DWORD_PTR codeAddress) {
  651. return (IsNativeCode() &&
  652. codeAddress >= GetNativeAddress() &&
  653. codeAddress < GetNativeAddress() + GetCodeSize());
  654. }
  655. #endif
  656. DWORD_PTR GetNativeAddress() const
  657. {
  658. // need the assert to skip for asmjsFunction as nativeAddress can be interpreter too for asmjs
  659. Assert(this->GetState() == CodeGenRecorded || this->GetState() == CodeGenDone || this->isAsmJsFunction);
  660. return (DWORD_PTR)this->nativeAddress;
  661. }
  662. ptrdiff_t GetCodeSize() const
  663. {
  664. Assert(this->GetState() == CodeGenRecorded || this->GetState() == CodeGenDone);
  665. return codeSize;
  666. }
  667. CodeGenWorkItem * GetWorkItem() const
  668. {
  669. State state = this->GetState();
  670. Assert(state != NotScheduled || this->workItem == nullptr);
  671. Assert(state == CleanedUp && this->workItem == nullptr ||
  672. state != CleanedUp);
  673. if (state == PendingCleanup)
  674. {
  675. return nullptr;
  676. }
  677. return this->workItem;
  678. }
  679. #ifndef TEMP_DISABLE_ASMJS
  680. // set code size, used by TJ to set the code size
  681. void SetCodeSize(ptrdiff_t size)
  682. {
  683. Assert(isAsmJsFunction);
  684. this->codeSize = size;
  685. }
  686. void SetNativeAddress(void* address)
  687. {
  688. Assert(isAsmJsFunction);
  689. this->nativeAddress = address;
  690. }
  691. void SetIsAsmJSFunction(bool value)
  692. {
  693. this->isAsmJsFunction = value;
  694. }
  695. #endif
  696. bool GetIsAsmJSFunction()const
  697. {
  698. return this->isAsmJsFunction;
  699. }
  700. #ifndef TEMP_DISABLE_ASMJS
  701. void SetTJCodeGenDone()
  702. {
  703. Assert(isAsmJsFunction);
  704. this->state = CodeGenDone;
  705. this->workItem = nullptr;
  706. }
  707. #endif
  708. #if ENABLE_NATIVE_CODEGEN
  709. void AddWeakFuncRef(RecyclerWeakReference<FunctionBody> *weakFuncRef, Recycler *recycler);
  710. WeakFuncRefSet *EnsureWeakFuncRefSet(Recycler *recycler);
  711. void EnsureIsReadyToCall();
  712. void ProcessJitTransferData();
  713. void ResetOnNativeCodeInstallFailure();
  714. virtual void OnNativeCodeInstallFailure() = 0;
  715. Js::PropertyGuard* RegisterSharedPropertyGuard(Js::PropertyId propertyId, ScriptContext* scriptContext);
  716. bool HasSharedPropertyGuards() { return this->sharedPropertyGuards != nullptr; }
  717. bool HasSharedPropertyGuard(Js::PropertyId propertyId);
  718. bool TryGetSharedPropertyGuard(Js::PropertyId propertyId, Js::PropertyGuard*& guard);
  719. void RecordTypeGuards(int propertyGuardCount, TypeGuardTransferEntry* typeGuardTransferRecord, size_t typeGuardTransferPlusSize);
  720. void RecordCtorCacheGuards(CtorCacheGuardTransferEntry* ctorCacheTransferRecord, size_t ctorCacheTransferPlusSize);
  721. void FreePropertyGuards();
  722. void FreeJitTransferData();
  723. void RegisterEquivalentTypeCaches();
  724. void UnregisterEquivalentTypeCaches();
  725. bool ClearEquivalentTypeCaches();
  726. void RegisterConstructorCache(Js::ConstructorCache* constructorCache, Recycler* recycler);
  727. uint GetConstructorCacheCount() const { return this->constructorCaches != nullptr ? this->constructorCaches->Count() : 0; }
  728. uint32 GetPendingPolymorphicCacheState() const { return this->pendingPolymorphicCacheState; }
  729. void SetPendingPolymorphicCacheState(uint32 state) { this->pendingPolymorphicCacheState = state; }
  730. BYTE GetPendingInlinerVersion() const { return this->pendingInlinerVersion; }
  731. void SetPendingInlinerVersion(BYTE version) { this->pendingInlinerVersion = version; }
  732. ImplicitCallFlags GetPendingImplicitCallFlags() const { return this->pendingImplicitCallFlags; }
  733. void SetPendingImplicitCallFlags(ImplicitCallFlags flags) { this->pendingImplicitCallFlags = flags; }
  734. virtual void Invalidate(bool prolongEntryPoint) { Assert(false); }
  735. void RecordBailOutMap(JsUtil::List<LazyBailOutRecord, ArenaAllocator>* bailoutMap);
  736. void RecordInlineeFrameMap(JsUtil::List<NativeOffsetInlineeFramePair, ArenaAllocator>* tempInlineeFrameMap);
  737. InlineeFrameRecord* FindInlineeFrame(void* returnAddress);
  738. bool HasInlinees() { return this->frameHeight > 0; }
  739. void DoLazyBailout(BYTE** addressOfReturnAddress, Js::FunctionBody* functionBody, const PropertyRecord* propertyRecord);
  740. #endif
  741. #if DBG_DUMP
  742. public:
  743. #elif defined(VTUNE_PROFILING)
  744. private:
  745. #endif
  746. #if DBG_DUMP || defined(VTUNE_PROFILING)
  747. // NativeOffsetMap is public for DBG_DUMP, private for VTUNE_PROFILING
  748. struct NativeOffsetMap
  749. {
  750. uint32 statementIndex;
  751. regex::Interval nativeOffsetSpan;
  752. };
  753. private:
  754. JsUtil::List<NativeOffsetMap, HeapAllocator> nativeOffsetMaps;
  755. public:
  756. void RecordNativeMap(uint32 offset, uint32 statementIndex);
  757. int GetNativeOffsetMapCount() const;
  758. #endif
  759. #if DBG_DUMP && ENABLE_NATIVE_CODEGEN
  760. void DumpNativeOffsetMaps();
  761. void DumpNativeThrowSpanSequence();
  762. NativeOffsetMap* GetNativeOffsetMap(int index)
  763. {
  764. Assert(index >= 0);
  765. Assert(index < GetNativeOffsetMapCount());
  766. return &nativeOffsetMaps.Item(index);
  767. }
  768. #endif
  769. #ifdef VTUNE_PROFILING
  770. public:
  771. uint PopulateLineInfo(void* pLineInfo, FunctionBody* body);
  772. #endif
  773. protected:
  774. void* validationCookie;
  775. };
  776. class FunctionEntryPointInfo : public EntryPointInfo
  777. {
  778. public:
  779. FunctionProxy * functionProxy;
  780. FunctionEntryPointInfo* nextEntryPoint;
  781. // The offset on the native stack, from which the locals are located (Populated at RegAlloc phase). Used for debug purpose.
  782. int32 localVarSlotsOffset;
  783. // The offset which stores that any of the locals are changed from the debugger.
  784. int32 localVarChangedOffset;
  785. uint entryPointIndex;
  786. uint8 callsCount;
  787. uint8 lastCallsCount;
  788. bool nativeEntryPointProcessed;
  789. private:
  790. ExecutionMode jitMode;
  791. FunctionEntryPointInfo* mOldFunctionEntryPointInfo; // strong ref to oldEntryPointInfo(Int or TJ) in asm to ensure we don't collect it before JIT is completed
  792. bool mIsTemplatizedJitMode; // true only if in TJ mode, used only for debugging
  793. public:
  794. static const uint8 GetDecrCallCountPerBailout()
  795. {
  796. return (100 / (uint8)CONFIG_FLAG(RejitRatioLimit)) + 1;
  797. }
  798. FunctionEntryPointInfo(FunctionProxy * functionInfo, void * address, ThreadContext* context, void* validationCookie);
  799. #ifndef TEMP_DISABLE_ASMJS
  800. //AsmJS Support
  801. void SetOldFunctionEntryPointInfo(FunctionEntryPointInfo* entrypointInfo);
  802. FunctionEntryPointInfo* GetOldFunctionEntryPointInfo()const;
  803. void SetIsTJMode(bool value);
  804. bool GetIsTJMode()const;
  805. //End AsmJS Support
  806. #endif
  807. virtual FunctionBody *GetFunctionBody() const override;
  808. #if ENABLE_NATIVE_CODEGEN
  809. ExecutionMode GetJitMode() const;
  810. void SetJitMode(const ExecutionMode jitMode);
  811. virtual void Invalidate(bool prolongEntryPoint) override;
  812. virtual void Expire() override;
  813. virtual void EnterExpirableCollectMode() override;
  814. virtual void OnNativeCodeInstallFailure() override;
  815. #endif
  816. virtual void OnCleanup(bool isShutdown) override;
  817. virtual void ReleasePendingWorkItem() override;
  818. #ifdef PERF_COUNTERS
  819. virtual void OnRecorded() override;
  820. #endif
  821. };
  822. class LoopEntryPointInfo : public EntryPointInfo
  823. {
  824. public:
  825. LoopHeader* loopHeader;
  826. LoopEntryPointInfo(LoopHeader* loopHeader, Js::JavascriptLibrary* library, void* validationCookie) :
  827. loopHeader(loopHeader), mIsTemplatizedJitMode(false),EntryPointInfo(nullptr, library, validationCookie, /*threadContext*/ nullptr, /*isLoopBody*/ true)
  828. #ifdef BGJIT_STATS
  829. ,used(false)
  830. #endif
  831. { }
  832. virtual FunctionBody *GetFunctionBody() const override;
  833. virtual void OnCleanup(bool isShutdown) override;
  834. #if ENABLE_NATIVE_CODEGEN
  835. virtual void OnNativeCodeInstallFailure() override;
  836. #endif
  837. #ifndef TEMP_DISABLE_ASMJS
  838. void SetIsTJMode(bool value)
  839. {
  840. Assert(this->GetIsAsmJSFunction());
  841. mIsTemplatizedJitMode = value;
  842. }
  843. bool GetIsTJMode()const
  844. {
  845. return mIsTemplatizedJitMode;
  846. };
  847. #endif
  848. #ifdef PERF_COUNTERS
  849. virtual void OnRecorded() override;
  850. #endif
  851. #ifdef BGJIT_STATS
  852. bool IsUsed() const
  853. {
  854. return this->used;
  855. }
  856. void MarkAsUsed()
  857. {
  858. this->used = true;
  859. }
  860. #endif
  861. private:
  862. #ifdef BGJIT_STATS
  863. bool used;
  864. #endif
  865. bool mIsTemplatizedJitMode;
  866. };
  867. typedef RecyclerWeakReference<FunctionEntryPointInfo> FunctionEntryPointWeakRef;
  868. typedef SynchronizableList<FunctionEntryPointWeakRef*, JsUtil::List<FunctionEntryPointWeakRef*>> FunctionEntryPointList;
  869. typedef SynchronizableList<LoopEntryPointInfo*, JsUtil::List<LoopEntryPointInfo*>> LoopEntryPointList;
  870. #pragma endregion
  871. struct LoopHeader
  872. {
  873. private:
  874. LoopEntryPointList* entryPoints;
  875. public:
  876. uint startOffset;
  877. uint endOffset;
  878. uint interpretCount;
  879. uint profiledLoopCounter;
  880. bool isNested;
  881. bool isInTry;
  882. FunctionBody * functionBody;
  883. #if DBG_DUMP
  884. uint nativeCount;
  885. #endif
  886. static const uint NoLoop = (uint)-1;
  887. static const uint GetOffsetOfProfiledLoopCounter() { return offsetof(LoopHeader, profiledLoopCounter); }
  888. static const uint GetOffsetOfInterpretCount() { return offsetof(LoopHeader, interpretCount); }
  889. bool Contains(Js::LoopHeader * loopHeader) const
  890. {
  891. return (this->startOffset <= loopHeader->startOffset && loopHeader->endOffset <= this->endOffset);
  892. }
  893. bool Contains(uint offset) const
  894. {
  895. return this->startOffset <= offset && offset < this->endOffset;
  896. }
  897. void * GetCurrentEntryPoint() const
  898. {
  899. LoopEntryPointInfo * entryPoint = GetCurrentEntryPointInfo();
  900. if (entryPoint != nullptr)
  901. {
  902. return this->entryPoints->Item(this->GetCurrentEntryPointIndex())->address;
  903. }
  904. return nullptr;
  905. }
  906. LoopEntryPointInfo * GetCurrentEntryPointInfo() const
  907. {
  908. Assert(this->entryPoints->Count() > 0);
  909. return this->entryPoints->Item(this->GetCurrentEntryPointIndex());
  910. }
  911. uint GetByteCodeCount()
  912. {
  913. return (endOffset - startOffset);
  914. }
  915. int GetCurrentEntryPointIndex() const
  916. {
  917. return this->entryPoints->Count() - 1;
  918. }
  919. LoopEntryPointInfo * GetEntryPointInfo(int index) const
  920. {
  921. return this->entryPoints->Item(index);
  922. }
  923. template <class Fn>
  924. void MapEntryPoints(Fn fn) const
  925. {
  926. if (this->entryPoints) // ETW rundown may call this before entryPoints initialization
  927. {
  928. this->entryPoints->Map([&](int index, LoopEntryPointInfo * entryPoint)
  929. {
  930. if (entryPoint != nullptr)
  931. {
  932. fn(index, entryPoint);
  933. }
  934. });
  935. }
  936. }
  937. template <class DebugSite, class Fn>
  938. HRESULT MapEntryPoints(DebugSite site, Fn fn) const // external debugging version
  939. {
  940. return Map(site, this->entryPoints, [&](int index, LoopEntryPointInfo * entryPoint)
  941. {
  942. if (entryPoint != nullptr)
  943. {
  944. fn(index, entryPoint);
  945. }
  946. });
  947. }
  948. void Init(FunctionBody * functionBody);
  949. #if ENABLE_NATIVE_CODEGEN
  950. int CreateEntryPoint();
  951. void ReleaseEntryPoints();
  952. #endif
  953. void ResetInterpreterCount()
  954. {
  955. this->interpretCount = 0;
  956. }
  957. void ResetProfiledLoopCounter()
  958. {
  959. this->profiledLoopCounter = 0;
  960. }
  961. };
  962. class FunctionProxy;
  963. typedef FunctionProxy** FunctionProxyArray;
  964. typedef FunctionProxy** FunctionProxyPtrPtr;
  965. //
  966. // FunctionProxy represents a user defined function
  967. // This could be either from a source file or the byte code cache
  968. // The function need not have been compiled yet- it could be parsed or compiled
  969. // at a later time
  970. //
  971. class FunctionProxy : public FunctionInfo
  972. {
  973. static CriticalSection GlobalLock;
  974. public:
  975. static CriticalSection* GetLock() { return &GlobalLock; }
  976. typedef RecyclerWeakReference<DynamicType> FunctionTypeWeakRef;
  977. typedef JsUtil::List<FunctionTypeWeakRef*, Recycler, false, WeakRefFreeListedRemovePolicy> FunctionTypeWeakRefList;
  978. protected:
  979. FunctionProxy(JavascriptMethod entryPoint, Attributes attributes,
  980. LocalFunctionId functionId, ScriptContext* scriptContext, Utf8SourceInfo* utf8SourceInfo, uint functionNumber);
  981. DEFINE_VTABLE_CTOR_NO_REGISTER(FunctionProxy, FunctionInfo);
  982. enum class AuxPointerType : uint8 {
  983. DeferredStubs = 0,
  984. CachedSourceString = 1,
  985. AsmJsFunctionInfo = 2,
  986. AsmJsModuleInfo = 3,
  987. StatementMaps = 4,
  988. StackNestedFuncParent = 5,
  989. SimpleJitEntryPointInfo = 6,
  990. FunctionObjectTypeList = 7, // Script function types not including the deferred prototype type
  991. CodeGenGetSetRuntimeData = 8,
  992. PropertyIdOnRegSlotsContainer = 9, // This is used for showing locals for the current frame.
  993. LoopHeaderArray = 10,
  994. CodeGenRuntimeData = 11,
  995. PolymorphicInlineCachesHead = 12, // DList of all polymorphic inline caches that aren't finalized yet
  996. PropertyIdsForScopeSlotArray = 13, // For SourceInfo
  997. PolymorphicCallSiteInfoHead = 14,
  998. AuxBlock = 15, // Optional auxiliary information
  999. AuxContextBlock = 16, // Optional auxiliary context specific information
  1000. ReferencedPropertyIdMap = 17,
  1001. LiteralRegexes = 18,
  1002. ObjLiteralTypes = 19,
  1003. ScopeInfo = 20,
  1004. Max,
  1005. Invalid = 0xff
  1006. };
  1007. typedef AuxPtrs<FunctionProxy, AuxPointerType> AuxPtrsT;
  1008. friend AuxPtrsT;
  1009. WriteBarrierPtr<AuxPtrsT> auxPtrs;
  1010. void* GetAuxPtr(AuxPointerType e) const;
  1011. void* GetAuxPtrWithLock(AuxPointerType e) const;
  1012. void SetAuxPtr(AuxPointerType e, void* ptr);
  1013. public:
  1014. enum SetDisplayNameFlags
  1015. {
  1016. SetDisplayNameFlagsNone = 0,
  1017. SetDisplayNameFlagsDontCopy = 1,
  1018. SetDisplayNameFlagsRecyclerAllocated = 2
  1019. };
  1020. Recycler* GetRecycler() const;
  1021. uint32 GetSourceContextId() const;
  1022. char16* GetDebugNumberSet(wchar(&bufferToWriteTo)[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE]) const;
  1023. bool GetIsTopLevel() { return m_isTopLevel; }
  1024. void SetIsTopLevel(bool set) { m_isTopLevel = set; }
  1025. bool GetIsAnonymousFunction() const { return this->GetDisplayName() == Js::Constants::AnonymousFunction; }
  1026. void Copy(FunctionProxy* other);
  1027. ParseableFunctionInfo* EnsureDeserialized();
  1028. ScriptContext* GetScriptContext() const;
  1029. Utf8SourceInfo* GetUtf8SourceInfo() const { return this->m_utf8SourceInfo; }
  1030. void SetUtf8SourceInfo(Utf8SourceInfo* utf8SourceInfo) { m_utf8SourceInfo = utf8SourceInfo; }
  1031. void SetReferenceInParentFunction(FunctionProxyPtrPtr reference);
  1032. void UpdateReferenceInParentFunction(FunctionProxy* newFunctionInfo);
  1033. bool IsInDebugMode() const { return this->m_utf8SourceInfo->IsInDebugMode(); }
  1034. DWORD_PTR GetSecondaryHostSourceContext() const;
  1035. DWORD_PTR GetHostSourceContext() const;
  1036. SourceContextInfo * GetSourceContextInfo() const;
  1037. SRCINFO const * GetHostSrcInfo() const;
  1038. uint GetFunctionNumber() const { return m_functionNumber; }
  1039. virtual void Finalize(bool isShutdown) override;
  1040. void UpdateFunctionBodyImpl(FunctionBody* body);
  1041. bool IsFunctionBody() const;
  1042. ProxyEntryPointInfo* GetDefaultEntryPointInfo() const;
  1043. ScriptFunctionType * GetDeferredPrototypeType() const;
  1044. ScriptFunctionType * EnsureDeferredPrototypeType();
  1045. JavascriptMethod GetDirectEntryPoint(ProxyEntryPointInfo* entryPoint) const;
  1046. // Function object type list methods
  1047. FunctionTypeWeakRefList* EnsureFunctionObjectTypeList();
  1048. void RegisterFunctionObjectType(DynamicType* functionType);
  1049. template <typename Fn>
  1050. void MapFunctionObjectTypes(Fn func);
  1051. static uint GetOffsetOfDeferredPrototypeType() { return offsetof(Js::FunctionProxy, deferredPrototypeType); }
  1052. static Js::ScriptFunctionType * EnsureFunctionProxyDeferredPrototypeType(FunctionProxy * proxy)
  1053. {
  1054. return proxy->EnsureDeferredPrototypeType();
  1055. }
  1056. void SetIsPublicLibraryCode() { m_isPublicLibraryCode = true; }
  1057. bool IsPublicLibraryCode() const { return m_isPublicLibraryCode; }
  1058. #if DBG
  1059. bool HasValidEntryPoint() const;
  1060. bool HasValidProfileEntryPoint() const;
  1061. bool HasValidNonProfileEntryPoint() const;
  1062. #endif
  1063. virtual void SetDisplayName(const char16* displayName, uint displayNameLength, uint displayShortNameOffset, SetDisplayNameFlags flags = SetDisplayNameFlagsNone) = 0;
  1064. virtual const char16* GetDisplayName() const = 0;
  1065. virtual uint GetDisplayNameLength() const = 0;
  1066. virtual uint GetShortDisplayNameOffset() const = 0;
  1067. static const char16* WrapWithBrackets(const char16* name, charcount_t sz, ScriptContext* scriptContext);
  1068. // Used only in the library function stringify (toString, DiagGetValueString).
  1069. // If we need more often to give the short name, we should create a member variable which points to the short name
  1070. // this is also now being used for function.name.
  1071. const char16* GetShortDisplayName(charcount_t * shortNameLength);
  1072. bool IsJitLoopBodyPhaseEnabled() const
  1073. {
  1074. // Consider: Allow JitLoopBody in generator functions for loops that do not yield.
  1075. return !PHASE_OFF(JITLoopBodyPhase, this) && DoFullJit() && !this->IsGenerator();
  1076. }
  1077. bool IsJitLoopBodyPhaseForced() const
  1078. {
  1079. return
  1080. IsJitLoopBodyPhaseEnabled() &&
  1081. (
  1082. PHASE_FORCE(JITLoopBodyPhase, this)
  1083. #ifdef ENABLE_PREJIT
  1084. || Configuration::Global.flags.Prejit
  1085. #endif
  1086. );
  1087. }
  1088. ULONG GetHostStartLine() const;
  1089. ULONG GetHostStartColumn() const;
  1090. bool DoFullJit() const
  1091. {
  1092. return !PHASE_OFF(FullJitPhase, this);
  1093. }
  1094. protected:
  1095. // Static method(s)
  1096. static void SetDisplayName(const char16* srcName, WriteBarrierPtr<const char16>* destName, uint displayNameLength, ScriptContext * scriptContext, SetDisplayNameFlags flags = SetDisplayNameFlagsNone);
  1097. static bool SetDisplayName(const char16* srcName, const char16** destName, uint displayNameLength, ScriptContext * scriptContext, SetDisplayNameFlags flags = SetDisplayNameFlagsNone);
  1098. static bool IsConstantFunctionName(const char16* srcName);
  1099. protected:
  1100. NoWriteBarrierPtr<ScriptContext> m_scriptContext; // Memory context for this function body
  1101. WriteBarrierPtr<Utf8SourceInfo> m_utf8SourceInfo;
  1102. // WriteBarrier-TODO: Consider changing this to NoWriteBarrierPtr, and skip tagging- also, tagging is likely unnecessary since that pointer in question is likely not resolvable
  1103. FunctionProxyPtrPtr m_referenceInParentFunction; // Reference to nested function reference to this function in the parent function body (tagged to not be actual reference)
  1104. WriteBarrierPtr<ScriptFunctionType> deferredPrototypeType;
  1105. WriteBarrierPtr<ProxyEntryPointInfo> m_defaultEntryPointInfo; // The default entry point info for the function proxy
  1106. NoWriteBarrierField<uint> m_functionNumber; // Per thread global function number
  1107. bool m_isTopLevel : 1; // Indicates that this function is top-level function, currently being used in script profiler and debugger
  1108. bool m_isPublicLibraryCode: 1; // Indicates this function is public boundary library code that should be visible in JS stack
  1109. void CleanupFunctionProxyCounters()
  1110. {
  1111. PERF_COUNTER_DEC(Code, TotalFunction);
  1112. }
  1113. ULONG ComputeAbsoluteLineNumber(ULONG relativeLineNumber) const;
  1114. ULONG ComputeAbsoluteColumnNumber(ULONG relativeLineNumber, ULONG relativeColumnNumber) const;
  1115. ULONG GetLineNumberInHostBuffer(ULONG relativeLineNumber) const;
  1116. private:
  1117. ScriptFunctionType * AllocDeferredPrototypeType();
  1118. };
  1119. // Represents a function from the byte code cache which will
  1120. // be deserialized upon use
  1121. class DeferDeserializeFunctionInfo: public FunctionProxy
  1122. {
  1123. friend struct ByteCodeSerializer;
  1124. private:
  1125. DeferDeserializeFunctionInfo(int nestedFunctionCount, LocalFunctionId functionId, ByteCodeCache* byteCodeCache, const byte* serializedFunction, Utf8SourceInfo* sourceInfo, ScriptContext* scriptContext, uint functionNumber, const char16* displayName, uint displayNameLength, uint displayShortNameOffset, NativeModule *nativeModule, Attributes attributes);
  1126. public:
  1127. static DeferDeserializeFunctionInfo* New(ScriptContext* scriptContext, int nestedFunctionCount, LocalFunctionId functionId, ByteCodeCache* byteCodeCache, const byte* serializedFunction, Utf8SourceInfo* utf8SourceInfo, const char16* displayName, uint displayNameLength, uint displayShortNameOffset, NativeModule *nativeModule, Attributes attributes);
  1128. virtual void Finalize(bool isShutdown) override;
  1129. FunctionBody* Deserialize();
  1130. virtual const char16* GetDisplayName() const override;
  1131. void SetDisplayName(const char16* displayName);
  1132. virtual void SetDisplayName(const char16* displayName, uint displayNameLength, uint displayShortNameOffset, SetDisplayNameFlags flags = SetDisplayNameFlagsNone) override;
  1133. virtual uint GetDisplayNameLength() const { return m_displayNameLength; }
  1134. virtual uint GetShortDisplayNameOffset() const { return m_displayShortNameOffset; }
  1135. LPCWSTR GetSourceInfo(int& lineNumber, int& columnNumber) const;
  1136. private:
  1137. const byte* m_functionBytes;
  1138. ByteCodeCache* m_cache;
  1139. const char16 * m_displayName; // Optional name
  1140. uint m_displayNameLength;
  1141. uint m_displayShortNameOffset;
  1142. NativeModule *m_nativeModule;
  1143. };
  1144. class ParseableFunctionInfo: public FunctionProxy
  1145. {
  1146. friend class ByteCodeBufferReader;
  1147. protected:
  1148. ParseableFunctionInfo(JavascriptMethod method, int nestedFunctionCount, LocalFunctionId functionId, Utf8SourceInfo* sourceInfo, ScriptContext* scriptContext, uint functionNumber, const char16* displayName, uint m_displayNameLength, uint displayShortNameOffset, Attributes attributes, Js::PropertyRecordList* propertyRecordList);
  1149. public:
  1150. struct NestedArray
  1151. {
  1152. NestedArray(uint32 count) :nestedCount(count) {}
  1153. uint32 nestedCount;
  1154. FunctionProxy* functionProxyArray[0];
  1155. };
  1156. template<typename Fn>
  1157. void ForEachNestedFunc(Fn fn)
  1158. {
  1159. NestedArray* nestedArray = GetNestedArray();
  1160. if (nestedArray != nullptr)
  1161. {
  1162. for (uint i = 0; i < nestedArray->nestedCount; i++)
  1163. {
  1164. if (!fn(nestedArray->functionProxyArray[i], i))
  1165. {
  1166. break;
  1167. }
  1168. }
  1169. }
  1170. }
  1171. NestedArray* GetNestedArray() const { return nestedArray; }
  1172. uint GetNestedCount() const { return nestedArray == nullptr ? 0 : nestedArray->nestedCount; }
  1173. public:
  1174. static ParseableFunctionInfo* New(ScriptContext* scriptContext, int nestedFunctionCount, LocalFunctionId functionId, Utf8SourceInfo* utf8SourceInfo, const char16* displayName, uint m_displayNameLength, uint displayShortNameOffset, Js::PropertyRecordList* propertyRecordList, Attributes attributes);
  1175. DEFINE_VTABLE_CTOR_NO_REGISTER(ParseableFunctionInfo, FunctionProxy);
  1176. FunctionBody* Parse(ScriptFunction ** functionRef = nullptr, bool isByteCodeDeserialization = false);
  1177. #ifndef TEMP_DISABLE_ASMJS
  1178. FunctionBody* ParseAsmJs(Parser * p, __out CompileScriptException * se, __out ParseNodePtr * ptree);
  1179. #endif
  1180. virtual uint GetDisplayNameLength() const { return m_displayNameLength; }
  1181. virtual uint GetShortDisplayNameOffset() const { return m_displayShortNameOffset; }
  1182. bool GetIsDeclaration() const { return m_isDeclaration; }
  1183. void SetIsDeclaration(const bool is) { m_isDeclaration = is; }
  1184. bool GetIsAccessor() const { return m_isAccessor; }
  1185. void SetIsAccessor(const bool is) { m_isAccessor = is; }
  1186. bool GetIsGlobalFunc() const { return m_isGlobalFunc; }
  1187. void SetIsStaticNameFunction(const bool is) { m_isStaticNameFunction = is; }
  1188. bool GetIsStaticNameFunction() const { return m_isStaticNameFunction; }
  1189. void SetIsNamedFunctionExpression(const bool is) { m_isNamedFunctionExpression = is; }
  1190. bool GetIsNamedFunctionExpression() const { return m_isNamedFunctionExpression; }
  1191. void SetIsNameIdentifierRef (const bool is) { m_isNameIdentifierRef = is; }
  1192. bool GetIsNameIdentifierRef () const { return m_isNameIdentifierRef ; }
  1193. // Fake global ->
  1194. // 1) new Function code's global code
  1195. // 2) global code generated from the reparsing deferred parse function
  1196. bool IsFakeGlobalFunc(ulong flags) const;
  1197. void SetIsGlobalFunc(bool is) { m_isGlobalFunc = is; }
  1198. bool GetIsStrictMode() const { return m_isStrictMode; }
  1199. void SetIsStrictMode() { m_isStrictMode = true; }
  1200. bool GetIsAsmjsMode() const { return m_isAsmjsMode; }
  1201. void SetIsAsmjsMode(bool value)
  1202. {
  1203. m_isAsmjsMode = value;
  1204. #if DBG
  1205. if (value)
  1206. {
  1207. m_wasEverAsmjsMode = true;
  1208. }
  1209. #endif
  1210. }
  1211. bool GetHasImplicitArgIns() { return m_hasImplicitArgIns; }
  1212. void SetHasImplicitArgIns(bool has) { m_hasImplicitArgIns = has; }
  1213. ulong GetGrfscr() const;
  1214. void SetGrfscr(ulong grfscr);
  1215. ///----------------------------------------------------------------------------
  1216. ///
  1217. /// ParseableFunctionInfo::GetInParamsCount
  1218. ///
  1219. /// GetInParamsCount() returns the number of "in parameters" that have
  1220. /// currently been declared for this function:
  1221. /// - If this is "RegSlot_VariableCount", the function takes a variable number
  1222. /// of parameters.
  1223. ///
  1224. /// Consider: Change to store type information about parameters- names, type,
  1225. /// direction, etc.
  1226. ///
  1227. ///----------------------------------------------------------------------------
  1228. ArgSlot GetInParamsCount() const { return m_inParamCount; }
  1229. void SetInParamsCount(ArgSlot newInParamCount);
  1230. ArgSlot GetReportedInParamsCount() const;
  1231. void SetReportedInParamsCount(ArgSlot newReportedInParamCount);
  1232. void ResetInParams();
  1233. ScopeInfo* GetScopeInfo() const { return static_cast<ScopeInfo*>(this->GetAuxPtr(AuxPointerType::ScopeInfo)); }
  1234. void SetScopeInfo(ScopeInfo* scopeInfo) { this->SetAuxPtr(AuxPointerType::ScopeInfo, scopeInfo); }
  1235. PropertyId GetOrAddPropertyIdTracked(JsUtil::CharacterBuffer<WCHAR> const& propName);
  1236. bool IsTrackedPropertyId(PropertyId pid);
  1237. Js::PropertyRecordList* GetBoundPropertyRecords() { return this->m_boundPropertyRecords; }
  1238. void SetBoundPropertyRecords(Js::PropertyRecordList* boundPropertyRecords)
  1239. {
  1240. Assert(this->m_boundPropertyRecords == nullptr);
  1241. this->m_boundPropertyRecords = boundPropertyRecords;
  1242. }
  1243. void ClearBoundPropertyRecords()
  1244. {
  1245. this->m_boundPropertyRecords = nullptr;
  1246. }
  1247. virtual ParseableFunctionInfo* Clone(ScriptContext *scriptContext, uint sourceIndex = Js::Constants::InvalidSourceIndex);
  1248. ParseableFunctionInfo* CopyFunctionInfoInto(ScriptContext *scriptContext, Js::ParseableFunctionInfo* functionInfo, uint sourceIndex = Js::Constants::InvalidSourceIndex);
  1249. void CloneSourceInfo(ScriptContext* scriptContext, const ParseableFunctionInfo& other, ScriptContext* othersScriptContext, uint sourceIndex);
  1250. void SetInitialDefaultEntryPoint();
  1251. void SetDeferredParsingEntryPoint();
  1252. void SetEntryPoint(ProxyEntryPointInfo* entryPoint, Js::JavascriptMethod address) {
  1253. entryPoint->address = (void*)address;
  1254. }
  1255. bool IsDynamicScript() const;
  1256. uint LengthInBytes() const { return m_cbLength; }
  1257. uint StartOffset() const;
  1258. ULONG GetLineNumber() const;
  1259. ULONG GetColumnNumber() const;
  1260. template <class T>
  1261. LPCWSTR GetSourceName(const T& sourceContextInfo) const;
  1262. template <class T>
  1263. static LPCWSTR GetSourceName(const T& sourceContextInfo, bool m_isEval, bool m_isDynamicFunction);
  1264. LPCWSTR GetSourceName() const;
  1265. ULONG GetRelativeLineNumber() const { return m_lineNumber; }
  1266. ULONG GetRelativeColumnNumber() const { return m_columnNumber; }
  1267. uint GetSourceIndex() const;
  1268. LPCUTF8 GetSource(const char16* reason = nullptr) const;
  1269. charcount_t LengthInChars() const { return m_cchLength; }
  1270. charcount_t StartInDocument() const;
  1271. bool IsEval() const { return m_isEval; }
  1272. bool IsDynamicFunction() const;
  1273. bool GetDontInline() { return m_dontInline; }
  1274. void SetDontInline(bool is) { m_dontInline = is; }
  1275. LPCUTF8 GetStartOfDocument(const char16* reason = nullptr) const;
  1276. bool IsReparsed() const { return m_reparsed; }
  1277. void SetReparsed(bool set) { m_reparsed = set; }
  1278. bool GetExternalDisplaySourceName(BSTR* sourceName);
  1279. void SetDoBackendArgumentsOptimization(bool set)
  1280. {
  1281. if (m_doBackendArgumentsOptimization)
  1282. {
  1283. m_doBackendArgumentsOptimization = set;
  1284. }
  1285. }
  1286. bool GetDoBackendArgumentsOptimization()
  1287. {
  1288. return m_doBackendArgumentsOptimization;
  1289. }
  1290. bool IsFunctionParsed()
  1291. {
  1292. return !IsDeferredParseFunction() || m_hasBeenParsed;
  1293. }
  1294. void SetFunctionParsed(bool hasBeenParsed)
  1295. {
  1296. m_hasBeenParsed = hasBeenParsed;
  1297. }
  1298. void SetSourceInfo(uint sourceIndex, ParseNodePtr node, bool isEval, bool isDynamicFunction);
  1299. void Copy(FunctionBody* other);
  1300. const char16* GetExternalDisplayName() const;
  1301. //
  1302. // Algorithm to retrieve a function body's external display name. Template supports both
  1303. // local FunctionBody and ScriptDAC (debugging) scenarios.
  1304. //
  1305. template <class T>
  1306. static const char16* GetExternalDisplayName(const T* funcBody)
  1307. {
  1308. Assert(funcBody != nullptr);
  1309. Assert(funcBody->GetDisplayName() != nullptr);
  1310. return funcBody->GetDisplayName();
  1311. }
  1312. virtual const char16* GetDisplayName() const override;
  1313. void SetDisplayName(const char16* displayName);
  1314. virtual void SetDisplayName(const char16* displayName, uint displayNameLength, uint displayShortNameOffset, SetDisplayNameFlags flags = SetDisplayNameFlagsNone) override;
  1315. virtual void Finalize(bool isShutdown) override;
  1316. Var GetCachedSourceString() { return this->GetAuxPtr(AuxPointerType::CachedSourceString); }
  1317. void SetCachedSourceString(Var sourceString)
  1318. {
  1319. Assert(this->GetCachedSourceString() == nullptr);
  1320. this->SetAuxPtr(AuxPointerType::CachedSourceString, sourceString);
  1321. }
  1322. FunctionProxyArray GetNestedFuncArray();
  1323. FunctionProxy* GetNestedFunc(uint index);
  1324. FunctionProxyPtrPtr GetNestedFuncReference(uint index);
  1325. ParseableFunctionInfo* GetNestedFunctionForExecution(uint index);
  1326. void SetNestedFunc(FunctionProxy* nestedFunc, uint index, ulong flags);
  1327. void ClearNestedFunctionParentFunctionReference();
  1328. void SetCapturesThis() { attributes = (Attributes)(attributes | Attributes::CapturesThis); }
  1329. bool GetCapturesThis() { return (attributes & Attributes::CapturesThis) != 0; }
  1330. void BuildDeferredStubs(ParseNode *pnodeFnc);
  1331. DeferredFunctionStub *GetDeferredStubs() const { return static_cast<DeferredFunctionStub *>(this->GetAuxPtr(AuxPointerType::DeferredStubs)); }
  1332. void SetDeferredStubs(DeferredFunctionStub *stub) { this->SetAuxPtr(AuxPointerType::DeferredStubs, stub); }
  1333. void RegisterFuncToDiag(ScriptContext * scriptContext, char16 const * pszTitle);
  1334. protected:
  1335. static HRESULT MapDeferredReparseError(HRESULT& hrParse, const CompileScriptException& se);
  1336. bool m_hasBeenParsed : 1; // Has function body been parsed- true for actual function bodies, false for deferparse
  1337. bool m_isDeclaration : 1;
  1338. bool m_isAccessor : 1; // Function is a property getter or setter
  1339. bool m_isStaticNameFunction : 1;
  1340. bool m_isNamedFunctionExpression : 1;
  1341. bool m_isNameIdentifierRef : 1;
  1342. bool m_isClassMember : 1;
  1343. bool m_isStrictMode : 1;
  1344. bool m_isAsmjsMode : 1;
  1345. bool m_isAsmJsFunction : 1;
  1346. bool m_isGlobalFunc : 1;
  1347. bool m_doBackendArgumentsOptimization :1;
  1348. bool m_isEval : 1; // Source code is in 'eval'
  1349. bool m_isDynamicFunction : 1; // Source code is in 'Function'
  1350. bool m_hasImplicitArgIns : 1;
  1351. bool m_dontInline : 1; // Used by the JIT's inliner
  1352. // Indicates if the function has been reparsed for debug attach/detach scenario.
  1353. bool m_reparsed : 1;
  1354. // This field is not required for deferred parsing but because our thunks can't handle offsets > 128 bytes
  1355. // yet, leaving this here for now. We can look at optimizing the function info and function proxy structures some
  1356. // more and also fix our thunks to handle 8 bit offsets
  1357. NoWriteBarrierField<bool> m_utf8SourceHasBeenSet; // start of UTF8-encoded source
  1358. NoWriteBarrierField<uint> m_sourceIndex; // index into the scriptContext's list of saved sources
  1359. #if DYNAMIC_INTERPRETER_THUNK
  1360. void* m_dynamicInterpreterThunk; // Unique 'thunk' for every interpreted function - used for ETW symbol decoding.
  1361. #endif
  1362. NoWriteBarrierField<uint> m_cbStartOffset; // pUtf8Source is this many bytes from the start of the scriptContext's source buffer.
  1363. // This is generally the same as m_cchStartOffset unless the buffer has a BOM
  1364. #define DEFINE_PARSEABLE_FUNCTION_INFO_FIELDS 1
  1365. #define CURRENT_ACCESS_MODIFIER protected:
  1366. #include "SerializableFunctionFields.h"
  1367. ULONG m_lineNumber;
  1368. ULONG m_columnNumber;
  1369. WriteBarrierPtr<const char16> m_displayName; // Optional name
  1370. uint m_displayNameLength;
  1371. uint m_displayShortNameOffset;
  1372. WriteBarrierPtr<PropertyRecordList> m_boundPropertyRecords;
  1373. WriteBarrierPtr<NestedArray> nestedArray;
  1374. public:
  1375. #if DBG
  1376. bool m_wasEverAsmjsMode; // has m_isAsmjsMode ever been true
  1377. NoWriteBarrierField<Js::LocalFunctionId> deferredParseNextFunctionId;
  1378. #endif
  1379. #if DBG
  1380. NoWriteBarrierField<UINT> scopeObjectSize; // If the scope is an activation object - its size
  1381. #endif
  1382. };
  1383. //
  1384. // Algorithm to retrieve a function body's source name (url). Template supports both
  1385. // local FunctionBody and ScriptDAC (debugging) scenarios.
  1386. //
  1387. template <class T>
  1388. LPCWSTR ParseableFunctionInfo::GetSourceName(const T& sourceContextInfo) const
  1389. {
  1390. return GetSourceName<T>(sourceContextInfo, this->m_isEval, this->m_isDynamicFunction);
  1391. }
  1392. template <class T>
  1393. LPCWSTR ParseableFunctionInfo::GetSourceName(const T& sourceContextInfo, bool m_isEval, bool m_isDynamicFunction)
  1394. {
  1395. if (sourceContextInfo->IsDynamic())
  1396. {
  1397. if (m_isEval)
  1398. {
  1399. return Constants::EvalCode;
  1400. }
  1401. else if (m_isDynamicFunction)
  1402. {
  1403. return Constants::FunctionCode;
  1404. }
  1405. else
  1406. {
  1407. return Constants::UnknownScriptCode;
  1408. }
  1409. }
  1410. else
  1411. {
  1412. return sourceContextInfo->url;
  1413. }
  1414. }
  1415. class FunctionBody : public ParseableFunctionInfo
  1416. {
  1417. DEFINE_VTABLE_CTOR_NO_REGISTER(FunctionBody, ParseableFunctionInfo);
  1418. friend class ByteCodeBufferBuilder;
  1419. friend class ByteCodeBufferReader;
  1420. public:
  1421. // same as MachDouble, used in the Func.h
  1422. static const uint DIAGLOCALSLOTSIZE = 8;
  1423. enum class CounterFields : uint8
  1424. {
  1425. VarCount = 0,
  1426. ConstantCount = 1,
  1427. OutParamMaxDepth = 2,
  1428. ByteCodeCount = 3,
  1429. ByteCodeWithoutLDACount = 4,
  1430. ByteCodeInLoopCount = 5,
  1431. LoopCount = 6,
  1432. InlineCacheCount = 7,
  1433. RootObjectLoadInlineCacheStart = 8,
  1434. RootObjectLoadMethodInlineCacheStart = 9,
  1435. RootObjectStoreInlineCacheStart = 10,
  1436. IsInstInlineCacheCount = 11,
  1437. ReferencedPropertyIdCount = 12,
  1438. ObjLiteralCount = 13,
  1439. LiteralRegexCount = 14,
  1440. InnerScopeCount = 15,
  1441. // Following counters uses ((uint32)-1) as default value
  1442. LocalClosureRegister = 16,
  1443. ParamClosureRegister = 17,
  1444. LocalFrameDisplayRegister = 18,
  1445. EnvRegister = 19,
  1446. ThisRegisterForEventHandler = 20,
  1447. FirstInnerScopeRegister = 21,
  1448. FuncExprScopeRegister = 22,
  1449. FirstTmpRegister = 23,
  1450. // Signed integers need keep the sign when promoting
  1451. SignedFieldsStart = 24,
  1452. SerializationIndex = 24,
  1453. Max
  1454. };
  1455. typedef CompactCounters<FunctionBody> CounterT;
  1456. CounterT counters;
  1457. uint32 GetCountField(FunctionBody::CounterFields fieldEnum) const
  1458. {
  1459. return counters.Get(fieldEnum);
  1460. }
  1461. uint32 SetCountField(FunctionBody::CounterFields fieldEnum, uint32 val)
  1462. {
  1463. return counters.Set(fieldEnum, val, this);
  1464. }
  1465. uint32 IncreaseCountField(FunctionBody::CounterFields fieldEnum)
  1466. {
  1467. return counters.Increase(fieldEnum, this);
  1468. }
  1469. int32 GetCountFieldSigned(FunctionBody::CounterFields fieldEnum) const
  1470. {
  1471. return counters.GetSigned(fieldEnum);
  1472. }
  1473. int32 SetCountFieldSigned(FunctionBody::CounterFields fieldEnum, int32 val)
  1474. {
  1475. return counters.SetSigned(fieldEnum, val, this);
  1476. }
  1477. struct StatementMap
  1478. {
  1479. StatementMap() : isSubexpression(false) {}
  1480. static StatementMap * New(Recycler* recycler)
  1481. {
  1482. return RecyclerNew(recycler, StatementMap);
  1483. }
  1484. regex::Interval sourceSpan;
  1485. regex::Interval byteCodeSpan;
  1486. bool isSubexpression;
  1487. };
  1488. // The type of StatementAdjustmentRecord.
  1489. // A bitmask that can be OR'ed of multiple values of the enum.
  1490. enum StatementAdjustmentType : ushort
  1491. {
  1492. SAT_None = 0,
  1493. // Specifies an adjustment for next statement when going from current to next.
  1494. // Used for transitioning from current stmt to next during normal control-flow,
  1495. // such as offset of Br after if-block when there is else block present,
  1496. // when throw happens inside if and we ignore exceptions (next statement in the list
  1497. // would be 'else' but we need to pass flow control to Br target rather than entering 'else').
  1498. SAT_FromCurrentToNext = 0x01,
  1499. // Specifies an adjustment for beginning of next statement.
  1500. // If there is adjustment record, the statement following it starts at specified offset and not at offset specified in statementMap.
  1501. // Used for set next statement from arbitrary location.
  1502. SAT_NextStatementStart = 0x02,
  1503. SAT_All = SAT_FromCurrentToNext | SAT_NextStatementStart
  1504. };
  1505. class StatementAdjustmentRecord
  1506. {
  1507. uint m_byteCodeOffset;
  1508. StatementAdjustmentType m_adjustmentType;
  1509. public:
  1510. StatementAdjustmentRecord();
  1511. StatementAdjustmentRecord(StatementAdjustmentType type, int byteCodeOffset);
  1512. StatementAdjustmentRecord(const StatementAdjustmentRecord& other);
  1513. uint GetByteCodeOffset();
  1514. StatementAdjustmentType GetAdjustmentType();
  1515. };
  1516. // Offset and entry/exit of a block that must be processed in new interpreter frame rather than current.
  1517. // Used for try and catch blocks.
  1518. class CrossFrameEntryExitRecord
  1519. {
  1520. uint m_byteCodeOffset;
  1521. // true means enter, false means exit.
  1522. bool m_isEnterBlock;
  1523. public:
  1524. CrossFrameEntryExitRecord();
  1525. CrossFrameEntryExitRecord(uint byteCodeOffset, bool isEnterBlock);
  1526. CrossFrameEntryExitRecord(const CrossFrameEntryExitRecord& other);
  1527. uint GetByteCodeOffset() const;
  1528. bool GetIsEnterBlock();
  1529. };
  1530. typedef JsUtil::List<Js::FunctionBody::StatementMap*> StatementMapList;
  1531. // Note: isLeaf = true template param below means that recycler should not be used to dispose the items.
  1532. typedef JsUtil::List<StatementAdjustmentRecord, Recycler, /* isLeaf = */ true> StatementAdjustmentRecordList;
  1533. typedef JsUtil::List<CrossFrameEntryExitRecord, Recycler, /* isLeaf = */ true> CrossFrameEntryExitRecordList;
  1534. // Contains recorded at bytecode generation time information about statements and try-catch blocks.
  1535. // Used by debugger.
  1536. struct AuxStatementData
  1537. {
  1538. // Contains statement adjustment data:
  1539. // For given bytecode, following statement needs an adjustment, see StatementAdjustmentType for details.
  1540. StatementAdjustmentRecordList* m_statementAdjustmentRecords;
  1541. // Contain data about entry/exit of blocks that cause processing in different interpreter stack frame, such as try or catch.
  1542. CrossFrameEntryExitRecordList* m_crossFrameBlockEntryExisRecords;
  1543. AuxStatementData();
  1544. };
  1545. class SourceInfo
  1546. {
  1547. friend class RemoteFunctionBody;
  1548. friend class ByteCodeBufferReader;
  1549. friend class ByteCodeBufferBuilder;
  1550. public:
  1551. SmallSpanSequence * pSpanSequence;
  1552. RegSlot frameDisplayRegister; // this register slot cannot be 0 so we use that sentinel value to indicate invalid
  1553. RegSlot objectRegister; // this register slot cannot be 0 so we use that sentinel value to indicate invalid
  1554. WriteBarrierPtr<ScopeObjectChain> pScopeObjectChain;
  1555. WriteBarrierPtr<ByteBlock> m_probeBackingBlock; // NULL if no Probes, otherwise a copy of the unmodified the byte-codeblock //Delay
  1556. int32 m_probeCount; // The number of installed probes (such as breakpoints).
  1557. // List of bytecode offset for the Branch bytecode.
  1558. WriteBarrierPtr<AuxStatementData> m_auxStatementData;
  1559. SourceInfo():
  1560. frameDisplayRegister(0),
  1561. objectRegister(0),
  1562. pScopeObjectChain(nullptr),
  1563. m_probeBackingBlock(nullptr),
  1564. m_probeCount(0),
  1565. m_auxStatementData(nullptr),
  1566. pSpanSequence(nullptr)
  1567. {
  1568. }
  1569. };
  1570. private:
  1571. WriteBarrierPtr<ByteBlock> byteCodeBlock; // Function byte-code for script functions
  1572. WriteBarrierPtr<FunctionEntryPointList> entryPoints;
  1573. WriteBarrierPtr<Var> m_constTable;
  1574. WriteBarrierPtr<void*> inlineCaches;
  1575. InlineCachePointerArray<PolymorphicInlineCache> polymorphicInlineCaches; // Contains the latest polymorphic inline caches
  1576. WriteBarrierPtr<PropertyId> cacheIdToPropertyIdMap;
  1577. #if DBG
  1578. #define InlineCacheTypeNone 0x00
  1579. #define InlineCacheTypeInlineCache 0x01
  1580. #define InlineCacheTypeIsInst 0x02
  1581. WriteBarrierPtr<byte> m_inlineCacheTypes;
  1582. #endif
  1583. public:
  1584. static DWORD GetAsmJsTotalLoopCountOffset() { return offsetof(FunctionBody, m_asmJsTotalLoopCount); }
  1585. #if DBG
  1586. int m_DEBUG_executionCount; // Count of outstanding on InterpreterStackFrame
  1587. bool m_nativeEntryPointIsInterpreterThunk; // NativeEntry entry point is in fact InterpreterThunk.
  1588. // Set by bgjit in OutOfMemory scenario during codegen.
  1589. #endif
  1590. #if ENABLE_DEBUG_CONFIG_OPTIONS
  1591. NoWriteBarrierField<uint> regAllocStoreCount;
  1592. NoWriteBarrierField<uint> regAllocLoadCount;
  1593. NoWriteBarrierField<uint> callCountStats;
  1594. #endif
  1595. // >>>>>>WARNING! WARNING!<<<<<<<<<<
  1596. //
  1597. // If you add compile-time attributes to this set, be sure to add them to the attributes that are
  1598. // copied in FunctionBody::Clone
  1599. //
  1600. SourceInfo m_sourceInfo; // position of the source
  1601. // Data needed by profiler:
  1602. NoWriteBarrierField<uint> m_uScriptId; // Delay //Script Block it belongs to. This is function no. of the global function created by engine for each block
  1603. #if DBG
  1604. NoWriteBarrierField<int> m_iProfileSession; // Script profile session the meta data of this function is reported to.
  1605. #endif // DEBUG
  1606. // R0 is reserved for the return value, R1 for the root object
  1607. static const RegSlot ReturnValueRegSlot = 0;
  1608. static const RegSlot RootObjectRegSlot = 1;
  1609. static const RegSlot FirstRegSlot = 1;
  1610. // This value be set on the stack (on a particular offset), when the frame value got changed.
  1611. static const int LocalsChangeDirtyValue = 1;
  1612. enum FunctionBodyFlags : byte
  1613. {
  1614. Flags_None = 0x00,
  1615. Flags_StackNestedFunc = 0x01,
  1616. Flags_HasOrParentHasArguments = 0x02,
  1617. Flags_HasTry = 0x04,
  1618. Flags_HasThis = 0x08,
  1619. Flags_NonUserCode = 0x10,
  1620. Flags_HasOnlyThisStatements = 0x20,
  1621. Flags_HasNoExplicitReturnValue = 0x40, // Returns undefined, i.e. has no return statements or return with no expression
  1622. Flags_HasRestParameter = 0x80
  1623. };
  1624. #define DEFINE_FUNCTION_BODY_FIELDS 1
  1625. #define CURRENT_ACCESS_MODIFIER public:
  1626. #include "SerializableFunctionFields.h"
  1627. private:
  1628. bool m_tag : 1; // Used to tag the low bit to prevent possible GC false references
  1629. bool m_nativeEntryPointUsed : 1; // Code might have been generated but not yet used.
  1630. bool hasDoneLoopBodyCodeGen : 1; // Code generated for loop body, but not necessary available to execute yet.
  1631. bool m_isFuncRegistered : 1;
  1632. bool m_isFuncRegisteredToDiag : 1; // Mentions the function's context is registered with diagprobe.
  1633. bool funcEscapes : 1;
  1634. bool m_hasBailoutInstrInJittedCode : 1; // Indicates whether function has bailout instructions. Valid only if hasDoneCodeGen is true
  1635. bool m_pendingLoopHeaderRelease : 1; // Indicates whether loop headers need to be released
  1636. bool hasExecutionDynamicProfileInfo : 1;
  1637. bool cleanedUp: 1;
  1638. bool sourceInfoCleanedUp: 1;
  1639. bool dontRethunkAfterBailout : 1;
  1640. bool disableInlineApply : 1;
  1641. bool disableInlineSpread : 1;
  1642. bool hasHotLoop: 1;
  1643. bool wasCalledFromLoop : 1;
  1644. bool hasNestedLoop : 1;
  1645. bool recentlyBailedOutOfJittedLoopBody : 1;
  1646. bool m_firstFunctionObject: 1;
  1647. bool m_inlineCachesOnFunctionObject: 1;
  1648. // Used for the debug re-parse. Saves state of function on the first parse, and restores it on a reparse. The state below is either dependent on
  1649. // the state of the script context, or on other factors like whether it was defer parsed or not.
  1650. bool m_hasSetIsObject : 1;
  1651. // Used for the debug purpose, this info will be stored (in the non-debug mode), when a function has all locals marked as non-local-referenced.
  1652. // So when we got to no-refresh debug mode, and try to re-use the same function body we can then enforce all locals to be non-local-referenced.
  1653. bool m_hasAllNonLocalReferenced : 1;
  1654. bool m_hasFunExprNameReference : 1;
  1655. bool m_ChildCallsEval : 1;
  1656. bool m_CallsEval : 1;
  1657. bool m_hasReferenceableBuiltInArguments : 1;
  1658. bool m_isParamAndBodyScopeMerged : 1;
  1659. // Used in the debug purpose. This is to avoid setting all locals to non-local-referenced, multiple times for each child function.
  1660. bool m_hasDoneAllNonLocalReferenced : 1;
  1661. // Used by the script profiler, once the function compiled is sent this will be set to true.
  1662. bool m_hasFunctionCompiledSent : 1;
  1663. bool m_isFromNativeCodeModule : 1;
  1664. bool m_isPartialDeserializedFunction : 1;
  1665. bool m_isAsmJsScheduledForFullJIT : 1;
  1666. bool m_hasLocalClosureRegister : 1;
  1667. bool m_hasParamClosureRegister : 1;
  1668. bool m_hasLocalFrameDisplayRegister : 1;
  1669. bool m_hasEnvRegister : 1;
  1670. bool m_hasThisRegisterForEventHandler : 1;
  1671. bool m_hasFirstInnerScopeRegister : 1;
  1672. bool m_hasFuncExprScopeRegister : 1;
  1673. bool m_hasFirstTmpRegister : 1;
  1674. #ifdef PERF_COUNTERS
  1675. bool m_isDeserializedFunction : 1;
  1676. #endif
  1677. #if DBG
  1678. // Indicates that nested functions can be allocated on the stack (but may not be)
  1679. bool m_canDoStackNestedFunc : 1;
  1680. #endif
  1681. #if DBG
  1682. bool initializedExecutionModeAndLimits : 1;
  1683. #endif
  1684. #ifdef IR_VIEWER
  1685. // whether IR Dump is enabled for this function (used by parseIR)
  1686. bool m_isIRDumpEnabled : 1;
  1687. WriteBarrierPtr<Js::DynamicObject> m_irDumpBaseObject;
  1688. #endif /* IR_VIEWER */
  1689. NoWriteBarrierField<uint8> bailOnMisingProfileCount;
  1690. NoWriteBarrierField<uint8> bailOnMisingProfileRejitCount;
  1691. NoWriteBarrierField<byte> inlineDepth; // Used by inlining to avoid recursively inlining functions excessively
  1692. NoWriteBarrierField<ExecutionMode> executionMode;
  1693. NoWriteBarrierField<uint16> interpreterLimit;
  1694. NoWriteBarrierField<uint16> autoProfilingInterpreter0Limit;
  1695. NoWriteBarrierField<uint16> profilingInterpreter0Limit;
  1696. NoWriteBarrierField<uint16> autoProfilingInterpreter1Limit;
  1697. NoWriteBarrierField<uint16> simpleJitLimit;
  1698. NoWriteBarrierField<uint16> profilingInterpreter1Limit;
  1699. NoWriteBarrierField<uint16> fullJitThreshold;
  1700. NoWriteBarrierField<uint16> fullJitRequeueThreshold;
  1701. NoWriteBarrierField<uint16> committedProfiledIterations;
  1702. NoWriteBarrierField<uint> m_depth; // Indicates how many times the function has been entered (so increases by one on each recursive call, decreases by one when we're done)
  1703. uint32 interpretedCount;
  1704. uint32 loopInterpreterLimit;
  1705. uint32 debuggerScopeIndex;
  1706. uint32 savedPolymorphicCacheState;
  1707. // >>>>>>WARNING! WARNING!<<<<<<<<<<
  1708. //
  1709. // If you add compile-time attributes to the above set, be sure to add them to the attributes that are
  1710. // copied in FunctionBody::Clone
  1711. //
  1712. NoWriteBarrierPtr<Js::ByteCodeCache> byteCodeCache; // Not GC allocated so naked pointer
  1713. #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
  1714. static bool shareInlineCaches;
  1715. #endif
  1716. WriteBarrierPtr<FunctionEntryPointInfo> defaultFunctionEntryPointInfo;
  1717. #if ENABLE_PROFILE_INFO
  1718. WriteBarrierPtr<DynamicProfileInfo> dynamicProfileInfo;
  1719. #endif
  1720. // select dynamic profile info saved off when we codegen and later
  1721. // used for rejit decisions (see bailout.cpp)
  1722. NoWriteBarrierField<BYTE> savedInlinerVersion;
  1723. #if ENABLE_NATIVE_CODEGEN
  1724. NoWriteBarrierField<ImplicitCallFlags> savedImplicitCallsFlags;
  1725. #endif
  1726. FunctionBody(ScriptContext* scriptContext, const char16* displayName, uint displayNameLength, uint displayShortNameOffset, uint nestedCount, Utf8SourceInfo* sourceInfo,
  1727. uint uFunctionNumber, uint uScriptId, Js::LocalFunctionId functionId, Js::PropertyRecordList* propRecordList, Attributes attributes
  1728. #ifdef PERF_COUNTERS
  1729. , bool isDeserializedFunction = false
  1730. #endif
  1731. );
  1732. void SetNativeEntryPoint(FunctionEntryPointInfo* entryPointInfo, JavascriptMethod originalEntryPoint, Var directEntryPoint);
  1733. #if DYNAMIC_INTERPRETER_THUNK
  1734. void GenerateDynamicInterpreterThunk();
  1735. #endif
  1736. void CloneByteCodeInto(ScriptContext * scriptContext, FunctionBody *newFunctionBody, uint sourceIndex);
  1737. void * GetEntryPoint(ProxyEntryPointInfo* entryPoint) const { return entryPoint->address; }
  1738. void CaptureDynamicProfileState(FunctionEntryPointInfo* entryPointInfo);
  1739. #if ENABLE_DEBUG_CONFIG_OPTIONS
  1740. void DumpRegStats(FunctionBody *funcBody);
  1741. #endif
  1742. public:
  1743. FunctionBody(ByteCodeCache* cache, Utf8SourceInfo* sourceInfo, ScriptContext* scriptContext):
  1744. ParseableFunctionInfo((JavascriptMethod) nullptr, 0, (LocalFunctionId) 0, sourceInfo, scriptContext, 0, nullptr, 0, 0, None, nullptr)
  1745. {
  1746. // Dummy constructor- does nothing
  1747. // Must be stack allocated
  1748. // Used during deferred bytecode serialization
  1749. }
  1750. static FunctionBody * NewFromRecycler(Js::ScriptContext * scriptContext, const char16 * displayName, uint displayNameLength, uint displayShortNameOffset, uint nestedCount,
  1751. Utf8SourceInfo* sourceInfo, uint uScriptId, Js::LocalFunctionId functionId, Js::PropertyRecordList* boundPropertyRecords, Attributes attributes
  1752. #ifdef PERF_COUNTERS
  1753. , bool isDeserializedFunction
  1754. #endif
  1755. );
  1756. static FunctionBody * NewFromRecycler(Js::ScriptContext * scriptContext, const char16 * displayName, uint displayNameLength, uint displayShortNameOffset, uint nestedCount,
  1757. Utf8SourceInfo* sourceInfo, uint uFunctionNumber, uint uScriptId, Js::LocalFunctionId functionId, Js::PropertyRecordList* boundPropertyRecords, Attributes attributes
  1758. #ifdef PERF_COUNTERS
  1759. , bool isDeserializedFunction
  1760. #endif
  1761. );
  1762. FunctionEntryPointInfo * GetEntryPointInfo(int index) const;
  1763. FunctionEntryPointInfo * TryGetEntryPointInfo(int index) const;
  1764. Js::RootObjectBase * LoadRootObject() const;
  1765. Js::RootObjectBase * GetRootObject() const;
  1766. ByteBlock* GetAuxiliaryData() const { return static_cast<ByteBlock*>(this->GetAuxPtr(AuxPointerType::AuxBlock)); }
  1767. ByteBlock* GetAuxiliaryDataWithLock() const { return static_cast<ByteBlock*>(this->GetAuxPtrWithLock(AuxPointerType::AuxBlock)); }
  1768. void SetAuxiliaryData(ByteBlock* auxBlock) { this->SetAuxPtr(AuxPointerType::AuxBlock, auxBlock); }
  1769. ByteBlock* GetAuxiliaryContextData()const { return static_cast<ByteBlock*>(this->GetAuxPtr(AuxPointerType::AuxContextBlock)); }
  1770. ByteBlock* GetAuxiliaryContextDataWithLock()const { return static_cast<ByteBlock*>(this->GetAuxPtrWithLock(AuxPointerType::AuxContextBlock)); }
  1771. void SetAuxiliaryContextData(ByteBlock* auxContextBlock) { this->SetAuxPtr(AuxPointerType::AuxContextBlock, auxContextBlock); }
  1772. ByteBlock* GetByteCode();
  1773. ByteBlock* GetOriginalByteCode(); // Returns original bytecode without probes (such as BPs).
  1774. Js::ByteCodeCache * GetByteCodeCache() const { return this->byteCodeCache; }
  1775. void SetByteCodeCache(Js::ByteCodeCache *byteCodeCache)
  1776. {
  1777. if (byteCodeCache != nullptr)
  1778. {
  1779. this->byteCodeCache = byteCodeCache;
  1780. }
  1781. }
  1782. void SetSerializationIndex(int index);
  1783. const int GetSerializationIndex() const;
  1784. uint GetByteCodeCount() const { return GetCountField(CounterFields::ByteCodeCount); }
  1785. void SetByteCodeCount(uint count) { SetCountField(CounterFields::ByteCodeCount, count); }
  1786. uint GetByteCodeWithoutLDACount() const { return GetCountField(CounterFields::ByteCodeWithoutLDACount); }
  1787. void SetByteCodeWithoutLDACount(uint count) { SetCountField(CounterFields::ByteCodeWithoutLDACount, count); }
  1788. uint GetByteCodeInLoopCount() const { return GetCountField(CounterFields::ByteCodeInLoopCount); }
  1789. void SetByteCodeInLoopCount(uint count) { SetCountField(CounterFields::ByteCodeInLoopCount, count); }
  1790. uint16 GetEnvDepth() const { return m_envDepth; }
  1791. void SetEnvDepth(uint16 depth) { m_envDepth = depth; }
  1792. void SetEnvRegister(RegSlot reg);
  1793. void MapAndSetEnvRegister(RegSlot reg);
  1794. RegSlot GetEnvRegister() const;
  1795. void SetThisRegisterForEventHandler(RegSlot reg);
  1796. void MapAndSetThisRegisterForEventHandler(RegSlot reg);
  1797. RegSlot GetThisRegisterForEventHandler() const;
  1798. void SetLocalClosureRegister(RegSlot reg);
  1799. void MapAndSetLocalClosureRegister(RegSlot reg);
  1800. RegSlot GetLocalClosureRegister() const;
  1801. void SetParamClosureRegister(RegSlot reg);
  1802. void MapAndSetParamClosureRegister(RegSlot reg);
  1803. RegSlot GetParamClosureRegister() const;
  1804. void SetLocalFrameDisplayRegister(RegSlot reg);
  1805. void MapAndSetLocalFrameDisplayRegister(RegSlot reg);
  1806. RegSlot GetLocalFrameDisplayRegister() const;
  1807. void SetFirstInnerScopeRegister(RegSlot reg);
  1808. void MapAndSetFirstInnerScopeRegister(RegSlot reg);
  1809. RegSlot GetFirstInnerScopeRegister() const;
  1810. void SetFuncExprScopeRegister(RegSlot reg);
  1811. void MapAndSetFuncExprScopeRegister(RegSlot reg);
  1812. RegSlot GetFuncExprScopeRegister() const;
  1813. bool HasScopeObject() const { return hasScopeObject; }
  1814. void SetHasScopeObject(bool has) { hasScopeObject = has; }
  1815. uint GetInnerScopeCount() const { return GetCountField(CounterFields::InnerScopeCount); }
  1816. void SetInnerScopeCount(uint count) { SetCountField(CounterFields::InnerScopeCount, count); }
  1817. bool HasCachedScopePropIds() const { return hasCachedScopePropIds; }
  1818. void SetHasCachedScopePropIds(bool has) { hasCachedScopePropIds = has; }
  1819. uint32 GetInterpretedCount() const { return interpretedCount; }
  1820. uint32 SetInterpretedCount(uint32 val) { return interpretedCount = val; }
  1821. uint32 IncreaseInterpretedCount() { return interpretedCount++; }
  1822. uint32 GetLoopInterpreterLimit() const { return loopInterpreterLimit; }
  1823. uint32 SetLoopInterpreterLimit(uint32 val) { return loopInterpreterLimit = val; }
  1824. // Gets the next index for tracking debugger scopes (increments the internal counter as well).
  1825. uint32 GetNextDebuggerScopeIndex() { return debuggerScopeIndex++; }
  1826. void SetDebuggerScopeIndex(uint32 index) { debuggerScopeIndex = index; }
  1827. size_t GetLoopBodyName(uint loopNumber, _Out_writes_opt_z_(sizeInChars) WCHAR* displayName, _In_ size_t sizeInChars);
  1828. void AllocateLoopHeaders();
  1829. void ReleaseLoopHeaders();
  1830. Js::LoopHeader * GetLoopHeader(uint index) const;
  1831. Js::LoopHeader * GetLoopHeaderWithLock(uint index) const;
  1832. Js::Var GetLoopHeaderArrayPtr() const
  1833. {
  1834. Assert(this->GetLoopHeaderArray() != nullptr);
  1835. return this->GetLoopHeaderArray();
  1836. }
  1837. #ifndef TEMP_DISABLE_ASMJS
  1838. void SetIsAsmJsFullJitScheduled(bool val){ m_isAsmJsScheduledForFullJIT = val; }
  1839. bool GetIsAsmJsFullJitScheduled(){ return m_isAsmJsScheduledForFullJIT; }
  1840. uint32 GetAsmJSTotalLoopCount() const
  1841. {
  1842. return m_asmJsTotalLoopCount;
  1843. }
  1844. void SetIsAsmJsFunction(bool isAsmJsFunction)
  1845. {
  1846. m_isAsmJsFunction = isAsmJsFunction;
  1847. }
  1848. #endif
  1849. const bool GetIsAsmJsFunction() const
  1850. {
  1851. return m_isAsmJsFunction;
  1852. }
  1853. #ifndef TEMP_DISABLE_ASMJS
  1854. bool IsHotAsmJsLoop()
  1855. {
  1856. // Negative MinTemplatizedJitLoopRunCount treats all loops as hot asm loop
  1857. if (CONFIG_FLAG(MinTemplatizedJitLoopRunCount) < 0 || m_asmJsTotalLoopCount > static_cast<uint>(CONFIG_FLAG(MinTemplatizedJitLoopRunCount)))
  1858. {
  1859. return true;
  1860. }
  1861. return false;
  1862. }
  1863. #endif
  1864. private:
  1865. void ResetLoops();
  1866. public:
  1867. static bool Is(void* ptr);
  1868. uint GetScriptId() const { return m_uScriptId; }
  1869. void* GetAddressOfScriptId() const
  1870. {
  1871. return (void*)&m_uScriptId;
  1872. }
  1873. uint8 *GetCallsCountAddress(EntryPointInfo* info) const
  1874. {
  1875. FunctionEntryPointInfo* entryPoint = (FunctionEntryPointInfo*) info;
  1876. return &entryPoint->callsCount;
  1877. }
  1878. FunctionEntryPointInfo* GetDefaultFunctionEntryPointInfo() const;
  1879. void SetDefaultFunctionEntryPointInfo(FunctionEntryPointInfo* entryPointInfo, const JavascriptMethod originalEntryPoint);
  1880. FunctionEntryPointInfo *GetSimpleJitEntryPointInfo() const;
  1881. void SetSimpleJitEntryPointInfo(FunctionEntryPointInfo *const entryPointInfo);
  1882. private:
  1883. void VerifyExecutionMode(const ExecutionMode executionMode) const;
  1884. public:
  1885. ExecutionMode GetDefaultInterpreterExecutionMode() const;
  1886. ExecutionMode GetExecutionMode() const;
  1887. ExecutionMode GetInterpreterExecutionMode(const bool isPostBailout);
  1888. void SetExecutionMode(const ExecutionMode executionMode);
  1889. private:
  1890. bool IsInterpreterExecutionMode() const;
  1891. public:
  1892. bool TryTransitionToNextExecutionMode();
  1893. void TryTransitionToNextInterpreterExecutionMode();
  1894. void SetIsSpeculativeJitCandidate();
  1895. bool TryTransitionToJitExecutionMode();
  1896. void TransitionToSimpleJitExecutionMode();
  1897. void TransitionToFullJitExecutionMode();
  1898. private:
  1899. void VerifyExecutionModeLimits();
  1900. void InitializeExecutionModeAndLimits();
  1901. public:
  1902. void ReinitializeExecutionModeAndLimits();
  1903. private:
  1904. void SetFullJitThreshold(const uint16 newFullJitThreshold, const bool skipSimpleJit = false);
  1905. void CommitExecutedIterations();
  1906. void CommitExecutedIterations(uint16 &limit, const uint executedIterations);
  1907. private:
  1908. uint16 GetSimpleJitExecutedIterations() const;
  1909. public:
  1910. void ResetSimpleJitLimitAndCallCount();
  1911. private:
  1912. void SetSimpleJitCallCount(const uint16 simpleJitLimit) const;
  1913. void ResetSimpleJitCallCount();
  1914. public:
  1915. uint16 GetProfiledIterations() const;
  1916. public:
  1917. void OnFullJitDequeued(const FunctionEntryPointInfo *const entryPointInfo);
  1918. public:
  1919. void TraceExecutionMode(const char *const eventDescription = nullptr) const;
  1920. void TraceInterpreterExecutionMode() const;
  1921. private:
  1922. void DoTraceExecutionMode(const char *const eventDescription) const;
  1923. public:
  1924. static bool IsNewSimpleJit();
  1925. bool DoSimpleJit() const;
  1926. bool DoSimpleJitDynamicProfile() const;
  1927. private:
  1928. bool DoInterpreterProfile() const;
  1929. bool DoInterpreterAutoProfile() const;
  1930. public:
  1931. bool WasCalledFromLoop() const;
  1932. void SetWasCalledFromLoop();
  1933. public:
  1934. bool RecentlyBailedOutOfJittedLoopBody() const;
  1935. void SetRecentlyBailedOutOfJittedLoopBody(const bool value);
  1936. private:
  1937. static uint16 GetMinProfileIterations();
  1938. public:
  1939. static uint16 GetMinFunctionProfileIterations();
  1940. private:
  1941. static uint GetMinLoopProfileIterations(const uint loopInterpreterLimit);
  1942. public:
  1943. uint GetLoopProfileThreshold(const uint loopInterpreterLimit) const;
  1944. private:
  1945. static uint GetReducedLoopInterpretCount();
  1946. public:
  1947. uint GetLoopInterpretCount(LoopHeader* loopHeader) const;
  1948. private:
  1949. static bool DoObjectHeaderInlining();
  1950. static bool DoObjectHeaderInliningForConstructors();
  1951. public:
  1952. static bool DoObjectHeaderInliningForConstructor(const uint32 inlineSlotCapacity);
  1953. private:
  1954. static bool DoObjectHeaderInliningForObjectLiterals();
  1955. public:
  1956. static bool DoObjectHeaderInliningForObjectLiteral(const uint32 inlineSlotCapacity);
  1957. static bool DoObjectHeaderInliningForObjectLiteral(const PropertyIdArray *const propIds, ScriptContext *const scriptContext);
  1958. static bool DoObjectHeaderInliningForEmptyObjects();
  1959. public:
  1960. #if DBG
  1961. int GetProfileSession() { return m_iProfileSession; }
  1962. #endif
  1963. virtual void Finalize(bool isShutdown) override;
  1964. void Cleanup(bool isScriptContextClosing);
  1965. void CleanupSourceInfo(bool isScriptContextClosing);
  1966. template<bool IsScriptContextShutdown>
  1967. void CleanUpInlineCaches();
  1968. void CleanupRecyclerData(bool isRecyclerShutdown, bool doEntryPointCleanupCaptureStack);
  1969. #ifdef PERF_COUNTERS
  1970. void CleanupPerfCounter();
  1971. #endif
  1972. virtual void Dispose(bool isShutdown) override { }
  1973. bool HasRejit() const
  1974. {
  1975. if(this->entryPoints)
  1976. {
  1977. return this->entryPoints->Count() > 1;
  1978. }
  1979. return false;
  1980. }
  1981. #pragma region SourceInfo Methods
  1982. void CopySourceInfo(ParseableFunctionInfo* originalFunctionInfo);
  1983. void FinishSourceInfo();
  1984. RegSlot GetFrameDisplayRegister() const;
  1985. void SetFrameDisplayRegister(RegSlot frameDisplayRegister);
  1986. RegSlot GetObjectRegister() const;
  1987. void SetObjectRegister(RegSlot objectRegister);
  1988. bool HasObjectRegister() const { return GetObjectRegister() != 0; }
  1989. ScopeObjectChain *GetScopeObjectChain() const;
  1990. void SetScopeObjectChain(ScopeObjectChain *pScopeObjectChain);
  1991. // fetch the Catch scope object which encloses the passed bytecode offset, returns NULL otherwise
  1992. Js::DebuggerScope * GetDiagCatchScopeObjectAt(int byteCodeOffset);
  1993. ByteBlock *GetProbeBackingBlock();
  1994. void SetProbeBackingBlock(ByteBlock* probeBackingBlock);
  1995. bool HasLineBreak() const;
  1996. bool HasLineBreak(charcount_t start, charcount_t end) const;
  1997. bool HasGeneratedFromByteCodeCache() const { return this->byteCodeCache != nullptr; }
  1998. bool EndsAfter(size_t offset) const;
  1999. void TrackLoad(int ichMin);
  2000. SmallSpanSequence* GetStatementMapSpanSequence() const { return m_sourceInfo.pSpanSequence; }
  2001. void RecordStatementMap(StatementMap* statementMap);
  2002. void RecordStatementMap(SmallSpanSequenceIter &iter, StatementData * data);
  2003. void RecordLoad(int ichMin, int bytecodeAfterLoad);
  2004. DebuggerScope* RecordStartScopeObject(DiagExtraScopesType scopeType, int start, RegSlot scopeLocation, int* index = nullptr);
  2005. void RecordEndScopeObject(DebuggerScope* currentScope, int end);
  2006. DebuggerScope* AddScopeObject(DiagExtraScopesType scopeType, int start, RegSlot scopeLocation);
  2007. bool TryGetDebuggerScopeAt(int index, DebuggerScope*& debuggerScope);
  2008. StatementMapList * GetStatementMaps() const { return static_cast<StatementMapList *>(this->GetAuxPtrWithLock(AuxPointerType::StatementMaps)); }
  2009. void SetStatementMaps(StatementMapList *pStatementMaps) { this->SetAuxPtr(AuxPointerType::StatementMaps, pStatementMaps); }
  2010. FunctionCodeGenRuntimeData ** GetCodeGenGetSetRuntimeData() const { return static_cast<FunctionCodeGenRuntimeData**>(this->GetAuxPtr(AuxPointerType::CodeGenGetSetRuntimeData)); }
  2011. FunctionCodeGenRuntimeData ** GetCodeGenGetSetRuntimeDataWithLock() const { return static_cast<FunctionCodeGenRuntimeData**>(this->GetAuxPtrWithLock(AuxPointerType::CodeGenGetSetRuntimeData)); }
  2012. void SetCodeGenGetSetRuntimeData(FunctionCodeGenRuntimeData** codeGenGetSetRuntimeData) { this->SetAuxPtr(AuxPointerType::CodeGenGetSetRuntimeData, codeGenGetSetRuntimeData); }
  2013. FunctionCodeGenRuntimeData ** GetCodeGenRuntimeData() const { return static_cast<FunctionCodeGenRuntimeData**>(this->GetAuxPtr(AuxPointerType::CodeGenRuntimeData)); }
  2014. FunctionCodeGenRuntimeData ** GetCodeGenRuntimeDataWithLock() const { return static_cast<FunctionCodeGenRuntimeData**>(this->GetAuxPtrWithLock(AuxPointerType::CodeGenRuntimeData)); }
  2015. void SetCodeGenRuntimeData(FunctionCodeGenRuntimeData** codeGenRuntimeData) { this->SetAuxPtr(AuxPointerType::CodeGenRuntimeData, codeGenRuntimeData); }
  2016. static StatementMap * GetNextNonSubexpressionStatementMap(StatementMapList *statementMapList, int & startingAtIndex);
  2017. static StatementMap * GetPrevNonSubexpressionStatementMap(StatementMapList *statementMapList, int & startingAtIndex);
  2018. void RecordStatementAdjustment(uint offset, StatementAdjustmentType adjType);
  2019. void RecordCrossFrameEntryExitRecord(uint byteCodeOffset, bool isEnterBlock);
  2020. // Find out an offset falls within the range. returns TRUE if found.
  2021. BOOL GetBranchOffsetWithin(uint start, uint end, StatementAdjustmentRecord* record);
  2022. bool GetLineCharOffset(int byteCodeOffset, ULONG* line, LONG* charOffset, bool canAllocateLineCache = true);
  2023. bool GetLineCharOffsetFromStartChar(int startCharOfStatement, ULONG* _line, LONG* _charOffset, bool canAllocateLineCache = true);
  2024. // Given bytecode position, returns the start position of the statement and length of the statement.
  2025. bool GetStatementIndexAndLengthAt(int byteCodeOffset, UINT32* statementIndex, UINT32* statementLength);
  2026. // skip any utf-8/utf-16 byte-order-mark. Returns the number of chars skipped.
  2027. static charcount_t SkipByteOrderMark(__in_bcount_z(4) LPCUTF8& documentStart)
  2028. {
  2029. charcount_t retValue = 0;
  2030. Assert(documentStart != nullptr);
  2031. if (documentStart[0] == 0xEF &&
  2032. documentStart[1] == 0xBB &&
  2033. documentStart[2] == 0xBF)
  2034. {
  2035. // UTF-8 - EF BB BF
  2036. // 3 bytes skipped - reports one char skipped
  2037. documentStart += 3;
  2038. retValue = 1;
  2039. }
  2040. else if ((documentStart[0] == 0xFF && documentStart[1] == 0xFE) ||
  2041. (documentStart[0] == 0xFE && documentStart[1] == 0xFF))
  2042. {
  2043. // UTF-16 LE - FF FE
  2044. // UTF-16 BE - FE FF
  2045. // 2 bytes skipped - reports one char skipped
  2046. documentStart += 2;
  2047. retValue = 1;
  2048. }
  2049. return retValue;
  2050. }
  2051. StatementMap* GetMatchingStatementMapFromByteCode(int byteCodeOffset, bool ignoreSubexpressions = false);
  2052. int GetEnclosingStatementIndexFromByteCode(int byteCodeOffset, bool ignoreSubexpressions = false);
  2053. StatementMap* GetEnclosingStatementMapFromByteCode(int byteCodeOffset, bool ignoreSubexpressions = false);
  2054. StatementMap* GetMatchingStatementMapFromSource(int byteCodeOffset, int* pMapIndex = nullptr);
  2055. void RecordFrameDisplayRegister(RegSlot slot);
  2056. void RecordObjectRegister(RegSlot slot);
  2057. CrossFrameEntryExitRecordList* GetCrossFrameEntryExitRecords();
  2058. #ifdef VTUNE_PROFILING
  2059. uint GetStartOffset(uint statementIndex) const;
  2060. ULONG GetSourceLineNumber(uint statementIndex);
  2061. #endif
  2062. #pragma endregion
  2063. // Field accessors
  2064. bool GetHasBailoutInstrInJittedCode() const { return this->m_hasBailoutInstrInJittedCode; }
  2065. void SetHasBailoutInstrInJittedCode(bool hasBailout) { this->m_hasBailoutInstrInJittedCode = hasBailout; }
  2066. bool GetCanReleaseLoopHeaders() const { return (this->m_depth == 0); }
  2067. void SetPendingLoopHeaderRelease(bool pendingLoopHeaderRelease) { this->m_pendingLoopHeaderRelease = pendingLoopHeaderRelease; }
  2068. bool GetIsFromNativeCodeModule() const { return m_isFromNativeCodeModule; }
  2069. void SetIsFromNativeCodeModule(bool isFromNativeCodeModule) { m_isFromNativeCodeModule = isFromNativeCodeModule; }
  2070. uint GetLoopNumber(LoopHeader const * loopHeader) const;
  2071. uint GetLoopNumberWithLock(LoopHeader const * loopHeader) const;
  2072. bool GetHasAllocatedLoopHeaders() { return this->GetLoopHeaderArray() != nullptr; }
  2073. Js::LoopHeader* GetLoopHeaderArray() const { return static_cast<Js::LoopHeader*>(this->GetAuxPtr(AuxPointerType::LoopHeaderArray)); }
  2074. Js::LoopHeader* GetLoopHeaderArrayWithLock() const { return static_cast<Js::LoopHeader*>(this->GetAuxPtrWithLock(AuxPointerType::LoopHeaderArray)); }
  2075. void SetLoopHeaderArray(Js::LoopHeader* loopHeaderArray) { this->SetAuxPtr(AuxPointerType::LoopHeaderArray, loopHeaderArray); }
  2076. #if ENABLE_NATIVE_CODEGEN
  2077. Js::JavascriptMethod GetLoopBodyEntryPoint(Js::LoopHeader * loopHeader, int entryPointIndex);
  2078. void SetLoopBodyEntryPoint(Js::LoopHeader * loopHeader, EntryPointInfo* entryPointInfo, Js::JavascriptMethod entryPoint);
  2079. #endif
  2080. void RestoreOldDefaultEntryPoint(FunctionEntryPointInfo* oldEntryPoint, JavascriptMethod oldOriginalEntryPoint, FunctionEntryPointInfo* newEntryPoint);
  2081. FunctionEntryPointInfo* CreateNewDefaultEntryPoint();
  2082. void AddEntryPointToEntryPointList(FunctionEntryPointInfo* entryPoint);
  2083. // Kind of entry point for original entry point
  2084. BOOL IsInterpreterThunk() const;
  2085. BOOL IsDynamicInterpreterThunk() const;
  2086. BOOL IsNativeOriginalEntryPoint() const;
  2087. bool IsSimpleJitOriginalEntryPoint() const;
  2088. #if DYNAMIC_INTERPRETER_THUNK
  2089. static BYTE GetOffsetOfDynamicInterpreterThunk() { return offsetof(FunctionBody, m_dynamicInterpreterThunk); }
  2090. void* GetDynamicInterpreterEntryPoint() const
  2091. {
  2092. return m_dynamicInterpreterThunk;
  2093. }
  2094. bool HasInterpreterThunkGenerated() const
  2095. {
  2096. return m_dynamicInterpreterThunk != nullptr;
  2097. }
  2098. DWORD GetDynamicInterpreterThunkSize() const;
  2099. #endif
  2100. bool GetHasHotLoop() const { return hasHotLoop; };
  2101. void SetHasHotLoop();
  2102. bool GetHasNestedLoop() const { return hasNestedLoop; };
  2103. void SetHasNestedLoop(bool nest) { hasNestedLoop = nest; };
  2104. bool IsInlineApplyDisabled();
  2105. void InitDisableInlineApply();
  2106. void SetDisableInlineApply(bool set);
  2107. bool IsInlineSpreadDisabled() const { return disableInlineSpread; }
  2108. void InitDisableInlineSpread() { disableInlineSpread = this->functionId != Js::Constants::NoFunctionId && PHASE_OFF(Js::InlinePhase, this); }
  2109. void SetDisableInlineSpread(bool set) { disableInlineSpread = set; }
  2110. bool CheckCalleeContextForInlining(FunctionProxy* calleeFunctionProxy);
  2111. #if DBG
  2112. bool HasValidSourceInfo();
  2113. #endif
  2114. #if DYNAMIC_INTERPRETER_THUNK
  2115. JavascriptMethod EnsureDynamicInterpreterThunk(FunctionEntryPointInfo* entryPointInfo);
  2116. #endif
  2117. void SetCheckCodeGenEntryPoint(FunctionEntryPointInfo* entryPointInfo, JavascriptMethod entryPoint);
  2118. #if ENABLE_NATIVE_CODEGEN
  2119. typedef void (*SetNativeEntryPointFuncType)(FunctionEntryPointInfo* entryPointInfo, Js::FunctionBody * functionBody, Js::JavascriptMethod entryPoint);
  2120. static void DefaultSetNativeEntryPoint(FunctionEntryPointInfo* entryPointInfo, FunctionBody * functionBody, JavascriptMethod entryPoint);
  2121. static void ProfileSetNativeEntryPoint(FunctionEntryPointInfo* entryPointInfo, FunctionBody * functionBody, JavascriptMethod entryPoint);
  2122. bool GetNativeEntryPointUsed() const { return m_nativeEntryPointUsed; }
  2123. void SetNativeEntryPointUsed(bool nativeEntryPointUsed) { this->m_nativeEntryPointUsed = nativeEntryPointUsed; }
  2124. #endif
  2125. bool GetIsFuncRegistered() { return m_isFuncRegistered; }
  2126. void SetIsFuncRegistered(bool isRegistered) { m_isFuncRegistered = isRegistered; }
  2127. bool GetHasLoops() const { return this->GetLoopCount() != 0; }
  2128. uint IncrLoopCount() { return this->IncreaseCountField(CounterFields::LoopCount); }
  2129. uint GetLoopCount() const { return this->GetCountField(CounterFields::LoopCount); }
  2130. uint SetLoopCount(uint count) { return this->SetCountField(CounterFields::LoopCount, count); }
  2131. bool AllocProfiledDivOrRem(ProfileId* profileId) { if (this->profiledDivOrRemCount != Constants::NoProfileId) { *profileId = this->profiledDivOrRemCount++; return true; } return false; }
  2132. ProfileId GetProfiledDivOrRemCount() { return this->profiledDivOrRemCount; }
  2133. bool AllocProfiledSwitch(ProfileId* profileId) { if (this->profiledSwitchCount != Constants::NoProfileId) { *profileId = this->profiledSwitchCount++; return true; } return false; }
  2134. ProfileId GetProfiledSwitchCount() { return this->profiledSwitchCount; }
  2135. bool AllocProfiledCallSiteId(ProfileId* profileId) { if (this->profiledCallSiteCount != Constants::NoProfileId) { *profileId = this->profiledCallSiteCount++; return true; } return false; }
  2136. ProfileId GetProfiledCallSiteCount() const { return this->profiledCallSiteCount; }
  2137. void SetProfiledCallSiteCount(ProfileId callSiteId) { this->profiledCallSiteCount = callSiteId; }
  2138. bool AllocProfiledArrayCallSiteId(ProfileId* profileId) { if (this->profiledArrayCallSiteCount != Constants::NoProfileId) { *profileId = this->profiledArrayCallSiteCount++; return true; } return false; }
  2139. ProfileId GetProfiledArrayCallSiteCount() const { return this->profiledArrayCallSiteCount; }
  2140. bool AllocProfiledReturnTypeId(ProfileId* profileId) { if (this->profiledReturnTypeCount != Constants::NoProfileId) { *profileId = this->profiledReturnTypeCount++; return true; } return false; }
  2141. ProfileId GetProfiledReturnTypeCount() const { return this->profiledReturnTypeCount; }
  2142. bool AllocProfiledSlotId(ProfileId* profileId) { if (this->profiledSlotCount != Constants::NoProfileId) { *profileId = this->profiledSlotCount++; return true; } return false; }
  2143. ProfileId GetProfiledSlotCount() const { return this->profiledSlotCount; }
  2144. ProfileId AllocProfiledLdElemId(ProfileId* profileId) { if (this->profiledLdElemCount != Constants::NoProfileId) { *profileId = this->profiledLdElemCount++; return true; } return false; }
  2145. ProfileId GetProfiledLdElemCount() const { return this->profiledLdElemCount; }
  2146. bool AllocProfiledStElemId(ProfileId* profileId) { if (this->profiledStElemCount != Constants::NoProfileId) { *profileId = this->profiledStElemCount++; return true; } return false; }
  2147. ProfileId GetProfiledStElemCount() const { return this->profiledStElemCount; }
  2148. uint GetProfiledFldCount() const { return this->GetInlineCacheCount(); }
  2149. ArgSlot GetProfiledInParamsCount() const { return this->GetInParamsCount() > 1? this->GetInParamsCount() - 1 : 0; }
  2150. bool IsPartialDeserializedFunction() { return this->m_isPartialDeserializedFunction; }
  2151. #ifdef PERF_COUNTERS
  2152. bool IsDeserializedFunction() { return this->m_isDeserializedFunction; }
  2153. #endif
  2154. #ifdef IR_VIEWER
  2155. bool IsIRDumpEnabled() const { return this->m_isIRDumpEnabled; }
  2156. void SetIRDumpEnabled(bool enabled) { this->m_isIRDumpEnabled = enabled; }
  2157. Js::DynamicObject * GetIRDumpBaseObject();
  2158. #endif /* IR_VIEWER */
  2159. #if ENABLE_NATIVE_CODEGEN
  2160. void SetPolymorphicCallSiteInfoHead(PolymorphicCallSiteInfo *polyCallSiteInfo) { this->SetAuxPtr(AuxPointerType::PolymorphicCallSiteInfoHead, polyCallSiteInfo); }
  2161. PolymorphicCallSiteInfo * GetPolymorphicCallSiteInfoHead() { return static_cast<PolymorphicCallSiteInfo *>(this->GetAuxPtr(AuxPointerType::PolymorphicCallSiteInfoHead)); }
  2162. #endif
  2163. PolymorphicInlineCache * GetPolymorphicInlineCachesHead() { return static_cast<PolymorphicInlineCache *>(this->GetAuxPtr(AuxPointerType::PolymorphicInlineCachesHead)); }
  2164. void SetPolymorphicInlineCachesHead(PolymorphicInlineCache * cache) { this->SetAuxPtr(AuxPointerType::PolymorphicInlineCachesHead, cache); }
  2165. bool PolyInliningUsingFixedMethodsAllowedByConfigFlags(FunctionBody* topFunctionBody)
  2166. {
  2167. return !PHASE_OFF(Js::InlinePhase, this) && !PHASE_OFF(Js::InlinePhase, topFunctionBody) &&
  2168. !PHASE_OFF(Js::PolymorphicInlinePhase, this) && !PHASE_OFF(Js::PolymorphicInlinePhase, topFunctionBody) &&
  2169. !PHASE_OFF(Js::FixedMethodsPhase, this) && !PHASE_OFF(Js::FixedMethodsPhase, topFunctionBody) &&
  2170. !PHASE_OFF(Js::PolymorphicInlineFixedMethodsPhase, this) && !PHASE_OFF(Js::PolymorphicInlineFixedMethodsPhase, topFunctionBody);
  2171. }
  2172. void SetScopeSlotArraySizes(uint scopeSlotCount, uint scopeSlotCountForParamScope)
  2173. {
  2174. this->scopeSlotArraySize = scopeSlotCount;
  2175. this->paramScopeSlotArraySize = scopeSlotCountForParamScope;
  2176. }
  2177. Js::PropertyId * GetPropertyIdsForScopeSlotArray() const { return static_cast<Js::PropertyId *>(this->GetAuxPtr(AuxPointerType::PropertyIdsForScopeSlotArray)); }
  2178. void SetPropertyIdsForScopeSlotArray(Js::PropertyId * propertyIdsForScopeSlotArray, uint scopeSlotCount, uint scopeSlotCountForParamScope = 0)
  2179. {
  2180. SetScopeSlotArraySizes(scopeSlotCount, scopeSlotCountForParamScope);
  2181. this->SetAuxPtr(AuxPointerType::PropertyIdsForScopeSlotArray, propertyIdsForScopeSlotArray);
  2182. }
  2183. Js::PropertyIdOnRegSlotsContainer * GetPropertyIdOnRegSlotsContainer() const
  2184. {
  2185. return static_cast<Js::PropertyIdOnRegSlotsContainer *>(this->GetAuxPtr(AuxPointerType::PropertyIdOnRegSlotsContainer));
  2186. }
  2187. Js::PropertyIdOnRegSlotsContainer * GetPropertyIdOnRegSlotsContainerWithLock() const
  2188. {
  2189. return static_cast<Js::PropertyIdOnRegSlotsContainer *>(this->GetAuxPtrWithLock(AuxPointerType::PropertyIdOnRegSlotsContainer));
  2190. }
  2191. void SetPropertyIdOnRegSlotsContainer(Js::PropertyIdOnRegSlotsContainer *propertyIdOnRegSlotsContainer)
  2192. {
  2193. this->SetAuxPtr(AuxPointerType::PropertyIdOnRegSlotsContainer, propertyIdOnRegSlotsContainer);
  2194. }
  2195. private:
  2196. void ResetProfileIds();
  2197. void SetFlags(bool does, FunctionBodyFlags newFlags)
  2198. {
  2199. if (does)
  2200. {
  2201. flags = (FunctionBodyFlags)(flags | newFlags);
  2202. }
  2203. else
  2204. {
  2205. flags = (FunctionBodyFlags)(flags & ~newFlags);
  2206. }
  2207. }
  2208. public:
  2209. bool GetHasThis() const { return (flags & Flags_HasThis) != 0; }
  2210. void SetHasThis(bool has) { SetFlags(has, Flags_HasThis); }
  2211. bool GetHasTry() const { return (flags & Flags_HasTry) != 0; }
  2212. void SetHasTry(bool has) { SetFlags(has, Flags_HasTry); }
  2213. bool GetHasFinally() const { return m_hasFinally; }
  2214. void SetHasFinally(bool has){ m_hasFinally = has; }
  2215. bool GetFuncEscapes() const { return funcEscapes; }
  2216. void SetFuncEscapes(bool does) { funcEscapes = does; }
  2217. bool GetHasOrParentHasArguments() const { return (flags & Flags_HasOrParentHasArguments) != 0; }
  2218. void SetHasOrParentHasArguments(bool has) { SetFlags(has, Flags_HasOrParentHasArguments); }
  2219. bool DoStackNestedFunc() const { return (flags & Flags_StackNestedFunc) != 0; }
  2220. void SetStackNestedFunc(bool does) { SetFlags(does, Flags_StackNestedFunc); }
  2221. #if DBG
  2222. bool CanDoStackNestedFunc() const { return m_canDoStackNestedFunc; }
  2223. void SetCanDoStackNestedFunc() { m_canDoStackNestedFunc = true; }
  2224. #endif
  2225. RecyclerWeakReference<FunctionBody> * GetStackNestedFuncParent();
  2226. FunctionBody * GetStackNestedFuncParentStrongRef();
  2227. FunctionBody * GetAndClearStackNestedFuncParent();
  2228. void ClearStackNestedFuncParent();
  2229. void SetStackNestedFuncParent(FunctionBody * parentFunctionBody);
  2230. #if defined(_M_IX86) || defined(_M_X64)
  2231. bool DoStackClosure() const
  2232. {
  2233. return DoStackNestedFunc() && GetNestedCount() != 0 && !PHASE_OFF(StackClosurePhase, this) && scopeSlotArraySize != 0 && GetEnvDepth() != (uint16)-1;
  2234. }
  2235. #else
  2236. bool DoStackClosure() const
  2237. {
  2238. return false;
  2239. }
  2240. #endif
  2241. bool DoStackFrameDisplay() const { return DoStackClosure(); }
  2242. bool DoStackScopeSlots() const { return DoStackClosure(); }
  2243. bool IsNonUserCode() const { return (flags & Flags_NonUserCode) != 0; }
  2244. void SetIsNonUserCode(bool set);
  2245. bool GetHasNoExplicitReturnValue() { return (flags & Flags_HasNoExplicitReturnValue) != 0; }
  2246. void SetHasNoExplicitReturnValue(bool has) { SetFlags(has, Flags_HasNoExplicitReturnValue); }
  2247. bool GetHasOnlyThisStmts() const { return (flags & Flags_HasOnlyThisStatements) != 0; }
  2248. void SetHasOnlyThisStmts(bool has) { SetFlags(has, Flags_HasOnlyThisStatements); }
  2249. bool GetIsFirstFunctionObject() const { return m_firstFunctionObject; }
  2250. void SetIsNotFirstFunctionObject() { m_firstFunctionObject = false; }
  2251. bool GetInlineCachesOnFunctionObject() { return m_inlineCachesOnFunctionObject; }
  2252. void SetInlineCachesOnFunctionObject(bool has) { m_inlineCachesOnFunctionObject = has; }
  2253. bool GetHasRestParameter() const { return (flags & Flags_HasRestParameter) != 0; }
  2254. void SetHasRestParameter() { SetFlags(true, Flags_HasRestParameter); }
  2255. uint GetNumberOfRecursiveCallSites();
  2256. bool CanInlineRecursively(uint depth, bool tryAggressive = true);
  2257. public:
  2258. bool CanInlineAgain() const
  2259. {
  2260. // Block excessive recursive inlining of the same function
  2261. return inlineDepth < static_cast<byte>(max(1, min(0xff, CONFIG_FLAG(MaxFuncInlineDepth))));
  2262. }
  2263. void OnBeginInlineInto()
  2264. {
  2265. ++inlineDepth;
  2266. }
  2267. void OnEndInlineInto()
  2268. {
  2269. --inlineDepth;
  2270. }
  2271. uint8 IncrementBailOnMisingProfileCount() { return ++bailOnMisingProfileCount; }
  2272. void ResetBailOnMisingProfileCount() { bailOnMisingProfileCount = 0; }
  2273. uint8 IncrementBailOnMisingProfileRejitCount() { return ++bailOnMisingProfileRejitCount; }
  2274. uint32 GetFrameHeight(EntryPointInfo* entryPointInfo) const;
  2275. void SetFrameHeight(EntryPointInfo* entryPointInfo, uint32 frameHeight);
  2276. RegSlot GetLocalsCount();
  2277. RegSlot GetConstantCount() const { return this->GetCountField(CounterFields::ConstantCount); }
  2278. void CheckAndSetConstantCount(RegSlot cNewConstants);
  2279. void SetConstantCount(RegSlot cNewConstants);
  2280. RegSlot GetVarCount();
  2281. void SetVarCount(RegSlot cNewVars);
  2282. void CheckAndSetVarCount(RegSlot cNewVars);
  2283. RegSlot MapRegSlot(RegSlot reg)
  2284. {
  2285. if (this->RegIsConst(reg))
  2286. {
  2287. reg = CONSTREG_TO_REGSLOT(reg);
  2288. Assert(reg < this->GetConstantCount());
  2289. }
  2290. else
  2291. {
  2292. reg += this->GetConstantCount();
  2293. }
  2294. return reg;
  2295. }
  2296. bool RegIsConst(RegSlot reg) { return reg > REGSLOT_TO_CONSTREG(this->GetConstantCount()); }
  2297. uint32 GetNonTempLocalVarCount();
  2298. uint32 GetFirstNonTempLocalIndex();
  2299. uint32 GetEndNonTempLocalIndex();
  2300. bool IsNonTempLocalVar(uint32 varIndex);
  2301. bool GetSlotOffset(RegSlot slotId, int32 * slotOffset, bool allowTemp = false);
  2302. RegSlot GetOutParamMaxDepth();
  2303. void SetOutParamMaxDepth(RegSlot cOutParamsDepth);
  2304. void CheckAndSetOutParamMaxDepth(RegSlot cOutParamsDepth);
  2305. RegSlot GetYieldRegister();
  2306. RegSlot GetFirstTmpRegister() const;
  2307. void SetFirstTmpRegister(RegSlot reg);
  2308. RegSlot GetFirstTmpReg();
  2309. void SetFirstTmpReg(RegSlot firstTmpReg);
  2310. RegSlot GetTempCount();
  2311. Js::ModuleID GetModuleID() const;
  2312. void CreateConstantTable();
  2313. void RecordNullObject(RegSlot location);
  2314. void RecordUndefinedObject(RegSlot location);
  2315. void RecordTrueObject(RegSlot location);
  2316. void RecordFalseObject(RegSlot location);
  2317. void RecordIntConstant(RegSlot location, unsigned int val);
  2318. void RecordStrConstant(RegSlot location, LPCOLESTR psz, ulong cch);
  2319. void RecordFloatConstant(RegSlot location, double d);
  2320. void RecordNullDisplayConstant(RegSlot location);
  2321. void RecordStrictNullDisplayConstant(RegSlot location);
  2322. void InitConstantSlots(Var *dstSlots);
  2323. Var GetConstantVar(RegSlot location);
  2324. Js::Var* GetConstTable() const { return this->m_constTable; }
  2325. void SetConstTable(Js::Var* constTable) { this->m_constTable = constTable; }
  2326. void CloneConstantTable(FunctionBody *newFunc);
  2327. void MarkScript(ByteBlock * pblkByteCode, ByteBlock * pblkAuxiliaryData, ByteBlock* auxContextBlock,
  2328. uint byteCodeCount, uint byteCodeInLoopCount, uint byteCodeWithoutLDACount);
  2329. void BeginExecution();
  2330. void EndExecution();
  2331. SourceInfo * GetSourceInfo() { return &this->m_sourceInfo; }
  2332. bool InstallProbe(int offset);
  2333. bool UninstallProbe(int offset);
  2334. bool ProbeAtOffset(int offset, OpCode* pOriginalOpcode);
  2335. ParseableFunctionInfo * Clone(ScriptContext *scriptContext, uint sourceIndex = Js::Constants::InvalidSourceIndex) override;
  2336. static bool ShouldShareInlineCaches() { return CONFIG_FLAG(ShareInlineCaches); }
  2337. uint GetInlineCacheCount() const { return GetCountField(CounterFields::InlineCacheCount); }
  2338. void SetInlineCacheCount(uint count) { SetCountField(CounterFields::InlineCacheCount, count); }
  2339. uint GetRootObjectLoadInlineCacheStart() const { return GetCountField(CounterFields::RootObjectLoadInlineCacheStart); }
  2340. void SetRootObjectLoadInlineCacheStart(uint count) { SetCountField(CounterFields::RootObjectLoadInlineCacheStart, count); }
  2341. uint GetRootObjectLoadMethodInlineCacheStart() const { return GetCountField(CounterFields::RootObjectLoadMethodInlineCacheStart); }
  2342. void SetRootObjectLoadMethodInlineCacheStart(uint count) { SetCountField(CounterFields::RootObjectLoadMethodInlineCacheStart, count); }
  2343. uint GetRootObjectStoreInlineCacheStart() const { return GetCountField(CounterFields::RootObjectStoreInlineCacheStart); }
  2344. void SetRootObjectStoreInlineCacheStart(uint count) { SetCountField(CounterFields::RootObjectStoreInlineCacheStart, count); }
  2345. uint GetIsInstInlineCacheCount() const { return GetCountField(CounterFields::IsInstInlineCacheCount); }
  2346. void SetIsInstInlineCacheCount(uint count) { SetCountField(CounterFields::IsInstInlineCacheCount, count); }
  2347. uint GetReferencedPropertyIdCount() const { return GetCountField(CounterFields::ReferencedPropertyIdCount); }
  2348. void SetReferencedPropertyIdCount(uint count) { SetCountField(CounterFields::ReferencedPropertyIdCount, count); }
  2349. uint GetObjLiteralCount() const { return GetCountField(CounterFields::ObjLiteralCount); }
  2350. void SetObjLiteralCount(uint count) { SetCountField(CounterFields::ObjLiteralCount, count); }
  2351. uint IncObjLiteralCount() { return IncreaseCountField(CounterFields::ObjLiteralCount); }
  2352. uint GetLiteralRegexCount() const { return GetCountField(CounterFields::LiteralRegexCount); }
  2353. void SetLiteralRegexCount(uint count) { SetCountField(CounterFields::LiteralRegexCount, count); }
  2354. uint IncLiteralRegexCount() { return IncreaseCountField(CounterFields::LiteralRegexCount); }
  2355. void AllocateInlineCache();
  2356. InlineCache * GetInlineCache(uint index);
  2357. bool CanFunctionObjectHaveInlineCaches();
  2358. void** GetInlineCaches();
  2359. #if DBG
  2360. byte* GetInlineCacheTypes();
  2361. #endif
  2362. IsInstInlineCache * GetIsInstInlineCache(uint index);
  2363. PolymorphicInlineCache * GetPolymorphicInlineCache(uint index);
  2364. PolymorphicInlineCache * CreateNewPolymorphicInlineCache(uint index, PropertyId propertyId, InlineCache * inlineCache);
  2365. PolymorphicInlineCache * CreateBiggerPolymorphicInlineCache(uint index, PropertyId propertyId);
  2366. private:
  2367. void ResetInlineCaches();
  2368. PolymorphicInlineCache * CreatePolymorphicInlineCache(uint index, uint16 size);
  2369. uint32 m_asmJsTotalLoopCount;
  2370. public:
  2371. void CreateCacheIdToPropertyIdMap();
  2372. void CreateCacheIdToPropertyIdMap(uint rootObjectLoadInlineCacheStart, uint rootObjectLoadMethodInlineCacheStart, uint rootObjectStoreInlineCacheStart,
  2373. uint totalFieldAccessInlineCacheCount, uint isInstInlineCacheCount);
  2374. void SetPropertyIdForCacheId(uint cacheId, PropertyId propertyId);
  2375. PropertyId GetPropertyIdFromCacheId(uint cacheId)
  2376. {
  2377. Assert(this->cacheIdToPropertyIdMap);
  2378. Assert(cacheId < this->GetInlineCacheCount());
  2379. return this->cacheIdToPropertyIdMap[cacheId];
  2380. }
  2381. #if DBG
  2382. void VerifyCacheIdToPropertyIdMap();
  2383. #endif
  2384. PropertyId* GetReferencedPropertyIdMap() const { return static_cast<PropertyId*>(this->GetAuxPtr(AuxPointerType::ReferencedPropertyIdMap)); }
  2385. PropertyId* GetReferencedPropertyIdMapWithLock() const { return static_cast<PropertyId*>(this->GetAuxPtrWithLock(AuxPointerType::ReferencedPropertyIdMap)); }
  2386. void SetReferencedPropertyIdMap(PropertyId* propIdMap) { this->SetAuxPtr(AuxPointerType::ReferencedPropertyIdMap, propIdMap); }
  2387. void CreateReferencedPropertyIdMap(uint referencedPropertyIdCount);
  2388. void CreateReferencedPropertyIdMap();
  2389. PropertyId GetReferencedPropertyIdWithMapIndex(uint mapIndex);
  2390. PropertyId GetReferencedPropertyIdWithMapIndexWithLock(uint mapIndex);
  2391. void SetReferencedPropertyIdWithMapIndex(uint mapIndex, PropertyId propertyId);
  2392. PropertyId GetReferencedPropertyId(uint index);
  2393. PropertyId GetReferencedPropertyIdWithLock(uint index);
  2394. #if DBG
  2395. void VerifyReferencedPropertyIdMap();
  2396. #endif
  2397. #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
  2398. void DumpFullFunctionName();
  2399. void DumpFunctionId(bool pad);
  2400. uint GetTraceFunctionNumber() const;
  2401. #endif
  2402. public:
  2403. uint NewObjectLiteral();
  2404. void AllocateObjectLiteralTypeArray();
  2405. DynamicType ** GetObjectLiteralTypeRef(uint index);
  2406. DynamicType ** GetObjectLiteralTypeRefWithLock(uint index);
  2407. uint NewLiteralRegex();
  2408. void AllocateLiteralRegexArray();
  2409. UnifiedRegex::RegexPattern **GetLiteralRegexes() const { return static_cast<UnifiedRegex::RegexPattern **>(this->GetAuxPtr(AuxPointerType::LiteralRegexes)); }
  2410. UnifiedRegex::RegexPattern **GetLiteralRegexesWithLock() const { return static_cast<UnifiedRegex::RegexPattern **>(this->GetAuxPtrWithLock(AuxPointerType::LiteralRegexes)); }
  2411. void SetLiteralRegexs(UnifiedRegex::RegexPattern ** literalRegexes) { this->SetAuxPtr(AuxPointerType::LiteralRegexes, literalRegexes); }
  2412. UnifiedRegex::RegexPattern *GetLiteralRegex(const uint index);
  2413. UnifiedRegex::RegexPattern *GetLiteralRegexWithLock(const uint index);
  2414. #ifndef TEMP_DISABLE_ASMJS
  2415. AsmJsFunctionInfo* GetAsmJsFunctionInfo()const { return static_cast<AsmJsFunctionInfo*>(this->GetAuxPtr(AuxPointerType::AsmJsFunctionInfo)); }
  2416. AsmJsFunctionInfo* GetAsmJsFunctionInfoWithLock()const { return static_cast<AsmJsFunctionInfo*>(this->GetAuxPtrWithLock(AuxPointerType::AsmJsFunctionInfo)); }
  2417. AsmJsFunctionInfo* AllocateAsmJsFunctionInfo();
  2418. AsmJsModuleInfo* GetAsmJsModuleInfo()const { return static_cast<AsmJsModuleInfo*>(this->GetAuxPtr(AuxPointerType::AsmJsModuleInfo)); }
  2419. void ResetAsmJsInfo()
  2420. {
  2421. SetAuxPtr(AuxPointerType::AsmJsFunctionInfo, nullptr);
  2422. SetAuxPtr(AuxPointerType::AsmJsModuleInfo, nullptr);
  2423. }
  2424. bool IsAsmJSModule()const{ return this->GetAsmJsFunctionInfo() != nullptr; }
  2425. AsmJsModuleInfo* AllocateAsmJsModuleInfo();
  2426. #endif
  2427. void SetLiteralRegex(const uint index, UnifiedRegex::RegexPattern *const pattern);
  2428. private:
  2429. void ResetLiteralRegexes();
  2430. void ResetObjectLiteralTypes();
  2431. DynamicType** GetObjectLiteralTypes() const { return static_cast<DynamicType**>(this->GetAuxPtr(AuxPointerType::ObjLiteralTypes)); }
  2432. DynamicType** GetObjectLiteralTypesWithLock() const { return static_cast<DynamicType**>(this->GetAuxPtrWithLock(AuxPointerType::ObjLiteralTypes)); }
  2433. void SetObjectLiteralTypes(DynamicType** objLiteralTypes) { this->SetAuxPtr(AuxPointerType::ObjLiteralTypes, objLiteralTypes); };
  2434. public:
  2435. void ResetByteCodeGenState();
  2436. void ResetByteCodeGenVisitState();
  2437. void FindClosestStatements(long characterOffset, StatementLocation *firstStatementLocation, StatementLocation *secondStatementLocation);
  2438. #if ENABLE_NATIVE_CODEGEN
  2439. const FunctionCodeGenRuntimeData *GetInlineeCodeGenRuntimeData(const ProfileId profiledCallSiteId) const;
  2440. const FunctionCodeGenRuntimeData *GetInlineeCodeGenRuntimeDataForTargetInlinee(const ProfileId profiledCallSiteId, FunctionBody *inlineeFuncBody) const;
  2441. FunctionCodeGenRuntimeData *EnsureInlineeCodeGenRuntimeData(
  2442. Recycler *const recycler,
  2443. __in_range(0, profiledCallSiteCount - 1) const ProfileId profiledCallSiteId,
  2444. FunctionBody *const inlinee);
  2445. const FunctionCodeGenRuntimeData *GetLdFldInlineeCodeGenRuntimeData(const InlineCacheIndex inlineCacheIndex) const;
  2446. FunctionCodeGenRuntimeData *EnsureLdFldInlineeCodeGenRuntimeData(
  2447. Recycler *const recycler,
  2448. const InlineCacheIndex inlineCacheIndex,
  2449. FunctionBody *const inlinee);
  2450. void LoadDynamicProfileInfo();
  2451. bool HasExecutionDynamicProfileInfo() const { return hasExecutionDynamicProfileInfo; }
  2452. bool HasDynamicProfileInfo() const { return dynamicProfileInfo != nullptr; }
  2453. bool NeedEnsureDynamicProfileInfo() const;
  2454. DynamicProfileInfo * GetDynamicProfileInfo() const { Assert(HasExecutionDynamicProfileInfo()); return dynamicProfileInfo; }
  2455. DynamicProfileInfo * GetAnyDynamicProfileInfo() const { Assert(HasDynamicProfileInfo()); return dynamicProfileInfo; }
  2456. DynamicProfileInfo * EnsureDynamicProfileInfo();
  2457. DynamicProfileInfo * AllocateDynamicProfile();
  2458. BYTE GetSavedInlinerVersion() const;
  2459. uint32 GetSavedPolymorphicCacheState() const;
  2460. void SetSavedPolymorphicCacheState(uint32 state);
  2461. ImplicitCallFlags GetSavedImplicitCallsFlags() const;
  2462. bool HasNonBuiltInCallee();
  2463. void RecordNativeThrowMap(SmallSpanSequenceIter& iter, uint32 offset, uint32 statementIndex, EntryPointInfo* entryPoint, uint loopNum);
  2464. void RecordNativeBaseAddress(BYTE* baseAddress, ptrdiff_t codeSizeS, NativeCodeData * data, NativeCodeData * transferData, CodeGenNumberChunk * numberChunks,
  2465. EntryPointInfo* info, uint loopNum);
  2466. void SetNativeThrowSpanSequence(SmallSpanSequence *seq, uint loopNum, LoopEntryPointInfo* entryPoint);
  2467. BOOL GetMatchingStatementMapFromNativeAddress(DWORD_PTR codeAddress, StatementData &data, uint loopNum, FunctionBody *inlinee = nullptr);
  2468. BOOL GetMatchingStatementMapFromNativeOffset(DWORD_PTR codeAddress, uint32 offset, StatementData &data, uint loopNum, FunctionBody *inlinee = nullptr);
  2469. FunctionEntryPointInfo * GetEntryPointFromNativeAddress(DWORD_PTR codeAddress);
  2470. LoopEntryPointInfo * GetLoopEntryPointInfoFromNativeAddress(DWORD_PTR codeAddress, uint loopNum) const;
  2471. #endif
  2472. void InsertSymbolToRegSlotList(JsUtil::CharacterBuffer<WCHAR> const& propName, RegSlot reg, RegSlot totalRegsCount);
  2473. void InsertSymbolToRegSlotList(RegSlot reg, PropertyId propertyId, RegSlot totalRegsCount);
  2474. void SetPropertyIdsOfFormals(PropertyIdArray * formalArgs);
  2475. bool DontRethunkAfterBailout() const { return dontRethunkAfterBailout; }
  2476. void SetDontRethunkAfterBailout() { dontRethunkAfterBailout = true; }
  2477. void ClearDontRethunkAfterBailout() { dontRethunkAfterBailout = false; }
  2478. void SaveState(ParseNodePtr pnode);
  2479. void RestoreState(ParseNodePtr pnode);
  2480. // Used for the debug purpose, this info will be stored (in the non-debug mode), when a function has all locals marked as non-local-referenced.
  2481. // So when we got to no-refresh debug mode, and try to re-use the same function body we can then enforce all locals to be non-local-referenced.
  2482. bool HasAllNonLocalReferenced() const { return m_hasAllNonLocalReferenced; }
  2483. void SetAllNonLocalReferenced(bool set) { m_hasAllNonLocalReferenced = set; }
  2484. bool HasSetIsObject() const { return m_hasSetIsObject; }
  2485. void SetHasSetIsObject(bool set) { m_hasSetIsObject = set; }
  2486. bool HasFuncExprNameReference() const { return m_hasFunExprNameReference; }
  2487. void SetFuncExprNameReference(bool value) { m_hasFunExprNameReference = value; }
  2488. bool GetChildCallsEval() const { return m_ChildCallsEval; }
  2489. void SetChildCallsEval(bool value) { m_ChildCallsEval = value; }
  2490. bool GetCallsEval() const { return m_CallsEval; }
  2491. void SetCallsEval(bool set) { m_CallsEval = set; }
  2492. bool HasReferenceableBuiltInArguments() const { return m_hasReferenceableBuiltInArguments; }
  2493. void SetHasReferenceableBuiltInArguments(bool value) { m_hasReferenceableBuiltInArguments = value; }
  2494. bool IsParamAndBodyScopeMerged() const { return m_isParamAndBodyScopeMerged; }
  2495. void SetParamAndBodyScopeNotMerged() { m_isParamAndBodyScopeMerged = false; }
  2496. // Used for the debug purpose. This is to avoid setting all locals to non-local-referenced, multiple time for each child function.
  2497. bool HasDoneAllNonLocalReferenced() const { return m_hasDoneAllNonLocalReferenced; }
  2498. void SetHasDoneAllNonLocalReferenced(bool set) { m_hasDoneAllNonLocalReferenced = set; }
  2499. // Once the function compiled is sent m_hasFunctionCompiledSent will be set to 'true'. The below check will be used only to determine during ProfileModeDeferredParse function.
  2500. bool HasFunctionCompiledSent() const { return m_hasFunctionCompiledSent; }
  2501. void SetHasFunctionCompiledSent(bool set) { m_hasFunctionCompiledSent = set; }
  2502. #if DBG_DUMP
  2503. void DumpStatementMaps();
  2504. void Dump();
  2505. void PrintStatementSourceLine(uint statementIndex);
  2506. void PrintStatementSourceLineFromStartOffset(uint cchStartOffset);
  2507. void DumpScopes();
  2508. #endif
  2509. uint GetStatementStartOffset(const uint statementIndex);
  2510. #ifdef IR_VIEWER
  2511. void GetSourceLineFromStartOffset(const uint startOffset, LPCUTF8 *sourceBegin, LPCUTF8 *sourceEnd,
  2512. ULONG * line, LONG * col);
  2513. void GetStatementSourceInfo(const uint statementIndex, LPCUTF8 *sourceBegin, LPCUTF8 *sourceEnd,
  2514. ULONG * line, LONG * col);
  2515. #endif
  2516. HRESULT RegisterFunction(BOOL fChangeMode, BOOL fOnlyCurrent = FALSE);
  2517. HRESULT ReportScriptCompiled();
  2518. HRESULT ReportFunctionCompiled();
  2519. void SetEntryToProfileMode();
  2520. void CheckAndRegisterFuncToDiag(ScriptContext *scriptContext);
  2521. void SetEntryToDeferParseForDebugger();
  2522. void ResetEntryPoint();
  2523. void CleanupToReparse();
  2524. void AddDeferParseAttribute();
  2525. void RemoveDeferParseAttribute();
  2526. #if DBG
  2527. void MustBeInDebugMode();
  2528. #endif
  2529. static bool IsDummyGlobalRetStatement(const regex::Interval *sourceSpan)
  2530. {
  2531. Assert(sourceSpan != nullptr);
  2532. return sourceSpan->begin == 0 && sourceSpan->end == 0;
  2533. }
  2534. static void GetShortNameFromUrl(__in LPCWSTR pchUrl, _Out_writes_z_(cchBuffer) LPWSTR pchShortName, __in size_t cchBuffer);
  2535. template<class Fn>
  2536. void MapLoopHeaders(Fn fn) const
  2537. {
  2538. Js::LoopHeader* loopHeaderArray = this->GetLoopHeaderArray();
  2539. if(loopHeaderArray)
  2540. {
  2541. uint loopCount = this->GetLoopCount();
  2542. for(uint i = 0; i < loopCount; i++)
  2543. {
  2544. fn(i , &loopHeaderArray[i]);
  2545. }
  2546. }
  2547. }
  2548. template<class Fn>
  2549. void MapLoopHeadersWithLock(Fn fn) const
  2550. {
  2551. Js::LoopHeader* loopHeaderArray = this->GetLoopHeaderArrayWithLock();
  2552. if (loopHeaderArray)
  2553. {
  2554. uint loopCount = this->GetLoopCount();
  2555. for (uint i = 0; i < loopCount; i++)
  2556. {
  2557. fn(i, &loopHeaderArray[i]);
  2558. }
  2559. }
  2560. }
  2561. template <class Fn>
  2562. void MapEntryPoints(Fn fn) const
  2563. {
  2564. if (this->entryPoints)
  2565. {
  2566. this->entryPoints->Map([&fn] (int index, RecyclerWeakReference<FunctionEntryPointInfo>* entryPoint) {
  2567. FunctionEntryPointInfo* strongRef = entryPoint->Get();
  2568. if (strongRef)
  2569. {
  2570. fn(index, strongRef);
  2571. }
  2572. });
  2573. }
  2574. }
  2575. bool DoJITLoopBody() const
  2576. {
  2577. return IsJitLoopBodyPhaseEnabled() && this->GetLoopHeaderArrayWithLock() != nullptr;
  2578. }
  2579. bool ForceJITLoopBody() const
  2580. {
  2581. return IsJitLoopBodyPhaseForced() && !this->GetHasTry();
  2582. }
  2583. bool IsGeneratorAndJitIsDisabled()
  2584. {
  2585. return this->IsGenerator() && !(CONFIG_ISENABLED(Js::JitES6GeneratorsFlag) && !this->GetHasTry());
  2586. }
  2587. FunctionBodyFlags * GetAddressOfFlags() { return &this->flags; }
  2588. Js::RegSlot GetRestParamRegSlot();
  2589. public:
  2590. void RecordConstant(RegSlot location, Var var);
  2591. private:
  2592. inline void CheckEmpty();
  2593. inline void CheckNotExecuting();
  2594. BOOL GetMatchingStatementMap(StatementData &data, int statementIndex, FunctionBody *inlinee);
  2595. #if ENABLE_NATIVE_CODEGEN
  2596. int GetStatementIndexFromNativeOffset(SmallSpanSequence *pThrowSpanSequence, uint32 nativeOffset);
  2597. int GetStatementIndexFromNativeAddress(SmallSpanSequence *pThrowSpanSequence, DWORD_PTR codeAddress, DWORD_PTR nativeBaseAddress);
  2598. #endif
  2599. void EnsureAuxStatementData();
  2600. StatementAdjustmentRecordList* GetStatementAdjustmentRecords();
  2601. #ifdef DYNAMIC_PROFILE_MUTATOR
  2602. friend class DynamicProfileMutator;
  2603. friend class DynamicProfileMutatorImpl;
  2604. #endif
  2605. friend class RemoteFunctionBody;
  2606. };
  2607. typedef SynchronizableList<FunctionBody*, JsUtil::List<FunctionBody*, ArenaAllocator, false, Js::FreeListedRemovePolicy> > FunctionBodyList;
  2608. struct ScopeSlots
  2609. {
  2610. public:
  2611. static uint const MaxEncodedSlotCount = Constants::UShortMaxValue;
  2612. // The slot index is at the same location as the vtable, so that we can distinguish between scope slot and frame display
  2613. static uint const EncodedSlotCountSlotIndex = 0;
  2614. static uint const ScopeMetadataSlotIndex = 1; // Either a FunctionBody* or DebuggerScope*
  2615. static uint const FirstSlotIndex = 2;
  2616. public:
  2617. ScopeSlots(Var* slotArray) : slotArray(slotArray)
  2618. {
  2619. }
  2620. bool IsFunctionScopeSlotArray()
  2621. {
  2622. return FunctionBody::Is(slotArray[ScopeMetadataSlotIndex]);
  2623. }
  2624. FunctionBody* GetFunctionBody()
  2625. {
  2626. Assert(IsFunctionScopeSlotArray());
  2627. return (FunctionBody*)(slotArray[ScopeMetadataSlotIndex]);
  2628. }
  2629. DebuggerScope* GetDebuggerScope()
  2630. {
  2631. Assert(!IsFunctionScopeSlotArray());
  2632. return (DebuggerScope*)(slotArray[ScopeMetadataSlotIndex]);
  2633. }
  2634. Var GetScopeMetadataRaw() const
  2635. {
  2636. return slotArray[ScopeMetadataSlotIndex];
  2637. }
  2638. void SetScopeMetadata(Var scopeMetadataObj)
  2639. {
  2640. slotArray[ScopeMetadataSlotIndex] = scopeMetadataObj;
  2641. }
  2642. uint GetCount() const
  2643. {
  2644. return ::Math::PointerCastToIntegralTruncate<uint>(slotArray[EncodedSlotCountSlotIndex]);
  2645. }
  2646. void SetCount(uint count)
  2647. {
  2648. slotArray[EncodedSlotCountSlotIndex] = (Var)min<uint>(count, ScopeSlots::MaxEncodedSlotCount);
  2649. }
  2650. Var Get(uint i) const
  2651. {
  2652. Assert(i < GetCount());
  2653. return slotArray[i + FirstSlotIndex];
  2654. }
  2655. void Set(uint i, Var value)
  2656. {
  2657. Assert(i < GetCount());
  2658. slotArray[i + FirstSlotIndex] = value;
  2659. }
  2660. template<class Fn>
  2661. void Map(Fn fn)
  2662. {
  2663. uint count = GetCount();
  2664. for(uint i = 0; i < count; i++)
  2665. {
  2666. fn(GetSlot[i]);
  2667. }
  2668. }
  2669. // The first pointer sized value in the object for scope slots is the count, while it is a vtable
  2670. // for Activation object or with scope (a recyclable object)
  2671. // VTable values are always > 64K because they are a pointer, hence anything less than that implies
  2672. // a slot array.
  2673. // CONSIDER: Use TaggedInt instead of range of slot count to distinguish slot array with others.
  2674. static bool Is(void* object)
  2675. {
  2676. size_t slotCount = *((size_t*)object);
  2677. if(slotCount <= MaxEncodedSlotCount)
  2678. {
  2679. return true;
  2680. }
  2681. return false;
  2682. }
  2683. private:
  2684. Var* slotArray;
  2685. };
  2686. enum ScopeType
  2687. {
  2688. ScopeType_ActivationObject,
  2689. ScopeType_SlotArray,
  2690. ScopeType_WithScope
  2691. };
  2692. // A FrameDisplay encodes a FunctionObject's scope chain. It is an array of scopes, where each scope can be either an inline slot array
  2693. // or a RecyclableObject. A FrameDisplay for a given FunctionObject will consist of the FrameDisplay from it's enclosing scope, with any additional
  2694. // scopes prepended. Due to with statements etc. a function may introduce multiple scopes to the FrameDisplay.
  2695. struct FrameDisplay
  2696. {
  2697. FrameDisplay(uint16 len, bool strictMode = false) :
  2698. tag(true),
  2699. length(len),
  2700. strictMode(strictMode)
  2701. #if _M_X64
  2702. , unused(0)
  2703. #endif
  2704. {
  2705. }
  2706. void SetTag(bool tag) { this->tag = tag; }
  2707. void SetItem(uint index, void* item);
  2708. void *GetItem(uint index);
  2709. uint16 GetLength() const { return length; }
  2710. void SetLength(uint16 len) { this->length = len; }
  2711. bool GetStrictMode() const { return strictMode; }
  2712. void SetStrictMode(bool flag) { this->strictMode = flag; }
  2713. void** GetDataAddress() { return (void**)&this->scopes; }
  2714. static uint32 GetOffsetOfStrictMode() { return offsetof(FrameDisplay, strictMode); }
  2715. static uint32 GetOffsetOfLength() { return offsetof(FrameDisplay, length); }
  2716. static uint32 GetOffsetOfScopes() { return offsetof(FrameDisplay, scopes); }
  2717. static ScopeType GetScopeType(void* scope);
  2718. private:
  2719. bool tag; // Tag it so that the NativeCodeGenerator::IsValidVar would not think this is var
  2720. bool strictMode;
  2721. uint16 length;
  2722. #if defined(_M_X64_OR_ARM64)
  2723. uint32 unused;
  2724. #endif
  2725. void* scopes[];
  2726. };
  2727. #pragma region Function Body helper classes
  2728. #pragma region Debugging related source classes
  2729. // Contains only the beginning part of the statement. This will mainly used in SmallSpanSequence which will further be compressed
  2730. // and stored in the buffer
  2731. struct StatementData
  2732. {
  2733. StatementData()
  2734. : sourceBegin(0),
  2735. bytecodeBegin(0)
  2736. {
  2737. }
  2738. int sourceBegin;
  2739. int bytecodeBegin;
  2740. };
  2741. struct StatementLocation
  2742. {
  2743. Js::FunctionBody* function;
  2744. regex::Interval statement;
  2745. regex::Interval bytecodeSpan;
  2746. };
  2747. // Small span in the Statement buffer of the SmallSpanSequence
  2748. struct SmallSpan
  2749. {
  2750. ushort sourceBegin;
  2751. ushort bytecodeBegin;
  2752. SmallSpan(uint32 val)
  2753. {
  2754. sourceBegin = (ushort)(val >> 16);
  2755. bytecodeBegin = (ushort)(val & 0x0000FFFF);
  2756. }
  2757. operator unsigned int()
  2758. {
  2759. return (uint32)sourceBegin << 16 | bytecodeBegin;
  2760. }
  2761. };
  2762. // Iterator which contains the state at particular index. These values will used when fetching next item from
  2763. // SmallSpanSequence
  2764. class SmallSpanSequenceIter
  2765. {
  2766. friend class SmallSpanSequence;
  2767. public:
  2768. SmallSpanSequenceIter()
  2769. : accumulatedIndex(-1),
  2770. accumulatedSourceBegin(0),
  2771. accumulatedBytecodeBegin(0),
  2772. indexOfActualOffset(0)
  2773. {
  2774. }
  2775. // Below are used for fast access when the last access happened nearby.
  2776. // so the actual index would be accumulatedIndex / 2 + (remainder for which byte).
  2777. int accumulatedIndex;
  2778. int accumulatedSourceBegin;
  2779. int accumulatedBytecodeBegin;
  2780. int indexOfActualOffset;
  2781. };
  2782. // This class compacts the range of the statement to BYTEs instead of ints.
  2783. // Instead of having start and end as int32s we will have them stored in bytes, and they will be
  2784. // treated as start offset and end offset.
  2785. // For simplicity, this class should be heap allocated, since it can be allocated from either the background
  2786. // or main thread.
  2787. class SmallSpanSequence
  2788. {
  2789. friend class SmallSpanSequenceIter;
  2790. friend class ByteCodeBufferBuilder;
  2791. friend class ByteCodeBufferReader;
  2792. private:
  2793. // Each item in the list contains two set of begins (one for bytecode and for sourcespan).
  2794. // The allowed valued for source and bytecode span is in between SHORT_MAX - 1 to SHORT_MIN (inclusive).
  2795. // otherwise its a miss
  2796. JsUtil::GrowingUint32HeapArray * pStatementBuffer;
  2797. // Contains list of values which are missed in StatementBuffer.
  2798. JsUtil::GrowingUint32HeapArray * pActualOffsetList;
  2799. // The first value of the sequence
  2800. int baseValue;
  2801. BOOL GetRangeAt(int index, SmallSpanSequenceIter &iter, int * pCountOfMissed, StatementData & data);
  2802. ushort GetDiff(int current, int prev);
  2803. public:
  2804. SmallSpanSequence();
  2805. ~SmallSpanSequence()
  2806. {
  2807. Cleanup();
  2808. }
  2809. void Cleanup()
  2810. {
  2811. if (pStatementBuffer != nullptr)
  2812. {
  2813. HeapDelete(pStatementBuffer);
  2814. }
  2815. if (pActualOffsetList != nullptr)
  2816. {
  2817. HeapDelete(pActualOffsetList);
  2818. }
  2819. }
  2820. // Trys to match passed bytecode in the statement, and returns the statement which includes that.
  2821. BOOL GetMatchingStatementFromBytecode(int bytecode, SmallSpanSequenceIter &iter, StatementData & data);
  2822. // Record the statement data in the statement buffer in the compressed manner.
  2823. BOOL RecordARange(SmallSpanSequenceIter &iter, StatementData * data);
  2824. // Reset the accumulator's state and value.
  2825. void Reset(SmallSpanSequenceIter &iter);
  2826. uint32 Count() const { return pStatementBuffer ? pStatementBuffer->Count() : 0; }
  2827. BOOL Item(int index, SmallSpanSequenceIter &iter, StatementData &data);
  2828. // Below function will not change any state, so it will not alter accumulated index and value
  2829. BOOL Seek(int index, StatementData & data);
  2830. SmallSpanSequence * Clone();
  2831. };
  2832. #pragma endregion
  2833. // This container represent the property ids for the locals which are placed at direct slot
  2834. // and list of formals args if user has not used the arguments object in the script for the current function
  2835. struct PropertyIdOnRegSlotsContainer
  2836. {
  2837. PropertyId * propertyIdsForRegSlots;
  2838. uint length;
  2839. PropertyIdArray * propertyIdsForFormalArgs;
  2840. PropertyIdOnRegSlotsContainer();
  2841. static PropertyIdOnRegSlotsContainer * New(Recycler * recycler);
  2842. void CreateRegSlotsArray(Recycler * recycler, uint _length);
  2843. void SetFormalArgs(PropertyIdArray * formalArgs);
  2844. // Helper methods
  2845. void Insert(RegSlot reg, PropertyId propId);
  2846. void FetchItemAt(uint index, FunctionBody *pFuncBody, __out PropertyId *pPropId, __out RegSlot *pRegSlot);
  2847. // Whether reg belongs to non-temp locals
  2848. bool IsRegSlotFormal(RegSlot reg);
  2849. };
  2850. // Flags for the DebuggerScopeProperty object.
  2851. typedef int DebuggerScopePropertyFlags;
  2852. const int DebuggerScopePropertyFlags_None = 0x000000000;
  2853. const int DebuggerScopePropertyFlags_Const = 0x000000001;
  2854. const int DebuggerScopePropertyFlags_CatchObject = 0x000000002;
  2855. const int DebuggerScopePropertyFlags_WithObject = 0x000000004;
  2856. const int DebuggerScopePropertyFlags_ForInOrOfCollection = 0x000000008;
  2857. // Used to store local property info for with/catch objects, lets, or consts
  2858. // that are needed for the debugger.
  2859. class DebuggerScopeProperty
  2860. {
  2861. public:
  2862. Js::PropertyId propId; // The property ID of the scope variable.
  2863. RegSlot location; // Contains the location of the scope variable (regslot, slotarray, direct).
  2864. int byteCodeInitializationOffset; // The byte code offset used when comparing let/const variables for dead zone exclusion debugger side.
  2865. DebuggerScopePropertyFlags flags; // Flags for the property.
  2866. bool IsConst() const { return (flags & DebuggerScopePropertyFlags_Const) != 0; }
  2867. bool IsCatchObject() const { return (flags & DebuggerScopePropertyFlags_CatchObject) != 0; }
  2868. bool IsWithObject() const { return (flags & DebuggerScopePropertyFlags_WithObject) != 0; }
  2869. bool IsForInOrForOfCollectionScope() const { return (flags & DebuggerScopePropertyFlags_ForInOrOfCollection) != 0; }
  2870. public:
  2871. // Determines if the current property is in a dead zone. Note that the property makes
  2872. // no assumptions about what scope it's in, that is determined by DebuggerScope.
  2873. // byteCodeOffset - The current offset in bytecode that the debugger is at.
  2874. bool IsInDeadZone(int byteCodeOffset) const
  2875. {
  2876. if (IsForInOrForOfCollectionScope())
  2877. {
  2878. // These are let/const loop variables of a for-in or for-of loop
  2879. // in the scope for the collection expression. They are always
  2880. // in TDZ in this scope, never initialized by the bytecode.
  2881. return true;
  2882. }
  2883. if (this->byteCodeInitializationOffset == Constants::InvalidByteCodeOffset && !(IsCatchObject() || IsWithObject()))
  2884. {
  2885. AssertMsg(false, "Debug let/const property never had its initialization point updated. This indicates that a Ld or St operation in ByteCodeGenerator was missed that needs to have DebuggerScope::UpdatePropertyInitializationOffset() added to it.");
  2886. return false;
  2887. }
  2888. return byteCodeOffset < this->byteCodeInitializationOffset;
  2889. }
  2890. };
  2891. // Used to track with, catch, and block scopes for the debugger to determine context.
  2892. class DebuggerScope
  2893. {
  2894. public:
  2895. typedef JsUtil::List<DebuggerScopeProperty> DebuggerScopePropertyList;
  2896. DebuggerScope(Recycler* recycler, DiagExtraScopesType scopeType, RegSlot scopeLocation, int rangeBegin)
  2897. : scopeType(scopeType),
  2898. scopeProperties(nullptr),
  2899. parentScope(nullptr),
  2900. siblingScope(nullptr),
  2901. scopeLocation(scopeLocation),
  2902. recycler(recycler)
  2903. {
  2904. this->range.begin = rangeBegin;
  2905. this->range.end = -1;
  2906. }
  2907. DebuggerScope * GetSiblingScope(RegSlot location, FunctionBody *functionBody);
  2908. void AddProperty(RegSlot location, Js::PropertyId propertyId, DebuggerScopePropertyFlags flags);
  2909. bool GetPropertyIndex(Js::PropertyId propertyId, int& i);
  2910. bool HasProperty(Js::PropertyId propertyId);
  2911. bool IsOffsetInScope(int offset) const;
  2912. bool Contains(Js::PropertyId propertyId, RegSlot location) const;
  2913. bool IsBlockScope() const;
  2914. bool IsBlockObjectScope() const
  2915. {
  2916. return this->scopeType == Js::DiagBlockScopeInObject;
  2917. }
  2918. bool IsCatchScope() const;
  2919. bool IsWithScope() const;
  2920. bool IsSlotScope() const;
  2921. bool HasProperties() const;
  2922. bool IsAncestorOf(const DebuggerScope* potentialChildScope);
  2923. bool AreAllPropertiesInDeadZone(int byteCodeOffset) const;
  2924. RegSlot GetLocation() const { Assert(IsOwnScope()); return scopeLocation; }
  2925. bool IsOwnScope() const { return scopeLocation != Js::Constants::NoRegister; }
  2926. bool TryGetProperty(Js::PropertyId propertyId, RegSlot location, DebuggerScopeProperty* outScopeProperty) const;
  2927. bool TryGetValidProperty(Js::PropertyId propertyId, RegSlot location, int offset, DebuggerScopeProperty* outScopeProperty, bool* isInDeadZone) const;
  2928. bool UpdatePropertyInitializationOffset(RegSlot location, Js::PropertyId propertyId, int byteCodeOffset, bool isFunctionDeclaration = false);
  2929. void UpdateDueToByteCodeRegeneration(DiagExtraScopesType scopeType, int start, RegSlot scopeLocation);
  2930. void UpdatePropertiesInForInOrOfCollectionScope();
  2931. void SetParentScope(DebuggerScope* parentScope) { this->parentScope = parentScope; }
  2932. DebuggerScope* GetParentScope() const { return parentScope; }
  2933. DebuggerScope* FindCommonAncestor(DebuggerScope* debuggerScope);
  2934. int GetEnd() const { return range.end; }
  2935. int GetStart() const { return range.begin; }
  2936. void SetScopeLocation(RegSlot scopeLocation) { this->scopeLocation = scopeLocation; }
  2937. void SetBegin(int begin);
  2938. void SetEnd(int end);
  2939. #if DBG
  2940. void Dump();
  2941. PCWSTR GetDebuggerScopeTypeString(DiagExtraScopesType scopeType);
  2942. #endif
  2943. public:
  2944. // The list of scope properties in this scope object.
  2945. // For with scope: Has 1 property that represents the scoped object.
  2946. // For catch scope: Has 1 property that represents the exception object.
  2947. // For block scope: Has 0-n properties that represent let/const variables in that scope.
  2948. DebuggerScopePropertyList* scopeProperties;
  2949. DiagExtraScopesType scopeType; // The type of scope being represented (With, Catch, or Block scope).
  2950. DebuggerScope* siblingScope; // Valid only when current scope is slot/activationobject and symbols are on direct regslot
  2951. static const int InvalidScopeIndex = -1;
  2952. private:
  2953. int GetScopeDepth() const;
  2954. bool UpdatePropertyInitializationOffsetInternal(RegSlot location, Js::PropertyId propertyId, int byteCodeOffset, bool isFunctionDeclaration = false);
  2955. void EnsurePropertyListIsAllocated();
  2956. private:
  2957. DebuggerScope* parentScope;
  2958. regex::Interval range; // The start and end byte code writer offsets used when comparing where the debugger is currently stopped at (breakpoint location).
  2959. RegSlot scopeLocation;
  2960. Recycler* recycler;
  2961. };
  2962. class ScopeObjectChain
  2963. {
  2964. public:
  2965. typedef JsUtil::List<DebuggerScope*> ScopeObjectChainList;
  2966. ScopeObjectChain(Recycler* recycler)
  2967. : pScopeChain(nullptr)
  2968. {
  2969. pScopeChain = RecyclerNew(recycler, ScopeObjectChainList, recycler);
  2970. }
  2971. // This function will return DebuggerScopeProperty when the property is found and correctly in the range.
  2972. // If the property is found, but the scope is not in the range, it will return false, but the out param (isPropertyInDebuggerScope) will set to true,
  2973. // and isConst will be updated.
  2974. // If the property is not found at all, it will return false, and isPropertyInDebuggerScope will be false.
  2975. bool TryGetDebuggerScopePropertyInfo(PropertyId propertyId, RegSlot location, int offset, bool* isPropertyInDebuggerScope, bool *isConst, bool* isInDeadZone);
  2976. // List of all Scope Objects in a function. Scopes are added to this list as when they are created in bytecode gen part.
  2977. ScopeObjectChainList* pScopeChain;
  2978. };
  2979. #pragma endregion
  2980. } // namespace Js