TempTracker.cpp 62 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft. All rights reserved.
  3. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  4. //-------------------------------------------------------------------------------------------------------
  5. #include "Backend.h"
  6. /* ===================================================================================
  7. * TempTracker runs the mark temp algorithm. The template parameter provides information
  8. * what are valid temp use, temp transfer, or temp producing operations and what bit to
  9. * set once a symbol def can be marked temp.
  10. *
  11. * NumberTemp mark temp JavascriptNumber creation for math operations, run during deadstore
  12. *
  13. * ObjectTemp mark temp object allocations, run during backward pass so that it can provide
  14. * information to the globopt to install pre op bailout on implicit call while during stack
  15. * allocation objects.
  16. *
  17. * ObjectTempVerify runs a similar mark temp during deadstore in debug mode to assert
  18. * that globopt have install the pre op necessary and a marked temp def is still valid
  19. * as a mark temp
  20. *
  21. * The basic of the mark temp algorithm is very simple: we keep track if we have seen
  22. * any use of a symbol that is not a valid mark temp (the nonTempSyms bitvector)
  23. * and on definition of the symbol, if the all the use allow temp object (not in nonTempSyms
  24. * bitvector) then it is mark them able.
  25. *
  26. * However, the complication comes when the stack object is transferred to another symbol
  27. * and we are in a loop. We need to make sure that the stack object isn't still referred
  28. * by another symbol when we allocate the number/object in the next iteration
  29. *
  30. * For example:
  31. * Loop top:
  32. * s1 = NewScObject
  33. * = s6
  34. * s6 = s1
  35. * Goto Loop top
  36. *
  37. * We cannot mark them this case because when s1 is created, the object might still be
  38. * referred to by s6 from previous iteration, and thus if we mark them we would have
  39. * change the content of s6 as well.
  40. *
  41. * To detect this dependency, we conservatively collect "all" transfers in the pre pass
  42. * of the loop. We have to be conservative to detect reverse dependencies without
  43. * iterating more than 2 times for the loop.
  44. * =================================================================================== */
  45. JitArenaAllocator *
  46. TempTrackerBase::GetAllocator() const
  47. {
  48. return nonTempSyms.GetAllocator();
  49. }
  50. TempTrackerBase::TempTrackerBase(JitArenaAllocator * alloc, bool inLoop)
  51. : nonTempSyms(alloc), tempTransferredSyms(alloc)
  52. {
  53. if (inLoop)
  54. {
  55. tempTransferDependencies = HashTable<BVSparse<JitArenaAllocator> *>::New(alloc, 16);
  56. }
  57. else
  58. {
  59. tempTransferDependencies = nullptr;
  60. }
  61. }
  62. TempTrackerBase::~TempTrackerBase()
  63. {
  64. if (this->tempTransferDependencies != nullptr)
  65. {
  66. JitArenaAllocator * alloc = this->GetAllocator();
  67. FOREACH_HASHTABLE_ENTRY(BVSparse<JitArenaAllocator> *, bucket, this->tempTransferDependencies)
  68. {
  69. JitAdelete(alloc, bucket.element);
  70. }
  71. NEXT_HASHTABLE_ENTRY;
  72. this->tempTransferDependencies->Delete();
  73. }
  74. }
  75. void
  76. TempTrackerBase::MergeData(TempTrackerBase * fromData, bool deleteData)
  77. {
  78. this->nonTempSyms.Or(&fromData->nonTempSyms);
  79. this->tempTransferredSyms.Or(&fromData->tempTransferredSyms);
  80. this->MergeDependencies(this->tempTransferDependencies, fromData->tempTransferDependencies, deleteData);
  81. if (this->tempTransferDependencies)
  82. {
  83. FOREACH_HASHTABLE_ENTRY(BVSparse<JitArenaAllocator> *, bucket, this->tempTransferDependencies)
  84. {
  85. if (bucket.element->Test(&this->nonTempSyms))
  86. {
  87. this->nonTempSyms.Set(bucket.value);
  88. }
  89. } NEXT_HASHTABLE_ENTRY;
  90. }
  91. }
  92. void
  93. TempTrackerBase::AddTransferDependencies(int sourceId, SymID dstSymID, HashTable<BVSparse<JitArenaAllocator> *> * dependencies)
  94. {
  95. // Add to the transfer dependencies set
  96. BVSparse<JitArenaAllocator> ** pBVSparse = dependencies->FindOrInsertNew(sourceId);
  97. if (*pBVSparse == nullptr)
  98. {
  99. *pBVSparse = JitAnew(this->GetAllocator(), BVSparse<JitArenaAllocator>, this->GetAllocator());
  100. }
  101. AddTransferDependencies(*pBVSparse, dstSymID);
  102. }
  103. void
  104. TempTrackerBase::AddTransferDependencies(BVSparse<JitArenaAllocator> * bv, SymID dstSymID)
  105. {
  106. bv->Set(dstSymID);
  107. // Add the indirect transfers (always from tempTransferDependencies)
  108. BVSparse<JitArenaAllocator> *dstBVSparse = this->tempTransferDependencies->GetAndClear(dstSymID);
  109. if (dstBVSparse != nullptr)
  110. {
  111. bv->Or(dstBVSparse);
  112. JitAdelete(this->GetAllocator(), dstBVSparse);
  113. }
  114. }
  115. template <typename T>
  116. TempTracker<T>::TempTracker(JitArenaAllocator * alloc, bool inLoop):
  117. T(alloc, inLoop)
  118. {
  119. }
  120. template <typename T>
  121. void
  122. TempTracker<T>::MergeData(TempTracker<T> * fromData, bool deleteData)
  123. {
  124. TempTrackerBase::MergeData(fromData, deleteData);
  125. T::MergeData(fromData, deleteData);
  126. if (deleteData)
  127. {
  128. JitAdelete(this->GetAllocator(), fromData);
  129. }
  130. }
  131. void
  132. TempTrackerBase::OrHashTableOfBitVector(HashTable<BVSparse<JitArenaAllocator> *> * toData, HashTable<BVSparse<JitArenaAllocator> *> *& fromData, bool deleteData)
  133. {
  134. Assert(toData != nullptr);
  135. Assert(fromData != nullptr);
  136. toData->Or(fromData,
  137. [=](BVSparse<JitArenaAllocator> * bv1, BVSparse<JitArenaAllocator> * bv2) -> BVSparse<JitArenaAllocator> *
  138. {
  139. if (bv1 == nullptr)
  140. {
  141. if (deleteData)
  142. {
  143. return bv2;
  144. }
  145. return bv2->CopyNew(this->GetAllocator());
  146. }
  147. bv1->Or(bv2);
  148. if (deleteData)
  149. {
  150. JitAdelete(this->GetAllocator(), bv2);
  151. }
  152. return bv1;
  153. });
  154. if (deleteData)
  155. {
  156. fromData->Delete();
  157. fromData = nullptr;
  158. }
  159. }
  160. void
  161. TempTrackerBase::MergeDependencies(HashTable<BVSparse<JitArenaAllocator> *> * toData, HashTable<BVSparse<JitArenaAllocator> *> *& fromData, bool deleteData)
  162. {
  163. if (fromData != nullptr)
  164. {
  165. if (toData != nullptr)
  166. {
  167. OrHashTableOfBitVector(toData, fromData, deleteData);
  168. }
  169. else if (deleteData)
  170. {
  171. FOREACH_HASHTABLE_ENTRY(BVSparse<JitArenaAllocator> *, bucket, fromData)
  172. {
  173. JitAdelete(this->GetAllocator(), bucket.element);
  174. }
  175. NEXT_HASHTABLE_ENTRY;
  176. fromData->Delete();
  177. fromData = nullptr;
  178. }
  179. }
  180. }
  181. #if DBG_DUMP
  182. void
  183. TempTrackerBase::Dump(char16 const * traceName)
  184. {
  185. Output::Print(_u("%s: Non temp syms:"), traceName);
  186. this->nonTempSyms.Dump();
  187. Output::Print(_u("%s: Temp transferred syms:"), traceName);
  188. this->tempTransferredSyms.Dump();
  189. if (this->tempTransferDependencies != nullptr)
  190. {
  191. Output::Print(_u("%s: Temp transfer dependencies:\n"), traceName);
  192. this->tempTransferDependencies->Dump();
  193. }
  194. }
  195. #endif
  196. template <typename T>
  197. void
  198. TempTracker<T>::ProcessUse(StackSym * sym, BackwardPass * backwardPass)
  199. {
  200. // Don't care about type specialized syms
  201. if (!sym->IsVar())
  202. {
  203. return;
  204. }
  205. IR::Instr * instr = backwardPass->currentInstr;
  206. SymID usedSymID = sym->m_id;
  207. bool isTempPropertyTransferStore = T::IsTempPropertyTransferStore(instr, backwardPass);
  208. bool isTempUse = isTempPropertyTransferStore || T::IsTempUse(instr, sym, backwardPass);
  209. if (!isTempUse)
  210. {
  211. this->nonTempSyms.Set(usedSymID);
  212. }
  213. #if DBG
  214. if (T::DoTrace(backwardPass))
  215. {
  216. Output::Print(_u("%s: %8s%4sTemp Use (s%-3d): "), T::GetTraceName(),
  217. backwardPass->IsPrePass() ? _u("Prepass ") : _u(""), isTempUse ? _u("") : _u("Non "), usedSymID);
  218. instr->DumpSimple();
  219. Output::Flush();
  220. }
  221. #endif
  222. if (T::IsTempTransfer(instr))
  223. {
  224. this->tempTransferredSyms.Set(usedSymID);
  225. // Track dependencies if we are in loop only
  226. if (this->tempTransferDependencies != nullptr)
  227. {
  228. IR::Opnd * dstOpnd = instr->GetDst();
  229. if (dstOpnd->IsRegOpnd())
  230. {
  231. SymID dstSymID = dstOpnd->AsRegOpnd()->m_sym->m_id;
  232. if (dstSymID != usedSymID)
  233. {
  234. // Record that the usedSymID may propagate to dstSymID and all the symbols
  235. // that it may propagate to as well
  236. this->AddTransferDependencies(usedSymID, dstSymID, this->tempTransferDependencies);
  237. #if DBG_DUMP
  238. if (T::DoTrace(backwardPass))
  239. {
  240. Output::Print(_u("%s: %8s s%d -> s%d: "), T::GetTraceName(),
  241. backwardPass->IsPrePass() ? _u("Prepass ") : _u(""), dstSymID, usedSymID);
  242. (*this->tempTransferDependencies->Get(usedSymID))->Dump();
  243. }
  244. #endif
  245. }
  246. }
  247. }
  248. }
  249. if (isTempPropertyTransferStore)
  250. {
  251. this->tempTransferredSyms.Set(usedSymID);
  252. PropertySym * propertySym = instr->GetDst()->AsSymOpnd()->m_sym->AsPropertySym();
  253. this->PropagateTempPropertyTransferStoreDependencies(usedSymID, propertySym, backwardPass);
  254. #if DBG_DUMP
  255. if (T::DoTrace(backwardPass) && this->tempTransferDependencies)
  256. {
  257. Output::Print(_u("%s: %8s (PropId:%d)+[] -> s%d: "), T::GetTraceName(),
  258. backwardPass->IsPrePass() ? _u("Prepass ") : _u(""), propertySym->m_propertyId, usedSymID);
  259. BVSparse<JitArenaAllocator> ** transferDependencies = this->tempTransferDependencies->Get(usedSymID);
  260. if (transferDependencies)
  261. {
  262. (*transferDependencies)->Dump();
  263. }
  264. else
  265. {
  266. Output::Print(_u("[]\n"));
  267. }
  268. }
  269. #endif
  270. }
  271. };
  272. template <typename T>
  273. void
  274. TempTracker<T>::MarkTemp(StackSym * sym, BackwardPass * backwardPass)
  275. {
  276. // Don't care about type specialized syms
  277. Assert(sym->IsVar());
  278. IR::Instr * instr = backwardPass->currentInstr;
  279. BOOLEAN nonTemp = this->nonTempSyms.TestAndClear(sym->m_id);
  280. BOOLEAN isTempTransferred;
  281. BVSparse<JitArenaAllocator> * bvTempTransferDependencies = nullptr;
  282. bool const isTransferOperation =
  283. T::IsTempTransfer(instr)
  284. || T::IsTempPropertyTransferLoad(instr, backwardPass)
  285. || T::IsTempIndirTransferLoad(instr, backwardPass);
  286. if (this->tempTransferDependencies != nullptr)
  287. {
  288. // Since we don't iterate "while (!changed)" in loops, we don't have complete accurate dataflow
  289. // for loop carried dependencies. So don't clear the dependency transfer info. WOOB:1121525
  290. // Check if this dst is transferred (assigned) to another symbol
  291. if (isTransferOperation)
  292. {
  293. isTempTransferred = this->tempTransferredSyms.Test(sym->m_id);
  294. }
  295. else
  296. {
  297. isTempTransferred = this->tempTransferredSyms.TestAndClear(sym->m_id);
  298. }
  299. // We only need to look at the dependencies if we are in a loop because of the back edge
  300. // Also we don't need to if we are in pre pass
  301. if (isTempTransferred)
  302. {
  303. if (!backwardPass->IsPrePass())
  304. {
  305. if (isTransferOperation)
  306. {
  307. // Transfer operation, load but not clear the information
  308. BVSparse<JitArenaAllocator> **pBv = this->tempTransferDependencies->Get(sym->m_id);
  309. if (pBv)
  310. {
  311. bvTempTransferDependencies = *pBv;
  312. }
  313. }
  314. else
  315. {
  316. // Non transfer operation, load and clear the information and the dst value is replaced
  317. bvTempTransferDependencies = this->tempTransferDependencies->GetAndClear(sym->m_id);
  318. }
  319. }
  320. else if (!isTransferOperation)
  321. {
  322. // In pre pass, and not a transfer operation (just an assign). We can clear the dependency info
  323. // and not look at it.
  324. this->tempTransferDependencies->Clear(sym->m_id);
  325. }
  326. }
  327. }
  328. else
  329. {
  330. isTempTransferred = this->tempTransferredSyms.TestAndClear(sym->m_id);
  331. }
  332. // Reset the dst is temp bit (we set it optimistically on the loop pre pass)
  333. bool dstIsTemp = false;
  334. bool dstIsTempTransferred = false;
  335. if (nonTemp)
  336. {
  337. #if DBG_DUMP
  338. if (T::DoTrace(backwardPass) && !backwardPass->IsPrePass() && T::CanMarkTemp(instr, backwardPass))
  339. {
  340. Output::Print(_u("%s: Not temp (s%-03d):"), T::GetTraceName(), sym->m_id);
  341. instr->DumpSimple();
  342. }
  343. #endif
  344. }
  345. else if (backwardPass->IsPrePass())
  346. {
  347. // On pre pass, we don't have complete information about whether it is tempable or
  348. // not from the back edge. If we already discovered that it is not a temp (above), then
  349. // we don't mark it, other wise, assume that it is okay to be tempable and have the
  350. // second pass set the bit correctly. The only works on dependency chain that is in order
  351. // e.g.
  352. // s1 = Add
  353. // s2 = s1
  354. // s3 = s2
  355. // The dependencies tracking to catch the case whether the dependency chain is out of order
  356. // e.g
  357. // s1 = Add
  358. // s3 = s2
  359. // s2 = s3
  360. Assert(isTransferOperation == T::IsTempTransfer(instr)
  361. || T::IsTempPropertyTransferLoad(instr, backwardPass)
  362. || T::IsTempIndirTransferLoad(instr, backwardPass));
  363. if (isTransferOperation)
  364. {
  365. dstIsTemp = true;
  366. }
  367. }
  368. else if (T::CanMarkTemp(instr, backwardPass))
  369. {
  370. dstIsTemp = true;
  371. if (isTempTransferred)
  372. {
  373. // Track whether the dst is transferred or not, and allocate separate stack slot for them
  374. // so that another dst will not overrides the value
  375. dstIsTempTransferred = true;
  376. // The temp is aliased, need to trace if there is another use of the set of aliased
  377. // sym that is still live so that we won't mark them this symbol and destroy the value
  378. if (bvTempTransferDependencies != nullptr)
  379. {
  380. // Inside a loop we need to track if any of the reg that we transferred to is still live
  381. // s1 = Add
  382. // = s2
  383. // s2 = s1
  384. // Since s2 is still live on the next iteration when we reassign s1, making s1 a temp
  385. // will cause the value of s2 to change before it's use.
  386. // The upwardExposedUses are the live regs, check if it intersect with the set
  387. // of dependency or not.
  388. #if DBG_DUMP
  389. if (T::DoTrace(backwardPass) && Js::Configuration::Global.flags.Verbose)
  390. {
  391. Output::Print(_u("%s: Loop mark temp check instr:\n"), T::GetTraceName());
  392. instr->DumpSimple();
  393. Output::Print(_u("Transfer dependencies: "));
  394. bvTempTransferDependencies->Dump();
  395. Output::Print(_u("Upward exposed Uses : "));
  396. backwardPass->currentBlock->upwardExposedUses->Dump();
  397. Output::Print(_u("\n"));
  398. }
  399. #endif
  400. BVSparse<JitArenaAllocator> * upwardExposedUses = backwardPass->currentBlock->upwardExposedUses;
  401. bool hasExposedDependencies = bvTempTransferDependencies->Test(upwardExposedUses)
  402. || T::HasExposedFieldDependencies(bvTempTransferDependencies, backwardPass);
  403. if (hasExposedDependencies)
  404. {
  405. #if DBG_DUMP
  406. if (T::DoTrace(backwardPass))
  407. {
  408. Output::Print(_u("%s: Not temp (s%-03d): "), T::GetTraceName(), sym->m_id);
  409. instr->DumpSimple();
  410. Output::Print(_u(" Transferred exposed uses: "));
  411. JitArenaAllocator tempAllocator(_u("temp"), this->GetAllocator()->GetPageAllocator(), Js::Throw::OutOfMemory);
  412. bvTempTransferDependencies->AndNew(upwardExposedUses, &tempAllocator)->Dump();
  413. }
  414. #endif
  415. dstIsTemp = false;
  416. dstIsTempTransferred = false;
  417. #if DBG
  418. if (IsObjectTempVerify<T>())
  419. {
  420. dstIsTemp = ObjectTempVerify::DependencyCheck(instr, bvTempTransferDependencies, backwardPass);
  421. }
  422. #endif
  423. // Only ObjectTmepVerify would do the do anything here. All other returns false
  424. }
  425. }
  426. }
  427. }
  428. T::SetDstIsTemp(dstIsTemp, dstIsTempTransferred, instr, backwardPass);
  429. }
  430. NumberTemp::NumberTemp(JitArenaAllocator * alloc, bool inLoop)
  431. : TempTrackerBase(alloc, inLoop), elemLoadDependencies(alloc), nonTempElemLoad(false),
  432. upwardExposedMarkTempObjectLiveFields(alloc), upwardExposedMarkTempObjectSymsProperties(nullptr)
  433. {
  434. propertyIdsTempTransferDependencies = inLoop ? HashTable<BVSparse<JitArenaAllocator> *>::New(alloc, 16) : nullptr;
  435. }
  436. void
  437. NumberTemp::MergeData(NumberTemp * fromData, bool deleteData)
  438. {
  439. nonTempElemLoad = nonTempElemLoad || fromData->nonTempElemLoad;
  440. if (!nonTempElemLoad) // Don't bother merging other data if we already have a nonTempElemLoad
  441. {
  442. if (IsInLoop())
  443. {
  444. // in loop
  445. elemLoadDependencies.Or(&fromData->elemLoadDependencies);
  446. }
  447. MergeDependencies(propertyIdsTempTransferDependencies, fromData->propertyIdsTempTransferDependencies, deleteData);
  448. if (fromData->upwardExposedMarkTempObjectSymsProperties)
  449. {
  450. if (upwardExposedMarkTempObjectSymsProperties)
  451. {
  452. OrHashTableOfBitVector(upwardExposedMarkTempObjectSymsProperties, fromData->upwardExposedMarkTempObjectSymsProperties, deleteData);
  453. }
  454. else if (deleteData)
  455. {
  456. upwardExposedMarkTempObjectSymsProperties = fromData->upwardExposedMarkTempObjectSymsProperties;
  457. fromData->upwardExposedMarkTempObjectSymsProperties = nullptr;
  458. }
  459. else
  460. {
  461. upwardExposedMarkTempObjectSymsProperties = HashTable<BVSparse<JitArenaAllocator> *>::New(this->GetAllocator(), 16);
  462. OrHashTableOfBitVector(upwardExposedMarkTempObjectSymsProperties, fromData->upwardExposedMarkTempObjectSymsProperties, deleteData);
  463. }
  464. }
  465. upwardExposedMarkTempObjectLiveFields.Or(&fromData->upwardExposedMarkTempObjectLiveFields);
  466. }
  467. }
  468. bool
  469. NumberTemp::IsTempUse(IR::Instr * instr, Sym * sym, BackwardPass * backwardPass)
  470. {
  471. Js::OpCode opcode = instr->m_opcode;
  472. if (OpCodeAttr::NonTempNumberSources(opcode)
  473. || (OpCodeAttr::TempNumberTransfer(opcode) && !instr->dstIsTempNumber))
  474. {
  475. // For TypedArray stores, we don't store the Var object, so MarkTemp is valid
  476. if (opcode != Js::OpCode::StElemI_A
  477. || !instr->GetDst()->AsIndirOpnd()->GetBaseOpnd()->GetValueType().IsLikelyOptimizedTypedArray())
  478. {
  479. // Mark the symbol as non-tempable if the instruction doesn't allow temp sources,
  480. // or it is transferred to a non-temp dst
  481. return false;
  482. }
  483. }
  484. return true;
  485. }
  486. bool
  487. NumberTemp::IsTempTransfer(IR::Instr * instr)
  488. {
  489. return OpCodeAttr::TempNumberTransfer(instr->m_opcode);
  490. }
  491. bool
  492. NumberTemp::IsTempProducing(IR::Instr * instr)
  493. {
  494. Js::OpCode opcode = instr->m_opcode;
  495. if (OpCodeAttr::TempNumberProducing(opcode))
  496. {
  497. return true;
  498. }
  499. // Loads from float typedArrays usually require a conversion to Var, which we can MarkTemp.
  500. if (opcode == Js::OpCode::LdElemI_A)
  501. {
  502. const ValueType baseValueType(instr->GetSrc1()->AsIndirOpnd()->GetBaseOpnd()->GetValueType());
  503. if (baseValueType.IsLikelyObject()
  504. && (baseValueType.GetObjectType() == ObjectType::Float32Array
  505. || baseValueType.GetObjectType() == ObjectType::Float64Array))
  506. {
  507. return true;
  508. }
  509. }
  510. return false;
  511. }
  512. bool
  513. NumberTemp::CanMarkTemp(IR::Instr * instr, BackwardPass * backwardPass)
  514. {
  515. if (IsTempTransfer(instr) || IsTempProducing(instr))
  516. {
  517. return true;
  518. }
  519. // REVIEW: this is added a long time ago, and I am not sure what this is for any more.
  520. if (OpCodeAttr::InlineCallInstr(instr->m_opcode))
  521. {
  522. return true;
  523. }
  524. if (NumberTemp::IsTempIndirTransferLoad(instr, backwardPass)
  525. || NumberTemp::IsTempPropertyTransferLoad(instr, backwardPass))
  526. {
  527. return true;
  528. }
  529. // the opcode is not temp producing or a transfer, this is not a tmp
  530. // Also mark calls which may get inlined.
  531. return false;
  532. }
  533. void
  534. NumberTemp::ProcessInstr(IR::Instr * instr, BackwardPass * backwardPass)
  535. {
  536. #if DBG
  537. if (instr->m_opcode == Js::OpCode::BailOnNoProfile)
  538. {
  539. // If we see BailOnNoProfile, we shouldn't have any successor to have any non temp syms
  540. Assert(!this->nonTempElemLoad);
  541. Assert(this->nonTempSyms.IsEmpty());
  542. Assert(this->tempTransferredSyms.IsEmpty());
  543. Assert(this->elemLoadDependencies.IsEmpty());
  544. Assert(this->upwardExposedMarkTempObjectLiveFields.IsEmpty());
  545. }
  546. #endif
  547. // We don't get to process all dst in MarkTemp. Do it here for the upwardExposedMarkTempObjectLiveFields
  548. if (!this->DoMarkTempNumbersOnTempObjects(backwardPass))
  549. {
  550. return;
  551. }
  552. IR::Opnd * dst = instr->GetDst();
  553. if (dst == nullptr || !dst->IsRegOpnd())
  554. {
  555. return;
  556. }
  557. StackSym * dstSym = dst->AsRegOpnd()->m_sym;
  558. if (!dstSym->IsVar())
  559. {
  560. dstSym = dstSym->GetVarEquivSym(nullptr);
  561. if (dstSym == nullptr)
  562. {
  563. return;
  564. }
  565. }
  566. SymID dstSymId = dstSym->m_id;
  567. if (this->upwardExposedMarkTempObjectSymsProperties)
  568. {
  569. // We are assigning to dstSym, it no longer has upward exposed use, get the information and clear it from the hash table
  570. BVSparse<JitArenaAllocator> * dstBv = this->upwardExposedMarkTempObjectSymsProperties->GetAndClear(dstSymId);
  571. if (dstBv)
  572. {
  573. // Clear the upward exposed live fields of all the property sym id associated to dstSym
  574. this->upwardExposedMarkTempObjectLiveFields.Minus(dstBv);
  575. if (ObjectTemp::IsTempTransfer(instr) && instr->GetSrc1()->IsRegOpnd())
  576. {
  577. // If it is transfer, copy the dst info to the src
  578. SymID srcStackSymId = instr->GetSrc1()->AsRegOpnd()->m_sym->AsStackSym()->m_id;
  579. SymTable * symTable = backwardPass->func->m_symTable;
  580. FOREACH_BITSET_IN_SPARSEBV(index, dstBv)
  581. {
  582. PropertySym * propertySym = symTable->FindPropertySym(srcStackSymId, index);
  583. if (propertySym)
  584. {
  585. this->upwardExposedMarkTempObjectLiveFields.Set(propertySym->m_id);
  586. }
  587. }
  588. NEXT_BITSET_IN_SPARSEBV;
  589. BVSparse<JitArenaAllocator> ** srcBv = this->upwardExposedMarkTempObjectSymsProperties->FindOrInsert(dstBv, srcStackSymId);
  590. if (srcBv)
  591. {
  592. (*srcBv)->Or(dstBv);
  593. JitAdelete(this->GetAllocator(), dstBv);
  594. }
  595. }
  596. else
  597. {
  598. JitAdelete(this->GetAllocator(), dstBv);
  599. }
  600. }
  601. }
  602. }
  603. void
  604. NumberTemp::SetDstIsTemp(bool dstIsTemp, bool dstIsTempTransferred, IR::Instr * instr, BackwardPass * backwardPass)
  605. {
  606. Assert(dstIsTemp || !dstIsTempTransferred);
  607. Assert(!instr->dstIsTempNumberTransferred);
  608. instr->dstIsTempNumber = dstIsTemp;
  609. instr->dstIsTempNumberTransferred = dstIsTempTransferred;
  610. #if DBG_DUMP
  611. if (!backwardPass->IsPrePass() && IsTempProducing(instr))
  612. {
  613. backwardPass->numMarkTempNumber += dstIsTemp;
  614. backwardPass->numMarkTempNumberTransferred += dstIsTempTransferred;
  615. }
  616. #endif
  617. }
  618. bool
  619. NumberTemp::IsTempPropertyTransferLoad(IR::Instr * instr, BackwardPass * backwardPass)
  620. {
  621. if (DoMarkTempNumbersOnTempObjects(backwardPass))
  622. {
  623. switch (instr->m_opcode)
  624. {
  625. case Js::OpCode::LdFld:
  626. case Js::OpCode::LdFldForTypeOf:
  627. case Js::OpCode::LdMethodFld:
  628. case Js::OpCode::LdFldForCallApplyTarget:
  629. case Js::OpCode::LdMethodFromFlags:
  630. {
  631. // Only care about load from possible stack allocated object.
  632. return instr->GetSrc1()->CanStoreTemp();
  633. }
  634. };
  635. // All other opcode shouldn't have sym opnd that can store temp, See ObjectTemp::IsTempUseOpCodeSym.
  636. Assert(instr->GetSrc1() == nullptr
  637. || instr->GetDst() == nullptr // this isn't a value loading instruction
  638. || instr->GetSrc1()->IsIndirOpnd() // this is detected in IsTempIndirTransferLoad
  639. || !instr->GetSrc1()->CanStoreTemp());
  640. }
  641. return false;
  642. }
  643. bool
  644. NumberTemp::IsTempPropertyTransferStore(IR::Instr * instr, BackwardPass * backwardPass)
  645. {
  646. if (DoMarkTempNumbersOnTempObjects(backwardPass))
  647. {
  648. switch (instr->m_opcode)
  649. {
  650. case Js::OpCode::InitFld:
  651. case Js::OpCode::StFld:
  652. case Js::OpCode::StFldStrict:
  653. {
  654. IR::Opnd * dst = instr->GetDst();
  655. Assert(dst->IsSymOpnd());
  656. if (!dst->CanStoreTemp())
  657. {
  658. return false;
  659. }
  660. // We don't mark temp store of numeric properties (e.g. object literal { 86: foo });
  661. // This should only happen for InitFld, as StFld should have changed to StElem
  662. PropertySym *propertySym = dst->AsSymOpnd()->m_sym->AsPropertySym();
  663. SymID propertySymId = this->GetRepresentativePropertySymId(propertySym, backwardPass);
  664. return !this->nonTempSyms.Test(propertySymId) &&
  665. !instr->m_func->GetThreadContextInfo()->IsNumericProperty(propertySym->m_propertyId);
  666. }
  667. };
  668. // All other opcode shouldn't have sym opnd that can store temp, see ObjectTemp::IsTempUseOpCodeSym.
  669. // We also never mark the dst indir as can store temp for StElemI_A because we don't know what property
  670. // it is storing in (or it could be an array index).
  671. Assert(instr->GetDst() == nullptr || !instr->GetDst()->CanStoreTemp());
  672. }
  673. return false;
  674. }
  675. bool
  676. NumberTemp::IsTempIndirTransferLoad(IR::Instr * instr, BackwardPass * backwardPass)
  677. {
  678. if (DoMarkTempNumbersOnTempObjects(backwardPass))
  679. {
  680. if (instr->m_opcode == Js::OpCode::LdElemI_A)
  681. {
  682. // If the index is an int, then we don't care about the non-temp use
  683. IR::Opnd * src1Opnd = instr->GetSrc1();
  684. IR::RegOpnd * indexOpnd = src1Opnd->AsIndirOpnd()->GetIndexOpnd();
  685. if (indexOpnd && (indexOpnd->m_sym->m_isNotNumber || !indexOpnd->GetValueType().IsInt()))
  686. {
  687. return src1Opnd->CanStoreTemp();
  688. }
  689. }
  690. else
  691. {
  692. // All other opcode shouldn't have sym opnd that can store temp, See ObjectTemp::IsTempUseOpCodeSym.
  693. Assert(instr->GetSrc1() == nullptr || instr->GetSrc1()->IsSymOpnd()
  694. || !instr->GetSrc1()->CanStoreTemp());
  695. }
  696. }
  697. return false;
  698. }
  699. void
  700. NumberTemp::PropagateTempPropertyTransferStoreDependencies(SymID usedSymID, PropertySym * propertySym, BackwardPass * backwardPass)
  701. {
  702. Assert(!this->nonTempElemLoad);
  703. upwardExposedMarkTempObjectLiveFields.Clear(propertySym->m_id);
  704. if (!this->IsInLoop())
  705. {
  706. // Don't need to track dependencies outside of loop, as we already marked the
  707. // use as temp transfer already and we won't have a case where the "dst" is reused again (outside of loop)
  708. return;
  709. }
  710. Assert(this->tempTransferDependencies != nullptr);
  711. SymID dstSymID = this->GetRepresentativePropertySymId(propertySym, backwardPass);
  712. AddTransferDependencies(usedSymID, dstSymID, this->tempTransferDependencies);
  713. Js::PropertyId storedPropertyId = propertySym->m_propertyId;
  714. // The symbol this properties are transferred to
  715. BVSparse<JitArenaAllocator> ** pPropertyTransferDependencies = this->propertyIdsTempTransferDependencies->Get(storedPropertyId);
  716. BVSparse<JitArenaAllocator> * transferDependencies = nullptr;
  717. if (pPropertyTransferDependencies == nullptr)
  718. {
  719. if (elemLoadDependencies.IsEmpty())
  720. {
  721. // No dependencies to transfer
  722. return;
  723. }
  724. transferDependencies = &elemLoadDependencies;
  725. }
  726. else
  727. {
  728. transferDependencies = *pPropertyTransferDependencies;
  729. }
  730. BVSparse<JitArenaAllocator> ** pBVSparse = this->tempTransferDependencies->FindOrInsertNew(usedSymID);
  731. if (*pBVSparse == nullptr)
  732. {
  733. *pBVSparse = transferDependencies->CopyNew(this->GetAllocator());
  734. }
  735. else
  736. {
  737. (*pBVSparse)->Or(transferDependencies);
  738. }
  739. if (transferDependencies != &elemLoadDependencies)
  740. {
  741. // Always include the element load dependencies as well
  742. (*pBVSparse)->Or(&elemLoadDependencies);
  743. }
  744. // Track the propertySym as well for the case where the dependence is not carried by the use
  745. // Loop1
  746. // o.x = e
  747. // Loop2
  748. // f = o.x
  749. // = f
  750. // e = e + blah
  751. // Here, although we can detect that e and f has dependent relationship, f's life time doesn't cross with e's.
  752. // But o.x will keep the value of e alive, so e can't be mark temp because o.x is still in use (not f)
  753. // We will add the property sym int he dependency set and check with the upward exposed mark temp object live fields
  754. // that we keep track of in NumberTemp
  755. (*pBVSparse)->Set(propertySym->m_id);
  756. }
  757. SymID
  758. NumberTemp::GetRepresentativePropertySymId(PropertySym * propertySym, BackwardPass * backwardPass)
  759. {
  760. // Since we don't track alias with objects, all property accesses are all grouped together.
  761. // Use a single property sym id to represent a propertyId to track dependencies.
  762. SymID symId = SymID_Invalid;
  763. Js::PropertyId propertyId = propertySym->m_propertyId;
  764. if (!backwardPass->numberTempRepresentativePropertySym->TryGetValue(propertyId, &symId))
  765. {
  766. symId = propertySym->m_id;
  767. backwardPass->numberTempRepresentativePropertySym->Add(propertyId, symId);
  768. }
  769. return symId;
  770. }
  771. void
  772. NumberTemp::ProcessIndirUse(IR::IndirOpnd * indirOpnd, IR::Instr * instr, BackwardPass * backwardPass)
  773. {
  774. Assert(backwardPass->DoMarkTempNumbersOnTempObjects());
  775. if (!NumberTemp::IsTempIndirTransferLoad(instr, backwardPass))
  776. {
  777. return;
  778. }
  779. bool isTempUse = instr->dstIsTempNumber;
  780. if (!isTempUse)
  781. {
  782. nonTempElemLoad = true;
  783. }
  784. else if (this->IsInLoop())
  785. {
  786. // We didn't already detect non temp use of this property id. so we should track the dependencies in loops
  787. IR::Opnd * dstOpnd = instr->GetDst();
  788. Assert(dstOpnd->IsRegOpnd());
  789. SymID dstSymID = dstOpnd->AsRegOpnd()->m_sym->m_id;
  790. // Use the no property id as a place holder for elem dependencies
  791. AddTransferDependencies(&elemLoadDependencies, dstSymID);
  792. #if DBG_DUMP
  793. if (NumberTemp::DoTrace(backwardPass))
  794. {
  795. Output::Print(_u("%s: %8s s%d -> []: "), NumberTemp::GetTraceName(),
  796. backwardPass->IsPrePass() ? _u("Prepass ") : _u(""), dstSymID);
  797. elemLoadDependencies.Dump();
  798. }
  799. #endif
  800. }
  801. #if DBG_DUMP
  802. if (NumberTemp::DoTrace(backwardPass))
  803. {
  804. Output::Print(_u("%s: %8s%4sTemp Use ([] )"), NumberTemp::GetTraceName(),
  805. backwardPass->IsPrePass() ? _u("Prepass ") : _u(""), isTempUse ? _u("") : _u("Non "));
  806. instr->DumpSimple();
  807. }
  808. #endif
  809. }
  810. void
  811. NumberTemp::ProcessPropertySymUse(IR::SymOpnd * symOpnd, IR::Instr * instr, BackwardPass * backwardPass)
  812. {
  813. Assert(backwardPass->DoMarkTempNumbersOnTempObjects());
  814. // We only care about instruction that may transfer the property value
  815. if (!NumberTemp::IsTempPropertyTransferLoad(instr, backwardPass))
  816. {
  817. return;
  818. }
  819. PropertySym * propertySym = symOpnd->m_sym->AsPropertySym();
  820. upwardExposedMarkTempObjectLiveFields.Set(propertySym->m_id);
  821. if (upwardExposedMarkTempObjectSymsProperties == nullptr)
  822. {
  823. upwardExposedMarkTempObjectSymsProperties = HashTable<BVSparse<JitArenaAllocator> *>::New(this->GetAllocator(), 16);
  824. }
  825. BVSparse<JitArenaAllocator> ** bv = upwardExposedMarkTempObjectSymsProperties->FindOrInsertNew(propertySym->m_stackSym->m_id);
  826. if (*bv == nullptr)
  827. {
  828. *bv = JitAnew(this->GetAllocator(), BVSparse<JitArenaAllocator>, this->GetAllocator());
  829. }
  830. (*bv)->Set(propertySym->m_propertyId);
  831. SymID propertySymId = this->GetRepresentativePropertySymId(propertySym, backwardPass);
  832. bool isTempUse = instr->dstIsTempNumber;
  833. if (!isTempUse)
  834. {
  835. // Use of the value is non temp, track the property ID's property representative sym so we don't mark temp
  836. // assignment to this property on stack objects.
  837. this->nonTempSyms.Set(propertySymId);
  838. }
  839. else if (this->IsInLoop() && !this->nonTempSyms.Test(propertySymId))
  840. {
  841. // We didn't already detect non temp use of this property id. so we should track the dependencies in loops
  842. IR::Opnd * dstOpnd = instr->GetDst();
  843. Assert(dstOpnd->IsRegOpnd());
  844. SymID dstSymID = dstOpnd->AsRegOpnd()->m_sym->m_id;
  845. AddTransferDependencies(propertySym->m_propertyId, dstSymID, this->propertyIdsTempTransferDependencies);
  846. #if DBG_DUMP
  847. if (NumberTemp::DoTrace(backwardPass))
  848. {
  849. Output::Print(_u("%s: %8s s%d -> PropId:%d: "), NumberTemp::GetTraceName(),
  850. backwardPass->IsPrePass() ? _u("Prepass ") : _u(""), dstSymID, propertySym->m_propertyId);
  851. (*this->propertyIdsTempTransferDependencies->Get(propertySym->m_propertyId))->Dump();
  852. }
  853. #endif
  854. }
  855. #if DBG_DUMP
  856. if (NumberTemp::DoTrace(backwardPass))
  857. {
  858. Output::Print(_u("%s: %8s%4sTemp Use (PropId:%d)"), NumberTemp::GetTraceName(),
  859. backwardPass->IsPrePass() ? _u("Prepass ") : _u(""), isTempUse ? _u("") : _u("Non "), propertySym->m_propertyId);
  860. instr->DumpSimple();
  861. }
  862. #endif
  863. }
  864. bool
  865. NumberTemp::HasExposedFieldDependencies(BVSparse<JitArenaAllocator> * bvTempTransferDependencies, BackwardPass * backwardPass)
  866. {
  867. if (!DoMarkTempNumbersOnTempObjects(backwardPass))
  868. {
  869. return false;
  870. }
  871. return bvTempTransferDependencies->Test(&upwardExposedMarkTempObjectLiveFields);
  872. }
  873. bool
  874. NumberTemp::DoMarkTempNumbersOnTempObjects(BackwardPass * backwardPass) const
  875. {
  876. return backwardPass->DoMarkTempNumbersOnTempObjects() && !this->nonTempElemLoad;
  877. }
  878. #if DBG
  879. void
  880. NumberTemp::Dump(char16 const * traceName)
  881. {
  882. if (nonTempElemLoad)
  883. {
  884. Output::Print(_u("%s: Has Non Temp Elem Load\n"), traceName);
  885. }
  886. else
  887. {
  888. Output::Print(_u("%s: Non Temp Syms"), traceName);
  889. this->nonTempSyms.Dump();
  890. if (this->propertyIdsTempTransferDependencies != nullptr)
  891. {
  892. Output::Print(_u("%s: Temp transfer propertyId dependencies:\n"), traceName);
  893. this->propertyIdsTempTransferDependencies->Dump();
  894. }
  895. }
  896. }
  897. #endif
  898. //=================================================================================================
  899. // ObjectTemp
  900. //=================================================================================================
  901. bool
  902. ObjectTemp::IsTempUse(IR::Instr * instr, Sym * sym, BackwardPass * backwardPass)
  903. {
  904. Js::OpCode opcode = instr->m_opcode;
  905. // If the opcode has implicit call and the profile say we have implicit call, then it is not a temp use
  906. // TODO: More precise implicit call tracking
  907. if (instr->HasAnyImplicitCalls()
  908. &&
  909. ((backwardPass->currentBlock->loop != nullptr ?
  910. !GlobOpt::ImplicitCallFlagsAllowOpts(backwardPass->currentBlock->loop) :
  911. !GlobOpt::ImplicitCallFlagsAllowOpts(backwardPass->func))
  912. || instr->CallsAccessor())
  913. )
  914. {
  915. return false;
  916. }
  917. return IsTempUseOpCodeSym(instr, opcode, sym);
  918. }
  919. bool
  920. ObjectTemp::IsTempUseOpCodeSym(IR::Instr * instr, Js::OpCode opcode, Sym * sym)
  921. {
  922. // Special case ArgOut_A which communicate information about CallDirect
  923. switch (opcode)
  924. {
  925. case Js::OpCode::ArgOut_A:
  926. return instr->dstIsTempObject;
  927. case Js::OpCode::LdLen_A:
  928. if (instr->GetSrc1()->IsRegOpnd())
  929. {
  930. return instr->GetSrc1()->AsRegOpnd()->GetStackSym() == sym;
  931. }
  932. // fall through
  933. case Js::OpCode::LdFld:
  934. case Js::OpCode::LdFldForTypeOf:
  935. case Js::OpCode::LdMethodFld:
  936. case Js::OpCode::LdFldForCallApplyTarget:
  937. case Js::OpCode::LdMethodFromFlags:
  938. return instr->GetSrc1()->AsPropertySymOpnd()->GetObjectSym() == sym;
  939. case Js::OpCode::InitFld:
  940. if (Js::PropertyRecord::DefaultAttributesForPropertyId(
  941. instr->GetDst()->AsPropertySymOpnd()->GetPropertySym()->m_propertyId, true) & PropertyDeleted)
  942. {
  943. // If the property record is marked PropertyDeleted, the InitFld will cause a type handler conversion,
  944. // which may result in creation of a weak reference to the object itself.
  945. return false;
  946. }
  947. // Fall through
  948. case Js::OpCode::StFld:
  949. case Js::OpCode::StFldStrict:
  950. return
  951. !(instr->GetSrc1() && instr->GetSrc1()->GetStackSym() == sym) &&
  952. !(instr->GetSrc2() && instr->GetSrc2()->GetStackSym() == sym) &&
  953. instr->GetDst()->AsPropertySymOpnd()->GetObjectSym() == sym;
  954. case Js::OpCode::LdElemI_A:
  955. return instr->GetSrc1()->AsIndirOpnd()->GetBaseOpnd()->m_sym == sym;
  956. case Js::OpCode::StElemI_A:
  957. case Js::OpCode::StElemI_A_Strict:
  958. return instr->GetDst()->AsIndirOpnd()->GetBaseOpnd()->m_sym == sym && instr->GetSrc1()->GetStackSym() != sym;
  959. case Js::OpCode::Memset:
  960. return instr->GetDst()->AsIndirOpnd()->GetBaseOpnd()->m_sym == sym || (instr->GetSrc1()->IsRegOpnd() && instr->GetSrc1()->AsRegOpnd()->m_sym == sym);
  961. case Js::OpCode::Memcopy:
  962. return instr->GetDst()->AsIndirOpnd()->GetBaseOpnd()->m_sym == sym || instr->GetSrc1()->AsIndirOpnd()->GetBaseOpnd()->m_sym == sym;
  963. // Special case FromVar for now until we can allow CallsValueOf opcode to be accept temp use
  964. case Js::OpCode::FromVar:
  965. return true;
  966. }
  967. // TODO: Currently, when we disable implicit call, we still don't allow valueOf/toString that has no side effects
  968. // So we shouldn't mark them if we have use of the sym on opcode that does OpndHasImplicitCall yet.
  969. if (OpCodeAttr::OpndHasImplicitCall(opcode))
  970. {
  971. return false;
  972. }
  973. // Mark the symbol as non-tempable if the instruction doesn't allow temp sources,
  974. // or it is transferred to a non-temp dst
  975. return (OpCodeAttr::TempObjectSources(opcode)
  976. && (!OpCodeAttr::TempObjectTransfer(opcode) || instr->dstIsTempObject));
  977. }
  978. bool
  979. ObjectTemp::IsTempTransfer(IR::Instr * instr)
  980. {
  981. return OpCodeAttr::TempObjectTransfer(instr->m_opcode);
  982. }
  983. bool
  984. ObjectTemp::IsTempProducing(IR::Instr * instr)
  985. {
  986. Js::OpCode opcode = instr->m_opcode;
  987. if (OpCodeAttr::TempObjectProducing(opcode))
  988. {
  989. if (instr->m_opcode == Js::OpCode::CallDirect)
  990. {
  991. IR::HelperCallOpnd* helper = instr->GetSrc1()->AsHelperCallOpnd();
  992. return HelperMethodAttributes::TempObjectProducing(helper->m_fnHelper);
  993. }
  994. else
  995. {
  996. return true;
  997. }
  998. }
  999. // TODO: Process NewScObject and CallI with isCtorCall when the ctor is fixed
  1000. return false;
  1001. }
  1002. bool
  1003. ObjectTemp::CanStoreTemp(IR::Instr * instr)
  1004. {
  1005. // In order to allow storing temp number on temp objects,
  1006. // We have to make sure that if the instr is marked as dstIsTempObject
  1007. // we will always generate the code to allocate the object on the stack (so no helper call).
  1008. // Currently, we only do this for NewRegEx, NewScObjectSimple, NewScObjectLiteral and
  1009. // NewScObjectNoCtor (where the ctor is inlined).
  1010. // CONSIDER: review lowering of other TempObjectProducing opcode and see if we can always allocate on the stack
  1011. // (for example, NewScArray should be able to, but plain NewScObject can't because the size depends on the
  1012. // number inline slots)
  1013. Js::OpCode opcode = instr->m_opcode;
  1014. if (OpCodeAttr::TempObjectCanStoreTemp(opcode))
  1015. {
  1016. // Special cases where stack allocation doesn't happen
  1017. #if ENABLE_REGEX_CONFIG_OPTIONS
  1018. if (opcode == Js::OpCode::NewRegEx && REGEX_CONFIG_FLAG(RegexTracing))
  1019. {
  1020. return false;
  1021. }
  1022. #endif
  1023. if (opcode == Js::OpCode::NewScObjectNoCtor)
  1024. {
  1025. if (PHASE_OFF(Js::FixedNewObjPhase, instr->m_func) && PHASE_OFF(Js::ObjTypeSpecNewObjPhase, instr->m_func->GetTopFunc()))
  1026. {
  1027. return false;
  1028. }
  1029. // Only if we have BailOutFailedCtorGuardCheck would we generate a stack object.
  1030. // Otherwise we will call the helper, which will not generate stack object.
  1031. return instr->HasBailOutInfo();
  1032. }
  1033. return true;
  1034. }
  1035. return false;
  1036. }
  1037. bool
  1038. ObjectTemp::CanMarkTemp(IR::Instr * instr, BackwardPass * backwardPass)
  1039. {
  1040. // We mark the ArgOut with the call in ProcessInstr, no need to do it here
  1041. return IsTempProducing(instr) || IsTempTransfer(instr);
  1042. }
  1043. void
  1044. ObjectTemp::ProcessBailOnNoProfile(IR::Instr * instr)
  1045. {
  1046. Assert(instr->m_opcode == Js::OpCode::BailOnNoProfile);
  1047. // ObjectTemp is done during Backward pass, which hasn't change all succ to BailOnNoProfile
  1048. // to dead yet, so we need to manually clear all the information
  1049. this->nonTempSyms.ClearAll();
  1050. this->tempTransferredSyms.ClearAll();
  1051. if (this->tempTransferDependencies)
  1052. {
  1053. this->tempTransferDependencies->ClearAll();
  1054. }
  1055. }
  1056. void
  1057. ObjectTemp::ProcessInstr(IR::Instr * instr)
  1058. {
  1059. if (instr->m_opcode != Js::OpCode::CallDirect)
  1060. {
  1061. return;
  1062. }
  1063. IR::HelperCallOpnd * helper = instr->GetSrc1()->AsHelperCallOpnd();
  1064. switch (helper->m_fnHelper)
  1065. {
  1066. case IR::JnHelperMethod::HelperString_Match:
  1067. case IR::JnHelperMethod::HelperString_Replace:
  1068. {
  1069. // First (non-this) parameter is either a regexp or search string.
  1070. // It doesn't escape.
  1071. IR::Instr * instrArgDef = nullptr;
  1072. instr->FindCallArgumentOpnd(2, &instrArgDef);
  1073. instrArgDef->dstIsTempObject = true;
  1074. break;
  1075. }
  1076. case IR::JnHelperMethod::HelperRegExp_Exec:
  1077. {
  1078. IR::Instr * instrArgDef = nullptr;
  1079. instr->FindCallArgumentOpnd(1, &instrArgDef);
  1080. instrArgDef->dstIsTempObject = true;
  1081. break;
  1082. }
  1083. };
  1084. }
  1085. void
  1086. ObjectTemp::SetDstIsTemp(bool dstIsTemp, bool dstIsTempTransferred, IR::Instr * instr, BackwardPass * backwardPass)
  1087. {
  1088. Assert(dstIsTemp || !dstIsTempTransferred);
  1089. // ArgOut_A are marked by CallDirect and don't need to be set
  1090. if (instr->m_opcode == Js::OpCode::ArgOut_A)
  1091. {
  1092. return;
  1093. }
  1094. instr->dstIsTempObject = dstIsTemp;
  1095. if (!backwardPass->IsPrePass())
  1096. {
  1097. if (OpCodeAttr::TempObjectProducing(instr->m_opcode))
  1098. {
  1099. backwardPass->func->SetHasMarkTempObjects();
  1100. #if DBG_DUMP
  1101. backwardPass->numMarkTempObject += dstIsTemp;
  1102. #endif
  1103. }
  1104. }
  1105. }
  1106. StackSym *
  1107. ObjectTemp::GetStackSym(IR::Opnd * opnd, IR::PropertySymOpnd ** pPropertySymOpnd)
  1108. {
  1109. StackSym * stackSym = nullptr;
  1110. switch (opnd->GetKind())
  1111. {
  1112. case IR::OpndKindReg:
  1113. stackSym = opnd->AsRegOpnd()->m_sym;
  1114. break;
  1115. case IR::OpndKindSym:
  1116. {
  1117. IR::SymOpnd * symOpnd = opnd->AsSymOpnd();
  1118. if (symOpnd->IsPropertySymOpnd())
  1119. {
  1120. IR::PropertySymOpnd * propertySymOpnd = symOpnd->AsPropertySymOpnd();
  1121. *pPropertySymOpnd = propertySymOpnd;
  1122. stackSym = propertySymOpnd->GetObjectSym();
  1123. }
  1124. else if (symOpnd->m_sym->IsPropertySym())
  1125. {
  1126. stackSym = symOpnd->m_sym->AsPropertySym()->m_stackSym;
  1127. }
  1128. break;
  1129. }
  1130. case IR::OpndKindIndir:
  1131. stackSym = opnd->AsIndirOpnd()->GetBaseOpnd()->m_sym;
  1132. break;
  1133. case IR::OpndKindList:
  1134. Assert(UNREACHED);
  1135. break;
  1136. };
  1137. return stackSym;
  1138. }
  1139. #if DBG
  1140. //=================================================================================================
  1141. // ObjectTempVerify
  1142. //=================================================================================================
  1143. ObjectTempVerify::ObjectTempVerify(JitArenaAllocator * alloc, bool inLoop)
  1144. : TempTrackerBase(alloc, inLoop), removedUpwardExposedUse(alloc)
  1145. {
  1146. }
  1147. bool
  1148. ObjectTempVerify::IsTempUse(IR::Instr * instr, Sym * sym, BackwardPass * backwardPass)
  1149. {
  1150. Js::OpCode opcode = instr->m_opcode;
  1151. // If the opcode has implicit call and the profile say we have implicit call, then it is not a temp use.
  1152. // TODO: More precise implicit call tracking
  1153. bool isLandingPad = backwardPass->currentBlock->IsLandingPad();
  1154. if (OpCodeAttr::HasImplicitCall(opcode) && !isLandingPad
  1155. &&
  1156. ((backwardPass->currentBlock->loop != nullptr ?
  1157. !GlobOpt::ImplicitCallFlagsAllowOpts(backwardPass->currentBlock->loop) :
  1158. !GlobOpt::ImplicitCallFlagsAllowOpts(backwardPass->func))
  1159. || instr->CallsAccessor())
  1160. )
  1161. {
  1162. return false;
  1163. }
  1164. if (!ObjectTemp::IsTempUseOpCodeSym(instr, opcode, sym))
  1165. {
  1166. // the opcode and sym is not a temp use, just return
  1167. return false;
  1168. }
  1169. // In the backward pass, this would have been a temp use already. Continue to verify
  1170. // if we have install sufficient bailout on implicit call
  1171. if (isLandingPad || !GlobOpt::MayNeedBailOnImplicitCall(instr, nullptr, nullptr))
  1172. {
  1173. // Implicit call would not happen, or we are in the landing pad where implicit call is disabled.
  1174. return true;
  1175. }
  1176. if (instr->HasBailOutInfo())
  1177. {
  1178. // make sure we have mark the bailout for mark temp object,
  1179. // so that we won't optimize it away in DeadStoreImplicitCalls
  1180. return ((instr->GetBailOutKind() & IR::BailOutMarkTempObject) != 0);
  1181. }
  1182. // Review (ObjTypeSpec): This is a bit conservative now that we don't revert from obj type specialized operations to live cache
  1183. // access even if the operation is isolated. Once we decide a given instruction is an object type spec candidate, we know it
  1184. // will never need an implicit call, so we could basically do opnd->IsObjTypeSpecOptimized() here, instead.
  1185. if (GlobOpt::IsTypeCheckProtected(instr))
  1186. {
  1187. return true;
  1188. }
  1189. return false;
  1190. }
  1191. bool
  1192. ObjectTempVerify::IsTempTransfer(IR::Instr * instr)
  1193. {
  1194. if (ObjectTemp::IsTempTransfer(instr)
  1195. // Add the Ld_I4, and LdC_A_I4 as the forward pass might have changed Ld_A to these
  1196. || instr->m_opcode == Js::OpCode::Ld_I4
  1197. || instr->m_opcode == Js::OpCode::LdC_A_I4)
  1198. {
  1199. if (!instr->dstIsTempObject && instr->GetDst() && instr->GetDst()->IsRegOpnd()
  1200. && instr->GetDst()->AsRegOpnd()->GetValueType().IsNotObject())
  1201. {
  1202. // Globopt has proved that dst is not an object, so this is not really an object transfer.
  1203. // This prevents the case where glob opt turned a Conv_Num to Ld_A and expose additional
  1204. // transfer.
  1205. return false;
  1206. }
  1207. return true;
  1208. }
  1209. return false;
  1210. }
  1211. bool
  1212. ObjectTempVerify::CanMarkTemp(IR::Instr * instr, BackwardPass * backwardPass)
  1213. {
  1214. // We mark the ArgOut with the call in ProcessInstr, no need to do it here
  1215. return ObjectTemp::IsTempProducing(instr)
  1216. || IsTempTransfer(instr);
  1217. }
  1218. void
  1219. ObjectTempVerify::ProcessInstr(IR::Instr * instr, BackwardPass * backwardPass)
  1220. {
  1221. if (instr->m_opcode == Js::OpCode::InlineThrow)
  1222. {
  1223. // We cannot accurately track mark temp for any upward exposed symbol here
  1224. this->removedUpwardExposedUse.Or(backwardPass->currentBlock->byteCodeUpwardExposedUsed);
  1225. return;
  1226. }
  1227. if (instr->m_opcode != Js::OpCode::CallDirect)
  1228. {
  1229. return;
  1230. }
  1231. IR::HelperCallOpnd * helper = instr->GetSrc1()->AsHelperCallOpnd();
  1232. switch (helper->m_fnHelper)
  1233. {
  1234. case IR::JnHelperMethod::HelperString_Match:
  1235. case IR::JnHelperMethod::HelperString_Replace:
  1236. {
  1237. // First (non-this) parameter is either a regexp or search string
  1238. // It doesn't escape
  1239. IR::Instr * instrArgDef;
  1240. instr->FindCallArgumentOpnd(2, &instrArgDef);
  1241. Assert(instrArgDef->dstIsTempObject);
  1242. break;
  1243. }
  1244. case IR::JnHelperMethod::HelperRegExp_Exec:
  1245. {
  1246. IR::Instr * instrArgDef;
  1247. instr->FindCallArgumentOpnd(1, &instrArgDef);
  1248. Assert(instrArgDef->dstIsTempObject);
  1249. break;
  1250. }
  1251. };
  1252. }
  1253. void
  1254. ObjectTempVerify::SetDstIsTemp(bool dstIsTemp, bool dstIsTempTransferred, IR::Instr * instr, BackwardPass * backwardPass)
  1255. {
  1256. Assert(dstIsTemp || !dstIsTempTransferred);
  1257. // ArgOut_A are marked by CallDirect and don't need to be set
  1258. if (instr->m_opcode == Js::OpCode::ArgOut_A)
  1259. {
  1260. return;
  1261. }
  1262. if (OpCodeAttr::TempObjectProducing(instr->m_opcode))
  1263. {
  1264. if (!backwardPass->IsPrePass())
  1265. {
  1266. if (dstIsTemp)
  1267. {
  1268. // Don't assert if we have detected a removed upward exposed use that could
  1269. // expose a new mark temp object. Don't assert if it is set in removedUpwardExposedUse
  1270. bool isBailOnNoProfileUpwardExposedUse =
  1271. !!this->removedUpwardExposedUse.Test(instr->GetDst()->AsRegOpnd()->m_sym->m_id);
  1272. #if DBG
  1273. if (DoTrace(backwardPass) && !instr->dstIsTempObject && !isBailOnNoProfileUpwardExposedUse)
  1274. {
  1275. Output::Print(_u("%s: Missed Mark Temp Object: "), GetTraceName());
  1276. instr->DumpSimple();
  1277. Output::Flush();
  1278. }
  1279. #endif
  1280. // TODO: Unfortunately we still hit this a lot as we are not accounting for some of the globopt changes
  1281. // to the IR. It is just reporting that we have missed mark temp object opportunity, so it doesn't
  1282. // indicate a functional failure. Disable for now.
  1283. // Assert(instr->dstIsTempObject || isBailOnNoProfileUpwardExposedUse);
  1284. }
  1285. else
  1286. {
  1287. // If we have marked the dst is temp in the backward pass, the globopt
  1288. // should have maintained it, and it will be wrong to have detect that it is not
  1289. // temp now in the deadstore pass (whether there is BailOnNoProfile or not)
  1290. #if DBG
  1291. if (DoTrace(backwardPass) && instr->dstIsTempObject)
  1292. {
  1293. Output::Print(_u("%s: Invalid Mark Temp Object: "), GetTraceName());
  1294. instr->DumpSimple();
  1295. Output::Flush();
  1296. }
  1297. #endif
  1298. Assert(!instr->dstIsTempObject);
  1299. }
  1300. }
  1301. }
  1302. else if (IsTempTransfer(instr))
  1303. {
  1304. // Only set the transfer
  1305. instr->dstIsTempObject = dstIsTemp;
  1306. }
  1307. else
  1308. {
  1309. Assert(!dstIsTemp);
  1310. Assert(!instr->dstIsTempObject);
  1311. }
  1312. // clear or transfer the bailOnNoProfile upward exposed use
  1313. if (this->removedUpwardExposedUse.TestAndClear(instr->GetDst()->AsRegOpnd()->m_sym->m_id)
  1314. && IsTempTransfer(instr) && instr->GetSrc1()->IsRegOpnd())
  1315. {
  1316. this->removedUpwardExposedUse.Set(instr->GetSrc1()->AsRegOpnd()->m_sym->m_id);
  1317. }
  1318. }
  1319. void
  1320. ObjectTempVerify::MergeData(ObjectTempVerify * fromData, bool deleteData)
  1321. {
  1322. this->removedUpwardExposedUse.Or(&fromData->removedUpwardExposedUse);
  1323. }
  1324. void
  1325. ObjectTempVerify::MergeDeadData(BasicBlock * block)
  1326. {
  1327. MergeData(block->tempObjectVerifyTracker, false);
  1328. if (!block->isDead)
  1329. {
  1330. // If there was dead flow to a block that is not dead, it might expose
  1331. // new mark temp object, so all its current used (upwardExposedUsed) and optimized
  1332. // use (byteCodeupwardExposedUsed) might not be trace for "missed" mark temp object
  1333. this->removedUpwardExposedUse.Or(block->upwardExposedUses);
  1334. if (block->byteCodeUpwardExposedUsed)
  1335. {
  1336. this->removedUpwardExposedUse.Or(block->byteCodeUpwardExposedUsed);
  1337. }
  1338. }
  1339. }
  1340. void
  1341. ObjectTempVerify::NotifyBailOutRemoval(IR:: Instr * instr, BackwardPass * backwardPass)
  1342. {
  1343. Js::OpCode opcode = instr->m_opcode;
  1344. switch (opcode)
  1345. {
  1346. case Js::OpCode::LdFld:
  1347. case Js::OpCode::LdFldForTypeOf:
  1348. case Js::OpCode::LdMethodFld:
  1349. ((TempTracker<ObjectTempVerify> *)this)->ProcessUse(instr->GetSrc1()->AsPropertySymOpnd()->GetObjectSym(), backwardPass);
  1350. break;
  1351. case Js::OpCode::InitFld:
  1352. case Js::OpCode::StFld:
  1353. case Js::OpCode::StFldStrict:
  1354. ((TempTracker<ObjectTempVerify> *)this)->ProcessUse(instr->GetDst()->AsPropertySymOpnd()->GetObjectSym(), backwardPass);
  1355. break;
  1356. case Js::OpCode::LdElemI_A:
  1357. ((TempTracker<ObjectTempVerify> *)this)->ProcessUse(instr->GetSrc1()->AsIndirOpnd()->GetBaseOpnd()->m_sym, backwardPass);
  1358. break;
  1359. case Js::OpCode::StElemI_A:
  1360. ((TempTracker<ObjectTempVerify> *)this)->ProcessUse(instr->GetDst()->AsIndirOpnd()->GetBaseOpnd()->m_sym, backwardPass);
  1361. break;
  1362. }
  1363. }
  1364. void
  1365. ObjectTempVerify::NotifyReverseCopyProp(IR::Instr * instr)
  1366. {
  1367. Assert(instr->GetDst());
  1368. SymID symId = instr->GetDst()->AsRegOpnd()->m_sym->m_id;
  1369. this->removedUpwardExposedUse.Clear(symId);
  1370. this->nonTempSyms.Clear(symId);
  1371. }
  1372. void
  1373. ObjectTempVerify::NotifyDeadStore(IR::Instr * instr, BackwardPass * backwardPass)
  1374. {
  1375. // Even if we dead store, simulate the uses
  1376. IR::Opnd * src1 = instr->GetSrc1();
  1377. if (src1)
  1378. {
  1379. IR::PropertySymOpnd * propertySymOpnd;
  1380. StackSym * stackSym = ObjectTemp::GetStackSym(src1, &propertySymOpnd);
  1381. if (stackSym)
  1382. {
  1383. ((TempTracker<ObjectTempVerify> *)this)->ProcessUse(stackSym, backwardPass);
  1384. }
  1385. IR::Opnd * src2 = instr->GetSrc2();
  1386. if (src2)
  1387. {
  1388. stackSym = ObjectTemp::GetStackSym(src2, &propertySymOpnd);
  1389. if (stackSym)
  1390. {
  1391. ((TempTracker<ObjectTempVerify> *)this)->ProcessUse(stackSym, backwardPass);
  1392. }
  1393. }
  1394. }
  1395. }
  1396. void
  1397. ObjectTempVerify::NotifyDeadByteCodeUses(IR::Instr * instr)
  1398. {
  1399. if (instr->GetDst())
  1400. {
  1401. SymID symId = instr->GetDst()->AsRegOpnd()->m_sym->m_id;
  1402. this->removedUpwardExposedUse.Clear(symId);
  1403. this->nonTempSyms.Clear(symId);
  1404. }
  1405. IR::ByteCodeUsesInstr *byteCodeUsesInstr = instr->AsByteCodeUsesInstr();
  1406. const BVSparse<JitArenaAllocator> * byteCodeUpwardExposedUsed = byteCodeUsesInstr->GetByteCodeUpwardExposedUsed();
  1407. if (byteCodeUpwardExposedUsed != nullptr)
  1408. {
  1409. this->removedUpwardExposedUse.Or(byteCodeUpwardExposedUsed);
  1410. }
  1411. }
  1412. bool
  1413. ObjectTempVerify::DependencyCheck(IR::Instr * instr, BVSparse<JitArenaAllocator> * bvTempTransferDependencies, BackwardPass * backwardPass)
  1414. {
  1415. if (!instr->dstIsTempObject)
  1416. {
  1417. // The instruction is not marked as temp object anyway, no need to do extra check
  1418. return false;
  1419. }
  1420. // Since our algorithm is conservative, there are cases where even though two defs are unrelated, the use will still
  1421. // seem like overlapping and not mark-temp-able
  1422. // For example:
  1423. // = s6.blah
  1424. // s1 = LdRootFld
  1425. // s6 = s1
  1426. // s1 = NewScObject // s1 is dependent of s6, and s6 is upward exposed.
  1427. // = s6.blah
  1428. // s6 = s1
  1429. // Here, although s1 is mark temp able because the s6.blah use is not related, we only know that s1 is dependent of s6
  1430. // so it looks like s1 may overlap through the iterations. The backward pass will be able to catch that and not mark temp them
  1431. // However, the globopt may create situation like the above while it wasn't there in the backward phase
  1432. // For example:
  1433. // = s6.blah
  1434. // s1 = LdRootFld g
  1435. // s6 = s1
  1436. // s1 = NewScObject
  1437. // s7 = LdRootFld g
  1438. // = s7.blah // Globopt copy prop s7 -> s6, creating the example above.
  1439. // s6 = s1
  1440. // This make it impossible to verify whether we did the right thing using the conservative algorithm.
  1441. // Luckily, this case is very rare (ExprGen didn't hit it with > 100K test cases)
  1442. // So we can use this rather expensive algorithm to find out if any of upward exposed used that we think overlaps
  1443. // really get their value from the marked temp sym or not.
  1444. // See unittest\Object\stackobject_dependency.js (with -maxinterpretcount:1 -off:inline)
  1445. BasicBlock * currentBlock = backwardPass->currentBlock;
  1446. BVSparse<JitArenaAllocator> * upwardExposedUses = currentBlock->upwardExposedUses;
  1447. JitArenaAllocator tempAllocator(_u("temp"), instr->m_func->m_alloc->GetPageAllocator(), Js::Throw::OutOfMemory);
  1448. BVSparse<JitArenaAllocator> * dependentSyms = bvTempTransferDependencies->AndNew(upwardExposedUses, &tempAllocator);
  1449. BVSparse<JitArenaAllocator> * initialDependentSyms = dependentSyms->CopyNew();
  1450. Assert(!dependentSyms->IsEmpty());
  1451. struct BlockRecord
  1452. {
  1453. BasicBlock * block;
  1454. BVSparse<JitArenaAllocator> * dependentSyms;
  1455. };
  1456. SList<BlockRecord> blockStack(&tempAllocator);
  1457. JsUtil::BaseDictionary<BasicBlock *, BVSparse<JitArenaAllocator> *, JitArenaAllocator> processedSyms(&tempAllocator);
  1458. IR::Instr * currentInstr = instr;
  1459. Assert(instr->GetDst()->AsRegOpnd()->m_sym->IsVar());
  1460. SymID markTempSymId = instr->GetDst()->AsRegOpnd()->m_sym->m_id;
  1461. bool initial = true;
  1462. while (true)
  1463. {
  1464. while (currentInstr != currentBlock->GetFirstInstr())
  1465. {
  1466. if (initial)
  1467. {
  1468. initial = false;
  1469. }
  1470. else if (currentInstr == instr)
  1471. {
  1472. if (dependentSyms->Test(markTempSymId))
  1473. {
  1474. // One of the dependent sym from the original set get it's value from the current marked temp dst.
  1475. // The dst definitely cannot be temp because it's lifetime overlaps across iterations.
  1476. return false;
  1477. }
  1478. // If we have already check the same dependent sym, no need to do it again.
  1479. // It will produce the same result anyway.
  1480. dependentSyms->Minus(initialDependentSyms);
  1481. if (dependentSyms->IsEmpty())
  1482. {
  1483. break;
  1484. }
  1485. // Add in newly discovered dependentSym so we won't do it again when it come back here.
  1486. initialDependentSyms->Or(dependentSyms);
  1487. }
  1488. if (currentInstr->GetDst() && currentInstr->GetDst()->IsRegOpnd())
  1489. {
  1490. // Clear the def and mark the src if it is transferred.
  1491. // If the dst sym is a type specialized sym, clear the var sym instead.
  1492. StackSym * dstSym = currentInstr->GetDst()->AsRegOpnd()->m_sym;
  1493. if (!dstSym->IsVar())
  1494. {
  1495. dstSym = dstSym->GetVarEquivSym(nullptr);
  1496. }
  1497. if (dstSym && dependentSyms->TestAndClear(dstSym->m_id) &&
  1498. IsTempTransfer(currentInstr) && currentInstr->GetSrc1()->IsRegOpnd())
  1499. {
  1500. // We only really care about var syms uses for object temp.
  1501. StackSym * srcSym = currentInstr->GetSrc1()->AsRegOpnd()->m_sym;
  1502. if (srcSym->IsVar())
  1503. {
  1504. dependentSyms->Set(srcSym->m_id);
  1505. }
  1506. }
  1507. if (dependentSyms->IsEmpty())
  1508. {
  1509. // No more dependent sym, we found the def of all of them we can move on to the next block.
  1510. break;
  1511. }
  1512. }
  1513. currentInstr = currentInstr->m_prev;
  1514. }
  1515. if (currentBlock->isLoopHeader && !dependentSyms->IsEmpty())
  1516. {
  1517. Assert(currentInstr == currentBlock->GetFirstInstr());
  1518. // If we have try to propagate the symbol through the loop before, we don't need to propagate it again.
  1519. BVSparse<JitArenaAllocator> * currentLoopProcessedSyms = processedSyms.Lookup(currentBlock, nullptr);
  1520. if (currentLoopProcessedSyms == nullptr)
  1521. {
  1522. processedSyms.Add(currentBlock, dependentSyms->CopyNew());
  1523. }
  1524. else
  1525. {
  1526. dependentSyms->Minus(currentLoopProcessedSyms);
  1527. currentLoopProcessedSyms->Or(dependentSyms);
  1528. }
  1529. }
  1530. if (!dependentSyms->IsEmpty())
  1531. {
  1532. Assert(currentInstr == currentBlock->GetFirstInstr());
  1533. FOREACH_PREDECESSOR_BLOCK(predBlock, currentBlock)
  1534. {
  1535. if (predBlock->loop == nullptr)
  1536. {
  1537. // No need to track outside of loops.
  1538. continue;
  1539. }
  1540. BlockRecord record;
  1541. record.block = predBlock;
  1542. record.dependentSyms = dependentSyms->CopyNew();
  1543. blockStack.Prepend(record);
  1544. }
  1545. NEXT_PREDECESSOR_BLOCK;
  1546. }
  1547. JitAdelete(&tempAllocator, dependentSyms);
  1548. if (blockStack.Empty())
  1549. {
  1550. // No more blocks. We are done.
  1551. break;
  1552. }
  1553. currentBlock = blockStack.Head().block;
  1554. dependentSyms = blockStack.Head().dependentSyms;
  1555. blockStack.RemoveHead();
  1556. currentInstr = currentBlock->GetLastInstr();
  1557. }
  1558. // All the dependent sym doesn't get their value from the marked temp def, so it can really be marked temp.
  1559. #if DBG
  1560. if (DoTrace(backwardPass))
  1561. {
  1562. Output::Print(_u("%s: Unrelated overlap mark temp (s%-3d): "), GetTraceName(), markTempSymId);
  1563. instr->DumpSimple();
  1564. Output::Flush();
  1565. }
  1566. #endif
  1567. return true;
  1568. }
  1569. #endif
  1570. #if DBG
  1571. bool
  1572. NumberTemp::DoTrace(BackwardPass * backwardPass)
  1573. {
  1574. return PHASE_TRACE(Js::MarkTempNumberPhase, backwardPass->func);
  1575. }
  1576. bool
  1577. ObjectTemp::DoTrace(BackwardPass * backwardPass)
  1578. {
  1579. return PHASE_TRACE(Js::MarkTempObjectPhase, backwardPass->func);
  1580. }
  1581. bool
  1582. ObjectTempVerify::DoTrace(BackwardPass * backwardPass)
  1583. {
  1584. return PHASE_TRACE(Js::MarkTempObjectPhase, backwardPass->func);
  1585. }
  1586. #endif
  1587. // explicit instantiation
  1588. template class TempTracker<NumberTemp>;
  1589. template class TempTracker<ObjectTemp>;
  1590. #if DBG
  1591. template class TempTracker<ObjectTempVerify>;
  1592. #endif