GlobOptBlockData.cpp 61 KB

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