GlobOptBlockData.cpp 68 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft Corporation and contributors. All rights reserved.
  3. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  4. //-------------------------------------------------------------------------------------------------------
  5. #include "Backend.h"
  6. void
  7. GlobOptBlockData::NullOutBlockData(GlobOpt* globOpt, Func* func)
  8. {
  9. this->globOpt = globOpt;
  10. this->symToValueMap = nullptr;
  11. this->exprToValueMap = nullptr;
  12. this->liveFields = nullptr;
  13. this->maybeWrittenTypeSyms = nullptr;
  14. this->isTempSrc = nullptr;
  15. this->liveVarSyms = nullptr;
  16. this->liveInt32Syms = nullptr;
  17. this->liveLossyInt32Syms = nullptr;
  18. this->liveFloat64Syms = nullptr;
  19. #ifdef ENABLE_SIMDJS
  20. // SIMD_JS
  21. this->liveSimd128F4Syms = nullptr;
  22. this->liveSimd128I4Syms = nullptr;
  23. #endif
  24. this->hoistableFields = nullptr;
  25. this->argObjSyms = nullptr;
  26. this->maybeTempObjectSyms = nullptr;
  27. this->canStoreTempObjectSyms = nullptr;
  28. this->valuesToKillOnCalls = nullptr;
  29. this->inductionVariables = nullptr;
  30. this->availableIntBoundChecks = nullptr;
  31. this->callSequence = nullptr;
  32. this->startCallCount = 0;
  33. this->argOutCount = 0;
  34. this->totalOutParamCount = 0;
  35. this->inlinedArgOutCount = 0;
  36. this->hasCSECandidates = false;
  37. this->curFunc = func;
  38. this->stackLiteralInitFldDataMap = nullptr;
  39. this->capturedValues = nullptr;
  40. this->changedSyms = nullptr;
  41. this->OnDataUnreferenced();
  42. }
  43. void
  44. GlobOptBlockData::InitBlockData(GlobOpt* globOpt, Func* func)
  45. {
  46. this->globOpt = globOpt;
  47. JitArenaAllocator *const alloc = this->globOpt->alloc;
  48. this->symToValueMap = GlobHashTable::New(alloc, 64);
  49. this->exprToValueMap = ExprHashTable::New(alloc, 64);
  50. this->liveFields = JitAnew(alloc, BVSparse<JitArenaAllocator>, alloc);
  51. this->liveArrayValues = JitAnew(alloc, BVSparse<JitArenaAllocator>, alloc);
  52. this->isTempSrc = JitAnew(alloc, BVSparse<JitArenaAllocator>, alloc);
  53. this->liveVarSyms = JitAnew(alloc, BVSparse<JitArenaAllocator>, alloc);
  54. this->liveInt32Syms = JitAnew(alloc, BVSparse<JitArenaAllocator>, alloc);
  55. this->liveLossyInt32Syms = JitAnew(alloc, BVSparse<JitArenaAllocator>, alloc);
  56. this->liveFloat64Syms = JitAnew(alloc, BVSparse<JitArenaAllocator>, alloc);
  57. #ifdef ENABLE_SIMDJS
  58. // SIMD_JS
  59. this->liveSimd128F4Syms = JitAnew(alloc, BVSparse<JitArenaAllocator>, alloc);
  60. this->liveSimd128I4Syms = JitAnew(alloc, BVSparse<JitArenaAllocator>, alloc);
  61. #endif
  62. this->hoistableFields = nullptr;
  63. this->argObjSyms = JitAnew(alloc, BVSparse<JitArenaAllocator>, alloc);
  64. this->maybeTempObjectSyms = nullptr;
  65. this->canStoreTempObjectSyms = nullptr;
  66. this->valuesToKillOnCalls = JitAnew(alloc, ValueSet, alloc);
  67. if(this->globOpt->DoBoundCheckHoist())
  68. {
  69. this->inductionVariables = this->globOpt->IsLoopPrePass() ? JitAnew(alloc, InductionVariableSet, alloc) : nullptr;
  70. this->availableIntBoundChecks = JitAnew(alloc, IntBoundCheckSet, alloc);
  71. }
  72. this->maybeWrittenTypeSyms = nullptr;
  73. this->callSequence = nullptr;
  74. this->startCallCount = 0;
  75. this->argOutCount = 0;
  76. this->totalOutParamCount = 0;
  77. this->inlinedArgOutCount = 0;
  78. this->hasCSECandidates = false;
  79. this->curFunc = func;
  80. this->stackLiteralInitFldDataMap = nullptr;
  81. this->changedSyms = JitAnew(alloc, BVSparse<JitArenaAllocator>, alloc);
  82. this->OnDataInitialized(alloc);
  83. }
  84. void
  85. GlobOptBlockData::ReuseBlockData(GlobOptBlockData *fromData)
  86. {
  87. this->globOpt = fromData->globOpt;
  88. // Reuse dead map
  89. this->symToValueMap = fromData->symToValueMap;
  90. this->exprToValueMap = fromData->exprToValueMap;
  91. this->liveFields = fromData->liveFields;
  92. this->liveArrayValues = fromData->liveArrayValues;
  93. this->maybeWrittenTypeSyms = fromData->maybeWrittenTypeSyms;
  94. this->isTempSrc = fromData->isTempSrc;
  95. this->liveVarSyms = fromData->liveVarSyms;
  96. this->liveInt32Syms = fromData->liveInt32Syms;
  97. this->liveLossyInt32Syms = fromData->liveLossyInt32Syms;
  98. this->liveFloat64Syms = fromData->liveFloat64Syms;
  99. #ifdef ENABLE_SIMDJS
  100. // SIMD_JS
  101. this->liveSimd128F4Syms = fromData->liveSimd128F4Syms;
  102. this->liveSimd128I4Syms = fromData->liveSimd128I4Syms;
  103. #endif
  104. if (this->globOpt->TrackHoistableFields())
  105. {
  106. this->hoistableFields = fromData->hoistableFields;
  107. }
  108. if (this->globOpt->TrackArgumentsObject())
  109. {
  110. this->argObjSyms = fromData->argObjSyms;
  111. }
  112. this->maybeTempObjectSyms = fromData->maybeTempObjectSyms;
  113. this->canStoreTempObjectSyms = fromData->canStoreTempObjectSyms;
  114. this->curFunc = fromData->curFunc;
  115. this->valuesToKillOnCalls = fromData->valuesToKillOnCalls;
  116. this->inductionVariables = fromData->inductionVariables;
  117. this->availableIntBoundChecks = fromData->availableIntBoundChecks;
  118. this->callSequence = fromData->callSequence;
  119. this->startCallCount = fromData->startCallCount;
  120. this->argOutCount = fromData->argOutCount;
  121. this->totalOutParamCount = fromData->totalOutParamCount;
  122. this->inlinedArgOutCount = fromData->inlinedArgOutCount;
  123. this->hasCSECandidates = fromData->hasCSECandidates;
  124. this->stackLiteralInitFldDataMap = fromData->stackLiteralInitFldDataMap;
  125. this->changedSyms = fromData->changedSyms;
  126. this->changedSyms->ClearAll();
  127. this->OnDataReused(fromData);
  128. }
  129. void
  130. GlobOptBlockData::CopyBlockData(GlobOptBlockData *fromData)
  131. {
  132. this->globOpt = fromData->globOpt;
  133. this->symToValueMap = fromData->symToValueMap;
  134. this->exprToValueMap = fromData->exprToValueMap;
  135. this->liveFields = fromData->liveFields;
  136. this->liveArrayValues = fromData->liveArrayValues;
  137. this->maybeWrittenTypeSyms = fromData->maybeWrittenTypeSyms;
  138. this->isTempSrc = fromData->isTempSrc;
  139. this->liveVarSyms = fromData->liveVarSyms;
  140. this->liveInt32Syms = fromData->liveInt32Syms;
  141. this->liveLossyInt32Syms = fromData->liveLossyInt32Syms;
  142. this->liveFloat64Syms = fromData->liveFloat64Syms;
  143. #ifdef ENABLE_SIMDJS
  144. // SIMD_JS
  145. this->liveSimd128F4Syms = fromData->liveSimd128F4Syms;
  146. this->liveSimd128I4Syms = fromData->liveSimd128I4Syms;
  147. #endif
  148. this->hoistableFields = fromData->hoistableFields;
  149. this->argObjSyms = fromData->argObjSyms;
  150. this->maybeTempObjectSyms = fromData->maybeTempObjectSyms;
  151. this->canStoreTempObjectSyms = fromData->canStoreTempObjectSyms;
  152. this->curFunc = fromData->curFunc;
  153. this->valuesToKillOnCalls = fromData->valuesToKillOnCalls;
  154. this->inductionVariables = fromData->inductionVariables;
  155. this->availableIntBoundChecks = fromData->availableIntBoundChecks;
  156. this->callSequence = fromData->callSequence;
  157. this->startCallCount = fromData->startCallCount;
  158. this->argOutCount = fromData->argOutCount;
  159. this->totalOutParamCount = fromData->totalOutParamCount;
  160. this->inlinedArgOutCount = fromData->inlinedArgOutCount;
  161. this->hasCSECandidates = fromData->hasCSECandidates;
  162. this->changedSyms = fromData->changedSyms;
  163. this->stackLiteralInitFldDataMap = fromData->stackLiteralInitFldDataMap;
  164. this->OnDataReused(fromData);
  165. }
  166. void
  167. GlobOptBlockData::DeleteBlockData()
  168. {
  169. JitArenaAllocator *const alloc = this->globOpt->alloc;
  170. this->symToValueMap->Delete();
  171. this->exprToValueMap->Delete();
  172. JitAdelete(alloc, this->liveFields);
  173. JitAdelete(alloc, this->liveArrayValues);
  174. if (this->maybeWrittenTypeSyms)
  175. {
  176. JitAdelete(alloc, this->maybeWrittenTypeSyms);
  177. }
  178. JitAdelete(alloc, this->isTempSrc);
  179. JitAdelete(alloc, this->liveVarSyms);
  180. JitAdelete(alloc, this->liveInt32Syms);
  181. JitAdelete(alloc, this->liveLossyInt32Syms);
  182. JitAdelete(alloc, this->liveFloat64Syms);
  183. #ifdef ENABLE_SIMDJS
  184. // SIMD_JS
  185. JitAdelete(alloc, this->liveSimd128F4Syms);
  186. JitAdelete(alloc, this->liveSimd128I4Syms);
  187. #endif
  188. if (this->hoistableFields)
  189. {
  190. JitAdelete(alloc, this->hoistableFields);
  191. }
  192. if (this->argObjSyms)
  193. {
  194. JitAdelete(alloc, this->argObjSyms);
  195. }
  196. if (this->maybeTempObjectSyms)
  197. {
  198. JitAdelete(alloc, this->maybeTempObjectSyms);
  199. if (this->canStoreTempObjectSyms)
  200. {
  201. JitAdelete(alloc, this->canStoreTempObjectSyms);
  202. }
  203. }
  204. else
  205. {
  206. Assert(!this->canStoreTempObjectSyms);
  207. }
  208. JitAdelete(alloc, this->valuesToKillOnCalls);
  209. if(this->inductionVariables)
  210. {
  211. JitAdelete(alloc, this->inductionVariables);
  212. }
  213. if(this->availableIntBoundChecks)
  214. {
  215. JitAdelete(alloc, this->availableIntBoundChecks);
  216. }
  217. if (this->stackLiteralInitFldDataMap)
  218. {
  219. JitAdelete(alloc, this->stackLiteralInitFldDataMap);
  220. }
  221. JitAdelete(alloc, this->changedSyms);
  222. this->changedSyms = nullptr;
  223. this->OnDataDeleted();
  224. }
  225. void GlobOptBlockData::CloneBlockData(BasicBlock *const toBlockContext, BasicBlock *const fromBlock)
  226. {
  227. GlobOptBlockData *const fromData = &fromBlock->globOptData;
  228. this->globOpt = fromData->globOpt;
  229. JitArenaAllocator *const alloc = this->globOpt->alloc;
  230. this->symToValueMap = fromData->symToValueMap->Copy();
  231. this->exprToValueMap = fromData->exprToValueMap->Copy();
  232. // Clone the values as well to allow for flow-sensitive ValueInfo
  233. this->globOpt->CloneValues(toBlockContext, this, fromData);
  234. if(this->globOpt->DoBoundCheckHoist())
  235. {
  236. this->globOpt->CloneBoundCheckHoistBlockData(toBlockContext, this, fromBlock, fromData);
  237. }
  238. this->liveFields = JitAnew(alloc, BVSparse<JitArenaAllocator>, alloc);
  239. this->liveFields->Copy(fromData->liveFields);
  240. this->liveArrayValues = JitAnew(alloc, BVSparse<JitArenaAllocator>, alloc);
  241. this->liveArrayValues->Copy(fromData->liveArrayValues);
  242. if (fromData->maybeWrittenTypeSyms)
  243. {
  244. this->maybeWrittenTypeSyms = JitAnew(alloc, BVSparse<JitArenaAllocator>, alloc);
  245. this->maybeWrittenTypeSyms->Copy(fromData->maybeWrittenTypeSyms);
  246. }
  247. this->isTempSrc = JitAnew(alloc, BVSparse<JitArenaAllocator>, alloc);
  248. this->isTempSrc->Copy(fromData->isTempSrc);
  249. this->liveVarSyms = JitAnew(alloc, BVSparse<JitArenaAllocator>, alloc);
  250. this->liveVarSyms->Copy(fromData->liveVarSyms);
  251. this->liveInt32Syms = JitAnew(alloc, BVSparse<JitArenaAllocator>, alloc);
  252. this->liveInt32Syms->Copy(fromData->liveInt32Syms);
  253. this->liveLossyInt32Syms = JitAnew(alloc, BVSparse<JitArenaAllocator>, alloc);
  254. this->liveLossyInt32Syms->Copy(fromData->liveLossyInt32Syms);
  255. this->liveFloat64Syms = JitAnew(alloc, BVSparse<JitArenaAllocator>, alloc);
  256. this->liveFloat64Syms->Copy(fromData->liveFloat64Syms);
  257. #ifdef ENABLE_SIMDJS
  258. // SIMD_JS
  259. this->liveSimd128F4Syms = JitAnew(alloc, BVSparse<JitArenaAllocator>, alloc);
  260. this->liveSimd128F4Syms->Copy(fromData->liveSimd128F4Syms);
  261. this->liveSimd128I4Syms = JitAnew(alloc, BVSparse<JitArenaAllocator>, alloc);
  262. this->liveSimd128I4Syms->Copy(fromData->liveSimd128I4Syms);
  263. #endif
  264. if (this->globOpt->TrackHoistableFields())
  265. {
  266. if (fromData->hoistableFields)
  267. {
  268. this->hoistableFields = fromData->hoistableFields->CopyNew(alloc);
  269. }
  270. }
  271. if (this->globOpt->TrackArgumentsObject() && fromData->argObjSyms)
  272. {
  273. this->argObjSyms = fromData->argObjSyms->CopyNew(alloc);
  274. }
  275. if (fromData->maybeTempObjectSyms && !fromData->maybeTempObjectSyms->IsEmpty())
  276. {
  277. this->maybeTempObjectSyms = fromData->maybeTempObjectSyms->CopyNew(alloc);
  278. if (fromData->canStoreTempObjectSyms && !fromData->canStoreTempObjectSyms->IsEmpty())
  279. {
  280. this->canStoreTempObjectSyms = fromData->canStoreTempObjectSyms->CopyNew(alloc);
  281. }
  282. }
  283. else
  284. {
  285. Assert(fromData->canStoreTempObjectSyms == nullptr || fromData->canStoreTempObjectSyms->IsEmpty());
  286. }
  287. this->curFunc = fromData->curFunc;
  288. if (fromData->callSequence != nullptr)
  289. {
  290. this->callSequence = JitAnew(alloc, SListBase<IR::Opnd *>);
  291. fromData->callSequence->CopyTo(alloc, *(this->callSequence));
  292. }
  293. else
  294. {
  295. this->callSequence = nullptr;
  296. }
  297. this->startCallCount = fromData->startCallCount;
  298. this->argOutCount = fromData->argOutCount;
  299. this->totalOutParamCount = fromData->totalOutParamCount;
  300. this->inlinedArgOutCount = fromData->inlinedArgOutCount;
  301. this->hasCSECandidates = fromData->hasCSECandidates;
  302. // Although we don't need the data on loop pre pass, we need to do it for the loop header
  303. // because we capture the loop header bailout on loop prepass
  304. if (fromData->stackLiteralInitFldDataMap != nullptr &&
  305. (!this->globOpt->IsLoopPrePass() || (toBlockContext->isLoopHeader && toBlockContext->loop == this->globOpt->rootLoopPrePass)))
  306. {
  307. this->stackLiteralInitFldDataMap = fromData->stackLiteralInitFldDataMap->Clone();
  308. }
  309. else
  310. {
  311. this->stackLiteralInitFldDataMap = nullptr;
  312. }
  313. this->changedSyms = JitAnew(alloc, BVSparse<JitArenaAllocator>, alloc);
  314. this->changedSyms->Copy(fromData->changedSyms);
  315. Assert(fromData->HasData());
  316. this->OnDataInitialized(alloc);
  317. }
  318. void GlobOptBlockData::RemoveUnavailableCandidates(PRECandidatesList * candidates)
  319. {
  320. // In case of multiple back-edges to the loop, make sure the candidates are still valid.
  321. FOREACH_SLIST_ENTRY_EDITING(GlobHashBucket*, candidate, candidates, iter)
  322. {
  323. Value *candidateValue = candidate->element;
  324. PropertySym *candidatePropertySym = candidate->value->AsPropertySym();
  325. ValueNumber valueNumber = candidateValue->GetValueNumber();
  326. Sym *symStore = candidateValue->GetValueInfo()->GetSymStore();
  327. Value *blockValue = this->FindValue(candidatePropertySym);
  328. if (blockValue && blockValue->GetValueNumber() == valueNumber
  329. && blockValue->GetValueInfo()->GetSymStore() == symStore)
  330. {
  331. Value *symStoreValue = this->FindValue(symStore);
  332. if (symStoreValue && symStoreValue->GetValueNumber() == valueNumber)
  333. {
  334. continue;
  335. }
  336. }
  337. iter.RemoveCurrent();
  338. } NEXT_SLIST_ENTRY_EDITING;
  339. }
  340. template <typename CapturedList, typename CapturedItemsAreEqual>
  341. void
  342. GlobOptBlockData::MergeCapturedValues(
  343. SListBase<CapturedList> * toList,
  344. SListBase<CapturedList> * fromList,
  345. CapturedItemsAreEqual itemsAreEqual)
  346. {
  347. typename SListBase<CapturedList>::Iterator iterTo(toList);
  348. typename SListBase<CapturedList>::Iterator iterFrom(fromList);
  349. bool hasTo = iterTo.Next();
  350. bool hasFrom = fromList == nullptr ? false : iterFrom.Next();
  351. // to be conservative, only copy the captured value for common sym Ids
  352. // in from and to CapturedList, mark all non-common sym Ids for re-capture
  353. while (hasFrom && hasTo)
  354. {
  355. Sym * symFrom = iterFrom.Data().Key();
  356. Sym * symTo = iterTo.Data().Key();
  357. if (symFrom->m_id < symTo->m_id)
  358. {
  359. this->changedSyms->Set(symFrom->m_id);
  360. hasFrom = iterFrom.Next();
  361. }
  362. else if(symFrom->m_id > symTo->m_id)
  363. {
  364. this->changedSyms->Set(symTo->m_id);
  365. hasTo = iterTo.Next();
  366. }
  367. else
  368. {
  369. if (!itemsAreEqual(&iterFrom.Data(), &iterTo.Data()))
  370. {
  371. this->changedSyms->Set(symTo->m_id);
  372. }
  373. hasFrom = iterFrom.Next();
  374. hasTo = iterTo.Next();
  375. }
  376. }
  377. bool hasRemain = hasFrom || hasTo;
  378. if (hasRemain)
  379. {
  380. typename SListBase<CapturedList>::Iterator iterRemain(hasFrom ? iterFrom : iterTo);
  381. do
  382. {
  383. Sym * symRemain = iterRemain.Data().Key();
  384. this->changedSyms->Set(symRemain->m_id);
  385. hasRemain = iterRemain.Next();
  386. } while (hasRemain);
  387. }
  388. }
  389. void
  390. GlobOptBlockData::MergeBlockData(
  391. BasicBlock *toBlock,
  392. BasicBlock *fromBlock,
  393. BVSparse<JitArenaAllocator> *const symsRequiringCompensation,
  394. BVSparse<JitArenaAllocator> *const symsCreatedForMerge,
  395. bool forceTypeSpecOnLoopHeader)
  396. {
  397. GlobOptBlockData *fromData = &(fromBlock->globOptData);
  398. if(this->globOpt->DoBoundCheckHoist())
  399. {
  400. // Do this before merging values so that it can see whether a sym's value was changed on one side or the other
  401. this->globOpt->MergeBoundCheckHoistBlockData(toBlock, this, fromBlock, fromData);
  402. }
  403. bool isLoopBackEdge = toBlock->isLoopHeader;
  404. this->MergeValueMaps(toBlock, fromBlock, symsRequiringCompensation, symsCreatedForMerge);
  405. this->globOpt->InsertCloneStrs(toBlock, this, fromData);
  406. this->liveFields->And(fromData->liveFields);
  407. this->liveArrayValues->And(fromData->liveArrayValues);
  408. this->isTempSrc->And(fromData->isTempSrc);
  409. this->hasCSECandidates &= fromData->hasCSECandidates;
  410. if (this->capturedValues == nullptr)
  411. {
  412. this->capturedValues = fromData->capturedValues;
  413. this->changedSyms->Or(fromData->changedSyms);
  414. }
  415. else
  416. {
  417. this->MergeCapturedValues(
  418. &this->capturedValues->constantValues,
  419. fromData->capturedValues == nullptr ? nullptr : &fromData->capturedValues->constantValues,
  420. [&](ConstantStackSymValue * symValueFrom, ConstantStackSymValue * symValueTo)
  421. {
  422. return symValueFrom->Value().IsEqual(symValueTo->Value());
  423. });
  424. this->MergeCapturedValues(
  425. &this->capturedValues->copyPropSyms,
  426. fromData->capturedValues == nullptr ? nullptr : &fromData->capturedValues->copyPropSyms,
  427. [&](CopyPropSyms * copyPropSymFrom, CopyPropSyms * copyPropSymTo)
  428. {
  429. if (copyPropSymFrom->Value()->m_id == copyPropSymTo->Value()->m_id)
  430. {
  431. Value * val = fromData->FindValue(copyPropSymFrom->Key());
  432. Value * copyVal = fromData->FindValue(copyPropSymTo->Key());
  433. return (val != nullptr && copyVal != nullptr &&
  434. val->GetValueNumber() == copyVal->GetValueNumber());
  435. }
  436. return false;
  437. });
  438. }
  439. if (fromData->maybeWrittenTypeSyms)
  440. {
  441. if (this->maybeWrittenTypeSyms == nullptr)
  442. {
  443. this->maybeWrittenTypeSyms = JitAnew(this->globOpt->alloc, BVSparse<JitArenaAllocator>, this->globOpt->alloc);
  444. this->maybeWrittenTypeSyms->Copy(fromData->maybeWrittenTypeSyms);
  445. }
  446. else
  447. {
  448. this->maybeWrittenTypeSyms->Or(fromData->maybeWrittenTypeSyms);
  449. }
  450. }
  451. {
  452. // - Keep the var sym live if any of the following is true:
  453. // - The var sym is live on both sides
  454. // - The var sym is the only live sym that contains the lossless value of the sym on a side (that is, the lossless
  455. // int32 sym is not live, and the float64 sym is not live on that side), and the sym of any type is live on the
  456. // other side
  457. // - On a side, the var and float64 syms are live, the lossless int32 sym is not live, the sym's merged value is
  458. // likely int, and the sym of any type is live on the other side. Since the value is likely int, it may be
  459. // int-specialized (with lossless conversion) later. Keeping only the float64 sym live requires doing a lossless
  460. // conversion from float64 to int32, with bailout if the value of the float is not a true 32-bit integer. Checking
  461. // that is costly, and if the float64 sym is converted back to var, it does not become a tagged int, causing a
  462. // guaranteed bailout if a lossless conversion to int happens later. Keep the var sym live to preserve its
  463. // tagged-ness so that it can be int-specialized while avoiding unnecessary bailouts.
  464. // - Keep the int32 sym live if it's live on both sides
  465. // - Mark the sym as lossy if it's lossy on any side
  466. // - Keep the float64 sym live if it's live on a side and the sym of a specialized lossless type is live on the other
  467. // side
  468. //
  469. // fromData.temp =
  470. // (fromData.var - (fromData.int32 - fromData.lossyInt32)) &
  471. // (this.var | this.int32 | this.float64)
  472. // this.temp =
  473. // (this.var - (this.int32 - this.lossyInt32)) &
  474. // (fromData.var | fromData.int32 | fromData.float64)
  475. // this.var =
  476. // (fromData.var & this.var) |
  477. // (fromData.temp - fromData.float64) |
  478. // (this.temp - this.float64) |
  479. // (fromData.temp & fromData.float64 | this.temp & this.float64) & (value ~ int)
  480. //
  481. // this.float64 =
  482. // fromData.float64 & ((this.int32 - this.lossyInt32) | this.float64) |
  483. // this.float64 & ((fromData.int32 - fromData.lossyInt32) | fromData.float64)
  484. // this.int32 &= fromData.int32
  485. // this.lossyInt32 = (fromData.lossyInt32 | this.lossyInt32) & this.int32
  486. BVSparse<JitArenaAllocator> tempBv1(this->globOpt->tempAlloc);
  487. BVSparse<JitArenaAllocator> tempBv2(this->globOpt->tempAlloc);
  488. if (isLoopBackEdge && forceTypeSpecOnLoopHeader)
  489. {
  490. Loop *const loop = toBlock->loop;
  491. // Force to lossless int32:
  492. // forceLosslessInt32 =
  493. // ((fromData.int32 - fromData.lossyInt32) - (this.int32 - this.lossyInt32)) &
  494. // loop.likelyIntSymsUsedBeforeDefined &
  495. // this.var
  496. tempBv1.Minus(fromData->liveInt32Syms, fromData->liveLossyInt32Syms);
  497. tempBv2.Minus(this->liveInt32Syms, this->liveLossyInt32Syms);
  498. tempBv1.Minus(&tempBv2);
  499. tempBv1.And(loop->likelyIntSymsUsedBeforeDefined);
  500. tempBv1.And(this->liveVarSyms);
  501. this->liveInt32Syms->Or(&tempBv1);
  502. this->liveLossyInt32Syms->Minus(&tempBv1);
  503. if(this->globOpt->DoLossyIntTypeSpec())
  504. {
  505. // Force to lossy int32:
  506. // forceLossyInt32 = (fromData.int32 - this.int32) & loop.symsUsedBeforeDefined & this.var
  507. tempBv1.Minus(fromData->liveInt32Syms, this->liveInt32Syms);
  508. tempBv1.And(loop->symsUsedBeforeDefined);
  509. tempBv1.And(this->liveVarSyms);
  510. this->liveInt32Syms->Or(&tempBv1);
  511. this->liveLossyInt32Syms->Or(&tempBv1);
  512. }
  513. // Force to float64:
  514. // forceFloat64 =
  515. // fromData.float64 & loop.forceFloat64 |
  516. // (fromData.float64 - this.float64) & loop.likelyNumberSymsUsedBeforeDefined
  517. tempBv1.And(fromData->liveFloat64Syms, loop->forceFloat64SymsOnEntry);
  518. this->liveFloat64Syms->Or(&tempBv1);
  519. tempBv1.Minus(fromData->liveFloat64Syms, this->liveFloat64Syms);
  520. tempBv1.And(loop->likelyNumberSymsUsedBeforeDefined);
  521. this->liveFloat64Syms->Or(&tempBv1);
  522. #ifdef ENABLE_SIMDJS
  523. // Force to Simd128 type:
  524. // if live on the backedge and we are hoisting the operand.
  525. // or if live on the backedge only and used before def in the loop.
  526. tempBv1.And(fromData->liveSimd128F4Syms, loop->forceSimd128F4SymsOnEntry);
  527. this->liveSimd128F4Syms->Or(&tempBv1);
  528. tempBv1.Minus(fromData->liveSimd128F4Syms, this->liveSimd128F4Syms);
  529. tempBv1.And(loop->likelySimd128F4SymsUsedBeforeDefined);
  530. this->liveSimd128F4Syms->Or(&tempBv1);
  531. tempBv1.And(fromData->liveSimd128I4Syms, loop->forceSimd128I4SymsOnEntry);
  532. this->liveSimd128I4Syms->Or(&tempBv1);
  533. tempBv1.Minus(fromData->liveSimd128I4Syms, this->liveSimd128I4Syms);
  534. tempBv1.And(loop->likelySimd128I4SymsUsedBeforeDefined);
  535. this->liveSimd128I4Syms->Or(&tempBv1);
  536. #endif
  537. }
  538. #ifdef ENABLE_SIMDJS
  539. BVSparse<JitArenaAllocator> simdSymsToVar(this->globOpt->tempAlloc);
  540. {
  541. // SIMD_JS
  542. // If we have simd128 type-spec sym live as one type on one side, but not of same type on the other, we look at the merged ValueType.
  543. // If it's Likely the simd128 type, we choose to keep the type-spec sym (compensate with a FromVar), if the following is true:
  544. // - We are not in jitLoopBody. Introducing a FromVar for compensation extends bytecode syms lifetime. If the value
  545. // is actually dead, and we enter the loop-body after bailing out from SimpleJit, the value will not be restored in
  546. // the bailout code.
  547. // - Value was never Undefined/Null. Avoid unboxing of possibly uninitialized values.
  548. // - Not loop back-edge. To keep unboxed value, the value has to be used-before def in the loop-body. This is done
  549. // separately in forceSimd128*SymsOnEntry and included in loop-header.
  550. // Live syms as F4 on one edge only
  551. tempBv1.Xor(fromData->liveSimd128F4Syms, this->liveSimd128F4Syms);
  552. FOREACH_BITSET_IN_SPARSEBV(id, &tempBv1)
  553. {
  554. StackSym *const stackSym = this->globOpt->func->m_symTable->FindStackSym(id);
  555. Assert(stackSym);
  556. Value *const value = this->FindValue(stackSym);
  557. ValueInfo * valueInfo = value ? value->GetValueInfo() : nullptr;
  558. // There are two possible representations for Simd128F4 Value: F4 or Var.
  559. // If the merged ValueType is LikelySimd128F4, then on the edge where F4 is dead, Var must be alive.
  560. // Unbox to F4 type-spec sym.
  561. if (
  562. valueInfo && valueInfo->IsLikelySimd128Float32x4() &&
  563. !valueInfo->HasBeenUndefined() && !valueInfo->HasBeenNull() &&
  564. !isLoopBackEdge && !this->globOpt->func->IsLoopBody()
  565. )
  566. {
  567. this->liveSimd128F4Syms->Set(id);
  568. }
  569. else
  570. {
  571. // If live on both edges, box it.
  572. if (fromData->IsLive(stackSym) && this->IsLive(stackSym))
  573. {
  574. simdSymsToVar.Set(id);
  575. }
  576. // kill F4 sym
  577. this->liveSimd128F4Syms->Clear(id);
  578. }
  579. } NEXT_BITSET_IN_SPARSEBV;
  580. // Same for I4
  581. tempBv1.Xor(fromData->liveSimd128I4Syms, this->liveSimd128I4Syms);
  582. FOREACH_BITSET_IN_SPARSEBV(id, &tempBv1)
  583. {
  584. StackSym *const stackSym = this->globOpt->func->m_symTable->FindStackSym(id);
  585. Assert(stackSym);
  586. Value *const value = this->FindValue(stackSym);
  587. ValueInfo * valueInfo = value ? value->GetValueInfo() : nullptr;
  588. if (
  589. valueInfo && valueInfo->IsLikelySimd128Int32x4() &&
  590. !valueInfo->HasBeenUndefined() && !valueInfo->HasBeenNull() &&
  591. !isLoopBackEdge && !this->globOpt->func->IsLoopBody()
  592. )
  593. {
  594. this->liveSimd128I4Syms->Set(id);
  595. }
  596. else
  597. {
  598. if (fromData->IsLive(stackSym) && this->IsLive(stackSym))
  599. {
  600. simdSymsToVar.Set(id);
  601. }
  602. this->liveSimd128I4Syms->Clear(id);
  603. }
  604. } NEXT_BITSET_IN_SPARSEBV;
  605. }
  606. #endif
  607. {
  608. BVSparse<JitArenaAllocator> tempBv3(this->globOpt->tempAlloc);
  609. // fromData.temp =
  610. // (fromData.var - (fromData.int32 - fromData.lossyInt32)) &
  611. // (this.var | this.int32 | this.float64)
  612. tempBv2.Minus(fromData->liveInt32Syms, fromData->liveLossyInt32Syms);
  613. tempBv1.Minus(fromData->liveVarSyms, &tempBv2);
  614. tempBv2.Or(this->liveVarSyms, this->liveInt32Syms);
  615. tempBv2.Or(this->liveFloat64Syms);
  616. tempBv1.And(&tempBv2);
  617. // this.temp =
  618. // (this.var - (this.int32 - this.lossyInt32)) &
  619. // (fromData.var | fromData.int32 | fromData.float64)
  620. tempBv3.Minus(this->liveInt32Syms, this->liveLossyInt32Syms);
  621. tempBv2.Minus(this->liveVarSyms, &tempBv3);
  622. tempBv3.Or(fromData->liveVarSyms, fromData->liveInt32Syms);
  623. tempBv3.Or(fromData->liveFloat64Syms);
  624. tempBv2.And(&tempBv3);
  625. {
  626. BVSparse<JitArenaAllocator> tempBv4(this->globOpt->tempAlloc);
  627. // fromData.temp & fromData.float64 | this.temp & this.float64
  628. tempBv3.And(&tempBv1, fromData->liveFloat64Syms);
  629. tempBv4.And(&tempBv2, this->liveFloat64Syms);
  630. tempBv3.Or(&tempBv4);
  631. }
  632. // (fromData.temp - fromData.float64) |
  633. // (this.temp - this.float64)
  634. tempBv1.Minus(fromData->liveFloat64Syms);
  635. tempBv2.Minus(this->liveFloat64Syms);
  636. tempBv1.Or(&tempBv2);
  637. // this.var =
  638. // (fromData.var & this.var) |
  639. // (fromData.temp - fromData.float64) |
  640. // (this.temp - this.float64)
  641. this->liveVarSyms->And(fromData->liveVarSyms);
  642. this->liveVarSyms->Or(&tempBv1);
  643. // this.var |=
  644. // (fromData.temp & fromData.float64 | this.temp & this.float64) & (value ~ int)
  645. FOREACH_BITSET_IN_SPARSEBV(id, &tempBv3)
  646. {
  647. StackSym *const stackSym = this->globOpt->func->m_symTable->FindStackSym(id);
  648. Assert(stackSym);
  649. Value *const value = this->FindValue(stackSym);
  650. if(value)
  651. {
  652. ValueInfo *const valueInfo = value->GetValueInfo();
  653. if(valueInfo->IsInt() || (valueInfo->IsLikelyInt() && this->globOpt->DoAggressiveIntTypeSpec()))
  654. {
  655. this->liveVarSyms->Set(id);
  656. }
  657. }
  658. } NEXT_BITSET_IN_SPARSEBV;
  659. #ifdef ENABLE_SIMDJS
  660. // SIMD_JS
  661. // Simd syms that need boxing
  662. this->liveVarSyms->Or(&simdSymsToVar);
  663. #endif
  664. }
  665. // fromData.float64 & ((this.int32 - this.lossyInt32) | this.float64)
  666. tempBv1.Minus(this->liveInt32Syms, this->liveLossyInt32Syms);
  667. tempBv1.Or(this->liveFloat64Syms);
  668. tempBv1.And(fromData->liveFloat64Syms);
  669. // this.float64 & ((fromData.int32 - fromData.lossyInt32) | fromData.float64)
  670. tempBv2.Minus(fromData->liveInt32Syms, fromData->liveLossyInt32Syms);
  671. tempBv2.Or(fromData->liveFloat64Syms);
  672. tempBv2.And(this->liveFloat64Syms);
  673. // this.float64 =
  674. // fromData.float64 & ((this.int32 - this.lossyInt32) | this.float64) |
  675. // this.float64 & ((fromData.int32 - fromData.lossyInt32) | fromData.float64)
  676. this->liveFloat64Syms->Or(&tempBv1, &tempBv2);
  677. // this.int32 &= fromData.int32
  678. // this.lossyInt32 = (fromData.lossyInt32 | this.lossyInt32) & this.int32
  679. this->liveInt32Syms->And(fromData->liveInt32Syms);
  680. this->liveLossyInt32Syms->Or(fromData->liveLossyInt32Syms);
  681. this->liveLossyInt32Syms->And(this->liveInt32Syms);
  682. }
  683. if (this->globOpt->TrackHoistableFields() && this->globOpt->HasHoistableFields(fromData))
  684. {
  685. if (this->hoistableFields)
  686. {
  687. this->hoistableFields->Or(fromData->hoistableFields);
  688. }
  689. else
  690. {
  691. this->hoistableFields = fromData->hoistableFields->CopyNew(this->globOpt->alloc);
  692. }
  693. }
  694. if (this->globOpt->TrackArgumentsObject())
  695. {
  696. if (!this->argObjSyms->Equal(fromData->argObjSyms))
  697. {
  698. this->globOpt->CannotAllocateArgumentsObjectOnStack();
  699. }
  700. }
  701. if (fromData->maybeTempObjectSyms && !fromData->maybeTempObjectSyms->IsEmpty())
  702. {
  703. if (this->maybeTempObjectSyms)
  704. {
  705. this->maybeTempObjectSyms->Or(fromData->maybeTempObjectSyms);
  706. }
  707. else
  708. {
  709. this->maybeTempObjectSyms = fromData->maybeTempObjectSyms->CopyNew(this->globOpt->alloc);
  710. }
  711. if (fromData->canStoreTempObjectSyms && !fromData->canStoreTempObjectSyms->IsEmpty())
  712. {
  713. if (this->canStoreTempObjectSyms)
  714. {
  715. // Both need to be temp object
  716. this->canStoreTempObjectSyms->And(fromData->canStoreTempObjectSyms);
  717. }
  718. }
  719. else if (this->canStoreTempObjectSyms)
  720. {
  721. this->canStoreTempObjectSyms->ClearAll();
  722. }
  723. }
  724. else
  725. {
  726. Assert(!fromData->canStoreTempObjectSyms || fromData->canStoreTempObjectSyms->IsEmpty());
  727. if (this->canStoreTempObjectSyms)
  728. {
  729. this->canStoreTempObjectSyms->ClearAll();
  730. }
  731. }
  732. Assert(this->curFunc == fromData->curFunc);
  733. Assert((this->callSequence == nullptr && fromData->callSequence == nullptr) || this->callSequence->Equals(*(fromData->callSequence)));
  734. Assert(this->startCallCount == fromData->startCallCount);
  735. Assert(this->argOutCount == fromData->argOutCount);
  736. Assert(this->totalOutParamCount == fromData->totalOutParamCount);
  737. Assert(this->inlinedArgOutCount == fromData->inlinedArgOutCount);
  738. // stackLiteralInitFldDataMap is a union of the stack literal from two path.
  739. // Although we don't need the data on loop prepass, we need to do it for the loop header
  740. // because we capture the loop header bailout on loop prepass.
  741. if (fromData->stackLiteralInitFldDataMap != nullptr &&
  742. (!this->globOpt->IsLoopPrePass() || (toBlock->isLoopHeader && toBlock->loop == this->globOpt->rootLoopPrePass)))
  743. {
  744. if (this->stackLiteralInitFldDataMap == nullptr)
  745. {
  746. this->stackLiteralInitFldDataMap = fromData->stackLiteralInitFldDataMap->Clone();
  747. }
  748. else
  749. {
  750. StackLiteralInitFldDataMap * toMap = this->stackLiteralInitFldDataMap;
  751. fromData->stackLiteralInitFldDataMap->Map([toMap](StackSym * stackSym, StackLiteralInitFldData const& data)
  752. {
  753. if (toMap->AddNew(stackSym, data) == -1)
  754. {
  755. // If there is an existing data for the stackSym, both path should match
  756. DebugOnly(StackLiteralInitFldData const * currentData);
  757. Assert(toMap->TryGetReference(stackSym, &currentData));
  758. Assert(currentData->currentInitFldCount == data.currentInitFldCount);
  759. Assert(currentData->propIds == data.propIds);
  760. }
  761. });
  762. }
  763. }
  764. }
  765. void
  766. GlobOptBlockData::MergeValueMaps(
  767. BasicBlock *toBlock,
  768. BasicBlock *fromBlock,
  769. BVSparse<JitArenaAllocator> *const symsRequiringCompensation,
  770. BVSparse<JitArenaAllocator> *const symsCreatedForMerge)
  771. {
  772. GlobOptBlockData *fromData = &(fromBlock->globOptData);
  773. bool isLoopBackEdge = toBlock->isLoopHeader;
  774. Loop *loop = toBlock->loop;
  775. bool isLoopPrepass = (loop && this->globOpt->prePassLoop == loop);
  776. Assert(this->globOpt->valuesCreatedForMerge->Count() == 0);
  777. DebugOnly(ValueSetByValueNumber mergedValues(this->globOpt->tempAlloc, 64));
  778. BVSparse<JitArenaAllocator> *const mergedValueTypesTrackedForKills = this->globOpt->tempBv;
  779. Assert(mergedValueTypesTrackedForKills->IsEmpty());
  780. this->valuesToKillOnCalls->Clear(); // the tracking will be reevaluated based on merged value types
  781. GlobHashTable *thisTable = this->symToValueMap;
  782. GlobHashTable *otherTable = fromData->symToValueMap;
  783. for (uint i = 0; i < thisTable->tableSize; i++)
  784. {
  785. SListBase<GlobHashBucket>::Iterator iter2(&otherTable->table[i]);
  786. iter2.Next();
  787. FOREACH_SLISTBASE_ENTRY_EDITING(GlobHashBucket, bucket, &thisTable->table[i], iter)
  788. {
  789. while (iter2.IsValid() && bucket.value->m_id < iter2.Data().value->m_id)
  790. {
  791. iter2.Next();
  792. }
  793. Value *newValue = nullptr;
  794. if (iter2.IsValid() && bucket.value->m_id == iter2.Data().value->m_id)
  795. {
  796. newValue =
  797. this->MergeValues(
  798. bucket.element,
  799. iter2.Data().element,
  800. iter2.Data().value,
  801. isLoopBackEdge,
  802. symsRequiringCompensation,
  803. symsCreatedForMerge);
  804. }
  805. if (newValue == nullptr)
  806. {
  807. iter.RemoveCurrent(thisTable->alloc);
  808. continue;
  809. }
  810. else
  811. {
  812. #if DBG
  813. // Ensure that only one value per value number is produced by merge. Byte-code constant values are reused in
  814. // multiple blocks without cloning, so exclude those value numbers.
  815. {
  816. Value *const previouslyMergedValue = mergedValues.Lookup(newValue->GetValueNumber());
  817. if (previouslyMergedValue)
  818. {
  819. if (!this->globOpt->byteCodeConstantValueNumbersBv->Test(newValue->GetValueNumber()))
  820. {
  821. Assert(newValue == previouslyMergedValue);
  822. }
  823. }
  824. else
  825. {
  826. mergedValues.Add(newValue);
  827. }
  828. }
  829. #endif
  830. this->globOpt->TrackMergedValueForKills(newValue, this, mergedValueTypesTrackedForKills);
  831. bucket.element = newValue;
  832. }
  833. iter2.Next();
  834. } NEXT_SLISTBASE_ENTRY_EDITING;
  835. if (isLoopPrepass && !this->globOpt->rootLoopPrePass->allFieldsKilled)
  836. {
  837. while (iter2.IsValid())
  838. {
  839. iter2.Next();
  840. }
  841. }
  842. }
  843. this->globOpt->valuesCreatedForMerge->Clear();
  844. DebugOnly(mergedValues.Reset());
  845. mergedValueTypesTrackedForKills->ClearAll();
  846. this->exprToValueMap->And(fromData->exprToValueMap);
  847. this->globOpt->ProcessValueKills(toBlock, this);
  848. bool isLastLoopBackEdge = false;
  849. if (isLoopBackEdge)
  850. {
  851. this->globOpt->ProcessValueKillsForLoopHeaderAfterBackEdgeMerge(toBlock, this);
  852. BasicBlock *lastBlock = nullptr;
  853. FOREACH_PREDECESSOR_BLOCK(pred, toBlock)
  854. {
  855. Assert(!lastBlock || pred->GetBlockNum() > lastBlock->GetBlockNum());
  856. lastBlock = pred;
  857. }NEXT_PREDECESSOR_BLOCK;
  858. isLastLoopBackEdge = (lastBlock == fromBlock);
  859. }
  860. }
  861. Value *
  862. GlobOptBlockData::MergeValues(
  863. Value *toDataValue,
  864. Value *fromDataValue,
  865. Sym *fromDataSym,
  866. bool isLoopBackEdge,
  867. BVSparse<JitArenaAllocator> *const symsRequiringCompensation,
  868. BVSparse<JitArenaAllocator> *const symsCreatedForMerge)
  869. {
  870. // Same map
  871. if (toDataValue == fromDataValue)
  872. {
  873. return toDataValue;
  874. }
  875. const ValueNumberPair sourceValueNumberPair(toDataValue->GetValueNumber(), fromDataValue->GetValueNumber());
  876. const bool sameValueNumber = sourceValueNumberPair.First() == sourceValueNumberPair.Second();
  877. ValueInfo *newValueInfo =
  878. this->MergeValueInfo(
  879. toDataValue,
  880. fromDataValue,
  881. fromDataSym,
  882. isLoopBackEdge,
  883. sameValueNumber,
  884. symsRequiringCompensation,
  885. symsCreatedForMerge);
  886. if (newValueInfo == nullptr)
  887. {
  888. return nullptr;
  889. }
  890. if (sameValueNumber && newValueInfo == toDataValue->GetValueInfo())
  891. {
  892. return toDataValue;
  893. }
  894. // There may be other syms in toData that haven't been merged yet, referring to the current toData value for this sym. If
  895. // the merge produced a new value info, don't corrupt the value info for the other sym by changing the same value. Instead,
  896. // create one value per source value number pair per merge and reuse that for new value infos.
  897. Value *newValue = this->globOpt->valuesCreatedForMerge->Lookup(sourceValueNumberPair, nullptr);
  898. if(newValue)
  899. {
  900. Assert(sameValueNumber == (newValue->GetValueNumber() == toDataValue->GetValueNumber()));
  901. // This is an exception where Value::SetValueInfo is called directly instead of GlobOpt::ChangeValueInfo, because we're
  902. // actually generating new value info through merges.
  903. newValue->SetValueInfo(newValueInfo);
  904. }
  905. else
  906. {
  907. newValue = this->globOpt->NewValue(sameValueNumber ? sourceValueNumberPair.First() : this->globOpt->NewValueNumber(), newValueInfo);
  908. this->globOpt->valuesCreatedForMerge->Add(sourceValueNumberPair, newValue);
  909. }
  910. // Set symStore if same on both paths.
  911. if (toDataValue->GetValueInfo()->GetSymStore() == fromDataValue->GetValueInfo()->GetSymStore())
  912. {
  913. this->globOpt->SetSymStoreDirect(newValueInfo, toDataValue->GetValueInfo()->GetSymStore());
  914. }
  915. return newValue;
  916. }
  917. ValueInfo *
  918. GlobOptBlockData::MergeValueInfo(
  919. Value *toDataVal,
  920. Value *fromDataVal,
  921. Sym *fromDataSym,
  922. bool isLoopBackEdge,
  923. bool sameValueNumber,
  924. BVSparse<JitArenaAllocator> *const symsRequiringCompensation,
  925. BVSparse<JitArenaAllocator> *const symsCreatedForMerge)
  926. {
  927. ValueInfo *const toDataValueInfo = toDataVal->GetValueInfo();
  928. ValueInfo *const fromDataValueInfo = fromDataVal->GetValueInfo();
  929. if (toDataValueInfo->IsJsType() || fromDataValueInfo->IsJsType())
  930. {
  931. Assert(toDataValueInfo->IsJsType() && fromDataValueInfo->IsJsType());
  932. return this->MergeJsTypeValueInfo(toDataValueInfo->AsJsType(), fromDataValueInfo->AsJsType(), isLoopBackEdge, sameValueNumber);
  933. }
  934. // Same value
  935. if (toDataValueInfo == fromDataValueInfo)
  936. {
  937. return toDataValueInfo;
  938. }
  939. ValueType newValueType(toDataValueInfo->Type().Merge(fromDataValueInfo->Type()));
  940. if (newValueType.IsLikelyInt())
  941. {
  942. return ValueInfo::MergeLikelyIntValueInfo(this->globOpt->alloc, toDataVal, fromDataVal, newValueType);
  943. }
  944. if(newValueType.IsLikelyAnyOptimizedArray())
  945. {
  946. if(newValueType.IsLikelyArrayOrObjectWithArray() &&
  947. toDataValueInfo->IsLikelyArrayOrObjectWithArray() &&
  948. fromDataValueInfo->IsLikelyArrayOrObjectWithArray())
  949. {
  950. // Value type merge for missing values is aggressive by default (for profile data) - if either side likely has no
  951. // missing values, then the merged value type also likely has no missing values. This is because arrays often start
  952. // off having missing values but are eventually filled up. In GlobOpt however, we need to be conservative because
  953. // the existence of a value type that likely has missing values indicates that it is more likely for it to have
  954. // missing values than not. Also, StElems that are likely to create missing values are tracked in profile data and
  955. // will update value types to say they are now likely to have missing values, and that needs to be propagated
  956. // conservatively.
  957. newValueType =
  958. newValueType.SetHasNoMissingValues(
  959. toDataValueInfo->HasNoMissingValues() && fromDataValueInfo->HasNoMissingValues());
  960. if(toDataValueInfo->HasIntElements() != fromDataValueInfo->HasIntElements() ||
  961. toDataValueInfo->HasFloatElements() != fromDataValueInfo->HasFloatElements())
  962. {
  963. // When merging arrays with different native storage types, make the merged value type a likely version to force
  964. // array checks to be done again and cause a conversion and/or bailout as necessary
  965. newValueType = newValueType.ToLikely();
  966. }
  967. }
  968. if(!(newValueType.IsObject() && toDataValueInfo->IsArrayValueInfo() && fromDataValueInfo->IsArrayValueInfo()))
  969. {
  970. return ValueInfo::New(this->globOpt->alloc, newValueType);
  971. }
  972. return
  973. this->MergeArrayValueInfo(
  974. newValueType,
  975. toDataValueInfo->AsArrayValueInfo(),
  976. fromDataValueInfo->AsArrayValueInfo(),
  977. fromDataSym,
  978. symsRequiringCompensation,
  979. symsCreatedForMerge);
  980. }
  981. // Consider: If both values are VarConstantValueInfo with the same value, we could
  982. // merge them preserving the value.
  983. return ValueInfo::New(this->globOpt->alloc, newValueType);
  984. }
  985. JsTypeValueInfo*
  986. GlobOptBlockData::MergeJsTypeValueInfo(JsTypeValueInfo * toValueInfo, JsTypeValueInfo * fromValueInfo, bool isLoopBackEdge, bool sameValueNumber)
  987. {
  988. // On loop back edges we must be conservative and only consider type values which are invariant throughout the loop.
  989. // That's because in dead store pass we can't correctly track object pointer assignments (o = p), and we may not
  990. // be able to register correct type checks for the right properties upstream. If we ever figure out how to enhance
  991. // the dead store pass to track this info we could go more aggressively, as below.
  992. if (isLoopBackEdge && !sameValueNumber)
  993. {
  994. return nullptr;
  995. }
  996. if (toValueInfo == fromValueInfo)
  997. {
  998. return toValueInfo;
  999. }
  1000. const JITTypeHolder toType = toValueInfo->GetJsType();
  1001. const JITTypeHolder fromType = fromValueInfo->GetJsType();
  1002. const JITTypeHolder mergedType = toType == fromType ? toType : JITTypeHolder(nullptr);
  1003. Js::EquivalentTypeSet* toTypeSet = toValueInfo->GetJsTypeSet();
  1004. Js::EquivalentTypeSet* fromTypeSet = fromValueInfo->GetJsTypeSet();
  1005. Js::EquivalentTypeSet* mergedTypeSet = (toTypeSet != nullptr && fromTypeSet != nullptr && Js::EquivalentTypeSet::AreIdentical(toTypeSet, fromTypeSet)) ? toTypeSet : nullptr;
  1006. #if DBG_DUMP
  1007. if (PHASE_TRACE(Js::ObjTypeSpecPhase, this->globOpt->func) || PHASE_TRACE(Js::EquivObjTypeSpecPhase, this->globOpt->func))
  1008. {
  1009. Output::Print(_u("ObjTypeSpec: Merging type value info:\n"));
  1010. Output::Print(_u(" from (shared %d): "), fromValueInfo->GetIsShared());
  1011. fromValueInfo->Dump();
  1012. Output::Print(_u("\n to (shared %d): "), toValueInfo->GetIsShared());
  1013. toValueInfo->Dump();
  1014. }
  1015. #endif
  1016. if (mergedType == toType && mergedTypeSet == toTypeSet)
  1017. {
  1018. #if DBG_DUMP
  1019. if (PHASE_TRACE(Js::ObjTypeSpecPhase, this->globOpt->func) || PHASE_TRACE(Js::EquivObjTypeSpecPhase, this->globOpt->func))
  1020. {
  1021. Output::Print(_u("\n result (shared %d): "), toValueInfo->GetIsShared());
  1022. toValueInfo->Dump();
  1023. Output::Print(_u("\n"));
  1024. }
  1025. #endif
  1026. return toValueInfo;
  1027. }
  1028. if (mergedType == nullptr && mergedTypeSet == nullptr)
  1029. {
  1030. // No info, so don't bother making a value.
  1031. return nullptr;
  1032. }
  1033. if (toValueInfo->GetIsShared())
  1034. {
  1035. JsTypeValueInfo* mergedValueInfo = JsTypeValueInfo::New(this->globOpt->alloc, mergedType, mergedTypeSet);
  1036. #if DBG_DUMP
  1037. if (PHASE_TRACE(Js::ObjTypeSpecPhase, this->globOpt->func) || PHASE_TRACE(Js::EquivObjTypeSpecPhase, this->globOpt->func))
  1038. {
  1039. Output::Print(_u("\n result (shared %d): "), mergedValueInfo->GetIsShared());
  1040. mergedValueInfo->Dump();
  1041. Output::Print(_u("\n"));
  1042. }
  1043. #endif
  1044. return mergedValueInfo;
  1045. }
  1046. else
  1047. {
  1048. toValueInfo->SetJsType(mergedType);
  1049. toValueInfo->SetJsTypeSet(mergedTypeSet);
  1050. #if DBG_DUMP
  1051. if (PHASE_TRACE(Js::ObjTypeSpecPhase, this->globOpt->func) || PHASE_TRACE(Js::EquivObjTypeSpecPhase, this->globOpt->func))
  1052. {
  1053. Output::Print(_u("\n result (shared %d): "), toValueInfo->GetIsShared());
  1054. toValueInfo->Dump();
  1055. Output::Print(_u("\n"));
  1056. }
  1057. #endif
  1058. return toValueInfo;
  1059. }
  1060. }
  1061. ValueInfo *GlobOptBlockData::MergeArrayValueInfo(
  1062. const ValueType mergedValueType,
  1063. const ArrayValueInfo *const toDataValueInfo,
  1064. const ArrayValueInfo *const fromDataValueInfo,
  1065. Sym *const arraySym,
  1066. BVSparse<JitArenaAllocator> *const symsRequiringCompensation,
  1067. BVSparse<JitArenaAllocator> *const symsCreatedForMerge)
  1068. {
  1069. Assert(mergedValueType.IsAnyOptimizedArray());
  1070. Assert(toDataValueInfo);
  1071. Assert(fromDataValueInfo);
  1072. Assert(toDataValueInfo != fromDataValueInfo);
  1073. Assert(arraySym);
  1074. Assert(!symsRequiringCompensation == this->globOpt->IsLoopPrePass());
  1075. Assert(!symsCreatedForMerge == this->globOpt->IsLoopPrePass());
  1076. // Merge the segment and segment length syms. If we have the segment and/or the segment length syms available on both sides
  1077. // but in different syms, create a new sym and record that the array sym requires compensation. Compensation will be
  1078. // inserted later to initialize this new sym from all predecessors of the merged block.
  1079. StackSym *newHeadSegmentSym;
  1080. if(toDataValueInfo->HeadSegmentSym() && fromDataValueInfo->HeadSegmentSym())
  1081. {
  1082. if(toDataValueInfo->HeadSegmentSym() == fromDataValueInfo->HeadSegmentSym())
  1083. {
  1084. newHeadSegmentSym = toDataValueInfo->HeadSegmentSym();
  1085. }
  1086. else
  1087. {
  1088. Assert(!this->globOpt->IsLoopPrePass());
  1089. Assert(symsRequiringCompensation);
  1090. symsRequiringCompensation->Set(arraySym->m_id);
  1091. Assert(symsCreatedForMerge);
  1092. if(symsCreatedForMerge->Test(toDataValueInfo->HeadSegmentSym()->m_id))
  1093. {
  1094. newHeadSegmentSym = toDataValueInfo->HeadSegmentSym();
  1095. }
  1096. else
  1097. {
  1098. newHeadSegmentSym = StackSym::New(TyMachPtr, this->globOpt->func);
  1099. symsCreatedForMerge->Set(newHeadSegmentSym->m_id);
  1100. }
  1101. }
  1102. }
  1103. else
  1104. {
  1105. newHeadSegmentSym = nullptr;
  1106. }
  1107. StackSym *newHeadSegmentLengthSym;
  1108. if(toDataValueInfo->HeadSegmentLengthSym() && fromDataValueInfo->HeadSegmentLengthSym())
  1109. {
  1110. if(toDataValueInfo->HeadSegmentLengthSym() == fromDataValueInfo->HeadSegmentLengthSym())
  1111. {
  1112. newHeadSegmentLengthSym = toDataValueInfo->HeadSegmentLengthSym();
  1113. }
  1114. else
  1115. {
  1116. Assert(!this->globOpt->IsLoopPrePass());
  1117. Assert(symsRequiringCompensation);
  1118. symsRequiringCompensation->Set(arraySym->m_id);
  1119. Assert(symsCreatedForMerge);
  1120. if(symsCreatedForMerge->Test(toDataValueInfo->HeadSegmentLengthSym()->m_id))
  1121. {
  1122. newHeadSegmentLengthSym = toDataValueInfo->HeadSegmentLengthSym();
  1123. }
  1124. else
  1125. {
  1126. newHeadSegmentLengthSym = StackSym::New(TyUint32, this->globOpt->func);
  1127. symsCreatedForMerge->Set(newHeadSegmentLengthSym->m_id);
  1128. }
  1129. }
  1130. }
  1131. else
  1132. {
  1133. newHeadSegmentLengthSym = nullptr;
  1134. }
  1135. StackSym *newLengthSym;
  1136. if(toDataValueInfo->LengthSym() && fromDataValueInfo->LengthSym())
  1137. {
  1138. if(toDataValueInfo->LengthSym() == fromDataValueInfo->LengthSym())
  1139. {
  1140. newLengthSym = toDataValueInfo->LengthSym();
  1141. }
  1142. else
  1143. {
  1144. Assert(!this->globOpt->IsLoopPrePass());
  1145. Assert(symsRequiringCompensation);
  1146. symsRequiringCompensation->Set(arraySym->m_id);
  1147. Assert(symsCreatedForMerge);
  1148. if(symsCreatedForMerge->Test(toDataValueInfo->LengthSym()->m_id))
  1149. {
  1150. newLengthSym = toDataValueInfo->LengthSym();
  1151. }
  1152. else
  1153. {
  1154. newLengthSym = StackSym::New(TyUint32, this->globOpt->func);
  1155. symsCreatedForMerge->Set(newLengthSym->m_id);
  1156. }
  1157. }
  1158. }
  1159. else
  1160. {
  1161. newLengthSym = nullptr;
  1162. }
  1163. if(newHeadSegmentSym || newHeadSegmentLengthSym || newLengthSym)
  1164. {
  1165. return ArrayValueInfo::New(this->globOpt->alloc, mergedValueType, newHeadSegmentSym, newHeadSegmentLengthSym, newLengthSym);
  1166. }
  1167. if(symsRequiringCompensation)
  1168. {
  1169. symsRequiringCompensation->Clear(arraySym->m_id);
  1170. }
  1171. return ValueInfo::New(this->globOpt->alloc, mergedValueType);
  1172. }
  1173. void
  1174. GlobOptBlockData::TrackArgumentsSym(IR::RegOpnd const* opnd)
  1175. {
  1176. if(!this->curFunc->argObjSyms)
  1177. {
  1178. this->curFunc->argObjSyms = JitAnew(this->globOpt->alloc, BVSparse<JitArenaAllocator>, this->globOpt->alloc);
  1179. }
  1180. this->curFunc->argObjSyms->Set(opnd->m_sym->m_id);
  1181. this->argObjSyms->Set(opnd->m_sym->m_id);
  1182. #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
  1183. if (PHASE_TESTTRACE(Js::StackArgOptPhase, this->globOpt->func))
  1184. {
  1185. char16 debugStringBuffer[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE];
  1186. char16 debugStringBuffer2[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE];
  1187. Output::Print(_u("Created a new alias s%d for arguments object in function %s(%s) topFunc %s(%s)\n"),
  1188. opnd->m_sym->m_id,
  1189. this->curFunc->GetJITFunctionBody()->GetDisplayName(),
  1190. this->curFunc->GetDebugNumberSet(debugStringBuffer),
  1191. this->globOpt->func->GetJITFunctionBody()->GetDisplayName(),
  1192. this->globOpt->func->GetDebugNumberSet(debugStringBuffer2)
  1193. );
  1194. Output::Flush();
  1195. }
  1196. #endif
  1197. }
  1198. void
  1199. GlobOptBlockData::ClearArgumentsSym(IR::RegOpnd const* opnd)
  1200. {
  1201. // We blindly clear so need to check func has argObjSyms
  1202. if (this->curFunc->argObjSyms)
  1203. {
  1204. this->curFunc->argObjSyms->Clear(opnd->m_sym->m_id);
  1205. }
  1206. this->argObjSyms->Clear(opnd->m_sym->m_id);
  1207. }
  1208. BOOL
  1209. GlobOptBlockData::TestAnyArgumentsSym() const
  1210. {
  1211. return this->argObjSyms->TestEmpty();
  1212. }
  1213. BOOL
  1214. GlobOptBlockData::IsArgumentsSymID(SymID id) const
  1215. {
  1216. return this->argObjSyms->Test(id);
  1217. }
  1218. BOOL
  1219. GlobOptBlockData::IsArgumentsOpnd(IR::Opnd const* opnd) const
  1220. {
  1221. SymID id = 0;
  1222. if (opnd->IsRegOpnd())
  1223. {
  1224. id = opnd->AsRegOpnd()->m_sym->m_id;
  1225. return this->IsArgumentsSymID(id);
  1226. }
  1227. else if (opnd->IsSymOpnd())
  1228. {
  1229. Sym const *sym = opnd->AsSymOpnd()->m_sym;
  1230. if (sym && sym->IsPropertySym())
  1231. {
  1232. PropertySym const *propertySym = sym->AsPropertySym();
  1233. id = propertySym->m_stackSym->m_id;
  1234. return this->IsArgumentsSymID(id);
  1235. }
  1236. return false;
  1237. }
  1238. else if (opnd->IsIndirOpnd())
  1239. {
  1240. IR::RegOpnd const *indexOpnd = opnd->AsIndirOpnd()->GetIndexOpnd();
  1241. IR::RegOpnd const *baseOpnd = opnd->AsIndirOpnd()->GetBaseOpnd();
  1242. return this->IsArgumentsSymID(baseOpnd->m_sym->m_id) || (indexOpnd && this->IsArgumentsSymID(indexOpnd->m_sym->m_id));
  1243. }
  1244. AssertMsg(false, "Unknown type");
  1245. return false;
  1246. }
  1247. Value*
  1248. GlobOptBlockData::FindValue(Sym *sym)
  1249. {
  1250. Assert(this->symToValueMap);
  1251. if (sym->IsStackSym() && sym->AsStackSym()->IsTypeSpec())
  1252. {
  1253. sym = sym->AsStackSym()->GetVarEquivSym(this->globOpt->func);
  1254. }
  1255. else if (sym->IsPropertySym())
  1256. {
  1257. return this->FindPropertyValue(sym->m_id);
  1258. }
  1259. if (sym->IsStackSym() && sym->AsStackSym()->IsFromByteCodeConstantTable())
  1260. {
  1261. return this->globOpt->byteCodeConstantValueArray->Get(sym->m_id);
  1262. }
  1263. else
  1264. {
  1265. return FindValueFromMapDirect(sym->m_id);
  1266. }
  1267. }
  1268. Value *
  1269. GlobOptBlockData::FindPropertyValue(SymID symId)
  1270. {
  1271. Assert(this->globOpt->func->m_symTable->Find(symId)->IsPropertySym());
  1272. if (!this->liveFields->Test(symId))
  1273. {
  1274. Assert(!this->globOpt->IsHoistablePropertySym(symId));
  1275. return nullptr;
  1276. }
  1277. return FindValueFromMapDirect(symId);
  1278. }
  1279. Value *
  1280. GlobOptBlockData::FindObjectTypeValue(SymID typeSymId)
  1281. {
  1282. Assert(this->globOpt->func->m_symTable->Find(typeSymId)->IsStackSym());
  1283. if (!this->liveFields->Test(typeSymId))
  1284. {
  1285. return nullptr;
  1286. }
  1287. return FindObjectTypeValueNoLivenessCheck(typeSymId);
  1288. }
  1289. Value *
  1290. GlobOptBlockData::FindObjectTypeValueNoLivenessCheck(StackSym* typeSym)
  1291. {
  1292. return FindObjectTypeValueNoLivenessCheck(typeSym->m_id);
  1293. }
  1294. Value *
  1295. GlobOptBlockData::FindObjectTypeValueNoLivenessCheck(SymID typeSymId)
  1296. {
  1297. Value* value = this->FindValueFromMapDirect(typeSymId);
  1298. Assert(value == nullptr || value->GetValueInfo()->IsJsType());
  1299. return value;
  1300. }
  1301. Value *
  1302. GlobOptBlockData::FindObjectTypeValue(StackSym* typeSym)
  1303. {
  1304. return FindObjectTypeValue(typeSym->m_id);
  1305. }
  1306. Value *
  1307. GlobOptBlockData::FindFuturePropertyValue(PropertySym *const propertySym)
  1308. {
  1309. Assert(propertySym);
  1310. // Try a direct lookup based on this sym
  1311. Value *const value = this->FindValue(propertySym);
  1312. if(value)
  1313. {
  1314. return value;
  1315. }
  1316. if(PHASE_OFF(Js::CopyPropPhase, this->globOpt->func))
  1317. {
  1318. // Need to use copy-prop info to backtrack
  1319. return nullptr;
  1320. }
  1321. // Try to get the property object's value
  1322. StackSym *const objectSym = propertySym->m_stackSym;
  1323. Value *objectValue = this->FindValue(objectSym);
  1324. if(!objectValue)
  1325. {
  1326. if(!objectSym->IsSingleDef())
  1327. {
  1328. return nullptr;
  1329. }
  1330. switch(objectSym->m_instrDef->m_opcode)
  1331. {
  1332. case Js::OpCode::Ld_A:
  1333. case Js::OpCode::LdSlotArr:
  1334. case Js::OpCode::LdSlot:
  1335. // Allow only these op-codes for tracking the object sym's value transfer backwards. Other transfer op-codes
  1336. // could be included here if this function is used in scenarios that need them.
  1337. break;
  1338. default:
  1339. return nullptr;
  1340. }
  1341. // Try to get the property object's value from the src of the definition
  1342. IR::Opnd *const objectTransferSrc = objectSym->m_instrDef->GetSrc1();
  1343. if(!objectTransferSrc)
  1344. {
  1345. return nullptr;
  1346. }
  1347. if(objectTransferSrc->IsRegOpnd())
  1348. {
  1349. objectValue = this->FindValue(objectTransferSrc->AsRegOpnd()->m_sym);
  1350. }
  1351. else if(objectTransferSrc->IsSymOpnd())
  1352. {
  1353. Sym *const objectTransferSrcSym = objectTransferSrc->AsSymOpnd()->m_sym;
  1354. if(objectTransferSrcSym->IsStackSym())
  1355. {
  1356. objectValue = this->FindValue(objectTransferSrcSym);
  1357. }
  1358. else
  1359. {
  1360. // About to make a recursive call, so when jitting in the foreground, probe the stack
  1361. if(!this->globOpt->func->IsBackgroundJIT())
  1362. {
  1363. PROBE_STACK(this->globOpt->func->GetScriptContext(), Js::Constants::MinStackDefault);
  1364. }
  1365. objectValue = FindFuturePropertyValue(objectTransferSrcSym->AsPropertySym());
  1366. }
  1367. }
  1368. else
  1369. {
  1370. return nullptr;
  1371. }
  1372. if(!objectValue)
  1373. {
  1374. return nullptr;
  1375. }
  1376. }
  1377. // Try to use the property object's copy-prop sym and the property ID to find a mapped property sym, and get its value
  1378. StackSym *const objectCopyPropSym = this->GetCopyPropSym(nullptr, objectValue);
  1379. if(!objectCopyPropSym)
  1380. {
  1381. return nullptr;
  1382. }
  1383. PropertySym *const propertyCopyPropSym = PropertySym::Find(objectCopyPropSym->m_id, propertySym->m_propertyId, this->globOpt->func);
  1384. if(!propertyCopyPropSym)
  1385. {
  1386. return nullptr;
  1387. }
  1388. return this->FindValue(propertyCopyPropSym);
  1389. }
  1390. Value *
  1391. GlobOptBlockData::FindValueFromMapDirect(SymID symId)
  1392. {
  1393. Value ** valuePtr = this->symToValueMap->Get(symId);
  1394. if (valuePtr == nullptr)
  1395. {
  1396. return 0;
  1397. }
  1398. return (*valuePtr);
  1399. }
  1400. StackSym *
  1401. GlobOptBlockData::GetCopyPropSym(Sym * sym, Value * value)
  1402. {
  1403. ValueInfo *valueInfo = value->GetValueInfo();
  1404. Sym * copySym = valueInfo->GetSymStore();
  1405. if (!copySym)
  1406. {
  1407. return nullptr;
  1408. }
  1409. // Only copy prop stackSym, as a propertySym wouldn't improve anything.
  1410. // SingleDef info isn't flow sensitive, so make sure the symbol is actually live.
  1411. if (copySym->IsStackSym() && copySym != sym)
  1412. {
  1413. Assert(!copySym->AsStackSym()->IsTypeSpec());
  1414. Value *copySymVal = this->FindValue(valueInfo->GetSymStore());
  1415. if (copySymVal && copySymVal->GetValueNumber() == value->GetValueNumber())
  1416. {
  1417. if (valueInfo->IsVarConstant() && !this->IsLive(copySym))
  1418. {
  1419. // Because the addrConstantToValueMap isn't flow-based, the symStore of
  1420. // varConstants may not be live.
  1421. return nullptr;
  1422. }
  1423. return copySym->AsStackSym();
  1424. }
  1425. }
  1426. return nullptr;
  1427. }
  1428. void
  1429. GlobOptBlockData::ClearSymValue(Sym* sym)
  1430. {
  1431. this->symToValueMap->Clear(sym->m_id);
  1432. }
  1433. void
  1434. GlobOptBlockData::MarkTempLastUse(IR::Instr *instr, IR::RegOpnd *regOpnd)
  1435. {
  1436. if (OpCodeAttr::NonTempNumberSources(instr->m_opcode))
  1437. {
  1438. // Turn off bit if opcode could cause the src to be aliased.
  1439. this->isTempSrc->Clear(regOpnd->m_sym->m_id);
  1440. }
  1441. else if (this->isTempSrc->Test(regOpnd->m_sym->m_id))
  1442. {
  1443. // We just mark things that are temp in the globopt phase.
  1444. // The backwards phase will turn this off if it is not the last use.
  1445. // The isTempSrc is freed at the end of each block, which is why the backwards phase can't
  1446. // just use it.
  1447. if (!PHASE_OFF(Js::BackwardPhase, this->globOpt->func) && !this->globOpt->IsLoopPrePass())
  1448. {
  1449. regOpnd->m_isTempLastUse = true;
  1450. }
  1451. }
  1452. }
  1453. Value *
  1454. GlobOptBlockData::InsertNewValue(Value *val, IR::Opnd *opnd)
  1455. {
  1456. return this->SetValue(val, opnd);
  1457. }
  1458. void
  1459. GlobOptBlockData::SetChangedSym(SymID symId)
  1460. {
  1461. // this->currentBlock might not be the one which contain the changing symId,
  1462. // like hoisting invariant, but more changed symId is overly conservative and safe.
  1463. // symId in the hoisted to block is marked as JITOptimizedReg so it does't affect bailout.
  1464. if (this->changedSyms)
  1465. {
  1466. this->changedSyms->Set(symId);
  1467. if (this->capturedValuesCandidate != nullptr)
  1468. {
  1469. this->globOpt->changedSymsAfterIncBailoutCandidate->Set(symId);
  1470. }
  1471. }
  1472. // else could be hit only in MergeValues and it is handled by MergeCapturedValues
  1473. }
  1474. void
  1475. GlobOptBlockData::SetValue(Value *val, Sym * sym)
  1476. {
  1477. ValueInfo *valueInfo = val->GetValueInfo();
  1478. sym = this->globOpt->SetSymStore(valueInfo, sym);
  1479. bool isStackSym = sym->IsStackSym();
  1480. if (isStackSym && sym->AsStackSym()->IsFromByteCodeConstantTable())
  1481. {
  1482. // Put the constants in a global array. This will minimize the per-block info.
  1483. this->globOpt->byteCodeConstantValueArray->Set(sym->m_id, val);
  1484. this->globOpt->byteCodeConstantValueNumbersBv->Set(val->GetValueNumber());
  1485. }
  1486. else
  1487. {
  1488. this->SetValueToHashTable(this->symToValueMap, val, sym);
  1489. if (isStackSym && sym->AsStackSym()->HasByteCodeRegSlot())
  1490. {
  1491. this->SetChangedSym(sym->m_id);
  1492. }
  1493. }
  1494. }
  1495. Value *
  1496. GlobOptBlockData::SetValue(Value *val, IR::Opnd *opnd)
  1497. {
  1498. if (opnd)
  1499. {
  1500. Sym *sym;
  1501. switch (opnd->GetKind())
  1502. {
  1503. case IR::OpndKindSym:
  1504. sym = opnd->AsSymOpnd()->m_sym;
  1505. break;
  1506. case IR::OpndKindReg:
  1507. sym = opnd->AsRegOpnd()->m_sym;
  1508. break;
  1509. default:
  1510. sym = nullptr;
  1511. }
  1512. if (sym)
  1513. {
  1514. this->SetValue(val, sym);
  1515. }
  1516. }
  1517. return val;
  1518. }
  1519. void
  1520. GlobOptBlockData::SetValueToHashTable(GlobHashTable *valueNumberMap, Value *val, Sym *sym)
  1521. {
  1522. Value **pValue = valueNumberMap->FindOrInsertNew(sym);
  1523. *pValue = val;
  1524. }
  1525. void
  1526. GlobOptBlockData::MakeLive(StackSym *sym, const bool lossy)
  1527. {
  1528. Assert(sym);
  1529. Assert(this);
  1530. if(sym->IsTypeSpec())
  1531. {
  1532. const SymID varSymId = sym->GetVarEquivSym(this->globOpt->func)->m_id;
  1533. if(sym->IsInt32())
  1534. {
  1535. this->liveInt32Syms->Set(varSymId);
  1536. if(lossy)
  1537. {
  1538. this->liveLossyInt32Syms->Set(varSymId);
  1539. }
  1540. else
  1541. {
  1542. this->liveLossyInt32Syms->Clear(varSymId);
  1543. }
  1544. return;
  1545. }
  1546. if (sym->IsFloat64())
  1547. {
  1548. this->liveFloat64Syms->Set(varSymId);
  1549. return;
  1550. }
  1551. #ifdef ENABLE_SIMDJS
  1552. // SIMD_JS
  1553. if (sym->IsSimd128F4())
  1554. {
  1555. this->liveSimd128F4Syms->Set(varSymId);
  1556. return;
  1557. }
  1558. if (sym->IsSimd128I4())
  1559. {
  1560. this->liveSimd128I4Syms->Set(varSymId);
  1561. return;
  1562. }
  1563. #endif
  1564. }
  1565. this->liveVarSyms->Set(sym->m_id);
  1566. }
  1567. bool
  1568. GlobOptBlockData::IsLive(Sym const * sym) const
  1569. {
  1570. sym = StackSym::GetVarEquivStackSym_NoCreate(sym);
  1571. return
  1572. sym &&
  1573. (
  1574. this->liveVarSyms->Test(sym->m_id) ||
  1575. this->liveInt32Syms->Test(sym->m_id) ||
  1576. this->liveFloat64Syms->Test(sym->m_id)
  1577. #ifdef ENABLE_SIMDJS
  1578. || this->liveSimd128F4Syms->Test(sym->m_id) || this->liveSimd128I4Syms->Test(sym->m_id)
  1579. #endif
  1580. );
  1581. }
  1582. bool
  1583. GlobOptBlockData::IsTypeSpecialized(Sym const * sym) const
  1584. {
  1585. return this->IsInt32TypeSpecialized(sym) || this->IsFloat64TypeSpecialized(sym)
  1586. #ifdef ENABLE_SIMDJS
  1587. || this->IsSimd128TypeSpecialized(sym)
  1588. #endif
  1589. ;
  1590. }
  1591. bool
  1592. GlobOptBlockData::IsSwitchInt32TypeSpecialized(IR::Instr const * instr) const
  1593. {
  1594. return GlobOpt::IsSwitchOptEnabled(instr->m_func->GetTopFunc())
  1595. && instr->GetSrc1()->IsRegOpnd()
  1596. && this->IsInt32TypeSpecialized(instr->GetSrc1()->AsRegOpnd()->m_sym);
  1597. }
  1598. bool
  1599. GlobOptBlockData::IsInt32TypeSpecialized(Sym const * sym) const
  1600. {
  1601. sym = StackSym::GetVarEquivStackSym_NoCreate(sym);
  1602. return sym && this->liveInt32Syms->Test(sym->m_id) && !this->liveLossyInt32Syms->Test(sym->m_id);
  1603. }
  1604. bool
  1605. GlobOptBlockData::IsFloat64TypeSpecialized(Sym const * sym) const
  1606. {
  1607. sym = StackSym::GetVarEquivStackSym_NoCreate(sym);
  1608. return sym && this->liveFloat64Syms->Test(sym->m_id);
  1609. }
  1610. #ifdef ENABLE_SIMDJS
  1611. // SIMD_JS
  1612. bool
  1613. GlobOptBlockData::IsSimd128TypeSpecialized(Sym const * sym) const
  1614. {
  1615. sym = StackSym::GetVarEquivStackSym_NoCreate(sym);
  1616. return sym && (this->liveSimd128F4Syms->Test(sym->m_id) || this->liveSimd128I4Syms->Test(sym->m_id));
  1617. }
  1618. bool
  1619. GlobOptBlockData::IsSimd128TypeSpecialized(IRType type, Sym const * sym) const
  1620. {
  1621. switch (type)
  1622. {
  1623. case TySimd128F4:
  1624. return this->IsSimd128F4TypeSpecialized(sym);
  1625. case TySimd128I4:
  1626. return this->IsSimd128I4TypeSpecialized(sym);
  1627. default:
  1628. Assert(UNREACHED);
  1629. return false;
  1630. }
  1631. }
  1632. bool
  1633. GlobOptBlockData::IsSimd128F4TypeSpecialized(Sym const * sym) const
  1634. {
  1635. sym = StackSym::GetVarEquivStackSym_NoCreate(sym);
  1636. return sym && (this->liveSimd128F4Syms->Test(sym->m_id));
  1637. }
  1638. bool
  1639. GlobOptBlockData::IsSimd128I4TypeSpecialized(Sym const * sym) const
  1640. {
  1641. sym = StackSym::GetVarEquivStackSym_NoCreate(sym);
  1642. return sym && (this->liveSimd128I4Syms->Test(sym->m_id));
  1643. }
  1644. bool
  1645. GlobOptBlockData::IsLiveAsSimd128(Sym const * sym) const
  1646. {
  1647. sym = StackSym::GetVarEquivStackSym_NoCreate(sym);
  1648. return
  1649. sym &&
  1650. (
  1651. this->liveSimd128F4Syms->Test(sym->m_id) ||
  1652. this->liveSimd128I4Syms->Test(sym->m_id)
  1653. );
  1654. }
  1655. bool
  1656. GlobOptBlockData::IsLiveAsSimd128F4(Sym const * sym) const
  1657. {
  1658. sym = StackSym::GetVarEquivStackSym_NoCreate(sym);
  1659. return sym && this->liveSimd128F4Syms->Test(sym->m_id);
  1660. }
  1661. bool
  1662. GlobOptBlockData::IsLiveAsSimd128I4(Sym const * sym) const
  1663. {
  1664. sym = StackSym::GetVarEquivStackSym_NoCreate(sym);
  1665. return sym && this->liveSimd128I4Syms->Test(sym->m_id);
  1666. }
  1667. #endif
  1668. void
  1669. GlobOptBlockData::KillStateForGeneratorYield()
  1670. {
  1671. /*
  1672. TODO[generators][ianhall]: Do a ToVar on any typespec'd syms before the bailout so that we can enable typespec in generators without bailin having to restore typespec'd values
  1673. FOREACH_BITSET_IN_SPARSEBV(symId, this->liveInt32Syms)
  1674. {
  1675. this->ToVar(instr, , this->globOpt->currentBlock, , );
  1676. }
  1677. NEXT_BITSET_IN_SPARSEBV;
  1678. FOREACH_BITSET_IN_SPARSEBV(symId, this->liveInt32Syms)
  1679. {
  1680. this->ToVar(instr, , this->globOpt->currentBlock, , );
  1681. }
  1682. NEXT_BITSET_IN_SPARSEBV;
  1683. */
  1684. FOREACH_GLOBHASHTABLE_ENTRY(bucket, this->symToValueMap)
  1685. {
  1686. ValueType type = bucket.element->GetValueInfo()->Type().ToLikely();
  1687. bucket.element = this->globOpt->NewGenericValue(type);
  1688. }
  1689. NEXT_GLOBHASHTABLE_ENTRY;
  1690. this->exprToValueMap->ClearAll();
  1691. this->liveFields->ClearAll();
  1692. this->liveArrayValues->ClearAll();
  1693. if (this->maybeWrittenTypeSyms)
  1694. {
  1695. this->maybeWrittenTypeSyms->ClearAll();
  1696. }
  1697. this->isTempSrc->ClearAll();
  1698. this->liveInt32Syms->ClearAll();
  1699. this->liveLossyInt32Syms->ClearAll();
  1700. this->liveFloat64Syms->ClearAll();
  1701. #ifdef ENABLE_SIMDJS
  1702. // SIMD_JS
  1703. this->liveSimd128F4Syms->ClearAll();
  1704. this->liveSimd128I4Syms->ClearAll();
  1705. #endif
  1706. if (this->hoistableFields)
  1707. {
  1708. this->hoistableFields->ClearAll();
  1709. }
  1710. // Keep this->liveVarSyms as is
  1711. // Keep this->argObjSyms as is
  1712. // MarkTemp should be disabled for generator functions for now
  1713. Assert(this->maybeTempObjectSyms == nullptr || this->maybeTempObjectSyms->IsEmpty());
  1714. Assert(this->canStoreTempObjectSyms == nullptr || this->canStoreTempObjectSyms->IsEmpty());
  1715. this->valuesToKillOnCalls->Clear();
  1716. if (this->inductionVariables)
  1717. {
  1718. this->inductionVariables->Clear();
  1719. }
  1720. if (this->availableIntBoundChecks)
  1721. {
  1722. this->availableIntBoundChecks->Clear();
  1723. }
  1724. // Keep bailout data as is
  1725. this->hasCSECandidates = false;
  1726. }
  1727. #if DBG_DUMP
  1728. void
  1729. GlobOptBlockData::DumpSymToValueMap() const
  1730. {
  1731. if (this->symToValueMap != nullptr)
  1732. {
  1733. this->symToValueMap->Dump(GlobOptBlockData::DumpSym);
  1734. }
  1735. }
  1736. void
  1737. GlobOptBlockData::DumpSym(Sym *sym)
  1738. {
  1739. ((Sym const*)sym)->Dump();
  1740. }
  1741. #endif