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