Encoder.cpp 60 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553
  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. const bool isSimpleJit = m_func->IsSimpleJit();
  388. if (this->m_inlineeFrameMap->Count() > 0 &&
  389. !(this->m_inlineeFrameMap->Count() == 1 && this->m_inlineeFrameMap->Item(0).record == nullptr))
  390. {
  391. if (!m_func->IsOOPJIT()) // in-proc JIT
  392. {
  393. m_func->GetInProcJITEntryPointInfo()->RecordInlineeFrameMap(m_inlineeFrameMap);
  394. }
  395. else // OOP JIT
  396. {
  397. NativeOffsetInlineeFrameRecordOffset* pairs = NativeCodeDataNewArrayZNoFixup(m_func->GetNativeCodeDataAllocator(), NativeOffsetInlineeFrameRecordOffset, this->m_inlineeFrameMap->Count());
  398. this->m_inlineeFrameMap->Map([&pairs](int i, NativeOffsetInlineeFramePair& p)
  399. {
  400. pairs[i].offset = p.offset;
  401. if (p.record)
  402. {
  403. pairs[i].recordOffset = NativeCodeData::GetDataChunk(p.record)->offset;
  404. }
  405. else
  406. {
  407. pairs[i].recordOffset = NativeOffsetInlineeFrameRecordOffset::InvalidRecordOffset;
  408. }
  409. });
  410. m_func->GetJITOutput()->RecordInlineeFrameOffsetsInfo(NativeCodeData::GetDataChunk(pairs)->offset, this->m_inlineeFrameMap->Count());
  411. }
  412. }
  413. if (this->m_bailoutRecordMap->Count() > 0)
  414. {
  415. m_func->GetInProcJITEntryPointInfo()->RecordBailOutMap(m_bailoutRecordMap);
  416. }
  417. if (this->m_func->pinnedTypeRefs != nullptr)
  418. {
  419. Assert(!isSimpleJit);
  420. int pinnedTypeRefCount = this->m_func->pinnedTypeRefs->Count();
  421. PinnedTypeRefsIDL* pinnedTypeRefs = nullptr;
  422. if (this->m_func->IsOOPJIT())
  423. {
  424. pinnedTypeRefs = (PinnedTypeRefsIDL*)midl_user_allocate(offsetof(PinnedTypeRefsIDL, typeRefs) + sizeof(void*)*pinnedTypeRefCount);
  425. if (!pinnedTypeRefs)
  426. {
  427. Js::Throw::OutOfMemory();
  428. }
  429. __analysis_assume(pinnedTypeRefs);
  430. pinnedTypeRefs->count = pinnedTypeRefCount;
  431. pinnedTypeRefs->isOOPJIT = true;
  432. this->m_func->GetJITOutput()->GetOutputData()->pinnedTypeRefs = pinnedTypeRefs;
  433. }
  434. else
  435. {
  436. pinnedTypeRefs = HeapNewStructPlus(offsetof(PinnedTypeRefsIDL, typeRefs) + sizeof(void*)*pinnedTypeRefCount - sizeof(PinnedTypeRefsIDL), PinnedTypeRefsIDL);
  437. pinnedTypeRefs->count = pinnedTypeRefCount;
  438. pinnedTypeRefs->isOOPJIT = false;
  439. }
  440. int index = 0;
  441. this->m_func->pinnedTypeRefs->Map([&pinnedTypeRefs, &index](void* typeRef) -> void
  442. {
  443. pinnedTypeRefs->typeRefs[index++] = ((JITType*)typeRef)->GetAddr();
  444. });
  445. if (PHASE_TRACE(Js::TracePinnedTypesPhase, this->m_func))
  446. {
  447. char16 debugStringBuffer[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE];
  448. Output::Print(_u("PinnedTypes: function %s(%s) pinned %d types.\n"),
  449. this->m_func->GetJITFunctionBody()->GetDisplayName(), this->m_func->GetDebugNumberSet(debugStringBuffer), pinnedTypeRefCount);
  450. Output::Flush();
  451. }
  452. if (!this->m_func->IsOOPJIT())
  453. {
  454. m_func->GetInProcJITEntryPointInfo()->GetJitTransferData()->SetRuntimeTypeRefs(pinnedTypeRefs);
  455. }
  456. }
  457. // Save all equivalent type guards in a fixed size array on the JIT transfer data
  458. if (this->m_func->equivalentTypeGuards != nullptr)
  459. {
  460. AssertMsg(!PHASE_OFF(Js::EquivObjTypeSpecPhase, this->m_func), "Why do we have equivalent type guards if we don't do equivalent object type spec?");
  461. int equivalentTypeGuardsCount = this->m_func->equivalentTypeGuards->Count();
  462. if (this->m_func->IsOOPJIT())
  463. {
  464. auto& equivalentTypeGuardOffsets = this->m_func->GetJITOutput()->GetOutputData()->equivalentTypeGuardOffsets;
  465. size_t allocSize = offsetof(EquivalentTypeGuardOffsets, guards) + equivalentTypeGuardsCount * sizeof(EquivalentTypeGuardIDL);
  466. equivalentTypeGuardOffsets = (EquivalentTypeGuardOffsets*)midl_user_allocate(allocSize);
  467. if (equivalentTypeGuardOffsets == nullptr)
  468. {
  469. Js::Throw::OutOfMemory();
  470. }
  471. equivalentTypeGuardOffsets->count = equivalentTypeGuardsCount;
  472. int i = 0;
  473. this->m_func->equivalentTypeGuards->Map([&equivalentTypeGuardOffsets, &i](Js::JitEquivalentTypeGuard* srcGuard) -> void
  474. {
  475. equivalentTypeGuardOffsets->guards[i].offset = NativeCodeData::GetDataTotalOffset(srcGuard);
  476. auto cache = srcGuard->GetCache();
  477. equivalentTypeGuardOffsets->guards[i].cache.guardOffset = NativeCodeData::GetDataTotalOffset(cache->guard);
  478. equivalentTypeGuardOffsets->guards[i].cache.hasFixedValue = cache->hasFixedValue;
  479. equivalentTypeGuardOffsets->guards[i].cache.isLoadedFromProto = cache->isLoadedFromProto;
  480. equivalentTypeGuardOffsets->guards[i].cache.nextEvictionVictim = cache->nextEvictionVictim;
  481. equivalentTypeGuardOffsets->guards[i].cache.record.propertyCount = cache->record.propertyCount;
  482. equivalentTypeGuardOffsets->guards[i].cache.record.propertyOffset = NativeCodeData::GetDataTotalOffset(cache->record.properties);
  483. for (int j = 0; j < EQUIVALENT_TYPE_CACHE_SIZE; j++)
  484. {
  485. equivalentTypeGuardOffsets->guards[i].cache.types[j] = (intptr_t)PointerValue(cache->types[j]);
  486. }
  487. i++;
  488. });
  489. Assert(equivalentTypeGuardsCount == i);
  490. }
  491. else
  492. {
  493. Js::JitEquivalentTypeGuard** guards = HeapNewArrayZ(Js::JitEquivalentTypeGuard*, equivalentTypeGuardsCount);
  494. Js::JitEquivalentTypeGuard** dstGuard = guards;
  495. this->m_func->equivalentTypeGuards->Map([&dstGuard](Js::JitEquivalentTypeGuard* srcGuard) -> void
  496. {
  497. *dstGuard++ = srcGuard;
  498. });
  499. m_func->GetInProcJITEntryPointInfo()->GetJitTransferData()->SetEquivalentTypeGuards(guards, equivalentTypeGuardsCount);
  500. }
  501. }
  502. if (this->m_func->lazyBailoutProperties.Count() > 0)
  503. {
  504. int count = this->m_func->lazyBailoutProperties.Count();
  505. Js::PropertyId* lazyBailoutProperties = HeapNewArrayZ(Js::PropertyId, count);
  506. Js::PropertyId* dstProperties = lazyBailoutProperties;
  507. this->m_func->lazyBailoutProperties.Map([&](Js::PropertyId propertyId)
  508. {
  509. *dstProperties++ = propertyId;
  510. });
  511. m_func->GetInProcJITEntryPointInfo()->GetJitTransferData()->SetLazyBailoutProperties(lazyBailoutProperties, count);
  512. }
  513. // 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
  514. // point to register each guard for invalidation.
  515. if (this->m_func->propertyGuardsByPropertyId != nullptr)
  516. {
  517. Assert(!isSimpleJit);
  518. AssertMsg(!(PHASE_OFF(Js::ObjTypeSpecPhase, this->m_func) && PHASE_OFF(Js::FixedMethodsPhase, this->m_func)),
  519. "Why do we have type guards if we don't do object type spec or fixed methods?");
  520. #if DBG
  521. int totalGuardCount = (this->m_func->singleTypeGuards != nullptr ? this->m_func->singleTypeGuards->Count() : 0)
  522. + (this->m_func->equivalentTypeGuards != nullptr ? this->m_func->equivalentTypeGuards->Count() : 0);
  523. Assert(totalGuardCount > 0);
  524. Assert(totalGuardCount == this->m_func->indexedPropertyGuardCount);
  525. #endif
  526. if (!this->m_func->IsOOPJIT())
  527. {
  528. int propertyCount = this->m_func->propertyGuardsByPropertyId->Count();
  529. Assert(propertyCount > 0);
  530. int guardSlotCount = 0;
  531. this->m_func->propertyGuardsByPropertyId->Map([&guardSlotCount](Js::PropertyId propertyId, Func::IndexedPropertyGuardSet* set) -> void
  532. {
  533. guardSlotCount += set->Count();
  534. });
  535. size_t typeGuardTransferSize = // Reserve enough room for:
  536. propertyCount * sizeof(Js::TypeGuardTransferEntry) + // each propertyId,
  537. propertyCount * sizeof(Js::JitIndexedPropertyGuard*) + // terminating nullptr guard for each propertyId,
  538. guardSlotCount * sizeof(Js::JitIndexedPropertyGuard*); // a pointer for each guard we counted above.
  539. // The extra room for sizeof(Js::TypePropertyGuardEntry) allocated by HeapNewPlus will be used for the terminating invalid propertyId.
  540. // Review (jedmiad): Skip zeroing? This is heap allocated so there shouldn't be any false recycler references.
  541. Js::TypeGuardTransferEntry* typeGuardTransferRecord = HeapNewPlusZ(typeGuardTransferSize, Js::TypeGuardTransferEntry);
  542. Func* func = this->m_func;
  543. Js::TypeGuardTransferEntry* dstEntry = typeGuardTransferRecord;
  544. this->m_func->propertyGuardsByPropertyId->Map([func, &dstEntry](Js::PropertyId propertyId, Func::IndexedPropertyGuardSet* srcSet) -> void
  545. {
  546. dstEntry->propertyId = propertyId;
  547. int guardIndex = 0;
  548. srcSet->Map([dstEntry, &guardIndex](Js::JitIndexedPropertyGuard* guard) -> void
  549. {
  550. dstEntry->guards[guardIndex++] = guard;
  551. });
  552. dstEntry->guards[guardIndex++] = nullptr;
  553. dstEntry = reinterpret_cast<Js::TypeGuardTransferEntry*>(&dstEntry->guards[guardIndex]);
  554. });
  555. dstEntry->propertyId = Js::Constants::NoProperty;
  556. dstEntry++;
  557. Assert(reinterpret_cast<char*>(dstEntry) <= reinterpret_cast<char*>(typeGuardTransferRecord) + typeGuardTransferSize + sizeof(Js::TypeGuardTransferEntry));
  558. m_func->GetInProcJITEntryPointInfo()->RecordTypeGuards(this->m_func->indexedPropertyGuardCount, typeGuardTransferRecord, typeGuardTransferSize);
  559. }
  560. else
  561. {
  562. Func* func = this->m_func;
  563. this->m_func->GetJITOutput()->GetOutputData()->propertyGuardCount = this->m_func->indexedPropertyGuardCount;
  564. auto entry = &this->m_func->GetJITOutput()->GetOutputData()->typeGuardEntries;
  565. this->m_func->propertyGuardsByPropertyId->Map([func, &entry](Js::PropertyId propertyId, Func::IndexedPropertyGuardSet* srcSet) -> void
  566. {
  567. auto count = srcSet->Count();
  568. (*entry) = (TypeGuardTransferEntryIDL*)midl_user_allocate(offsetof(TypeGuardTransferEntryIDL, guardOffsets) + count*sizeof(int));
  569. if (!*entry)
  570. {
  571. Js::Throw::OutOfMemory();
  572. }
  573. __analysis_assume(*entry);
  574. (*entry)->propId = propertyId;
  575. (*entry)->guardsCount = count;
  576. (*entry)->next = nullptr;
  577. auto& guardOffsets = (*entry)->guardOffsets;
  578. int guardIndex = 0;
  579. srcSet->Map([&guardOffsets, &guardIndex](Js::JitIndexedPropertyGuard* guard) -> void
  580. {
  581. guardOffsets[guardIndex++] = NativeCodeData::GetDataTotalOffset(guard);
  582. });
  583. Assert(guardIndex == count);
  584. entry = &(*entry)->next;
  585. });
  586. }
  587. }
  588. // 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
  589. // point to register each cache for invalidation.
  590. if (this->m_func->ctorCachesByPropertyId != nullptr)
  591. {
  592. Assert(!isSimpleJit);
  593. AssertMsg(!(PHASE_OFF(Js::ObjTypeSpecPhase, this->m_func) && PHASE_OFF(Js::FixedMethodsPhase, this->m_func)),
  594. "Why do we have constructor cache guards if we don't do object type spec or fixed methods?");
  595. int propertyCount = this->m_func->ctorCachesByPropertyId->Count();
  596. Assert(propertyCount > 0);
  597. int cacheSlotCount = 0;
  598. this->m_func->ctorCachesByPropertyId->Map([&cacheSlotCount](Js::PropertyId propertyId, Func::CtorCacheSet* cacheSet) -> void
  599. {
  600. cacheSlotCount += cacheSet->Count();
  601. });
  602. if (m_func->IsOOPJIT())
  603. {
  604. Func* func = this->m_func;
  605. m_func->GetJITOutput()->GetOutputData()->ctorCachesCount = propertyCount;
  606. m_func->GetJITOutput()->GetOutputData()->ctorCacheEntries = (CtorCacheTransferEntryIDL**)midl_user_allocate(propertyCount * sizeof(CtorCacheTransferEntryIDL*));
  607. CtorCacheTransferEntryIDL** entries = m_func->GetJITOutput()->GetOutputData()->ctorCacheEntries;
  608. if (!entries)
  609. {
  610. Js::Throw::OutOfMemory();
  611. }
  612. __analysis_assume(entries);
  613. uint propIndex = 0;
  614. m_func->ctorCachesByPropertyId->Map([func, entries, &propIndex](Js::PropertyId propertyId, Func::CtorCacheSet* srcCacheSet) -> void
  615. {
  616. entries[propIndex] = (CtorCacheTransferEntryIDL*)midl_user_allocate(srcCacheSet->Count() * sizeof(intptr_t) + sizeof(CtorCacheTransferEntryIDL));
  617. if (!entries[propIndex])
  618. {
  619. Js::Throw::OutOfMemory();
  620. }
  621. __analysis_assume(entries[propIndex]);
  622. entries[propIndex]->propId = propertyId;
  623. int cacheIndex = 0;
  624. srcCacheSet->Map([entries, propIndex, &cacheIndex](intptr_t cache) -> void
  625. {
  626. entries[propIndex]->caches[cacheIndex++] = cache;
  627. });
  628. entries[propIndex]->cacheCount = cacheIndex;
  629. propIndex++;
  630. });
  631. }
  632. else
  633. {
  634. Assert(m_func->GetInProcJITEntryPointInfo()->GetConstructorCacheCount() > 0);
  635. size_t ctorCachesTransferSize = // Reserve enough room for:
  636. propertyCount * sizeof(Js::CtorCacheGuardTransferEntry) + // each propertyId,
  637. propertyCount * sizeof(Js::ConstructorCache*) + // terminating null cache for each propertyId,
  638. cacheSlotCount * sizeof(Js::JitIndexedPropertyGuard*); // a pointer for each cache we counted above.
  639. // The extra room for sizeof(Js::CtorCacheGuardTransferEntry) allocated by HeapNewPlus will be used for the terminating invalid propertyId.
  640. // Review (jedmiad): Skip zeroing? This is heap allocated so there shouldn't be any false recycler references.
  641. Js::CtorCacheGuardTransferEntry* ctorCachesTransferRecord = HeapNewPlusZ(ctorCachesTransferSize, Js::CtorCacheGuardTransferEntry);
  642. Func* func = this->m_func;
  643. Js::CtorCacheGuardTransferEntry* dstEntry = ctorCachesTransferRecord;
  644. this->m_func->ctorCachesByPropertyId->Map([func, &dstEntry](Js::PropertyId propertyId, Func::CtorCacheSet* srcCacheSet) -> void
  645. {
  646. dstEntry->propertyId = propertyId;
  647. int cacheIndex = 0;
  648. srcCacheSet->Map([dstEntry, &cacheIndex](intptr_t cache) -> void
  649. {
  650. dstEntry->caches[cacheIndex++] = cache;
  651. });
  652. dstEntry->caches[cacheIndex++] = 0;
  653. dstEntry = reinterpret_cast<Js::CtorCacheGuardTransferEntry*>(&dstEntry->caches[cacheIndex]);
  654. });
  655. dstEntry->propertyId = Js::Constants::NoProperty;
  656. dstEntry++;
  657. Assert(reinterpret_cast<char*>(dstEntry) <= reinterpret_cast<char*>(ctorCachesTransferRecord) + ctorCachesTransferSize + sizeof(Js::CtorCacheGuardTransferEntry));
  658. m_func->GetInProcJITEntryPointInfo()->RecordCtorCacheGuards(ctorCachesTransferRecord, ctorCachesTransferSize);
  659. }
  660. }
  661. m_func->GetJITOutput()->FinalizeNativeCode();
  662. END_CODEGEN_PHASE(m_func, Js::EmitterPhase);
  663. #if DBG_DUMP
  664. m_func->m_codeSize = codeSize;
  665. if (PHASE_DUMP(Js::EncoderPhase, m_func) || PHASE_DUMP(Js::BackEndPhase, m_func))
  666. {
  667. bool dumpIRAddressesValue = Js::Configuration::Global.flags.DumpIRAddresses;
  668. Js::Configuration::Global.flags.DumpIRAddresses = true;
  669. this->m_func->DumpHeader();
  670. m_instrNumber = 0;
  671. FOREACH_INSTR_IN_FUNC(instr, m_func)
  672. {
  673. __analysis_assume(m_instrNumber < instrCount);
  674. instr->DumpGlobOptInstrString();
  675. #ifdef _WIN64
  676. Output::Print(_u("%12IX "), m_offsetBuffer[m_instrNumber++] + (BYTE *)m_func->GetJITOutput()->GetCodeAddress());
  677. #else
  678. Output::Print(_u("%8IX "), m_offsetBuffer[m_instrNumber++] + (BYTE *)m_func->GetJITOutput()->GetCodeAddress());
  679. #endif
  680. instr->Dump();
  681. } NEXT_INSTR_IN_FUNC;
  682. Output::Flush();
  683. Js::Configuration::Global.flags.DumpIRAddresses = dumpIRAddressesValue;
  684. }
  685. if (PHASE_DUMP(Js::EncoderPhase, m_func) && Js::Configuration::Global.flags.Verbose && !m_func->IsOOPJIT())
  686. {
  687. m_func->GetInProcJITEntryPointInfo()->DumpNativeOffsetMaps();
  688. m_func->GetInProcJITEntryPointInfo()->DumpNativeThrowSpanSequence();
  689. this->DumpInlineeFrameMap(m_func->GetJITOutput()->GetCodeAddress());
  690. Output::Flush();
  691. }
  692. #endif
  693. }
  694. bool Encoder::DoTrackAllStatementBoundary() const
  695. {
  696. #if DBG_DUMP | defined(VTUNE_PROFILING)
  697. return this->m_func->DoRecordNativeMap();
  698. #else
  699. return false;
  700. #endif
  701. }
  702. void Encoder::TryCopyAndAddRelocRecordsForSwitchJumpTableEntries(BYTE *codeStart, size_t codeSize, JmpTableList * jumpTableListForSwitchStatement, size_t totalJmpTableSizeInBytes)
  703. {
  704. if (jumpTableListForSwitchStatement == nullptr)
  705. {
  706. return;
  707. }
  708. BYTE * jmpTableStartAddress = codeStart + codeSize - totalJmpTableSizeInBytes;
  709. EncoderMD * encoderMD = &m_encoderMD;
  710. jumpTableListForSwitchStatement->Map([&](uint index, BranchJumpTableWrapper * branchJumpTableWrapper) -> void
  711. {
  712. Assert(branchJumpTableWrapper != nullptr);
  713. void ** srcJmpTable = branchJumpTableWrapper->jmpTable;
  714. size_t jmpTableSizeInBytes = branchJumpTableWrapper->tableSize * sizeof(void*);
  715. AssertMsg(branchJumpTableWrapper->labelInstr != nullptr, "Label not yet created?");
  716. Assert(branchJumpTableWrapper->labelInstr->GetPC() == nullptr);
  717. branchJumpTableWrapper->labelInstr->SetPC(jmpTableStartAddress);
  718. memcpy(jmpTableStartAddress, srcJmpTable, jmpTableSizeInBytes);
  719. for (int i = 0; i < branchJumpTableWrapper->tableSize; i++)
  720. {
  721. void * addressOfJmpTableEntry = jmpTableStartAddress + (i * sizeof(void*));
  722. Assert((ptrdiff_t) addressOfJmpTableEntry - (ptrdiff_t) jmpTableStartAddress < (ptrdiff_t) jmpTableSizeInBytes);
  723. #if defined(_M_ARM32_OR_ARM64)
  724. encoderMD->AddLabelReloc((byte*) addressOfJmpTableEntry);
  725. #else
  726. encoderMD->AppendRelocEntry(RelocTypeLabelUse, addressOfJmpTableEntry, *(IR::LabelInstr**)addressOfJmpTableEntry);
  727. *((size_t*)addressOfJmpTableEntry) = 0;
  728. #endif
  729. }
  730. jmpTableStartAddress += (jmpTableSizeInBytes);
  731. });
  732. Assert(jmpTableStartAddress == codeStart + codeSize);
  733. }
  734. uint32 Encoder::GetCurrentOffset() const
  735. {
  736. Assert(m_pc - m_encodeBuffer <= UINT_MAX); // encode buffer size is uint32
  737. return static_cast<uint32>(m_pc - m_encodeBuffer);
  738. }
  739. void Encoder::RecordInlineeFrame(Func* inlinee, uint32 currentOffset)
  740. {
  741. // The only restriction for not supporting loop bodies is that inlinee frame map is created on FunctionEntryPointInfo & not
  742. // the base class EntryPointInfo.
  743. if (!(this->m_func->IsLoopBody() && PHASE_OFF(Js::InlineInJitLoopBodyPhase, this->m_func)) && !this->m_func->IsSimpleJit())
  744. {
  745. InlineeFrameRecord* record = nullptr;
  746. if (inlinee->frameInfo && inlinee->m_hasInlineArgsOpt)
  747. {
  748. record = inlinee->frameInfo->record;
  749. Assert(record != nullptr);
  750. }
  751. if (m_inlineeFrameMap->Count() > 0)
  752. {
  753. // update existing record if the entry is the same.
  754. NativeOffsetInlineeFramePair& lastPair = m_inlineeFrameMap->Item(m_inlineeFrameMap->Count() - 1);
  755. if (lastPair.record == record)
  756. {
  757. lastPair.offset = currentOffset;
  758. return;
  759. }
  760. }
  761. NativeOffsetInlineeFramePair pair = { currentOffset, record };
  762. m_inlineeFrameMap->Add(pair);
  763. }
  764. }
  765. #if defined(_M_IX86) || defined(_M_X64)
  766. /*
  767. * ValidateCRCOnFinalBuffer
  768. * - Validates the CRC that is last computed (could be either the one after BranchShortening or after encoding itself)
  769. * - We calculate the CRC for jump table and dictionary after computing the code section.
  770. * - 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.
  771. * - 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.
  772. */
  773. 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)
  774. {
  775. RelocList * relocList = m_encoderMD.GetRelocList();
  776. BYTE * currentStartAddress = finalCodeBufferStart;
  777. BYTE * currentEndAddress = nullptr;
  778. size_t crcSizeToCompute = 0;
  779. size_t finalCodeSizeWithoutJumpTable = finalCodeSize - jumpTableSize;
  780. uint finalBufferCRC = initialCrcSeed;
  781. BYTE * oldPtr = nullptr;
  782. if (relocList != nullptr)
  783. {
  784. for (int index = 0; index < relocList->Count(); index++)
  785. {
  786. EncodeRelocAndLabels * relocTuple = &relocList->Item(index);
  787. //We will deal with the jump table and dictionary entries along with other reloc records in ApplyRelocs()
  788. if ((BYTE*)m_encoderMD.GetRelocBufferAddress(relocTuple) >= oldCodeBufferStart && (BYTE*)m_encoderMD.GetRelocBufferAddress(relocTuple) < (oldCodeBufferStart + finalCodeSizeWithoutJumpTable))
  789. {
  790. BYTE* finalBufferRelocTuplePtr = (BYTE*)m_encoderMD.GetRelocBufferAddress(relocTuple) - oldCodeBufferStart + finalCodeBufferStart;
  791. Assert(finalBufferRelocTuplePtr >= finalCodeBufferStart && finalBufferRelocTuplePtr < (finalCodeBufferStart + finalCodeSizeWithoutJumpTable));
  792. uint relocDataSize = m_encoderMD.GetRelocDataSize(relocTuple);
  793. if (relocDataSize != 0)
  794. {
  795. AssertMsg(oldPtr == nullptr || oldPtr < finalBufferRelocTuplePtr, "Assumption here is that the reloc list is strictly increasing in terms of bufferAddress");
  796. oldPtr = finalBufferRelocTuplePtr;
  797. currentEndAddress = finalBufferRelocTuplePtr;
  798. crcSizeToCompute = currentEndAddress - currentStartAddress;
  799. Assert(currentEndAddress >= currentStartAddress);
  800. finalBufferCRC = CalculateCRC(finalBufferCRC, crcSizeToCompute, currentStartAddress);
  801. for (uint i = 0; i < relocDataSize; i++)
  802. {
  803. finalBufferCRC = CalculateCRC(finalBufferCRC, 0);
  804. }
  805. currentStartAddress = currentEndAddress + relocDataSize;
  806. }
  807. }
  808. }
  809. }
  810. currentEndAddress = finalCodeBufferStart + finalCodeSizeWithoutJumpTable;
  811. crcSizeToCompute = currentEndAddress - currentStartAddress;
  812. Assert(currentEndAddress >= currentStartAddress);
  813. finalBufferCRC = CalculateCRC(finalBufferCRC, crcSizeToCompute, currentStartAddress);
  814. //Include all offsets from the reloc records to the CRC.
  815. m_encoderMD.ApplyRelocs((size_t)finalCodeBufferStart, finalCodeSize, &finalBufferCRC, isSuccessBrShortAndLoopAlign, true);
  816. if (finalBufferCRC != bufferCrcToValidate)
  817. {
  818. Assert(false);
  819. Fatal();
  820. }
  821. }
  822. #endif
  823. /*
  824. * EnsureRelocEntryIntegrity
  825. * - We compute the target address as the processor would compute it and check if the target is within the final buffer's bounds.
  826. * - For relative addressing, Target = current m_pc + offset
  827. * - For absolute addressing, Target = direct address
  828. */
  829. void Encoder::EnsureRelocEntryIntegrity(size_t newBufferStartAddress, size_t codeSize, size_t oldBufferAddress, size_t relocAddress, uint offsetBytes, ptrdiff_t opndData, bool isRelativeAddr)
  830. {
  831. size_t targetBrAddress = 0;
  832. size_t newBufferEndAddress = newBufferStartAddress + codeSize;
  833. //Handle Dictionary addresses here - The target address will be in the dictionary.
  834. if (relocAddress < oldBufferAddress || relocAddress >= (oldBufferAddress + codeSize))
  835. {
  836. targetBrAddress = (size_t)(*(size_t*)relocAddress);
  837. }
  838. else
  839. {
  840. size_t newBufferRelocAddr = relocAddress - oldBufferAddress + newBufferStartAddress;
  841. if (isRelativeAddr)
  842. {
  843. targetBrAddress = (size_t)newBufferRelocAddr + offsetBytes + opndData;
  844. }
  845. else // Absolute Address
  846. {
  847. targetBrAddress = (size_t)opndData;
  848. }
  849. }
  850. if (targetBrAddress < newBufferStartAddress || targetBrAddress >= newBufferEndAddress)
  851. {
  852. Assert(false);
  853. Fatal();
  854. }
  855. }
  856. uint Encoder::CalculateCRC(uint bufferCRC, size_t data)
  857. {
  858. #if defined(_WIN32) || defined(__SSE4_2__)
  859. #if defined(_M_IX86)
  860. if (AutoSystemInfo::Data.SSE4_2Available())
  861. {
  862. return _mm_crc32_u32(bufferCRC, data);
  863. }
  864. #elif defined(_M_X64)
  865. if (AutoSystemInfo::Data.SSE4_2Available())
  866. {
  867. //CRC32 always returns a 32-bit result
  868. return (uint)_mm_crc32_u64(bufferCRC, data);
  869. }
  870. #endif
  871. #endif
  872. return CalculateCRC32(bufferCRC, data);
  873. }
  874. uint Encoder::CalculateCRC(uint bufferCRC, size_t count, _In_reads_bytes_(count) void * buffer)
  875. {
  876. for (uint index = 0; index < count; index++)
  877. {
  878. bufferCRC = CalculateCRC(bufferCRC, *((BYTE*)buffer + index));
  879. }
  880. return bufferCRC;
  881. }
  882. void Encoder::ValidateCRC(uint bufferCRC, uint initialCRCSeed, _In_reads_bytes_(count) void* buffer, size_t count)
  883. {
  884. uint validationCRC = initialCRCSeed;
  885. validationCRC = CalculateCRC(validationCRC, count, buffer);
  886. if (validationCRC != bufferCRC)
  887. {
  888. //TODO: This throws internal error. Is this error type, Fine?
  889. Fatal();
  890. }
  891. }
  892. #if defined(_M_IX86) || defined(_M_X64)
  893. ///----------------------------------------------------------------------------
  894. ///
  895. /// EncoderMD::ShortenBranchesAndLabelAlign
  896. /// We try to shorten branches if the label instr is within 8-bits target range (-128 to 127)
  897. /// and fix the relocList accordingly.
  898. /// Also align LoopTop Label and TryCatchLabel
  899. ///----------------------------------------------------------------------------
  900. BOOL
  901. Encoder::ShortenBranchesAndLabelAlign(BYTE **codeStart, ptrdiff_t *codeSize, uint * pShortenedBufferCRC, uint bufferCrcToValidate, size_t jumpTableSize)
  902. {
  903. #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
  904. static uint32 globalTotalBytesSaved = 0, globalTotalBytesWithoutShortening = 0;
  905. static uint32 globalTotalBytesInserted = 0; // loop alignment nops
  906. #endif
  907. uint32 brShortenedCount = 0;
  908. bool codeChange = false; // any overall BR shortened or label aligned ?
  909. BYTE* buffStart = *codeStart;
  910. BYTE* buffEnd = buffStart + *codeSize;
  911. ptrdiff_t newCodeSize = *codeSize;
  912. RelocList* relocList = m_encoderMD.GetRelocList();
  913. if (relocList == nullptr)
  914. {
  915. return false;
  916. }
  917. #if DBG
  918. // Sanity check
  919. m_encoderMD.VerifyRelocList(buffStart, buffEnd);
  920. #endif
  921. // Copy of original maps. Used to revert from BR shortening.
  922. OffsetList *m_origInlineeFrameRecords = nullptr,
  923. *m_origInlineeFrameMap = nullptr,
  924. *m_origPragmaInstrToRecordOffset = nullptr;
  925. OffsetList *m_origOffsetBuffer = nullptr;
  926. // we record the original maps, in case we have to revert.
  927. CopyMaps<false>(&m_origInlineeFrameRecords
  928. , &m_origInlineeFrameMap
  929. , &m_origPragmaInstrToRecordOffset
  930. , &m_origOffsetBuffer );
  931. // Here we mark BRs to be shortened and adjust Labels and relocList entries offsets.
  932. uint32 offsetBuffIndex = 0, pragmaInstToRecordOffsetIndex = 0, inlineeFrameRecordsIndex = 0, inlineeFrameMapIndex = 0;
  933. int32 totalBytesSaved = 0;
  934. // loop over all BRs, find the ones we can convert to short form
  935. for (int32 j = 0; j < relocList->Count(); j++)
  936. {
  937. IR::LabelInstr *targetLabel;
  938. int32 relOffset;
  939. uint32 bytesSaved = 0;
  940. BYTE* labelPc, *opcodeByte;
  941. BYTE* shortBrPtr, *fixedBrPtr; // without shortening
  942. EncodeRelocAndLabels &reloc = relocList->Item(j);
  943. // If not a long branch, just fix the reloc entry and skip.
  944. if (!reloc.isLongBr())
  945. {
  946. // if loop alignment is required, total bytes saved can change
  947. int32 newTotalBytesSaved = m_encoderMD.FixRelocListEntry(j, totalBytesSaved, buffStart, buffEnd);
  948. if (newTotalBytesSaved != totalBytesSaved)
  949. {
  950. AssertMsg(reloc.isAlignedLabel(), "Expecting aligned label.");
  951. // we aligned a loop, fix maps
  952. m_encoderMD.FixMaps((uint32)(reloc.getLabelOrigPC() - buffStart), totalBytesSaved, &inlineeFrameRecordsIndex, &inlineeFrameMapIndex, &pragmaInstToRecordOffsetIndex, &offsetBuffIndex);
  953. codeChange = true;
  954. }
  955. totalBytesSaved = newTotalBytesSaved;
  956. continue;
  957. }
  958. AssertMsg(reloc.isLongBr(), "Cannot shorten already shortened branch.");
  959. // long branch
  960. opcodeByte = reloc.getBrOpCodeByte();
  961. targetLabel = reloc.getBrTargetLabel();
  962. AssertMsg(targetLabel != nullptr, "Branch to non-existing label");
  963. labelPc = targetLabel->GetPC();
  964. // compute the new offset of that Br because of previous shortening/alignment
  965. shortBrPtr = fixedBrPtr = (BYTE*)reloc.m_ptr - totalBytesSaved;
  966. if (*opcodeByte == 0xe9 /* JMP rel32 */)
  967. {
  968. bytesSaved = 3;
  969. }
  970. else if (*opcodeByte >= 0x80 && *opcodeByte < 0x90 /* Jcc rel32 */)
  971. {
  972. Assert(*(opcodeByte - 1) == 0x0f);
  973. bytesSaved = 4;
  974. // Jcc rel8 is one byte shorter in opcode, fix Br ptr to point to start of rel8
  975. shortBrPtr--;
  976. }
  977. else
  978. {
  979. Assert(false);
  980. }
  981. // compute current distance to label
  982. if (labelPc >= (BYTE*) reloc.m_ptr)
  983. {
  984. // forward Br. We compare using the unfixed m_ptr, because the label is ahead and its Pc is not fixed it.
  985. relOffset = (int32)(labelPc - ((BYTE*)reloc.m_ptr + 4));
  986. }
  987. else
  988. {
  989. // backward Br. We compute relOffset after fixing the Br, since the label is already fixed.
  990. // We also include the 3-4 bytes saved after shortening the Br since the Br itself is included in the relative offset.
  991. relOffset = (int32)(labelPc - (shortBrPtr + 1));
  992. }
  993. // update Br offset (overwritten later if Br is shortened)
  994. reloc.m_ptr = fixedBrPtr;
  995. // can we shorten ?
  996. if (relOffset >= -128 && relOffset <= 127)
  997. {
  998. uint32 brOffset;
  999. brShortenedCount++;
  1000. // update with shortened br offset
  1001. reloc.m_ptr = shortBrPtr;
  1002. // fix all maps entries from last shortened br to this one, before updating total bytes saved.
  1003. brOffset = (uint32) ((BYTE*)reloc.m_origPtr - buffStart);
  1004. m_encoderMD.FixMaps(brOffset, totalBytesSaved, &inlineeFrameRecordsIndex, &inlineeFrameMapIndex, &pragmaInstToRecordOffsetIndex, &offsetBuffIndex);
  1005. codeChange = true;
  1006. totalBytesSaved += bytesSaved;
  1007. // mark br reloc entry as shortened
  1008. #ifdef _M_IX86
  1009. reloc.setAsShortBr(targetLabel);
  1010. #else
  1011. reloc.setAsShortBr();
  1012. #endif
  1013. }
  1014. }
  1015. // Fix the rest of the maps, if needed.
  1016. if (totalBytesSaved != 0)
  1017. {
  1018. m_encoderMD.FixMaps((uint32) -1, totalBytesSaved, &inlineeFrameRecordsIndex, &inlineeFrameMapIndex, &pragmaInstToRecordOffsetIndex, &offsetBuffIndex);
  1019. codeChange = true;
  1020. newCodeSize -= totalBytesSaved;
  1021. }
  1022. // no BR shortening or Label alignment happened, no need to copy code
  1023. if (!codeChange)
  1024. return codeChange;
  1025. #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
  1026. globalTotalBytesWithoutShortening += (uint32)(*codeSize);
  1027. globalTotalBytesSaved += (uint32)(*codeSize - newCodeSize);
  1028. if (PHASE_TRACE(Js::BrShortenPhase, this->m_func))
  1029. {
  1030. 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"),
  1031. this->m_func->GetJITFunctionBody()->GetDisplayName(), (*codeSize - newCodeSize), ((float)*codeSize - newCodeSize) / *codeSize * 100,
  1032. globalTotalBytesSaved, ((float)globalTotalBytesSaved) / globalTotalBytesWithoutShortening * 100 , brShortenedCount);
  1033. Output::Flush();
  1034. }
  1035. #endif
  1036. // At this point BRs are marked to be shortened, and relocList offsets are adjusted to new instruction length.
  1037. // Next, we re-write the code to shorten the BRs and adjust relocList offsets to point to new buffer.
  1038. // We also write NOPs for aligned loops.
  1039. BYTE* tmpBuffer = AnewArray(m_tempAlloc, BYTE, newCodeSize);
  1040. uint srcBufferCrc = *pShortenedBufferCRC; //This has the intial Random CRC seed to start with.
  1041. // start copying to new buffer
  1042. // this can possibly be done during fixing, but there is no evidence it is an overhead to justify the complexity.
  1043. BYTE *from = buffStart, *to = nullptr;
  1044. BYTE *dst_p = (BYTE*)tmpBuffer;
  1045. size_t dst_size = newCodeSize;
  1046. size_t src_size;
  1047. for (int32 i = 0; i < relocList->Count(); i++)
  1048. {
  1049. EncodeRelocAndLabels &reloc = relocList->Item(i);
  1050. // shorten BR and copy
  1051. if (reloc.isShortBr())
  1052. {
  1053. // validate that short BR offset is within 1 byte offset range.
  1054. // This handles the rare case with loop alignment breaks br shortening.
  1055. // Consider:
  1056. // BR $L1 // shortened
  1057. // ...
  1058. // L2: // aligned, and makes the BR $L1 non-shortable anymore
  1059. // ...
  1060. // BR $L2
  1061. // ...
  1062. // L1:
  1063. // In this case, we simply give up and revert the relocList.
  1064. if(!reloc.validateShortBrTarget())
  1065. {
  1066. revertRelocList();
  1067. // restore maps
  1068. CopyMaps<true>(&m_origInlineeFrameRecords
  1069. , &m_origInlineeFrameMap
  1070. , &m_origPragmaInstrToRecordOffset
  1071. , &m_origOffsetBuffer
  1072. );
  1073. return false;
  1074. }
  1075. // m_origPtr points to imm32 field in the original buffer
  1076. BYTE *opcodeByte = (BYTE*)reloc.m_origPtr - 1;
  1077. if (*opcodeByte == 0xe9 /* JMP rel32 */)
  1078. {
  1079. to = opcodeByte - 1;
  1080. }
  1081. else if (*opcodeByte >= 0x80 && *opcodeByte < 0x90 /* Jcc rel32 */)
  1082. {
  1083. Assert(*(opcodeByte - 1) == 0x0f);
  1084. to = opcodeByte - 2;
  1085. }
  1086. else
  1087. {
  1088. Assert(false);
  1089. }
  1090. src_size = to - from + 1;
  1091. AnalysisAssert(dst_size >= src_size);
  1092. memcpy_s(dst_p, dst_size, from, src_size);
  1093. srcBufferCrc = CalculateCRC(srcBufferCrc, (BYTE*)reloc.m_origPtr - from + 4, from);
  1094. *pShortenedBufferCRC = CalculateCRC(*pShortenedBufferCRC, src_size, dst_p);
  1095. dst_p += src_size;
  1096. dst_size -= src_size;
  1097. // fix the BR
  1098. // write new opcode
  1099. AnalysisAssert(dst_p < tmpBuffer + newCodeSize);
  1100. *dst_p = (*opcodeByte == 0xe9) ? (BYTE)0xeb : (BYTE)(*opcodeByte - 0x10);
  1101. *(dst_p + 1) = 0; // imm8
  1102. *pShortenedBufferCRC = CalculateCRC(*pShortenedBufferCRC, 2, dst_p);
  1103. dst_p += 2; // 1 byte for opcode + 1 byte for imm8
  1104. dst_size -= 2;
  1105. from = (BYTE*)reloc.m_origPtr + 4;
  1106. }
  1107. else if (reloc.m_type == RelocTypeInlineeEntryOffset)
  1108. {
  1109. to = (BYTE*)reloc.m_origPtr - 1;
  1110. CopyPartialBufferAndCalculateCRC(&dst_p, dst_size, from, to, pShortenedBufferCRC);
  1111. *(size_t*)dst_p = reloc.GetInlineOffset();
  1112. *pShortenedBufferCRC = CalculateCRC(*pShortenedBufferCRC, sizeof(size_t), dst_p);
  1113. dst_p += sizeof(size_t);
  1114. dst_size -= sizeof(size_t);
  1115. srcBufferCrc = CalculateCRC(srcBufferCrc, (BYTE*)reloc.m_origPtr + sizeof(size_t) - from , from);
  1116. from = (BYTE*)reloc.m_origPtr + sizeof(size_t);
  1117. }
  1118. // insert NOPs for aligned labels
  1119. else if ((!PHASE_OFF(Js::LoopAlignPhase, m_func) && reloc.isAlignedLabel()) && reloc.getLabelNopCount() > 0)
  1120. {
  1121. IR::LabelInstr *label = reloc.getLabel();
  1122. BYTE nop_count = reloc.getLabelNopCount();
  1123. AssertMsg((BYTE*)label < buffStart || (BYTE*)label >= buffEnd, "Invalid label pointer.");
  1124. AssertMsg((((uint32)(label->GetPC() - buffStart)) & 0xf) == 0, "Misaligned Label");
  1125. to = reloc.getLabelOrigPC() - 1;
  1126. CopyPartialBufferAndCalculateCRC(&dst_p, dst_size, from, to, pShortenedBufferCRC);
  1127. srcBufferCrc = CalculateCRC(srcBufferCrc, to - from + 1, from);
  1128. #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
  1129. if (PHASE_TRACE(Js::LoopAlignPhase, this->m_func))
  1130. {
  1131. globalTotalBytesInserted += nop_count;
  1132. OUTPUT_VERBOSE_TRACE(Js::LoopAlignPhase, _u("func: %s, bytes inserted: %d, bytes inserted %%:%.4f, total bytes inserted:%d, total bytes inserted %%:%.4f\n"),
  1133. this->m_func->GetJITFunctionBody()->GetDisplayName(), nop_count, (float)nop_count / newCodeSize * 100, globalTotalBytesInserted, (float)globalTotalBytesInserted / (globalTotalBytesWithoutShortening - globalTotalBytesSaved) * 100);
  1134. Output::Flush();
  1135. }
  1136. #endif
  1137. BYTE * tmpDst_p = dst_p;
  1138. InsertNopsForLabelAlignment(nop_count, &dst_p);
  1139. *pShortenedBufferCRC = CalculateCRC(*pShortenedBufferCRC, nop_count, tmpDst_p);
  1140. dst_size -= nop_count;
  1141. from = to + 1;
  1142. }
  1143. }
  1144. // copy last chunk
  1145. //Exclude jumpTable content from CRC calculation.
  1146. //Though jumpTable is not part of the encoded bytes, codeSize has jumpTableSize included in it.
  1147. CopyPartialBufferAndCalculateCRC(&dst_p, dst_size, from, buffStart + *codeSize - 1, pShortenedBufferCRC, jumpTableSize);
  1148. srcBufferCrc = CalculateCRC(srcBufferCrc, buffStart + *codeSize - from - jumpTableSize, from);
  1149. m_encoderMD.UpdateRelocListWithNewBuffer(relocList, tmpBuffer, buffStart, buffEnd);
  1150. if (srcBufferCrc != bufferCrcToValidate)
  1151. {
  1152. Assert(false);
  1153. Fatal();
  1154. }
  1155. // switch buffers
  1156. *codeStart = tmpBuffer;
  1157. *codeSize = newCodeSize;
  1158. return true;
  1159. }
  1160. BYTE Encoder::FindNopCountFor16byteAlignment(size_t address)
  1161. {
  1162. return (16 - (BYTE) (address & 0xf)) % 16;
  1163. }
  1164. void Encoder::CopyPartialBufferAndCalculateCRC(BYTE ** ptrDstBuffer, size_t &dstSize, BYTE * srcStart, BYTE * srcEnd, uint* pBufferCRC, size_t jumpTableSize)
  1165. {
  1166. BYTE * destBuffer = *ptrDstBuffer;
  1167. size_t srcSize = srcEnd - srcStart + 1;
  1168. Assert(dstSize >= srcSize);
  1169. memcpy_s(destBuffer, dstSize, srcStart, srcSize);
  1170. Assert(srcSize >= jumpTableSize);
  1171. //Exclude the jump table content (which is at the end of the buffer) for calculating CRC - at this point.
  1172. *pBufferCRC = CalculateCRC(*pBufferCRC, srcSize - jumpTableSize, destBuffer);
  1173. *ptrDstBuffer += srcSize;
  1174. dstSize -= srcSize;
  1175. }
  1176. void Encoder::InsertNopsForLabelAlignment(int nopCount, BYTE ** ptrDstBuffer)
  1177. {
  1178. // write NOPs
  1179. for (int32 i = 0; i < nopCount; i++, (*ptrDstBuffer)++)
  1180. {
  1181. **ptrDstBuffer = 0x90;
  1182. }
  1183. }
  1184. void Encoder::revertRelocList()
  1185. {
  1186. RelocList* relocList = m_encoderMD.GetRelocList();
  1187. for (int32 i = 0; i < relocList->Count(); i++)
  1188. {
  1189. relocList->Item(i).revert();
  1190. }
  1191. }
  1192. template <bool restore>
  1193. void Encoder::CopyMaps(OffsetList **m_origInlineeFrameRecords
  1194. , OffsetList **m_origInlineeFrameMap
  1195. , OffsetList **m_origPragmaInstrToRecordOffset
  1196. , OffsetList **m_origOffsetBuffer
  1197. )
  1198. {
  1199. InlineeFrameRecords *recList = m_inlineeFrameRecords;
  1200. InlineeFrameMap *mapList = m_inlineeFrameMap;
  1201. PragmaInstrList *pInstrList = m_pragmaInstrToRecordOffset;
  1202. OffsetList *origRecList, *origMapList, *origPInstrList;
  1203. if (!restore)
  1204. {
  1205. Assert(*m_origInlineeFrameRecords == nullptr);
  1206. Assert(*m_origInlineeFrameMap == nullptr);
  1207. Assert(*m_origPragmaInstrToRecordOffset == nullptr);
  1208. *m_origInlineeFrameRecords = origRecList = Anew(m_tempAlloc, OffsetList, m_tempAlloc);
  1209. *m_origInlineeFrameMap = origMapList = Anew(m_tempAlloc, OffsetList, m_tempAlloc);
  1210. *m_origPragmaInstrToRecordOffset = origPInstrList = Anew(m_tempAlloc, OffsetList, m_tempAlloc);
  1211. #if DBG_DUMP
  1212. Assert((*m_origOffsetBuffer) == nullptr);
  1213. *m_origOffsetBuffer = Anew(m_tempAlloc, OffsetList, m_tempAlloc);
  1214. #endif
  1215. }
  1216. else
  1217. {
  1218. Assert((*m_origInlineeFrameRecords) && (*m_origInlineeFrameMap) && (*m_origPragmaInstrToRecordOffset));
  1219. origRecList = *m_origInlineeFrameRecords;
  1220. origMapList = *m_origInlineeFrameMap;
  1221. origPInstrList = *m_origPragmaInstrToRecordOffset;
  1222. Assert(origRecList->Count() == recList->Count());
  1223. Assert(origMapList->Count() == mapList->Count());
  1224. Assert(origPInstrList->Count() == pInstrList->Count());
  1225. #if DBG_DUMP
  1226. Assert(m_origOffsetBuffer);
  1227. Assert((uint32)(*m_origOffsetBuffer)->Count() == m_instrNumber);
  1228. #endif
  1229. }
  1230. for (int i = 0; i < recList->Count(); i++)
  1231. {
  1232. if (!restore)
  1233. {
  1234. origRecList->Add(recList->Item(i)->inlineeStartOffset);
  1235. }
  1236. else
  1237. {
  1238. recList->Item(i)->inlineeStartOffset = origRecList->Item(i);
  1239. }
  1240. }
  1241. for (int i = 0; i < mapList->Count(); i++)
  1242. {
  1243. if (!restore)
  1244. {
  1245. origMapList->Add(mapList->Item(i).offset);
  1246. }
  1247. else
  1248. {
  1249. mapList->Item(i).offset = origMapList->Item(i);
  1250. }
  1251. }
  1252. for (int i = 0; i < pInstrList->Count(); i++)
  1253. {
  1254. if (!restore)
  1255. {
  1256. origPInstrList->Add(pInstrList->Item(i)->m_offsetInBuffer);
  1257. }
  1258. else
  1259. {
  1260. pInstrList->Item(i)->m_offsetInBuffer = origPInstrList->Item(i);
  1261. }
  1262. }
  1263. if (restore)
  1264. {
  1265. (*m_origInlineeFrameRecords)->Delete();
  1266. (*m_origInlineeFrameMap)->Delete();
  1267. (*m_origPragmaInstrToRecordOffset)->Delete();
  1268. (*m_origInlineeFrameRecords) = nullptr;
  1269. (*m_origInlineeFrameMap) = nullptr;
  1270. (*m_origPragmaInstrToRecordOffset) = nullptr;
  1271. }
  1272. #if DBG_DUMP
  1273. for (uint i = 0; i < m_instrNumber; i++)
  1274. {
  1275. if (!restore)
  1276. {
  1277. (*m_origOffsetBuffer)->Add(m_offsetBuffer[i]);
  1278. }
  1279. else
  1280. {
  1281. m_offsetBuffer[i] = (*m_origOffsetBuffer)->Item(i);
  1282. }
  1283. }
  1284. if (restore)
  1285. {
  1286. (*m_origOffsetBuffer)->Delete();
  1287. (*m_origOffsetBuffer) = nullptr;
  1288. }
  1289. #endif
  1290. }
  1291. #endif
  1292. void Encoder::RecordBailout(IR::Instr* instr, uint32 currentOffset)
  1293. {
  1294. BailOutInfo* bailoutInfo = instr->GetBailOutInfo();
  1295. if (bailoutInfo->bailOutRecord == nullptr)
  1296. {
  1297. return;
  1298. }
  1299. #if DBG_DUMP
  1300. if (PHASE_DUMP(Js::LazyBailoutPhase, m_func))
  1301. {
  1302. Output::Print(_u("Offset: %u Instr: "), currentOffset);
  1303. instr->Dump();
  1304. Output::Print(_u("Bailout label: "));
  1305. bailoutInfo->bailOutInstr->Dump();
  1306. }
  1307. #endif
  1308. Assert(bailoutInfo->bailOutInstr->IsLabelInstr());
  1309. LazyBailOutRecord record(currentOffset, (BYTE*)bailoutInfo->bailOutInstr, bailoutInfo->bailOutRecord);
  1310. m_bailoutRecordMap->Add(record);
  1311. }
  1312. #if DBG_DUMP
  1313. void Encoder::DumpInlineeFrameMap(size_t baseAddress)
  1314. {
  1315. Output::Print(_u("Inlinee frame info mapping\n"));
  1316. Output::Print(_u("---------------------------------------\n"));
  1317. m_inlineeFrameMap->Map([=](uint index, NativeOffsetInlineeFramePair& pair) {
  1318. Output::Print(_u("%Ix"), baseAddress + pair.offset);
  1319. Output::SkipToColumn(20);
  1320. if (pair.record)
  1321. {
  1322. pair.record->Dump();
  1323. }
  1324. else
  1325. {
  1326. Output::Print(_u("<NULL>"));
  1327. }
  1328. Output::Print(_u("\n"));
  1329. });
  1330. }
  1331. #endif