Encoder.cpp 61 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558
  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. #include "Core/CRC.h"
  7. #include "NativeEntryPointData.h"
  8. #include "JitTransferData.h"
  9. ///----------------------------------------------------------------------------
  10. ///
  11. /// Encoder::Encode
  12. ///
  13. /// Main entrypoint of encoder. Encode each IR instruction into the
  14. /// appropriate machine encoding.
  15. ///
  16. ///----------------------------------------------------------------------------
  17. void
  18. Encoder::Encode()
  19. {
  20. NoRecoverMemoryArenaAllocator localArena(_u("BE-Encoder"), m_func->m_alloc->GetPageAllocator(), Js::Throw::OutOfMemory);
  21. m_tempAlloc = &localArena;
  22. #if ENABLE_OOP_NATIVE_CODEGEN
  23. class AutoLocalAlloc {
  24. public:
  25. AutoLocalAlloc(Func * func) : localXdataAddr(nullptr), localAddress(nullptr), segment(nullptr), func(func) { }
  26. ~AutoLocalAlloc()
  27. {
  28. if (localAddress)
  29. {
  30. this->func->GetOOPThreadContext()->GetCodePageAllocators()->FreeLocal(this->localAddress, this->segment);
  31. }
  32. if (localXdataAddr)
  33. {
  34. this->func->GetOOPThreadContext()->GetCodePageAllocators()->FreeLocal(this->localXdataAddr, this->segment);
  35. }
  36. }
  37. Func * func;
  38. char * localXdataAddr;
  39. char * localAddress;
  40. void * segment;
  41. } localAlloc(m_func);
  42. #endif
  43. uint32 instrCount = m_func->GetInstrCount();
  44. size_t totalJmpTableSizeInBytes = 0;
  45. JmpTableList * jumpTableListForSwitchStatement = nullptr;
  46. m_encoderMD.Init(this);
  47. m_encodeBufferSize = UInt32Math::Mul(instrCount, MachMaxInstrSize);
  48. m_encodeBufferSize += m_func->m_totalJumpTableSizeInBytesForSwitchStatements;
  49. m_encodeBuffer = AnewArray(m_tempAlloc, BYTE, m_encodeBufferSize);
  50. #if DBG_DUMP
  51. m_instrNumber = 0;
  52. m_offsetBuffer = AnewArray(m_tempAlloc, uint, instrCount);
  53. #endif
  54. m_pragmaInstrToRecordMap = Anew(m_tempAlloc, PragmaInstrList, m_tempAlloc);
  55. if (DoTrackAllStatementBoundary())
  56. {
  57. // Create a new list, if we are tracking all statement boundaries.
  58. m_pragmaInstrToRecordOffset = Anew(m_tempAlloc, PragmaInstrList, m_tempAlloc);
  59. }
  60. else
  61. {
  62. // Set the list to the same as the throw map list, so that processing of the list
  63. // of pragma are done on those only.
  64. m_pragmaInstrToRecordOffset = m_pragmaInstrToRecordMap;
  65. }
  66. #if defined(_M_IX86) || defined(_M_X64)
  67. // for BR shortening
  68. m_inlineeFrameRecords = Anew(m_tempAlloc, InlineeFrameRecords, m_tempAlloc);
  69. #endif
  70. m_pc = m_encodeBuffer;
  71. m_inlineeFrameMap = Anew(m_tempAlloc, ArenaInlineeFrameMap, m_tempAlloc);
  72. m_bailoutRecordMap = Anew(m_tempAlloc, ArenaBailoutRecordMap, m_tempAlloc);
  73. IR::PragmaInstr* pragmaInstr = nullptr;
  74. uint32 pragmaOffsetInBuffer = 0;
  75. #ifdef _M_X64
  76. bool inProlog = false;
  77. #endif
  78. bool isCallInstr = false;
  79. // CRC Check to ensure the integrity of the encoded bytes.
  80. uint initialCRCSeed = 0;
  81. errno_t err = rand_s(&initialCRCSeed);
  82. if (err != 0)
  83. {
  84. Fatal();
  85. }
  86. uint bufferCRC = initialCRCSeed;
  87. FOREACH_INSTR_IN_FUNC(instr, m_func)
  88. {
  89. Assert(Lowerer::ValidOpcodeAfterLower(instr, m_func));
  90. if (GetCurrentOffset() + MachMaxInstrSize < m_encodeBufferSize)
  91. {
  92. ptrdiff_t count;
  93. #if DBG_DUMP
  94. AssertMsg(m_instrNumber < instrCount, "Bad instr count?");
  95. __analysis_assume(m_instrNumber < instrCount);
  96. m_offsetBuffer[m_instrNumber++] = GetCurrentOffset();
  97. #endif
  98. if (instr->IsPragmaInstr())
  99. {
  100. switch (instr->m_opcode)
  101. {
  102. #ifdef _M_X64
  103. case Js::OpCode::PrologStart:
  104. m_func->m_prologEncoder.Begin(m_pc - m_encodeBuffer);
  105. inProlog = true;
  106. continue;
  107. case Js::OpCode::PrologEnd:
  108. m_func->m_prologEncoder.End();
  109. inProlog = false;
  110. continue;
  111. #endif
  112. case Js::OpCode::StatementBoundary:
  113. pragmaOffsetInBuffer = GetCurrentOffset();
  114. pragmaInstr = instr->AsPragmaInstr();
  115. pragmaInstr->m_offsetInBuffer = pragmaOffsetInBuffer;
  116. // will record after BR shortening with adjusted offsets
  117. if (DoTrackAllStatementBoundary())
  118. {
  119. m_pragmaInstrToRecordOffset->Add(pragmaInstr);
  120. }
  121. break;
  122. default:
  123. continue;
  124. }
  125. }
  126. else if (instr->IsBranchInstr() && instr->AsBranchInstr()->IsMultiBranch())
  127. {
  128. Assert(instr->GetSrc1() && instr->GetSrc1()->IsRegOpnd());
  129. IR::MultiBranchInstr * multiBranchInstr = instr->AsBranchInstr()->AsMultiBrInstr();
  130. if (multiBranchInstr->m_isSwitchBr &&
  131. (multiBranchInstr->m_kind == IR::MultiBranchInstr::IntJumpTable || multiBranchInstr->m_kind == IR::MultiBranchInstr::SingleCharStrJumpTable))
  132. {
  133. BranchJumpTableWrapper * branchJumpTableWrapper = multiBranchInstr->GetBranchJumpTable();
  134. if (jumpTableListForSwitchStatement == nullptr)
  135. {
  136. jumpTableListForSwitchStatement = Anew(m_tempAlloc, JmpTableList, m_tempAlloc);
  137. }
  138. jumpTableListForSwitchStatement->Add(branchJumpTableWrapper);
  139. totalJmpTableSizeInBytes += (branchJumpTableWrapper->tableSize * sizeof(void*));
  140. }
  141. else
  142. {
  143. //Reloc Records
  144. EncoderMD * encoderMD = &(this->m_encoderMD);
  145. multiBranchInstr->MapMultiBrTargetByAddress([=](void ** offset) -> void
  146. {
  147. #if defined(_M_ARM32_OR_ARM64)
  148. encoderMD->AddLabelReloc((byte*)offset);
  149. #else
  150. encoderMD->AppendRelocEntry(RelocTypeLabelUse, (void*)(offset), *(IR::LabelInstr**)(offset));
  151. *((size_t*)offset) = 0;
  152. #endif
  153. });
  154. }
  155. }
  156. else
  157. {
  158. isCallInstr = LowererMD::IsCall(instr);
  159. if (pragmaInstr && (instr->isInlineeEntryInstr || isCallInstr))
  160. {
  161. // will record throw map after BR shortening with adjusted offsets
  162. m_pragmaInstrToRecordMap->Add(pragmaInstr);
  163. pragmaInstr = nullptr; // Only once per pragma instr -- do we need to make this record?
  164. }
  165. if (instr->HasBailOutInfo())
  166. {
  167. Assert(this->m_func->hasBailout);
  168. Assert(LowererMD::IsCall(instr));
  169. instr->GetBailOutInfo()->FinalizeBailOutRecord(this->m_func);
  170. }
  171. if (instr->isInlineeEntryInstr)
  172. {
  173. m_encoderMD.EncodeInlineeCallInfo(instr, GetCurrentOffset());
  174. }
  175. if (instr->m_opcode == Js::OpCode::InlineeStart)
  176. {
  177. Assert(!instr->isInlineeEntryInstr);
  178. if (pragmaInstr)
  179. {
  180. m_pragmaInstrToRecordMap->Add(pragmaInstr);
  181. pragmaInstr = nullptr;
  182. }
  183. Func* inlinee = instr->m_func;
  184. if (inlinee->frameInfo && inlinee->frameInfo->record)
  185. {
  186. inlinee->frameInfo->record->Finalize(inlinee, GetCurrentOffset());
  187. #if defined(_M_IX86) || defined(_M_X64)
  188. // Store all records to be adjusted for BR shortening
  189. m_inlineeFrameRecords->Add(inlinee->frameInfo->record);
  190. #endif
  191. }
  192. continue;
  193. }
  194. }
  195. count = m_encoderMD.Encode(instr, m_pc, m_encodeBuffer);
  196. #if defined(_M_IX86) || defined(_M_X64)
  197. bufferCRC = CalculateCRC(bufferCRC, count, m_pc);
  198. #endif
  199. #if DBG_DUMP
  200. if (PHASE_TRACE(Js::EncoderPhase, this->m_func))
  201. {
  202. instr->Dump((IRDumpFlags)(IRDumpFlags_SimpleForm | IRDumpFlags_SkipEndLine | IRDumpFlags_SkipByteCodeOffset));
  203. Output::SkipToColumn(80);
  204. for (BYTE * current = m_pc; current < m_pc + count; current++)
  205. {
  206. Output::Print(_u("%02X "), *current);
  207. }
  208. Output::Print(_u("\n"));
  209. Output::Flush();
  210. }
  211. #endif
  212. #ifdef _M_X64
  213. if (inProlog)
  214. m_func->m_prologEncoder.EncodeInstr(instr, count & 0xFF);
  215. #endif
  216. m_pc += count;
  217. #if defined(_M_IX86) || defined(_M_X64)
  218. // for BR shortening.
  219. if (instr->isInlineeEntryInstr)
  220. m_encoderMD.AppendRelocEntry(RelocType::RelocTypeInlineeEntryOffset, (void*)(m_pc - MachPtr));
  221. #endif
  222. if (isCallInstr)
  223. {
  224. isCallInstr = false;
  225. this->RecordInlineeFrame(instr->m_func, GetCurrentOffset());
  226. }
  227. if (instr->HasBailOutInfo() && Lowerer::DoLazyBailout(this->m_func))
  228. {
  229. this->RecordBailout(instr, (uint32)(m_pc - m_encodeBuffer));
  230. }
  231. }
  232. else
  233. {
  234. Fatal();
  235. }
  236. } NEXT_INSTR_IN_FUNC;
  237. ptrdiff_t codeSize = m_pc - m_encodeBuffer + totalJmpTableSizeInBytes;
  238. BOOL isSuccessBrShortAndLoopAlign = false;
  239. #if defined(_M_IX86) || defined(_M_X64)
  240. // Shorten branches. ON by default
  241. if (!PHASE_OFF(Js::BrShortenPhase, m_func))
  242. {
  243. uint brShortenedbufferCRC = initialCRCSeed;
  244. isSuccessBrShortAndLoopAlign = ShortenBranchesAndLabelAlign(&m_encodeBuffer, &codeSize, &brShortenedbufferCRC, bufferCRC, totalJmpTableSizeInBytes);
  245. if (isSuccessBrShortAndLoopAlign)
  246. {
  247. bufferCRC = brShortenedbufferCRC;
  248. }
  249. }
  250. #endif
  251. #if DBG_DUMP | defined(VTUNE_PROFILING)
  252. if (this->m_func->DoRecordNativeMap())
  253. {
  254. // Record PragmaInstr offsets and throw maps
  255. for (int32 i = 0; i < m_pragmaInstrToRecordOffset->Count(); i++)
  256. {
  257. IR::PragmaInstr *inst = m_pragmaInstrToRecordOffset->Item(i);
  258. inst->Record(inst->m_offsetInBuffer);
  259. }
  260. }
  261. #endif
  262. if (m_pragmaInstrToRecordMap->Count() > 0)
  263. {
  264. if (m_func->IsOOPJIT())
  265. {
  266. int allocSize = m_pragmaInstrToRecordMap->Count();
  267. Js::ThrowMapEntry * throwMap = NativeCodeDataNewArrayNoFixup(m_func->GetNativeCodeDataAllocator(), Js::ThrowMapEntry, allocSize);
  268. for (int i = 0; i < allocSize; i++)
  269. {
  270. IR::PragmaInstr *inst = m_pragmaInstrToRecordMap->Item(i);
  271. throwMap[i].nativeBufferOffset = inst->m_offsetInBuffer;
  272. throwMap[i].statementIndex = inst->m_statementIndex;
  273. }
  274. m_func->GetJITOutput()->RecordThrowMap(throwMap, m_pragmaInstrToRecordMap->Count());
  275. }
  276. else
  277. {
  278. auto entryPointInfo = m_func->GetInProcJITEntryPointInfo();
  279. auto functionBody = entryPointInfo->GetFunctionBody();
  280. Js::SmallSpanSequenceIter iter;
  281. for (int32 i = 0; i < m_pragmaInstrToRecordMap->Count(); i++)
  282. {
  283. IR::PragmaInstr *inst = m_pragmaInstrToRecordMap->Item(i);
  284. functionBody->RecordNativeThrowMap(iter, inst->m_offsetInBuffer, inst->m_statementIndex, entryPointInfo, Js::LoopHeader::NoLoop);
  285. }
  286. }
  287. }
  288. BEGIN_CODEGEN_PHASE(m_func, Js::EmitterPhase);
  289. // Copy to permanent buffer.
  290. Assert(Math::FitsInDWord(codeSize));
  291. ushort xdataSize;
  292. ushort pdataCount;
  293. #ifdef _M_X64
  294. pdataCount = 1;
  295. xdataSize = (ushort)m_func->m_prologEncoder.SizeOfUnwindInfo();
  296. #elif defined(_M_ARM64)
  297. pdataCount = 1;
  298. xdataSize = XDATA_SIZE;
  299. #elif defined(_M_ARM)
  300. pdataCount = (ushort)m_func->m_unwindInfo.GetPDataCount(codeSize);
  301. xdataSize = (UnwindInfoManager::MaxXdataBytes + 3) * pdataCount;
  302. #else
  303. xdataSize = 0;
  304. pdataCount = 0;
  305. #endif
  306. OUTPUT_VERBOSE_TRACE(Js::EmitterPhase, _u("PDATA count:%u\n"), pdataCount);
  307. OUTPUT_VERBOSE_TRACE(Js::EmitterPhase, _u("Size of XDATA:%u\n"), xdataSize);
  308. OUTPUT_VERBOSE_TRACE(Js::EmitterPhase, _u("Size of code:%u\n"), codeSize);
  309. TryCopyAndAddRelocRecordsForSwitchJumpTableEntries(m_encodeBuffer, codeSize, jumpTableListForSwitchStatement, totalJmpTableSizeInBytes);
  310. CustomHeap::Allocation * allocation = nullptr;
  311. bool inPrereservedRegion = false;
  312. char * localAddress = nullptr;
  313. #if ENABLE_OOP_NATIVE_CODEGEN
  314. if (JITManager::GetJITManager()->IsJITServer())
  315. {
  316. EmitBufferAllocation<SectionAllocWrapper, PreReservedSectionAllocWrapper> * alloc = m_func->GetJITOutput()->RecordOOPNativeCodeSize(m_func, (DWORD)codeSize, pdataCount, xdataSize);
  317. allocation = alloc->allocation;
  318. inPrereservedRegion = alloc->inPrereservedRegion;
  319. localAlloc.segment = (alloc->bytesCommitted > CustomHeap::Page::MaxAllocationSize) ? allocation->largeObjectAllocation.segment : allocation->page->segment;
  320. localAddress = m_func->GetOOPThreadContext()->GetCodePageAllocators()->AllocLocal(allocation->address, alloc->bytesCommitted, localAlloc.segment);
  321. localAlloc.localAddress = localAddress;
  322. if (localAddress == nullptr)
  323. {
  324. Js::Throw::OutOfMemory();
  325. }
  326. }
  327. else
  328. #endif
  329. {
  330. EmitBufferAllocation<VirtualAllocWrapper, PreReservedVirtualAllocWrapper> * alloc = m_func->GetJITOutput()->RecordInProcNativeCodeSize(m_func, (DWORD)codeSize, pdataCount, xdataSize);
  331. allocation = alloc->allocation;
  332. inPrereservedRegion = alloc->inPrereservedRegion;
  333. localAddress = allocation->address;
  334. }
  335. if (!inPrereservedRegion)
  336. {
  337. m_func->GetThreadContextInfo()->ResetIsAllJITCodeInPreReservedRegion();
  338. }
  339. this->m_bailoutRecordMap->MapAddress([=](int index, LazyBailOutRecord* record)
  340. {
  341. this->m_encoderMD.AddLabelReloc((BYTE*)&record->instructionPointer);
  342. });
  343. // Relocs
  344. m_encoderMD.ApplyRelocs((size_t)allocation->address, codeSize, &bufferCRC, isSuccessBrShortAndLoopAlign);
  345. m_func->GetJITOutput()->RecordNativeCode(m_encodeBuffer, (BYTE *)localAddress);
  346. #if defined(_M_IX86) || defined(_M_X64)
  347. if (!JITManager::GetJITManager()->IsJITServer())
  348. {
  349. ValidateCRCOnFinalBuffer((BYTE *)allocation->address, codeSize, totalJmpTableSizeInBytes, m_encodeBuffer, initialCRCSeed, bufferCRC, isSuccessBrShortAndLoopAlign);
  350. }
  351. #endif
  352. #ifdef TARGET_64
  353. #ifdef _M_X64
  354. PrologEncoder &unwindInfo = m_func->m_prologEncoder;
  355. unwindInfo.FinalizeUnwindInfo((BYTE*)m_func->GetJITOutput()->GetCodeAddress(), (DWORD)codeSize);
  356. #else
  357. UnwindInfoManager &unwindInfo = m_func->m_unwindInfo;
  358. unwindInfo.FinalizeUnwindInfo((BYTE*)localAddress, (DWORD)codeSize);
  359. #endif
  360. char * localXdataAddr = nullptr;
  361. #if ENABLE_OOP_NATIVE_CODEGEN
  362. if (JITManager::GetJITManager()->IsJITServer())
  363. {
  364. localXdataAddr = m_func->GetOOPThreadContext()->GetCodePageAllocators()->AllocLocal((char*)allocation->xdata.address, XDATA_SIZE, localAlloc.segment);
  365. localAlloc.localXdataAddr = localXdataAddr;
  366. if (localXdataAddr == nullptr)
  367. {
  368. Js::Throw::OutOfMemory();
  369. }
  370. }
  371. else
  372. #endif
  373. {
  374. localXdataAddr = (char*)allocation->xdata.address;
  375. }
  376. m_func->GetJITOutput()->RecordUnwindInfo(
  377. unwindInfo.GetUnwindInfo(),
  378. unwindInfo.SizeOfUnwindInfo(),
  379. allocation->xdata.address,
  380. (BYTE*)localXdataAddr);
  381. #elif _M_ARM
  382. m_func->m_unwindInfo.EmitUnwindInfo(m_func->GetJITOutput(), allocation);
  383. if (m_func->IsOOPJIT())
  384. {
  385. size_t allocSize = XDataAllocator::GetAllocSize(allocation->xdata.pdataCount, allocation->xdata.xdataSize);
  386. BYTE * xprocXdata = NativeCodeDataNewArrayNoFixup(m_func->GetNativeCodeDataAllocator(), BYTE, allocSize);
  387. memcpy_s(xprocXdata, allocSize, allocation->xdata.address, allocSize);
  388. m_func->GetJITOutput()->RecordXData(xprocXdata);
  389. }
  390. else
  391. {
  392. XDataAllocator::Register(&allocation->xdata, m_func->GetJITOutput()->GetCodeAddress(), (DWORD)m_func->GetJITOutput()->GetCodeSize());
  393. m_func->GetInProcJITEntryPointInfo()->GetNativeEntryPointData()->SetXDataInfo(&allocation->xdata);
  394. }
  395. m_func->GetJITOutput()->SetCodeAddress(m_func->GetJITOutput()->GetCodeAddress() | 0x1); // Set thumb mode
  396. #endif
  397. const bool isSimpleJit = m_func->IsSimpleJit();
  398. if (this->m_inlineeFrameMap->Count() > 0 &&
  399. !(this->m_inlineeFrameMap->Count() == 1 && this->m_inlineeFrameMap->Item(0).record == nullptr))
  400. {
  401. if (!m_func->IsOOPJIT()) // in-proc JIT
  402. {
  403. m_func->GetInProcJITEntryPointInfo()->GetInProcNativeEntryPointData()->RecordInlineeFrameMap(m_inlineeFrameMap);
  404. }
  405. else // OOP JIT
  406. {
  407. NativeOffsetInlineeFrameRecordOffset* pairs = NativeCodeDataNewArrayZNoFixup(m_func->GetNativeCodeDataAllocator(), NativeOffsetInlineeFrameRecordOffset, this->m_inlineeFrameMap->Count());
  408. this->m_inlineeFrameMap->Map([&pairs](int i, NativeOffsetInlineeFramePair& p)
  409. {
  410. pairs[i].offset = p.offset;
  411. if (p.record)
  412. {
  413. pairs[i].recordOffset = NativeCodeData::GetDataChunk(p.record)->offset;
  414. }
  415. else
  416. {
  417. pairs[i].recordOffset = NativeOffsetInlineeFrameRecordOffset::InvalidRecordOffset;
  418. }
  419. });
  420. m_func->GetJITOutput()->RecordInlineeFrameOffsetsInfo(NativeCodeData::GetDataChunk(pairs)->offset, this->m_inlineeFrameMap->Count());
  421. }
  422. }
  423. if (this->m_bailoutRecordMap->Count() > 0)
  424. {
  425. m_func->GetInProcJITEntryPointInfo()->GetInProcNativeEntryPointData()->RecordBailOutMap(m_bailoutRecordMap);
  426. }
  427. if (this->m_func->pinnedTypeRefs != nullptr)
  428. {
  429. Assert(!isSimpleJit);
  430. int pinnedTypeRefCount = this->m_func->pinnedTypeRefs->Count();
  431. PinnedTypeRefsIDL* pinnedTypeRefs = nullptr;
  432. if (this->m_func->IsOOPJIT())
  433. {
  434. pinnedTypeRefs = (PinnedTypeRefsIDL*)midl_user_allocate(offsetof(PinnedTypeRefsIDL, typeRefs) + sizeof(void*)*pinnedTypeRefCount);
  435. if (!pinnedTypeRefs)
  436. {
  437. Js::Throw::OutOfMemory();
  438. }
  439. __analysis_assume(pinnedTypeRefs);
  440. pinnedTypeRefs->count = pinnedTypeRefCount;
  441. pinnedTypeRefs->isOOPJIT = true;
  442. }
  443. else
  444. {
  445. pinnedTypeRefs = HeapNewStructPlus(offsetof(PinnedTypeRefsIDL, typeRefs) + sizeof(void*)*pinnedTypeRefCount - sizeof(PinnedTypeRefsIDL), PinnedTypeRefsIDL);
  446. pinnedTypeRefs->count = pinnedTypeRefCount;
  447. pinnedTypeRefs->isOOPJIT = false;
  448. }
  449. int index = 0;
  450. this->m_func->pinnedTypeRefs->Map([&pinnedTypeRefs, &index](void* typeRef) -> void
  451. {
  452. pinnedTypeRefs->typeRefs[index++] = ((JITType*)typeRef)->GetAddr();
  453. });
  454. if (PHASE_TRACE(Js::TracePinnedTypesPhase, this->m_func))
  455. {
  456. char16 debugStringBuffer[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE];
  457. Output::Print(_u("PinnedTypes: function %s(%s) pinned %d types.\n"),
  458. this->m_func->GetJITFunctionBody()->GetDisplayName(), this->m_func->GetDebugNumberSet(debugStringBuffer), pinnedTypeRefCount);
  459. Output::Flush();
  460. }
  461. this->m_func->GetJITOutput()->GetOutputData()->pinnedTypeRefs = pinnedTypeRefs;
  462. }
  463. // Save all equivalent type guards in a fixed size array on the JIT transfer data
  464. if (this->m_func->equivalentTypeGuards != nullptr)
  465. {
  466. AssertMsg(!PHASE_OFF(Js::EquivObjTypeSpecPhase, this->m_func), "Why do we have equivalent type guards if we don't do equivalent object type spec?");
  467. int equivalentTypeGuardsCount = this->m_func->equivalentTypeGuards->Count();
  468. if (this->m_func->IsOOPJIT())
  469. {
  470. auto& equivalentTypeGuardOffsets = this->m_func->GetJITOutput()->GetOutputData()->equivalentTypeGuardOffsets;
  471. size_t allocSize = offsetof(EquivalentTypeGuardOffsets, guards) + equivalentTypeGuardsCount * sizeof(EquivalentTypeGuardIDL);
  472. equivalentTypeGuardOffsets = (EquivalentTypeGuardOffsets*)midl_user_allocate(allocSize);
  473. if (equivalentTypeGuardOffsets == nullptr)
  474. {
  475. Js::Throw::OutOfMemory();
  476. }
  477. equivalentTypeGuardOffsets->count = equivalentTypeGuardsCount;
  478. int i = 0;
  479. this->m_func->equivalentTypeGuards->Map([&equivalentTypeGuardOffsets, &i](Js::JitEquivalentTypeGuard* srcGuard) -> void
  480. {
  481. equivalentTypeGuardOffsets->guards[i].offset = NativeCodeData::GetDataTotalOffset(srcGuard);
  482. auto cache = srcGuard->GetCache();
  483. equivalentTypeGuardOffsets->guards[i].cache.guardOffset = NativeCodeData::GetDataTotalOffset(cache->guard);
  484. equivalentTypeGuardOffsets->guards[i].cache.hasFixedValue = cache->hasFixedValue;
  485. equivalentTypeGuardOffsets->guards[i].cache.isLoadedFromProto = cache->isLoadedFromProto;
  486. equivalentTypeGuardOffsets->guards[i].cache.nextEvictionVictim = cache->nextEvictionVictim;
  487. equivalentTypeGuardOffsets->guards[i].cache.record.propertyCount = cache->record.propertyCount;
  488. equivalentTypeGuardOffsets->guards[i].cache.record.propertyOffset = NativeCodeData::GetDataTotalOffset(cache->record.properties);
  489. for (int j = 0; j < EQUIVALENT_TYPE_CACHE_SIZE; j++)
  490. {
  491. equivalentTypeGuardOffsets->guards[i].cache.types[j] = (intptr_t)PointerValue(cache->types[j]);
  492. }
  493. i++;
  494. });
  495. Assert(equivalentTypeGuardsCount == i);
  496. }
  497. else
  498. {
  499. Js::JitEquivalentTypeGuard** guards = HeapNewArrayZ(Js::JitEquivalentTypeGuard*, equivalentTypeGuardsCount);
  500. Js::JitEquivalentTypeGuard** dstGuard = guards;
  501. this->m_func->equivalentTypeGuards->Map([&dstGuard](Js::JitEquivalentTypeGuard* srcGuard) -> void
  502. {
  503. *dstGuard++ = srcGuard;
  504. });
  505. m_func->GetInProcJITEntryPointInfo()->GetJitTransferData()->SetEquivalentTypeGuards(guards, equivalentTypeGuardsCount);
  506. }
  507. }
  508. if (this->m_func->lazyBailoutProperties.Count() > 0)
  509. {
  510. int count = this->m_func->lazyBailoutProperties.Count();
  511. Js::PropertyId* lazyBailoutProperties = HeapNewArrayZ(Js::PropertyId, count);
  512. Js::PropertyId* dstProperties = lazyBailoutProperties;
  513. this->m_func->lazyBailoutProperties.Map([&](Js::PropertyId propertyId)
  514. {
  515. *dstProperties++ = propertyId;
  516. });
  517. m_func->GetInProcJITEntryPointInfo()->GetJitTransferData()->SetLazyBailoutProperties(lazyBailoutProperties, count);
  518. }
  519. // Save all property guards on the JIT transfer data in a map keyed by property ID. We will use this map when installing the entry
  520. // point to register each guard for invalidation.
  521. if (this->m_func->propertyGuardsByPropertyId != nullptr)
  522. {
  523. Assert(!isSimpleJit);
  524. AssertMsg(!(PHASE_OFF(Js::ObjTypeSpecPhase, this->m_func) && PHASE_OFF(Js::FixedMethodsPhase, this->m_func)),
  525. "Why do we have type guards if we don't do object type spec or fixed methods?");
  526. #if DBG
  527. int totalGuardCount = (this->m_func->singleTypeGuards != nullptr ? this->m_func->singleTypeGuards->Count() : 0)
  528. + (this->m_func->equivalentTypeGuards != nullptr ? this->m_func->equivalentTypeGuards->Count() : 0);
  529. Assert(totalGuardCount > 0);
  530. Assert(totalGuardCount == this->m_func->indexedPropertyGuardCount);
  531. #endif
  532. if (!this->m_func->IsOOPJIT())
  533. {
  534. int propertyCount = this->m_func->propertyGuardsByPropertyId->Count();
  535. Assert(propertyCount > 0);
  536. int guardSlotCount = 0;
  537. this->m_func->propertyGuardsByPropertyId->Map([&guardSlotCount](Js::PropertyId propertyId, Func::IndexedPropertyGuardSet* set) -> void
  538. {
  539. guardSlotCount += set->Count();
  540. });
  541. size_t typeGuardTransferSize = // Reserve enough room for:
  542. propertyCount * sizeof(Js::TypeGuardTransferEntry) + // each propertyId,
  543. propertyCount * sizeof(Js::JitIndexedPropertyGuard*) + // terminating nullptr guard for each propertyId,
  544. guardSlotCount * sizeof(Js::JitIndexedPropertyGuard*); // a pointer for each guard we counted above.
  545. // The extra room for sizeof(Js::TypePropertyGuardEntry) allocated by HeapNewPlus will be used for the terminating invalid propertyId.
  546. // Review (jedmiad): Skip zeroing? This is heap allocated so there shouldn't be any false recycler references.
  547. Js::TypeGuardTransferEntry* typeGuardTransferRecord = HeapNewPlusZ(typeGuardTransferSize, Js::TypeGuardTransferEntry);
  548. Func* func = this->m_func;
  549. Js::TypeGuardTransferEntry* dstEntry = typeGuardTransferRecord;
  550. this->m_func->propertyGuardsByPropertyId->Map([func, &dstEntry](Js::PropertyId propertyId, Func::IndexedPropertyGuardSet* srcSet) -> void
  551. {
  552. dstEntry->propertyId = propertyId;
  553. int guardIndex = 0;
  554. srcSet->Map([dstEntry, &guardIndex](Js::JitIndexedPropertyGuard* guard) -> void
  555. {
  556. dstEntry->guards[guardIndex++] = guard;
  557. });
  558. dstEntry->guards[guardIndex++] = nullptr;
  559. dstEntry = reinterpret_cast<Js::TypeGuardTransferEntry*>(&dstEntry->guards[guardIndex]);
  560. });
  561. dstEntry->propertyId = Js::Constants::NoProperty;
  562. dstEntry++;
  563. Assert(reinterpret_cast<char*>(dstEntry) <= reinterpret_cast<char*>(typeGuardTransferRecord) + typeGuardTransferSize + sizeof(Js::TypeGuardTransferEntry));
  564. m_func->GetInProcJITEntryPointInfo()->GetJitTransferData()->RecordTypeGuards(this->m_func->indexedPropertyGuardCount, typeGuardTransferRecord, typeGuardTransferSize);
  565. }
  566. else
  567. {
  568. Func* func = this->m_func;
  569. this->m_func->GetJITOutput()->GetOutputData()->propertyGuardCount = this->m_func->indexedPropertyGuardCount;
  570. auto entry = &this->m_func->GetJITOutput()->GetOutputData()->typeGuardEntries;
  571. this->m_func->propertyGuardsByPropertyId->Map([func, &entry](Js::PropertyId propertyId, Func::IndexedPropertyGuardSet* srcSet) -> void
  572. {
  573. auto count = srcSet->Count();
  574. (*entry) = (TypeGuardTransferEntryIDL*)midl_user_allocate(offsetof(TypeGuardTransferEntryIDL, guardOffsets) + count*sizeof(int));
  575. if (!*entry)
  576. {
  577. Js::Throw::OutOfMemory();
  578. }
  579. __analysis_assume(*entry);
  580. (*entry)->propId = propertyId;
  581. (*entry)->guardsCount = count;
  582. (*entry)->next = nullptr;
  583. auto& guardOffsets = (*entry)->guardOffsets;
  584. int guardIndex = 0;
  585. srcSet->Map([&guardOffsets, &guardIndex](Js::JitIndexedPropertyGuard* guard) -> void
  586. {
  587. guardOffsets[guardIndex++] = NativeCodeData::GetDataTotalOffset(guard);
  588. });
  589. Assert(guardIndex == count);
  590. entry = &(*entry)->next;
  591. });
  592. }
  593. }
  594. // Save all constructor caches on the JIT transfer data in a map keyed by property ID. We will use this map when installing the entry
  595. // point to register each cache for invalidation.
  596. if (this->m_func->ctorCachesByPropertyId != nullptr)
  597. {
  598. Assert(!isSimpleJit);
  599. AssertMsg(!(PHASE_OFF(Js::ObjTypeSpecPhase, this->m_func) && PHASE_OFF(Js::FixedMethodsPhase, this->m_func)),
  600. "Why do we have constructor cache guards if we don't do object type spec or fixed methods?");
  601. int propertyCount = this->m_func->ctorCachesByPropertyId->Count();
  602. Assert(propertyCount > 0);
  603. int cacheSlotCount = 0;
  604. this->m_func->ctorCachesByPropertyId->Map([&cacheSlotCount](Js::PropertyId propertyId, Func::CtorCacheSet* cacheSet) -> void
  605. {
  606. cacheSlotCount += cacheSet->Count();
  607. });
  608. if (m_func->IsOOPJIT())
  609. {
  610. Func* func = this->m_func;
  611. m_func->GetJITOutput()->GetOutputData()->ctorCachesCount = propertyCount;
  612. m_func->GetJITOutput()->GetOutputData()->ctorCacheEntries = (CtorCacheTransferEntryIDL**)midl_user_allocate(propertyCount * sizeof(CtorCacheTransferEntryIDL*));
  613. CtorCacheTransferEntryIDL** entries = m_func->GetJITOutput()->GetOutputData()->ctorCacheEntries;
  614. if (!entries)
  615. {
  616. Js::Throw::OutOfMemory();
  617. }
  618. __analysis_assume(entries);
  619. uint propIndex = 0;
  620. m_func->ctorCachesByPropertyId->Map([func, entries, &propIndex](Js::PropertyId propertyId, Func::CtorCacheSet* srcCacheSet) -> void
  621. {
  622. entries[propIndex] = (CtorCacheTransferEntryIDL*)midl_user_allocate(srcCacheSet->Count() * sizeof(intptr_t) + sizeof(CtorCacheTransferEntryIDL));
  623. if (!entries[propIndex])
  624. {
  625. Js::Throw::OutOfMemory();
  626. }
  627. __analysis_assume(entries[propIndex]);
  628. entries[propIndex]->propId = propertyId;
  629. int cacheIndex = 0;
  630. srcCacheSet->Map([entries, propIndex, &cacheIndex](intptr_t cache) -> void
  631. {
  632. entries[propIndex]->caches[cacheIndex++] = cache;
  633. });
  634. entries[propIndex]->cacheCount = cacheIndex;
  635. propIndex++;
  636. });
  637. }
  638. else
  639. {
  640. Assert(m_func->GetInProcJITEntryPointInfo()->GetNativeEntryPointData()->GetConstructorCacheCount() > 0);
  641. size_t ctorCachesTransferSize = // Reserve enough room for:
  642. propertyCount * sizeof(Js::CtorCacheGuardTransferEntry) + // each propertyId,
  643. propertyCount * sizeof(Js::ConstructorCache*) + // terminating null cache for each propertyId,
  644. cacheSlotCount * sizeof(Js::JitIndexedPropertyGuard*); // a pointer for each cache we counted above.
  645. // The extra room for sizeof(Js::CtorCacheGuardTransferEntry) allocated by HeapNewPlus will be used for the terminating invalid propertyId.
  646. // Review (jedmiad): Skip zeroing? This is heap allocated so there shouldn't be any false recycler references.
  647. Js::CtorCacheGuardTransferEntry* ctorCachesTransferRecord = HeapNewPlusZ(ctorCachesTransferSize, Js::CtorCacheGuardTransferEntry);
  648. Func* func = this->m_func;
  649. Js::CtorCacheGuardTransferEntry* dstEntry = ctorCachesTransferRecord;
  650. this->m_func->ctorCachesByPropertyId->Map([func, &dstEntry](Js::PropertyId propertyId, Func::CtorCacheSet* srcCacheSet) -> void
  651. {
  652. dstEntry->propertyId = propertyId;
  653. int cacheIndex = 0;
  654. srcCacheSet->Map([dstEntry, &cacheIndex](intptr_t cache) -> void
  655. {
  656. dstEntry->caches[cacheIndex++] = cache;
  657. });
  658. dstEntry->caches[cacheIndex++] = 0;
  659. dstEntry = reinterpret_cast<Js::CtorCacheGuardTransferEntry*>(&dstEntry->caches[cacheIndex]);
  660. });
  661. dstEntry->propertyId = Js::Constants::NoProperty;
  662. dstEntry++;
  663. Assert(reinterpret_cast<char*>(dstEntry) <= reinterpret_cast<char*>(ctorCachesTransferRecord) + ctorCachesTransferSize + sizeof(Js::CtorCacheGuardTransferEntry));
  664. m_func->GetInProcJITEntryPointInfo()->GetJitTransferData()->RecordCtorCacheGuards(ctorCachesTransferRecord, ctorCachesTransferSize);
  665. }
  666. }
  667. m_func->GetJITOutput()->FinalizeNativeCode();
  668. END_CODEGEN_PHASE(m_func, Js::EmitterPhase);
  669. #if DBG_DUMP
  670. m_func->m_codeSize = codeSize;
  671. if (PHASE_DUMP(Js::EncoderPhase, m_func) || PHASE_DUMP(Js::BackEndPhase, m_func))
  672. {
  673. bool dumpIRAddressesValue = Js::Configuration::Global.flags.DumpIRAddresses;
  674. Js::Configuration::Global.flags.DumpIRAddresses = true;
  675. this->m_func->DumpHeader();
  676. m_instrNumber = 0;
  677. FOREACH_INSTR_IN_FUNC(instr, m_func)
  678. {
  679. __analysis_assume(m_instrNumber < instrCount);
  680. instr->DumpGlobOptInstrString();
  681. #ifdef TARGET_64
  682. Output::Print(_u("%12IX "), m_offsetBuffer[m_instrNumber++] + (BYTE *)m_func->GetJITOutput()->GetCodeAddress());
  683. #else
  684. Output::Print(_u("%8IX "), m_offsetBuffer[m_instrNumber++] + (BYTE *)m_func->GetJITOutput()->GetCodeAddress());
  685. #endif
  686. instr->Dump();
  687. } NEXT_INSTR_IN_FUNC;
  688. Output::Flush();
  689. Js::Configuration::Global.flags.DumpIRAddresses = dumpIRAddressesValue;
  690. }
  691. if (PHASE_DUMP(Js::EncoderPhase, m_func) && Js::Configuration::Global.flags.Verbose && !m_func->IsOOPJIT())
  692. {
  693. m_func->GetInProcJITEntryPointInfo()->DumpNativeOffsetMaps();
  694. m_func->GetInProcJITEntryPointInfo()->DumpNativeThrowSpanSequence();
  695. this->DumpInlineeFrameMap(m_func->GetJITOutput()->GetCodeAddress());
  696. Output::Flush();
  697. }
  698. #endif
  699. }
  700. bool Encoder::DoTrackAllStatementBoundary() const
  701. {
  702. #if DBG_DUMP | defined(VTUNE_PROFILING)
  703. return this->m_func->DoRecordNativeMap();
  704. #else
  705. return false;
  706. #endif
  707. }
  708. void Encoder::TryCopyAndAddRelocRecordsForSwitchJumpTableEntries(BYTE *codeStart, size_t codeSize, JmpTableList * jumpTableListForSwitchStatement, size_t totalJmpTableSizeInBytes)
  709. {
  710. if (jumpTableListForSwitchStatement == nullptr)
  711. {
  712. return;
  713. }
  714. BYTE * jmpTableStartAddress = codeStart + codeSize - totalJmpTableSizeInBytes;
  715. EncoderMD * encoderMD = &m_encoderMD;
  716. jumpTableListForSwitchStatement->Map([&](uint index, BranchJumpTableWrapper * branchJumpTableWrapper) -> void
  717. {
  718. Assert(branchJumpTableWrapper != nullptr);
  719. void ** srcJmpTable = branchJumpTableWrapper->jmpTable;
  720. size_t jmpTableSizeInBytes = branchJumpTableWrapper->tableSize * sizeof(void*);
  721. AssertMsg(branchJumpTableWrapper->labelInstr != nullptr, "Label not yet created?");
  722. Assert(branchJumpTableWrapper->labelInstr->GetPC() == nullptr);
  723. branchJumpTableWrapper->labelInstr->SetPC(jmpTableStartAddress);
  724. memcpy(jmpTableStartAddress, srcJmpTable, jmpTableSizeInBytes);
  725. for (int i = 0; i < branchJumpTableWrapper->tableSize; i++)
  726. {
  727. void * addressOfJmpTableEntry = jmpTableStartAddress + (i * sizeof(void*));
  728. Assert((ptrdiff_t) addressOfJmpTableEntry - (ptrdiff_t) jmpTableStartAddress < (ptrdiff_t) jmpTableSizeInBytes);
  729. #if defined(_M_ARM32_OR_ARM64)
  730. encoderMD->AddLabelReloc((byte*) addressOfJmpTableEntry);
  731. #else
  732. encoderMD->AppendRelocEntry(RelocTypeLabelUse, addressOfJmpTableEntry, *(IR::LabelInstr**)addressOfJmpTableEntry);
  733. *((size_t*)addressOfJmpTableEntry) = 0;
  734. #endif
  735. }
  736. jmpTableStartAddress += (jmpTableSizeInBytes);
  737. });
  738. Assert(jmpTableStartAddress == codeStart + codeSize);
  739. }
  740. uint32 Encoder::GetCurrentOffset() const
  741. {
  742. Assert(m_pc - m_encodeBuffer <= UINT_MAX); // encode buffer size is uint32
  743. return static_cast<uint32>(m_pc - m_encodeBuffer);
  744. }
  745. void Encoder::RecordInlineeFrame(Func* inlinee, uint32 currentOffset)
  746. {
  747. // The only restriction for not supporting loop bodies is that inlinee frame map is created on FunctionEntryPointInfo & not
  748. // the base class EntryPointInfo.
  749. if (!(this->m_func->IsLoopBody() && PHASE_OFF(Js::InlineInJitLoopBodyPhase, this->m_func)) && !this->m_func->IsSimpleJit())
  750. {
  751. InlineeFrameRecord* record = nullptr;
  752. if (inlinee->frameInfo && inlinee->m_hasInlineArgsOpt)
  753. {
  754. record = inlinee->frameInfo->record;
  755. Assert(record != nullptr);
  756. }
  757. if (m_inlineeFrameMap->Count() > 0)
  758. {
  759. // update existing record if the entry is the same.
  760. NativeOffsetInlineeFramePair& lastPair = m_inlineeFrameMap->Item(m_inlineeFrameMap->Count() - 1);
  761. if (lastPair.record == record)
  762. {
  763. lastPair.offset = currentOffset;
  764. return;
  765. }
  766. }
  767. NativeOffsetInlineeFramePair pair = { currentOffset, record };
  768. m_inlineeFrameMap->Add(pair);
  769. }
  770. }
  771. #if defined(_M_IX86) || defined(_M_X64)
  772. /*
  773. * ValidateCRCOnFinalBuffer
  774. * - Validates the CRC that is last computed (could be either the one after BranchShortening or after encoding itself)
  775. * - We calculate the CRC for jump table and dictionary after computing the code section.
  776. * - Also, all reloc data are computed towards the end - after computing the code section - because we don't have to deal with the changes relocs while operating on the code section.
  777. * - The version of CRC that we are validating with, doesn't have Relocs applied but the final buffer does - So we have to make adjustments while calculating the final buffer's CRC.
  778. */
  779. void Encoder::ValidateCRCOnFinalBuffer(_In_reads_bytes_(finalCodeSize) BYTE * finalCodeBufferStart, size_t finalCodeSize, size_t jumpTableSize, _In_reads_bytes_(finalCodeSize) BYTE * oldCodeBufferStart, uint initialCrcSeed, uint bufferCrcToValidate, BOOL isSuccessBrShortAndLoopAlign)
  780. {
  781. RelocList * relocList = m_encoderMD.GetRelocList();
  782. BYTE * currentStartAddress = finalCodeBufferStart;
  783. BYTE * currentEndAddress = nullptr;
  784. size_t crcSizeToCompute = 0;
  785. size_t finalCodeSizeWithoutJumpTable = finalCodeSize - jumpTableSize;
  786. uint finalBufferCRC = initialCrcSeed;
  787. BYTE * oldPtr = nullptr;
  788. if (relocList != nullptr)
  789. {
  790. for (int index = 0; index < relocList->Count(); index++)
  791. {
  792. EncodeRelocAndLabels * relocTuple = &relocList->Item(index);
  793. //We will deal with the jump table and dictionary entries along with other reloc records in ApplyRelocs()
  794. if ((BYTE*)m_encoderMD.GetRelocBufferAddress(relocTuple) >= oldCodeBufferStart && (BYTE*)m_encoderMD.GetRelocBufferAddress(relocTuple) < (oldCodeBufferStart + finalCodeSizeWithoutJumpTable))
  795. {
  796. BYTE* finalBufferRelocTuplePtr = (BYTE*)m_encoderMD.GetRelocBufferAddress(relocTuple) - oldCodeBufferStart + finalCodeBufferStart;
  797. Assert(finalBufferRelocTuplePtr >= finalCodeBufferStart && finalBufferRelocTuplePtr < (finalCodeBufferStart + finalCodeSizeWithoutJumpTable));
  798. uint relocDataSize = m_encoderMD.GetRelocDataSize(relocTuple);
  799. if (relocDataSize != 0)
  800. {
  801. AssertMsg(oldPtr == nullptr || oldPtr < finalBufferRelocTuplePtr, "Assumption here is that the reloc list is strictly increasing in terms of bufferAddress");
  802. oldPtr = finalBufferRelocTuplePtr;
  803. currentEndAddress = finalBufferRelocTuplePtr;
  804. crcSizeToCompute = currentEndAddress - currentStartAddress;
  805. Assert(currentEndAddress >= currentStartAddress);
  806. finalBufferCRC = CalculateCRC(finalBufferCRC, crcSizeToCompute, currentStartAddress);
  807. for (uint i = 0; i < relocDataSize; i++)
  808. {
  809. finalBufferCRC = CalculateCRC(finalBufferCRC, 0);
  810. }
  811. currentStartAddress = currentEndAddress + relocDataSize;
  812. }
  813. }
  814. }
  815. }
  816. currentEndAddress = finalCodeBufferStart + finalCodeSizeWithoutJumpTable;
  817. crcSizeToCompute = currentEndAddress - currentStartAddress;
  818. Assert(currentEndAddress >= currentStartAddress);
  819. finalBufferCRC = CalculateCRC(finalBufferCRC, crcSizeToCompute, currentStartAddress);
  820. //Include all offsets from the reloc records to the CRC.
  821. m_encoderMD.ApplyRelocs((size_t)finalCodeBufferStart, finalCodeSize, &finalBufferCRC, isSuccessBrShortAndLoopAlign, true);
  822. if (finalBufferCRC != bufferCrcToValidate)
  823. {
  824. Assert(false);
  825. Fatal();
  826. }
  827. }
  828. #endif
  829. /*
  830. * EnsureRelocEntryIntegrity
  831. * - We compute the target address as the processor would compute it and check if the target is within the final buffer's bounds.
  832. * - For relative addressing, Target = current m_pc + offset
  833. * - For absolute addressing, Target = direct address
  834. */
  835. void Encoder::EnsureRelocEntryIntegrity(size_t newBufferStartAddress, size_t codeSize, size_t oldBufferAddress, size_t relocAddress, uint offsetBytes, ptrdiff_t opndData, bool isRelativeAddr)
  836. {
  837. size_t targetBrAddress = 0;
  838. size_t newBufferEndAddress = newBufferStartAddress + codeSize;
  839. //Handle Dictionary addresses here - The target address will be in the dictionary.
  840. if (relocAddress < oldBufferAddress || relocAddress >= (oldBufferAddress + codeSize))
  841. {
  842. targetBrAddress = (size_t)(*(size_t*)relocAddress);
  843. }
  844. else
  845. {
  846. size_t newBufferRelocAddr = relocAddress - oldBufferAddress + newBufferStartAddress;
  847. if (isRelativeAddr)
  848. {
  849. targetBrAddress = (size_t)newBufferRelocAddr + offsetBytes + opndData;
  850. }
  851. else // Absolute Address
  852. {
  853. targetBrAddress = (size_t)opndData;
  854. }
  855. }
  856. if (targetBrAddress < newBufferStartAddress || targetBrAddress >= newBufferEndAddress)
  857. {
  858. Assert(false);
  859. Fatal();
  860. }
  861. }
  862. uint Encoder::CalculateCRC(uint bufferCRC, size_t data)
  863. {
  864. #if defined(_WIN32) || defined(__SSE4_2__)
  865. #if defined(_M_IX86)
  866. if (AutoSystemInfo::Data.SSE4_2Available())
  867. {
  868. return _mm_crc32_u32(bufferCRC, data);
  869. }
  870. #elif defined(_M_X64)
  871. if (AutoSystemInfo::Data.SSE4_2Available())
  872. {
  873. //CRC32 always returns a 32-bit result
  874. return (uint)_mm_crc32_u64(bufferCRC, data);
  875. }
  876. #endif
  877. #endif
  878. return CalculateCRC32(bufferCRC, data);
  879. }
  880. uint Encoder::CalculateCRC(uint bufferCRC, size_t count, _In_reads_bytes_(count) void * buffer)
  881. {
  882. for (uint index = 0; index < count; index++)
  883. {
  884. bufferCRC = CalculateCRC(bufferCRC, *((BYTE*)buffer + index));
  885. }
  886. return bufferCRC;
  887. }
  888. void Encoder::ValidateCRC(uint bufferCRC, uint initialCRCSeed, _In_reads_bytes_(count) void* buffer, size_t count)
  889. {
  890. uint validationCRC = initialCRCSeed;
  891. validationCRC = CalculateCRC(validationCRC, count, buffer);
  892. if (validationCRC != bufferCRC)
  893. {
  894. //TODO: This throws internal error. Is this error type, Fine?
  895. Fatal();
  896. }
  897. }
  898. #if defined(_M_IX86) || defined(_M_X64)
  899. ///----------------------------------------------------------------------------
  900. ///
  901. /// EncoderMD::ShortenBranchesAndLabelAlign
  902. /// We try to shorten branches if the label instr is within 8-bits target range (-128 to 127)
  903. /// and fix the relocList accordingly.
  904. /// Also align LoopTop Label and TryCatchLabel
  905. ///----------------------------------------------------------------------------
  906. BOOL
  907. Encoder::ShortenBranchesAndLabelAlign(BYTE **codeStart, ptrdiff_t *codeSize, uint * pShortenedBufferCRC, uint bufferCrcToValidate, size_t jumpTableSize)
  908. {
  909. #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
  910. static uint32 globalTotalBytesSaved = 0, globalTotalBytesWithoutShortening = 0;
  911. static uint32 globalTotalBytesInserted = 0; // loop alignment nops
  912. #endif
  913. uint32 brShortenedCount = 0;
  914. bool codeChange = false; // any overall BR shortened or label aligned ?
  915. BYTE* buffStart = *codeStart;
  916. BYTE* buffEnd = buffStart + *codeSize;
  917. ptrdiff_t newCodeSize = *codeSize;
  918. RelocList* relocList = m_encoderMD.GetRelocList();
  919. if (relocList == nullptr)
  920. {
  921. return false;
  922. }
  923. #if DBG
  924. // Sanity check
  925. m_encoderMD.VerifyRelocList(buffStart, buffEnd);
  926. #endif
  927. // Copy of original maps. Used to revert from BR shortening.
  928. OffsetList *m_origInlineeFrameRecords = nullptr,
  929. *m_origInlineeFrameMap = nullptr,
  930. *m_origPragmaInstrToRecordOffset = nullptr;
  931. OffsetList *m_origOffsetBuffer = nullptr;
  932. // we record the original maps, in case we have to revert.
  933. CopyMaps<false>(&m_origInlineeFrameRecords
  934. , &m_origInlineeFrameMap
  935. , &m_origPragmaInstrToRecordOffset
  936. , &m_origOffsetBuffer );
  937. // Here we mark BRs to be shortened and adjust Labels and relocList entries offsets.
  938. uint32 offsetBuffIndex = 0, pragmaInstToRecordOffsetIndex = 0, inlineeFrameRecordsIndex = 0, inlineeFrameMapIndex = 0;
  939. int32 totalBytesSaved = 0;
  940. // loop over all BRs, find the ones we can convert to short form
  941. for (int32 j = 0; j < relocList->Count(); j++)
  942. {
  943. IR::LabelInstr *targetLabel;
  944. int32 relOffset;
  945. uint32 bytesSaved = 0;
  946. BYTE* labelPc, *opcodeByte;
  947. BYTE* shortBrPtr, *fixedBrPtr; // without shortening
  948. EncodeRelocAndLabels &reloc = relocList->Item(j);
  949. // If not a long branch, just fix the reloc entry and skip.
  950. if (!reloc.isLongBr())
  951. {
  952. // if loop alignment is required, total bytes saved can change
  953. int32 newTotalBytesSaved = m_encoderMD.FixRelocListEntry(j, totalBytesSaved, buffStart, buffEnd);
  954. if (newTotalBytesSaved != totalBytesSaved)
  955. {
  956. AssertMsg(reloc.isAlignedLabel(), "Expecting aligned label.");
  957. // we aligned a loop, fix maps
  958. m_encoderMD.FixMaps((uint32)(reloc.getLabelOrigPC() - buffStart), totalBytesSaved, &inlineeFrameRecordsIndex, &inlineeFrameMapIndex, &pragmaInstToRecordOffsetIndex, &offsetBuffIndex);
  959. codeChange = true;
  960. }
  961. totalBytesSaved = newTotalBytesSaved;
  962. continue;
  963. }
  964. AssertMsg(reloc.isLongBr(), "Cannot shorten already shortened branch.");
  965. // long branch
  966. opcodeByte = reloc.getBrOpCodeByte();
  967. targetLabel = reloc.getBrTargetLabel();
  968. AssertMsg(targetLabel != nullptr, "Branch to non-existing label");
  969. labelPc = targetLabel->GetPC();
  970. // compute the new offset of that Br because of previous shortening/alignment
  971. shortBrPtr = fixedBrPtr = (BYTE*)reloc.m_ptr - totalBytesSaved;
  972. if (*opcodeByte == 0xe9 /* JMP rel32 */)
  973. {
  974. bytesSaved = 3;
  975. }
  976. else if (*opcodeByte >= 0x80 && *opcodeByte < 0x90 /* Jcc rel32 */)
  977. {
  978. Assert(*(opcodeByte - 1) == 0x0f);
  979. bytesSaved = 4;
  980. // Jcc rel8 is one byte shorter in opcode, fix Br ptr to point to start of rel8
  981. shortBrPtr--;
  982. }
  983. else
  984. {
  985. Assert(false);
  986. }
  987. // compute current distance to label
  988. if (labelPc >= (BYTE*) reloc.m_ptr)
  989. {
  990. // forward Br. We compare using the unfixed m_ptr, because the label is ahead and its Pc is not fixed it.
  991. relOffset = (int32)(labelPc - ((BYTE*)reloc.m_ptr + 4));
  992. }
  993. else
  994. {
  995. // backward Br. We compute relOffset after fixing the Br, since the label is already fixed.
  996. // We also include the 3-4 bytes saved after shortening the Br since the Br itself is included in the relative offset.
  997. relOffset = (int32)(labelPc - (shortBrPtr + 1));
  998. }
  999. // update Br offset (overwritten later if Br is shortened)
  1000. reloc.m_ptr = fixedBrPtr;
  1001. // can we shorten ?
  1002. if (relOffset >= -128 && relOffset <= 127)
  1003. {
  1004. uint32 brOffset;
  1005. brShortenedCount++;
  1006. // update with shortened br offset
  1007. reloc.m_ptr = shortBrPtr;
  1008. // fix all maps entries from last shortened br to this one, before updating total bytes saved.
  1009. brOffset = (uint32) ((BYTE*)reloc.m_origPtr - buffStart);
  1010. m_encoderMD.FixMaps(brOffset, totalBytesSaved, &inlineeFrameRecordsIndex, &inlineeFrameMapIndex, &pragmaInstToRecordOffsetIndex, &offsetBuffIndex);
  1011. codeChange = true;
  1012. totalBytesSaved += bytesSaved;
  1013. // mark br reloc entry as shortened
  1014. #ifdef _M_IX86
  1015. reloc.setAsShortBr(targetLabel);
  1016. #else
  1017. reloc.setAsShortBr();
  1018. #endif
  1019. }
  1020. }
  1021. // Fix the rest of the maps, if needed.
  1022. if (totalBytesSaved != 0)
  1023. {
  1024. m_encoderMD.FixMaps((uint32) -1, totalBytesSaved, &inlineeFrameRecordsIndex, &inlineeFrameMapIndex, &pragmaInstToRecordOffsetIndex, &offsetBuffIndex);
  1025. codeChange = true;
  1026. newCodeSize -= totalBytesSaved;
  1027. }
  1028. // no BR shortening or Label alignment happened, no need to copy code
  1029. if (!codeChange)
  1030. return codeChange;
  1031. #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
  1032. globalTotalBytesWithoutShortening += (uint32)(*codeSize);
  1033. globalTotalBytesSaved += (uint32)(*codeSize - newCodeSize);
  1034. if (PHASE_TRACE(Js::BrShortenPhase, this->m_func))
  1035. {
  1036. OUTPUT_VERBOSE_TRACE(Js::BrShortenPhase, _u("func: %s, bytes saved: %d, bytes saved %%:%.2f, total bytes saved: %d, total bytes saved%%: %.2f, BR shortened: %d\n"),
  1037. this->m_func->GetJITFunctionBody()->GetDisplayName(), (*codeSize - newCodeSize), ((float)*codeSize - newCodeSize) / *codeSize * 100,
  1038. globalTotalBytesSaved, ((float)globalTotalBytesSaved) / globalTotalBytesWithoutShortening * 100 , brShortenedCount);
  1039. Output::Flush();
  1040. }
  1041. #endif
  1042. // At this point BRs are marked to be shortened, and relocList offsets are adjusted to new instruction length.
  1043. // Next, we re-write the code to shorten the BRs and adjust relocList offsets to point to new buffer.
  1044. // We also write NOPs for aligned loops.
  1045. BYTE* tmpBuffer = AnewArray(m_tempAlloc, BYTE, newCodeSize);
  1046. uint srcBufferCrc = *pShortenedBufferCRC; //This has the intial Random CRC seed to start with.
  1047. // start copying to new buffer
  1048. // this can possibly be done during fixing, but there is no evidence it is an overhead to justify the complexity.
  1049. BYTE *from = buffStart, *to = nullptr;
  1050. BYTE *dst_p = (BYTE*)tmpBuffer;
  1051. size_t dst_size = newCodeSize;
  1052. size_t src_size;
  1053. for (int32 i = 0; i < relocList->Count(); i++)
  1054. {
  1055. EncodeRelocAndLabels &reloc = relocList->Item(i);
  1056. // shorten BR and copy
  1057. if (reloc.isShortBr())
  1058. {
  1059. // validate that short BR offset is within 1 byte offset range.
  1060. // This handles the rare case with loop alignment breaks br shortening.
  1061. // Consider:
  1062. // BR $L1 // shortened
  1063. // ...
  1064. // L2: // aligned, and makes the BR $L1 non-shortable anymore
  1065. // ...
  1066. // BR $L2
  1067. // ...
  1068. // L1:
  1069. // In this case, we simply give up and revert the relocList.
  1070. if(!reloc.validateShortBrTarget())
  1071. {
  1072. revertRelocList();
  1073. // restore maps
  1074. CopyMaps<true>(&m_origInlineeFrameRecords
  1075. , &m_origInlineeFrameMap
  1076. , &m_origPragmaInstrToRecordOffset
  1077. , &m_origOffsetBuffer
  1078. );
  1079. return false;
  1080. }
  1081. // m_origPtr points to imm32 field in the original buffer
  1082. BYTE *opcodeByte = (BYTE*)reloc.m_origPtr - 1;
  1083. if (*opcodeByte == 0xe9 /* JMP rel32 */)
  1084. {
  1085. to = opcodeByte - 1;
  1086. }
  1087. else if (*opcodeByte >= 0x80 && *opcodeByte < 0x90 /* Jcc rel32 */)
  1088. {
  1089. Assert(*(opcodeByte - 1) == 0x0f);
  1090. to = opcodeByte - 2;
  1091. }
  1092. else
  1093. {
  1094. Assert(false);
  1095. }
  1096. src_size = to - from + 1;
  1097. AnalysisAssert(dst_size >= src_size);
  1098. memcpy_s(dst_p, dst_size, from, src_size);
  1099. srcBufferCrc = CalculateCRC(srcBufferCrc, (BYTE*)reloc.m_origPtr - from + 4, from);
  1100. *pShortenedBufferCRC = CalculateCRC(*pShortenedBufferCRC, src_size, dst_p);
  1101. dst_p += src_size;
  1102. dst_size -= src_size;
  1103. // fix the BR
  1104. // write new opcode
  1105. AnalysisAssert(dst_p < tmpBuffer + newCodeSize);
  1106. *dst_p = (*opcodeByte == 0xe9) ? (BYTE)0xeb : (BYTE)(*opcodeByte - 0x10);
  1107. *(dst_p + 1) = 0; // imm8
  1108. *pShortenedBufferCRC = CalculateCRC(*pShortenedBufferCRC, 2, dst_p);
  1109. dst_p += 2; // 1 byte for opcode + 1 byte for imm8
  1110. dst_size -= 2;
  1111. from = (BYTE*)reloc.m_origPtr + 4;
  1112. }
  1113. else if (reloc.m_type == RelocTypeInlineeEntryOffset)
  1114. {
  1115. to = (BYTE*)reloc.m_origPtr - 1;
  1116. CopyPartialBufferAndCalculateCRC(&dst_p, dst_size, from, to, pShortenedBufferCRC);
  1117. *(size_t*)dst_p = reloc.GetInlineOffset();
  1118. *pShortenedBufferCRC = CalculateCRC(*pShortenedBufferCRC, sizeof(size_t), dst_p);
  1119. dst_p += sizeof(size_t);
  1120. dst_size -= sizeof(size_t);
  1121. srcBufferCrc = CalculateCRC(srcBufferCrc, (BYTE*)reloc.m_origPtr + sizeof(size_t) - from , from);
  1122. from = (BYTE*)reloc.m_origPtr + sizeof(size_t);
  1123. }
  1124. // insert NOPs for aligned labels
  1125. else if ((!PHASE_OFF(Js::LoopAlignPhase, m_func) && reloc.isAlignedLabel()) && reloc.getLabelNopCount() > 0)
  1126. {
  1127. IR::LabelInstr *label = reloc.getLabel();
  1128. BYTE nop_count = reloc.getLabelNopCount();
  1129. AssertMsg((BYTE*)label < buffStart || (BYTE*)label >= buffEnd, "Invalid label pointer.");
  1130. AssertMsg((((uint32)(label->GetPC() - buffStart)) & 0xf) == 0, "Misaligned Label");
  1131. to = reloc.getLabelOrigPC() - 1;
  1132. CopyPartialBufferAndCalculateCRC(&dst_p, dst_size, from, to, pShortenedBufferCRC);
  1133. srcBufferCrc = CalculateCRC(srcBufferCrc, to - from + 1, from);
  1134. #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
  1135. if (PHASE_TRACE(Js::LoopAlignPhase, this->m_func))
  1136. {
  1137. globalTotalBytesInserted += nop_count;
  1138. OUTPUT_VERBOSE_TRACE(Js::LoopAlignPhase, _u("func: %s, bytes inserted: %d, bytes inserted %%:%.4f, total bytes inserted:%d, total bytes inserted %%:%.4f\n"),
  1139. this->m_func->GetJITFunctionBody()->GetDisplayName(), nop_count, (float)nop_count / newCodeSize * 100, globalTotalBytesInserted, (float)globalTotalBytesInserted / (globalTotalBytesWithoutShortening - globalTotalBytesSaved) * 100);
  1140. Output::Flush();
  1141. }
  1142. #endif
  1143. BYTE * tmpDst_p = dst_p;
  1144. InsertNopsForLabelAlignment(nop_count, &dst_p);
  1145. *pShortenedBufferCRC = CalculateCRC(*pShortenedBufferCRC, nop_count, tmpDst_p);
  1146. dst_size -= nop_count;
  1147. from = to + 1;
  1148. }
  1149. }
  1150. // copy last chunk
  1151. //Exclude jumpTable content from CRC calculation.
  1152. //Though jumpTable is not part of the encoded bytes, codeSize has jumpTableSize included in it.
  1153. CopyPartialBufferAndCalculateCRC(&dst_p, dst_size, from, buffStart + *codeSize - 1, pShortenedBufferCRC, jumpTableSize);
  1154. srcBufferCrc = CalculateCRC(srcBufferCrc, buffStart + *codeSize - from - jumpTableSize, from);
  1155. m_encoderMD.UpdateRelocListWithNewBuffer(relocList, tmpBuffer, buffStart, buffEnd);
  1156. if (srcBufferCrc != bufferCrcToValidate)
  1157. {
  1158. Assert(false);
  1159. Fatal();
  1160. }
  1161. // switch buffers
  1162. *codeStart = tmpBuffer;
  1163. *codeSize = newCodeSize;
  1164. return true;
  1165. }
  1166. BYTE Encoder::FindNopCountFor16byteAlignment(size_t address)
  1167. {
  1168. return (16 - (BYTE) (address & 0xf)) % 16;
  1169. }
  1170. void Encoder::CopyPartialBufferAndCalculateCRC(BYTE ** ptrDstBuffer, size_t &dstSize, BYTE * srcStart, BYTE * srcEnd, uint* pBufferCRC, size_t jumpTableSize)
  1171. {
  1172. BYTE * destBuffer = *ptrDstBuffer;
  1173. size_t srcSize = srcEnd - srcStart + 1;
  1174. Assert(dstSize >= srcSize);
  1175. memcpy_s(destBuffer, dstSize, srcStart, srcSize);
  1176. Assert(srcSize >= jumpTableSize);
  1177. //Exclude the jump table content (which is at the end of the buffer) for calculating CRC - at this point.
  1178. *pBufferCRC = CalculateCRC(*pBufferCRC, srcSize - jumpTableSize, destBuffer);
  1179. *ptrDstBuffer += srcSize;
  1180. dstSize -= srcSize;
  1181. }
  1182. void Encoder::InsertNopsForLabelAlignment(int nopCount, BYTE ** ptrDstBuffer)
  1183. {
  1184. // write NOPs
  1185. for (int32 i = 0; i < nopCount; i++, (*ptrDstBuffer)++)
  1186. {
  1187. **ptrDstBuffer = 0x90;
  1188. }
  1189. }
  1190. void Encoder::revertRelocList()
  1191. {
  1192. RelocList* relocList = m_encoderMD.GetRelocList();
  1193. for (int32 i = 0; i < relocList->Count(); i++)
  1194. {
  1195. relocList->Item(i).revert();
  1196. }
  1197. }
  1198. template <bool restore>
  1199. void Encoder::CopyMaps(OffsetList **m_origInlineeFrameRecords
  1200. , OffsetList **m_origInlineeFrameMap
  1201. , OffsetList **m_origPragmaInstrToRecordOffset
  1202. , OffsetList **m_origOffsetBuffer
  1203. )
  1204. {
  1205. InlineeFrameRecords *recList = m_inlineeFrameRecords;
  1206. ArenaInlineeFrameMap *mapList = m_inlineeFrameMap;
  1207. PragmaInstrList *pInstrList = m_pragmaInstrToRecordOffset;
  1208. OffsetList *origRecList, *origMapList, *origPInstrList;
  1209. if (!restore)
  1210. {
  1211. Assert(*m_origInlineeFrameRecords == nullptr);
  1212. Assert(*m_origInlineeFrameMap == nullptr);
  1213. Assert(*m_origPragmaInstrToRecordOffset == nullptr);
  1214. *m_origInlineeFrameRecords = origRecList = Anew(m_tempAlloc, OffsetList, m_tempAlloc);
  1215. *m_origInlineeFrameMap = origMapList = Anew(m_tempAlloc, OffsetList, m_tempAlloc);
  1216. *m_origPragmaInstrToRecordOffset = origPInstrList = Anew(m_tempAlloc, OffsetList, m_tempAlloc);
  1217. #if DBG_DUMP
  1218. Assert((*m_origOffsetBuffer) == nullptr);
  1219. *m_origOffsetBuffer = Anew(m_tempAlloc, OffsetList, m_tempAlloc);
  1220. #endif
  1221. }
  1222. else
  1223. {
  1224. Assert((*m_origInlineeFrameRecords) && (*m_origInlineeFrameMap) && (*m_origPragmaInstrToRecordOffset));
  1225. origRecList = *m_origInlineeFrameRecords;
  1226. origMapList = *m_origInlineeFrameMap;
  1227. origPInstrList = *m_origPragmaInstrToRecordOffset;
  1228. Assert(origRecList->Count() == recList->Count());
  1229. Assert(origMapList->Count() == mapList->Count());
  1230. Assert(origPInstrList->Count() == pInstrList->Count());
  1231. #if DBG_DUMP
  1232. Assert(m_origOffsetBuffer);
  1233. Assert((uint32)(*m_origOffsetBuffer)->Count() == m_instrNumber);
  1234. #endif
  1235. }
  1236. for (int i = 0; i < recList->Count(); i++)
  1237. {
  1238. if (!restore)
  1239. {
  1240. origRecList->Add(recList->Item(i)->inlineeStartOffset);
  1241. }
  1242. else
  1243. {
  1244. recList->Item(i)->inlineeStartOffset = origRecList->Item(i);
  1245. }
  1246. }
  1247. for (int i = 0; i < mapList->Count(); i++)
  1248. {
  1249. if (!restore)
  1250. {
  1251. origMapList->Add(mapList->Item(i).offset);
  1252. }
  1253. else
  1254. {
  1255. mapList->Item(i).offset = origMapList->Item(i);
  1256. }
  1257. }
  1258. for (int i = 0; i < pInstrList->Count(); i++)
  1259. {
  1260. if (!restore)
  1261. {
  1262. origPInstrList->Add(pInstrList->Item(i)->m_offsetInBuffer);
  1263. }
  1264. else
  1265. {
  1266. pInstrList->Item(i)->m_offsetInBuffer = origPInstrList->Item(i);
  1267. }
  1268. }
  1269. if (restore)
  1270. {
  1271. (*m_origInlineeFrameRecords)->Delete();
  1272. (*m_origInlineeFrameMap)->Delete();
  1273. (*m_origPragmaInstrToRecordOffset)->Delete();
  1274. (*m_origInlineeFrameRecords) = nullptr;
  1275. (*m_origInlineeFrameMap) = nullptr;
  1276. (*m_origPragmaInstrToRecordOffset) = nullptr;
  1277. }
  1278. #if DBG_DUMP
  1279. for (uint i = 0; i < m_instrNumber; i++)
  1280. {
  1281. if (!restore)
  1282. {
  1283. (*m_origOffsetBuffer)->Add(m_offsetBuffer[i]);
  1284. }
  1285. else
  1286. {
  1287. m_offsetBuffer[i] = (*m_origOffsetBuffer)->Item(i);
  1288. }
  1289. }
  1290. if (restore)
  1291. {
  1292. (*m_origOffsetBuffer)->Delete();
  1293. (*m_origOffsetBuffer) = nullptr;
  1294. }
  1295. #endif
  1296. }
  1297. #endif
  1298. void Encoder::RecordBailout(IR::Instr* instr, uint32 currentOffset)
  1299. {
  1300. BailOutInfo* bailoutInfo = instr->GetBailOutInfo();
  1301. if (bailoutInfo->bailOutRecord == nullptr)
  1302. {
  1303. return;
  1304. }
  1305. #if DBG_DUMP
  1306. if (PHASE_DUMP(Js::LazyBailoutPhase, m_func))
  1307. {
  1308. Output::Print(_u("Offset: %u Instr: "), currentOffset);
  1309. instr->Dump();
  1310. Output::Print(_u("Bailout label: "));
  1311. bailoutInfo->bailOutInstr->Dump();
  1312. }
  1313. #endif
  1314. Assert(bailoutInfo->bailOutInstr->IsLabelInstr());
  1315. LazyBailOutRecord record(currentOffset, (BYTE*)bailoutInfo->bailOutInstr, bailoutInfo->bailOutRecord);
  1316. m_bailoutRecordMap->Add(record);
  1317. }
  1318. #if DBG_DUMP
  1319. void Encoder::DumpInlineeFrameMap(size_t baseAddress)
  1320. {
  1321. Output::Print(_u("Inlinee frame info mapping\n"));
  1322. Output::Print(_u("---------------------------------------\n"));
  1323. m_inlineeFrameMap->Map([=](uint index, NativeOffsetInlineeFramePair& pair) {
  1324. Output::Print(_u("%Ix"), baseAddress + pair.offset);
  1325. Output::SkipToColumn(20);
  1326. if (pair.record)
  1327. {
  1328. pair.record->Dump();
  1329. }
  1330. else
  1331. {
  1332. Output::Print(_u("<NULL>"));
  1333. }
  1334. Output::Print(_u("\n"));
  1335. });
  1336. }
  1337. #endif