TempTracker.cpp 61 KB

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